mirror of
https://github.com/yunionio/cloudpods.git
synced 2026-09-19 10:46:58 +08:00
loadbalancers: 增加rps限速支持
This commit is contained in:
@@ -9,10 +9,13 @@ import (
|
||||
|
||||
"yunion.io/x/log"
|
||||
"yunion.io/x/onecloud/pkg/cloudcommon"
|
||||
"yunion.io/x/onecloud/pkg/cloudcommon/consts"
|
||||
"yunion.io/x/onecloud/pkg/lbagent"
|
||||
)
|
||||
|
||||
func main() {
|
||||
consts.SetServiceType("lbagent")
|
||||
|
||||
opts := &lbagent.Options{}
|
||||
commonOpts := &opts.CommonOpts
|
||||
{
|
||||
|
||||
@@ -39,6 +39,8 @@ type SLoadbalancerListenerRule struct {
|
||||
|
||||
Domain string `width:"128" charset:"ascii" nullable:"false" list:"user" create:"optional"`
|
||||
Path string `width:"128" charset:"ascii" nullable:"false" list:"user" create:"optional"`
|
||||
|
||||
SLoadbalancerHTTPRateLimiter
|
||||
}
|
||||
|
||||
func loadbalancerListenerRuleCheckUniqueness(ctx context.Context, lbls *SLoadbalancerListener, domain, path string) error {
|
||||
@@ -101,6 +103,9 @@ func (man *SLoadbalancerListenerRuleManager) ValidateCreateData(ctx context.Cont
|
||||
"backend_group": backendGroupV,
|
||||
"domain": domainV.AllowEmpty(true).Default(""),
|
||||
"path": pathV.Default(""),
|
||||
|
||||
"http_request_rate": validators.NewNonNegativeValidator("http_request_rate").Default(0),
|
||||
"http_request_rate_per_src": validators.NewNonNegativeValidator("http_request_rate_per_src").Default(0),
|
||||
}
|
||||
for _, v := range keyV {
|
||||
if err := v.Validate(data); err != nil {
|
||||
@@ -131,10 +136,16 @@ func (lbr *SLoadbalancerListenerRule) AllowPerformStatus(ctx context.Context, us
|
||||
|
||||
func (lbr *SLoadbalancerListenerRule) ValidateUpdateData(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data *jsonutils.JSONDict) (*jsonutils.JSONDict, error) {
|
||||
backendGroupV := validators.NewModelIdOrNameValidator("backend_group", "loadbalancerbackendgroup", lbr.GetOwnerProjectId())
|
||||
backendGroupV.Optional(true)
|
||||
err := backendGroupV.Validate(data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
keyV := map[string]validators.IValidator{
|
||||
"backend_group": backendGroupV,
|
||||
"http_request_rate": validators.NewNonNegativeValidator("http_request_rate"),
|
||||
"http_request_rate_per_src": validators.NewNonNegativeValidator("http_request_rate_per_src"),
|
||||
}
|
||||
for _, v := range keyV {
|
||||
v.Optional(true)
|
||||
if err := v.Validate(data); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if backendGroup, ok := backendGroupV.Model.(*SLoadbalancerBackendGroup); ok && backendGroup.Id != lbr.BackendGroupId {
|
||||
listenerM, err := LoadbalancerListenerManager.FetchById(lbr.ListenerId)
|
||||
|
||||
@@ -33,6 +33,11 @@ func init() {
|
||||
}
|
||||
}
|
||||
|
||||
type SLoadbalancerHTTPRateLimiter struct {
|
||||
HTTPRequestRate int `nullable:"false" list:"user" create:"optional" update:"user"`
|
||||
HTTPRequestRatePerSrc int `nullable:"false" list:"user" create:"optional" update:"user"`
|
||||
}
|
||||
|
||||
type SLoadbalancerTCPListener struct{}
|
||||
type SLoadbalancerUDPListener struct{}
|
||||
|
||||
@@ -97,6 +102,8 @@ type SLoadbalancerListener struct {
|
||||
SLoadbalancerUDPListener
|
||||
SLoadbalancerHTTPListener
|
||||
SLoadbalancerHTTPSListener
|
||||
|
||||
SLoadbalancerHTTPRateLimiter
|
||||
}
|
||||
|
||||
func (man *SLoadbalancerListenerManager) checkListenerUniqueness(ctx context.Context, lb *SLoadbalancer, listenerType string, listenerPort int64) error {
|
||||
@@ -198,6 +205,9 @@ func (man *SLoadbalancerListenerManager) ValidateCreateData(ctx context.Context,
|
||||
|
||||
"x_forwarded_for": validators.NewBoolValidator("x_forwarded_for").Default(true),
|
||||
"gzip": validators.NewBoolValidator("gzip").Default(false),
|
||||
|
||||
"http_request_rate": validators.NewNonNegativeValidator("http_request_rate").Default(0),
|
||||
"http_request_rate_per_src": validators.NewNonNegativeValidator("http_request_rate_per_src").Default(0),
|
||||
}
|
||||
for _, v := range keyV {
|
||||
if err := v.Validate(data); err != nil {
|
||||
@@ -342,6 +352,9 @@ func (lblis *SLoadbalancerListener) ValidateUpdateData(ctx context.Context, user
|
||||
"x_forwarded_for": validators.NewBoolValidator("x_forwarded_for"),
|
||||
"gzip": validators.NewBoolValidator("gzip"),
|
||||
|
||||
"http_request_rate": validators.NewNonNegativeValidator("http_request_rate").Default(0),
|
||||
"http_request_rate_per_src": validators.NewNonNegativeValidator("http_request_rate_per_src").Default(0),
|
||||
|
||||
"certificate": certV,
|
||||
"tls_cipher_policy": tlsCipherPolicyV,
|
||||
"enable_http2": validators.NewBoolValidator("enable_http2").Default(true),
|
||||
|
||||
@@ -318,6 +318,43 @@ func (b *LoadbalancerCorpus) genHaproxyConfigBackend(data map[string]interface{}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *LoadbalancerCorpus) genHaproxyConfigHttpRate(data map[string]interface{}, requestRate, requestRatePerSrc int) error {
|
||||
periodSecond := 10
|
||||
id := data["id"].(string)
|
||||
dummyBackends := []map[string]string{}
|
||||
rateRules := []string{}
|
||||
|
||||
// order matters here: every src uses up his own quota before touching
|
||||
// the shared one
|
||||
if requestRatePerSrc > 0 {
|
||||
idPerSrc := id + "_persrc"
|
||||
dummyBackends = append(dummyBackends, map[string]string{
|
||||
"id": idPerSrc,
|
||||
"stick_table": fmt.Sprintf("stick-table type ip size 1m expire 1m store http_req_rate(%ds)", periodSecond),
|
||||
})
|
||||
rateRules = append(rateRules,
|
||||
fmt.Sprintf("http-request deny deny_status 429 if { src_http_req_rate(%s) gt %d }",
|
||||
idPerSrc, requestRatePerSrc*periodSecond),
|
||||
fmt.Sprintf("http-request track-sc0 src table %s",
|
||||
idPerSrc))
|
||||
}
|
||||
if requestRate > 0 {
|
||||
idTotal := id + "_total"
|
||||
dummyBackends = append(dummyBackends, map[string]string{
|
||||
"id": idTotal,
|
||||
"stick_table": fmt.Sprintf("stick-table type integer size 1 expire 1m store http_req_rate(%ds)", periodSecond),
|
||||
})
|
||||
rateRules = append(rateRules,
|
||||
fmt.Sprintf("http-request deny deny_status 429 if { int(1),table_http_req_rate(%s) gt %d }",
|
||||
idTotal, requestRate*periodSecond),
|
||||
fmt.Sprintf("http-request track-sc1 int(1) table %s",
|
||||
idTotal))
|
||||
}
|
||||
data["rate_rules"] = rateRules
|
||||
data["dummy_backends"] = dummyBackends
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *LoadbalancerCorpus) genHaproxyConfigHttp(buf *bytes.Buffer, listener *LoadbalancerListener, opts *AgentParams) error {
|
||||
lb := listener.loadbalancer
|
||||
rules := listener.rules.OrderedEnabledList()
|
||||
@@ -366,8 +403,10 @@ func (b *LoadbalancerCorpus) genHaproxyConfigHttp(buf *bytes.Buffer, listener *L
|
||||
backendGroup.Name, backendGroup.Id),
|
||||
"id": ruleBackendIdGen(rule.Id),
|
||||
}
|
||||
err := b.genHaproxyConfigBackend(backendData, lb, listener, backendGroup)
|
||||
if err != nil {
|
||||
if err := b.genHaproxyConfigBackend(backendData, lb, listener, backendGroup); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := b.genHaproxyConfigHttpRate(backendData, rule.HTTPRequestRate, rule.HTTPRequestRatePerSrc); err != nil {
|
||||
return err
|
||||
}
|
||||
backends = append(backends, backendData)
|
||||
@@ -381,8 +420,10 @@ func (b *LoadbalancerCorpus) genHaproxyConfigHttp(buf *bytes.Buffer, listener *L
|
||||
backendGroup.Name, backendGroup.Id),
|
||||
"id": fmt.Sprintf("backends_listener_default-%s", listener.Id),
|
||||
}
|
||||
err := b.genHaproxyConfigBackend(backendData, lb, listener, backendGroup)
|
||||
if err != nil {
|
||||
if err := b.genHaproxyConfigBackend(backendData, lb, listener, backendGroup); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := b.genHaproxyConfigHttpRate(backendData, listener.HTTPRequestRate, listener.HTTPRequestRatePerSrc); err != nil {
|
||||
return err
|
||||
}
|
||||
backends = append(backends, backendData)
|
||||
@@ -436,12 +477,17 @@ listen {{ .id }}
|
||||
|
||||
{{ define "httpListen" -}}
|
||||
# {{ .listener_type }} listener: {{ .comment }}
|
||||
{{- range .dummy_backends }}
|
||||
backend {{ .id }}
|
||||
{{ println .stick_table }}
|
||||
{{- end }}
|
||||
frontend {{ .id }}
|
||||
bind {{ .bind }}
|
||||
mode http
|
||||
{{- println }}
|
||||
{{- if .log }} {{ println "option httplog clf" }} {{- end }}
|
||||
{{- if .acl }} {{ println .acl }} {{- end}}
|
||||
{{- range .rate_rules }} {{ println . }} {{- end }}
|
||||
{{- if .client_request_timeout }} timeout http-request {{ println .client_request_timeout }} {{- end}}
|
||||
{{- if .client_idle_timeout }} timeout http-keep-alive {{ println .client_idle_timeout }} {{- end}}
|
||||
{{- if .xforwardedfor }} {{ println "option forwardfor" }} {{- end}}
|
||||
@@ -455,10 +501,15 @@ frontend {{ .id }}
|
||||
|
||||
{{ define "backend" -}}
|
||||
# {{ .comment }}
|
||||
{{- range .dummy_backends }}
|
||||
backend {{ .id }}
|
||||
{{ println .stick_table }}
|
||||
{{- end }}
|
||||
backend {{ .id }}
|
||||
mode {{ .mode }}
|
||||
balance {{ .balanceAlgorithm }}
|
||||
{{- println }}
|
||||
{{- range .rate_rules }} {{ println . }} {{- end }}
|
||||
{{- if .backend_connect_timeout }} timeout connect {{ println .backend_connect_timeout }} {{- end}}
|
||||
{{- if .backend_idle_timeout }} timeout server {{ println .backend_idle_timeout }} {{- end}}
|
||||
{{- if .timeout_check }} {{ println .timeout_check }} {{- end }}
|
||||
|
||||
@@ -36,6 +36,11 @@ type LoadbalancerHTTPSListener struct {
|
||||
EnableHttp2 bool
|
||||
}
|
||||
|
||||
type LoadbalancerHTTPRateLimiter struct {
|
||||
HTTPRequestRate int
|
||||
HTTPRequestRatePerSrc int
|
||||
}
|
||||
|
||||
type LoadbalancerListener struct {
|
||||
VirtualResource
|
||||
|
||||
@@ -75,6 +80,8 @@ type LoadbalancerListener struct {
|
||||
LoadbalancerUDPListener
|
||||
LoadbalancerHTTPListener
|
||||
LoadbalancerHTTPSListener
|
||||
|
||||
LoadbalancerHTTPRateLimiter
|
||||
}
|
||||
|
||||
type LoadbalancerListenerRule struct {
|
||||
@@ -85,6 +92,8 @@ type LoadbalancerListenerRule struct {
|
||||
|
||||
Domain string
|
||||
Path string
|
||||
|
||||
LoadbalancerHTTPRateLimiter
|
||||
}
|
||||
|
||||
type LoadbalancerBackendGroup struct {
|
||||
|
||||
@@ -45,6 +45,9 @@ type LoadbalancerListenerCreateOptions struct {
|
||||
Certificate string
|
||||
TLSCipherPolicy string
|
||||
EnableHttp2 string `choices:"true|false"`
|
||||
|
||||
HTTPRequestRate *int
|
||||
HTTPRequestRatePerSrc *int
|
||||
}
|
||||
|
||||
type LoadbalancerListenerListOptions struct {
|
||||
@@ -92,6 +95,9 @@ type LoadbalancerListenerListOptions struct {
|
||||
Certificate string
|
||||
TLSCipherPolicy string
|
||||
EnableHttp2 string `choices:"true|false"`
|
||||
|
||||
HTTPRequestRate *int
|
||||
HTTPRequestRatePerSrc *int
|
||||
}
|
||||
|
||||
type LoadbalancerListenerUpdateOptions struct {
|
||||
@@ -137,6 +143,9 @@ type LoadbalancerListenerUpdateOptions struct {
|
||||
Certificate string
|
||||
TLSCipherPolicy string
|
||||
EnableHttp2 string `choices:"true|false"`
|
||||
|
||||
HTTPRequestRate *int
|
||||
HTTPRequestRatePerSrc *int
|
||||
}
|
||||
|
||||
type LoadbalancerListenerGetOptions struct {
|
||||
|
||||
Reference in New Issue
Block a user