This is an automated email from the ASF dual-hosted git repository.

littlecui 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 3147e0b  [SCB-2094] Move the service/util package (#727)
3147e0b is described below

commit 3147e0b600f59e51c685d99e8aa335e246fd1047
Author: robotLJW <[email protected]>
AuthorDate: Fri Oct 23 14:47:31 2020 +0800

    [SCB-2094] Move the service/util package (#727)
    
    1. move the service/util package to the datasource/etcd/util  directory
    
    2. adjust the reference to service/util package
---
 datasource/etcd/account.go                         |   2 +-
 datasource/etcd/dep.go                             |   2 +-
 datasource/etcd/ms.go                              |   5 +-
 datasource/etcd/util.go                            |   2 +-
 datasource/etcd/util/dependency.go                 | 132 ++++++
 datasource/etcd/util/dependency_query.go           | 366 +++++++++++++++
 datasource/etcd/util/dependency_test.go            | 294 ++++++++++++
 datasource/etcd/util/dependency_util.go            | 514 +++++++++++++++++++++
 datasource/etcd/util/domain_util.go                | 127 +++++
 datasource/etcd/util/domain_util_test.go           |  84 ++++
 datasource/etcd/util/heartbeat_util.go             |  53 +++
 .../etcd/util/heartbeat_util_test.go               |  25 +-
 datasource/etcd/util/instance_util.go              | 276 +++++++++++
 datasource/etcd/util/instance_util_test.go         | 170 +++++++
 datasource/etcd/util/microservice_util.go          | 310 +++++++++++++
 datasource/etcd/util/rule_util.go                  | 300 ++++++++++++
 datasource/etcd/util/rule_util_test.go             | 306 ++++++++++++
 .../etcd/util/schema_util.go                       |  30 +-
 .../etcd/util/schema_util_test.go                  |  13 +-
 datasource/etcd/util/tag_util.go                   |  67 +++
 .../etcd/util/tag_util_test.go                     |  18 +-
 .../tracing.go => datasource/etcd/util/util.go     |  31 +-
 datasource/etcd/util/util_suite_test.go            | 140 ++++++
 datasource/etcd/util/versionrule.go                | 264 +++++++++++
 datasource/etcd/util/versionrule_test.go           | 413 +++++++++++++++++
 pkg/chain/chain_test.go                            |  16 +-
 pkg/chain/invocation.go                            |   2 +-
 pkg/rest/common.go                                 |  10 +-
 pkg/util/common.go                                 |  14 +-
 pkg/util/context.go                                |  10 +-
 pkg/util/context_grpc.go                           |   4 +-
 server/handler/cache/cache.go                      |  12 +-
 server/plugin/tracing/pzipkin/buildin.go           |   2 +-
 server/plugin/tracing/tracing.go                   |   3 +-
 server/plugin/uuid/uuid.go                         |   4 +-
 server/rest/handler.go                             |   2 +-
 36 files changed, 3934 insertions(+), 89 deletions(-)

diff --git a/datasource/etcd/account.go b/datasource/etcd/account.go
index 68fbada..486b6b4 100644
--- a/datasource/etcd/account.go
+++ b/datasource/etcd/account.go
@@ -18,11 +18,11 @@ package etcd
 import (
        "context"
        "encoding/json"
+       utils 
"github.com/apache/servicecomb-service-center/datasource/etcd/util"
        "github.com/apache/servicecomb-service-center/pkg/log"
        "github.com/apache/servicecomb-service-center/pkg/rbacframe"
        "github.com/apache/servicecomb-service-center/server/core/backend"
        "github.com/apache/servicecomb-service-center/server/plugin/registry"
-       utils "github.com/apache/servicecomb-service-center/server/service/util"
 )
 
 func (ds *DataSource) AccountExist(ctx context.Context, key string) (bool, 
error) {
diff --git a/datasource/etcd/dep.go b/datasource/etcd/dep.go
index 5e04fd4..36c6666 100644
--- a/datasource/etcd/dep.go
+++ b/datasource/etcd/dep.go
@@ -21,6 +21,7 @@ import (
        "context"
        "encoding/json"
        "fmt"
+       serviceUtil 
"github.com/apache/servicecomb-service-center/datasource/etcd/util"
        "github.com/apache/servicecomb-service-center/pkg/log"
        pb "github.com/apache/servicecomb-service-center/pkg/registry"
        "github.com/apache/servicecomb-service-center/pkg/util"
@@ -29,7 +30,6 @@ import (
        "github.com/apache/servicecomb-service-center/server/core/proto"
        "github.com/apache/servicecomb-service-center/server/plugin/registry"
        scerr "github.com/apache/servicecomb-service-center/server/scerror"
-       serviceUtil 
"github.com/apache/servicecomb-service-center/server/service/util"
 )
 
 func (ds *DataSource) SearchProviderDependency(ctx context.Context, request 
*pb.GetDependenciesRequest) ([]*pb.MicroService, error) {
diff --git a/datasource/etcd/ms.go b/datasource/etcd/ms.go
index 7f26e45..b7d29f3 100644
--- a/datasource/etcd/ms.go
+++ b/datasource/etcd/ms.go
@@ -22,6 +22,7 @@ import (
        "encoding/json"
        "errors"
        "fmt"
+       serviceUtil 
"github.com/apache/servicecomb-service-center/datasource/etcd/util"
        "github.com/apache/servicecomb-service-center/pkg/gopool"
        "github.com/apache/servicecomb-service-center/pkg/log"
        pb "github.com/apache/servicecomb-service-center/pkg/registry"
@@ -35,7 +36,6 @@ import (
        "github.com/apache/servicecomb-service-center/server/plugin/registry"
        scerr "github.com/apache/servicecomb-service-center/server/scerror"
        "github.com/apache/servicecomb-service-center/server/service/cache"
-       serviceUtil 
"github.com/apache/servicecomb-service-center/server/service/util"
        "sort"
        "strconv"
        "time"
@@ -928,8 +928,7 @@ func (ds *DataSource) reshapeProviderKey(ctx 
context.Context, provider *pb.Micro
        return provider, nil
 }
 
-func (ds *DataSource) UpdateInstanceStatus(ctx context.Context, request 
*pb.UpdateInstanceStatusRequest) (*pb.
-       UpdateInstanceStatusResponse, error) {
+func (ds *DataSource) UpdateInstanceStatus(ctx context.Context, request 
*pb.UpdateInstanceStatusRequest) (*pb.UpdateInstanceStatusResponse, error) {
        domainProject := util.ParseDomainProject(ctx)
        updateStatusFlag := util.StringJoin([]string{request.ServiceId, 
request.InstanceId, request.Status}, "/")
 
diff --git a/datasource/etcd/util.go b/datasource/etcd/util.go
index a9f1c3e..d4eb76e 100644
--- a/datasource/etcd/util.go
+++ b/datasource/etcd/util.go
@@ -20,6 +20,7 @@ package etcd
 import (
        "context"
        "encoding/json"
+       serviceUtil 
"github.com/apache/servicecomb-service-center/datasource/etcd/util"
        errorsEx "github.com/apache/servicecomb-service-center/pkg/errors"
        "github.com/apache/servicecomb-service-center/pkg/gopool"
        "github.com/apache/servicecomb-service-center/pkg/log"
@@ -32,7 +33,6 @@ import (
        "github.com/apache/servicecomb-service-center/server/plugin/registry"
        "github.com/apache/servicecomb-service-center/server/plugin/uuid"
        scerr "github.com/apache/servicecomb-service-center/server/scerror"
-       serviceUtil 
"github.com/apache/servicecomb-service-center/server/service/util"
        "strconv"
        "strings"
        "time"
diff --git a/datasource/etcd/util/dependency.go 
b/datasource/etcd/util/dependency.go
new file mode 100644
index 0000000..0b13d99
--- /dev/null
+++ b/datasource/etcd/util/dependency.go
@@ -0,0 +1,132 @@
+/*
+ * 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 util
+
+import (
+       "context"
+       "encoding/json"
+
+       "github.com/apache/servicecomb-service-center/pkg/log"
+       rmodel "github.com/apache/servicecomb-service-center/pkg/registry"
+       apt "github.com/apache/servicecomb-service-center/server/core"
+       "github.com/apache/servicecomb-service-center/server/core/backend"
+       "github.com/apache/servicecomb-service-center/server/plugin/registry"
+)
+
+// Dependency contains dependency rules
+type Dependency struct {
+       DomainProject string
+       // store the consumer Dependency from dep-queue object
+       Consumer      *rmodel.MicroServiceKey
+       ProvidersRule []*rmodel.MicroServiceKey
+       // store the parsed rules from Dependency object
+       DeleteDependencyRuleList []*rmodel.MicroServiceKey
+       CreateDependencyRuleList []*rmodel.MicroServiceKey
+}
+
+func (dep *Dependency) removeConsumerOfProviderRule(ctx context.Context) 
([]registry.PluginOp, error) {
+       opts := make([]registry.PluginOp, 0, len(dep.DeleteDependencyRuleList))
+       for _, providerRule := range dep.DeleteDependencyRuleList {
+               proProkey := 
apt.GenerateProviderDependencyRuleKey(providerRule.Tenant, providerRule)
+               log.Debugf("This proProkey is %s", proProkey)
+               consumerValue, err := TransferToMicroServiceDependency(ctx, 
proProkey)
+               if err != nil {
+                       return nil, err
+               }
+               for key, tmp := range consumerValue.Dependency {
+                       if ok := equalServiceDependency(tmp, dep.Consumer); ok {
+                               consumerValue.Dependency = 
append(consumerValue.Dependency[:key], consumerValue.Dependency[key+1:]...)
+                               break
+                       }
+                       log.Debugf("tmp and dep.Consumer not equal, tmp %v, 
consumer %v", tmp, dep.Consumer)
+               }
+               //删除后,如果不存在依赖规则了,就删除该provider的依赖规则,如果有,则更新该依赖规则
+               if len(consumerValue.Dependency) == 0 {
+                       opts = append(opts, 
registry.OpDel(registry.WithStrKey(proProkey)))
+                       continue
+               }
+               data, err := json.Marshal(consumerValue)
+               if err != nil {
+                       log.Errorf(err, "Marshal MicroServiceDependency failed")
+                       return nil, err
+               }
+               opts = append(opts, registry.OpPut(
+                       registry.WithStrKey(proProkey),
+                       registry.WithValue(data)))
+       }
+       return opts, nil
+}
+
+func (dep *Dependency) addConsumerOfProviderRule(ctx context.Context) 
([]registry.PluginOp, error) {
+       opts := make([]registry.PluginOp, 0, len(dep.CreateDependencyRuleList))
+       for _, providerRule := range dep.CreateDependencyRuleList {
+               proProkey := 
apt.GenerateProviderDependencyRuleKey(providerRule.Tenant, providerRule)
+               tmpValue, err := TransferToMicroServiceDependency(ctx, 
proProkey)
+               if err != nil {
+                       return nil, err
+               }
+               tmpValue.Dependency = append(tmpValue.Dependency, dep.Consumer)
+
+               data, errMarshal := json.Marshal(tmpValue)
+               if errMarshal != nil {
+                       log.Errorf(errMarshal, "Marshal MicroServiceDependency 
failed")
+                       return nil, errMarshal
+               }
+               opts = append(opts, registry.OpPut(
+                       registry.WithStrKey(proProkey),
+                       registry.WithValue(data)))
+               if providerRule.ServiceName == "*" {
+                       break
+               }
+       }
+       return opts, nil
+}
+
+func (dep *Dependency) updateProvidersRuleOfConsumer(_ context.Context) 
([]registry.PluginOp, error) {
+       conKey := apt.GenerateConsumerDependencyRuleKey(dep.DomainProject, 
dep.Consumer)
+       if len(dep.ProvidersRule) == 0 {
+               return 
[]registry.PluginOp{registry.OpDel(registry.WithStrKey(conKey))}, nil
+       }
+
+       dependency := &rmodel.MicroServiceDependency{
+               Dependency: dep.ProvidersRule,
+       }
+       data, err := json.Marshal(dependency)
+       if err != nil {
+               log.Errorf(err, "Marshal MicroServiceDependency failed")
+               return nil, err
+       }
+       return []registry.PluginOp{registry.OpPut(registry.WithStrKey(conKey), 
registry.WithValue(data))}, nil
+}
+
+// Commit is dependent rule operations
+func (dep *Dependency) Commit(ctx context.Context) error {
+       dopts, err := dep.removeConsumerOfProviderRule(ctx)
+       if err != nil {
+               return err
+       }
+       copts, err := dep.addConsumerOfProviderRule(ctx)
+       if err != nil {
+               return err
+       }
+       uopts, err := dep.updateProvidersRuleOfConsumer(ctx)
+       if err != nil {
+               return err
+       }
+       return backend.BatchCommit(ctx, append(append(dopts, copts...), 
uopts...))
+}
diff --git a/datasource/etcd/util/dependency_query.go 
b/datasource/etcd/util/dependency_query.go
new file mode 100644
index 0000000..0bdf296
--- /dev/null
+++ b/datasource/etcd/util/dependency_query.go
@@ -0,0 +1,366 @@
+/*
+ * 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 util
+
+import (
+       "context"
+       "fmt"
+       "strings"
+
+       "github.com/apache/servicecomb-service-center/pkg/log"
+       pb "github.com/apache/servicecomb-service-center/pkg/registry"
+       "github.com/apache/servicecomb-service-center/pkg/util"
+       apt "github.com/apache/servicecomb-service-center/server/core"
+       "github.com/apache/servicecomb-service-center/server/core/backend"
+       "github.com/apache/servicecomb-service-center/server/core/proto"
+       "github.com/apache/servicecomb-service-center/server/plugin/registry"
+)
+
+// DependencyRelationFilterOpt contains SameDomainProject and NonSelf flag
+type DependencyRelationFilterOpt struct {
+       SameDomainProject bool
+       NonSelf           bool
+}
+
+type DependencyRelationFilterOption func(opt DependencyRelationFilterOpt) 
DependencyRelationFilterOpt
+
+func WithSameDomainProject() DependencyRelationFilterOption {
+       return func(opt DependencyRelationFilterOpt) 
DependencyRelationFilterOpt {
+               opt.SameDomainProject = true
+               return opt
+       }
+}
+func WithoutSelfDependency() DependencyRelationFilterOption {
+       return func(opt DependencyRelationFilterOpt) 
DependencyRelationFilterOpt {
+               opt.NonSelf = true
+               return opt
+       }
+}
+
+func toDependencyRelationFilterOpt(opts ...DependencyRelationFilterOption) (op 
DependencyRelationFilterOpt) {
+       for _, opt := range opts {
+               op = opt(op)
+       }
+       return
+}
+
+type DependencyRelation struct {
+       ctx           context.Context
+       domainProject string
+       consumer      *pb.MicroService
+       provider      *pb.MicroService
+}
+
+func (dr *DependencyRelation) GetDependencyProviders(opts 
...DependencyRelationFilterOption) ([]*pb.MicroService, error) {
+       keys, err := dr.getProviderKeys()
+       if err != nil {
+               return nil, err
+       }
+       services := make([]*pb.MicroService, 0, len(keys))
+       op := toDependencyRelationFilterOpt(opts...)
+       for _, key := range keys {
+               if op.SameDomainProject && key.Tenant != dr.domainProject {
+                       continue
+               }
+
+               providerIDs, err := dr.parseDependencyRule(key)
+               if err != nil {
+                       return nil, err
+               }
+
+               if key.ServiceName == "*" {
+                       services = services[:0]
+               }
+
+               for _, providerID := range providerIDs {
+                       provider, err := GetService(dr.ctx, key.Tenant, 
providerID)
+                       if err != nil {
+                               log.Warnf("get provider[%s/%s/%s/%s] failed",
+                                       key.Environment, key.AppId, 
key.ServiceName, key.Version)
+                               continue
+                       }
+                       if provider == nil {
+                               log.Warnf("provider[%s/%s/%s/%s] does not 
exist",
+                                       key.Environment, key.AppId, 
key.ServiceName, key.Version)
+                               continue
+                       }
+                       if op.NonSelf && providerID == dr.consumer.ServiceId {
+                               continue
+                       }
+                       services = append(services, provider)
+               }
+
+               if key.ServiceName == "*" {
+                       break
+               }
+       }
+       return services, nil
+}
+
+func (dr *DependencyRelation) GetDependencyProviderIds() ([]string, error) {
+       keys, err := dr.getProviderKeys()
+       if err != nil {
+               return nil, err
+       }
+       return dr.getDependencyProviderIds(keys)
+}
+
+func (dr *DependencyRelation) getProviderKeys() ([]*pb.MicroServiceKey, error) 
{
+       if dr.consumer == nil {
+               return nil, fmt.Errorf("Invalid consumer")
+       }
+       consumerMicroServiceKey := proto.MicroServiceToKey(dr.domainProject, 
dr.consumer)
+
+       conKey := apt.GenerateConsumerDependencyRuleKey(dr.domainProject, 
consumerMicroServiceKey)
+       consumerDependency, err := TransferToMicroServiceDependency(dr.ctx, 
conKey)
+       if err != nil {
+               return nil, err
+       }
+       return consumerDependency.Dependency, nil
+}
+
+func (dr *DependencyRelation) getDependencyProviderIds(providerRules 
[]*pb.MicroServiceKey) ([]string, error) {
+       provideServiceIds := make([]string, 0, len(providerRules))
+       for _, provider := range providerRules {
+               serviceIDs, err := dr.parseDependencyRule(provider)
+               switch {
+               case provider.ServiceName == "*":
+                       if err != nil {
+                               log.Errorf(err, "get all serviceIDs failed")
+                               return provideServiceIds, err
+                       }
+                       return serviceIDs, nil
+               default:
+                       if err != nil {
+                               log.Errorf(err, "get service[%s/%s/%s/%s]'s 
providerIDs failed",
+                                       provider.Environment, provider.AppId, 
provider.ServiceName, provider.Version)
+                               return provideServiceIds, err
+                       }
+                       if len(serviceIDs) == 0 {
+                               log.Warnf("get service[%s/%s/%s/%s]'s 
providerIDs is empty",
+                                       provider.Environment, provider.AppId, 
provider.ServiceName, provider.Version)
+                               continue
+                       }
+                       provideServiceIds = append(provideServiceIds, 
serviceIDs...)
+               }
+       }
+       return provideServiceIds, nil
+}
+
+func (dr *DependencyRelation) parseDependencyRule(dependencyRule 
*pb.MicroServiceKey) (serviceIDs []string, err error) {
+       opts := FromContext(dr.ctx)
+       switch {
+       case dependencyRule.ServiceName == "*":
+               log.Infof("service[%s/%s/%s/%s] rely all service",
+                       dr.consumer.Environment, dr.consumer.AppId, 
dr.consumer.ServiceName, dr.consumer.Version)
+               splited := 
strings.Split(apt.GenerateServiceIndexKey(dependencyRule), "/")
+               allServiceKey := util.StringJoin(splited[:len(splited)-3], "/") 
+ "/"
+               sopts := append(opts,
+                       registry.WithStrKey(allServiceKey),
+                       registry.WithPrefix())
+               resp, err := backend.Store().ServiceIndex().Search(dr.ctx, 
sopts...)
+               if err != nil {
+                       return nil, err
+               }
+
+               for _, kv := range resp.Kvs {
+                       serviceIDs = append(serviceIDs, kv.Value.(string))
+               }
+       default:
+               serviceIDs, _, err = FindServiceIds(dr.ctx, 
dependencyRule.Version, dependencyRule)
+       }
+       return
+}
+
+func (dr *DependencyRelation) GetDependencyConsumers(opts 
...DependencyRelationFilterOption) ([]*pb.MicroService, error) {
+       consumerDependAllList, err := dr.getDependencyConsumersOfProvider()
+       if err != nil {
+               log.Errorf(err, "get service[%s]'s consumers failed", 
dr.provider.ServiceId)
+               return nil, err
+       }
+       consumers := make([]*pb.MicroService, 0)
+       op := toDependencyRelationFilterOpt(opts...)
+       for _, consumer := range consumerDependAllList {
+               if op.SameDomainProject && consumer.Tenant != dr.domainProject {
+                       continue
+               }
+
+               service, err := dr.getServiceByMicroServiceKey(consumer)
+               if err != nil {
+                       return nil, err
+               }
+               if service == nil {
+                       log.Warnf("consumer[%s/%s/%s/%s] does not exist",
+                               consumer.Environment, consumer.AppId, 
consumer.ServiceName, consumer.Version)
+                       continue
+               }
+
+               if op.NonSelf && service.ServiceId == dr.provider.ServiceId {
+                       continue
+               }
+
+               consumers = append(consumers, service)
+       }
+       return consumers, nil
+}
+
+func (dr *DependencyRelation) getServiceByMicroServiceKey(service 
*pb.MicroServiceKey) (*pb.MicroService, error) {
+       serviceID, err := GetServiceID(dr.ctx, service)
+       if err != nil {
+               return nil, err
+       }
+       if len(serviceID) == 0 {
+               log.Warnf("service[%s/%s/%s/%s] not exist",
+                       service.Environment, service.AppId, 
service.ServiceName, service.Version)
+               return nil, nil
+       }
+       return GetService(dr.ctx, service.Tenant, serviceID)
+}
+
+func (dr *DependencyRelation) GetDependencyConsumerIds() ([]string, error) {
+       consumerDependAllList, err := dr.getDependencyConsumersOfProvider()
+       if err != nil {
+               return nil, err
+       }
+       consumerIDs := make([]string, 0, len(consumerDependAllList))
+       for _, consumer := range consumerDependAllList {
+               consumerID, err := GetServiceID(dr.ctx, consumer)
+               if err != nil {
+                       log.Errorf(err, "get consumer[%s/%s/%s/%s] failed",
+                               consumer.Environment, consumer.AppId, 
consumer.ServiceName, consumer.Version)
+                       return nil, err
+               }
+               if len(consumerID) == 0 {
+                       log.Warnf("get consumer[%s/%s/%s/%s] not exist",
+                               consumer.Environment, consumer.AppId, 
consumer.ServiceName, consumer.Version)
+                       continue
+               }
+               consumerIDs = append(consumerIDs, consumerID)
+       }
+       return consumerIDs, nil
+
+}
+
+func (dr *DependencyRelation) getDependencyConsumersOfProvider() 
([]*pb.MicroServiceKey, error) {
+       if dr.provider == nil {
+               return nil, fmt.Errorf("Invalid provider")
+       }
+       providerService := proto.MicroServiceToKey(dr.domainProject, 
dr.provider)
+       consumerDependAllList, err := dr.getConsumerOfDependAllServices()
+       if err != nil {
+               log.Errorf(err, "get consumers that depend on all services 
failed, %s", dr.provider.ServiceId)
+               return nil, err
+       }
+
+       consumerDependList, err := 
dr.getConsumerOfSameServiceNameAndAppID(providerService)
+       if err != nil {
+               log.Errorf(err, "get consumers that depend on rule[%s/%s/%s/%s] 
failed",
+                       dr.provider.Environment, dr.provider.AppId, 
dr.provider.ServiceName, dr.provider.Version)
+               return nil, err
+       }
+       consumerDependAllList = append(consumerDependAllList, 
consumerDependList...)
+       return consumerDependAllList, nil
+}
+
+func (dr *DependencyRelation) getConsumerOfDependAllServices() 
([]*pb.MicroServiceKey, error) {
+       providerService := proto.MicroServiceToKey(dr.domainProject, 
dr.provider)
+       providerService.ServiceName = "*"
+       relyAllKey := apt.GenerateProviderDependencyRuleKey(dr.domainProject, 
providerService)
+       opts := append(FromContext(dr.ctx), registry.WithStrKey(relyAllKey))
+       rsp, err := backend.Store().DependencyRule().Search(dr.ctx, opts...)
+       if err != nil {
+               log.Errorf(err, "get consumers that rely all service failed, 
%s/%s/%s/%s",
+                       dr.provider.Environment, dr.provider.AppId, 
dr.provider.ServiceName, dr.provider.Version)
+               return nil, err
+       }
+       if len(rsp.Kvs) != 0 {
+               log.Infof("exist consumers that rely all service, %s/%s/%s/%s",
+                       dr.provider.Environment, dr.provider.AppId, 
dr.provider.ServiceName, dr.provider.Version)
+               return 
rsp.Kvs[0].Value.(*pb.MicroServiceDependency).Dependency, nil
+       }
+       return nil, nil
+}
+
+func (dr *DependencyRelation) getConsumerOfSameServiceNameAndAppID(provider 
*pb.MicroServiceKey) ([]*pb.MicroServiceKey, error) {
+       providerVersion := provider.Version
+       provider.Version = ""
+       prefix := apt.GenerateProviderDependencyRuleKey(dr.domainProject, 
provider)
+       provider.Version = providerVersion
+
+       opts := append(FromContext(dr.ctx),
+               registry.WithStrKey(prefix),
+               registry.WithPrefix())
+       rsp, err := backend.Store().DependencyRule().Search(dr.ctx, opts...)
+       if err != nil {
+               log.Errorf(err, "get service[%s/%s/%s]'s dependency rules 
failed",
+                       provider.Environment, provider.AppId, 
provider.ServiceName)
+               return nil, err
+       }
+
+       allConsumers := make([]*pb.MicroServiceKey, 0, len(rsp.Kvs))
+       var latestServiceID []string
+
+       for _, kv := range rsp.Kvs {
+               providerVersionRuleArr := 
strings.Split(util.BytesToStringWithNoCopy(kv.Key), "/")
+               providerVersionRule := 
providerVersionRuleArr[len(providerVersionRuleArr)-1]
+               if providerVersionRule == "latest" {
+                       if latestServiceID == nil {
+                               latestServiceID, _, err = 
FindServiceIds(dr.ctx, providerVersionRule, provider)
+                               if err != nil {
+                                       log.Errorf(err, "get 
service[%s/%s/%s/%s]'s serviceID failed",
+                                               provider.Environment, 
provider.AppId, provider.ServiceName, providerVersionRule)
+                                       return nil, err
+                               }
+                       }
+                       if len(latestServiceID) == 0 {
+                               log.Infof("service[%s/%s/%s/%s] does not exist",
+                                       provider.Environment, provider.AppId, 
provider.ServiceName, providerVersionRule)
+                               continue
+                       }
+                       if dr.provider.ServiceId != latestServiceID[0] {
+                               continue
+                       }
+
+               } else {
+                       if !VersionMatchRule(providerVersion, 
providerVersionRule) {
+                               continue
+                       }
+               }
+
+               log.Debugf("providerETCD is %s", providerVersionRuleArr)
+               allConsumers = append(allConsumers, 
kv.Value.(*pb.MicroServiceDependency).Dependency...)
+       }
+       return allConsumers, nil
+}
+
+func NewProviderDependencyRelation(ctx context.Context, domainProject string, 
provider *pb.MicroService) *DependencyRelation {
+       return NewDependencyRelation(ctx, domainProject, nil, provider)
+}
+
+func NewConsumerDependencyRelation(ctx context.Context, domainProject string, 
consumer *pb.MicroService) *DependencyRelation {
+       return NewDependencyRelation(ctx, domainProject, consumer, nil)
+}
+
+func NewDependencyRelation(ctx context.Context, domainProject string, consumer 
*pb.MicroService, provider *pb.MicroService) *DependencyRelation {
+       return &DependencyRelation{
+               ctx:           ctx,
+               domainProject: domainProject,
+               consumer:      consumer,
+               provider:      provider,
+       }
+}
diff --git a/datasource/etcd/util/dependency_test.go 
b/datasource/etcd/util/dependency_test.go
new file mode 100644
index 0000000..acf50a0
--- /dev/null
+++ b/datasource/etcd/util/dependency_test.go
@@ -0,0 +1,294 @@
+/*
+ * 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 util
+
+import (
+       "context"
+       "testing"
+
+       "github.com/apache/servicecomb-service-center/pkg/registry"
+)
+
+func TestDeleteDependencyForService(t *testing.T) {
+       _, err := DeleteDependencyForDeleteService("", "", 
&registry.MicroServiceKey{})
+       if err != nil {
+               t.Fatalf(`DeleteDependencyForDeleteService failed`)
+       }
+}
+
+func TestTransferToMicroServiceDependency(t *testing.T) {
+       _, err := TransferToMicroServiceDependency(context.Background(), "")
+       if err == nil {
+               t.Fatalf(`TransferToMicroServiceDependency failed`)
+       }
+}
+
+func TestEqualServiceDependency(t *testing.T) {
+       b := equalServiceDependency(&registry.MicroServiceKey{}, 
&registry.MicroServiceKey{})
+       if !b {
+               t.Fatalf(`equalServiceDependency failed`)
+       }
+
+       b = equalServiceDependency(&registry.MicroServiceKey{
+               AppId: "a",
+       }, &registry.MicroServiceKey{
+               AppId: "b",
+       })
+       if b {
+               t.Fatalf(`equalServiceDependency failed`)
+       }
+}
+
+func TestCreateDependencyRule(t *testing.T) {
+       err := CreateDependencyRule(context.Background(), &Dependency{
+               Consumer: &registry.MicroServiceKey{},
+       })
+       if err != nil {
+               t.Fatalf(`CreateDependencyRule failed`)
+       }
+
+       err = AddDependencyRule(context.Background(), &Dependency{
+               Consumer: &registry.MicroServiceKey{},
+       })
+       if err != nil {
+               t.Fatalf(`AddDependencyRule failed`)
+       }
+
+       err = AddServiceVersionRule(context.Background(), "", 
&registry.MicroService{}, &registry.MicroServiceKey{})
+       if err != nil {
+               t.Fatalf(`AddServiceVersionRule failed`)
+       }
+
+       b, err := containServiceDependency([]*registry.MicroServiceKey{
+               {AppId: "a"},
+       }, &registry.MicroServiceKey{
+               AppId: "b",
+       })
+       if b {
+               t.Fatalf(`containServiceDependency contain failed`)
+       }
+
+       b, err = containServiceDependency([]*registry.MicroServiceKey{
+               {AppId: "a"},
+       }, &registry.MicroServiceKey{
+               AppId: "a",
+       })
+       if !b {
+               t.Fatalf(`containServiceDependency not contain failed`)
+       }
+
+       _, err = containServiceDependency(nil, nil)
+       if err == nil {
+               t.Fatalf(`containServiceDependency invalid failed`)
+       }
+
+       ok := diffServiceVersion(&registry.MicroServiceKey{
+               AppId:       "a",
+               ServiceName: "a",
+               Version:     "1",
+       }, &registry.MicroServiceKey{
+               AppId:       "a",
+               ServiceName: "a",
+               Version:     "2",
+       })
+       if !ok {
+               t.Fatalf(`diffServiceVersion failed`)
+       }
+}
+
+func TestBadParamsResponse(t *testing.T) {
+       p := BadParamsResponse("a")
+       if p == nil {
+               t.Fatalf(`BadParamsResponse failed`)
+       }
+}
+
+func TestDependencyRuleExistUtil(t *testing.T) {
+       _, err := dependencyRuleExistUtil(context.Background(), "", 
&registry.MicroServiceKey{})
+       if err == nil {
+               t.Fatalf(`dependencyRuleExistUtil failed`)
+       }
+}
+
+func TestParamsChecker(t *testing.T) {
+       p := ParamsChecker(nil, nil)
+       if p != nil {
+               t.Fatalf(`ParamsChecker invalid failed`)
+       }
+
+       p = ParamsChecker(&registry.MicroServiceKey{
+               AppId:       "a",
+               ServiceName: "b",
+               Version:     "1.0.0",
+       }, nil)
+       if p != nil {
+               t.Fatalf(`ParamsChecker invalid failed`)
+       }
+
+       p = ParamsChecker(&registry.MicroServiceKey{
+               AppId:       "a",
+               ServiceName: "b",
+               Version:     "1.0.0",
+       }, []*registry.MicroServiceKey{
+               {ServiceName: "*"},
+       })
+       if p != nil {
+               t.Fatalf(`ParamsChecker * failed`)
+       }
+
+       p = ParamsChecker(&registry.MicroServiceKey{
+               AppId:       "a",
+               ServiceName: "b",
+               Version:     "1.0.0",
+       }, []*registry.MicroServiceKey{
+               {},
+       })
+       if p == nil {
+               t.Fatalf(`ParamsChecker invalid provider key failed`)
+       }
+
+       p = ParamsChecker(&registry.MicroServiceKey{
+               AppId:       "a",
+               ServiceName: "b",
+               Version:     "1.0.0",
+       }, []*registry.MicroServiceKey{
+               {ServiceName: "a", Version: "1"},
+               {ServiceName: "a", Version: "1"},
+       })
+       if p == nil {
+               t.Fatalf(`ParamsChecker duplicate provider key failed`)
+       }
+}
+
+func TestServiceDependencyRuleExist(t *testing.T) {
+       _, err := DependencyRuleExist(context.Background(), 
&registry.MicroServiceKey{}, &registry.MicroServiceKey{})
+       if err != nil {
+               t.Fatalf(`ServiceDependencyRuleExist failed`)
+       }
+}
+
+func TestUpdateServiceForAddDependency(t *testing.T) {
+       old := isNeedUpdate([]*registry.MicroServiceKey{
+               {
+                       AppId:       "a",
+                       ServiceName: "a",
+                       Version:     "1",
+               },
+       }, &registry.MicroServiceKey{
+               AppId:       "a",
+               ServiceName: "a",
+               Version:     "2",
+       })
+       if old == nil {
+               t.Fatalf(`isNeedUpdate failed`)
+       }
+}
+
+func TestDependency(t *testing.T) {
+       d := &Dependency{
+               DeleteDependencyRuleList: []*registry.MicroServiceKey{
+                       {ServiceName: "a", Version: "1.0.0"},
+               },
+               CreateDependencyRuleList: []*registry.MicroServiceKey{
+                       {ServiceName: "a", Version: "1.0.0"},
+               },
+       }
+       err := d.Commit(context.Background())
+       if err != nil {
+               t.Fatalf(`Dependency_UpdateProvidersRuleOfConsumer failed`)
+       }
+
+       dr := &DependencyRelation{
+               provider: &registry.MicroService{},
+               consumer: &registry.MicroService{},
+               ctx:      context.Background(),
+       }
+       _, err = dr.getDependencyProviderIds([]*registry.MicroServiceKey{
+               {ServiceName: "*"},
+       })
+       if err != nil {
+               t.Fatalf(`DependencyRelation_getDependencyProviderIds * failed`)
+       }
+       _, err = dr.getDependencyProviderIds([]*registry.MicroServiceKey{
+               {ServiceName: "a", Version: "1.0.0"},
+               {ServiceName: "b", Version: "latest"},
+       })
+       if err != nil {
+               t.Fatalf(`DependencyRelation_getDependencyProviderIds failed`)
+       }
+
+       _, err = dr.GetDependencyConsumers()
+       if err != nil {
+               t.Fatalf(`DependencyRelation_GetDependencyConsumers failed`)
+       }
+
+       _, err = dr.getServiceByMicroServiceKey(&registry.MicroServiceKey{})
+       if err != nil {
+               t.Fatalf(`DependencyRelation_getServiceByMicroServiceKey 
failed`)
+       }
+
+       _, err = 
dr.getConsumerOfSameServiceNameAndAppID(&registry.MicroServiceKey{})
+       if err != nil {
+               
t.Fatalf(`DependencyRelation_getConsumerOfSameServiceNameAndAppId failed`)
+       }
+
+       dr = &DependencyRelation{
+               consumer: &registry.MicroService{},
+               ctx:      context.Background(),
+       }
+       _, err = dr.getDependencyConsumersOfProvider()
+       if err == nil {
+               t.Fatalf(`DependencyRelation_getDependencyConsumersOfProvider 
failed`)
+       }
+       _, err = dr.GetDependencyProviders()
+       if err != nil {
+               t.Fatalf(`DependencyRelation_GetDependencyProviders failed`)
+       }
+
+       err = CleanUpDependencyRules(context.Background(), "")
+       if err == nil {
+               t.Fatalf(`DependencyRelation_CleanUpDependencyRules failed`)
+       }
+
+       err = CleanUpDependencyRules(context.Background(), "a/b")
+       if err != nil {
+               t.Fatalf(`DependencyRelation_CleanUpDependencyRules failed`)
+       }
+
+       _, err = removeProviderRuleKeys(context.Background(), "a/b", nil)
+       if err != nil {
+               t.Fatalf(`DependencyRelation_removeProviderRuleKeys failed`)
+       }
+}
+
+func TestDependencyRelationFilterOpt(t *testing.T) {
+       op := toDependencyRelationFilterOpt(
+               WithSameDomainProject(),
+               WithoutSelfDependency(),
+       )
+       if !op.NonSelf || !op.SameDomainProject {
+               t.Fatalf(`toDependencyRelationFilterOpt failed`)
+       }
+}
+
+func TestGetConsumerIdsWithFilter(t *testing.T) {
+       _, _, err := getConsumerIdsWithFilter(context.Background(), "", 
&registry.MicroService{}, nil)
+       if err != nil {
+               t.Fatalf(`TestGetConsumerIdsWithFilter failed`)
+       }
+}
diff --git a/datasource/etcd/util/dependency_util.go 
b/datasource/etcd/util/dependency_util.go
new file mode 100644
index 0000000..ac509d9
--- /dev/null
+++ b/datasource/etcd/util/dependency_util.go
@@ -0,0 +1,514 @@
+/*
+ * 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 util
+
+import (
+       "context"
+       "encoding/json"
+       "errors"
+       "fmt"
+       "github.com/apache/servicecomb-service-center/pkg/log"
+       pb "github.com/apache/servicecomb-service-center/pkg/registry"
+       "github.com/apache/servicecomb-service-center/pkg/util"
+       apt "github.com/apache/servicecomb-service-center/server/core"
+       "github.com/apache/servicecomb-service-center/server/core/backend"
+       "github.com/apache/servicecomb-service-center/server/core/proto"
+       "github.com/apache/servicecomb-service-center/server/plugin/registry"
+       scerr "github.com/apache/servicecomb-service-center/server/scerror"
+       "strings"
+)
+
+func GetConsumerIds(ctx context.Context, domainProject string, provider 
*pb.MicroService) ([]string, error) {
+       // 查询所有consumer
+       dr := NewProviderDependencyRelation(ctx, domainProject, provider)
+       consumerIds, err := dr.GetDependencyConsumerIds()
+       if err != nil {
+               log.Errorf(err, "get service[%s]'s consumerIds failed", 
provider.ServiceId)
+               return nil, err
+       }
+       return consumerIds, nil
+}
+
+func GetProviderIds(ctx context.Context, domainProject string, consumer 
*pb.MicroService) ([]string, error) {
+       // 查询所有provider
+       dr := NewConsumerDependencyRelation(ctx, domainProject, consumer)
+       providerIDs, err := dr.GetDependencyProviderIds()
+       if err != nil {
+               log.Errorf(err, "get service[%s]'s providerIDs failed", 
consumer.ServiceId)
+               return nil, err
+       }
+       return providerIDs, nil
+}
+
+// GetAllConsumerIds is the function get from dependency rule and filter with 
service rules
+func GetAllConsumerIds(ctx context.Context, domainProject string, provider 
*pb.MicroService) (allow []string, deny []string, _ error) {
+       if provider == nil || len(provider.ServiceId) == 0 {
+               return nil, nil, fmt.Errorf("invalid provider")
+       }
+
+       //todo 删除服务,最后实例推送有误差
+       providerRules, err := GetRulesUtil(ctx, domainProject, 
provider.ServiceId)
+       if err != nil {
+               return nil, nil, err
+       }
+
+       rf := &RuleFilter{
+               DomainProject: domainProject,
+               ProviderRules: providerRules,
+       }
+
+       allow, deny, err = getConsumerIdsWithFilter(ctx, domainProject, 
provider, rf)
+       if err != nil {
+               return nil, nil, err
+       }
+       return allow, deny, nil
+}
+
+func getConsumerIdsWithFilter(ctx context.Context, domainProject string, 
provider *pb.MicroService, rf *RuleFilter) (allow []string, deny []string, err 
error) {
+       consumerIds, err := GetConsumerIds(ctx, domainProject, provider)
+       if err != nil {
+               return nil, nil, err
+       }
+       return rf.FilterAll(ctx, consumerIds)
+}
+
+func GetAllProviderIds(ctx context.Context, domainProject string, service 
*pb.MicroService) (allow []string, deny []string, _ error) {
+       providerIDsInCache, err := GetProviderIds(ctx, domainProject, service)
+       if err != nil {
+               return nil, nil, err
+       }
+       l := len(providerIDsInCache)
+       rf := RuleFilter{
+               DomainProject: domainProject,
+       }
+       allowIdx, denyIdx := 0, l
+       providerIDs := make([]string, l)
+       copyCtx := util.SetContext(util.CloneContext(ctx), util.CtxCacheOnly, 
"1")
+       for _, providerID := range providerIDsInCache {
+               providerRules, err := GetRulesUtil(copyCtx, domainProject, 
providerID)
+               if err != nil {
+                       return nil, nil, err
+               }
+               if len(providerRules) == 0 {
+                       providerIDs[allowIdx] = providerID
+                       allowIdx++
+                       continue
+               }
+               rf.ProviderRules = providerRules
+               ok, err := rf.Filter(ctx, service.ServiceId)
+               if err != nil {
+                       return nil, nil, err
+               }
+               if ok {
+                       providerIDs[allowIdx] = providerID
+                       allowIdx++
+               } else {
+                       denyIdx--
+                       providerIDs[denyIdx] = providerID
+               }
+       }
+       return providerIDs[:allowIdx], providerIDs[denyIdx:], nil
+}
+
+func DependencyRuleExist(ctx context.Context, provider *pb.MicroServiceKey, 
consumer *pb.MicroServiceKey) (bool, error) {
+       targetDomainProject := provider.Tenant
+       if len(targetDomainProject) == 0 {
+               targetDomainProject = consumer.Tenant
+       }
+
+       consumerKey := apt.GenerateConsumerDependencyRuleKey(consumer.Tenant, 
consumer)
+       existed, err := dependencyRuleExistUtil(ctx, consumerKey, provider)
+       if err != nil || existed {
+               return existed, err
+       }
+
+       providerKey := 
apt.GenerateProviderDependencyRuleKey(targetDomainProject, provider)
+       return dependencyRuleExistUtil(ctx, providerKey, consumer)
+}
+
+func dependencyRuleExistUtil(ctx context.Context, key string, target 
*pb.MicroServiceKey) (bool, error) {
+       compareData, err := TransferToMicroServiceDependency(ctx, key)
+       if err != nil {
+               return false, err
+       }
+       if len(compareData.Dependency) != 0 {
+               isEqual, err := 
containServiceDependency(compareData.Dependency, target)
+               if err != nil {
+                       return false, err
+               }
+               if isEqual {
+                       //删除之前的依赖
+                       return true, nil
+               }
+       }
+       return false, nil
+}
+
+func AddServiceVersionRule(ctx context.Context, domainProject string, consumer 
*pb.MicroService, provider *pb.MicroServiceKey) error {
+       //创建依赖一致
+       consumerKey := proto.MicroServiceToKey(domainProject, consumer)
+       exist, err := DependencyRuleExist(ctx, provider, consumerKey)
+       if exist || err != nil {
+               return err
+       }
+
+       r := &pb.ConsumerDependency{
+               Consumer:  consumerKey,
+               Providers: []*pb.MicroServiceKey{provider},
+               Override:  false,
+       }
+       data, err := json.Marshal(r)
+       if err != nil {
+               return err
+       }
+
+       id := util.StringJoin([]string{provider.AppId, provider.ServiceName}, 
"_")
+       key := apt.GenerateConsumerDependencyQueueKey(domainProject, 
consumer.ServiceId, id)
+       resp, err := backend.Registry().TxnWithCmp(ctx,
+               nil,
+               []registry.CompareOp{registry.OpCmp(registry.CmpStrVal(key), 
registry.CmpEqual, util.BytesToStringWithNoCopy(data))},
+               []registry.PluginOp{registry.OpPut(registry.WithStrKey(key), 
registry.WithValue(data))})
+       if err != nil {
+               return err
+       }
+       if !resp.Succeeded {
+               log.Infof("put in queue[%s/%s]: consumer[%s/%s/%s/%s] -> 
provider[%s/%s/%s/%s]", consumer.ServiceId, id,
+                       consumer.Environment, consumer.AppId, 
consumer.ServiceName, consumer.Version,
+                       provider.Environment, provider.AppId, 
provider.ServiceName, provider.Version)
+       }
+       return nil
+}
+
+func TransferToMicroServiceDependency(ctx context.Context, key string) 
(*pb.MicroServiceDependency, error) {
+       microServiceDependency := &pb.MicroServiceDependency{
+               Dependency: []*pb.MicroServiceKey{},
+       }
+
+       opts := append(FromContext(ctx), registry.WithStrKey(key))
+       res, err := backend.Store().DependencyRule().Search(ctx, opts...)
+       if err != nil {
+               log.Errorf(nil, "get dependency rule[%s] failed", key)
+               return nil, err
+       }
+       if len(res.Kvs) != 0 {
+               return res.Kvs[0].Value.(*pb.MicroServiceDependency), nil
+       }
+       return microServiceDependency, nil
+}
+
+func equalServiceDependency(serviceA *pb.MicroServiceKey, serviceB 
*pb.MicroServiceKey) bool {
+       stringA := toString(serviceA)
+       stringB := toString(serviceB)
+       return stringA == stringB
+}
+
+func diffServiceVersion(serviceA *pb.MicroServiceKey, serviceB 
*pb.MicroServiceKey) bool {
+       stringA := toString(serviceA)
+       stringB := toString(serviceB)
+       if stringA != stringB &&
+               stringA[:strings.LastIndex(stringA, "/")+1] == 
stringB[:strings.LastIndex(stringB, "/")+1] {
+               return true
+       }
+       return false
+}
+
+func toString(in *pb.MicroServiceKey) string {
+       return apt.GenerateProviderDependencyRuleKey(in.Tenant, in)
+}
+
+func parseAddOrUpdateRules(ctx context.Context, dep *Dependency) 
(createDependencyRuleList, existDependencyRuleList, deleteDependencyRuleList 
[]*pb.MicroServiceKey) {
+       conKey := apt.GenerateConsumerDependencyRuleKey(dep.DomainProject, 
dep.Consumer)
+
+       oldProviderRules, err := TransferToMicroServiceDependency(ctx, conKey)
+       if err != nil {
+               log.Errorf(err, "update dependency rule failed, get 
consumer[%s/%s/%s/%s]'s dependency rule failed",
+                       dep.Consumer.Environment, dep.Consumer.AppId, 
dep.Consumer.ServiceName, dep.Consumer.Version)
+               return
+       }
+
+       deleteDependencyRuleList = make([]*pb.MicroServiceKey, 0, 
len(oldProviderRules.Dependency))
+       createDependencyRuleList = make([]*pb.MicroServiceKey, 0, 
len(dep.ProvidersRule))
+       existDependencyRuleList = make([]*pb.MicroServiceKey, 0, 
len(oldProviderRules.Dependency))
+       for _, tmpProviderRule := range dep.ProvidersRule {
+               if ok, _ := 
containServiceDependency(oldProviderRules.Dependency, tmpProviderRule); ok {
+                       continue
+               }
+
+               if tmpProviderRule.ServiceName == "*" {
+                       createDependencyRuleList = 
append([]*pb.MicroServiceKey{}, tmpProviderRule)
+                       deleteDependencyRuleList = oldProviderRules.Dependency
+                       break
+               }
+
+               createDependencyRuleList = append(createDependencyRuleList, 
tmpProviderRule)
+               old := isNeedUpdate(oldProviderRules.Dependency, 
tmpProviderRule)
+               if old != nil {
+                       deleteDependencyRuleList = 
append(deleteDependencyRuleList, old)
+               }
+       }
+       for _, oldProviderRule := range oldProviderRules.Dependency {
+               if oldProviderRule.ServiceName == "*" {
+                       createDependencyRuleList = nil
+                       deleteDependencyRuleList = nil
+                       return
+               }
+               if ok, _ := containServiceDependency(deleteDependencyRuleList, 
oldProviderRule); !ok {
+                       existDependencyRuleList = 
append(existDependencyRuleList, oldProviderRule)
+               }
+       }
+
+       dep.ProvidersRule = append(createDependencyRuleList, 
existDependencyRuleList...)
+       return
+}
+
+func parseOverrideRules(ctx context.Context, dep *Dependency) 
(createDependencyRuleList, existDependencyRuleList, deleteDependencyRuleList 
[]*pb.MicroServiceKey) {
+       conKey := apt.GenerateConsumerDependencyRuleKey(dep.DomainProject, 
dep.Consumer)
+
+       oldProviderRules, err := TransferToMicroServiceDependency(ctx, conKey)
+       if err != nil {
+               log.Errorf(err, "override dependency rule failed, get 
consumer[%s/%s/%s/%s]'s dependency rule failed",
+                       dep.Consumer.Environment, dep.Consumer.AppId, 
dep.Consumer.ServiceName, dep.Consumer.Version)
+               return
+       }
+
+       deleteDependencyRuleList = make([]*pb.MicroServiceKey, 0, 
len(oldProviderRules.Dependency))
+       createDependencyRuleList = make([]*pb.MicroServiceKey, 0, 
len(dep.ProvidersRule))
+       existDependencyRuleList = make([]*pb.MicroServiceKey, 0, 
len(oldProviderRules.Dependency))
+       for _, oldProviderRule := range oldProviderRules.Dependency {
+               if ok, _ := containServiceDependency(dep.ProvidersRule, 
oldProviderRule); !ok {
+                       deleteDependencyRuleList = 
append(deleteDependencyRuleList, oldProviderRule)
+               } else {
+                       existDependencyRuleList = 
append(existDependencyRuleList, oldProviderRule)
+               }
+       }
+       for _, tmpProviderRule := range dep.ProvidersRule {
+               if ok, _ := containServiceDependency(existDependencyRuleList, 
tmpProviderRule); !ok {
+                       createDependencyRuleList = 
append(createDependencyRuleList, tmpProviderRule)
+               }
+       }
+       return
+}
+
+func syncDependencyRule(ctx context.Context, dep *Dependency, filter 
func(context.Context, *Dependency) (_, _, _ []*pb.MicroServiceKey)) error {
+       //更新consumer的providers的值,consumer的版本是确定的
+       consumerFlag := strings.Join([]string{dep.Consumer.Environment, 
dep.Consumer.AppId, dep.Consumer.ServiceName, dep.Consumer.Version}, "/")
+
+       createDependencyRuleList, existDependencyRuleList, 
deleteDependencyRuleList := filter(ctx, dep)
+       if len(createDependencyRuleList) == 0 && len(existDependencyRuleList) 
== 0 && len(deleteDependencyRuleList) == 0 {
+               return nil
+       }
+
+       if len(deleteDependencyRuleList) != 0 {
+               log.Infof("delete consumer[%s]'s dependency rule %v", 
consumerFlag, deleteDependencyRuleList)
+               dep.DeleteDependencyRuleList = deleteDependencyRuleList
+       }
+
+       if len(createDependencyRuleList) != 0 {
+               log.Infof("create consumer[%s]'s dependency rule %v", 
consumerFlag, createDependencyRuleList)
+               dep.CreateDependencyRuleList = createDependencyRuleList
+       }
+
+       return dep.Commit(ctx)
+}
+
+func AddDependencyRule(ctx context.Context, dep *Dependency) error {
+       return syncDependencyRule(ctx, dep, parseAddOrUpdateRules)
+}
+
+func CreateDependencyRule(ctx context.Context, dep *Dependency) error {
+       return syncDependencyRule(ctx, dep, parseOverrideRules)
+}
+
+func isNeedUpdate(services []*pb.MicroServiceKey, service *pb.MicroServiceKey) 
*pb.MicroServiceKey {
+       for _, tmp := range services {
+               if diffServiceVersion(tmp, service) {
+                       return tmp
+               }
+       }
+       return nil
+}
+
+func containServiceDependency(services []*pb.MicroServiceKey, service 
*pb.MicroServiceKey) (bool, error) {
+       if services == nil || service == nil {
+               return false, errors.New("invalid params input")
+       }
+       for _, value := range services {
+               rst := equalServiceDependency(service, value)
+               if rst {
+                       return true, nil
+               }
+       }
+       return false, nil
+}
+
+func BadParamsResponse(detailErr string) *pb.CreateDependenciesResponse {
+       log.Errorf(nil, "request params is invalid. %s", detailErr)
+       if len(detailErr) == 0 {
+               detailErr = "Request params is invalid."
+       }
+       return &pb.CreateDependenciesResponse{
+               Response: proto.CreateResponse(scerr.ErrInvalidParams, 
detailErr),
+       }
+}
+
+func ParamsChecker(consumerInfo *pb.MicroServiceKey, providersInfo 
[]*pb.MicroServiceKey) *pb.CreateDependenciesResponse {
+       flag := make(map[string]bool, len(providersInfo))
+       for _, providerInfo := range providersInfo {
+               //存在带*的情况,后面的数据就不校验了
+               if providerInfo.ServiceName == "*" {
+                       break
+               }
+               if len(providerInfo.AppId) == 0 {
+                       providerInfo.AppId = consumerInfo.AppId
+               }
+
+               version := providerInfo.Version
+               if len(version) == 0 {
+                       return BadParamsResponse("Required provider version")
+               }
+
+               providerInfo.Version = ""
+               if _, ok := flag[toString(providerInfo)]; ok {
+                       return BadParamsResponse("Invalid request body for 
provider info.Duplicate provider or (serviceName and appId is same).")
+               }
+               flag[toString(providerInfo)] = true
+               providerInfo.Version = version
+       }
+       return nil
+}
+
+func DeleteDependencyForDeleteService(domainProject string, serviceID string, 
service *pb.MicroServiceKey) (registry.PluginOp, error) {
+       key := apt.GenerateConsumerDependencyQueueKey(domainProject, serviceID, 
apt.DepsQueueUUID)
+       conDep := new(pb.ConsumerDependency)
+       conDep.Consumer = service
+       conDep.Providers = []*pb.MicroServiceKey{}
+       conDep.Override = true
+       data, err := json.Marshal(conDep)
+       if err != nil {
+               return registry.PluginOp{}, err
+       }
+       return registry.OpPut(registry.WithStrKey(key), 
registry.WithValue(data)), nil
+}
+
+func removeProviderRuleOfConsumer(ctx context.Context, domainProject string, 
cache map[string]bool) ([]registry.PluginOp, error) {
+       key := apt.GenerateConsumerDependencyRuleKey(domainProject, nil) + 
apt.SPLIT
+       resp, err := backend.Store().DependencyRule().Search(ctx,
+               registry.WithStrKey(key), registry.WithPrefix())
+       if err != nil {
+               return nil, err
+       }
+
+       var ops []registry.PluginOp
+loop:
+       for _, kv := range resp.Kvs {
+               var left []*pb.MicroServiceKey
+               all := kv.Value.(*pb.MicroServiceDependency).Dependency
+               for _, key := range all {
+                       if key.ServiceName == "*" {
+                               continue loop
+                       }
+
+                       id := apt.GenerateProviderDependencyRuleKey(key.Tenant, 
key)
+                       exist, ok := cache[id]
+                       if !ok {
+                               _, exist, err = FindServiceIds(ctx, 
key.Version, key)
+                               if err != nil {
+                                       return nil, fmt.Errorf("%v, find 
service %s/%s/%s/%s",
+                                               err, key.Tenant, key.AppId, 
key.ServiceName, key.Version)
+                               }
+                               cache[id] = exist
+                       }
+
+                       if exist {
+                               left = append(left, key)
+                       }
+               }
+
+               if len(all) == len(left) {
+                       continue
+               }
+
+               if len(left) == 0 {
+                       ops = append(ops, 
registry.OpDel(registry.WithKey(kv.Key)))
+               } else {
+                       val, err := 
json.Marshal(&pb.MicroServiceDependency{Dependency: left})
+                       if err != nil {
+                               return nil, fmt.Errorf("%v, marshal %v", err, 
left)
+                       }
+                       ops = append(ops, 
registry.OpPut(registry.WithKey(kv.Key), registry.WithValue(val)))
+               }
+       }
+       return ops, nil
+}
+
+func removeProviderRuleKeys(ctx context.Context, domainProject string, cache 
map[string]bool) ([]registry.PluginOp, error) {
+       key := apt.GenerateProviderDependencyRuleKey(domainProject, nil) + 
apt.SPLIT
+       resp, err := backend.Store().DependencyRule().Search(ctx,
+               registry.WithStrKey(key), registry.WithPrefix(), 
registry.WithKeyOnly())
+       if err != nil {
+               return nil, err
+       }
+
+       var ops []registry.PluginOp
+       for _, kv := range resp.Kvs {
+               id := util.BytesToStringWithNoCopy(kv.Key)
+               exist, ok := cache[id]
+               if !ok {
+                       _, key := apt.GetInfoFromDependencyRuleKV(kv.Key)
+                       if key == nil || key.ServiceName == "*" {
+                               continue
+                       }
+
+                       _, exist, err = FindServiceIds(ctx, key.Version, key)
+                       if err != nil {
+                               return nil, fmt.Errorf("find service 
%s/%s/%s/%s, %v",
+                                       key.Tenant, key.AppId, key.ServiceName, 
key.Version, err)
+                       }
+                       cache[id] = exist
+               }
+
+               if !exist {
+                       ops = append(ops, 
registry.OpDel(registry.WithKey(kv.Key)))
+               }
+       }
+       return ops, nil
+}
+
+func CleanUpDependencyRules(ctx context.Context, domainProject string) error {
+       if len(domainProject) == 0 {
+               return errors.New("required domainProject")
+       }
+
+       cache := make(map[string]bool)
+       pOps, err := removeProviderRuleOfConsumer(ctx, domainProject, cache)
+       if err != nil {
+               return err
+       }
+
+       kOps, err := removeProviderRuleKeys(ctx, domainProject, cache)
+       if err != nil {
+               return err
+       }
+
+       ops := append(append([]registry.PluginOp(nil), pOps...), kOps...)
+       if len(ops) == 0 {
+               return nil
+       }
+
+       return backend.BatchCommit(ctx, ops)
+}
diff --git a/datasource/etcd/util/domain_util.go 
b/datasource/etcd/util/domain_util.go
new file mode 100644
index 0000000..ff0b1c0
--- /dev/null
+++ b/datasource/etcd/util/domain_util.go
@@ -0,0 +1,127 @@
+/*
+ * 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 util
+
+import (
+       "context"
+       "strings"
+
+       "github.com/apache/servicecomb-service-center/pkg/log"
+       "github.com/apache/servicecomb-service-center/pkg/util"
+       apt "github.com/apache/servicecomb-service-center/server/core"
+       "github.com/apache/servicecomb-service-center/server/core/backend"
+       "github.com/apache/servicecomb-service-center/server/plugin/discovery"
+       "github.com/apache/servicecomb-service-center/server/plugin/registry"
+)
+
+func GetAllDomainRawData(ctx context.Context) ([]*discovery.KeyValue, error) {
+       opts := append(FromContext(ctx),
+               registry.WithStrKey(apt.GenerateDomainKey("")),
+               registry.WithPrefix())
+       rsp, err := backend.Store().Domain().Search(ctx, opts...)
+       if err != nil {
+               return nil, err
+       }
+       return rsp.Kvs, nil
+
+}
+
+func GetAllDomain(ctx context.Context) ([]string, error) {
+       insWatherByDomainKeys := []string{}
+       kvs, err := GetAllDomainRawData(ctx)
+       if err != nil {
+               return nil, err
+       }
+
+       if len(kvs) == 0 {
+               return insWatherByDomainKeys, err
+       }
+
+       domain := ""
+       instByDomain := ""
+       var arrTmp []string
+       for _, kv := range kvs {
+               arrTmp = strings.Split(util.BytesToStringWithNoCopy(kv.Key), 
"/")
+               domain = arrTmp[len(arrTmp)-1]
+               instByDomain = apt.GetInstanceRootKey(domain)
+               insWatherByDomainKeys = append(insWatherByDomainKeys, 
instByDomain)
+       }
+       return insWatherByDomainKeys, err
+}
+
+func DomainExist(ctx context.Context, domain string) (bool, error) {
+       opts := append(FromContext(ctx),
+               registry.WithStrKey(apt.GenerateDomainKey(domain)),
+               registry.WithCountOnly())
+       rsp, err := backend.Store().Domain().Search(ctx, opts...)
+       if err != nil {
+               return false, err
+       }
+       return rsp.Count > 0, nil
+}
+
+func ProjectExist(ctx context.Context, domain, project string) (bool, error) {
+       opts := append(FromContext(ctx),
+               registry.WithStrKey(apt.GenerateProjectKey(domain, project)),
+               registry.WithCountOnly())
+       rsp, err := backend.Store().Project().Search(ctx, opts...)
+       if err != nil {
+               return false, err
+       }
+       return rsp.Count > 0, nil
+}
+
+func NewDomain(ctx context.Context, domain string) (bool, error) {
+       ok, err := backend.Registry().PutNoOverride(ctx,
+               registry.WithStrKey(apt.GenerateDomainKey(domain)))
+       if err != nil {
+               return false, err
+       }
+       return ok, nil
+}
+
+func NewProject(ctx context.Context, domain, project string) (bool, error) {
+       ok, err := backend.Registry().PutNoOverride(ctx,
+               registry.WithStrKey(apt.GenerateProjectKey(domain, project)))
+       if err != nil {
+               return ok, err
+       }
+       return ok, nil
+}
+
+func NewDomainProject(ctx context.Context, domain, project string) error {
+       copyCtx := util.SetContext(util.CloneContext(ctx), util.CtxCacheOnly, 
"1")
+       ok, err := DomainExist(copyCtx, domain)
+       if !ok && err == nil {
+               ok, err = NewDomain(ctx, domain)
+               if ok {
+                       log.Infof("new domain(%s)", domain)
+               }
+       }
+       if err != nil {
+               return err
+       }
+       ok, err = ProjectExist(copyCtx, domain, project)
+       if !ok && err == nil {
+               ok, err = NewProject(ctx, domain, project)
+               if ok {
+                       log.Infof("new project(%s/%s)", domain, project)
+               }
+       }
+       return err
+}
diff --git a/datasource/etcd/util/domain_util_test.go 
b/datasource/etcd/util/domain_util_test.go
new file mode 100644
index 0000000..d18a810
--- /dev/null
+++ b/datasource/etcd/util/domain_util_test.go
@@ -0,0 +1,84 @@
+/*
+ * 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 util
+
+import (
+       "context"
+       "testing"
+)
+
+func TestGetOneDomainProjectServiceCount(t *testing.T) {
+       _, err := GetOneDomainProjectServiceCount(context.Background(), "")
+       if err != nil {
+               t.Fatalf("GetOneDomainProjectServiceCount failed")
+       }
+}
+
+func TestGetOneDomainProjectInstanceCount(t *testing.T) {
+       _, err := GetOneDomainProjectInstanceCount(context.Background(), "")
+       if err != nil {
+               t.Fatalf("GetOneDomainProjectInstanceCount failed")
+       }
+}
+
+func TestGetDomain(t *testing.T) {
+       _, err := GetAllDomainRawData(context.Background())
+       if err != nil {
+               t.Fatalf("GetAllDomainRawData failed")
+       }
+
+       _, err = GetAllDomain(context.Background())
+       if err != nil {
+               t.Fatalf("GetAllDomain failed")
+       }
+}
+
+func TestDomainExist(t *testing.T) {
+       _, err := DomainExist(context.Background(), "")
+       if err != nil {
+               t.Fatalf("DomainExist failed")
+       }
+}
+
+func TestNewDomain(t *testing.T) {
+       _, err := NewDomain(context.Background(), "")
+       if err != nil {
+               t.Fatalf("NewDomain failed")
+       }
+}
+
+func TestProjectExist(t *testing.T) {
+       _, err := ProjectExist(context.Background(), "", "")
+       if err != nil {
+               t.Fatalf("DomainExist failed")
+       }
+}
+
+func TestNewProject(t *testing.T) {
+       _, err := NewProject(context.Background(), "", "")
+       if err != nil {
+               t.Fatalf("NewProject failed")
+       }
+}
+
+func TestNewDomainProject(t *testing.T) {
+       err := NewDomainProject(context.Background(), "", "")
+       if err != nil {
+               t.Fatalf("NewDomainProject failed")
+       }
+}
diff --git a/datasource/etcd/util/heartbeat_util.go 
b/datasource/etcd/util/heartbeat_util.go
new file mode 100644
index 0000000..8db60f8
--- /dev/null
+++ b/datasource/etcd/util/heartbeat_util.go
@@ -0,0 +1,53 @@
+/*
+ * 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 util
+
+import (
+       "context"
+       "errors"
+
+       apt "github.com/apache/servicecomb-service-center/server/core"
+       "github.com/apache/servicecomb-service-center/server/core/backend"
+       "github.com/apache/servicecomb-service-center/server/plugin/registry"
+       scerr "github.com/apache/servicecomb-service-center/server/scerror"
+)
+
+func HeartbeatUtil(ctx context.Context, domainProject string, serviceID 
string, instanceID string) (leaseID int64, ttl int64, _ *scerr.Error) {
+       leaseID, err := GetLeaseID(ctx, domainProject, serviceID, instanceID)
+       if err != nil {
+               return leaseID, ttl, 
scerr.NewError(scerr.ErrUnavailableBackend, err.Error())
+       }
+       ttl, err = KeepAliveLease(ctx, domainProject, serviceID, instanceID, 
leaseID)
+       if err != nil {
+               return leaseID, ttl, scerr.NewError(scerr.ErrInstanceNotExists, 
err.Error())
+       }
+       return leaseID, ttl, nil
+}
+
+func KeepAliveLease(ctx context.Context, domainProject, serviceID, instanceID 
string, leaseID int64) (ttl int64, err error) {
+       if leaseID == -1 {
+               return ttl, errors.New("leaseId not exist, instance not exist")
+       }
+       ttl, err = backend.Store().KeepAlive(ctx,
+               registry.WithStrKey(apt.GenerateInstanceLeaseKey(domainProject, 
serviceID, instanceID)),
+               registry.WithLease(leaseID))
+       if err != nil {
+               return ttl, err
+       }
+       return ttl, nil
+}
diff --git a/server/plugin/uuid/uuid.go 
b/datasource/etcd/util/heartbeat_util_test.go
similarity index 62%
copy from server/plugin/uuid/uuid.go
copy to datasource/etcd/util/heartbeat_util_test.go
index c8aaa7c..38c91b0 100644
--- a/server/plugin/uuid/uuid.go
+++ b/datasource/etcd/util/heartbeat_util_test.go
@@ -15,15 +15,30 @@
  * limitations under the License.
  */
 
-package uuid
+package util
 
 import (
        "context"
+       "testing"
 )
 
-const ContextKey = "_uuid_key"
+func TestHeartbeatUtil(t *testing.T) {
+       defer func() {
+               if r := recover(); r != nil {
+                       t.Fatalf("TestHeartbeatUtil failed")
+               }
+       }()
+       HeartbeatUtil(context.Background(), "", "", "")
+}
+
+func TestKeepAliveLease(t *testing.T) {
+       _, err := KeepAliveLease(context.Background(), "", "", "", -1)
+       if err == nil {
+               t.Fatalf("KeepAliveLease -1 failed")
+       }
 
-type UUID interface {
-       GetServiceID(ctx context.Context) string
-       GetInstanceID(ctx context.Context) string
+       _, err = KeepAliveLease(context.Background(), "", "", "", 0)
+       if err != nil {
+               t.Fatalf("KeepAliveLease failed")
+       }
 }
diff --git a/datasource/etcd/util/instance_util.go 
b/datasource/etcd/util/instance_util.go
new file mode 100644
index 0000000..d8f833e
--- /dev/null
+++ b/datasource/etcd/util/instance_util.go
@@ -0,0 +1,276 @@
+/*
+ * 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 util
+
+import (
+       "context"
+       "crypto/sha1"
+       "encoding/json"
+       "fmt"
+       "strconv"
+       "strings"
+       "time"
+
+       "github.com/apache/servicecomb-service-center/pkg/log"
+       pb "github.com/apache/servicecomb-service-center/pkg/registry"
+       rmodel "github.com/apache/servicecomb-service-center/pkg/registry"
+       "github.com/apache/servicecomb-service-center/pkg/util"
+       apt "github.com/apache/servicecomb-service-center/server/core"
+       "github.com/apache/servicecomb-service-center/server/core/backend"
+       "github.com/apache/servicecomb-service-center/server/core/proto"
+       "github.com/apache/servicecomb-service-center/server/plugin/discovery"
+       "github.com/apache/servicecomb-service-center/server/plugin/registry"
+       scerr "github.com/apache/servicecomb-service-center/server/scerror"
+)
+
+func GetLeaseID(ctx context.Context, domainProject string, serviceID string, 
instanceID string) (int64, error) {
+       opts := append(FromContext(ctx),
+               registry.WithStrKey(apt.GenerateInstanceLeaseKey(domainProject, 
serviceID, instanceID)))
+       resp, err := backend.Store().Lease().Search(ctx, opts...)
+       if err != nil {
+               return -1, err
+       }
+       if len(resp.Kvs) <= 0 {
+               return -1, nil
+       }
+       leaseID, _ := strconv.ParseInt(resp.Kvs[0].Value.(string), 10, 64)
+       return leaseID, nil
+}
+
+func GetInstance(ctx context.Context, domainProject string, serviceID string, 
instanceID string) (*pb.MicroServiceInstance, error) {
+       key := apt.GenerateInstanceKey(domainProject, serviceID, instanceID)
+       opts := append(FromContext(ctx), registry.WithStrKey(key))
+
+       resp, err := backend.Store().Instance().Search(ctx, opts...)
+       if err != nil {
+               return nil, err
+       }
+       if len(resp.Kvs) == 0 {
+               return nil, nil
+       }
+
+       return resp.Kvs[0].Value.(*pb.MicroServiceInstance), nil
+}
+
+func FormatRevision(revs, counts []int64) (s string) {
+       for i, rev := range revs {
+               s += fmt.Sprintf("%d.%d,", rev, counts[i])
+       }
+       return fmt.Sprintf("%x", sha1.Sum(util.StringToBytesWithNoCopy(s)))
+}
+
+func GetAllInstancesOfOneService(ctx context.Context, domainProject string, 
serviceID string) ([]*pb.MicroServiceInstance, error) {
+       key := apt.GenerateInstanceKey(domainProject, serviceID, "")
+       opts := append(FromContext(ctx), registry.WithStrKey(key), 
registry.WithPrefix())
+       resp, err := backend.Store().Instance().Search(ctx, opts...)
+       if err != nil {
+               log.Errorf(err, "get service[%s]'s instances failed", serviceID)
+               return nil, err
+       }
+
+       instances := make([]*pb.MicroServiceInstance, 0, len(resp.Kvs))
+       for _, kv := range resp.Kvs {
+               instances = append(instances, 
kv.Value.(*pb.MicroServiceInstance))
+       }
+       return instances, nil
+}
+
+func GetInstanceCountOfOneService(ctx context.Context, domainProject string, 
serviceID string) (int64, error) {
+       key := apt.GenerateInstanceKey(domainProject, serviceID, "")
+       opts := append(FromContext(ctx),
+               registry.WithStrKey(key),
+               registry.WithPrefix(),
+               registry.WithCountOnly())
+       resp, err := backend.Store().Instance().Search(ctx, opts...)
+       if err != nil {
+               log.Errorf(err, "get number of service[%s]'s instances failed", 
serviceID)
+               return 0, err
+       }
+       return resp.Count, nil
+}
+
+type EndpointIndexValue struct {
+       serviceID  string
+       instanceID string
+}
+
+func ParseEndpointIndexValue(value []byte) EndpointIndexValue {
+       endpointValue := EndpointIndexValue{}
+       tmp := util.BytesToStringWithNoCopy(value)
+       splitedTmp := strings.Split(tmp, "/")
+       endpointValue.serviceID = splitedTmp[0]
+       endpointValue.instanceID = splitedTmp[1]
+       return endpointValue
+}
+
+func DeleteServiceAllInstances(ctx context.Context, serviceID string) error {
+       domainProject := util.ParseDomainProject(ctx)
+
+       instanceLeaseKey := apt.GenerateInstanceLeaseKey(domainProject, 
serviceID, "")
+       resp, err := backend.Store().Lease().Search(ctx,
+               registry.WithStrKey(instanceLeaseKey),
+               registry.WithPrefix(),
+               registry.WithNoCache())
+       if err != nil {
+               log.Errorf(err, "delete all of service[%s]'s instances failed: 
get instance lease failed", serviceID)
+               return err
+       }
+       if resp.Count <= 0 {
+               log.Warnf("service[%s] has no deployment of instance.", 
serviceID)
+               return nil
+       }
+       for _, v := range resp.Kvs {
+               leaseID, _ := strconv.ParseInt(v.Value.(string), 10, 64)
+               err := backend.Registry().LeaseRevoke(ctx, leaseID)
+               if err != nil {
+                       log.Error("", err)
+               }
+       }
+       return nil
+}
+
+func QueryAllProvidersInstances(ctx context.Context, selfServiceID string) 
(results []*pb.WatchInstanceResponse, rev int64) {
+       results = []*pb.WatchInstanceResponse{}
+
+       domainProject := util.ParseDomainProject(ctx)
+
+       service, err := GetService(ctx, domainProject, selfServiceID)
+       if err != nil {
+               log.Errorf(err, "get service[%s]'s file failed", selfServiceID)
+               return
+       }
+       if service == nil {
+               log.Errorf(nil, "service[%s] does not exist", selfServiceID)
+               return
+       }
+       providerIDs, _, err := GetAllProviderIds(ctx, domainProject, service)
+       if err != nil {
+               log.Errorf(err, "get service[%s]'s providerIDs failed", 
selfServiceID)
+               return
+       }
+
+       rev = backend.Revision()
+
+       for _, providerID := range providerIDs {
+               service, err := GetServiceWithRev(ctx, domainProject, 
providerID, rev)
+               if err != nil {
+                       log.Errorf(err, "get service[%s]'s provider[%s] file 
with revision %d failed",
+                               selfServiceID, providerID, rev)
+                       return
+               }
+               if service == nil {
+                       continue
+               }
+
+               kvs, err := queryServiceInstancesKvs(ctx, providerID, rev)
+               if err != nil {
+                       log.Errorf(err, "get service[%s]'s provider[%s] 
instances with revision %d failed",
+                               selfServiceID, providerID, rev)
+                       return
+               }
+
+               for _, kv := range kvs {
+                       results = append(results, &pb.WatchInstanceResponse{
+                               Response: 
proto.CreateResponse(proto.Response_SUCCESS, "List instance successfully."),
+                               Action:   string(rmodel.EVT_INIT),
+                               Key: &pb.MicroServiceKey{
+                                       Environment: service.Environment,
+                                       AppId:       service.AppId,
+                                       ServiceName: service.ServiceName,
+                                       Version:     service.Version,
+                               },
+                               Instance: kv.Value.(*pb.MicroServiceInstance),
+                       })
+               }
+       }
+       return
+}
+
+func queryServiceInstancesKvs(ctx context.Context, serviceID string, rev 
int64) ([]*discovery.KeyValue, error) {
+       domainProject := util.ParseDomainProject(ctx)
+       key := apt.GenerateInstanceKey(domainProject, serviceID, "")
+       resp, err := backend.Store().Instance().Search(ctx,
+               registry.WithStrKey(key),
+               registry.WithPrefix(),
+               registry.WithRev(rev))
+       if err != nil {
+               log.Errorf(err, "get service[%s]'s instances with revision %d 
failed",
+                       serviceID, rev)
+               return nil, err
+       }
+       return resp.Kvs, nil
+}
+
+func UpdateInstance(ctx context.Context, domainProject string, instance 
*pb.MicroServiceInstance) *scerr.Error {
+       leaseID, err := GetLeaseID(ctx, domainProject, instance.ServiceId, 
instance.InstanceId)
+       if err != nil {
+               return scerr.NewError(scerr.ErrInternal, err.Error())
+       }
+       if leaseID == -1 {
+               return scerr.NewError(scerr.ErrInstanceNotExists, "Instance's 
leaseId not exist.")
+       }
+
+       instance.ModTimestamp = strconv.FormatInt(time.Now().Unix(), 10)
+       data, err := json.Marshal(instance)
+       if err != nil {
+               return scerr.NewError(scerr.ErrInternal, err.Error())
+       }
+
+       key := apt.GenerateInstanceKey(domainProject, instance.ServiceId, 
instance.InstanceId)
+
+       resp, err := backend.Registry().TxnWithCmp(ctx,
+               []registry.PluginOp{registry.OpPut(
+                       registry.WithStrKey(key),
+                       registry.WithValue(data),
+                       registry.WithLease(leaseID))},
+               []registry.CompareOp{registry.OpCmp(
+                       
registry.CmpVer(util.StringToBytesWithNoCopy(apt.GenerateServiceKey(domainProject,
 instance.ServiceId))),
+                       registry.CmpNotEqual, 0)},
+               nil)
+       if err != nil {
+               return scerr.NewError(scerr.ErrUnavailableBackend, err.Error())
+       }
+       if !resp.Succeeded {
+               return scerr.NewError(scerr.ErrInstanceNotExists, "Instance 
does not exist.")
+       }
+       return nil
+}
+
+func AppendFindResponse(ctx context.Context, index int64, resp *pb.Response, 
instances []*pb.MicroServiceInstance,
+       updatedResult *[]*pb.FindResult, notModifiedResult *[]int64, 
failedResult **pb.FindFailedResult) {
+       if code := resp.GetCode(); code != proto.Response_SUCCESS {
+               if *failedResult == nil {
+                       *failedResult = &pb.FindFailedResult{
+                               Error: scerr.NewError(code, resp.GetMessage()),
+                       }
+               }
+               (*failedResult).Indexes = append((*failedResult).Indexes, index)
+               return
+       }
+       iv, _ := ctx.Value(util.CtxRequestRevision).(string)
+       ov, _ := ctx.Value(util.CtxResponseRevision).(string)
+       if len(iv) > 0 && iv == ov {
+               *notModifiedResult = append(*notModifiedResult, index)
+               return
+       }
+       *updatedResult = append(*updatedResult, &pb.FindResult{
+               Index:     index,
+               Instances: instances,
+               Rev:       ov,
+       })
+}
diff --git a/datasource/etcd/util/instance_util_test.go 
b/datasource/etcd/util/instance_util_test.go
new file mode 100644
index 0000000..d20b34a
--- /dev/null
+++ b/datasource/etcd/util/instance_util_test.go
@@ -0,0 +1,170 @@
+/*
+ * 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 util
+
+import (
+       "context"
+       pb "github.com/apache/servicecomb-service-center/pkg/registry"
+       "github.com/apache/servicecomb-service-center/pkg/util"
+       "github.com/apache/servicecomb-service-center/server/core/proto"
+       scerr "github.com/apache/servicecomb-service-center/server/scerror"
+       "testing"
+)
+
+func TestFormatRevision(t *testing.T) {
+       // null
+       if x := FormatRevision(nil, nil); 
"da39a3ee5e6b4b0d3255bfef95601890afd80709" != x {
+               t.Fatalf("TestFormatRevision failed, %s", x)
+       }
+       // 1.1,11.1,
+       if x := FormatRevision([]int64{1, 11}, []int64{1, 1}); 
"87aa7d310290ff4f93248c0aed6870b928edf45a" != x {
+               t.Fatalf("TestFormatRevision failed, %s", x)
+       }
+       // 1.11,1.1,
+       if x := FormatRevision([]int64{1, 1}, []int64{11, 1}); 
"24675d196e3dea5be0c774cab281366640fc99ef" != x {
+               t.Fatalf("TestFormatRevision failed, %s", x)
+       }
+}
+
+func TestGetLeaseId(t *testing.T) {
+       _, err := GetLeaseID(context.Background(), "", "", "")
+       if err != nil {
+               t.Fatalf(`GetLeaseID failed`)
+       }
+}
+
+func TestGetInstance(t *testing.T) {
+       _, err := GetInstance(context.Background(), "", "", "")
+       if err != nil {
+               t.Fatalf(`GetInstance failed`)
+       }
+
+       _, err = GetAllInstancesOfOneService(context.Background(), "", "")
+       if err != nil {
+               t.Fatalf(`GetAllInstancesOfOneService failed`)
+       }
+
+       QueryAllProvidersInstances(context.Background(), "")
+
+       _, err = queryServiceInstancesKvs(context.Background(), "", 0)
+       if err != nil {
+               t.Fatalf(`queryServiceInstancesKvs failed`)
+       }
+}
+
+func TestDeleteServiceAllInstances(t *testing.T) {
+       err := DeleteServiceAllInstances(context.Background(), "")
+       if err != nil {
+               t.Fatalf(`DeleteServiceAllInstances failed`)
+       }
+}
+
+func TestParseEndpointValue(t *testing.T) {
+       epv := ParseEndpointIndexValue([]byte("x/y"))
+       if epv.serviceID != "x" || epv.instanceID != "y" {
+               t.Fatalf(`ParseEndpointIndexValue failed`)
+       }
+}
+
+func TestGetInstanceCountOfOneService(t *testing.T) {
+       _, err := GetInstanceCountOfOneService(context.Background(), "", "")
+       if err != nil {
+               t.Fatalf(`GetInstanceCountOfOneService failed`)
+       }
+}
+
+func TestUpdateInstance(t *testing.T) {
+       err := UpdateInstance(util.SetContext(context.Background(), 
util.CtxNocache, "1"), "", &pb.MicroServiceInstance{})
+       if err == nil {
+               t.Fatalf(`UpdateInstance CTX_NOCACHE failed`)
+       }
+}
+
+func TestAppendFindResponse(t *testing.T) {
+       ctx := context.Background()
+       var (
+               find              pb.FindInstancesResponse
+               updatedResult     []*pb.FindResult
+               notModifiedResult []int64
+               failedResult      *pb.FindFailedResult
+       )
+       AppendFindResponse(ctx, 1, find.Response, find.Instances, 
&updatedResult, &notModifiedResult, &failedResult)
+       if updatedResult == nil || notModifiedResult != nil || failedResult != 
nil {
+               t.Fatal("TestAppendFindResponse failed")
+       }
+       if updatedResult[0].Index != 1 {
+               t.Fatal("TestAppendFindResponse failed")
+       }
+
+       updatedResult = nil
+       cloneCtx := context.WithValue(ctx, util.CtxResponseRevision, "1")
+       AppendFindResponse(cloneCtx, 1, find.Response, find.Instances, 
&updatedResult, &notModifiedResult, &failedResult)
+       if updatedResult == nil || notModifiedResult != nil || failedResult != 
nil {
+               t.Fatal("TestAppendFindResponse failed")
+       }
+       if updatedResult[0].Index != 1 || updatedResult[0].Rev != "1" {
+               t.Fatal("TestAppendFindResponse failed")
+       }
+
+       updatedResult = nil
+       cloneCtx = context.WithValue(ctx, util.CtxRequestRevision, "1")
+       cloneCtx = context.WithValue(cloneCtx, util.CtxResponseRevision, "1")
+       AppendFindResponse(cloneCtx, 1, find.Response, find.Instances, 
&updatedResult, &notModifiedResult, &failedResult)
+       if updatedResult != nil || notModifiedResult == nil || failedResult != 
nil {
+               t.Fatal("TestAppendFindResponse failed")
+       }
+       if notModifiedResult[0] != 1 {
+               t.Fatal("TestAppendFindResponse failed")
+       }
+
+       notModifiedResult = nil
+       find.Response = proto.CreateResponse(scerr.ErrInternal, "test")
+       AppendFindResponse(ctx, 1, find.Response, find.Instances, 
&updatedResult, &notModifiedResult, &failedResult)
+       if updatedResult != nil || notModifiedResult != nil || failedResult == 
nil {
+               t.Fatal("TestAppendFindResponse failed")
+       }
+       if failedResult.Error.Code != scerr.ErrInternal {
+               t.Fatal("TestAppendFindResponse failed")
+       }
+       find.Response = proto.CreateResponse(scerr.ErrInvalidParams, "test")
+       AppendFindResponse(ctx, 2, find.Response, find.Instances, 
&updatedResult, &notModifiedResult, &failedResult)
+       if updatedResult != nil || notModifiedResult != nil || failedResult == 
nil {
+               t.Fatal("TestAppendFindResponse failed")
+       }
+       if failedResult.Error.Code != scerr.ErrInternal {
+               t.Fatal("TestAppendFindResponse failed")
+       }
+
+       failedResult = nil
+       find.Response = nil
+       AppendFindResponse(ctx, 1, find.Response, find.Instances, 
&updatedResult, &notModifiedResult, &failedResult)
+       AppendFindResponse(ctx, 2, find.Response, find.Instances, 
&updatedResult, &notModifiedResult, &failedResult)
+       cloneCtx = context.WithValue(ctx, util.CtxRequestRevision, "1")
+       cloneCtx = context.WithValue(cloneCtx, util.CtxResponseRevision, "1")
+       AppendFindResponse(cloneCtx, 3, find.Response, find.Instances, 
&updatedResult, &notModifiedResult, &failedResult)
+       AppendFindResponse(cloneCtx, 4, find.Response, find.Instances, 
&updatedResult, &notModifiedResult, &failedResult)
+       find.Response = proto.CreateResponse(scerr.ErrInternal, "test")
+       AppendFindResponse(ctx, 5, find.Response, find.Instances, 
&updatedResult, &notModifiedResult, &failedResult)
+       AppendFindResponse(ctx, 6, find.Response, find.Instances, 
&updatedResult, &notModifiedResult, &failedResult)
+       if updatedResult == nil || notModifiedResult == nil || failedResult == 
nil {
+               t.Fatal("TestAppendFindResponse failed")
+       }
+       if len(updatedResult) != 2 || len(notModifiedResult) != 2 || 
len(failedResult.Indexes) != 2 {
+               t.Fatal("TestAppendFindResponse failed")
+       }
+}
diff --git a/datasource/etcd/util/microservice_util.go 
b/datasource/etcd/util/microservice_util.go
new file mode 100644
index 0000000..98f1911
--- /dev/null
+++ b/datasource/etcd/util/microservice_util.go
@@ -0,0 +1,310 @@
+/*
+ * 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 util
+
+import (
+       "context"
+       "encoding/json"
+       "strings"
+
+       "github.com/apache/servicecomb-service-center/pkg/log"
+       pb "github.com/apache/servicecomb-service-center/pkg/registry"
+       "github.com/apache/servicecomb-service-center/pkg/util"
+       apt "github.com/apache/servicecomb-service-center/server/core"
+       "github.com/apache/servicecomb-service-center/server/core/backend"
+       "github.com/apache/servicecomb-service-center/server/core/proto"
+       "github.com/apache/servicecomb-service-center/server/plugin"
+       "github.com/apache/servicecomb-service-center/server/plugin/discovery"
+       "github.com/apache/servicecomb-service-center/server/plugin/quota"
+       "github.com/apache/servicecomb-service-center/server/plugin/registry"
+)
+
+const defaultCacheValue = "1"
+
+/*
+       get Service by service id
+*/
+func GetServiceWithRev(ctx context.Context, domain string, id string, rev 
int64) (*pb.MicroService, error) {
+       key := apt.GenerateServiceKey(domain, id)
+       serviceResp, err := backend.Store().Service().Search(ctx,
+               registry.WithStrKey(key),
+               registry.WithRev(rev))
+       if err != nil {
+               return nil, err
+       }
+       if len(serviceResp.Kvs) == 0 {
+               return nil, nil
+       }
+       return serviceResp.Kvs[0].Value.(*pb.MicroService), nil
+}
+
+func GetService(ctx context.Context, domainProject string, serviceID string) 
(*pb.MicroService, error) {
+       key := apt.GenerateServiceKey(domainProject, serviceID)
+       opts := append(FromContext(ctx), registry.WithStrKey(key))
+       serviceResp, err := backend.Store().Service().Search(ctx, opts...)
+       if err != nil {
+               return nil, err
+       }
+       if len(serviceResp.Kvs) == 0 {
+               return nil, nil
+       }
+       return serviceResp.Kvs[0].Value.(*pb.MicroService), nil
+}
+
+// GetServiceFromCache gets service from cache
+func GetServiceFromCache(domainProject string, serviceID string) 
*pb.MicroService {
+       ctx := context.WithValue(context.WithValue(context.Background(),
+               util.CtxCacheOnly, defaultCacheValue),
+               util.CtxGlobal, defaultCacheValue)
+       svc, _ := GetService(ctx, domainProject, serviceID)
+       return svc
+}
+
+func getServicesRawData(ctx context.Context, domainProject string) 
([]*discovery.KeyValue, error) {
+       key := apt.GenerateServiceKey(domainProject, "")
+       opts := append(FromContext(ctx),
+               registry.WithStrKey(key),
+               registry.WithPrefix())
+       resp, err := backend.Store().Service().Search(ctx, opts...)
+       if err != nil {
+               return nil, err
+       }
+       return resp.Kvs, err
+}
+
+//GetAllServicesAcrossDomainProject get services of all domains, projects
+//the map's key is domainProject
+func GetAllServicesAcrossDomainProject(ctx context.Context) 
(map[string][]*pb.MicroService, error) {
+       key := apt.GetServiceRootKey("")
+       opts := append(FromContext(ctx),
+               registry.WithStrKey(key),
+               registry.WithPrefix())
+       serviceResp, err := backend.Store().Service().Search(ctx, opts...)
+       if err != nil {
+               return nil, err
+       }
+
+       services := make(map[string][]*pb.MicroService)
+       if len(serviceResp.Kvs) == 0 {
+               return services, nil
+       }
+
+       for _, value := range serviceResp.Kvs {
+               prefix := util.BytesToStringWithNoCopy(value.Key)
+               parts := strings.Split(prefix, apt.SPLIT)
+               if len(parts) != 7 {
+                       continue
+               }
+               domainProject := parts[4] + apt.SPLIT + parts[5]
+               microService, ok := value.Value.(*pb.MicroService)
+               if !ok {
+                       log.Errorf(nil, "backend key[%s]'s value is not type 
*pb.MicroService", prefix)
+                       continue
+               }
+               services[domainProject] = append(services[domainProject], 
microService)
+       }
+       return services, nil
+}
+
+func GetServicesByDomainProject(ctx context.Context, domainProject string) 
([]*pb.MicroService, error) {
+       kvs, err := getServicesRawData(ctx, domainProject)
+       if err != nil {
+               return nil, err
+       }
+       services := []*pb.MicroService{}
+       for _, kv := range kvs {
+               services = append(services, kv.Value.(*pb.MicroService))
+       }
+       return services, nil
+}
+
+func GetServiceID(ctx context.Context, key *pb.MicroServiceKey) (serviceID 
string, err error) {
+       serviceID, err = searchServiceID(ctx, key)
+       if err != nil {
+               return
+       }
+       if len(serviceID) == 0 {
+               // 别名查询
+               log.Debugf("could not search microservice[%s/%s/%s/%s] id by 
'serviceName', now try 'alias'",
+                       key.Environment, key.AppId, key.ServiceName, 
key.Version)
+               return searchServiceIDFromAlias(ctx, key)
+       }
+       return
+}
+
+func searchServiceID(ctx context.Context, key *pb.MicroServiceKey) (string, 
error) {
+       opts := append(FromContext(ctx), 
registry.WithStrKey(apt.GenerateServiceIndexKey(key)))
+       resp, err := backend.Store().ServiceIndex().Search(ctx, opts...)
+       if err != nil {
+               return "", err
+       }
+       if len(resp.Kvs) == 0 {
+               return "", nil
+       }
+       return resp.Kvs[0].Value.(string), nil
+}
+
+func searchServiceIDFromAlias(ctx context.Context, key *pb.MicroServiceKey) 
(string, error) {
+       opts := append(FromContext(ctx), 
registry.WithStrKey(apt.GenerateServiceAliasKey(key)))
+       resp, err := backend.Store().ServiceAlias().Search(ctx, opts...)
+       if err != nil {
+               return "", err
+       }
+       if len(resp.Kvs) == 0 {
+               return "", nil
+       }
+       return resp.Kvs[0].Value.(string), nil
+}
+
+func GetServiceAllVersions(ctx context.Context, key *pb.MicroServiceKey, alias 
bool) (*discovery.Response, error) {
+       copy := *key
+       copy.Version = ""
+       var (
+               prefix  string
+               indexer discovery.Indexer
+       )
+       if alias {
+               prefix = apt.GenerateServiceAliasKey(&copy)
+               indexer = backend.Store().ServiceAlias()
+       } else {
+               prefix = apt.GenerateServiceIndexKey(&copy)
+               indexer = backend.Store().ServiceIndex()
+       }
+       opts := append(FromContext(ctx),
+               registry.WithStrKey(prefix),
+               registry.WithPrefix(),
+               registry.WithDescendOrder())
+       resp, err := indexer.Search(ctx, opts...)
+       return resp, err
+}
+
+func FindServiceIds(ctx context.Context, versionRule string, key 
*pb.MicroServiceKey) ([]string, bool, error) {
+       // 版本规则
+       match := ParseVersionRule(versionRule)
+       if match == nil {
+               copy := *key
+               copy.Version = versionRule
+               serviceID, err := GetServiceID(ctx, &copy)
+               if err != nil {
+                       return nil, false, err
+               }
+               if len(serviceID) > 0 {
+                       return []string{serviceID}, true, nil
+               }
+               return nil, false, nil
+       }
+
+       searchAlias := false
+       alsoFindAlias := len(key.Alias) > 0
+
+FIND_RULE:
+       resp, err := GetServiceAllVersions(ctx, key, searchAlias)
+       if err != nil {
+               return nil, false, err
+       }
+       if len(resp.Kvs) == 0 {
+               if !alsoFindAlias {
+                       return nil, false, nil
+               }
+               searchAlias = true
+               alsoFindAlias = false
+               goto FIND_RULE
+       }
+       return match(resp.Kvs), true, nil
+}
+
+func ServiceExist(ctx context.Context, domainProject string, serviceID string) 
bool {
+       opts := append(FromContext(ctx),
+               registry.WithStrKey(apt.GenerateServiceKey(domainProject, 
serviceID)),
+               registry.WithCountOnly())
+       resp, err := backend.Store().Service().Search(ctx, opts...)
+       if err != nil || resp.Count == 0 {
+               return false
+       }
+       return true
+}
+
+func GetAllServiceUtil(ctx context.Context) ([]*pb.MicroService, error) {
+       domainProject := util.ParseDomainProject(ctx)
+       services, err := GetServicesByDomainProject(ctx, domainProject)
+       if err != nil {
+               return nil, err
+       }
+       return services, nil
+}
+
+func RemandServiceQuota(ctx context.Context) {
+       plugin.Plugins().Quota().RemandQuotas(ctx, quota.MicroServiceQuotaType)
+}
+
+func RemandInstanceQuota(ctx context.Context) {
+       plugin.Plugins().Quota().RemandQuotas(ctx, 
quota.MicroServiceInstanceQuotaType)
+}
+
+func UpdateService(domainProject string, serviceID string, service 
*pb.MicroService) (opt registry.PluginOp, err error) {
+       opt = registry.PluginOp{}
+       key := apt.GenerateServiceKey(domainProject, serviceID)
+       data, err := json.Marshal(service)
+       if err != nil {
+               log.Errorf(err, "marshal service file failed")
+               return
+       }
+       opt = registry.OpPut(registry.WithStrKey(key), registry.WithValue(data))
+       return
+}
+
+func GetOneDomainProjectServiceCount(ctx context.Context, domainProject 
string) (int64, error) {
+       key := apt.GenerateServiceKey(domainProject, "")
+       opts := append(FromContext(ctx),
+               registry.WithStrKey(key),
+               registry.WithCountOnly(),
+               registry.WithPrefix())
+       resp, err := backend.Store().Service().Search(ctx, opts...)
+       if err != nil {
+               return 0, err
+       }
+       return resp.Count, nil
+}
+
+func GetOneDomainProjectInstanceCount(ctx context.Context, domainProject 
string) (int64, error) {
+       key := apt.GetInstanceRootKey(domainProject) + "/"
+       opts := append(FromContext(ctx),
+               registry.WithStrKey(key),
+               registry.WithCountOnly(),
+               registry.WithPrefix())
+       resp, err := backend.Store().Instance().Search(ctx, opts...)
+       if err != nil {
+               return 0, err
+       }
+       return resp.Count, nil
+}
+
+func SetServiceDefaultValue(service *pb.MicroService) {
+       if len(service.AppId) == 0 {
+               service.AppId = proto.APP_ID
+       }
+       if len(service.Version) == 0 {
+               service.Version = proto.VERSION
+       }
+       if len(service.Level) == 0 {
+               service.Level = "BACK"
+       }
+       if len(service.Status) == 0 {
+               service.Status = pb.MS_UP
+       }
+}
diff --git a/datasource/etcd/util/rule_util.go 
b/datasource/etcd/util/rule_util.go
new file mode 100644
index 0000000..a7eba03
--- /dev/null
+++ b/datasource/etcd/util/rule_util.go
@@ -0,0 +1,300 @@
+/*
+ * 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 util
+
+import (
+       "context"
+       "fmt"
+       "reflect"
+       "regexp"
+       "strings"
+
+       "github.com/apache/servicecomb-service-center/pkg/log"
+       pb "github.com/apache/servicecomb-service-center/pkg/registry"
+       "github.com/apache/servicecomb-service-center/pkg/util"
+       apt "github.com/apache/servicecomb-service-center/server/core"
+       "github.com/apache/servicecomb-service-center/server/core/backend"
+       "github.com/apache/servicecomb-service-center/server/core/proto"
+       "github.com/apache/servicecomb-service-center/server/plugin/registry"
+       scerr "github.com/apache/servicecomb-service-center/server/scerror"
+)
+
+type RuleFilter struct {
+       DomainProject string
+       ProviderRules []*pb.ServiceRule
+}
+
+func (rf *RuleFilter) Filter(ctx context.Context, consumerID string) (bool, 
error) {
+       copyCtx := util.SetContext(util.CloneContext(ctx), util.CtxCacheOnly, 
"1")
+       consumer, err := GetService(copyCtx, rf.DomainProject, consumerID)
+       if consumer == nil {
+               return false, err
+       }
+
+       if len(rf.ProviderRules) == 0 {
+               return true, nil
+       }
+
+       tags, err := GetTagsUtils(copyCtx, rf.DomainProject, consumerID)
+       if err != nil {
+               return false, err
+       }
+       matchErr := MatchRules(rf.ProviderRules, consumer, tags)
+       if matchErr != nil {
+               if matchErr.Code == scerr.ErrPermissionDeny {
+                       return false, nil
+               }
+               return false, matchErr
+       }
+       return true, nil
+}
+
+func (rf *RuleFilter) FilterAll(ctx context.Context, consumerIDs []string) 
(allow []string, deny []string, err error) {
+       l := len(consumerIDs)
+       if l == 0 || len(rf.ProviderRules) == 0 {
+               return consumerIDs, nil, nil
+       }
+
+       allowIdx, denyIdx := 0, l
+       consumers := make([]string, l)
+       for _, consumerID := range consumerIDs {
+               ok, err := rf.Filter(ctx, consumerID)
+               if err != nil {
+                       return nil, nil, err
+               }
+               if ok {
+                       consumers[allowIdx] = consumerID
+                       allowIdx++
+               } else {
+                       denyIdx--
+                       consumers[denyIdx] = consumerID
+               }
+       }
+       return consumers[:allowIdx], consumers[denyIdx:], nil
+}
+
+func GetRulesUtil(ctx context.Context, domainProject string, serviceID string) 
([]*pb.ServiceRule, error) {
+       key := util.StringJoin([]string{
+               apt.GetServiceRuleRootKey(domainProject),
+               serviceID,
+               "",
+       }, "/")
+
+       opts := append(FromContext(ctx), registry.WithStrKey(key), 
registry.WithPrefix())
+       resp, err := backend.Store().Rule().Search(ctx, opts...)
+       if err != nil {
+               return nil, err
+       }
+
+       rules := []*pb.ServiceRule{}
+       for _, kv := range resp.Kvs {
+               rules = append(rules, kv.Value.(*pb.ServiceRule))
+       }
+       return rules, nil
+}
+
+func RuleExist(ctx context.Context, domainProject string, serviceID string, 
attr string, pattern string) bool {
+       opts := append(FromContext(ctx),
+               registry.WithStrKey(apt.GenerateRuleIndexKey(domainProject, 
serviceID, attr, pattern)),
+               registry.WithCountOnly())
+       resp, err := backend.Store().RuleIndex().Search(ctx, opts...)
+       if err != nil || resp.Count == 0 {
+               return false
+       }
+       return true
+}
+
+func GetServiceRuleType(ctx context.Context, domainProject string, serviceID 
string) (string, int, error) {
+       key := apt.GenerateServiceRuleKey(domainProject, serviceID, "")
+       opts := append(FromContext(ctx),
+               registry.WithStrKey(key),
+               registry.WithPrefix())
+       resp, err := backend.Store().Rule().Search(ctx, opts...)
+       if err != nil {
+               log.Errorf(err, "get service[%s] rule failed", serviceID)
+               return "", 0, err
+       }
+       if len(resp.Kvs) == 0 {
+               return "", 0, nil
+       }
+       return resp.Kvs[0].Value.(*pb.ServiceRule).RuleType, len(resp.Kvs), nil
+}
+
+func GetOneRule(ctx context.Context, domainProject, serviceID, ruleID string) 
(*pb.ServiceRule, error) {
+       opts := append(FromContext(ctx),
+               registry.WithStrKey(apt.GenerateServiceRuleKey(domainProject, 
serviceID, ruleID)))
+       resp, err := backend.Store().Rule().Search(ctx, opts...)
+       if err != nil {
+               log.Errorf(err, "get service rule[%s/%s]", serviceID, ruleID)
+               return nil, err
+       }
+       if len(resp.Kvs) == 0 {
+               log.Errorf(nil, "get service rule[%s/%s] failed", serviceID, 
ruleID)
+               return nil, nil
+       }
+       return resp.Kvs[0].Value.(*pb.ServiceRule), nil
+}
+
+func AllowAcrossDimension(ctx context.Context, providerService 
*pb.MicroService, consumerService *pb.MicroService) error {
+       if providerService.AppId != consumerService.AppId {
+               if len(providerService.Properties) == 0 {
+                       return fmt.Errorf("not allow across app access")
+               }
+
+               if allowCrossApp, ok := 
providerService.Properties[proto.PROP_ALLOW_CROSS_APP]; !ok || 
strings.ToLower(allowCrossApp) != "true" {
+                       return fmt.Errorf("not allow across app access")
+               }
+       }
+
+       if 
!apt.IsShared(proto.MicroServiceToKey(util.ParseTargetDomainProject(ctx), 
providerService)) &&
+               providerService.Environment != consumerService.Environment {
+               return fmt.Errorf("not allow across environment access")
+       }
+
+       return nil
+}
+
+func MatchRules(rulesOfProvider []*pb.ServiceRule, consumer *pb.MicroService, 
tagsOfConsumer map[string]string) *scerr.Error {
+       if consumer == nil {
+               return scerr.NewError(scerr.ErrInvalidParams, "consumer is nil")
+       }
+
+       if len(rulesOfProvider) <= 0 {
+               return nil
+       }
+       if rulesOfProvider[0].RuleType == "WHITE" {
+               return patternWhiteList(rulesOfProvider, tagsOfConsumer, 
consumer)
+       }
+       return patternBlackList(rulesOfProvider, tagsOfConsumer, consumer)
+}
+
+func patternWhiteList(rulesOfProvider []*pb.ServiceRule, tagsOfConsumer 
map[string]string, consumer *pb.MicroService) *scerr.Error {
+       v := reflect.Indirect(reflect.ValueOf(consumer))
+       consumerID := consumer.ServiceId
+       for _, rule := range rulesOfProvider {
+               value, err := parsePattern(v, rule, tagsOfConsumer, consumerID)
+               if err != nil {
+                       return err
+               }
+               if len(value) == 0 {
+                       continue
+               }
+
+               match, _ := regexp.MatchString(rule.Pattern, value)
+               if match {
+                       log.Infof("consumer[%s][%s/%s/%s/%s] match white list, 
rule.Pattern is %s, value is %s",
+                               consumerID, consumer.Environment, 
consumer.AppId, consumer.ServiceName, consumer.Version,
+                               rule.Pattern, value)
+                       return nil
+               }
+       }
+       return scerr.NewError(scerr.ErrPermissionDeny, "Not found in white 
list")
+}
+
+func parsePattern(v reflect.Value, rule *pb.ServiceRule, tagsOfConsumer 
map[string]string, consumerID string) (string, *scerr.Error) {
+       if strings.HasPrefix(rule.Attribute, "tag_") {
+               key := rule.Attribute[4:]
+               value := tagsOfConsumer[key]
+               if len(value) == 0 {
+                       log.Infof("can not find service[%s] tag[%s]", 
consumerID, key)
+               }
+               return value, nil
+       }
+       key := v.FieldByName(rule.Attribute)
+       if !key.IsValid() {
+               log.Errorf(nil, "can not find service[%] field[%s], ruleID is 
%s",
+                       consumerID, rule.Attribute, rule.RuleId)
+               return "", scerr.NewErrorf(scerr.ErrInternal, "Can not find 
field '%s'", rule.Attribute)
+       }
+       return key.String(), nil
+
+}
+
+func patternBlackList(rulesOfProvider []*pb.ServiceRule, tagsOfConsumer 
map[string]string, consumer *pb.MicroService) *scerr.Error {
+       v := reflect.Indirect(reflect.ValueOf(consumer))
+       consumerID := consumer.ServiceId
+       for _, rule := range rulesOfProvider {
+               var value string
+               value, err := parsePattern(v, rule, tagsOfConsumer, consumerID)
+               if err != nil {
+                       return err
+               }
+               if len(value) == 0 {
+                       continue
+               }
+
+               match, _ := regexp.MatchString(rule.Pattern, value)
+               if match {
+                       log.Warnf("no permission to access, 
consumer[%s][%s/%s/%s/%s] match black list, rule.Pattern is %s, value is %s",
+                               consumerID, consumer.Environment, 
consumer.AppId, consumer.ServiceName, consumer.Version,
+                               rule.Pattern, value)
+                       return scerr.NewError(scerr.ErrPermissionDeny, "Found 
in black list")
+               }
+       }
+       return nil
+}
+
+func Accessible(ctx context.Context, consumerID string, providerID string) 
*scerr.Error {
+       if len(consumerID) == 0 {
+               return nil
+       }
+
+       domainProject := util.ParseDomainProject(ctx)
+       targetDomainProject := util.ParseTargetDomainProject(ctx)
+
+       consumerService, err := GetService(ctx, domainProject, consumerID)
+       if err != nil {
+               return scerr.NewErrorf(scerr.ErrInternal, "An error occurred in 
query consumer(%s)", err.Error())
+       }
+       if consumerService == nil {
+               return scerr.NewError(scerr.ErrServiceNotExists, "consumer 
serviceID is invalid")
+       }
+
+       // 跨应用权限
+       providerService, err := GetService(ctx, targetDomainProject, providerID)
+       if err != nil {
+               return scerr.NewErrorf(scerr.ErrInternal, "An error occurred in 
query provider(%s)", err.Error())
+       }
+       if providerService == nil {
+               return scerr.NewError(scerr.ErrServiceNotExists, "provider 
serviceID is invalid")
+       }
+
+       err = AllowAcrossDimension(ctx, providerService, consumerService)
+       if err != nil {
+               return scerr.NewError(scerr.ErrPermissionDeny, err.Error())
+       }
+
+       ctx = util.SetContext(util.CloneContext(ctx), util.CtxCacheOnly, "1")
+
+       // 黑白名单
+       rules, err := GetRulesUtil(ctx, targetDomainProject, providerID)
+       if err != nil {
+               return scerr.NewErrorf(scerr.ErrInternal, "An error occurred in 
query provider rules(%s)", err.Error())
+       }
+
+       if len(rules) == 0 {
+               return nil
+       }
+
+       validateTags, err := GetTagsUtils(ctx, domainProject, 
consumerService.ServiceId)
+       if err != nil {
+               return scerr.NewErrorf(scerr.ErrInternal, "An error occurred in 
query consumer tags(%s)", err.Error())
+       }
+
+       return MatchRules(rules, consumerService, validateTags)
+}
diff --git a/datasource/etcd/util/rule_util_test.go 
b/datasource/etcd/util/rule_util_test.go
new file mode 100644
index 0000000..7bdc853
--- /dev/null
+++ b/datasource/etcd/util/rule_util_test.go
@@ -0,0 +1,306 @@
+/*
+ * 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 util
+
+import (
+       "context"
+       "net/http"
+       "testing"
+
+       "github.com/apache/servicecomb-service-center/pkg/registry"
+       "github.com/apache/servicecomb-service-center/pkg/util"
+       "github.com/apache/servicecomb-service-center/server/core/proto"
+)
+
+func TestRuleFilter_Filter(t *testing.T) {
+       rf := RuleFilter{
+               DomainProject: "",
+               ProviderRules: []*registry.ServiceRule{},
+       }
+       _, err := rf.Filter(context.Background(), "")
+       if err != nil {
+               t.Fatalf("RuleFilter Filter failed")
+       }
+       _, _, err = rf.FilterAll(context.Background(), []string{""})
+       if err != nil {
+               t.Fatalf("RuleFilter FilterAll failed")
+       }
+       rf.ProviderRules = []*registry.ServiceRule{
+               {},
+       }
+       _, _, err = rf.FilterAll(context.Background(), []string{""})
+       if err != nil {
+               t.Fatalf("RuleFilter FilterAll failed")
+       }
+}
+
+func TestGetRulesUtil(t *testing.T) {
+       _, err := GetRulesUtil(context.Background(), "", "")
+       if err != nil {
+               t.Fatalf("GetRulesUtil failed")
+       }
+
+       _, err = GetOneRule(context.Background(), "", "", "")
+       if err != nil {
+               t.Fatalf("GetOneRule failed")
+       }
+}
+
+func TestRuleExist(t *testing.T) {
+       defer func() {
+               if r := recover(); r != nil {
+                       t.Fatalf("TestRuleExist panic")
+               }
+       }()
+       RuleExist(util.SetContext(context.Background(), util.CtxCacheOnly, 
"1"), "", "", "", "")
+       RuleExist(context.Background(), "", "", "", "")
+}
+
+func TestGetServiceRuleType(t *testing.T) {
+       _, _, err := GetServiceRuleType(context.Background(), "", "")
+       if err != nil {
+               t.Fatalf("GetServiceRuleType failed")
+       }
+}
+
+func TestAllowAcrossApp(t *testing.T) {
+       err := AllowAcrossDimension(context.Background(), 
&registry.MicroService{
+               AppId: "a",
+       }, &registry.MicroService{
+               AppId: "a",
+       })
+       if err != nil {
+               t.Fatalf("AllowAcrossApp with the same appId and no property 
failed")
+       }
+
+       err = AllowAcrossDimension(context.Background(), &registry.MicroService{
+               AppId: "a",
+       }, &registry.MicroService{
+               AppId: "c",
+       })
+       if err == nil {
+               t.Fatalf("AllowAcrossApp with the diff appId and no property 
failed")
+       }
+
+       err = AllowAcrossDimension(context.Background(), &registry.MicroService{
+               AppId: "a",
+               Properties: map[string]string{
+                       proto.PROP_ALLOW_CROSS_APP: "true",
+               },
+       }, &registry.MicroService{
+               AppId: "a",
+       })
+       if err != nil {
+               t.Fatalf("AllowAcrossApp with the same appId and allow property 
failed")
+       }
+
+       err = AllowAcrossDimension(context.Background(), &registry.MicroService{
+               AppId: "a",
+               Properties: map[string]string{
+                       proto.PROP_ALLOW_CROSS_APP: "true",
+               },
+       }, &registry.MicroService{
+               AppId: "b",
+       })
+       if err != nil {
+               t.Fatalf("AllowAcrossApp with the diff appId and allow property 
failed")
+       }
+
+       err = AllowAcrossDimension(context.Background(), &registry.MicroService{
+               AppId: "a",
+               Properties: map[string]string{
+                       proto.PROP_ALLOW_CROSS_APP: "false",
+               },
+       }, &registry.MicroService{
+               AppId: "b",
+       })
+       if err == nil {
+               t.Fatalf("AllowAcrossApp with the diff appId and deny property 
failed")
+       }
+
+       err = AllowAcrossDimension(context.Background(), &registry.MicroService{
+               AppId: "a",
+               Properties: map[string]string{
+                       proto.PROP_ALLOW_CROSS_APP: "",
+               },
+       }, &registry.MicroService{
+               AppId: "b",
+       })
+       if err == nil {
+               t.Fatalf("AllowAcrossApp with the diff appId and empty property 
failed")
+       }
+}
+
+func TestMatchRules(t *testing.T) {
+       err := MatchRules([]*registry.ServiceRule{
+               {
+                       RuleType:  "WHITE",
+                       Attribute: "",
+                       Pattern:   "",
+               },
+       }, nil, nil)
+       if err == nil {
+               t.Fatalf("MatchRules nil failed")
+       }
+
+       err = MatchRules([]*registry.ServiceRule{
+               {
+                       RuleType:  "WHITE",
+                       Attribute: "",
+                       Pattern:   "",
+               },
+       }, &registry.MicroService{}, nil)
+       if err == nil {
+               t.Fatalf("MatchRules invalid WHITE failed")
+       }
+
+       err = MatchRules([]*registry.ServiceRule{
+               {
+                       RuleType:  "WHITE",
+                       Attribute: "ServiceName",
+                       Pattern:   "^a.*",
+               },
+       }, &registry.MicroService{
+               ServiceName: "a",
+       }, nil)
+       if err != nil {
+               t.Fatalf("MatchRules WHITE with field ServiceName failed")
+       }
+
+       err = MatchRules([]*registry.ServiceRule{
+               {
+                       RuleType:  "WHITE",
+                       Attribute: "tag_a",
+                       Pattern:   "^b.*",
+               },
+       }, &registry.MicroService{}, map[string]string{
+               "a": "b",
+       })
+       if err != nil {
+               t.Fatalf("MatchRules WHITE with tag b failed")
+       }
+
+       err = MatchRules([]*registry.ServiceRule{
+               {
+                       RuleType:  "WHITE",
+                       Attribute: "tag_a",
+                       Pattern:   "^b.*",
+               },
+       }, &registry.MicroService{}, map[string]string{
+               "a": "c",
+       })
+       if err == nil {
+               t.Fatalf("MatchRules WHITE with tag c failed")
+       }
+
+       err = MatchRules([]*registry.ServiceRule{
+               {
+                       RuleType:  "BLACK",
+                       Attribute: "tag_a",
+                       Pattern:   "^b.*",
+               },
+       }, &registry.MicroService{}, map[string]string{
+               "a": "b",
+       })
+       if err == nil {
+               t.Fatalf("MatchRules BLACK with tag b failed")
+       }
+
+       err = MatchRules([]*registry.ServiceRule{
+               {
+                       RuleType:  "BLACK",
+                       Attribute: "ServiceName",
+                       Pattern:   "^a.*",
+               },
+       }, &registry.MicroService{
+               ServiceName: "a",
+       }, nil)
+       if err == nil {
+               t.Fatalf("MatchRules BLACK with field ServiceName failed")
+       }
+
+       err = MatchRules([]*registry.ServiceRule{
+               {
+                       RuleType:  "BLACK",
+                       Attribute: "tag_a",
+                       Pattern:   "^b.*",
+               },
+       }, &registry.MicroService{}, map[string]string{
+               "a": "c",
+       })
+       if err != nil {
+               t.Fatalf("MatchRules BLACK with tag c failed")
+       }
+
+       err = MatchRules([]*registry.ServiceRule{
+               {
+                       RuleType:  "BLACK",
+                       Attribute: "tag_a",
+                       Pattern:   "^b.*",
+               },
+       }, &registry.MicroService{}, map[string]string{
+               "b": "b",
+       })
+       if err != nil {
+               t.Fatalf("MatchRules with not exist tag failed")
+       }
+}
+
+func TestGetConsumer(t *testing.T) {
+       _, _, err := GetAllProviderIds(context.Background(), "", 
&registry.MicroService{})
+       if err != nil {
+               t.Fatalf("GetConsumerIdsByProvider invalid failed")
+       }
+
+       _, _, err = GetAllConsumerIds(context.Background(), "", 
&registry.MicroService{
+               ServiceId: "a",
+       })
+       if err != nil {
+               t.Fatalf("GetConsumerIdsByProvider WithCacheOnly not exist 
service failed")
+       }
+
+       _, err = GetConsumerIds(context.Background(), "",
+               &registry.MicroService{
+                       ServiceId: "a",
+               })
+       if err != nil {
+               t.Fatalf("GetConsumerIds WithCacheOnly failed")
+       }
+}
+
+func TestGetProvider(t *testing.T) {
+       _, err := GetProviderIds(context.Background(), "",
+               &registry.MicroService{
+                       ServiceId: "a",
+               })
+       if err != nil {
+               t.Fatalf("GetProviderIds WithCacheOnly failed")
+       }
+
+       _, _, err = GetAllProviderIds(context.Background(), "", 
&registry.MicroService{})
+       if err != nil {
+               t.Fatalf("GetAllProviderIds WithCacheOnly failed")
+       }
+}
+
+func TestAccessible(t *testing.T) {
+       err := Accessible(context.Background(), "xxx", "")
+       if err.StatusCode() != http.StatusBadRequest {
+               t.Fatalf("Accessible invalid failed")
+       }
+}
diff --git a/server/plugin/tracing/tracing.go 
b/datasource/etcd/util/schema_util.go
similarity index 67%
copy from server/plugin/tracing/tracing.go
copy to datasource/etcd/util/schema_util.go
index 309eeb4..298ef99 100644
--- a/server/plugin/tracing/tracing.go
+++ b/datasource/etcd/util/schema_util.go
@@ -15,27 +15,23 @@
  * limitations under the License.
  */
 
-package tracing
+package util
 
 import (
        "context"
+
+       "github.com/apache/servicecomb-service-center/server/core/backend"
        "github.com/apache/servicecomb-service-center/server/plugin/registry"
 )
 
-const CtxTraceSpan = "x-trace-span"
-
-type Request interface{}
-type Span interface{}
-
-type Tracing interface {
-       ServerBegin(operationName string, r Request) Span
-       ServerEnd(span Span, code int, message string)
-       ClientBegin(operationName string, r Request) Span
-       ClientEnd(span Span, code int, message string)
-}
-
-type RegistryRequest struct {
-       Ctx      context.Context
-       Endpoint string
-       Options  registry.PluginOp
+func CheckSchemaInfoExist(ctx context.Context, key string) (bool, error) {
+       opts := append(FromContext(ctx), registry.WithStrKey(key), 
registry.WithCountOnly())
+       resp, errDo := backend.Store().Schema().Search(ctx, opts...)
+       if errDo != nil {
+               return false, errDo
+       }
+       if resp.Count == 0 {
+               return false, nil
+       }
+       return true, nil
 }
diff --git a/server/plugin/uuid/uuid.go 
b/datasource/etcd/util/schema_util_test.go
similarity index 81%
copy from server/plugin/uuid/uuid.go
copy to datasource/etcd/util/schema_util_test.go
index c8aaa7c..f67f3cb 100644
--- a/server/plugin/uuid/uuid.go
+++ b/datasource/etcd/util/schema_util_test.go
@@ -15,15 +15,16 @@
  * limitations under the License.
  */
 
-package uuid
+package util
 
 import (
        "context"
+       "testing"
 )
 
-const ContextKey = "_uuid_key"
-
-type UUID interface {
-       GetServiceID(ctx context.Context) string
-       GetInstanceID(ctx context.Context) string
+func TestCheckSchemaInfoExist(t *testing.T) {
+       _, err := CheckSchemaInfoExist(context.Background(), "")
+       if err == nil {
+               t.Fatalf("TestCheckSchemaInfoExist failed")
+       }
 }
diff --git a/datasource/etcd/util/tag_util.go b/datasource/etcd/util/tag_util.go
new file mode 100644
index 0000000..e63fb7c
--- /dev/null
+++ b/datasource/etcd/util/tag_util.go
@@ -0,0 +1,67 @@
+/*
+ * 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 util
+
+import (
+       "context"
+       "encoding/json"
+
+       "github.com/apache/servicecomb-service-center/pkg/log"
+       "github.com/apache/servicecomb-service-center/pkg/util"
+       apt "github.com/apache/servicecomb-service-center/server/core"
+       "github.com/apache/servicecomb-service-center/server/core/backend"
+       "github.com/apache/servicecomb-service-center/server/plugin/registry"
+       scerr "github.com/apache/servicecomb-service-center/server/scerror"
+)
+
+func AddTagIntoETCD(ctx context.Context, domainProject string, serviceID 
string, dataTags map[string]string) *scerr.Error {
+       key := apt.GenerateServiceTagKey(domainProject, serviceID)
+       data, err := json.Marshal(dataTags)
+       if err != nil {
+               return scerr.NewError(scerr.ErrInternal, err.Error())
+       }
+
+       resp, err := backend.Registry().TxnWithCmp(ctx,
+               []registry.PluginOp{registry.OpPut(registry.WithStrKey(key), 
registry.WithValue(data))},
+               []registry.CompareOp{registry.OpCmp(
+                       
registry.CmpVer(util.StringToBytesWithNoCopy(apt.GenerateServiceKey(domainProject,
 serviceID))),
+                       registry.CmpNotEqual, 0)},
+               nil)
+       if err != nil {
+               return scerr.NewError(scerr.ErrUnavailableBackend, err.Error())
+       }
+       if !resp.Succeeded {
+               return scerr.NewError(scerr.ErrServiceNotExists, "Service does 
not exist.")
+       }
+       return nil
+}
+
+func GetTagsUtils(ctx context.Context, domainProject, serviceID string) (tags 
map[string]string, err error) {
+       key := apt.GenerateServiceTagKey(domainProject, serviceID)
+       opts := append(FromContext(ctx), registry.WithStrKey(key))
+       resp, err := backend.Store().ServiceTag().Search(ctx, opts...)
+       if err != nil {
+               log.Errorf(err, "get service[%s] tags file failed", serviceID)
+               return tags, err
+       }
+
+       if len(resp.Kvs) != 0 {
+               tags = resp.Kvs[0].Value.(map[string]string)
+       }
+       return tags, nil
+}
diff --git a/server/plugin/uuid/uuid.go b/datasource/etcd/util/tag_util_test.go
similarity index 69%
copy from server/plugin/uuid/uuid.go
copy to datasource/etcd/util/tag_util_test.go
index c8aaa7c..61afb76 100644
--- a/server/plugin/uuid/uuid.go
+++ b/datasource/etcd/util/tag_util_test.go
@@ -15,15 +15,23 @@
  * limitations under the License.
  */
 
-package uuid
+package util
 
 import (
        "context"
+       "testing"
 )
 
-const ContextKey = "_uuid_key"
+func TestAddTagIntoETCD(t *testing.T) {
+       err := AddTagIntoETCD(context.Background(), "", "", 
map[string]string{"a": "1"})
+       if err == nil {
+               t.Fatalf(`AddTagIntoETCD with {"a": "1"} tags failed`)
+       }
+}
 
-type UUID interface {
-       GetServiceID(ctx context.Context) string
-       GetInstanceID(ctx context.Context) string
+func TestGetTagsUtils(t *testing.T) {
+       _, err := GetTagsUtils(context.Background(), "", "")
+       if err != nil {
+               t.Fatalf(`GetTagsUtils failed`)
+       }
 }
diff --git a/server/plugin/tracing/tracing.go b/datasource/etcd/util/util.go
similarity index 65%
copy from server/plugin/tracing/tracing.go
copy to datasource/etcd/util/util.go
index 309eeb4..aeaab00 100644
--- a/server/plugin/tracing/tracing.go
+++ b/datasource/etcd/util/util.go
@@ -15,27 +15,24 @@
  * limitations under the License.
  */
 
-package tracing
+package util
 
 import (
        "context"
+       "github.com/apache/servicecomb-service-center/pkg/util"
        "github.com/apache/servicecomb-service-center/server/plugin/registry"
 )
 
-const CtxTraceSpan = "x-trace-span"
-
-type Request interface{}
-type Span interface{}
-
-type Tracing interface {
-       ServerBegin(operationName string, r Request) Span
-       ServerEnd(span Span, code int, message string)
-       ClientBegin(operationName string, r Request) Span
-       ClientEnd(span Span, code int, message string)
-}
-
-type RegistryRequest struct {
-       Ctx      context.Context
-       Endpoint string
-       Options  registry.PluginOp
+func FromContext(ctx context.Context) []registry.PluginOpOption {
+       opts := make([]registry.PluginOpOption, 0, 5)
+       switch {
+       case ctx.Value(util.CtxNocache) == "1":
+               opts = append(opts, registry.WithNoCache())
+       case ctx.Value(util.CtxCacheOnly) == "1":
+               opts = append(opts, registry.WithCacheOnly())
+       }
+       if ctx.Value(util.CtxGlobal) == "1" {
+               opts = append(opts, registry.WithGlobal())
+       }
+       return opts
 }
diff --git a/datasource/etcd/util/util_suite_test.go 
b/datasource/etcd/util/util_suite_test.go
new file mode 100644
index 0000000..716ff72
--- /dev/null
+++ b/datasource/etcd/util/util_suite_test.go
@@ -0,0 +1,140 @@
+/*
+ * 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 util_test
+
+import (
+       _ 
"github.com/apache/servicecomb-service-center/server/plugin/discovery/etcd"
+       _ 
"github.com/apache/servicecomb-service-center/server/plugin/quota/buildin"
+       _ 
"github.com/apache/servicecomb-service-center/server/plugin/registry/buildin"
+)
+
+import (
+       "context"
+       "testing"
+
+       serviceUtil 
"github.com/apache/servicecomb-service-center/datasource/etcd/util"
+       proto "github.com/apache/servicecomb-service-center/pkg/registry"
+       "github.com/apache/servicecomb-service-center/pkg/util"
+       "github.com/apache/servicecomb-service-center/server/plugin/registry"
+       . "github.com/onsi/ginkgo"
+       "github.com/onsi/ginkgo/reporters"
+       . "github.com/onsi/gomega"
+)
+
+func init() {
+}
+
+func TestMicroservice(t *testing.T) {
+       RegisterFailHandler(Fail)
+       junitReporter := reporters.NewJUnitReporter("model.junit.xml")
+       RunSpecsWithDefaultAndCustomReporters(t, "model Suite", 
[]Reporter{junitReporter})
+}
+
+func TestFindServiceIds(t *testing.T) {
+       _, _, err := serviceUtil.FindServiceIds(context.Background(),
+               "latest", &proto.MicroServiceKey{})
+       if err != nil {
+               t.Fatalf("TestFindServiceIds failed")
+       }
+
+       _, _, err = serviceUtil.FindServiceIds(context.Background(),
+               "1.0.0", &proto.MicroServiceKey{})
+       if err != nil {
+               t.Fatalf("TestFindServiceIds failed")
+       }
+
+       _, _, err = serviceUtil.FindServiceIds(context.Background(),
+               "1.0+", &proto.MicroServiceKey{Alias: "test"})
+       if err != nil {
+               t.Fatalf("TestFindServiceIds failed")
+       }
+}
+
+func TestGetService(t *testing.T) {
+       _, err := serviceUtil.GetService(context.Background(), "", "")
+       if err != nil {
+               t.Fatalf("TestGetService failed")
+       }
+
+       _, err = serviceUtil.GetServicesByDomainProject(context.Background(), 
"")
+       if err != nil {
+               t.Fatalf("TestGetService failed")
+       }
+
+       _, err = serviceUtil.GetAllServiceUtil(context.Background())
+       if err != nil {
+               t.Fatalf("TestGetService failed")
+       }
+
+       _, err = serviceUtil.GetServiceWithRev(context.Background(), "", "", 0)
+       if err != nil {
+               t.Fatalf("TestGetService failed")
+       }
+
+       _, err = serviceUtil.GetServiceWithRev(context.Background(), "", "", 1)
+       if err != nil {
+               t.Fatalf("TestGetService failed")
+       }
+}
+
+func TestServiceExist(t *testing.T) {
+       defer func() {
+               if r := recover(); r != nil {
+                       t.Fatalf("TestServiceExist failed")
+               }
+       }()
+       serviceUtil.ServiceExist(util.SetContext(context.Background(), 
util.CtxCacheOnly, "1"), "", "")
+}
+
+func TestFromContext(t *testing.T) {
+       ctx := context.WithValue(context.Background(), util.CtxNocache, "1")
+       opts := serviceUtil.FromContext(ctx)
+       if len(opts) == 0 {
+               t.Fatalf("TestFromContext failed")
+       }
+
+       op := registry.OptionsToOp(opts...)
+       if op.Mode != registry.ModeNoCache {
+               t.Fatalf("TestFromContext failed")
+       }
+
+       ctx = context.WithValue(context.Background(), util.CtxCacheOnly, "1")
+       opts = serviceUtil.FromContext(ctx)
+       if len(opts) == 0 {
+               t.Fatalf("TestFromContext failed")
+       }
+
+       op = registry.OptionsToOp(opts...)
+       if op.Mode != registry.ModeCache {
+               t.Fatalf("TestFromContext failed")
+       }
+}
+
+func TestRemandQuota(t *testing.T) {
+       serviceUtil.RemandServiceQuota(context.Background())
+       serviceUtil.RemandInstanceQuota(context.Background())
+}
+
+func TestSetDefault(t *testing.T) {
+       service := &proto.MicroService{}
+       serviceUtil.SetServiceDefaultValue(service)
+       if len(service.Level) == 0 ||
+               len(service.Status) == 0 {
+               t.Fatalf(`TestSetDefault failed`)
+       }
+}
diff --git a/datasource/etcd/util/versionrule.go 
b/datasource/etcd/util/versionrule.go
new file mode 100644
index 0000000..1b3be1e
--- /dev/null
+++ b/datasource/etcd/util/versionrule.go
@@ -0,0 +1,264 @@
+/*
+ * 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 util
+
+import (
+       "regexp"
+       "sort"
+       "strconv"
+       "strings"
+
+       "github.com/apache/servicecomb-service-center/pkg/util"
+       "github.com/apache/servicecomb-service-center/server/plugin/discovery"
+)
+
+type VersionRule func(sorted []string, kvs map[string]*discovery.KeyValue, 
start, end string) []string
+
+func (vr VersionRule) Match(kvs []*discovery.KeyValue, ops ...string) []string 
{
+       sorter := &serviceKeySorter{
+               sortArr: make([]string, len(kvs)),
+               kvs:     make(map[string]*discovery.KeyValue, len(kvs)),
+               cmp:     Larger,
+       }
+       for i, kv := range kvs {
+               key := util.BytesToStringWithNoCopy(kv.Key)
+               ver := key[strings.LastIndex(key, "/")+1:]
+               sorter.sortArr[i] = ver
+               sorter.kvs[ver] = kv
+       }
+       sort.Sort(sorter)
+
+       args := [2]string{}
+       switch {
+       case len(ops) > 1:
+               args[1] = ops[1]
+               fallthrough
+       case len(ops) > 0:
+               args[0] = ops[0]
+       }
+       return vr(sorter.sortArr, sorter.kvs, args[0], args[1])
+}
+
+type serviceKeySorter struct {
+       sortArr []string
+       kvs     map[string]*discovery.KeyValue
+       cmp     func(i, j string) bool
+}
+
+func (sks *serviceKeySorter) Len() int {
+       return len(sks.sortArr)
+}
+
+func (sks *serviceKeySorter) Swap(i, j int) {
+       sks.sortArr[i], sks.sortArr[j] = sks.sortArr[j], sks.sortArr[i]
+}
+
+func (sks *serviceKeySorter) Less(i, j int) bool {
+       return sks.cmp(sks.sortArr[i], sks.sortArr[j])
+}
+
+func VersionToInt64(versionStr string) (ret int64, err error) {
+       verBytes := [4]int16{}
+       idx := 0
+       for i := 0; i < 4 && idx < len(versionStr); i++ {
+               f := strings.IndexRune(versionStr[idx:], '.')
+               if f < 0 {
+                       f = len(versionStr) - idx
+               }
+               integer, err := strconv.ParseInt(versionStr[idx:idx+f], 10, 16)
+               if err != nil {
+                       return 0, err
+               }
+               verBytes[i] = int16(integer)
+               idx += f + 1
+       }
+       ret = util.Int16ToInt64(verBytes[:])
+       return
+}
+
+func Larger(start, end string) bool {
+       s, _ := VersionToInt64(start)
+       e, _ := VersionToInt64(end)
+       return s > e
+}
+
+func LessEqual(start, end string) bool {
+       return !Larger(start, end)
+}
+
+func Latest(sorted []string, kvs map[string]*discovery.KeyValue, start, end 
string) []string {
+       if len(sorted) == 0 {
+               return []string{}
+       }
+       return []string{kvs[sorted[0]].Value.(string)}
+}
+
+func Range(sorted []string, kvs map[string]*discovery.KeyValue, start, end 
string) []string {
+       result := make([]string, len(sorted))
+       i, flag := 0, 0
+
+       if Larger(start, end) {
+               start, end = end, start
+       }
+
+       l := len(sorted)
+       if l == 0 || Larger(start, sorted[0]) || LessEqual(end, sorted[l-1]) {
+               return []string{}
+       }
+
+       for _, k := range sorted {
+               // end >= k >= start
+               switch flag {
+               case 0:
+                       if LessEqual(end, k) {
+                               continue
+                       }
+                       flag = 1
+               case 1:
+                       if Larger(start, k) {
+                               return result[:i]
+                       }
+               }
+
+               result[i] = kvs[k].Value.(string)
+               i++
+       }
+       return result[:i]
+}
+
+func AtLess(sorted []string, kvs map[string]*discovery.KeyValue, start, end 
string) []string {
+       result := make([]string, len(sorted))
+
+       if len(sorted) == 0 || Larger(start, sorted[0]) {
+               return []string{}
+       }
+
+       for i, k := range sorted {
+               if Larger(start, k) {
+                       return result[:i]
+               }
+               result[i] = kvs[k].Value.(string)
+       }
+       return result[:]
+}
+
+func ParseVersionRule(versionRule string) func(kvs []*discovery.KeyValue) 
[]string {
+       if len(versionRule) == 0 {
+               return nil
+       }
+
+       rangeIdx := strings.Index(versionRule, "-")
+       switch {
+       case versionRule == "latest":
+               return func(kvs []*discovery.KeyValue) []string {
+                       return VersionRule(Latest).Match(kvs)
+               }
+       case versionRule[len(versionRule)-1:] == "+":
+               // 取最低版本及高版本集合
+               start := versionRule[:len(versionRule)-1]
+               return func(kvs []*discovery.KeyValue) []string {
+                       return VersionRule(AtLess).Match(kvs, start)
+               }
+       case rangeIdx > 0:
+               // 取版本范围集合
+               start := versionRule[:rangeIdx]
+               end := versionRule[rangeIdx+1:]
+               return func(kvs []*discovery.KeyValue) []string {
+                       return VersionRule(Range).Match(kvs, start, end)
+               }
+       default:
+               // 精确匹配
+               return nil
+       }
+}
+
+func VersionMatchRule(version string, versionRule string) bool {
+       match := ParseVersionRule(versionRule)
+       if match == nil {
+               return version == versionRule
+       }
+
+       return len(match([]*discovery.KeyValue{
+               {
+                       Key:   util.StringToBytesWithNoCopy("/" + version),
+                       Value: "",
+               },
+       })) > 0
+}
+
+type VersionRegexp struct {
+       Regex *regexp.Regexp
+       Fuzzy bool
+}
+
+func (vr *VersionRegexp) MatchString(s string) bool {
+       if vr.Regex != nil && !vr.Regex.MatchString(s) {
+               return false
+       }
+       return vr.validateVersionRule(s) == nil
+}
+
+func (vr *VersionRegexp) String() string {
+       if vr.Fuzzy {
+               return "the form x[.y[.z]] or x[.y[.z]]+ or x[.y[.z]]-x[.y[.z]] 
or 'latest' where x y and z are 0-32767 range"
+       }
+       return "the form x[.y[.z]] where x y and z are 0-32767 range"
+}
+
+func (vr *VersionRegexp) validateVersionRule(versionRule string) (err error) {
+       if len(versionRule) == 0 {
+               return
+       }
+
+       if !vr.Fuzzy {
+               _, err = VersionToInt64(versionRule)
+               return
+       }
+
+       rangeIdx := strings.Index(versionRule, "-")
+       switch {
+       case versionRule == "latest":
+               return
+       case versionRule[len(versionRule)-1:] == "+":
+               // 取最低版本及高版本集合
+               start := versionRule[:len(versionRule)-1]
+               _, err = VersionToInt64(start)
+       case rangeIdx > 0:
+               // 取版本范围集合
+               start := versionRule[:rangeIdx]
+               end := versionRule[rangeIdx+1:]
+               _, err = VersionToInt64(start)
+               if err == nil {
+                       _, err = VersionToInt64(end)
+               }
+       default:
+               // 精确匹配
+               _, err = VersionToInt64(versionRule)
+       }
+       return
+}
+
+func NewVersionRegexp(fuzzy bool) (vr *VersionRegexp) {
+       vr = &VersionRegexp{Fuzzy: fuzzy}
+       if fuzzy {
+               vr.Regex, _ = 
regexp.Compile(`^\d+(\.\d+){0,3}\+?$|^\d+(\.\d+){0,3}-\d+(\.\d+){0,3}$|^latest$`)
+               return
+       }
+       vr.Regex, _ = regexp.Compile(`^\d+(\.\d+){0,3}$`)
+       return
+}
diff --git a/datasource/etcd/util/versionrule_test.go 
b/datasource/etcd/util/versionrule_test.go
new file mode 100644
index 0000000..bd47d08
--- /dev/null
+++ b/datasource/etcd/util/versionrule_test.go
@@ -0,0 +1,413 @@
+/*
+ * 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 util
+
+import (
+       "fmt"
+       "reflect"
+       "sort"
+       "testing"
+
+       "github.com/apache/servicecomb-service-center/pkg/log"
+       "github.com/apache/servicecomb-service-center/server/plugin/discovery"
+       "github.com/stretchr/testify/assert"
+)
+
+const VERSIONRULE_BASE = 5000
+
+func BenchmarkVersionRule_Latest_GetServicesIds(b *testing.B) {
+       var kvs = make([]*discovery.KeyValue, VERSIONRULE_BASE)
+       for i := 1; i <= VERSIONRULE_BASE; i++ {
+               kvs[i-1] = &discovery.KeyValue{
+                       Key:   []byte(fmt.Sprintf("/service/ver/1.%d", i)),
+                       Value: []byte(fmt.Sprintf("%d", i)),
+               }
+       }
+       b.N = VERSIONRULE_BASE
+       b.ResetTimer()
+       for i := 0; i < b.N; i++ {
+               VersionRule(Latest).Match(kvs)
+       }
+       b.ReportAllocs()
+       // 5000    7105020 ns/op         2180198 B/op      39068 allocs/op
+}
+
+func BenchmarkVersionRule_Range_GetServicesIds(b *testing.B) {
+       var kvs = make([]*discovery.KeyValue, VERSIONRULE_BASE)
+       for i := 1; i <= VERSIONRULE_BASE; i++ {
+               kvs[i-1] = &discovery.KeyValue{
+                       Key:   []byte(fmt.Sprintf("/service/ver/1.%d", i)),
+                       Value: []byte(fmt.Sprintf("%d", i)),
+               }
+       }
+       b.N = VERSIONRULE_BASE
+       b.ResetTimer()
+       for i := 0; i < b.N; i++ {
+               VersionRule(Range).Match(kvs, fmt.Sprintf("1.%d", i), 
fmt.Sprintf("1.%d", i+VERSIONRULE_BASE/10))
+       }
+       b.ReportAllocs()
+       // 5000    7244029 ns/op         2287389 B/op      39584 allocs/op
+}
+
+func BenchmarkVersionRule_AtLess_GetServicesIds(b *testing.B) {
+       var kvs = make([]*discovery.KeyValue, VERSIONRULE_BASE)
+       for i := 1; i <= VERSIONRULE_BASE; i++ {
+               kvs[i-1] = &discovery.KeyValue{
+                       Key:   []byte(fmt.Sprintf("/service/ver/1.%d", i)),
+                       Value: []byte(fmt.Sprintf("%d", i)),
+               }
+       }
+       b.N = VERSIONRULE_BASE
+       b.ResetTimer()
+       for i := 0; i < b.N; i++ {
+               VersionRule(AtLess).Match(kvs, fmt.Sprintf("1.%d", i))
+       }
+       b.ReportAllocs()
+       // 5000   11221098 ns/op         3174720 B/op      58064 allocs/op
+}
+
+func BenchmarkParseVersionRule(b *testing.B) {
+       f := ParseVersionRule("latest")
+       kvs := []*discovery.KeyValue{
+               {
+                       Key:   []byte("/service/ver/1.0.300"),
+                       Value: "1.0.300",
+               },
+               {
+                       Key:   []byte("/service/ver/1.0.303"),
+                       Value: "1.0.303",
+               },
+               {
+                       Key:   []byte("/service/ver/1.0.304"),
+                       Value: "1.0.304",
+               },
+       }
+       b.ResetTimer()
+       b.RunParallel(func(pb *testing.PB) {
+               for pb.Next() {
+                       f(kvs)
+               }
+       })
+       b.ReportAllocs()
+}
+
+func TestSorter(t *testing.T) {
+       log.Info("normal")
+
+       t.Run("version asc", func(t *testing.T) {
+               kvs := []string{"1.0.0", "1.0.1"}
+               sort.Sort(&serviceKeySorter{
+                       sortArr: kvs,
+                       kvs:     make(map[string]*discovery.KeyValue),
+                       cmp:     Larger,
+               })
+               assert.Equal(t, "1.0.1", kvs[0])
+               assert.Equal(t, "1.0.0", kvs[1])
+       })
+
+       t.Run("version desc", func(t *testing.T) {
+               kvs := []string{"1.0.1", "1.0.0"}
+               sort.Sort(&serviceKeySorter{
+                       sortArr: kvs,
+                       kvs:     make(map[string]*discovery.KeyValue),
+                       cmp:     Larger,
+               })
+               assert.Equal(t, "1.0.1", kvs[0])
+               assert.Equal(t, "1.0.0", kvs[1])
+       })
+
+       t.Run("len(v1) != len(v2)", func(t *testing.T) {
+               kvs := []string{"1.0.0.0", "1.0.1"}
+               sort.Sort(&serviceKeySorter{
+                       sortArr: kvs,
+                       kvs:     make(map[string]*discovery.KeyValue),
+                       cmp:     Larger,
+               })
+               assert.Equal(t, "1.0.1", kvs[0])
+               assert.Equal(t, "1.0.0.0", kvs[1])
+       })
+
+       t.Run("1.0.9 vs 1.0.10", func(t *testing.T) {
+               kvs := []string{"1.0.9", "1.0.10"}
+               sort.Sort(&serviceKeySorter{
+                       sortArr: kvs,
+                       kvs:     make(map[string]*discovery.KeyValue),
+                       cmp:     Larger,
+               })
+               assert.Equal(t, "1.0.10", kvs[0])
+               assert.Equal(t, "1.0.9", kvs[1])
+       })
+
+       t.Run("1.10 vs 4", func(t *testing.T) {
+               kvs := []string{"1.10", "4"}
+               sort.Sort(&serviceKeySorter{
+                       sortArr: kvs,
+                       kvs:     make(map[string]*discovery.KeyValue),
+                       cmp:     Larger,
+               })
+               assert.Equal(t, "4", kvs[0])
+               assert.Equal(t, "1.10", kvs[1])
+       })
+
+       log.Info("exception")
+
+       t.Run("invalid version1", func(t *testing.T) {
+               kvs := []string{"1.a", "1.0.1.a", ""}
+               sort.Sort(&serviceKeySorter{
+                       sortArr: kvs,
+                       kvs:     make(map[string]*discovery.KeyValue),
+                       cmp:     Larger,
+               })
+               assert.Equal(t, "1.a", kvs[0])
+               assert.Equal(t, "1.0.1.a", kvs[1])
+               assert.Equal(t, "", kvs[2])
+       })
+
+       t.Run("invalid version2 > 32767", func(t *testing.T) {
+               kvs := []string{"1.0", "1.0.1.32768"}
+               sort.Sort(&serviceKeySorter{
+                       sortArr: kvs,
+                       kvs:     make(map[string]*discovery.KeyValue),
+                       cmp:     Larger,
+               })
+               assert.Equal(t, "1.0", kvs[0])
+               assert.Equal(t, "1.0.1.32768", kvs[1])
+               kvs = []string{"1.0", "1.0.1.32767"}
+               sort.Sort(&serviceKeySorter{
+                       sortArr: kvs,
+                       kvs:     make(map[string]*discovery.KeyValue),
+                       cmp:     Larger,
+               })
+               assert.Equal(t, "1.0.1.32767", kvs[0])
+               assert.Equal(t, "1.0", kvs[1])
+       })
+}
+
+func TestVersionRule(t *testing.T) {
+       const count = 10
+       var kvs = [count]*discovery.KeyValue{}
+       for i := 1; i <= count; i++ {
+               kvs[i-1] = &discovery.KeyValue{
+                       Key:   []byte(fmt.Sprintf("/service/ver/1.%d", i)),
+                       Value: fmt.Sprintf("%d", i),
+               }
+       }
+
+       log.Info("normal")
+
+       t.Run("latest", func(t *testing.T) {
+               results := VersionRule(Latest).Match(kvs[:])
+               assert.Equal(t, 1, len(results))
+               assert.Equal(t, fmt.Sprintf("%d", count), results[0])
+       })
+
+       t.Run("range1.1 ver in [1.4, 1.8)", func(t *testing.T) {
+               results := VersionRule(Range).Match(kvs[:], "1.4", "1.8")
+               assert.Equal(t, 4, len(results))
+               assert.Equal(t, "7", results[0])
+               assert.Equal(t, "4", results[3])
+       })
+
+       t.Run("range1.2 ver in (1.8, 1.4]", func(t *testing.T) {
+               results := VersionRule(Range).Match(kvs[:], "1.8", "1.4")
+               assert.Equal(t, 4, len(results))
+               assert.Equal(t, "7", results[0])
+               assert.Equal(t, "4", results[3])
+       })
+
+       t.Run("range2 ver in [1, 2]", func(t *testing.T) {
+               results := VersionRule(Range).Match(kvs[:], "1", "2")
+               assert.Equal(t, 10, len(results))
+               assert.Equal(t, "10", results[0])
+               assert.Equal(t, "1", results[9])
+       })
+
+       t.Run("range3 ver in [1.4.1, 1.9.1]", func(t *testing.T) {
+               results := VersionRule(Range).Match(kvs[:], "1.4.1", "1.9.1")
+               assert.Equal(t, 5, len(results))
+               assert.Equal(t, "9", results[0])
+               assert.Equal(t, "5", results[4])
+       })
+
+       t.Run("range4 ver in [2, 4]", func(t *testing.T) {
+               results := VersionRule(Range).Match(kvs[:], "2", "4")
+               assert.Equal(t, len(results), 0)
+       })
+
+       t.Run("atLess1 ver >= 1.6", func(t *testing.T) {
+               results := VersionRule(AtLess).Match(kvs[:], "1.6")
+               assert.Equal(t, len(results), 5)
+               assert.Equal(t, "10", results[0])
+               assert.Equal(t, "6", results[4])
+       })
+
+       t.Run("atLess2 ver >= 1", func(t *testing.T) {
+               results := VersionRule(AtLess).Match(kvs[:], "1")
+               assert.Equal(t, len(results), 10)
+               assert.Equal(t, "10", results[0])
+               assert.Equal(t, "1", results[9])
+       })
+
+       t.Run("atLess3 ver >= 1.5.1", func(t *testing.T) {
+               results := VersionRule(AtLess).Match(kvs[:], "1.5.1")
+               assert.Equal(t, 5, len(results))
+               assert.Equal(t, "10", results[0])
+               assert.Equal(t, "6", results[4])
+       })
+
+       t.Run("atLess4 ver >= 2", func(t *testing.T) {
+               results := VersionRule(AtLess).Match(kvs[:], "2")
+               assert.Equal(t, 0, len(results))
+       })
+
+       log.Info("exception")
+
+       t.Run("nil", func(t *testing.T) {
+               results := VersionRule(Latest).Match(nil)
+               assert.Equal(t, 0, len(results))
+               results = VersionRule(AtLess).Match(nil)
+               assert.Equal(t, 0, len(results))
+               results = VersionRule(Range).Match(nil)
+               assert.Equal(t, 0, len(results))
+               rule := ParseVersionRule("")
+               assert.Equal(t, true, reflect.ValueOf(rule).IsNil())
+               rule = ParseVersionRule("abc")
+               assert.Equal(t, true, reflect.ValueOf(rule).IsNil())
+               assert.Equal(t, true, VersionMatchRule("1.0", "1.0"))
+               assert.Equal(t, false, VersionMatchRule("1.0", "1.2"))
+       })
+
+       log.Info("parse")
+
+       t.Run("latest", func(t *testing.T) {
+               match := ParseVersionRule("latest")
+               results := match(kvs[:])
+               assert.Equal(t, 1, len(results))
+               assert.Equal(t, fmt.Sprintf("%d", count), results[0])
+       })
+
+       t.Run("range ver in[1.4, 1.8]", func(t *testing.T) {
+               match := ParseVersionRule("1.4-1.8")
+               results := match(kvs[:])
+               assert.Equal(t, 4, len(results))
+               assert.Equal(t, "7", results[0])
+               assert.Equal(t, "4", results[3])
+       })
+
+       t.Run("atLess ver >= 1.6", func(t *testing.T) {
+               match := ParseVersionRule("1.6+")
+               results := match(kvs[:])
+               assert.Equal(t, 5, len(results))
+               assert.Equal(t, "10", results[0])
+               assert.Equal(t, "6", results[4])
+       })
+
+       log.Info("version match rule")
+
+       t.Run("latest", func(t *testing.T) {
+               assert.Equal(t, true, VersionMatchRule("1.0", "latest"))
+       })
+
+       t.Run("range ver in [1.4, 1.8]", func(t *testing.T) {
+               assert.Equal(t, true, VersionMatchRule("1.4", "1.4-1.8"))
+               assert.Equal(t, true, VersionMatchRule("1.6", "1.4-1.8"))
+               assert.Equal(t, false, VersionMatchRule("1.8", "1.4-1.8"))
+               assert.Equal(t, false, VersionMatchRule("1.0", "1.4-1.8"))
+               assert.Equal(t, false, VersionMatchRule("1.9", "1.4-1.8"))
+       })
+
+       t.Run("atLess ver >= 1.6", func(t *testing.T) {
+               assert.Equal(t, true, VersionMatchRule("1.6", "1.6+"))
+               assert.Equal(t, true, VersionMatchRule("1.9", "1.6+"))
+               assert.Equal(t, false, VersionMatchRule("1.0", "1.6+"))
+       })
+}
+
+func TestNewVersionRegexp(t *testing.T) {
+       log.Info("normal")
+
+       t.Run("latest", func(t *testing.T) {
+               vr := NewVersionRegexp(false)
+               assert.Equal(t, false, vr.MatchString("latest"))
+               vr = NewVersionRegexp(true)
+               assert.Equal(t, true, vr.MatchString("latest"))
+       })
+
+       t.Run("range", func(t *testing.T) {
+               vr := NewVersionRegexp(false)
+               assert.Equal(t, false, vr.MatchString("1.1-2.2"))
+               vr = NewVersionRegexp(true)
+               assert.Equal(t, false, vr.MatchString("-"))
+               assert.Equal(t, false, vr.MatchString("1.1-"))
+               assert.Equal(t, false, vr.MatchString("-1.1"))
+               assert.Equal(t, false, vr.MatchString("1.a-2.b"))
+               assert.Equal(t, false, vr.MatchString("1.-.2"))
+               assert.Equal(t, false, vr.MatchString("60000-1"))
+               assert.Equal(t, true, vr.MatchString("1.1-2.2"))
+               assert.Equal(t, true, vr.MatchString("1.1.1.1-2.2.2.2"))
+               assert.Equal(t, false, vr.MatchString("1.1.1.1.1-2.2.2.2"))
+               assert.Equal(t, false, vr.MatchString("1.1.1.1-2.2.2.2.2"))
+       })
+
+       t.Run("atLess", func(t *testing.T) {
+               vr := NewVersionRegexp(false)
+               assert.Equal(t, false, vr.MatchString("1.0+"))
+               vr = NewVersionRegexp(true)
+               assert.Equal(t, false, vr.MatchString("+"))
+               assert.Equal(t, false, vr.MatchString("+1.0"))
+               assert.Equal(t, false, vr.MatchString("1.a+"))
+               assert.Equal(t, false, vr.MatchString(".1+"))
+               assert.Equal(t, false, vr.MatchString("1.+"))
+               assert.Equal(t, false, vr.MatchString(".+"))
+               assert.Equal(t, false, vr.MatchString("60000+"))
+               assert.Equal(t, true, vr.MatchString("1.0+"))
+               assert.Equal(t, true, vr.MatchString("1.0.0.0+"))
+               assert.Equal(t, false, vr.MatchString("1.0.0.0.0+"))
+       })
+
+       t.Run("explicit", func(t *testing.T) {
+               vr := NewVersionRegexp(false)
+               assert.Equal(t, false, vr.MatchString(""))
+               assert.Equal(t, false, vr.MatchString("a"))
+               assert.Equal(t, false, vr.MatchString("60000"))
+               assert.Equal(t, false, vr.MatchString("."))
+               assert.Equal(t, false, vr.MatchString("1."))
+               assert.Equal(t, false, vr.MatchString(".1"))
+               assert.Equal(t, true, vr.MatchString("1.4"))
+               vr = NewVersionRegexp(true)
+               assert.Equal(t, false, vr.MatchString(""))
+               assert.Equal(t, false, vr.MatchString("a"))
+               assert.Equal(t, false, vr.MatchString("60000"))
+               assert.Equal(t, false, vr.MatchString("."))
+               assert.Equal(t, false, vr.MatchString("1."))
+               assert.Equal(t, false, vr.MatchString(".1"))
+               assert.Equal(t, true, vr.MatchString("1.4"))
+               assert.Equal(t, true, vr.MatchString("1.4.0.0"))
+               assert.Equal(t, false, vr.MatchString("1.4.0.0.0"))
+       })
+
+       log.Info("exception")
+
+       t.Run("MatchString & String", func(t *testing.T) {
+               vr := VersionRegexp{}
+               assert.Equal(t, true, vr.MatchString(""))
+               assert.NotEqual(t, "", vr.String())
+               vr = VersionRegexp{Fuzzy: true}
+               assert.Equal(t, true, vr.MatchString(""))
+               assert.NotEqual(t, "", vr.String())
+       })
+}
diff --git a/pkg/chain/chain_test.go b/pkg/chain/chain_test.go
index c21ad3a..ad6dd4c 100644
--- a/pkg/chain/chain_test.go
+++ b/pkg/chain/chain_test.go
@@ -87,7 +87,7 @@ type mockHandler struct {
 }
 
 func (h *mockHandler) Handle(i *Invocation) {
-       x := i.Context().Value("x").(int)
+       x := i.Context().Value(util.CtxKey("x")).(int)
        switch x {
        case 1:
                i.Success(x)
@@ -100,7 +100,7 @@ func (h *mockHandler) Handle(i *Invocation) {
        case 4:
                i.Next(WithAsyncFunc(func(r Result) {
                        i.WithContext("x", x*x)
-                       ch, _ := i.Context().Value("ch").(chan struct{})
+                       ch, _ := i.Context().Value(util.CtxKey("ch")).(chan 
struct{})
                        ch <- struct{}{}
                }))
        case 5:
@@ -132,7 +132,7 @@ func TestChain_Next(t *testing.T) {
        i := NewInvocation(context.Background(), ch)
        i.WithContext("x", x)
        i.Invoke(func(r Result) {
-               if !r.OK || i.Context().Value("x").(int) != -len(hs) {
+               if !r.OK || i.Context().Value(util.CtxKey("x")).(int) != 
-len(hs) {
                        t.Fatalf("TestChain_Next")
                }
        })
@@ -162,11 +162,11 @@ func TestChain_Next(t *testing.T) {
        i = NewInvocation(context.Background(), ch)
        i.WithContext("x", x)
        i.Invoke(func(r Result) {
-               if !r.OK || i.Context().Value("x").(int) != x {
+               if !r.OK || i.Context().Value(util.CtxKey("x")).(int) != x {
                        t.Fatalf("TestChain_Next")
                }
        })
-       if i.Context().Value("x").(int) != x*x {
+       if i.Context().Value(util.CtxKey("x")).(int) != x*x {
                t.Fatalf("TestChain_Next")
        }
 
@@ -176,12 +176,12 @@ func TestChain_Next(t *testing.T) {
        i.WithContext("x", x)
        i.WithContext("ch", make(chan struct{}))
        i.Invoke(func(r Result) {
-               if !r.OK || i.Context().Value("x").(int) != x {
+               if !r.OK || i.Context().Value(util.CtxKey("x")).(int) != x {
                        t.Fatalf("TestChain_Next")
                }
        })
-       <-i.Context().Value("ch").(chan struct{})
-       if i.Context().Value("x").(int) != x*x {
+       <-i.Context().Value(util.CtxKey("ch")).(chan struct{})
+       if i.Context().Value(util.CtxKey("x")).(int) != x*x {
                t.Fatalf("TestChain_Next")
        }
 
diff --git a/pkg/chain/invocation.go b/pkg/chain/invocation.go
index 6d87500..9701ebd 100644
--- a/pkg/chain/invocation.go
+++ b/pkg/chain/invocation.go
@@ -53,7 +53,7 @@ func (i *Invocation) Context() context.Context {
        return i.context
 }
 
-func (i *Invocation) WithContext(key string, val interface{}) *Invocation {
+func (i *Invocation) WithContext(key util.CtxKey, val interface{}) *Invocation 
{
        i.context.SetKV(key, val)
        return i
 }
diff --git a/pkg/rest/common.go b/pkg/rest/common.go
index 0e364e8..919ebff 100644
--- a/pkg/rest/common.go
+++ b/pkg/rest/common.go
@@ -19,6 +19,8 @@ package rest
 
 import (
        "net/http"
+
+       "github.com/apache/servicecomb-service-center/pkg/util"
 )
 
 const (
@@ -27,10 +29,10 @@ const (
        HTTPMethodPost   = http.MethodPost
        HTTPMethodDelete = http.MethodDelete
 
-       CtxResponse     = "_server_response"
-       CtxRequest      = "_server_request"
-       CtxMatchPattern = "_server_match_pattern"
-       CtxMatchFunc    = "_server_match_func"
+       CtxResponse     util.CtxKey = "_server_response"
+       CtxRequest      util.CtxKey = "_server_request"
+       CtxMatchPattern util.CtxKey = "_server_match_pattern"
+       CtxMatchFunc    util.CtxKey = "_server_match_func"
 
        ServerChainName = "_server_chain"
 
diff --git a/pkg/util/common.go b/pkg/util/common.go
index a876bc9..93ed11a 100644
--- a/pkg/util/common.go
+++ b/pkg/util/common.go
@@ -17,11 +17,13 @@
 
 package util
 
+type CtxKey string
+
 const (
-       HeaderRev           = "X-Resource-Revision"
-       CtxGlobal           = "global"
-       CtxNocache          = "noCache"
-       CtxCacheOnly        = "cacheOnly"
-       CtxRequestRevision  = "requestRev"
-       CtxResponseRevision = "responseRev"
+       HeaderRev                  = "X-Resource-Revision"
+       CtxGlobal           CtxKey = "global"
+       CtxNocache          CtxKey = "noCache"
+       CtxCacheOnly        CtxKey = "cacheOnly"
+       CtxRequestRevision  CtxKey = "requestRev"
+       CtxResponseRevision CtxKey = "responseRev"
 )
diff --git a/pkg/util/context.go b/pkg/util/context.go
index d1d4ceb..7fbec0c 100644
--- a/pkg/util/context.go
+++ b/pkg/util/context.go
@@ -48,7 +48,7 @@ func (c *StringContext) Err() error {
 }
 
 func (c *StringContext) Value(key interface{}) interface{} {
-       k, ok := key.(string)
+       k, ok := key.(CtxKey)
        if !ok {
                return c.parentCtx.Value(key)
        }
@@ -59,7 +59,7 @@ func (c *StringContext) Value(key interface{}) interface{} {
        return v
 }
 
-func (c *StringContext) SetKV(key string, val interface{}) {
+func (c *StringContext) SetKV(key CtxKey, val interface{}) {
        c.kv.Put(key, val)
 }
 
@@ -74,7 +74,7 @@ func NewStringContext(ctx context.Context) *StringContext {
        return strCtx
 }
 
-func SetContext(ctx context.Context, key string, val interface{}) 
context.Context {
+func SetContext(ctx context.Context, key CtxKey, val interface{}) 
context.Context {
        strCtx := NewStringContext(ctx)
        strCtx.SetKV(key, val)
        return strCtx
@@ -101,14 +101,14 @@ func CloneContext(ctx context.Context) context.Context {
        return strCtx
 }
 
-func FromContext(ctx context.Context, key string) interface{} {
+func FromContext(ctx context.Context, key CtxKey) interface{} {
        if v := ctx.Value(key); v != nil {
                return v
        }
        return FromMetadata(ctx, key)
 }
 
-func SetRequestContext(r *http.Request, key string, val interface{}) 
*http.Request {
+func SetRequestContext(r *http.Request, key CtxKey, val interface{}) 
*http.Request {
        ctx := r.Context()
        ctx = SetContext(ctx, key, val)
        if ctx != r.Context() {
diff --git a/pkg/util/context_grpc.go b/pkg/util/context_grpc.go
index bbb10f8..53f68b0 100644
--- a/pkg/util/context_grpc.go
+++ b/pkg/util/context_grpc.go
@@ -20,12 +20,12 @@ import (
        "google.golang.org/grpc/metadata"
 )
 
-func FromMetadata(ctx context.Context, key string) string {
+func FromMetadata(ctx context.Context, key CtxKey) string {
        md, ok := metadata.FromIncomingContext(ctx)
        if !ok {
                return ""
        }
-       if values, ok := md[key]; ok && len(values) > 0 {
+       if values, ok := md[string(key)]; ok && len(values) > 0 {
                return values[0]
        }
        return ""
diff --git a/server/handler/cache/cache.go b/server/handler/cache/cache.go
index 8d3072f..6d407ca 100644
--- a/server/handler/cache/cache.go
+++ b/server/handler/cache/cache.go
@@ -24,6 +24,12 @@ import (
        "net/http"
 )
 
+const (
+       queryGlobal    = "global"
+       queryNoCache   = "noCache"
+       queryCacheOnly = "cacheOnly"
+)
+
 type Handler struct {
 }
 
@@ -33,18 +39,18 @@ func (l *Handler) Handle(i *chain.Invocation) {
        r := i.Context().Value(rest.CtxRequest).(*http.Request)
        query := r.URL.Query()
 
-       global := util.StringTRUE(query.Get(string(util.CtxGlobal)))
+       global := util.StringTRUE(query.Get(queryGlobal))
        if global && r.Method == http.MethodGet {
                i.WithContext(util.CtxGlobal, "1")
        }
 
-       noCache := util.StringTRUE(query.Get(util.CtxNocache))
+       noCache := util.StringTRUE(query.Get(queryNoCache))
        if noCache {
                i.WithContext(util.CtxNocache, "1")
                return
        }
 
-       cacheOnly := util.StringTRUE(query.Get(string(util.CtxCacheOnly)))
+       cacheOnly := util.StringTRUE(query.Get(queryCacheOnly))
        if cacheOnly {
                i.WithContext(util.CtxCacheOnly, "1")
                return
diff --git a/server/plugin/tracing/pzipkin/buildin.go 
b/server/plugin/tracing/pzipkin/buildin.go
index 1cfbc00..c2530da 100644
--- a/server/plugin/tracing/pzipkin/buildin.go
+++ b/server/plugin/tracing/pzipkin/buildin.go
@@ -150,7 +150,7 @@ func (zp *Zipkin) ClientBegin(operationName string, itf 
tracing.Request) tracing
                }
                // inject context
                err := carrier.ForeachKey(func(key, val string) error {
-                       ctx = util.SetContext(ctx, key, val)
+                       ctx = util.SetContext(ctx, util.CtxKey(key), val)
                        return nil
                })
                if err != nil {
diff --git a/server/plugin/tracing/tracing.go b/server/plugin/tracing/tracing.go
index 309eeb4..9171005 100644
--- a/server/plugin/tracing/tracing.go
+++ b/server/plugin/tracing/tracing.go
@@ -19,10 +19,11 @@ package tracing
 
 import (
        "context"
+       "github.com/apache/servicecomb-service-center/pkg/util"
        "github.com/apache/servicecomb-service-center/server/plugin/registry"
 )
 
-const CtxTraceSpan = "x-trace-span"
+const CtxTraceSpan util.CtxKey = "x-trace-span"
 
 type Request interface{}
 type Span interface{}
diff --git a/server/plugin/uuid/uuid.go b/server/plugin/uuid/uuid.go
index c8aaa7c..1f0a6c5 100644
--- a/server/plugin/uuid/uuid.go
+++ b/server/plugin/uuid/uuid.go
@@ -19,9 +19,11 @@ package uuid
 
 import (
        "context"
+
+       "github.com/apache/servicecomb-service-center/pkg/util"
 )
 
-const ContextKey = "_uuid_key"
+const ContextKey util.CtxKey = "_uuid_key"
 
 type UUID interface {
        GetServiceID(ctx context.Context) string
diff --git a/server/rest/handler.go b/server/rest/handler.go
index dc22b10..26280d1 100644
--- a/server/rest/handler.go
+++ b/server/rest/handler.go
@@ -26,7 +26,7 @@ import (
        "github.com/apache/servicecomb-service-center/server/interceptor"
 )
 
-const CtxStartTimestamp = "x-start-timestamp"
+const CtxStartTimestamp util.CtxKey = "x-start-timestamp"
 
 func init() {
        // api

Reply via email to