-
Notifications
You must be signed in to change notification settings - Fork 498
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
able to scale in/out with delete slots feature #1361
Conversation
go.mod
Outdated
@@ -142,3 +142,5 @@ replace k8s.io/legacy-cloud-providers => k8s.io/legacy-cloud-providers v0.0.0-20 | |||
replace k8s.io/node-api => k8s.io/node-api v0.0.0-20190918163711-2299658ad911 | |||
|
|||
replace github.com/uber-go/atomic => go.uber.org/atomic v1.5.0 | |||
|
|||
replace github.com/pingcap/advanced-statefulset => /data/go/src/github.com/pingcap/advanced-statefulset |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
probably don't want to commit this
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is for local development only, I'll remove this
7c30943
to
30169a5
Compare
/run-e2e-test |
1a007b1
to
cd53f6f
Compare
scope: Namespaced | ||
names: | ||
plural: statefulsets | ||
singular: statefulset | ||
kind: StatefulSet | ||
shortNames: | ||
- asts | ||
versions: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
there are already two versions?
08477b9
to
4dae600
Compare
/run-e2e-test |
tests/actions.go
Outdated
@@ -393,15 +397,19 @@ func (oi *OperatorConfig) OperatorHelmSetString(m map[string]string) string { | |||
"scheduler.kubeSchedulerImageName": oi.SchedulerImage, | |||
"controllerManager.logLevel": oi.LogLevel, | |||
"scheduler.logLevel": "4", | |||
"controllerManager.replicas": "2", | |||
"scheduler.replicas": "2", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
make it configurable, in some tests, we can use 1 replica to consumes fewer resources
tests/actions.go
Outdated
name := fmt.Sprintf("%s-%d", memberName, 0) | ||
pod, err := kubeCli.CoreV1().Pods(namespace).Get(name, metav1.GetOptions{}) | ||
// getMemberContainer gets member container | ||
func getMemberContainer(kubeCli kubernetes.Interface, namespace, tcName, component string) (*corev1.Container, bool) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
instead of fetching the -0
pod, we list the pods and use the first one.
tests/dt.go
Outdated
@@ -63,7 +63,7 @@ func (oa *operatorActions) LabelNodes() error { | |||
} | |||
|
|||
for i, node := range nodes.Items { | |||
err := wait.Poll(3*time.Second, time.Minute, func() (bool, error) { | |||
err := wait.PollImmediate(3*time.Second, time.Minute, func() (bool, error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
no need to wait at the first try, this reduces time
9e60e30
to
20c79ba
Compare
/run-e2e-test |
@@ -41,7 +41,7 @@ type DBInfo struct { | |||
// TiDBControlInterface is the interface that knows how to manage tidb peers | |||
type TiDBControlInterface interface { | |||
// GetHealth returns tidb's health info | |||
GetHealth(tc *v1alpha1.TidbCluster) map[string]bool | |||
GetHealth(tc *v1alpha1.TidbCluster, ordinal int32) (bool, error) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
tidb member controller will decide which member we need to request the health status
pkg/manager/member/scaler.go
Outdated
return nil | ||
} | ||
// Following cases are not supported yet. | ||
// TODO support it or validate in validation phase |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
some desired states are not allowed because the controller has to delete and create pods. I decided to implement in the future. There are two ways to solve this issue:
- avoid in validation phase
- support it in multiple scaling operations (e.g. by scaling out first and then scaling in)
-replicas 5, delete slots [0]
is changed toreplicas 4, delete slots[1]
, we need to delete pod 1 and 5 and create pod 4.
// from a string like feature1=true,feature2=false,... | ||
Set(value string) error | ||
// SetFromMap stores flag gates for enabled features from a map[string]bool | ||
SetFromMap(m map[string]bool) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
able to change features settings in unit tests
if err != nil { | ||
return err | ||
} | ||
resetReplicas(newSet, oldSet) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've updated the scaling logic like this:
- get desired replicas and delete slot by comparing the old and new statefulsets
- reset the new statefulset
- if our scaling logic succeeds, set desired replicas and delete slots, otherwise, return an error
pkg/manager/member/scaler.go
Outdated
} | ||
|
||
// scaleOne scales actual set to desired set by deleting or creating a replica | ||
func scaleOne(actual *apps.StatefulSet, desired *apps.StatefulSet) (int32, int32, sets.Int, error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this function calculates desired replicas
and delete slots
from actual/desired stateful sets by allowing one pod to be deleted or created
func (psd *pdScaler) ScaleOut(tc *v1alpha1.TidbCluster, oldSet *apps.StatefulSet, newSet *apps.StatefulSet) error { | ||
_, ordinal, replicas, deleteSlots := scaleOne(oldSet, newSet) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
recalculating again because of less code needs to be changed (otherwise ScaleOut/ScaleIn function signatures need to change and a lot of tests must be updated)
func (tsd *tikvScaler) ScaleOut(tc *v1alpha1.TidbCluster, oldSet *apps.StatefulSet, newSet *apps.StatefulSet) error { | ||
_, ordinal, replicas, deleteSlots := scaleOne(oldSet, newSet) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
recalculating again because of less code needs to be changed (otherwise ScaleOut/ScaleIn function signatures need to change and a lot of tests must be updated)
/run-e2e-test |
/run-e2e-test |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rest LGTM, the scaleOne()
method is excellent
// - scaling: | ||
// - 0: no scaling required | ||
// - 1: scaling out | ||
// - -1: scaling in |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could we define enums for this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think it's necessary because it's used internally and I actually uses > 0
and < 0
to decide whether to scale in or scale out.
@@ -158,3 +163,188 @@ func newFakeGeneralScaler() (*generalScaler, cache.Indexer, *controller.FakePVCC | |||
return &generalScaler{pvcLister: pvcInformer.Lister(), pvcControl: pvcControl}, | |||
pvcInformer.Informer().GetIndexer(), pvcControl | |||
} | |||
|
|||
func TestScaleOne(t *testing.T) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could we add a case for "scale tidb to 0"?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed some corner cases and add more tests in c8eb405
pkg/manager/member/scaler.go
Outdated
additions := desiredDesiredPodOrdinals.Difference(actualDesiredPodOrdinals) | ||
deletions := actualDesiredPodOrdinals.Difference(desiredDesiredPodOrdinals) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is the order of the diff result guaranteed? or random?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
internal struct of sets is a map, List()
will sort the set members in ascending order
29e6c30
to
4792854
Compare
/run-e2e-test |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
well done.
LGTM
/merge |
/run-all-tests |
What problem does this PR solve?
xref: #1348
What is changed and how does it work?
Check List
Tests
Does this PR introduce a user-facing change?: