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(), &quota.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(), &quota.ApplyQuotaResource{}, func() int64 {
-		return 1
-	}, nil)
-	if rst.Err == nil || !rst.Err.InternalError() {
-		t.Fatalf("TestCommonQuotaCheck failed")
-	}
-
-	// case: error
-	rst = buildin.CommonQuotaCheck(context.Background(), &quota.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(), &quota.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(), &quota.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