Skip to content

Commit 55b99e6

Browse files
KunWuLuanFuture-Outlieryueming.wkkevin85421
authored
Support to set QPS and burst by configuration. (#3969)
Signed-off-by: KunWuLuan <[email protected]> Signed-off-by: Future-Outlier <[email protected]> Signed-off-by: Kai-Hsun Chen <[email protected]> Co-authored-by: Future-Outlier <[email protected]> Co-authored-by: yueming.wk <[email protected]> Co-authored-by: Kai-Hsun Chen <[email protected]>
1 parent 979b909 commit 55b99e6

File tree

6 files changed

+94
-24
lines changed

6 files changed

+94
-24
lines changed

ray-operator/apis/config/v1alpha1/configuration_types.go

Lines changed: 26 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -12,25 +12,26 @@ import (
1212

1313
// Configuration is the Schema for Ray operator config.
1414
type Configuration struct {
15-
metav1.TypeMeta `json:",inline"`
15+
// Burst allows temporary exceeding of QPS limit for handling request spikes.
16+
// Default: 200
17+
Burst *int `json:"burst,omitempty"`
1618

17-
// MetricsAddr is the address the metrics endpoint binds to.
18-
MetricsAddr string `json:"metricsAddr,omitempty"`
19-
20-
// ProbeAddr is the address the probe endpoint binds to.
21-
ProbeAddr string `json:"probeAddr,omitempty"`
19+
// QPS controls the maximum requests per second to the Kubernetes API server.
20+
// Default: 100.0
21+
QPS *float64 `json:"qps,omitempty"`
2222

2323
// EnableLeaderElection enables leader election. Enabling this will ensure
2424
// there is only one active instance of the operator.
2525
EnableLeaderElection *bool `json:"enableLeaderElection,omitempty"`
2626

27-
// LeaderElectionNamespace is the namespace where the leader election
28-
// resources live. Defaults to the pod namesapce if not set.
29-
LeaderElectionNamespace string `json:"leaderElectionNamespace,omitempty"`
27+
metav1.TypeMeta `json:",inline"`
3028

31-
// WatchNamespace specifies a list of namespaces to watch for custom resources, separated by commas.
32-
// If empty, all namespaces will be watched.
33-
WatchNamespace string `json:"watchNamespace,omitempty"`
29+
// LogStdoutEncoder is the encoder to use when logging to stdout. Valid values are "json" and "console".
30+
// Defaults to `json` if empty.
31+
LogStdoutEncoder string `json:"logStdoutEncoder,omitempty"`
32+
33+
// ProbeAddr is the address the probe endpoint binds to.
34+
ProbeAddr string `json:"probeAddr,omitempty"`
3435

3536
// LogFile is a path to a local file for synchronizing logs.
3637
LogFile string `json:"logFile,omitempty"`
@@ -39,22 +40,29 @@ type Configuration struct {
3940
// Defaults to `json` if empty.
4041
LogFileEncoder string `json:"logFileEncoder,omitempty"`
4142

42-
// LogFileEncoder is the encoder to use when logging to a file. Valid values are "json" and "console".
43-
// Defaults to `json` if empty.
44-
LogStdoutEncoder string `json:"logStdoutEncoder,omitempty"`
43+
// LeaderElectionNamespace is the namespace where the leader election
44+
// resources live. Defaults to the pod namesapce if not set.
45+
LeaderElectionNamespace string `json:"leaderElectionNamespace,omitempty"`
4546

4647
// BatchScheduler enables the batch scheduler integration with a specific scheduler
4748
// based on the given name, currently, supported values are volcano, yunikorn, kai-scheduler.
4849
BatchScheduler string `json:"batchScheduler,omitempty"`
4950

50-
// HeadSidecarContainers includes specification for a sidecar container
51-
// to inject into every Head pod.
52-
HeadSidecarContainers []corev1.Container `json:"headSidecarContainers,omitempty"`
51+
// MetricsAddr is the address the metrics endpoint binds to.
52+
MetricsAddr string `json:"metricsAddr,omitempty"`
53+
54+
// WatchNamespace specifies a list of namespaces to watch for custom resources, separated by commas.
55+
// If empty, all namespaces will be watched.
56+
WatchNamespace string `json:"watchNamespace,omitempty"`
5357

5458
// WorkerSidecarContainers includes specification for a sidecar container
5559
// to inject into every Worker pod.
5660
WorkerSidecarContainers []corev1.Container `json:"workerSidecarContainers,omitempty"`
5761

62+
// HeadSidecarContainers includes specification for a sidecar container
63+
// to inject into every Head pod.
64+
HeadSidecarContainers []corev1.Container `json:"headSidecarContainers,omitempty"`
65+
5866
// ReconcileConcurrency is the max concurrency for each reconciler.
5967
ReconcileConcurrency int `json:"reconcileConcurrency,omitempty"`
6068

ray-operator/apis/config/v1alpha1/defaults.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ const (
1010
DefaultProbeAddr = ":8082"
1111
DefaultEnableLeaderElection = true
1212
DefaultReconcileConcurrency = 1
13+
DefaultQPS = float64(100)
14+
DefaultBurst = 200
1315
)
1416

1517
func addDefaultingFuncs(scheme *runtime.Scheme) error {
@@ -36,4 +38,12 @@ func SetDefaults_Configuration(cfg *Configuration) {
3638
if cfg.ReconcileConcurrency == 0 {
3739
cfg.ReconcileConcurrency = DefaultReconcileConcurrency
3840
}
41+
42+
if cfg.QPS == nil {
43+
cfg.QPS = ptr.To(DefaultQPS)
44+
}
45+
46+
if cfg.Burst == nil {
47+
cfg.Burst = ptr.To(DefaultBurst)
48+
}
3949
}

ray-operator/apis/config/v1alpha1/zz_generated.deepcopy.go

Lines changed: 15 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

ray-operator/go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ require (
66
github.com/Masterminds/semver/v3 v3.3.1
77
github.com/go-logr/logr v1.4.3
88
github.com/go-logr/zapr v1.3.0
9+
github.com/google/go-cmp v0.7.0
910
github.com/jarcoal/httpmock v1.4.0
1011
github.com/onsi/ginkgo/v2 v2.23.4
1112
github.com/onsi/gomega v1.37.0
@@ -49,7 +50,6 @@ require (
4950
github.com/gogo/protobuf v1.3.2 // indirect
5051
github.com/google/btree v1.1.3 // indirect
5152
github.com/google/gnostic-models v0.6.9 // indirect
52-
github.com/google/go-cmp v0.7.0 // indirect
5353
github.com/google/pprof v0.0.0-20250403155104-27863c87afa6 // indirect
5454
github.com/google/uuid v1.6.0 // indirect
5555
github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 // indirect

ray-operator/main.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,8 @@ func main() {
7070
var enableBatchScheduler bool
7171
var batchScheduler string
7272
var enableMetrics bool
73+
var qps float64
74+
var burst int
7375

7476
// TODO: remove flag-based config once Configuration API graduates to v1.
7577
flag.StringVar(&metricsAddr, "metrics-addr", configapi.DefaultMetricsAddr, "The address the metric endpoint binds to.")
@@ -101,6 +103,8 @@ func main() {
101103
"Use Kubernetes proxy subresource when connecting to the Ray Head node.")
102104
flag.StringVar(&featureGates, "feature-gates", "", "A set of key=value pairs that describe feature gates. E.g. FeatureOne=true,FeatureTwo=false,...")
103105
flag.BoolVar(&enableMetrics, "enable-metrics", false, "Enable the emission of control plane metrics.")
106+
flag.Float64Var(&qps, "qps", float64(configapi.DefaultQPS), "The QPS value for the client communicating with the Kubernetes API server.")
107+
flag.IntVar(&burst, "burst", configapi.DefaultBurst, "The maximum burst for throttling requests from this client to the Kubernetes API server.")
104108

105109
opts := k8szap.Options{
106110
TimeEncoder: zapcore.ISO8601TimeEncoder,
@@ -131,6 +135,8 @@ func main() {
131135
config.UseKubernetesProxy = useKubernetesProxy
132136
config.DeleteRayJobAfterJobFinishes = os.Getenv(utils.DELETE_RAYJOB_CR_AFTER_JOB_FINISHES) == "true"
133137
config.EnableMetrics = enableMetrics
138+
config.QPS = &qps
139+
config.Burst = &burst
134140
}
135141

136142
stdoutEncoder, err := newLogEncoder(logStdoutEncoder)
@@ -228,6 +234,8 @@ func main() {
228234
setupLog.Info("Setup manager")
229235
restConfig := ctrl.GetConfigOrDie()
230236
restConfig.UserAgent = userAgent
237+
restConfig.QPS = float32(*config.QPS)
238+
restConfig.Burst = *config.Burst
231239
mgr, err := ctrl.NewManager(restConfig, options)
232240
exitOnError(err, "unable to start manager")
233241

ray-operator/main_test.go

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ kind: Configuration
3434
ProbeAddr: ":8082",
3535
EnableLeaderElection: ptr.To(true),
3636
ReconcileConcurrency: 1,
37+
QPS: ptr.To(configapi.DefaultQPS),
38+
Burst: ptr.To(configapi.DefaultBurst),
3739
},
3840
expectErr: false,
3941
},
@@ -55,6 +57,8 @@ reconcileConcurrency: 1
5557
ProbeAddr: ":8082",
5658
EnableLeaderElection: ptr.To(true),
5759
ReconcileConcurrency: 1,
60+
QPS: ptr.To(configapi.DefaultQPS),
61+
Burst: ptr.To(configapi.DefaultBurst),
5862
},
5963
expectErr: false,
6064
},
@@ -94,6 +98,8 @@ workerSidecarContainers:
9498
Image: "fluent/fluent-bit:1.9.6",
9599
},
96100
},
101+
QPS: ptr.To(configapi.DefaultQPS),
102+
Burst: ptr.To(configapi.DefaultBurst),
97103
},
98104
expectErr: false,
99105
},
@@ -116,6 +122,8 @@ unknownfield: 1
116122
ProbeAddr: ":8082",
117123
EnableLeaderElection: ptr.To(true),
118124
ReconcileConcurrency: 1,
125+
QPS: ptr.To(configapi.DefaultQPS),
126+
Burst: ptr.To(configapi.DefaultBurst),
119127
},
120128
expectErr: false,
121129
},
@@ -137,6 +145,8 @@ reconcileConcurrency: true
137145
ProbeAddr: ":8082",
138146
EnableLeaderElection: ptr.To(true),
139147
ReconcileConcurrency: 0,
148+
QPS: ptr.To(configapi.DefaultQPS),
149+
Burst: ptr.To(configapi.DefaultBurst),
140150
},
141151
expectErr: true,
142152
errContains: "json: cannot unmarshal bool into Go struct field Configuration.reconcileConcurrency of type int",
@@ -154,6 +164,30 @@ reconcileConcurrency: true
154164
MetricsAddr: ":8080",
155165
ProbeAddr: ":8082",
156166
EnableLeaderElection: ptr.To(true),
167+
QPS: ptr.To(configapi.DefaultQPS),
168+
Burst: ptr.To(configapi.DefaultBurst),
169+
},
170+
expectErr: true,
171+
errContains: `no kind "Configuration" is registered for version "config.ray.io/v1beta1" in scheme`,
172+
},
173+
{
174+
name: "set QPS and Burst",
175+
configData: `apiVersion: config.ray.io/v1beta1
176+
kind: Configuration
177+
qps: 150
178+
burst: 300
179+
`,
180+
expectedConfig: configapi.Configuration{
181+
TypeMeta: metav1.TypeMeta{
182+
Kind: "Configuration",
183+
APIVersion: "config.ray.io/v1alpha1",
184+
},
185+
MetricsAddr: ":8080",
186+
ProbeAddr: ":8082",
187+
EnableLeaderElection: ptr.To(true),
188+
ReconcileConcurrency: 1,
189+
QPS: ptr.To((150.0)),
190+
Burst: ptr.To(300),
157191
},
158192
expectErr: true,
159193
errContains: `no kind "Configuration" is registered for version "config.ray.io/v1beta1" in scheme`,

0 commit comments

Comments
 (0)