Skip to content

Commit c114781

Browse files
authored
reconstruct the logic of GameServers scaling (#171)
Signed-off-by: ChrisLiu <[email protected]>
1 parent 41d902a commit c114781

File tree

3 files changed

+244
-125
lines changed

3 files changed

+244
-125
lines changed

pkg/controllers/gameserverset/gameserverset_controller_test.go

+81
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,87 @@ func TestInitAsts(t *testing.T) {
100100
},
101101
},
102102
},
103+
104+
{
105+
gss: &gameKruiseV1alpha1.GameServerSet{
106+
TypeMeta: metav1.TypeMeta{
107+
Kind: "GameServerSet",
108+
APIVersion: "game.kruise.io/v1alpha1",
109+
},
110+
ObjectMeta: metav1.ObjectMeta{
111+
Namespace: "xxx",
112+
Name: "case1",
113+
UID: "xxx1",
114+
},
115+
Spec: gameKruiseV1alpha1.GameServerSetSpec{
116+
Replicas: ptr.To[int32](4),
117+
ReserveGameServerIds: []int{0},
118+
UpdateStrategy: gameKruiseV1alpha1.UpdateStrategy{
119+
Type: apps.RollingUpdateStatefulSetStrategyType,
120+
RollingUpdate: &gameKruiseV1alpha1.RollingUpdateStatefulSetStrategy{},
121+
},
122+
},
123+
},
124+
asts: &kruiseV1beta1.StatefulSet{
125+
TypeMeta: metav1.TypeMeta{
126+
Kind: "StatefulSet",
127+
APIVersion: "apps.kruise.io/v1beta1",
128+
},
129+
ObjectMeta: metav1.ObjectMeta{
130+
Namespace: "xxx",
131+
Name: "case1",
132+
OwnerReferences: []metav1.OwnerReference{
133+
{
134+
APIVersion: "game.kruise.io/v1alpha1",
135+
Kind: "GameServerSet",
136+
Name: "case1",
137+
UID: "xxx1",
138+
Controller: ptr.To[bool](true),
139+
BlockOwnerDeletion: ptr.To[bool](true),
140+
},
141+
},
142+
ResourceVersion: "1",
143+
},
144+
Spec: kruiseV1beta1.StatefulSetSpec{
145+
Replicas: ptr.To[int32](4),
146+
ReserveOrdinals: []int{0},
147+
PodManagementPolicy: apps.ParallelPodManagement,
148+
ServiceName: "case1",
149+
Selector: &metav1.LabelSelector{
150+
MatchLabels: map[string]string{gameKruiseV1alpha1.GameServerOwnerGssKey: "case1"},
151+
},
152+
UpdateStrategy: kruiseV1beta1.StatefulSetUpdateStrategy{
153+
Type: apps.RollingUpdateStatefulSetStrategyType,
154+
RollingUpdate: &kruiseV1beta1.RollingUpdateStatefulSetStrategy{
155+
UnorderedUpdate: &kruiseV1beta1.UnorderedUpdateStrategy{
156+
PriorityStrategy: &appspub.UpdatePriorityStrategy{
157+
OrderPriority: []appspub.UpdatePriorityOrderTerm{
158+
{
159+
OrderedKey: gameKruiseV1alpha1.GameServerUpdatePriorityKey,
160+
},
161+
},
162+
},
163+
},
164+
},
165+
},
166+
Template: corev1.PodTemplateSpec{
167+
ObjectMeta: metav1.ObjectMeta{
168+
Labels: map[string]string{
169+
gameKruiseV1alpha1.GameServerOwnerGssKey: "case1",
170+
},
171+
},
172+
Spec: corev1.PodSpec{
173+
ReadinessGates: []corev1.PodReadinessGate{
174+
{
175+
ConditionType: appspub.InPlaceUpdateReady,
176+
},
177+
},
178+
},
179+
},
180+
ScaleStrategy: &kruiseV1beta1.StatefulSetScaleStrategy{},
181+
},
182+
},
183+
},
103184
}
104185

105186
for i, test := range tests {

pkg/controllers/gameserverset/gameserverset_manager.go

+47-69
Original file line numberDiff line numberDiff line change
@@ -124,10 +124,11 @@ func (manager *GameServerSetManager) GameServerScale() error {
124124
notExistIds := util.GetSliceInANotInB(asts.Spec.ReserveOrdinals, reserveIds)
125125
gssReserveIds := gss.Spec.ReserveGameServerIds
126126

127-
klog.Infof("GameServers %s/%s already has %d replicas, expect to have %d replicas.", gss.GetNamespace(), gss.GetName(), currentReplicas, expectedReplicas)
127+
klog.Infof("GameServers %s/%s already has %d replicas, expect to have %d replicas; With newExplicit: %v; oldExplicit: %v; oldImplicit: %v",
128+
gss.GetNamespace(), gss.GetName(), currentReplicas, expectedReplicas, gssReserveIds, reserveIds, notExistIds)
128129
manager.eventRecorder.Eventf(gss, corev1.EventTypeNormal, ScaleReason, "scale from %d to %d", currentReplicas, expectedReplicas)
129130

130-
newManageIds, newReserveIds := computeToScaleGs(gssReserveIds, reserveIds, notExistIds, expectedReplicas, podList, gss.Spec.ScaleStrategy.ScaleDownStrategyType)
131+
newManageIds, newReserveIds := computeToScaleGs(gssReserveIds, reserveIds, notExistIds, expectedReplicas, podList)
131132

132133
if gss.Spec.GameServerTemplate.ReclaimPolicy == gameKruiseV1alpha1.DeleteGameServerReclaimPolicy {
133134
err := SyncGameServer(gss, c, newManageIds, util.GetIndexListFromPodList(podList))
@@ -163,82 +164,59 @@ func (manager *GameServerSetManager) GameServerScale() error {
163164
return nil
164165
}
165166

166-
func computeToScaleGs(gssReserveIds, reserveIds, notExistIds []int, expectedReplicas int, pods []corev1.Pod, scaleDownType gameKruiseV1alpha1.ScaleDownStrategyType) ([]int, []int) {
167-
workloadManageIds := util.GetIndexListFromPodList(pods)
168-
169-
var toAdd []int
170-
var toDelete []int
171-
172-
// 1. compute reserved GameServerIds, firstly
173-
174-
// 1.a. to delete those new reserved GameServers already in workloadManageIds
175-
toDelete = util.GetSliceInAandInB(util.GetSliceInANotInB(gssReserveIds, reserveIds), workloadManageIds)
176-
177-
// 1.b. to add those remove-reserved GameServers already in workloadManageIds
178-
existLastIndex := -1
179-
if len(workloadManageIds) != 0 {
180-
sort.Ints(workloadManageIds)
181-
existLastIndex = workloadManageIds[len(workloadManageIds)-1]
182-
}
183-
for _, id := range util.GetSliceInANotInB(reserveIds, gssReserveIds) {
184-
if existLastIndex > id {
185-
toAdd = append(toAdd, id)
167+
// computeToScaleGs is to compute what the id list the pods should be existed in cluster, and what the asts reserve id list should be.
168+
// reserveIds is the explicit id list.
169+
// notExistIds is the implicit id list.
170+
// gssReserveIds is the newest explicit id list.
171+
// pods is the pods that managed by gss now.
172+
func computeToScaleGs(gssReserveIds, reserveIds, notExistIds []int, expectedReplicas int, pods []corev1.Pod) ([]int, []int) {
173+
// 1. Get newest implicit list & explicit.
174+
newAddExplicit := util.GetSliceInANotInB(gssReserveIds, reserveIds)
175+
newDeleteExplicit := util.GetSliceInANotInB(reserveIds, gssReserveIds)
176+
newImplicit := util.GetSliceInANotInB(notExistIds, newAddExplicit)
177+
newImplicit = append(newImplicit, newDeleteExplicit...)
178+
newExplicit := gssReserveIds
179+
180+
// 2. Remove the pods ids is in newExplicit.
181+
var workloadManageIds []int
182+
var newPods []corev1.Pod
183+
for _, pod := range pods {
184+
index := util.GetIndexFromGsName(pod.Name)
185+
if util.IsNumInList(index, newExplicit) {
186+
continue
186187
}
187-
}
188-
// those remove-reserved GameServers will only be added when expansion is required
189-
if len(toDelete)-len(pods)+expectedReplicas > 0 {
190-
index := util.Min(len(toAdd), len(toDelete)-len(pods)+expectedReplicas)
191-
sort.Ints(toAdd)
192-
toAdd = toAdd[:index]
193-
} else {
194-
toAdd = nil
188+
workloadManageIds = append(workloadManageIds, index)
189+
newPods = append(newPods, pod)
195190
}
196191

197-
// 2. compute remain GameServerIds, secondly
192+
// 3. Continue to delete or add pods based on the current and expected number of pods.
193+
existReplicas := len(workloadManageIds)
198194

199-
numToAdd := expectedReplicas - len(pods) + len(toDelete) - len(toAdd)
200-
if numToAdd < 0 {
201-
202-
// 2.a to delete GameServers according to DeleteSequence
203-
sortedGs := util.DeleteSequenceGs(pods)
204-
sort.Sort(sortedGs)
205-
toDelete = append(toDelete, util.GetIndexListFromPodList(sortedGs[:-numToAdd])...)
206-
} else {
207-
208-
// 2.b to add GameServers, firstly add those in add notExistIds, secondly add those in future sequence
209-
numNotExist := len(notExistIds)
210-
if numNotExist < numToAdd {
211-
toAdd = append(toAdd, notExistIds...)
212-
times := 0
213-
for i := existLastIndex + 1; times < numToAdd-numNotExist; i++ {
214-
if !util.IsNumInList(i, gssReserveIds) {
215-
toAdd = append(toAdd, i)
216-
times++
217-
}
195+
if existReplicas < expectedReplicas {
196+
// Add pods.
197+
num := 0
198+
var toAdd []int
199+
for i := 0; num < expectedReplicas-existReplicas; i++ {
200+
if util.IsNumInList(i, workloadManageIds) || util.IsNumInList(i, newExplicit) {
201+
continue
218202
}
219-
} else {
220-
toAdd = append(toAdd, notExistIds[:numToAdd]...)
221-
}
222-
}
223-
224-
newManageIds := append(workloadManageIds, util.GetSliceInANotInB(toAdd, workloadManageIds)...)
225-
newManageIds = util.GetSliceInANotInB(newManageIds, toDelete)
226-
227-
if scaleDownType == gameKruiseV1alpha1.ReserveIdsScaleDownStrategyType {
228-
return newManageIds, append(gssReserveIds, util.GetSliceInANotInB(toDelete, gssReserveIds)...)
229-
}
230-
231-
var newReserveIds []int
232-
if len(newManageIds) != 0 {
233-
sort.Ints(newManageIds)
234-
for i := 0; i < newManageIds[len(newManageIds)-1]; i++ {
235-
if !util.IsNumInList(i, newManageIds) {
236-
newReserveIds = append(newReserveIds, i)
203+
if util.IsNumInList(i, newImplicit) {
204+
newImplicit = util.GetSliceInANotInB(newImplicit, []int{i})
237205
}
206+
toAdd = append(toAdd, i)
207+
num++
238208
}
209+
workloadManageIds = append(workloadManageIds, toAdd...)
210+
} else if existReplicas > expectedReplicas {
211+
// Delete pods.
212+
sortedGs := util.DeleteSequenceGs(newPods)
213+
sort.Sort(sortedGs)
214+
toDelete := util.GetIndexListFromPodList(sortedGs[:existReplicas-expectedReplicas])
215+
workloadManageIds = util.GetSliceInANotInB(workloadManageIds, toDelete)
216+
newImplicit = append(newImplicit, toDelete...)
239217
}
240218

241-
return newManageIds, newReserveIds
219+
return workloadManageIds, append(newImplicit, newExplicit...)
242220
}
243221

244222
func SyncGameServer(gss *gameKruiseV1alpha1.GameServerSet, c client.Client, newManageIds, oldManageIds []int) error {

0 commit comments

Comments
 (0)