You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@servicecomb.apache.org by ti...@apache.org on 2021/03/11 06:35:50 UTC
[servicecomb-service-center] branch master updated: refactor quota,
make clean code (#890)
This is an automated email from the ASF dual-hosted git repository.
tianxiaoliang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/servicecomb-service-center.git
The following commit(s) were added to refs/heads/master by this push:
new 04c166a refactor quota, make clean code (#890)
04c166a is described below
commit 04c166a06968594cab166d391f68184f81f5e10a
Author: Shawn <xi...@gmail.com>
AuthorDate: Thu Mar 11 14:35:43 2021 +0800
refactor quota, make clean code (#890)
---
datasource/etcd/ms.go | 53 +++++-------
datasource/etcd/util.go | 4 +-
datasource/etcd/util/microservice_util.go | 4 +-
datasource/mongo/ms.go | 15 ++--
etc/conf/app.conf | 6 +-
etc/conf/app.yaml | 2 +-
server/bootstrap/bootstrap.go | 2 -
server/plugin/quota/buildin/buildin.go | 22 +++--
server/plugin/quota/buildin/buildin_test.go | 62 ++++++++++++++
server/plugin/quota/buildin/common.go | 117 --------------------------
server/plugin/quota/buildin/common_test.go | 87 -------------------
server/plugin/quota/quota.go | 125 ++++++++++++++++++----------
server/plugin/quota/unlimit/unlimit.go | 45 ----------
server/service/schema.go | 5 +-
14 files changed, 191 insertions(+), 358 deletions(-)
diff --git a/datasource/etcd/ms.go b/datasource/etcd/ms.go
index b7e70a5..34aad64 100644
--- a/datasource/etcd/ms.go
+++ b/datasource/etcd/ms.go
@@ -63,16 +63,15 @@ func (ds *DataSource) RegisterService(ctx context.Context, request *pb.CreateSer
Version: service.Version,
}
- reporter := checkQuota(ctx, domainProject)
- defer reporter.Close(ctx)
- if reporter != nil && reporter.Err != nil {
+ Err := checkQuota(ctx, domainProject)
+ if Err != nil {
log.Error(fmt.Sprintf("create micro-service[%s] failed, operator: %s",
- serviceFlag, remoteIP), reporter.Err)
+ serviceFlag, remoteIP), Err)
resp := &pb.CreateServiceResponse{
- Response: pb.CreateResponseWithSCErr(reporter.Err),
+ Response: pb.CreateResponseWithSCErr(Err),
}
- if reporter.Err.InternalError() {
- return resp, reporter.Err
+ if Err.InternalError() {
+ return resp, Err
}
return resp, nil
}
@@ -160,9 +159,7 @@ func (ds *DataSource) RegisterService(ctx context.Context, request *pb.CreateSer
}, nil
}
- if err := reporter.ReportUsedQuota(ctx); err != nil {
- log.Error("report the used quota failed", err)
- }
+ //TODO increase usage in quota system
log.Info(fmt.Sprintf("create micro-service[%s][%s] successfully, operator: %s",
service.ServiceId, serviceFlag, remoteIP))
@@ -576,21 +573,19 @@ func (ds *DataSource) RegisterInstance(ctx context.Context, request *pb.Register
//先以domain/project的方式组装
domainProject := util.ParseDomainProject(ctx)
- var reporter *quota.ApplyQuotaResult
if !core.IsSCInstance(ctx) {
- res := quota.NewApplyQuotaResource(quota.MicroServiceInstanceQuotaType,
+ res := quota.NewApplyQuotaResource(quota.TypeInstance,
domainProject, request.Instance.ServiceId, 1)
- reporter = quota.Apply(ctx, res)
- defer reporter.Close(ctx)
+ applyErr := quota.Apply(ctx, res)
- if reporter.Err != nil {
+ if applyErr != nil {
log.Error(fmt.Sprintf("register instance failed, %s, operator %s",
- instanceFlag, remoteIP), reporter.Err)
+ instanceFlag, remoteIP), applyErr)
response := &pb.RegisterInstanceResponse{
- Response: pb.CreateResponseWithSCErr(reporter.Err),
+ Response: pb.CreateResponseWithSCErr(applyErr),
}
- if reporter.Err.InternalError() {
- return response, reporter.Err
+ if applyErr.InternalError() {
+ return response, applyErr
}
return response, nil
}
@@ -645,10 +640,7 @@ func (ds *DataSource) RegisterInstance(ctx context.Context, request *pb.Register
}, nil
}
- if err := reporter.ReportUsedQuota(ctx); err != nil {
- log.Error(fmt.Sprintf("register instance failed, %s, instanceID %s, operator %s",
- instanceFlag, instanceID, remoteIP), err)
- }
+ //TODO increase usage in quota system
log.Info(fmt.Sprintf("register instance %s, instanceID %s, operator %s",
instanceFlag, instanceID, remoteIP))
@@ -1823,9 +1815,8 @@ func (ds *DataSource) AddRule(ctx context.Context, request *pb.AddServiceRulesRe
Response: pb.CreateResponse(pb.ErrInvalidParams, "Service does not exist."),
}, nil
}
- res := quota.NewApplyQuotaResource(quota.RuleQuotaType, domainProject, request.ServiceId, int64(len(request.Rules)))
- rst := quota.Apply(ctx, res)
- errQuota := rst.Err
+ res := quota.NewApplyQuotaResource(quota.TypeRule, domainProject, request.ServiceId, int64(len(request.Rules)))
+ errQuota := quota.Apply(ctx, res)
if errQuota != nil {
log.Errorf(errQuota, "add service[%s] rule failed, operator: %s", request.ServiceId, remoteIP)
response := &pb.AddServiceRulesResponse{
@@ -2154,9 +2145,8 @@ func (ds *DataSource) modifySchemas(ctx context.Context, domainProject string, s
pluginOps := make([]client.PluginOp, 0)
if !ds.isSchemaEditable(service) {
if len(service.Schemas) == 0 {
- res := quota.NewApplyQuotaResource(quota.SchemaQuotaType, domainProject, serviceID, int64(len(nonExistSchemaIds)))
- rst := quota.Apply(ctx, res)
- errQuota := rst.Err
+ res := quota.NewApplyQuotaResource(quota.TypeSchema, domainProject, serviceID, int64(len(nonExistSchemaIds)))
+ errQuota := quota.Apply(ctx, res)
if errQuota != nil {
log.Errorf(errQuota, "modify service[%s] schemas failed, operator: %s", serviceID, remoteIP)
return errQuota
@@ -2199,9 +2189,8 @@ func (ds *DataSource) modifySchemas(ctx context.Context, domainProject string, s
} else {
quotaSize := len(needAddSchemas) - len(needDeleteSchemas)
if quotaSize > 0 {
- res := quota.NewApplyQuotaResource(quota.SchemaQuotaType, domainProject, serviceID, int64(quotaSize))
- rst := quota.Apply(ctx, res)
- err := rst.Err
+ res := quota.NewApplyQuotaResource(quota.TypeSchema, domainProject, serviceID, int64(quotaSize))
+ err := quota.Apply(ctx, res)
if err != nil {
log.Errorf(err, "modify service[%s] schemas failed, operator: %s", serviceID, remoteIP)
return err
diff --git a/datasource/etcd/util.go b/datasource/etcd/util.go
index cfb549d..497b69a 100644
--- a/datasource/etcd/util.go
+++ b/datasource/etcd/util.go
@@ -463,12 +463,12 @@ func toDependencyFilterOptions(in *pb.GetDependenciesRequest) (opts []serviceUti
return opts
}
-func checkQuota(ctx context.Context, domainProject string) *quota.ApplyQuotaResult {
+func checkQuota(ctx context.Context, domainProject string) *pb.Error {
if core.IsSCInstance(ctx) {
log.Debugf("skip quota check")
return nil
}
- res := quota.NewApplyQuotaResource(quota.MicroServiceQuotaType, domainProject, "", 1)
+ res := quota.NewApplyQuotaResource(quota.TypeService, domainProject, "", 1)
rst := quota.Apply(ctx, res)
return rst
}
diff --git a/datasource/etcd/util/microservice_util.go b/datasource/etcd/util/microservice_util.go
index 2d76525..d7c30ef 100644
--- a/datasource/etcd/util/microservice_util.go
+++ b/datasource/etcd/util/microservice_util.go
@@ -245,11 +245,11 @@ func GetAllServiceUtil(ctx context.Context) ([]*pb.MicroService, error) {
}
func RemandServiceQuota(ctx context.Context) {
- quota.Remand(ctx, quota.MicroServiceQuotaType)
+ quota.Remand(ctx, quota.TypeService)
}
func RemandInstanceQuota(ctx context.Context) {
- quota.Remand(ctx, quota.MicroServiceInstanceQuotaType)
+ quota.Remand(ctx, quota.TypeInstance)
}
func UpdateService(domainProject string, serviceID string, service *pb.MicroService) (opt client.PluginOp, err error) {
diff --git a/datasource/mongo/ms.go b/datasource/mongo/ms.go
index cbbbd78..f63dcac 100644
--- a/datasource/mongo/ms.go
+++ b/datasource/mongo/ms.go
@@ -835,9 +835,8 @@ func (ds *DataSource) modifySchemas(ctx context.Context, service *discovery.Micr
var serviceOps []mongo.WriteModel
if !ds.isSchemaEditable(service) {
if len(service.Schemas) == 0 {
- res := quota.NewApplyQuotaResource(quota.SchemaQuotaType, util.ParseDomainProject(ctx), serviceID, int64(len(nonExistSchemaIds)))
- rst := quota.Apply(ctx, res)
- errQuota := rst.Err
+ res := quota.NewApplyQuotaResource(quota.TypeSchema, util.ParseDomainProject(ctx), serviceID, int64(len(nonExistSchemaIds)))
+ errQuota := quota.Apply(ctx, res)
if errQuota != nil {
log.Error(fmt.Sprintf("modify service[%s] schemas failed, operator: %s", serviceID, remoteIP), errQuota)
return errQuota
@@ -877,9 +876,8 @@ func (ds *DataSource) modifySchemas(ctx context.Context, service *discovery.Micr
} else {
quotaSize := len(needAddSchemas) - len(needDeleteSchemas)
if quotaSize > 0 {
- res := quota.NewApplyQuotaResource(quota.SchemaQuotaType, util.ParseDomainProject(ctx), serviceID, int64(quotaSize))
- rst := quota.Apply(ctx, res)
- err := rst.Err
+ res := quota.NewApplyQuotaResource(quota.TypeSchema, util.ParseDomainProject(ctx), serviceID, int64(quotaSize))
+ err := quota.Apply(ctx, res)
if err != nil {
log.Error(fmt.Sprintf("modify service[%s] schemas failed, operator: %s", serviceID, remoteIP), err)
return err
@@ -1008,9 +1006,8 @@ func (ds *DataSource) AddRule(ctx context.Context, request *discovery.AddService
if !exist {
return &discovery.AddServiceRulesResponse{Response: discovery.CreateResponse(discovery.ErrServiceNotExists, "Service does not exist")}, nil
}
- res := quota.NewApplyQuotaResource(quota.RuleQuotaType, util.ParseDomainProject(ctx), request.ServiceId, int64(len(request.Rules)))
- rst := quota.Apply(ctx, res)
- errQuota := rst.Err
+ res := quota.NewApplyQuotaResource(quota.TypeRule, util.ParseDomainProject(ctx), request.ServiceId, int64(len(request.Rules)))
+ errQuota := quota.Apply(ctx, res)
if errQuota != nil {
log.Error(fmt.Sprintf("add service[%s] rule failed, operator: %s", request.ServiceId, remoteIP), errQuota)
response := &discovery.AddServiceRulesResponse{
diff --git a/etc/conf/app.conf b/etc/conf/app.conf
index d40cc50..c1d788d 100644
--- a/etc/conf/app.conf
+++ b/etc/conf/app.conf
@@ -93,15 +93,13 @@ cache_ttl = ""
# pluggable cipher
cipher_plugin = ""
-# suppot buildin, unlimit
+# suppot buildin
# in buildin mode(default): microservice capacity is 50000
# instance capacity is 150000
# schema capacity of single microservice is 100
# rule capacity of single microservice is 100
# tag capacity of single microservice is 100
-# in unlimit mode: all resource capacities are unlimited, including
-# microservices, instances, schemas, rules, tags
-quota_plugin = ""
+quota_plugin = "buildin"
#access control plugin
auth_plugin = ""
diff --git a/etc/conf/app.yaml b/etc/conf/app.yaml
index 4f21a9d..a3906bb 100644
--- a/etc/conf/app.yaml
+++ b/etc/conf/app.yaml
@@ -172,7 +172,7 @@ tracing:
rate:
quota:
- kind:
+ kind: buildin
syncer:
diff --git a/server/bootstrap/bootstrap.go b/server/bootstrap/bootstrap.go
index e42b4aa..6e00e8b 100644
--- a/server/bootstrap/bootstrap.go
+++ b/server/bootstrap/bootstrap.go
@@ -37,8 +37,6 @@ import (
//quota
_ "github.com/apache/servicecomb-service-center/server/plugin/quota/buildin"
- _ "github.com/apache/servicecomb-service-center/server/plugin/quota/unlimit"
-
//auth
_ "github.com/apache/servicecomb-service-center/server/plugin/auth/buildin"
diff --git a/server/plugin/quota/buildin/buildin.go b/server/plugin/quota/buildin/buildin.go
index 543d535..5b532ab 100644
--- a/server/plugin/quota/buildin/buildin.go
+++ b/server/plugin/quota/buildin/buildin.go
@@ -19,7 +19,6 @@ package buildin
import (
"context"
-
"github.com/apache/servicecomb-service-center/pkg/log"
mgr "github.com/apache/servicecomb-service-center/server/plugin"
"github.com/apache/servicecomb-service-center/server/plugin/quota"
@@ -40,14 +39,21 @@ func New() mgr.Instance {
type Quota struct {
}
-//申请配额sourceType serviceinstance servicetype
-func (q *Quota) Apply4Quotas(ctx context.Context, res *quota.ApplyQuotaResource) *quota.ApplyQuotaResult {
- df, ok := mgr.DynamicPluginFunc(quota.QUOTA, "Apply4Quotas").(func(context.Context, *quota.ApplyQuotaResource) *quota.ApplyQuotaResult)
- if ok {
- return df(ctx, res)
+func (q *Quota) GetQuota(t quota.ResourceType) int64 {
+ switch t {
+ case quota.TypeInstance:
+ return int64(quota.DefaultInstanceQuota)
+ case quota.TypeService:
+ return int64(quota.DefaultServiceQuota)
+ case quota.TypeRule:
+ return int64(quota.DefaultRuleQuota)
+ case quota.TypeSchema:
+ return int64(quota.DefaultSchemaQuota)
+ case quota.TypeTag:
+ return int64(quota.DefaultTagQuota)
+ default:
+ return 0
}
-
- return CommonQuotaCheck(ctx, res, resourceQuota(res.QuotaType), resourceLimitHandler)
}
//向配额中心上报配额使用量
diff --git a/server/plugin/quota/buildin/buildin_test.go b/server/plugin/quota/buildin/buildin_test.go
new file mode 100644
index 0000000..bc69e26
--- /dev/null
+++ b/server/plugin/quota/buildin/buildin_test.go
@@ -0,0 +1,62 @@
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership.
+// The ASF licenses this file to You under the Apache License, Version 2.0
+// (the "License"); you may not use this file except in compliance with
+// the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package buildin_test
+
+import (
+ "context"
+
+ "github.com/apache/servicecomb-service-center/datasource"
+ _ "github.com/apache/servicecomb-service-center/server/init"
+
+ _ "github.com/apache/servicecomb-service-center/server/bootstrap"
+ "github.com/apache/servicecomb-service-center/server/plugin/quota"
+ pb "github.com/go-chassis/cari/discovery"
+ "github.com/go-chassis/go-archaius"
+ "github.com/stretchr/testify/assert"
+ "testing"
+)
+
+func init() {
+ archaius.Set("registry.cache.mode", 0)
+ archaius.Set("discovery.kind", "etcd")
+ archaius.Set("registry.kind", "etcd")
+ err := datasource.Init(datasource.Options{Kind: "etcd"})
+ if err != nil {
+ panic(err)
+ }
+}
+func TestGetResourceLimit(t *testing.T) {
+ //var id string
+ t.Run("create service,should success", func(t *testing.T) {
+ res := quota.NewApplyQuotaResource(quota.TypeService, "default/default", "", 1)
+ err := quota.Apply(context.TODO(), res)
+ assert.Nil(t, err)
+ })
+ t.Run("create instance,should success", func(t *testing.T) {
+ resp, err := datasource.Instance().RegisterService(context.TODO(), &pb.CreateServiceRequest{
+ Service: &pb.MicroService{
+ ServiceName: "quota",
+ },
+ })
+ assert.NoError(t, err)
+ assert.Equal(t, pb.ResponseSuccess, resp.Response.GetCode())
+
+ res := quota.NewApplyQuotaResource(quota.TypeInstance, "default/default", resp.ServiceId, 1)
+ err = quota.Apply(context.TODO(), res)
+ assert.Nil(t, err)
+ })
+
+}
diff --git a/server/plugin/quota/buildin/common.go b/server/plugin/quota/buildin/common.go
deleted file mode 100644
index ca69707..0000000
--- a/server/plugin/quota/buildin/common.go
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package buildin
-
-import (
- "context"
- "errors"
- "fmt"
-
- "github.com/apache/servicecomb-service-center/datasource"
- "github.com/apache/servicecomb-service-center/pkg/log"
- "github.com/apache/servicecomb-service-center/pkg/metrics"
- "github.com/apache/servicecomb-service-center/server/plugin/quota"
- pb "github.com/go-chassis/cari/discovery"
-)
-
-const (
- TotalService = "db_service_total"
- TotalInstance = "db_instance_total"
-)
-
-type GetCurUsedNum func(context.Context, *quota.ApplyQuotaResource) (int64, error)
-type GetLimitQuota func() int64
-
-func CommonQuotaCheck(ctx context.Context, res *quota.ApplyQuotaResource,
- getLimitQuota GetLimitQuota, getCurUsedNum GetCurUsedNum) *quota.ApplyQuotaResult {
- if res == nil || getLimitQuota == nil || getCurUsedNum == nil {
- err := errors.New("invalid parameters")
- log.Errorf(err, "quota check failed")
- return quota.NewApplyQuotaResult(nil, pb.NewError(pb.ErrInternal, err.Error()))
- }
-
- limitQuota := getLimitQuota()
- curNum, err := getCurUsedNum(ctx, res)
- if err != nil {
- log.Errorf(err, "%s quota check failed", res.QuotaType)
- return quota.NewApplyQuotaResult(nil, pb.NewError(pb.ErrInternal, err.Error()))
- }
- if curNum+res.QuotaSize > limitQuota {
- mes := fmt.Sprintf("no quota to create %s, max num is %d, curNum is %d, apply num is %d",
- res.QuotaType, limitQuota, curNum, res.QuotaSize)
- log.Errorf(nil, mes)
- return quota.NewApplyQuotaResult(nil, pb.NewError(pb.ErrNotEnoughQuota, mes))
- }
- return quota.NewApplyQuotaResult(nil, nil)
-}
-
-func resourceQuota(t quota.ResourceType) GetLimitQuota {
- return func() int64 {
- switch t {
- case quota.MicroServiceInstanceQuotaType:
- return int64(quota.DefaultInstanceQuota)
- case quota.MicroServiceQuotaType:
- return int64(quota.DefaultServiceQuota)
- case quota.RuleQuotaType:
- return int64(quota.DefaultRuleQuota)
- case quota.SchemaQuotaType:
- return int64(quota.DefaultSchemaQuota)
- case quota.TagQuotaType:
- return int64(quota.DefaultTagQuota)
- default:
- return 0
- }
- }
-}
-
-func resourceLimitHandler(ctx context.Context, res *quota.ApplyQuotaResource) (int64, error) {
- serviceID := res.ServiceID
-
- switch res.QuotaType {
- case quota.MicroServiceQuotaType:
- return metrics.GaugeValue(TotalService, nil), nil
- case quota.MicroServiceInstanceQuotaType:
- return metrics.GaugeValue(TotalInstance, nil), nil
- case quota.RuleQuotaType:
- {
- resp, err := datasource.Instance().GetRules(ctx, &pb.GetServiceRulesRequest{
- ServiceId: serviceID,
- })
- if err != nil {
- return 0, err
- }
- return int64(len(resp.Rules)), nil
- }
- case quota.SchemaQuotaType:
- {
- resp, err := datasource.Instance().GetAllSchemas(ctx, &pb.GetAllSchemaRequest{
- ServiceId: serviceID,
- WithSchema: false,
- })
- if err != nil {
- return 0, err
- }
- return int64(len(resp.Schemas)), nil
- }
- case quota.TagQuotaType:
- // always re-create the service old tags
- return 0, nil
- default:
- return 0, fmt.Errorf("not define quota type '%s'", res.QuotaType)
- }
-}
diff --git a/server/plugin/quota/buildin/common_test.go b/server/plugin/quota/buildin/common_test.go
deleted file mode 100644
index 144a6ce..0000000
--- a/server/plugin/quota/buildin/common_test.go
+++ /dev/null
@@ -1,87 +0,0 @@
-// Licensed to the Apache Software Foundation (ASF) under one or more
-// contributor license agreements. See the NOTICE file distributed with
-// this work for additional information regarding copyright ownership.
-// The ASF licenses this file to You under the Apache License, Version 2.0
-// (the "License"); you may not use this file except in compliance with
-// the License. You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package buildin_test
-
-import (
- "context"
- "errors"
- "testing"
-
- "github.com/apache/servicecomb-service-center/server/plugin/quota"
- "github.com/apache/servicecomb-service-center/server/plugin/quota/buildin"
-)
-
-func TestCommonQuotaCheck(t *testing.T) {
- // case: invalid input
- rst := buildin.CommonQuotaCheck(context.Background(), nil, func() int64 {
- return 1
- }, func(ctx context.Context, resource *quota.ApplyQuotaResource) (int64, error) {
- return 0, nil
- })
- if rst.Err == nil || !rst.Err.InternalError() {
- t.Fatalf("TestCommonQuotaCheck failed")
- }
- rst = buildin.CommonQuotaCheck(context.Background(), "a.ApplyQuotaResource{}, nil, func(ctx context.Context, resource *quota.ApplyQuotaResource) (int64, error) {
- return 0, nil
- })
- if rst.Err == nil || !rst.Err.InternalError() {
- t.Fatalf("TestCommonQuotaCheck failed")
- }
- rst = buildin.CommonQuotaCheck(context.Background(), "a.ApplyQuotaResource{}, func() int64 {
- return 1
- }, nil)
- if rst.Err == nil || !rst.Err.InternalError() {
- t.Fatalf("TestCommonQuotaCheck failed")
- }
-
- // case: error
- rst = buildin.CommonQuotaCheck(context.Background(), "a.ApplyQuotaResource{
- QuotaType: quota.MicroServiceQuotaType,
- QuotaSize: 1,
- }, func() int64 {
- return 1
- }, func(_ context.Context, _ *quota.ApplyQuotaResource) (int64, error) {
- return 0, errors.New("error")
- })
- if rst.Err == nil || !rst.Err.InternalError() {
- t.Fatalf("TestCommonQuotaCheck failed %v", rst.Err)
- }
-
- // case: normal
- rst = buildin.CommonQuotaCheck(context.Background(), "a.ApplyQuotaResource{
- QuotaType: quota.MicroServiceQuotaType,
- QuotaSize: 1,
- }, func() int64 {
- return 1
- }, func(_ context.Context, _ *quota.ApplyQuotaResource) (int64, error) {
- return 0, nil
- })
- if rst.Err != nil {
- t.Fatalf("TestCommonQuotaCheck failed %v", rst.Err)
- }
-
- rst = buildin.CommonQuotaCheck(context.Background(), "a.ApplyQuotaResource{
- QuotaType: quota.MicroServiceQuotaType,
- QuotaSize: 1,
- }, func() int64 {
- return 1
- }, func(_ context.Context, _ *quota.ApplyQuotaResource) (int64, error) {
- return 1, nil
- })
- if rst.Err == nil || rst.Err.InternalError() {
- t.Fatalf("TestCommonQuotaCheck failed %v", rst.Err)
- }
-}
diff --git a/server/plugin/quota/quota.go b/server/plugin/quota/quota.go
index b64df94..58a194d 100644
--- a/server/plugin/quota/quota.go
+++ b/server/plugin/quota/quota.go
@@ -19,11 +19,18 @@ package quota
import (
"context"
+ "errors"
+ "fmt"
+ "github.com/apache/servicecomb-service-center/datasource"
+ "github.com/apache/servicecomb-service-center/pkg/log"
+ "github.com/apache/servicecomb-service-center/pkg/metrics"
+ "github.com/apache/servicecomb-service-center/pkg/util"
+ "github.com/prometheus/client_golang/prometheus"
"strconv"
"github.com/apache/servicecomb-service-center/server/config"
"github.com/apache/servicecomb-service-center/server/plugin"
- "github.com/go-chassis/cari/discovery"
+ pb "github.com/go-chassis/cari/discovery"
)
const QUOTA plugin.Kind = "quota"
@@ -37,11 +44,15 @@ const (
)
const (
- RuleQuotaType ResourceType = iota
- SchemaQuotaType
- TagQuotaType
- MicroServiceQuotaType
- MicroServiceInstanceQuotaType
+ TypeRule ResourceType = iota
+ TypeSchema
+ TypeTag
+ TypeService
+ TypeInstance
+)
+const (
+ TotalService = "db_service_total"
+ TotalInstance = "db_instance_total"
)
var (
@@ -60,33 +71,6 @@ func Init() {
DefaultRuleQuota = config.GetInt("quota.cap.rule", defaultRuleLimit, config.WithStandby("QUOTA_RULE"))
}
-type ApplyQuotaResult struct {
- Err *discovery.Error
-
- reporter Reporter
-}
-
-func (r *ApplyQuotaResult) ReportUsedQuota(ctx context.Context) error {
- if r == nil || r.reporter == nil {
- return nil
- }
- return r.reporter.ReportUsedQuota(ctx)
-}
-
-func (r *ApplyQuotaResult) Close(ctx context.Context) {
- if r == nil || r.reporter == nil {
- return
- }
- r.reporter.Close(ctx)
-}
-
-func NewApplyQuotaResult(reporter Reporter, err *discovery.Error) *ApplyQuotaResult {
- return &ApplyQuotaResult{
- reporter: reporter,
- Err: err,
- }
-}
-
type ApplyQuotaResource struct {
QuotaType ResourceType
DomainProject string
@@ -104,38 +88,87 @@ func NewApplyQuotaResource(quotaType ResourceType, domainProject, serviceID stri
}
type Manager interface {
- Apply4Quotas(ctx context.Context, res *ApplyQuotaResource) *ApplyQuotaResult
RemandQuotas(ctx context.Context, quotaType ResourceType)
-}
-
-type Reporter interface {
- ReportUsedQuota(ctx context.Context) error
- Close(ctx context.Context)
+ GetQuota(t ResourceType) int64
}
type ResourceType int
func (r ResourceType) String() string {
switch r {
- case RuleQuotaType:
+ case TypeRule:
return "RULE"
- case SchemaQuotaType:
+ case TypeSchema:
return "SCHEMA"
- case TagQuotaType:
+ case TypeTag:
return "TAG"
- case MicroServiceQuotaType:
+ case TypeService:
return "SERVICE"
- case MicroServiceInstanceQuotaType:
+ case TypeInstance:
return "INSTANCE"
default:
return "RESOURCE" + strconv.Itoa(int(r))
}
}
-func Apply(ctx context.Context, res *ApplyQuotaResource) *ApplyQuotaResult {
- return plugin.Plugins().Instance(QUOTA).(Manager).Apply4Quotas(ctx, res)
+//申请配额sourceType serviceinstance servicetype
+func Apply(ctx context.Context, res *ApplyQuotaResource) *pb.Error {
+ if res == nil {
+ err := errors.New("invalid parameters")
+ log.Errorf(err, "quota check failed")
+ return pb.NewError(pb.ErrInternal, err.Error())
+ }
+
+ limitQuota := plugin.Plugins().Instance(QUOTA).(Manager).GetQuota(res.QuotaType)
+ curNum, err := GetResourceUsage(ctx, res)
+ if err != nil {
+ log.Errorf(err, "%s quota check failed", res.QuotaType)
+ return pb.NewError(pb.ErrInternal, err.Error())
+ }
+ if curNum+res.QuotaSize > limitQuota {
+ mes := fmt.Sprintf("no quota to create %s, max num is %d, curNum is %d, apply num is %d",
+ res.QuotaType, limitQuota, curNum, res.QuotaSize)
+ log.Errorf(nil, mes)
+ return pb.NewError(pb.ErrNotEnoughQuota, mes)
+ }
+ return nil
}
func Remand(ctx context.Context, quotaType ResourceType) {
plugin.Plugins().Instance(QUOTA).(Manager).RemandQuotas(ctx, quotaType)
}
+func GetResourceUsage(ctx context.Context, res *ApplyQuotaResource) (int64, error) {
+ serviceID := res.ServiceID
+ switch res.QuotaType {
+ case TypeService:
+ return metrics.GaugeValue(TotalService, prometheus.Labels{"domain": util.ParseDomain(ctx)}), nil
+ case TypeInstance:
+ return metrics.GaugeValue(TotalInstance, prometheus.Labels{"domain": util.ParseDomain(ctx)}), nil
+ case TypeRule:
+ {
+ resp, err := datasource.Instance().GetRules(ctx, &pb.GetServiceRulesRequest{
+ ServiceId: serviceID,
+ })
+ if err != nil {
+ return 0, err
+ }
+ return int64(len(resp.Rules)), nil
+ }
+ case TypeSchema:
+ {
+ resp, err := datasource.Instance().GetAllSchemas(ctx, &pb.GetAllSchemaRequest{
+ ServiceId: serviceID,
+ WithSchema: false,
+ })
+ if err != nil {
+ return 0, err
+ }
+ return int64(len(resp.Schemas)), nil
+ }
+ case TypeTag:
+ // always re-create the service old tags
+ return 0, nil
+ default:
+ return 0, fmt.Errorf("not define quota type '%s'", res.QuotaType)
+ }
+}
diff --git a/server/plugin/quota/unlimit/unlimit.go b/server/plugin/quota/unlimit/unlimit.go
deleted file mode 100644
index 4f9a8a9..0000000
--- a/server/plugin/quota/unlimit/unlimit.go
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package unlimit
-
-import (
- "context"
-
- "github.com/apache/servicecomb-service-center/pkg/log"
- mgr "github.com/apache/servicecomb-service-center/server/plugin"
- "github.com/apache/servicecomb-service-center/server/plugin/quota"
-)
-
-func init() {
- mgr.RegisterPlugin(mgr.Plugin{Kind: quota.QUOTA, Name: "unlimit", New: New})
-}
-
-type Unlimit struct {
-}
-
-func New() mgr.Instance {
- log.Warnf("quota init, all resources are unlimited")
- return &Unlimit{}
-}
-
-func (q *Unlimit) Apply4Quotas(ctx context.Context, res *quota.ApplyQuotaResource) *quota.ApplyQuotaResult {
- return quota.NewApplyQuotaResult(nil, nil)
-}
-
-func (q *Unlimit) RemandQuotas(ctx context.Context, quotaType quota.ResourceType) {
-}
diff --git a/server/service/schema.go b/server/service/schema.go
index a4b63d9..e139e7e 100644
--- a/server/service/schema.go
+++ b/server/service/schema.go
@@ -129,9 +129,8 @@ func (s *MicroServiceService) canModifySchema(ctx context.Context, domainProject
return pb.NewError(pb.ErrInvalidParams, err.Error())
}
- res := quota.NewApplyQuotaResource(quota.SchemaQuotaType, domainProject, serviceID, 1)
- rst := quota.Apply(ctx, res)
- errQuota := rst.Err
+ res := quota.NewApplyQuotaResource(quota.TypeSchema, domainProject, serviceID, 1)
+ errQuota := quota.Apply(ctx, res)
if errQuota != nil {
log.Errorf(errQuota, "update schema[%s/%s] failed, operator: %s", serviceID, schemaID, remoteIP)
return errQuota