You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@servicecomb.apache.org by as...@apache.org on 2018/08/01 11:32:03 UTC

[incubator-servicecomb-service-center] branch master updated: SCB-735 Add admin dump api (#396)

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

asifdxtreme pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-servicecomb-service-center.git


The following commit(s) were added to refs/heads/master by this push:
     new 7bf5c58  SCB-735 Add admin dump api (#396)
7bf5c58 is described below

commit 7bf5c582204d6237f3c3fe61d5d6f59986796a23
Author: little-cui <su...@qq.com>
AuthorDate: Wed Aug 1 19:31:59 2018 +0800

    SCB-735 Add admin dump api (#396)
    
    * SCB-735 Add admin dump api
    
    * SCB-735 Add admin dump api
    
    * SCB-735 Add admin dump api
    
    * SCB-735 Add admin dump api
    
    * SCB-735 Add admin dump api
    
    * SCB-735 Add admin dump api
    
    * Optimize code
    
    * Optimize code
    
    * Add find cross app UT
    
    * Print accurate domain/project logs
    
    * Add core UT
    
    * Fix publisher dispatch job even if websocket handler is busy
    
    * Add some UTs
    
    * Optimize registry config
    
    * Fix UT failure
    
    * Optimize core package
    
    * Bug fix: can not connect etcd with TLS
    
    * Optimize server mux
    
    * Add more metrics
    
    * Update the swagger file
---
 .gitignore                                         |    2 +
 etc/conf/app.conf                                  |   14 +-
 examples/service_center/ssl/cert_pwd               |    1 +
 examples/service_center/ssl/server.cer             |   13 +
 examples/service_center/ssl/server_key.pem         |   18 +
 examples/service_center/ssl/trust.cer              |   13 +
 frontend/main.go                                   |    5 +-
 .../mutex_test.go => integration/admin_test.go     |   43 +-
 integration/apis.go                                |    3 +
 integration/health-metrics-grafana.json            | 1772 +++++++++++++++++---
 integration/instances_test.go                      |    6 +-
 integration/microservices_test.go                  |   53 +-
 integration/rules_test.go                          |   28 +-
 integration/tags_test.go                           |   22 +-
 main.go                                            |   10 +-
 pkg/chain/callback_test.go                         |   56 +
 pkg/chain/chain_test.go                            |  150 +-
 pkg/chain/handler.go                               |    4 +-
 pkg/chain/invocation.go                            |   11 +-
 pkg/etcdsync/etcdsync_suite_test.go                |   15 +-
 pkg/etcdsync/mutex.go                              |  126 +-
 pkg/etcdsync/mutex_test.go                         |   39 +-
 pkg/rest/client.go                                 |    4 +-
 pkg/rest/listener.go                               |   14 +-
 pkg/rest/roa.go                                    |   14 +-
 pkg/rest/server.go                                 |   51 +-
 pkg/rpc/grpc.go                                    |    2 +-
 pkg/{async => task}/executor.go                    |    2 +-
 pkg/{async/async.go => task/service.go}            |    6 +-
 pkg/{async/service.go => task/service_async.go}    |   31 +-
 pkg/{async/async_test.go => task/service_test.go}  |    3 +-
 pkg/{async => task}/task.go                        |   11 +-
 pkg/tlsutil/tlsutil.go                             |    4 +-
 pkg/tlsutil/tlsutil_test.go                        |    4 +-
 pkg/util/context.go                                |   11 +-
 pkg/util/context_test.go                           |   77 +
 pkg/util/goroutines.go                             |  119 +-
 pkg/util/goroutines_test.go                        |   12 +-
 pkg/util/log.go                                    |   57 +-
 pkg/util/log_test.go                               |   23 +-
 pkg/util/logrotate.go                              |    3 +
 pkg/util/logrotate_test.go                         |   17 +
 pkg/util/net.go                                    |   18 +-
 pkg/util/net_test.go                               |   47 +-
 pkg/util/reflect.go                                |   88 +-
 pkg/util/reflect_test.go                           |   59 +-
 pkg/util/util.go                                   |   82 +-
 pkg/util/util_test.go                              |   42 +
 pkg/util/{logrotate_test.go => uuid_test.go}       |    9 +-
 pkg/validate/url.go                                |   53 +-
 pkg/validate/validator.go                          |    2 +-
 scripts/prepare_env_ut.sh                          |    3 +-
 scripts/ut_test_in_docker.sh                       |   11 +-
 server/{broker/broker.go => admin/admin.go}        |    4 +-
 .../admin_suite_test.go}                           |   13 +-
 main.go => server/admin/controller_v4.go           |   33 +-
 server/admin/model/dump.go                         |  185 ++
 server/admin/service.go                            |   71 +
 .../broker_suite_test.go => admin/service_test.go} |   45 +-
 server/api.go                                      |   10 +-
 server/bootstrap/bootstrap.go                      |    5 +-
 server/broker/broker.go                            |    2 +-
 server/broker/broker_suite_test.go                 |    7 +-
 server/broker/{ => brokerpb}/broker.pb.go          |    2 +-
 server/broker/{ => brokerpb}/broker.proto          |    0
 server/broker/controller.go                        |   19 +-
 server/broker/{broker.go => controller_test.go}    |   30 +-
 server/broker/service.go                           |  201 +--
 server/broker/service_test.go                      |   74 +-
 server/broker/store.go                             |   28 +-
 server/broker/util.go                              |  187 +--
 server/core/backend/cache.go                       |    8 +-
 server/core/backend/cache_kv.go                    |   22 +-
 server/core/backend/cache_null.go                  |   15 +-
 server/core/backend/cache_test.go                  |   57 +-
 server/core/backend/cacher_kv.go                   |   69 +-
 server/core/backend/cacher_kv_test.go              |  340 ++++
 server/core/backend/common.go                      |   40 +-
 server/core/backend/config.go                      |   43 +-
 server/core/backend/defer_instance.go              |   18 +-
 server/core/backend/defer_test.go                  |   14 +-
 pkg/async/task.go => server/core/backend/entity.go |   12 +-
 server/core/backend/entity_kv.go                   |   76 +
 main.go => server/core/backend/entity_test.go      |   35 +-
 server/core/backend/event_proxy.go                 |   27 +-
 .../core/backend/{extend_test.go => event_test.go} |   37 +-
 server/core/backend/extend.go                      |   31 +-
 server/core/backend/indexer.go                     |   68 -
 .../core/backend/{indexer.go => indexer_base.go}   |   61 +-
 server/core/backend/indexer_kv.go                  |   86 +-
 server/core/backend/indexer_test.go                |  178 ++
 server/core/backend/lease.go                       |    5 +-
 .../backend/lease_test.go}                         |   45 +-
 server/core/backend/listwatch.go                   |  123 +-
 .../backend/{listwatch.go => listwatch_inner.go}   |   73 +-
 server/core/backend/listwatch_test.go              |  119 ++
 server/core/backend/metrics.go                     |   21 +-
 .../backend/{extend_test.go => metrics_test.go}    |   33 +-
 server/core/backend/{kv.go => model.go}            |   19 +-
 server/core/backend/parser.go                      |   38 +-
 server/core/backend/parser_test.go                 |  109 ++
 .../task.go => server/core/backend/service.go      |   12 +-
 server/core/backend/store.go                       |  192 +--
 server/core/backend/store_test.go                  |  141 ++
 .../core/backend/watcher.go                        |   12 +-
 server/core/backend/watcher_inner.go               |   82 +
 server/core/backend/watcher_test.go                |   86 +
 server/core/config.go                              |   18 +-
 server/core/core.go                                |    6 +-
 server/core/proto/services.go                      |    6 +-
 server/core/swagger/v4.yaml                        |  163 +-
 server/error/error.go                              |    4 +
 server/govern/controller_v4.go                     |   34 -
 server/govern/govern.go                            |    4 +-
 server/govern/govern_suite_test.go                 |   11 +-
 main.go => server/govern/graph.go                  |   44 +-
 server/govern/service.go                           |    7 +-
 server/govern/service_test.go                      |   77 +-
 server/infra/quota/quota.go                        |    4 +-
 server/infra/registry/registry.go                  |   55 +-
 pkg/async/task.go => server/init/init.go           |   10 +-
 .../interceptor/interceptors_test.go               |   70 +-
 pkg/async/task.go => server/main.go                |   10 +-
 pkg/util/metric.go => server/metric/calculator.go  |   38 +-
 server/metric/common.go                            |   43 +-
 server/metric/gatherer.go                          |    5 +-
 server/metric/metrics.go                           |    2 +-
 server/{service/event/event.go => metrics.go}      |   26 +-
 .../infra/registry/embededetcd/embededetcd.go      |   23 +-
 server/plugin/infra/registry/etcd/etcd.go          |  333 ++--
 server/plugin/infra/registry/etcd/etcd_test.go     |  707 +++++++-
 .../infra/registry/etcd/logger_test.go}            |   51 +-
 .../infra/registry/etcd/metrics.go}                |   26 +-
 server/plugin/infra/tls/buildin/tls_test.go        |    5 +-
 server/plugin/infra/tracing/buildin/buildin.go     |    2 +-
 .../plugin/infra/tracing/buildin/buildin_test.go   |   75 +
 server/plugin/infra/tracing/buildin/common.go      |    3 +-
 .../plugin/infra/tracing/buildin/file_collector.go |   38 +-
 .../infra/tracing/buildin/file_collector_test.go   |   27 +-
 server/plugin/plugin.go                            |   56 +-
 .../file_collector_test.go => plugin_test.go}      |   64 +-
 server/rest/controller/rest_util.go                |    9 +-
 server/rest/controller/v3/v3.go                    |   16 +-
 server/rest/controller/v4/instance_controller.go   |    3 +-
 server/rest/controller/v4/main_controller.go       |    2 +-
 server/rest/controller/v4/v4.go                    |   16 +-
 server/rest/metrics.go                             |   11 +-
 server/rest/server.go                              |   48 -
 server/rest/server_mux.go                          |   45 +-
 server/rpc/server.go                               |   10 +-
 server/server.go                                   |   91 +-
 server/service/dependency_test.go                  |    4 +-
 .../event/{event.go => domain_event_handler.go}    |   27 +-
 server/service/event/event.go                      |    1 +
 server/service/event/instance_event_handler.go     |   14 +-
 server/service/event/rule_event_handler.go         |    4 +-
 server/service/event/service_event_handler.go      |   17 +
 server/service/event/tag_event_handler.go          |    4 +-
 server/service/instance_test.go                    |    7 +-
 server/service/metrics/metrics.go                  |   67 +
 server/service/notification/common.go              |    7 +-
 .../service/notification/notification_service.go   |    2 +-
 server/service/notification/stream.go              |    6 +-
 server/service/notification/websocket.go           |   99 +-
 server/service/notification/websocket_test.go      |   21 +-
 server/service/rule_test.go                        |   27 +-
 server/service/service_suite_test.go               |   10 +-
 server/service/tag_test.go                         |    3 +-
 server/service/util/dependency_query.go            |    4 +-
 server/service/util/domain_util.go                 |   24 +-
 server/service/util/domain_util_test.go            |    4 +-
 server/service/watch.go                            |    4 +-
 server/{rpc/server.go => version.go}               |   63 +-
 173 files changed, 6662 insertions(+), 2601 deletions(-)

diff --git a/.gitignore b/.gitignore
index 84fb882..8bb0528 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,6 +1,8 @@
 bin/
 output
 **/*.coverprofile
+**/coverage.out
+**/coverage.txt
 
 service-center.iml
 .idea/
diff --git a/etc/conf/app.conf b/etc/conf/app.conf
index 4b49680..16fe484 100644
--- a/etc/conf/app.conf
+++ b/etc/conf/app.conf
@@ -60,17 +60,23 @@ registry_plugin = etcd
 # manager_cluster = "127.0.0.1:2379"
 manager_cluster = "127.0.0.1:2379"
 
-#heartbeat that sync synchronizes client's endpoints with the known endpoints from the etcd membership,unit is second.
-#<=0, use default 30s
+# heartbeat that sync synchronizes client's endpoints with the known endpoints from
+# the etcd membership, unit is second and value must greater then 1s, it is set
+# default 30s if value less then 0
 auto_sync_interval = 30s
 
+# bootstrap time out of registry
+connect_timeout = 10s
+
+# request registry time out
 registry_timeout = 30s
 
 # indicate how many revision you want to keep in etcd
 compact_index_delta = 100
 compact_interval = 12h
 
-# registry cache
+# registry cache, if this option value set 0, service center can run
+# in lower memory but no longer push the events to client.
 enable_cache = 1
 
 # pluggable cipher
@@ -112,7 +118,7 @@ ssl_mode = 0
 ssl_verify_client = 1
 # minimal tls protocol, [TLSv1.0, TLSv1.1, TLSv1.2]
 ssl_protocols = TLSv1.2
-ssl_ciphers = TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,TLS_RSA_WITH_AES_256_GCM_SHA384,TLS_RSA_WITH_AES_128_GCM_SHA256
+ssl_ciphers = TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_RSA_WITH_AES_256_GCM_SHA384,TLS_RSA_WITH_AES_128_GCM_SHA256
 
 ###################################################################
 # log options
diff --git a/examples/service_center/ssl/cert_pwd b/examples/service_center/ssl/cert_pwd
new file mode 100644
index 0000000..0a783b7
--- /dev/null
+++ b/examples/service_center/ssl/cert_pwd
@@ -0,0 +1 @@
+Changeme_123
\ No newline at end of file
diff --git a/examples/service_center/ssl/server.cer b/examples/service_center/ssl/server.cer
new file mode 100644
index 0000000..c29eb6a
--- /dev/null
+++ b/examples/service_center/ssl/server.cer
@@ -0,0 +1,13 @@
+-----BEGIN CERTIFICATE-----
+MIICATCCAWoCCQDmvlmfua/ThTANBgkqhkiG9w0BAQsFADBFMQswCQYDVQQGEwJB
+VTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0
+cyBQdHkgTHRkMB4XDTE3MTIwNTA5MzA0NloXDTE4MTIwNTA5MzA0NlowRTELMAkG
+A1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0
+IFdpZGdpdHMgUHR5IEx0ZDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAtu5H
+L8mlCL6n+BrQ71eJgJJJ427/DgovzHBqLTYuk/It987wNJFmTMgdWRXHujwe4bFt
+G78d7OJteXcR7a68sIxWrytWeAwG88M62duS+DCUke1YuQ6hrfIADvE2ZgYEuVxz
+5UxOTYYIjtSxCGKDuxmlvkJgO6lE0zIhtFxz1WcCAwEAATANBgkqhkiG9w0BAQsF
+AAOBgQCq89sMPmhVS5+Mh+FvnNC9qOnsnqWhyAEc5XEmqtCTAe1XpO3CvPH7DdHz
+Ss0FVqpBRqmxUR0sQo6t/S0kW7uwDgjm7nIy67wtTLOLclYW2Yw+d3ApwBVMhVBp
+yhDpV90YZF7QM9uhdsEgLpbTqs4hvPB1pUWH6oXdtjnEkp6lFQ==
+-----END CERTIFICATE-----
diff --git a/examples/service_center/ssl/server_key.pem b/examples/service_center/ssl/server_key.pem
new file mode 100644
index 0000000..c0b907e
--- /dev/null
+++ b/examples/service_center/ssl/server_key.pem
@@ -0,0 +1,18 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: AES-128-CBC,22C64A026937643A490027AC7931D19A
+
+FdV2dDDn5l767Ulha9IMxiwvyMu6BziFCjXbfsHB1aHdBfuFWV8uJ5lEYiWPWdj3
+QIeK79QH8i6N0n2f1VfXtW7RJKS+6Gg9m1dttxGXY/6sEIkFJRPiWrNrzeHaXAoI
+38CBZli2nvtZMLo8oBj/iuQ0qlkh00Mm2RW1SgJx2I6FJZLS8xb9kKUhPL/SlBYd
+EboWXpKtubg5DhvQd8MKIaTJDf3L1Iqc7OMnLs64ONvfylYy39uv8yGsimHNItQh
+ylHjUhmqOjCwnogO1Nh2wsjQCODRPEJzpu2fJ1lb2+xqwbTg3ygVwzLoK2ScXND4
+DIo8YOa9jBCR9/Yg1IzqOIUD+UzQWhBqDejMHVXAGQb5e2AldLdFnGwx1Yz4FCIl
+nULP8lcMDeYRK0sS4N5/I4nqfvlVPyj96Nj4F3D68Q8oQXl1rTSbKXmWILxIIlHm
+tBf+NA16p9A9TegHr/qn3L3NRCxyY7gLwL+cNG2uZ9NqmxnSmWhL9UQgWYPeGr8Z
+Z9nqqshfzIMoBjZ4QP1pifKhEvb0w2MpjKtiAR3hmwn8SJDp7CPTlb7nm5e5fjZb
+nkzsTXYaJiYYiuEjiIsxJY/6ptWeYq9kqTT/3Hmy0MdkcqeDbcLwqo6jbAJxcPFf
+C0SCJ+woIZJeHpZZjmH/qsZUKq2UEDsLqGruNMDzxarmme67lwPIDG2pZ90EIcNx
+BR0ZU4owv9N+dO2sFsMNHae9X8mHWynUJ2V3ISxshvS3WJmq+YkeYTjYljeIZ28x
++UBhUrmikzx/CrIFd9irnkVhPIqJ+uUZEiMNEnT7VxCpHZHDU+ujweChUzaLkh0x
+-----END RSA PRIVATE KEY-----
diff --git a/examples/service_center/ssl/trust.cer b/examples/service_center/ssl/trust.cer
new file mode 100644
index 0000000..8fb3139
--- /dev/null
+++ b/examples/service_center/ssl/trust.cer
@@ -0,0 +1,13 @@
+-----BEGIN CERTIFICATE-----
+MIICATCCAWoCCQCu7pAj81WabjANBgkqhkiG9w0BAQsFADBFMQswCQYDVQQGEwJB
+VTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0
+cyBQdHkgTHRkMB4XDTE3MTIwNTA5MTMzNVoXDTE4MTIwNTA5MTMzNVowRTELMAkG
+A1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0
+IFdpZGdpdHMgUHR5IEx0ZDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAyDpT
+In6x3H0HEGOXzJMByOnvzD4rL0B4wyE9K2Nng0Ev0pS0dlPQK67fZJ6e2KDcA72d
+dSps61YQ6tWnBbssCZat0qI2g3Kh4wKgEoCv/0Wm9J+c9gHO9VXyRd91FkJNFDB4
+Lsh4EF4kMVsdLfvP98LkQQAfjg621Yqa1bEu5RUCAwEAATANBgkqhkiG9w0BAQsF
+AAOBgQCbURtlhZMNUN8W2EQJVqgEbZmtNriI1VpKvfU4b8d05PwaoL3qV8tx6p5/
+2p/+diRH8XWkPMm0Ix+c7752ebWSVb8WoQL40ZBd4PIuy6RlS7/45VeMUk7LvxBG
+iPXnB72OzQmBiPhVNiINVumQWJ62NPlbYaJsG/WsZdaWYMDeww==
+-----END CERTIFICATE-----
diff --git a/frontend/main.go b/frontend/main.go
index 237b9ff..c460299 100644
--- a/frontend/main.go
+++ b/frontend/main.go
@@ -23,6 +23,7 @@ import (
 	"github.com/astaxie/beego"
 	"net"
 	"net/url"
+	"strconv"
 )
 
 type Config struct {
@@ -42,8 +43,8 @@ func main() {
 	flag.Parse()
 
 	cfg := Config{}
-	cfg.scAddr = fmt.Sprintf("http://%s/", net.JoinHostPort(url.PathEscape(scIp), fmt.Sprint(scPort)))
-	cfg.frontendAddr = net.JoinHostPort(frontendIp, fmt.Sprint(*port))
+	cfg.scAddr = fmt.Sprintf("http://%s/", net.JoinHostPort(url.PathEscape(scIp), strconv.Itoa(scPort)))
+	cfg.frontendAddr = net.JoinHostPort(frontendIp, strconv.Itoa(*port))
 
 	// run frontend web server
 	Serve(cfg)
diff --git a/pkg/etcdsync/mutex_test.go b/integration/admin_test.go
similarity index 55%
copy from pkg/etcdsync/mutex_test.go
copy to integration/admin_test.go
index 23a333b..a8cb888 100644
--- a/pkg/etcdsync/mutex_test.go
+++ b/integration/admin_test.go
@@ -14,36 +14,27 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package etcdsync_test
+package integrationtest_test
 
 import (
-	. "github.com/apache/incubator-servicecomb-service-center/pkg/etcdsync"
-
-	"fmt"
+	. "github.com/apache/incubator-servicecomb-service-center/integration"
 	. "github.com/onsi/ginkgo"
+	. "github.com/onsi/gomega"
+	"github.com/widuu/gojson"
+	"io/ioutil"
+	"net/http"
 )
 
-var _ = Describe("Mutex", func() {
-	Context("normal", func() {
-		It("TestLockTimeout", func() {
-			m1 := NewLockFactory("key1", 10)
-			m2 := NewLockFactory("key1", 2)
-			m1.NewDLock(true)
-			fmt.Println("UT===================m1 locked")
-			ch := make(chan bool)
-			go func() {
-				l, _ := m2.NewDLock(true)
-				fmt.Println("UT===================m2 locked")
-				l.Unlock()
-				ch <- true
-			}()
-			<-ch
-			fmt.Println("lock m1 timeout")
-			m3 := NewLockFactory("key1", 2)
-			l, _ := m3.NewDLock(true)
-			fmt.Println("UT===================m3 locked")
-			l.Unlock()
-
-		})
+var _ = Describe("Admin Api Test", func() {
+	It("dump", func() {
+		req, _ := http.NewRequest(GET, SCURL+DUMP, nil)
+		req.Header.Set("X-Domain-Name", "default")
+		resp, err := scclient.Do(req)
+		respbody, _ := ioutil.ReadAll(resp.Body)
+		_, d := gojson.Json(string(respbody)).Getpath("cache", "services").ToArray()
+		Expect(err).To(BeNil())
+		Expect(resp.StatusCode).To(Equal(http.StatusOK))
+		Expect(len(d)).ToNot(Equal(0))
+		defer resp.Body.Close()
 	})
 })
diff --git a/integration/apis.go b/integration/apis.go
index d4ee813..ef65212 100644
--- a/integration/apis.go
+++ b/integration/apis.go
@@ -66,6 +66,9 @@ var UPDATETAG = "/v4/default/registry/microservices/:serviceId/tags/:key"
 var GETTAGS = "/v4/default/registry/microservices/:serviceId/tags"
 var DELETETAG = "/v4/default/registry/microservices/:serviceId/tags/:key"
 
+//Admin API's
+var DUMP = "/v4/default/admin/dump"
+
 // HTTP METHODS
 var GET = "GET"
 var POST = "POST"
diff --git a/integration/health-metrics-grafana.json b/integration/health-metrics-grafana.json
index 280aec3..fdc80d2 100644
--- a/integration/health-metrics-grafana.json
+++ b/integration/health-metrics-grafana.json
@@ -33,6 +33,12 @@
     },
     {
       "type": "panel",
+      "id": "grafana-piechart-panel",
+      "name": "Pie Chart",
+      "version": "1.3.3"
+    },
+    {
+      "type": "panel",
       "id": "graph",
       "name": "Graph",
       "version": "5.0.0"
@@ -84,127 +90,30 @@
   ],
   "panels": [
     {
-      "aliasColors": {},
-      "bars": false,
-      "dashLength": 10,
-      "dashes": false,
-      "datasource": "${DS_LOCAL}",
-      "fill": 1,
-      "gridPos": {
-        "h": 6,
-        "w": 8,
-        "x": 0,
-        "y": 0
-      },
-      "height": "",
-      "id": 1,
-      "legend": {
-        "alignAsTable": true,
-        "avg": true,
-        "current": true,
-        "max": false,
-        "min": false,
-        "show": true,
-        "sort": null,
-        "sortDesc": null,
-        "total": false,
-        "values": true
-      },
-      "lines": true,
-      "linewidth": 1,
-      "links": [],
-      "minSpan": 4,
-      "nullPointMode": "null",
-      "percentage": false,
-      "pointradius": 5,
-      "points": false,
-      "renderer": "flot",
-      "seriesOverrides": [],
-      "spaceLength": 10,
-      "stack": false,
-      "steppedLine": false,
-      "targets": [
-        {
-          "expr": "max(max_over_time(service_center_http_request_durations_microseconds{job=\"service-center\",method=\"GET\"}[1m]))",
-          "format": "time_series",
-          "instant": false,
-          "intervalFactor": 2,
-          "legendFormat": "read",
-          "refId": "A"
-        },
-        {
-          "expr": "max(max_over_time(service_center_http_request_durations_microseconds{job=\"service-center\",method!=\"GET\"}[1m]))",
-          "format": "time_series",
-          "intervalFactor": 2,
-          "legendFormat": "write",
-          "refId": "B"
-        }
-      ],
-      "thresholds": [],
-      "timeFrom": null,
-      "timeShift": null,
-      "title": "I/O Latency",
-      "tooltip": {
-        "shared": true,
-        "sort": 0,
-        "value_type": "individual"
-      },
-      "type": "graph",
-      "xaxis": {
-        "buckets": null,
-        "mode": "time",
-        "name": null,
-        "show": true,
-        "values": []
-      },
-      "yaxes": [
-        {
-          "format": "µs",
-          "label": null,
-          "logBase": 1,
-          "max": null,
-          "min": null,
-          "show": true
-        },
-        {
-          "format": "short",
-          "label": null,
-          "logBase": 1,
-          "max": null,
-          "min": null,
-          "show": true
-        }
-      ],
-      "yaxis": {
-        "align": false,
-        "alignLevel": null
-      }
-    },
-    {
       "cacheTimeout": null,
       "colorBackground": false,
-      "colorValue": true,
+      "colorValue": false,
       "colors": [
-        "#d44a3a",
+        "#299c46",
         "rgba(237, 129, 40, 0.89)",
-        "#299c46"
+        "#d44a3a"
       ],
       "datasource": "${DS_LOCAL}",
-      "format": "percentunit",
+      "format": "none",
       "gauge": {
-        "maxValue": 1,
+        "maxValue": 100,
         "minValue": 0,
-        "show": true,
+        "show": false,
         "thresholdLabels": false,
         "thresholdMarkers": true
       },
       "gridPos": {
-        "h": 6,
-        "w": 4,
-        "x": 8,
+        "h": 3,
+        "w": 2,
+        "x": 0,
         "y": 0
       },
-      "id": 12,
+      "id": 27,
       "interval": null,
       "links": [],
       "mappingType": 1,
@@ -237,20 +146,20 @@
         "fillColor": "rgba(31, 118, 189, 0.18)",
         "full": true,
         "lineColor": "rgb(31, 120, 193)",
-        "show": true
+        "show": false
       },
       "tableColumn": "",
       "targets": [
         {
-          "expr": "sum(service_center_http_success_total{job=\"service-center\"})/sum(service_center_http_request_total{job=\"service-center\"})",
+          "expr": "sum(service_center_db_sc_total{job=\"service-center\"})",
           "format": "time_series",
+          "instant": false,
           "intervalFactor": 2,
           "refId": "A"
         }
       ],
-      "thresholds": ".5,.8",
-      "title": "Global Success Rate",
-      "transparent": false,
+      "thresholds": "",
+      "title": "ServiceCenters",
       "type": "singlestat",
       "valueFontSize": "80%",
       "valueMaps": [
@@ -281,12 +190,12 @@
         "thresholdMarkers": true
       },
       "gridPos": {
-        "h": 6,
-        "w": 4,
-        "x": 12,
+        "h": 3,
+        "w": 2,
+        "x": 2,
         "y": 0
       },
-      "id": 13,
+      "id": 19,
       "interval": null,
       "links": [],
       "mappingType": 1,
@@ -319,12 +228,12 @@
         "fillColor": "rgba(31, 118, 189, 0.18)",
         "full": true,
         "lineColor": "rgb(31, 120, 193)",
-        "show": true
+        "show": false
       },
       "tableColumn": "",
       "targets": [
         {
-          "expr": "sum(irate(service_center_http_request_total{job=\"service-center\"}[1m]))",
+          "expr": "max(service_center_db_backend_total{job=\"service-center\"})",
           "format": "time_series",
           "instant": false,
           "intervalFactor": 2,
@@ -332,7 +241,7 @@
         }
       ],
       "thresholds": "",
-      "title": "Global Request Volume",
+      "title": "Backends",
       "type": "singlestat",
       "valueFontSize": "80%",
       "valueMaps": [
@@ -342,7 +251,7 @@
           "value": "null"
         }
       ],
-      "valueName": "avg"
+      "valueName": "current"
     },
     {
       "cacheTimeout": null,
@@ -354,7 +263,7 @@
         "#d44a3a"
       ],
       "datasource": "${DS_LOCAL}",
-      "format": "rps",
+      "format": "none",
       "gauge": {
         "maxValue": 100,
         "minValue": 0,
@@ -363,12 +272,12 @@
         "thresholdMarkers": true
       },
       "gridPos": {
-        "h": 6,
-        "w": 4,
-        "x": 16,
+        "h": 3,
+        "w": 3,
+        "x": 4,
         "y": 0
       },
-      "id": 10,
+      "id": 26,
       "interval": null,
       "links": [],
       "mappingType": 1,
@@ -397,130 +306,1511 @@
           "to": "null"
         }
       ],
-      "sparkline": {
-        "fillColor": "rgba(31, 118, 189, 0.18)",
-        "full": true,
-        "lineColor": "rgb(31, 120, 193)",
-        "show": true
+      "sparkline": {
+        "fillColor": "rgba(31, 118, 189, 0.18)",
+        "full": true,
+        "lineColor": "rgb(31, 120, 193)",
+        "show": false
+      },
+      "tableColumn": "",
+      "targets": [
+        {
+          "expr": "max(service_center_db_domain_total{job=\"service-center\"})",
+          "format": "time_series",
+          "instant": false,
+          "intervalFactor": 2,
+          "refId": "A"
+        }
+      ],
+      "thresholds": "",
+      "title": "Domain Volume",
+      "type": "singlestat",
+      "valueFontSize": "80%",
+      "valueMaps": [
+        {
+          "op": "=",
+          "text": "N/A",
+          "value": "null"
+        }
+      ],
+      "valueName": "current"
+    },
+    {
+      "aliasColors": {},
+      "bars": false,
+      "dashLength": 10,
+      "dashes": false,
+      "datasource": "${DS_LOCAL}",
+      "fill": 1,
+      "gridPos": {
+        "h": 5,
+        "w": 8,
+        "x": 7,
+        "y": 0
+      },
+      "height": "",
+      "id": 22,
+      "legend": {
+        "alignAsTable": true,
+        "avg": true,
+        "current": true,
+        "max": true,
+        "min": true,
+        "rightSide": false,
+        "show": true,
+        "sortDesc": true,
+        "total": false,
+        "values": true
+      },
+      "lines": true,
+      "linewidth": 1,
+      "links": [],
+      "minSpan": 4,
+      "nullPointMode": "null",
+      "percentage": false,
+      "pointradius": 5,
+      "points": false,
+      "renderer": "flot",
+      "seriesOverrides": [],
+      "spaceLength": 10,
+      "stack": false,
+      "steppedLine": false,
+      "targets": [
+        {
+          "expr": "max(service_center_db_service_total{job=\"service-center\"})",
+          "format": "time_series",
+          "instant": false,
+          "intervalFactor": 2,
+          "legendFormat": "instances",
+          "refId": "A"
+        }
+      ],
+      "thresholds": [],
+      "timeFrom": null,
+      "timeShift": null,
+      "title": "Microservices",
+      "tooltip": {
+        "shared": true,
+        "sort": 0,
+        "value_type": "individual"
+      },
+      "type": "graph",
+      "xaxis": {
+        "buckets": null,
+        "mode": "time",
+        "name": null,
+        "show": true,
+        "values": []
+      },
+      "yaxes": [
+        {
+          "format": "locale",
+          "label": null,
+          "logBase": 1,
+          "max": null,
+          "min": null,
+          "show": true
+        },
+        {
+          "format": "short",
+          "label": null,
+          "logBase": 1,
+          "max": null,
+          "min": null,
+          "show": true
+        }
+      ],
+      "yaxis": {
+        "align": false,
+        "alignLevel": null
+      }
+    },
+    {
+      "aliasColors": {},
+      "breakPoint": "50%",
+      "cacheTimeout": null,
+      "combine": {
+        "label": "Others",
+        "threshold": 0
+      },
+      "datasource": "${DS_LOCAL}",
+      "decimals": null,
+      "fontSize": "80%",
+      "format": "short",
+      "gridPos": {
+        "h": 5,
+        "w": 9,
+        "x": 15,
+        "y": 0
+      },
+      "id": 25,
+      "interval": null,
+      "legend": {
+        "header": "",
+        "percentage": true,
+        "percentageDecimals": 1,
+        "show": true,
+        "sideWidth": null,
+        "sort": "current",
+        "sortDesc": true,
+        "values": true
+      },
+      "legendType": "Right side",
+      "links": [],
+      "maxDataPoints": 3,
+      "nullPointMode": "connected",
+      "pieType": "pie",
+      "strokeWidth": 1,
+      "targets": [
+        {
+          "expr": "max(service_center_db_service_total{job=\"service-center\"}) by (framework)",
+          "format": "time_series",
+          "intervalFactor": 1,
+          "legendFormat": "{{framework}}",
+          "refId": "A"
+        }
+      ],
+      "title": "Frameworks",
+      "type": "grafana-piechart-panel",
+      "valueName": "current"
+    },
+    {
+      "cacheTimeout": null,
+      "colorBackground": false,
+      "colorValue": false,
+      "colors": [
+        "#299c46",
+        "rgba(237, 129, 40, 0.89)",
+        "#d44a3a"
+      ],
+      "datasource": "${DS_LOCAL}",
+      "format": "none",
+      "gauge": {
+        "maxValue": 100,
+        "minValue": 0,
+        "show": false,
+        "thresholdLabels": false,
+        "thresholdMarkers": true
+      },
+      "gridPos": {
+        "h": 3,
+        "w": 3,
+        "x": 4,
+        "y": 3
+      },
+      "id": 20,
+      "interval": null,
+      "links": [],
+      "mappingType": 1,
+      "mappingTypes": [
+        {
+          "name": "value to text",
+          "value": 1
+        },
+        {
+          "name": "range to text",
+          "value": 2
+        }
+      ],
+      "maxDataPoints": 100,
+      "minSpan": 4,
+      "nullPointMode": "connected",
+      "nullText": null,
+      "postfix": "",
+      "postfixFontSize": "50%",
+      "prefix": "",
+      "prefixFontSize": "50%",
+      "rangeMaps": [
+        {
+          "from": "null",
+          "text": "N/A",
+          "to": "null"
+        }
+      ],
+      "sparkline": {
+        "fillColor": "rgba(31, 118, 189, 0.18)",
+        "full": true,
+        "lineColor": "rgb(31, 120, 193)",
+        "show": false
+      },
+      "tableColumn": "",
+      "targets": [
+        {
+          "expr": "max(sum(service_center_db_service_total{job=\"service-center\"}) by (instance))",
+          "format": "time_series",
+          "instant": false,
+          "intervalFactor": 2,
+          "refId": "A"
+        }
+      ],
+      "thresholds": "",
+      "title": "Microservice Volume",
+      "type": "singlestat",
+      "valueFontSize": "80%",
+      "valueMaps": [
+        {
+          "op": "=",
+          "text": "N/A",
+          "value": "null"
+        }
+      ],
+      "valueName": "current"
+    },
+    {
+      "aliasColors": {},
+      "bars": false,
+      "dashLength": 10,
+      "dashes": false,
+      "datasource": "${DS_LOCAL}",
+      "fill": 1,
+      "gridPos": {
+        "h": 5,
+        "w": 8,
+        "x": 7,
+        "y": 5
+      },
+      "height": "",
+      "id": 29,
+      "legend": {
+        "alignAsTable": true,
+        "avg": true,
+        "current": true,
+        "hideEmpty": false,
+        "hideZero": false,
+        "max": true,
+        "min": true,
+        "rightSide": false,
+        "show": true,
+        "sortDesc": true,
+        "total": false,
+        "values": true
+      },
+      "lines": true,
+      "linewidth": 1,
+      "links": [],
+      "minSpan": 4,
+      "nullPointMode": "null",
+      "percentage": false,
+      "pointradius": 5,
+      "points": false,
+      "renderer": "flot",
+      "seriesOverrides": [],
+      "spaceLength": 10,
+      "stack": false,
+      "steppedLine": false,
+      "targets": [
+        {
+          "expr": "max(service_center_db_instance_total{job=\"service-center\"})",
+          "format": "time_series",
+          "instant": false,
+          "intervalFactor": 2,
+          "legendFormat": "instances",
+          "refId": "A"
+        }
+      ],
+      "thresholds": [],
+      "timeFrom": null,
+      "timeShift": null,
+      "title": "Instances",
+      "tooltip": {
+        "shared": true,
+        "sort": 0,
+        "value_type": "individual"
+      },
+      "type": "graph",
+      "xaxis": {
+        "buckets": null,
+        "mode": "time",
+        "name": null,
+        "show": true,
+        "values": []
+      },
+      "yaxes": [
+        {
+          "format": "locale",
+          "label": null,
+          "logBase": 1,
+          "max": null,
+          "min": null,
+          "show": true
+        },
+        {
+          "format": "short",
+          "label": null,
+          "logBase": 1,
+          "max": null,
+          "min": null,
+          "show": true
+        }
+      ],
+      "yaxis": {
+        "align": false,
+        "alignLevel": null
+      }
+    },
+    {
+      "aliasColors": {},
+      "breakPoint": "50%",
+      "cacheTimeout": null,
+      "combine": {
+        "label": "Others",
+        "threshold": 0
+      },
+      "datasource": "${DS_LOCAL}",
+      "decimals": null,
+      "fontSize": "80%",
+      "format": "short",
+      "gridPos": {
+        "h": 5,
+        "w": 3,
+        "x": 15,
+        "y": 5
+      },
+      "id": 31,
+      "interval": null,
+      "legend": {
+        "header": "",
+        "percentage": true,
+        "percentageDecimals": 1,
+        "show": false,
+        "sideWidth": null,
+        "sort": "current",
+        "sortDesc": true,
+        "values": false
+      },
+      "legendType": "On graph",
+      "links": [],
+      "maxDataPoints": 3,
+      "nullPointMode": "connected",
+      "pieType": "pie",
+      "strokeWidth": 1,
+      "targets": [
+        {
+          "expr": "max(service_center_db_service_total{job=\"service-center\", framework=\"servicecomb-java-chassis\"}) by (frameworkVersion)",
+          "format": "time_series",
+          "intervalFactor": 1,
+          "legendFormat": "{{frameworkVersion}}",
+          "refId": "A"
+        }
+      ],
+      "title": "Java Chassis Versions",
+      "type": "grafana-piechart-panel",
+      "valueName": "current"
+    },
+    {
+      "aliasColors": {},
+      "breakPoint": "50%",
+      "cacheTimeout": null,
+      "combine": {
+        "label": "Others",
+        "threshold": 0
+      },
+      "datasource": "${DS_LOCAL}",
+      "decimals": null,
+      "fontSize": "80%",
+      "format": "short",
+      "gridPos": {
+        "h": 5,
+        "w": 3,
+        "x": 18,
+        "y": 5
+      },
+      "id": 32,
+      "interval": null,
+      "legend": {
+        "header": "",
+        "percentage": true,
+        "percentageDecimals": 1,
+        "show": false,
+        "sideWidth": null,
+        "sort": "current",
+        "sortDesc": true,
+        "values": false
+      },
+      "legendType": "On graph",
+      "links": [],
+      "maxDataPoints": 3,
+      "nullPointMode": "connected",
+      "pieType": "pie",
+      "strokeWidth": 1,
+      "targets": [
+        {
+          "expr": "max(service_center_db_service_total{job=\"service-center\", framework=\"Go-Chassis\"}) by (frameworkVersion)",
+          "format": "time_series",
+          "intervalFactor": 1,
+          "legendFormat": "{{frameworkVersion}}",
+          "refId": "A"
+        }
+      ],
+      "title": "Go Chassis Versions",
+      "type": "grafana-piechart-panel",
+      "valueName": "current"
+    },
+    {
+      "aliasColors": {},
+      "breakPoint": "50%",
+      "cacheTimeout": null,
+      "combine": {
+        "label": "Others",
+        "threshold": 0
+      },
+      "datasource": "${DS_LOCAL}",
+      "decimals": null,
+      "fontSize": "80%",
+      "format": "short",
+      "gridPos": {
+        "h": 5,
+        "w": 3,
+        "x": 21,
+        "y": 5
+      },
+      "id": 33,
+      "interval": null,
+      "legend": {
+        "header": "",
+        "percentage": true,
+        "percentageDecimals": 1,
+        "show": false,
+        "sideWidth": null,
+        "sort": "current",
+        "sortDesc": true,
+        "values": false
+      },
+      "legendType": "On graph",
+      "links": [],
+      "maxDataPoints": 3,
+      "nullPointMode": "connected",
+      "pieType": "pie",
+      "strokeWidth": 1,
+      "targets": [
+        {
+          "expr": "max(service_center_db_service_total{job=\"service-center\", framework=\"Mesher\"}) by (frameworkVersion)",
+          "format": "time_series",
+          "intervalFactor": 1,
+          "legendFormat": "{{frameworkVersion}}",
+          "refId": "A"
+        }
+      ],
+      "title": "Mesher Versions",
+      "type": "grafana-piechart-panel",
+      "valueName": "current"
+    },
+    {
+      "cacheTimeout": null,
+      "colorBackground": false,
+      "colorValue": false,
+      "colors": [
+        "#299c46",
+        "rgba(237, 129, 40, 0.89)",
+        "#d44a3a"
+      ],
+      "datasource": "${DS_LOCAL}",
+      "format": "none",
+      "gauge": {
+        "maxValue": 100,
+        "minValue": 0,
+        "show": false,
+        "thresholdLabels": false,
+        "thresholdMarkers": true
+      },
+      "gridPos": {
+        "h": 3,
+        "w": 3,
+        "x": 4,
+        "y": 6
+      },
+      "id": 21,
+      "interval": null,
+      "links": [],
+      "mappingType": 1,
+      "mappingTypes": [
+        {
+          "name": "value to text",
+          "value": 1
+        },
+        {
+          "name": "range to text",
+          "value": 2
+        }
+      ],
+      "maxDataPoints": 100,
+      "minSpan": 4,
+      "nullPointMode": "connected",
+      "nullText": null,
+      "postfix": "",
+      "postfixFontSize": "50%",
+      "prefix": "",
+      "prefixFontSize": "50%",
+      "rangeMaps": [
+        {
+          "from": "null",
+          "text": "N/A",
+          "to": "null"
+        }
+      ],
+      "sparkline": {
+        "fillColor": "rgba(31, 118, 189, 0.18)",
+        "full": true,
+        "lineColor": "rgb(31, 120, 193)",
+        "show": false
+      },
+      "tableColumn": "Value",
+      "targets": [
+        {
+          "expr": "max(service_center_db_instance_total{job=\"service-center\"})",
+          "format": "time_series",
+          "instant": false,
+          "intervalFactor": 2,
+          "refId": "A"
+        }
+      ],
+      "thresholds": "",
+      "title": "Instance Volume",
+      "type": "singlestat",
+      "valueFontSize": "80%",
+      "valueMaps": [
+        {
+          "op": "=",
+          "text": "N/A",
+          "value": "null"
+        }
+      ],
+      "valueName": "current"
+    },
+    {
+      "content": "<div class=\"text-center dashboard-header\">\n  <span>PERFORMANCE</span>\n</div>\n",
+      "gridPos": {
+        "h": 3,
+        "w": 24,
+        "x": 0,
+        "y": 10
+      },
+      "height": "1px",
+      "id": 3,
+      "links": [],
+      "mode": "html",
+      "repeat": null,
+      "title": "",
+      "transparent": true,
+      "type": "text"
+    },
+    {
+      "aliasColors": {},
+      "bars": false,
+      "dashLength": 10,
+      "dashes": false,
+      "datasource": "${DS_LOCAL}",
+      "fill": 1,
+      "gridPos": {
+        "h": 6,
+        "w": 8,
+        "x": 0,
+        "y": 13
+      },
+      "height": "",
+      "id": 1,
+      "legend": {
+        "alignAsTable": true,
+        "avg": true,
+        "current": true,
+        "max": true,
+        "min": true,
+        "show": true,
+        "sort": null,
+        "sortDesc": null,
+        "total": false,
+        "values": true
+      },
+      "lines": true,
+      "linewidth": 1,
+      "links": [],
+      "minSpan": 4,
+      "nullPointMode": "null",
+      "percentage": false,
+      "pointradius": 5,
+      "points": false,
+      "renderer": "flot",
+      "seriesOverrides": [],
+      "spaceLength": 10,
+      "stack": false,
+      "steppedLine": false,
+      "targets": [
+        {
+          "expr": "sum(irate(service_center_http_request_total{job=\"service-center\"}[1m]))",
+          "format": "time_series",
+          "instant": false,
+          "intervalFactor": 2,
+          "legendFormat": "tps",
+          "refId": "A"
+        }
+      ],
+      "thresholds": [],
+      "timeFrom": null,
+      "timeShift": null,
+      "title": "TPS",
+      "tooltip": {
+        "shared": true,
+        "sort": 0,
+        "value_type": "individual"
+      },
+      "type": "graph",
+      "xaxis": {
+        "buckets": null,
+        "mode": "time",
+        "name": null,
+        "show": true,
+        "values": []
+      },
+      "yaxes": [
+        {
+          "format": "ops",
+          "label": null,
+          "logBase": 1,
+          "max": null,
+          "min": null,
+          "show": true
+        },
+        {
+          "format": "short",
+          "label": null,
+          "logBase": 1,
+          "max": null,
+          "min": null,
+          "show": true
+        }
+      ],
+      "yaxis": {
+        "align": false,
+        "alignLevel": null
+      }
+    },
+    {
+      "cacheTimeout": null,
+      "colorBackground": false,
+      "colorValue": false,
+      "colors": [
+        "#299c46",
+        "rgba(237, 129, 40, 0.89)",
+        "#d44a3a"
+      ],
+      "datasource": "${DS_LOCAL}",
+      "format": "none",
+      "gauge": {
+        "maxValue": 100,
+        "minValue": 0,
+        "show": false,
+        "thresholdLabels": false,
+        "thresholdMarkers": true
+      },
+      "gridPos": {
+        "h": 6,
+        "w": 4,
+        "x": 8,
+        "y": 13
+      },
+      "id": 13,
+      "interval": null,
+      "links": [],
+      "mappingType": 1,
+      "mappingTypes": [
+        {
+          "name": "value to text",
+          "value": 1
+        },
+        {
+          "name": "range to text",
+          "value": 2
+        }
+      ],
+      "maxDataPoints": 100,
+      "minSpan": 4,
+      "nullPointMode": "connected",
+      "nullText": null,
+      "postfix": "",
+      "postfixFontSize": "50%",
+      "prefix": "",
+      "prefixFontSize": "50%",
+      "rangeMaps": [
+        {
+          "from": "null",
+          "text": "N/A",
+          "to": "null"
+        }
+      ],
+      "sparkline": {
+        "fillColor": "rgba(31, 118, 189, 0.18)",
+        "full": true,
+        "lineColor": "rgb(31, 120, 193)",
+        "show": true
+      },
+      "tableColumn": "",
+      "targets": [
+        {
+          "expr": "sum(irate(service_center_http_request_total{job=\"service-center\"}[1m]))",
+          "format": "time_series",
+          "instant": false,
+          "intervalFactor": 2,
+          "refId": "A"
+        }
+      ],
+      "thresholds": "",
+      "title": "Global Request Volume",
+      "type": "singlestat",
+      "valueFontSize": "80%",
+      "valueMaps": [
+        {
+          "op": "=",
+          "text": "N/A",
+          "value": "null"
+        }
+      ],
+      "valueName": "current"
+    },
+    {
+      "cacheTimeout": null,
+      "colorBackground": false,
+      "colorValue": true,
+      "colors": [
+        "#d44a3a",
+        "rgba(237, 129, 40, 0.89)",
+        "#299c46"
+      ],
+      "datasource": "${DS_LOCAL}",
+      "format": "percentunit",
+      "gauge": {
+        "maxValue": 1,
+        "minValue": 0,
+        "show": true,
+        "thresholdLabels": false,
+        "thresholdMarkers": true
+      },
+      "gridPos": {
+        "h": 6,
+        "w": 4,
+        "x": 12,
+        "y": 13
+      },
+      "id": 12,
+      "interval": null,
+      "links": [],
+      "mappingType": 1,
+      "mappingTypes": [
+        {
+          "name": "value to text",
+          "value": 1
+        },
+        {
+          "name": "range to text",
+          "value": 2
+        }
+      ],
+      "maxDataPoints": 100,
+      "minSpan": 4,
+      "nullPointMode": "connected",
+      "nullText": null,
+      "postfix": "",
+      "postfixFontSize": "50%",
+      "prefix": "",
+      "prefixFontSize": "50%",
+      "rangeMaps": [
+        {
+          "from": "null",
+          "text": "N/A",
+          "to": "null"
+        }
+      ],
+      "sparkline": {
+        "fillColor": "rgba(31, 118, 189, 0.18)",
+        "full": true,
+        "lineColor": "rgb(31, 120, 193)",
+        "show": true
+      },
+      "tableColumn": "",
+      "targets": [
+        {
+          "expr": "sum(service_center_http_success_total{job=\"service-center\"})/sum(service_center_http_request_total{job=\"service-center\"})",
+          "format": "time_series",
+          "intervalFactor": 2,
+          "refId": "A"
+        }
+      ],
+      "thresholds": ".5,.8",
+      "title": "Global Success Rate",
+      "transparent": false,
+      "type": "singlestat",
+      "valueFontSize": "80%",
+      "valueMaps": [
+        {
+          "op": "=",
+          "text": "N/A",
+          "value": "null"
+        }
+      ],
+      "valueName": "current"
+    },
+    {
+      "cacheTimeout": null,
+      "colorBackground": false,
+      "colorValue": false,
+      "colors": [
+        "#299c46",
+        "rgba(237, 129, 40, 0.89)",
+        "#d44a3a"
+      ],
+      "datasource": "${DS_LOCAL}",
+      "format": "ops",
+      "gauge": {
+        "maxValue": 100,
+        "minValue": 0,
+        "show": false,
+        "thresholdLabels": false,
+        "thresholdMarkers": true
+      },
+      "gridPos": {
+        "h": 6,
+        "w": 4,
+        "x": 16,
+        "y": 13
+      },
+      "id": 10,
+      "interval": null,
+      "links": [],
+      "mappingType": 1,
+      "mappingTypes": [
+        {
+          "name": "value to text",
+          "value": 1
+        },
+        {
+          "name": "range to text",
+          "value": 2
+        }
+      ],
+      "maxDataPoints": 100,
+      "minSpan": 4,
+      "nullPointMode": "connected",
+      "nullText": null,
+      "postfix": "",
+      "postfixFontSize": "50%",
+      "prefix": "",
+      "prefixFontSize": "50%",
+      "rangeMaps": [
+        {
+          "from": "null",
+          "text": "N/A",
+          "to": "null"
+        }
+      ],
+      "sparkline": {
+        "fillColor": "rgba(31, 118, 189, 0.18)",
+        "full": true,
+        "lineColor": "rgb(31, 120, 193)",
+        "show": true
+      },
+      "tableColumn": "",
+      "targets": [
+        {
+          "expr": "sum(irate(service_center_http_request_total{job=\"service-center\",code=~\"4.+\"}[1m]))",
+          "format": "time_series",
+          "instant": false,
+          "intervalFactor": 2,
+          "legendFormat": "",
+          "refId": "A"
+        }
+      ],
+      "thresholds": "",
+      "title": "4XX Errors",
+      "type": "singlestat",
+      "valueFontSize": "80%",
+      "valueMaps": [
+        {
+          "op": "=",
+          "text": "N/A",
+          "value": "null"
+        }
+      ],
+      "valueName": "avg"
+    },
+    {
+      "cacheTimeout": null,
+      "colorBackground": false,
+      "colorValue": false,
+      "colors": [
+        "#299c46",
+        "rgba(237, 129, 40, 0.89)",
+        "#d44a3a"
+      ],
+      "datasource": "${DS_LOCAL}",
+      "format": "ops",
+      "gauge": {
+        "maxValue": 100,
+        "minValue": 0,
+        "show": false,
+        "thresholdLabels": false,
+        "thresholdMarkers": true
+      },
+      "gridPos": {
+        "h": 6,
+        "w": 4,
+        "x": 20,
+        "y": 13
+      },
+      "id": 11,
+      "interval": null,
+      "links": [],
+      "mappingType": 1,
+      "mappingTypes": [
+        {
+          "name": "value to text",
+          "value": 1
+        },
+        {
+          "name": "range to text",
+          "value": 2
+        }
+      ],
+      "maxDataPoints": 100,
+      "minSpan": 4,
+      "nullPointMode": "connected",
+      "nullText": null,
+      "postfix": "",
+      "postfixFontSize": "50%",
+      "prefix": "",
+      "prefixFontSize": "50%",
+      "rangeMaps": [
+        {
+          "from": "null",
+          "text": "N/A",
+          "to": "null"
+        }
+      ],
+      "sparkline": {
+        "fillColor": "rgba(31, 118, 189, 0.18)",
+        "full": true,
+        "lineColor": "rgb(31, 120, 193)",
+        "show": true
+      },
+      "tableColumn": "",
+      "targets": [
+        {
+          "expr": "sum(irate(service_center_http_request_total{job=\"service-center\",code=~\"5.+\"}[1m]))",
+          "format": "time_series",
+          "intervalFactor": 2,
+          "refId": "A"
+        }
+      ],
+      "thresholds": "",
+      "title": "5XX Errors",
+      "type": "singlestat",
+      "valueFontSize": "80%",
+      "valueMaps": [
+        {
+          "op": "=",
+          "text": "N/A",
+          "value": "null"
+        }
+      ],
+      "valueName": "avg"
+    },
+    {
+      "aliasColors": {},
+      "bars": false,
+      "dashLength": 10,
+      "dashes": false,
+      "datasource": "${DS_LOCAL}",
+      "fill": 1,
+      "gridPos": {
+        "h": 6,
+        "w": 8,
+        "x": 0,
+        "y": 19
+      },
+      "height": "",
+      "id": 28,
+      "legend": {
+        "alignAsTable": true,
+        "avg": true,
+        "current": true,
+        "max": true,
+        "min": true,
+        "show": true,
+        "sort": null,
+        "sortDesc": null,
+        "total": false,
+        "values": true
+      },
+      "lines": true,
+      "linewidth": 1,
+      "links": [],
+      "minSpan": 4,
+      "nullPointMode": "null",
+      "percentage": false,
+      "pointradius": 5,
+      "points": false,
+      "renderer": "flot",
+      "seriesOverrides": [],
+      "spaceLength": 10,
+      "stack": false,
+      "steppedLine": false,
+      "targets": [
+        {
+          "expr": "sum(service_center_http_success_total{job=\"service-center\"})/sum(service_center_http_request_total{job=\"service-center\"})",
+          "format": "time_series",
+          "instant": false,
+          "intervalFactor": 2,
+          "legendFormat": "rate",
+          "refId": "A"
+        }
+      ],
+      "thresholds": [],
+      "timeFrom": null,
+      "timeShift": null,
+      "title": "Success Rate",
+      "tooltip": {
+        "shared": true,
+        "sort": 0,
+        "value_type": "individual"
+      },
+      "type": "graph",
+      "xaxis": {
+        "buckets": null,
+        "mode": "time",
+        "name": null,
+        "show": true,
+        "values": []
+      },
+      "yaxes": [
+        {
+          "format": "percentunit",
+          "label": null,
+          "logBase": 1,
+          "max": null,
+          "min": null,
+          "show": true
+        },
+        {
+          "format": "short",
+          "label": null,
+          "logBase": 1,
+          "max": null,
+          "min": null,
+          "show": true
+        }
+      ],
+      "yaxis": {
+        "align": false,
+        "alignLevel": null
+      }
+    },
+    {
+      "content": "<div class=\"text-center dashboard-header\">\n  <span>INSTANCE METRICS</span>\n</div>\n",
+      "gridPos": {
+        "h": 3,
+        "w": 24,
+        "x": 0,
+        "y": 25
+      },
+      "height": "1px",
+      "id": 30,
+      "links": [],
+      "mode": "html",
+      "title": "",
+      "transparent": true,
+      "type": "text"
+    },
+    {
+      "aliasColors": {},
+      "bars": false,
+      "dashLength": 10,
+      "dashes": false,
+      "datasource": "${DS_LOCAL}",
+      "fill": 1,
+      "gridPos": {
+        "h": 6,
+        "w": 6,
+        "x": 0,
+        "y": 28
+      },
+      "height": "",
+      "id": 18,
+      "legend": {
+        "alignAsTable": false,
+        "avg": false,
+        "current": false,
+        "hideEmpty": true,
+        "hideZero": true,
+        "max": false,
+        "min": false,
+        "rightSide": false,
+        "show": false,
+        "sort": "avg",
+        "sortDesc": true,
+        "total": false,
+        "values": false
+      },
+      "lines": true,
+      "linewidth": 1,
+      "links": [],
+      "minSpan": 4,
+      "nullPointMode": "null",
+      "percentage": false,
+      "pointradius": 5,
+      "points": false,
+      "renderer": "flot",
+      "seriesOverrides": [],
+      "spaceLength": 10,
+      "stack": false,
+      "steppedLine": false,
+      "targets": [
+        {
+          "expr": "sum(service_center_http_request_total{job=\"service-center\"}) by (method,api,instance)",
+          "format": "time_series",
+          "instant": false,
+          "intervalFactor": 2,
+          "legendFormat": "{{instance}}> {{method}} {{api}}",
+          "refId": "A"
+        },
+        {
+          "expr": "sum(service_center_http_request_total{job=\"service-center\"})",
+          "format": "time_series",
+          "intervalFactor": 1,
+          "legendFormat": "{{instance}}> Total",
+          "refId": "B"
+        }
+      ],
+      "thresholds": [],
+      "timeFrom": null,
+      "timeShift": null,
+      "title": "Request Total",
+      "tooltip": {
+        "shared": true,
+        "sort": 0,
+        "value_type": "individual"
+      },
+      "transparent": false,
+      "type": "graph",
+      "xaxis": {
+        "buckets": null,
+        "mode": "time",
+        "name": null,
+        "show": true,
+        "values": []
+      },
+      "yaxes": [
+        {
+          "format": "ops",
+          "label": null,
+          "logBase": 1,
+          "max": null,
+          "min": null,
+          "show": true
+        },
+        {
+          "format": "short",
+          "label": null,
+          "logBase": 1,
+          "max": null,
+          "min": null,
+          "show": true
+        }
+      ],
+      "yaxis": {
+        "align": false,
+        "alignLevel": null
+      }
+    },
+    {
+      "aliasColors": {},
+      "bars": false,
+      "dashLength": 10,
+      "dashes": false,
+      "datasource": "${DS_LOCAL}",
+      "fill": 1,
+      "gridPos": {
+        "h": 6,
+        "w": 6,
+        "x": 6,
+        "y": 28
+      },
+      "height": "",
+      "id": 17,
+      "legend": {
+        "alignAsTable": true,
+        "avg": true,
+        "current": true,
+        "hideEmpty": true,
+        "hideZero": true,
+        "max": true,
+        "min": true,
+        "show": false,
+        "sort": null,
+        "sortDesc": null,
+        "total": false,
+        "values": true
+      },
+      "lines": true,
+      "linewidth": 1,
+      "links": [],
+      "minSpan": 4,
+      "nullPointMode": "null",
+      "percentage": false,
+      "pointradius": 5,
+      "points": false,
+      "renderer": "flot",
+      "seriesOverrides": [],
+      "spaceLength": 10,
+      "stack": false,
+      "steppedLine": false,
+      "targets": [
+        {
+          "expr": "sum(irate(service_center_http_request_total{job=\"service-center\"}[1m])) by (method,api,instance)",
+          "format": "time_series",
+          "instant": false,
+          "intervalFactor": 2,
+          "legendFormat": "{{instance}}> {{method}} {{api}}",
+          "refId": "A"
+        }
+      ],
+      "thresholds": [],
+      "timeFrom": null,
+      "timeShift": null,
+      "title": "TPS of APIs",
+      "tooltip": {
+        "shared": true,
+        "sort": 0,
+        "value_type": "individual"
+      },
+      "type": "graph",
+      "xaxis": {
+        "buckets": null,
+        "mode": "time",
+        "name": null,
+        "show": true,
+        "values": []
+      },
+      "yaxes": [
+        {
+          "format": "ops",
+          "label": null,
+          "logBase": 1,
+          "max": null,
+          "min": null,
+          "show": true
+        },
+        {
+          "format": "short",
+          "label": null,
+          "logBase": 1,
+          "max": null,
+          "min": null,
+          "show": true
+        }
+      ],
+      "yaxis": {
+        "align": false,
+        "alignLevel": null
+      }
+    },
+    {
+      "aliasColors": {},
+      "bars": false,
+      "dashLength": 10,
+      "dashes": false,
+      "datasource": "${DS_LOCAL}",
+      "fill": 1,
+      "gridPos": {
+        "h": 6,
+        "w": 6,
+        "x": 12,
+        "y": 28
       },
-      "tableColumn": "",
+      "height": "",
+      "id": 15,
+      "legend": {
+        "alignAsTable": false,
+        "avg": true,
+        "current": false,
+        "hideEmpty": true,
+        "hideZero": true,
+        "max": true,
+        "min": true,
+        "rightSide": true,
+        "show": false,
+        "sort": "avg",
+        "sortDesc": true,
+        "total": false,
+        "values": true
+      },
+      "lines": true,
+      "linewidth": 1,
+      "links": [],
+      "minSpan": 4,
+      "nullPointMode": "null",
+      "percentage": false,
+      "pointradius": 5,
+      "points": false,
+      "renderer": "flot",
+      "seriesOverrides": [],
+      "spaceLength": 10,
+      "stack": false,
+      "steppedLine": false,
       "targets": [
         {
-          "expr": "sum(irate(service_center_http_request_total{job=\"service-center\",code=~\"4.+\"}[1m]))",
+          "expr": "max(avg_over_time(service_center_http_request_durations_microseconds{job=\"service-center\",method=\"GET\"}[1m])) by (method,api,instance)",
           "format": "time_series",
           "instant": false,
           "intervalFactor": 2,
-          "legendFormat": "",
+          "legendFormat": "{{instance}}> {{method}} {{api}}",
           "refId": "A"
         }
       ],
-      "thresholds": "",
-      "title": "4XX Errors",
-      "type": "singlestat",
-      "valueFontSize": "80%",
-      "valueMaps": [
+      "thresholds": [],
+      "timeFrom": null,
+      "timeShift": null,
+      "title": "Read Latency",
+      "tooltip": {
+        "shared": true,
+        "sort": 0,
+        "value_type": "individual"
+      },
+      "transparent": false,
+      "type": "graph",
+      "xaxis": {
+        "buckets": null,
+        "mode": "time",
+        "name": null,
+        "show": true,
+        "values": []
+      },
+      "yaxes": [
         {
-          "op": "=",
-          "text": "N/A",
-          "value": "null"
+          "format": "µs",
+          "label": null,
+          "logBase": 1,
+          "max": null,
+          "min": null,
+          "show": true
+        },
+        {
+          "format": "short",
+          "label": null,
+          "logBase": 1,
+          "max": null,
+          "min": null,
+          "show": true
         }
       ],
-      "valueName": "avg"
+      "yaxis": {
+        "align": false,
+        "alignLevel": null
+      }
     },
     {
-      "cacheTimeout": null,
-      "colorBackground": false,
-      "colorValue": false,
-      "colors": [
-        "#299c46",
-        "rgba(237, 129, 40, 0.89)",
-        "#d44a3a"
-      ],
+      "aliasColors": {},
+      "bars": false,
+      "dashLength": 10,
+      "dashes": false,
       "datasource": "${DS_LOCAL}",
-      "format": "rps",
-      "gauge": {
-        "maxValue": 100,
-        "minValue": 0,
-        "show": false,
-        "thresholdLabels": false,
-        "thresholdMarkers": true
-      },
+      "fill": 1,
       "gridPos": {
         "h": 6,
-        "w": 4,
-        "x": 20,
-        "y": 0
+        "w": 6,
+        "x": 18,
+        "y": 28
       },
-      "id": 11,
-      "interval": null,
+      "height": "",
+      "id": 16,
+      "legend": {
+        "alignAsTable": false,
+        "avg": true,
+        "current": false,
+        "hideEmpty": true,
+        "hideZero": true,
+        "max": true,
+        "min": true,
+        "rightSide": true,
+        "show": false,
+        "sort": "avg",
+        "sortDesc": true,
+        "total": false,
+        "values": true
+      },
+      "lines": true,
+      "linewidth": 1,
       "links": [],
-      "mappingType": 1,
-      "mappingTypes": [
-        {
-          "name": "value to text",
-          "value": 1
-        },
-        {
-          "name": "range to text",
-          "value": 2
-        }
-      ],
-      "maxDataPoints": 100,
       "minSpan": 4,
-      "nullPointMode": "connected",
-      "nullText": null,
-      "postfix": "",
-      "postfixFontSize": "50%",
-      "prefix": "",
-      "prefixFontSize": "50%",
-      "rangeMaps": [
-        {
-          "from": "null",
-          "text": "N/A",
-          "to": "null"
-        }
-      ],
-      "sparkline": {
-        "fillColor": "rgba(31, 118, 189, 0.18)",
-        "full": true,
-        "lineColor": "rgb(31, 120, 193)",
-        "show": true
-      },
-      "tableColumn": "",
+      "nullPointMode": "null",
+      "percentage": false,
+      "pointradius": 5,
+      "points": false,
+      "renderer": "flot",
+      "seriesOverrides": [],
+      "spaceLength": 10,
+      "stack": false,
+      "steppedLine": false,
       "targets": [
         {
-          "expr": "sum(irate(service_center_http_request_total{job=\"service-center\",code=~\"5.+\"}[1m]))",
+          "expr": "max(avg_over_time(service_center_http_request_durations_microseconds{job=\"service-center\",method!=\"GET\"}[1m])) by (method,api,instance)",
           "format": "time_series",
+          "instant": false,
           "intervalFactor": 2,
+          "legendFormat": "{{instance}}> {{method}} {{api}}",
           "refId": "A"
         }
       ],
-      "thresholds": "",
-      "title": "5XX Errors",
-      "type": "singlestat",
-      "valueFontSize": "80%",
-      "valueMaps": [
+      "thresholds": [],
+      "timeFrom": null,
+      "timeShift": null,
+      "title": "Write Latency",
+      "tooltip": {
+        "shared": true,
+        "sort": 0,
+        "value_type": "individual"
+      },
+      "transparent": false,
+      "type": "graph",
+      "xaxis": {
+        "buckets": null,
+        "mode": "time",
+        "name": null,
+        "show": true,
+        "values": []
+      },
+      "yaxes": [
         {
-          "op": "=",
-          "text": "N/A",
-          "value": "null"
+          "format": "µs",
+          "label": null,
+          "logBase": 1,
+          "max": null,
+          "min": null,
+          "show": true
+        },
+        {
+          "format": "short",
+          "label": null,
+          "logBase": 1,
+          "max": null,
+          "min": null,
+          "show": true
         }
       ],
-      "valueName": "avg"
+      "yaxis": {
+        "align": false,
+        "alignLevel": null
+      }
     },
     {
-      "content": "<div class=\"text-center dashboard-header\">\n  <span>INSTANCE METRICS</span>\n</div>\n",
+      "content": "<div class=\"text-center dashboard-header\">\n  <span>RESOURCES</span>\n</div>\n",
       "gridPos": {
         "h": 3,
         "w": 24,
         "x": 0,
-        "y": 6
+        "y": 34
       },
       "height": "1px",
-      "id": 3,
+      "id": 4,
       "links": [],
       "mode": "html",
-      "repeat": null,
       "title": "",
       "transparent": true,
       "type": "text"
@@ -536,7 +1826,7 @@
         "h": 7,
         "w": 8,
         "x": 0,
-        "y": 9
+        "y": 37
       },
       "height": "",
       "id": 2,
@@ -570,7 +1860,7 @@
           "format": "time_series",
           "instant": false,
           "intervalFactor": 2,
-          "legendFormat": "goroutines_{{instance}}",
+          "legendFormat": "{{instance}}",
           "refId": "A"
         }
       ],
@@ -625,7 +1915,7 @@
         "h": 7,
         "w": 8,
         "x": 8,
-        "y": 9
+        "y": 37
       },
       "height": "",
       "id": 9,
@@ -657,7 +1947,7 @@
           "format": "time_series",
           "instant": false,
           "intervalFactor": 2,
-          "legendFormat": "cpu_{{instance}}",
+          "legendFormat": "{{instance}}",
           "refId": "A"
         }
       ],
@@ -712,7 +2002,7 @@
         "h": 7,
         "w": 8,
         "x": 16,
-        "y": 9
+        "y": 37
       },
       "height": "",
       "id": 8,
@@ -740,11 +2030,11 @@
       "steppedLine": false,
       "targets": [
         {
-          "expr": "max(max_over_time(go_gc_duration_seconds{job=\"service-center\"}[1m])) by (instance)",
+          "expr": "max(avg_over_time(go_gc_duration_seconds{job=\"service-center\"}[1m])) by (instance)",
           "format": "time_series",
           "instant": false,
           "intervalFactor": 2,
-          "legendFormat": "gc_{{instance}}",
+          "legendFormat": "{{instance}}",
           "refId": "A"
         }
       ],
@@ -789,22 +2079,6 @@
       }
     },
     {
-      "content": "<div class=\"text-center dashboard-header\">\n  <span>RESOURCES</span>\n</div>\n",
-      "gridPos": {
-        "h": 3,
-        "w": 24,
-        "x": 0,
-        "y": 16
-      },
-      "height": "1px",
-      "id": 4,
-      "links": [],
-      "mode": "html",
-      "title": "",
-      "transparent": true,
-      "type": "text"
-    },
-    {
       "aliasColors": {},
       "bars": false,
       "dashLength": 10,
@@ -815,7 +2089,7 @@
         "h": 7,
         "w": 8,
         "x": 0,
-        "y": 19
+        "y": 44
       },
       "id": 5,
       "legend": {
@@ -845,7 +2119,7 @@
           "expr": "go_threads{job=\"service-center\"}",
           "format": "time_series",
           "intervalFactor": 2,
-          "legendFormat": "threads_{{instance}}",
+          "legendFormat": "{{instance}}",
           "refId": "A"
         }
       ],
@@ -900,7 +2174,7 @@
         "h": 7,
         "w": 8,
         "x": 8,
-        "y": 19
+        "y": 44
       },
       "id": 6,
       "legend": {
@@ -930,7 +2204,7 @@
           "expr": "process_open_fds{job=\"service-center\"}",
           "format": "time_series",
           "intervalFactor": 2,
-          "legendFormat": "fds_{{instance}}",
+          "legendFormat": "{{instance}}",
           "refId": "A"
         }
       ],
@@ -985,7 +2259,7 @@
         "h": 7,
         "w": 8,
         "x": 16,
-        "y": 19
+        "y": 44
       },
       "id": 14,
       "legend": {
@@ -1012,24 +2286,10 @@
       "steppedLine": false,
       "targets": [
         {
-          "expr": "go_memstats_heap_inuse_bytes{job=\"service-center\"} + go_memstats_heap_idle_bytes{job=\"service-center\"}",
-          "format": "time_series",
-          "intervalFactor": 1,
-          "legendFormat": "heap_{{instance}}",
-          "refId": "B"
-        },
-        {
-          "expr": "go_memstats_heap_inuse_bytes{job=\"service-center\"}",
-          "format": "time_series",
-          "intervalFactor": 1,
-          "legendFormat": "inuse_{{instance}}",
-          "refId": "C"
-        },
-        {
           "expr": "process_resident_memory_bytes{job=\"service-center\"}",
           "format": "time_series",
           "intervalFactor": 1,
-          "legendFormat": "all_{{instance}}",
+          "legendFormat": "{{instance}}",
           "refId": "A"
         }
       ],
@@ -1084,7 +2344,7 @@
         "h": 7,
         "w": 24,
         "x": 0,
-        "y": 26
+        "y": 51
       },
       "id": 7,
       "legend": {
@@ -1117,14 +2377,14 @@
           "expr": "sum(service_center_local_cache_size_bytes{job=\"service-center\"}) by (resource,instance)",
           "format": "time_series",
           "intervalFactor": 2,
-          "legendFormat": "{{resource}}_{{instance}}",
+          "legendFormat": "{{instance}}> {{resource}}",
           "refId": "A"
         },
         {
           "expr": "sum(service_center_local_cache_size_bytes{job=\"service-center\"}) by (instance)",
           "format": "time_series",
           "intervalFactor": 2,
-          "legendFormat": "ALL_{{instance}}",
+          "legendFormat": "{{instance}}> ALL",
           "refId": "B"
         }
       ],
@@ -1208,5 +2468,5 @@
   "timezone": "",
   "title": "ServiceCenter",
   "uid": "Zg6NoHGiz",
-  "version": 6
+  "version": 45
 }
\ No newline at end of file
diff --git a/integration/instances_test.go b/integration/instances_test.go
index ec71f21..458c45d 100644
--- a/integration/instances_test.go
+++ b/integration/instances_test.go
@@ -249,7 +249,7 @@ var _ = Describe("MicroService Api Test", func() {
 
 		By("Discover MicroService Instance API", func() {
 			It("Find Micro-service Info by AppID", func() {
-				req, _ := http.NewRequest(GET, SCURL+FINDINSTANCE+"?noCache=1&appId="+serviceAppId+"&serviceName="+serviceName+"&version="+serviceVersion, nil)
+				req, _ := http.NewRequest(GET, SCURL+FINDINSTANCE+"?appId="+serviceAppId+"&serviceName="+serviceName+"&version="+serviceVersion, nil)
 				req.Header.Set("X-Domain-Name", "default")
 				req.Header.Set("X-ConsumerId", serviceId)
 				resp, _ := scclient.Do(req)
@@ -330,7 +330,7 @@ var _ = Describe("MicroService Api Test", func() {
 			})
 
 			It("Find Micro-Service Instance with rev", func() {
-				req, _ := http.NewRequest(GET, SCURL+FINDINSTANCE+"?noCache=1&appId="+serviceAppId+"&serviceName="+serviceName+"&version="+serviceVersion, nil)
+				req, _ := http.NewRequest(GET, SCURL+FINDINSTANCE+"?appId="+serviceAppId+"&serviceName="+serviceName+"&version="+serviceVersion, nil)
 				req.Header.Set("X-Domain-Name", "default")
 				req.Header.Set("X-ConsumerId", serviceId)
 				resp, _ := scclient.Do(req)
@@ -349,6 +349,7 @@ var _ = Describe("MicroService Api Test", func() {
 				Expect(rev).NotTo(BeEmpty())
 			})
 		})
+
 		By("Update Micro-Service Instance Information API's", func() {
 			It("Update Micro-Service Instance Properties", func() {
 				propertiesInstance := map[string]interface{}{
@@ -473,6 +474,7 @@ var _ = Describe("MicroService Api Test", func() {
 				}
 			})
 		})
+
 		By("Micro-Service Instance heartbeat API", func() {
 			It("Send HeartBeat for micro-service instance", func() {
 				url := strings.Replace(INSTANCEHEARTBEAT, ":serviceId", serviceId, 1)
diff --git a/integration/microservices_test.go b/integration/microservices_test.go
index 9544580..0361275 100644
--- a/integration/microservices_test.go
+++ b/integration/microservices_test.go
@@ -410,9 +410,21 @@ var _ = Describe("MicroService Api Test", func() {
 					// Validate the dependency creation
 					Expect(resp.StatusCode).To(Equal(http.StatusOK))
 
-					<-time.After(time.Second)
+					// add new dependency
+					dependency["providers"] = []interface{}{consumer}
+					body, _ = json.Marshal(bodyParams)
+					bodyBuf = bytes.NewReader(body)
+					req, _ = http.NewRequest(POST, SCURL+CREATEDEPENDENCIES, bodyBuf)
+					req.Header.Set("X-Domain-Name", "default")
+					resp, err = scclient.Do(req)
+					Expect(err).To(BeNil())
+					defer resp.Body.Close()
+
+					// Validate the dependency creation
+					Expect(resp.StatusCode).To(Equal(http.StatusOK))
 
 					//Get Provider by ConsumerID
+					<-time.After(time.Second)
 					url := strings.Replace(GETCONPRODEPENDENCY, ":consumerId", consumerServiceID, 1)
 					req, _ = http.NewRequest(GET, SCURL+url, nil)
 					req.Header.Set("X-Domain-Name", "default")
@@ -432,7 +444,6 @@ var _ = Describe("MicroService Api Test", func() {
 					Expect(foundMicroService).To(Equal(true))
 
 					//Get Consumer by ProviderID
-
 					url = strings.Replace(GETPROCONDEPENDENCY, ":providerId", serviceId, 1)
 					req, _ = http.NewRequest(GET, SCURL+url, nil)
 					req.Header.Set("X-Domain-Name", "default")
@@ -451,10 +462,30 @@ var _ = Describe("MicroService Api Test", func() {
 					}
 					Expect(foundMicroService).To(Equal(true))
 
-					providersArray = []interface{}{consumer}
+					//Get new dependency by ConsumerID
+					url = strings.Replace(GETCONPRODEPENDENCY, ":consumerId", consumerServiceID, 1)
+					req, _ = http.NewRequest(GET, SCURL+url, nil)
+					req.Header.Set("X-Domain-Name", "default")
+					resp, _ = scclient.Do(req)
+					respbody, _ = ioutil.ReadAll(resp.Body)
+					Expect(resp.StatusCode).To(Equal(http.StatusOK))
+					servicesStruct = map[string][]map[string]interface{}{}
+
+					json.Unmarshal(respbody, &servicesStruct)
+					foundMicroService = false
+					for _, services := range servicesStruct["providers"] {
+						if services["serviceName"] == consumerAppName {
+							foundMicroService = true
+							break
+						}
+					}
+					Expect(foundMicroService).To(Equal(true))
+
+					// override the dependency
+					dependency["providers"] = []interface{}{}
 					body, _ = json.Marshal(bodyParams)
 					bodyBuf = bytes.NewReader(body)
-					req, _ = http.NewRequest(POST, SCURL+CREATEDEPENDENCIES, bodyBuf)
+					req, _ = http.NewRequest(UPDATE, SCURL+CREATEDEPENDENCIES, bodyBuf)
 					req.Header.Set("X-Domain-Name", "default")
 					resp, err = scclient.Do(req)
 					Expect(err).To(BeNil())
@@ -463,7 +494,8 @@ var _ = Describe("MicroService Api Test", func() {
 					// Validate the dependency creation
 					Expect(resp.StatusCode).To(Equal(http.StatusOK))
 
-					//Get Provider by ConsumerID
+					//Get Provider by ConsumerID again
+					<-time.After(time.Second)
 					url = strings.Replace(GETCONPRODEPENDENCY, ":consumerId", consumerServiceID, 1)
 					req, _ = http.NewRequest(GET, SCURL+url, nil)
 					req.Header.Set("X-Domain-Name", "default")
@@ -471,16 +503,8 @@ var _ = Describe("MicroService Api Test", func() {
 					respbody, _ = ioutil.ReadAll(resp.Body)
 					Expect(resp.StatusCode).To(Equal(http.StatusOK))
 					servicesStruct = map[string][]map[string]interface{}{}
-
 					json.Unmarshal(respbody, &servicesStruct)
-					foundMicroService = false
-					for _, services := range servicesStruct["providers"] {
-						if services["serviceName"] == serviceName {
-							foundMicroService = true
-							break
-						}
-					}
-					Expect(foundMicroService).To(Equal(true))
+					Expect(len(servicesStruct["providers"])).To(Equal(0))
 
 					//Delete Consumer and Provider
 					url = strings.Replace(UNREGISTERMICROSERVICE, ":serviceId", consumerServiceID, 1)
@@ -498,7 +522,6 @@ var _ = Describe("MicroService Api Test", func() {
 				})
 
 				It("Invalid scenario for GET Providers and Consumers", func() {
-
 					//Get Provider by ConsumerID
 					url := strings.Replace(GETCONPRODEPENDENCY, ":consumerId", "wrongID", 1)
 					req, _ := http.NewRequest(GET, SCURL+url, nil)
diff --git a/integration/rules_test.go b/integration/rules_test.go
index 206f039..13543c3 100644
--- a/integration/rules_test.go
+++ b/integration/rules_test.go
@@ -28,6 +28,7 @@ import (
 	"net/http"
 	"strconv"
 	"strings"
+	"time"
 )
 
 var _ = Describe("MicroService Api Test", func() {
@@ -185,8 +186,9 @@ var _ = Describe("MicroService Api Test", func() {
 				Expect(resp.StatusCode).To(Equal(http.StatusOK))
 
 				//Duplicate Request
+				<-time.After(time.Second)
 				bodyBuf = bytes.NewReader(body)
-				req, _ = http.NewRequest(POST, SCURL+url+"?noCache=1", bodyBuf)
+				req, _ = http.NewRequest(POST, SCURL+url, bodyBuf)
 				req.Header.Set("X-Domain-Name", "default")
 				resp, err = scclient.Do(req)
 				Expect(err).To(BeNil())
@@ -224,8 +226,9 @@ var _ = Describe("MicroService Api Test", func() {
 				Expect(resp.StatusCode).To(Equal(http.StatusOK))
 
 				//Get Rules
+				<-time.After(time.Second)
 				url = strings.Replace(GETRULES, ":serviceId", serviceId, 1)
-				req, _ = http.NewRequest(GET, SCURL+url+"?noCache=1", nil)
+				req, _ = http.NewRequest(GET, SCURL+url, nil)
 				req.Header.Set("X-Domain-Name", "default")
 				req.Header.Set("X-ConsumerId", serviceId)
 				resp, _ = scclient.Do(req)
@@ -295,6 +298,7 @@ var _ = Describe("MicroService Api Test", func() {
 				}
 
 				//Update Rules
+				<-time.After(time.Second)
 				updateParams := map[string]interface{}{
 					"ruleType":    "WHITE",
 					"attribute":   "tag_b",
@@ -305,7 +309,7 @@ var _ = Describe("MicroService Api Test", func() {
 				url = strings.Replace(url, ":rule_id", ruleID, 1)
 				body, _ = json.Marshal(updateParams)
 				bodyBuf = bytes.NewReader(body)
-				req, _ = http.NewRequest(UPDATE, SCURL+url+"?noCache=1", bodyBuf)
+				req, _ = http.NewRequest(UPDATE, SCURL+url, bodyBuf)
 				req.Header.Set("X-Domain-Name", "default")
 				resp, err = scclient.Do(req)
 				Expect(err).To(BeNil())
@@ -314,8 +318,9 @@ var _ = Describe("MicroService Api Test", func() {
 				Expect(resp.StatusCode).To(Equal(http.StatusOK))
 
 				//Get Rules
+				<-time.After(time.Second)
 				url = strings.Replace(GETRULES, ":serviceId", serviceId, 1)
-				req, _ = http.NewRequest(GET, SCURL+url+"?noCache=1", nil)
+				req, _ = http.NewRequest(GET, SCURL+url, nil)
 				req.Header.Set("X-Domain-Name", "default")
 				req.Header.Set("X-ConsumerId", serviceId)
 				resp, _ = scclient.Do(req)
@@ -362,6 +367,7 @@ var _ = Describe("MicroService Api Test", func() {
 				}
 
 				//Update Rules with invalid RuleType
+				<-time.After(time.Second)
 				updateParams := map[string]interface{}{
 					"ruleType":    "UNKNOWN",
 					"attribute":   "tag_b",
@@ -372,7 +378,7 @@ var _ = Describe("MicroService Api Test", func() {
 				url = strings.Replace(url, ":rule_id", ruleID, 1)
 				body, _ = json.Marshal(updateParams)
 				bodyBuf = bytes.NewReader(body)
-				req, _ = http.NewRequest(UPDATE, SCURL+url+"?noCache=1", bodyBuf)
+				req, _ = http.NewRequest(UPDATE, SCURL+url, bodyBuf)
 				req.Header.Set("X-Domain-Name", "default")
 				resp, err = scclient.Do(req)
 				Expect(err).To(BeNil())
@@ -380,6 +386,7 @@ var _ = Describe("MicroService Api Test", func() {
 				Expect(resp.StatusCode).To(Equal(http.StatusBadRequest))
 
 				//Update Rules with invalid pattern
+				<-time.After(time.Second)
 				updateParams = map[string]interface{}{
 					"ruleType":    "WHITE",
 					"attribute":   "tag_b",
@@ -390,7 +397,7 @@ var _ = Describe("MicroService Api Test", func() {
 				url = strings.Replace(url, ":rule_id", ruleID, 1)
 				body, _ = json.Marshal(updateParams)
 				bodyBuf = bytes.NewReader(body)
-				req, _ = http.NewRequest(UPDATE, SCURL+url+"?noCache=1", bodyBuf)
+				req, _ = http.NewRequest(UPDATE, SCURL+url, bodyBuf)
 				req.Header.Set("X-Domain-Name", "default")
 				resp, err = scclient.Do(req)
 				Expect(err).To(BeNil())
@@ -398,6 +405,7 @@ var _ = Describe("MicroService Api Test", func() {
 				Expect(resp.StatusCode).To(Equal(http.StatusBadRequest))
 
 				//Update Rules with invalid different ruleType
+				<-time.After(time.Second)
 				updateParams = map[string]interface{}{
 					"ruleType":    "BLACK",
 					"attribute":   "tag_b",
@@ -408,7 +416,7 @@ var _ = Describe("MicroService Api Test", func() {
 				url = strings.Replace(url, ":rule_id", ruleID, 1)
 				body, _ = json.Marshal(updateParams)
 				bodyBuf = bytes.NewReader(body)
-				req, _ = http.NewRequest(UPDATE, SCURL+url+"?noCache=1", bodyBuf)
+				req, _ = http.NewRequest(UPDATE, SCURL+url, bodyBuf)
 				req.Header.Set("X-Domain-Name", "default")
 				resp, err = scclient.Do(req)
 				Expect(err).To(BeNil())
@@ -470,9 +478,10 @@ var _ = Describe("MicroService Api Test", func() {
 				}
 
 				//Delete the Rules
+				<-time.After(time.Second)
 				url = strings.Replace(DELETERULES, ":serviceId", serviceId, 1)
 				url = strings.Replace(url, ":rule_id", ruleID, 1)
-				req, _ = http.NewRequest(DELETE, SCURL+url+"?noCache=1", nil)
+				req, _ = http.NewRequest(DELETE, SCURL+url, nil)
 				req.Header.Set("X-Domain-Name", "default")
 				resp, err = scclient.Do(req)
 				Expect(err).To(BeNil())
@@ -480,8 +489,9 @@ var _ = Describe("MicroService Api Test", func() {
 				Expect(resp.StatusCode).To(Equal(http.StatusOK))
 
 				//verify Delete
+				<-time.After(time.Second)
 				url = strings.Replace(GETTAGS, ":serviceId", serviceId, 1)
-				req, _ = http.NewRequest(GET, SCURL+url+"?noCache=1", nil)
+				req, _ = http.NewRequest(GET, SCURL+url, nil)
 				req.Header.Set("X-Domain-Name", "default")
 				req.Header.Set("X-ConsumerId", serviceId)
 				resp, _ = scclient.Do(req)
diff --git a/integration/tags_test.go b/integration/tags_test.go
index 78b3a50..ba96a7c 100644
--- a/integration/tags_test.go
+++ b/integration/tags_test.go
@@ -159,8 +159,9 @@ var _ = Describe("MicroService Api Test", func() {
 				Expect(resp.StatusCode).To(Equal(http.StatusOK))
 
 				//Get Tags
+				<-time.After(time.Second)
 				url = strings.Replace(GETTAGS, ":serviceId", serviceId, 1)
-				req, _ = http.NewRequest(GET, SCURL+url+"?noCache=1", nil)
+				req, _ = http.NewRequest(GET, SCURL+url, nil)
 				req.Header.Set("X-Domain-Name", "default")
 				req.Header.Set("X-ConsumerId", serviceId)
 				resp, _ = scclient.Do(req)
@@ -215,9 +216,10 @@ var _ = Describe("MicroService Api Test", func() {
 				Expect(resp.StatusCode).To(Equal(http.StatusOK))
 
 				//Update Tags
+				<-time.After(time.Second)
 				url = strings.Replace(UPDATETAG, ":serviceId", serviceId, 1)
 				url = strings.Replace(url, ":key", "testkey", 1)
-				req, _ = http.NewRequest(UPDATE, SCURL+url+"?value=newValue&noCache=1", nil)
+				req, _ = http.NewRequest(UPDATE, SCURL+url+"?value=newValue", nil)
 				req.Header.Set("X-Domain-Name", "default")
 				resp, err = scclient.Do(req)
 				Expect(err).To(BeNil())
@@ -227,7 +229,7 @@ var _ = Describe("MicroService Api Test", func() {
 				//Verify the Tags
 				<-time.After(time.Second)
 				url = strings.Replace(GETTAGS, ":serviceId", serviceId, 1)
-				req, _ = http.NewRequest(GET, SCURL+url+"?noCache=1", nil)
+				req, _ = http.NewRequest(GET, SCURL+url, nil)
 				req.Header.Set("X-Domain-Name", "default")
 				req.Header.Set("X-ConsumerId", serviceId)
 				resp, _ = scclient.Do(req)
@@ -266,9 +268,10 @@ var _ = Describe("MicroService Api Test", func() {
 				Expect(resp.StatusCode).To(Equal(http.StatusOK))
 
 				//Update Tags
+				<-time.After(time.Second)
 				url = strings.Replace(UPDATETAG, ":serviceId", serviceId, 1)
 				url = strings.Replace(url, ":key", "unknownkey", 1)
-				req, _ = http.NewRequest(UPDATE, SCURL+url+"?value=newValue&noCache=1", nil)
+				req, _ = http.NewRequest(UPDATE, SCURL+url+"?value=newValue", nil)
 				req.Header.Set("X-Domain-Name", "default")
 				resp, err = scclient.Do(req)
 				Expect(err).To(BeNil())
@@ -311,9 +314,10 @@ var _ = Describe("MicroService Api Test", func() {
 				Expect(resp.StatusCode).To(Equal(http.StatusOK))
 
 				//Delete the tag
+				<-time.After(time.Second)
 				url = strings.Replace(DELETETAG, ":serviceId", serviceId, 1)
 				url = strings.Replace(url, ":key", "testkey", 1)
-				req, _ = http.NewRequest(DELETE, SCURL+url+"?noCache=1", nil)
+				req, _ = http.NewRequest(DELETE, SCURL+url, nil)
 				req.Header.Set("X-Domain-Name", "default")
 				resp, err = scclient.Do(req)
 				Expect(err).To(BeNil())
@@ -323,7 +327,7 @@ var _ = Describe("MicroService Api Test", func() {
 				//verify Delete
 				<-time.After(time.Second)
 				url = strings.Replace(GETTAGS, ":serviceId", serviceId, 1)
-				req, _ = http.NewRequest(GET, SCURL+url+"?noCache=1", nil)
+				req, _ = http.NewRequest(GET, SCURL+url, nil)
 				req.Header.Set("X-Domain-Name", "default")
 				req.Header.Set("X-ConsumerId", serviceId)
 				resp, _ = scclient.Do(req)
@@ -353,9 +357,10 @@ var _ = Describe("MicroService Api Test", func() {
 				Expect(resp.StatusCode).To(Equal(http.StatusOK))
 
 				//Delete the tag
+				<-time.After(time.Second)
 				url = strings.Replace(DELETETAG, ":serviceId", serviceId, 1)
 				url = strings.Replace(url, ":key", "unknowTag", 1)
-				req, _ = http.NewRequest(DELETE, SCURL+url+"?noCache=1", nil)
+				req, _ = http.NewRequest(DELETE, SCURL+url, nil)
 				req.Header.Set("X-Domain-Name", "default")
 				resp, err = scclient.Do(req)
 				Expect(err).To(BeNil())
@@ -363,8 +368,9 @@ var _ = Describe("MicroService Api Test", func() {
 				Expect(resp.StatusCode).To(Equal(http.StatusBadRequest))
 
 				//verify Non-deleted of exsiting tag
+				<-time.After(time.Second)
 				url = strings.Replace(GETTAGS, ":serviceId", serviceId, 1)
-				req, _ = http.NewRequest(GET, SCURL+url+"?noCache=1", nil)
+				req, _ = http.NewRequest(GET, SCURL+url, nil)
 				req.Header.Set("X-Domain-Name", "default")
 				req.Header.Set("X-ConsumerId", serviceId)
 				resp, _ = scclient.Do(req)
diff --git a/main.go b/main.go
index 3d7ac97..efbcaac 100644
--- a/main.go
+++ b/main.go
@@ -16,20 +16,12 @@
  */
 package main
 
-// plugins
+import _ "github.com/apache/incubator-servicecomb-service-center/server/init"
 import _ "github.com/apache/incubator-servicecomb-service-center/server/bootstrap"
 import (
-	"github.com/apache/incubator-servicecomb-service-center/pkg/util"
 	"github.com/apache/incubator-servicecomb-service-center/server"
-	"github.com/apache/incubator-servicecomb-service-center/server/core/backend"
 )
 
 func main() {
 	server.Run()
-
-	util.GoCloseAndWait()
-
-	backend.Registry().Close()
-
-	util.Logger().Warn("service center exited", nil)
 }
diff --git a/pkg/chain/callback_test.go b/pkg/chain/callback_test.go
new file mode 100644
index 0000000..db452a6
--- /dev/null
+++ b/pkg/chain/callback_test.go
@@ -0,0 +1,56 @@
+/*
+ * 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 chain
+
+import (
+	"errors"
+	"testing"
+)
+
+func TestCallback_Invoke(t *testing.T) {
+	cb := &Callback{Func: func(r Result) {
+		if r.Args[0].(bool) != r.OK {
+			t.Fatalf("TestCallback_Invoke failed")
+		}
+		if !r.OK && r.Err == nil {
+			t.Fatalf("TestCallback_Invoke failed")
+		}
+	}, Async: false}
+	cb.Success(true)
+	cb.Fail(errors.New("error"), false)
+	cb.Invoke(Result{OK: true, Args: []interface{}{true}})
+
+	ch := make(chan struct{})
+	cb = &Callback{Func: func(r Result) {
+		if r.Args[0].(bool) != r.OK {
+			t.Fatalf("TestCallback_Invoke failed")
+		}
+		if !r.OK && r.Err == nil {
+			t.Fatalf("TestCallback_Invoke failed")
+		}
+		ch <- struct{}{}
+	}, Async: true}
+	cb.Success(true)
+	cb.Fail(errors.New("error"), false)
+	cb.Invoke(Result{OK: true, Args: []interface{}{true}})
+	<-ch
+
+	cb = &Callback{}
+	cb.Success(true)
+	cb.Fail(errors.New("error"), false)
+	cb.Invoke(Result{OK: true, Args: []interface{}{true}})
+}
diff --git a/pkg/chain/chain_test.go b/pkg/chain/chain_test.go
index 1bec164..d053a81 100644
--- a/pkg/chain/chain_test.go
+++ b/pkg/chain/chain_test.go
@@ -14,11 +14,11 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package chain_test
+package chain
 
 import (
 	"context"
-	"github.com/apache/incubator-servicecomb-service-center/pkg/chain"
+	"errors"
 	"github.com/apache/incubator-servicecomb-service-center/pkg/util"
 	"testing"
 )
@@ -30,14 +30,14 @@ const (
 
 func init() {
 	for i := 0; i < count; i++ {
-		chain.RegisterHandler("_bench_handlers_", &handler{})
+		RegisterHandler("_bench_handlers_", &handler{})
 	}
 }
 
 type handler struct {
 }
 
-func (h *handler) Handle(i *chain.Invocation) {
+func (h *handler) Handle(i *Invocation) {
 	i.Next()
 }
 
@@ -50,9 +50,9 @@ func syncFunc(i int) {
 
 func BenchmarkInvocationOption(b *testing.B) {
 	var (
-		op   chain.InvocationOp
-		f    = func(r chain.Result) {}
-		opts = []chain.InvocationOption{chain.WithFunc(f), chain.WithAsyncFunc(f)}
+		op   InvocationOp
+		f    = func(r Result) {}
+		opts = []InvocationOption{WithFunc(f), WithAsyncFunc(f)}
 	)
 	b.RunParallel(func(pb *testing.PB) {
 		for pb.Next() {
@@ -68,14 +68,14 @@ func BenchmarkInvocationOption(b *testing.B) {
 func BenchmarkChain(b *testing.B) {
 	var (
 		ctx = util.NewStringContext(context.Background())
-		f   = func(r chain.Result) {}
+		f   = func(r Result) {}
 	)
 
 	b.N = times
 	b.ResetTimer()
 	b.RunParallel(func(pb *testing.PB) {
 		for pb.Next() {
-			inv := chain.NewInvocation(ctx, chain.NewChain("_bench_chain_", chain.Handlers("_bench_handlers_")))
+			inv := NewInvocation(ctx, NewChain("_bench_chain_", Handlers("_bench_handlers_")))
 			inv.Invoke(f)
 		}
 	})
@@ -94,3 +94,135 @@ func BenchmarkSync(b *testing.B) {
 	b.ReportAllocs()
 	// 1000000	        46.9 ns/op	       0 B/op	       0 allocs/op
 }
+
+type mockHandler struct {
+}
+
+func (h *mockHandler) Handle(i *Invocation) {
+	x := i.Context().Value("x").(int)
+	switch x {
+	case 1:
+		i.Success(x)
+	case 2:
+		i.Fail(errors.New("error"), x)
+	case 3:
+		i.Next(WithFunc(func(r Result) {
+			i.WithContext("x", x*x)
+		}))
+	case 4:
+		i.Next(WithAsyncFunc(func(r Result) {
+			i.WithContext("x", x*x)
+			i.Context().Value("ch").(chan struct{}) <- struct{}{}
+		}))
+	case 5:
+		panic(errors.New("error"))
+	case 6:
+		i.Next(WithFunc(func(r Result) {
+			panic(errors.New("error"))
+		}))
+	case 7:
+		i.Next(WithAsyncFunc(func(r Result) {
+			panic(errors.New("error"))
+		}))
+	default:
+		i.WithContext("x", x-1)
+		i.Next()
+	}
+}
+
+func TestChain_Next(t *testing.T) {
+	h := &mockHandler{}
+	hs := Handlers("test")
+	hs = []Handler{h, h, h}
+
+	x := 0
+	ch := NewChain("test", hs)
+	if ch.Name() != "test" {
+		t.Fatalf("TestChain_Next")
+	}
+	i := NewInvocation(context.Background(), ch)
+	i.WithContext("x", x)
+	i.Invoke(func(r Result) {
+		if !r.OK || i.Context().Value("x").(int) != -len(hs) {
+			t.Fatalf("TestChain_Next")
+		}
+	})
+
+	x = 1
+	ch = NewChain("test", hs)
+	i = NewInvocation(context.Background(), ch)
+	i.WithContext("x", x)
+	i.Invoke(func(r Result) {
+		if !r.OK || r.Args[0].(int) != x {
+			t.Fatalf("TestChain_Next")
+		}
+	})
+
+	x = 2
+	ch = NewChain("test", hs)
+	i = NewInvocation(context.Background(), ch)
+	i.WithContext("x", x)
+	i.Invoke(func(r Result) {
+		if r.OK || r.Args[0].(int) != x {
+			t.Fatalf("TestChain_Next")
+		}
+	})
+
+	x = 3
+	ch = NewChain("test", hs)
+	i = NewInvocation(context.Background(), ch)
+	i.WithContext("x", x)
+	i.Invoke(func(r Result) {
+		if !r.OK || i.Context().Value("x").(int) != x {
+			t.Fatalf("TestChain_Next")
+		}
+	})
+	if i.Context().Value("x").(int) != x*x {
+		t.Fatalf("TestChain_Next")
+	}
+
+	x = 4
+	ch = NewChain("test", hs)
+	i = NewInvocation(context.Background(), ch)
+	i.WithContext("x", x)
+	i.WithContext("ch", make(chan struct{}))
+	i.Invoke(func(r Result) {
+		if !r.OK || i.Context().Value("x").(int) != x {
+			t.Fatalf("TestChain_Next")
+		}
+	})
+	<-i.Context().Value("ch").(chan struct{})
+	if i.Context().Value("x").(int) != x*x {
+		t.Fatalf("TestChain_Next")
+	}
+
+	x = 5
+	ch = NewChain("test", hs)
+	i = NewInvocation(context.Background(), ch)
+	i.WithContext("x", x)
+	i.Invoke(func(r Result) {
+		if r.OK || r.Err == nil {
+			t.Fatalf("TestChain_Next")
+		}
+	})
+
+	x = 6
+	ch = NewChain("test", hs)
+	i = NewInvocation(context.Background(), ch)
+	i.WithContext("x", x)
+	i.Invoke(func(r Result) {
+		if !r.OK || r.Err != nil {
+			t.Fatalf("TestChain_Next")
+		}
+	})
+
+	x = 7
+	ch = NewChain("test", hs)
+	i = NewInvocation(context.Background(), ch)
+	i.WithContext("x", x)
+	i.Invoke(func(r Result) {
+		if !r.OK || r.Err != nil {
+			t.Fatalf("TestChain_Next")
+		}
+	})
+}
diff --git a/pkg/chain/handler.go b/pkg/chain/handler.go
index 372e8c7..5efdab7 100644
--- a/pkg/chain/handler.go
+++ b/pkg/chain/handler.go
@@ -36,8 +36,8 @@ func RegisterHandler(catalog string, h Handler) {
 	handlers = append(handlers, h)
 	handlersMap[catalog] = handlers
 
-	t := util.ReflectObject(h)
-	util.Logger().Infof("register handler[%s] %s/%s", catalog, t.Type.PkgPath(), t.Type.Name())
+	t := util.Reflect(h)
+	util.Logger().Infof("register handler[%s] %s", catalog, t.Name())
 }
 
 func Handlers(catalog string) []Handler {
diff --git a/pkg/chain/invocation.go b/pkg/chain/invocation.go
index 5e5276c..bb024ca 100644
--- a/pkg/chain/invocation.go
+++ b/pkg/chain/invocation.go
@@ -55,6 +55,12 @@ func (i *Invocation) WithContext(key string, val interface{}) *Invocation {
 	return i
 }
 
+// Next is the method to go next step in handler chain
+// WithFunc and WithAsyncFunc options can add customize callbacks in chain
+// and the callbacks seq like below
+// i.Success/Fail() -> CB1 ---> CB3 ----------> END           goroutine 0
+//                          \-> CB2(async) \                  goroutine 1
+//                                          \-> CB4(async)    goroutine 1 or 2
 func (i *Invocation) Next(opts ...InvocationOption) {
 	var op InvocationOp
 	for _, opt := range opts {
@@ -75,11 +81,6 @@ func (i *Invocation) setCallback(f CallbackFunc, async bool) {
 		i.Async = async
 		return
 	}
-
-	// the callbacks seq like below
-	// i.Success() -> CB1 ---> CB3 ----------> END           goroutine 0
-	//                     \-> CB2(async) \                  goroutine 1
-	//                                     \-> CB4(async)    goroutine 1 or 2
 	cb := i.Func
 	i.Func = func(r Result) {
 		cb(r)
diff --git a/pkg/etcdsync/etcdsync_suite_test.go b/pkg/etcdsync/etcdsync_suite_test.go
index 7af14fa..c5ded54 100644
--- a/pkg/etcdsync/etcdsync_suite_test.go
+++ b/pkg/etcdsync/etcdsync_suite_test.go
@@ -14,22 +14,19 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package etcdsync_test
+package etcdsync
 
 import (
-	_ "github.com/apache/incubator-servicecomb-service-center/server/plugin/infra/registry/embededetcd"
+	"fmt"
 	_ "github.com/apache/incubator-servicecomb-service-center/server/plugin/infra/registry/etcd"
+	_ "github.com/apache/incubator-servicecomb-service-center/server/plugin/infra/tracing/buildin"
 	. "github.com/onsi/ginkgo"
 	. "github.com/onsi/gomega"
-)
-import (
-	"fmt"
-	"github.com/apache/incubator-servicecomb-service-center/pkg/etcdsync"
 	"testing"
 )
 
 func init() {
-	etcdsync.IsDebug = true
+	IsDebug = true
 }
 
 func TestEtcdsync(t *testing.T) {
@@ -41,11 +38,11 @@ func BenchmarkLock(b *testing.B) {
 	var g = 0
 	b.RunParallel(func(pb *testing.PB) {
 		for pb.Next() {
-			lock, _ := etcdsync.Lock("/test", true)
-			defer lock.Unlock()
+			lock, _ := Lock("/test", true)
 			//do something
 			g += 1
 			fmt.Println(g)
+			lock.Unlock()
 		}
 	})
 	fmt.Println("Parallel:", b.N)
diff --git a/pkg/etcdsync/mutex.go b/pkg/etcdsync/mutex.go
index d1a35b9..cc7fc2d 100644
--- a/pkg/etcdsync/mutex.go
+++ b/pkg/etcdsync/mutex.go
@@ -50,10 +50,11 @@ var (
 	globalMap = make(map[string]*DLockFactory)
 	globalMux sync.Mutex
 	IsDebug   bool
-	hostname  string = util.HostName()
-	pid       int    = os.Getpid()
+	hostname  = util.HostName()
+	pid       = os.Getpid()
 )
 
+// lock will not be release automatically if ttl = 0
 func NewLockFactory(key string, ttl int64) *DLockFactory {
 	if len(key) == 0 {
 		return nil
@@ -81,86 +82,92 @@ func (m *DLockFactory) NewDLock(wait bool) (l *DLock, err error) {
 	for try := 1; try <= DEFAULT_RETRY_TIMES; try++ {
 		err = l.Lock(wait)
 		if err == nil {
-			return l, nil
+			return
 		}
 
 		if !wait {
-			l, err = nil, nil
 			break
 		}
-
-		if try <= DEFAULT_RETRY_TIMES {
-			util.Logger().Warnf(err, "Try to lock key %s again, id=%s", m.key, l.id)
-		} else {
-			util.Logger().Errorf(err, "Lock key %s failed, id=%s", m.key, l.id)
-		}
 	}
+	// failed
+	util.Logger().Errorf(err, "Lock key %s failed, id=%s", m.key, l.id)
+	l = nil
+
 	if !IsDebug {
 		m.mutex.Unlock()
 	}
-	return l, err
+	return
 }
 
 func (m *DLock) ID() string {
 	return m.id
 }
 
-func (m *DLock) Lock(wait bool) error {
+func (m *DLock) Lock(wait bool) (err error) {
 	opts := []registry.PluginOpOption{
 		registry.WithStrKey(m.builder.key),
 		registry.WithStrValue(m.id)}
 
-	for {
-		util.Logger().Infof("Trying to create a lock: key=%s, id=%s", m.builder.key, m.id)
+	util.Logger().Infof("Trying to create a lock: key=%s, id=%s", m.builder.key, m.id)
 
-		putOpts := opts
-		if m.builder.ttl > 0 {
-			leaseID, err := backend.Registry().LeaseGrant(m.builder.ctx, m.builder.ttl)
-			if err != nil {
-				return err
-			}
-			putOpts = append(opts, registry.WithLease(leaseID))
-		}
-		success, err := backend.Registry().PutNoOverride(m.builder.ctx, putOpts...)
-		if err == nil && success {
-			util.Logger().Infof("Create Lock OK, key=%s, id=%s", m.builder.key, m.id)
-			return nil
+	var leaseID int64
+	putOpts := opts
+	if m.builder.ttl > 0 {
+		leaseID, err = backend.Registry().LeaseGrant(m.builder.ctx, m.builder.ttl)
+		if err != nil {
+			return err
 		}
+		putOpts = append(opts, registry.WithLease(leaseID))
+	}
+	success, err := backend.Registry().PutNoOverride(m.builder.ctx, putOpts...)
+	if err == nil && success {
+		util.Logger().Infof("Create Lock OK, key=%s, id=%s", m.builder.key, m.id)
+		return nil
+	}
 
-		if !wait {
-			return fmt.Errorf("Key %s is locked by id=%s", m.builder.key, m.id)
-		}
+	if leaseID > 0 {
+		backend.Registry().LeaseRevoke(m.builder.ctx, leaseID)
+	}
+
+	if m.builder.ttl == 0 || !wait {
+		return fmt.Errorf("Key %s is locked by id=%s", m.builder.key, m.id)
+	}
 
-		util.Logger().Warnf(err, "Key %s is locked, waiting for other node releases it, id=%s", m.builder.key, m.id)
-
-		ctx, cancel := context.WithTimeout(m.builder.ctx, DEFAULT_LOCK_TTL*time.Second)
-		util.Go(func(context.Context) {
-			defer cancel()
-			err := backend.Registry().Watch(ctx,
-				registry.WithStrKey(m.builder.key),
-				registry.WithWatchCallback(
-					func(message string, evt *registry.PluginResponse) error {
-						if evt != nil && evt.Action == registry.Delete {
-							// break this for-loop, and try to create the node again.
-							return fmt.Errorf("Lock released")
-						}
-						return nil
-					}))
-			if err != nil {
-				util.Logger().Warnf(nil, "%s, key=%s, id=%s", err.Error(), m.builder.key, m.id)
-			}
-		})
-		select {
-		case <-ctx.Done():
-			continue // 可以重新尝试获取锁
-		case <-m.builder.ctx.Done():
-			cancel()
-			return m.builder.ctx.Err() // 机制错误,不应该超时的
+	util.Logger().Warnf(err, "Key %s is locked, waiting for other node releases it, id=%s", m.builder.key, m.id)
+
+	ctx, cancel := context.WithTimeout(m.builder.ctx, time.Duration(m.builder.ttl)*time.Second)
+	util.Go(func(context.Context) {
+		defer cancel()
+		err := backend.Registry().Watch(ctx,
+			registry.WithStrKey(m.builder.key),
+			registry.WithWatchCallback(
+				func(message string, evt *registry.PluginResponse) error {
+					if evt != nil && evt.Action == registry.Delete {
+						// break this for-loop, and try to create the node again.
+						return fmt.Errorf("Lock released")
+					}
+					return nil
+				}))
+		if err != nil {
+			util.Logger().Warnf(nil, "%s, key=%s, id=%s", err.Error(), m.builder.key, m.id)
 		}
+	})
+	select {
+	case <-ctx.Done():
+		return ctx.Err() // 可以重新尝试获取锁
+	case <-m.builder.ctx.Done():
+		cancel()
+		return m.builder.ctx.Err() // 机制错误,不应该超时的
 	}
 }
 
 func (m *DLock) Unlock() (err error) {
+	defer func() {
+		if !IsDebug {
+			m.builder.mutex.Unlock()
+		}
+	}()
+
 	opts := []registry.PluginOpOption{
 		registry.DEL,
 		registry.WithStrKey(m.builder.key)}
@@ -168,24 +175,15 @@ func (m *DLock) Unlock() (err error) {
 	for i := 1; i <= DEFAULT_RETRY_TIMES; i++ {
 		_, err = backend.Registry().Do(m.builder.ctx, opts...)
 		if err == nil {
-			if !IsDebug {
-				m.builder.mutex.Unlock()
-			}
 			util.Logger().Infof("Delete lock OK, key=%s, id=%s", m.builder.key, m.id)
 			return nil
 		}
-		util.Logger().Errorf(err, "Delete lock falied, key=%s, id=%s", m.builder.key, m.id)
+		util.Logger().Errorf(err, "Delete lock failed, key=%s, id=%s", m.builder.key, m.id)
 		e, ok := err.(client.Error)
 		if ok && e.Code == client.ErrorCodeKeyNotFound {
-			if !IsDebug {
-				m.builder.mutex.Unlock()
-			}
 			return nil
 		}
 	}
-	if !IsDebug {
-		m.builder.mutex.Unlock()
-	}
 	return err
 }
 
diff --git a/pkg/etcdsync/mutex_test.go b/pkg/etcdsync/mutex_test.go
index 23a333b..e602388 100644
--- a/pkg/etcdsync/mutex_test.go
+++ b/pkg/etcdsync/mutex_test.go
@@ -14,36 +14,51 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package etcdsync_test
+package etcdsync
 
 import (
-	. "github.com/apache/incubator-servicecomb-service-center/pkg/etcdsync"
-
 	"fmt"
 	. "github.com/onsi/ginkgo"
+	. "github.com/onsi/gomega"
 )
 
 var _ = Describe("Mutex", func() {
 	Context("normal", func() {
 		It("TestLockTimeout", func() {
-			m1 := NewLockFactory("key1", 10)
-			m2 := NewLockFactory("key1", 2)
-			m1.NewDLock(true)
+			m1 := NewLockFactory("key1", 5)
+			m2 := NewLockFactory("key1", 1)
+			l1, err := m1.NewDLock(true)
+			Expect(l1).ToNot(BeNil())
+			Expect(err).To(BeNil())
+
 			fmt.Println("UT===================m1 locked")
 			ch := make(chan bool)
 			go func() {
-				l, _ := m2.NewDLock(true)
-				fmt.Println("UT===================m2 locked")
-				l.Unlock()
+				l2, err := m2.NewDLock(false)
+				Expect(l2).To(BeNil())
+				Expect(err).ToNot(BeNil())
+				fmt.Println("UT===================m2 try failed")
+
+				l2, err = m2.NewDLock(true) // 1s * 3
+				Expect(l2).To(BeNil())
+				Expect(err).ToNot(BeNil())
+				fmt.Println("UT===================m2 timed out")
 				ch <- true
 			}()
 			<-ch
-			fmt.Println("lock m1 timeout")
+
 			m3 := NewLockFactory("key1", 2)
-			l, _ := m3.NewDLock(true)
+			l3, err := m3.NewDLock(true)
+			Expect(l3).ToNot(BeNil())
+			Expect(err).To(BeNil())
+
 			fmt.Println("UT===================m3 locked")
-			l.Unlock()
+			err = l3.Unlock()
+			Expect(err).To(BeNil())
 
+			err = l1.Unlock()
+			Expect(err).To(BeNil())
+			fmt.Println("UT===================m1 unlocked")
 		})
 	})
 })
diff --git a/pkg/rest/client.go b/pkg/rest/client.go
index 6fc15d1..56f7423 100644
--- a/pkg/rest/client.go
+++ b/pkg/rest/client.go
@@ -146,7 +146,9 @@ func (client *HttpClient) httpDo(method string, url string, headers map[string]s
 			var ok bool = false
 			bodyBytes, ok = body.([]byte)
 			if !ok {
-				util.Logger().Errorf(nil, "invalid body type '%s'(%s), body must type of byte array if Content-Type specified.", reflect.TypeOf(body), headers[HEADER_CONTENT_TYPE])
+				util.Logger().Errorf(nil,
+					"invalid body type '%s'(%s), body must type of byte array if Content-Type specified.",
+					reflect.TypeOf(body), headers[HEADER_CONTENT_TYPE])
 				return status, result
 			}
 		}
diff --git a/pkg/rest/listener.go b/pkg/rest/listener.go
index 0f119a5..a5f8467 100644
--- a/pkg/rest/listener.go
+++ b/pkg/rest/listener.go
@@ -22,28 +22,27 @@ import (
 	"syscall"
 )
 
-type restListener struct {
+type TcpListener struct {
 	net.Listener
 	stopCh chan error
 	closed bool
 	server *Server
 }
 
-func newRestListener(l net.Listener, srv *Server) (el *restListener) {
-	el = &restListener{
+func NewTcpListener(l net.Listener, srv *Server) (el *TcpListener) {
+	el = &TcpListener{
 		Listener: l,
 		stopCh:   make(chan error),
 		server:   srv,
 	}
 	go func() {
 		<-el.stopCh
-		el.closed = true
 		el.stopCh <- el.Listener.Close()
 	}()
 	return
 }
 
-func (rl *restListener) Accept() (c net.Conn, err error) {
+func (rl *TcpListener) Accept() (c net.Conn, err error) {
 	tc, err := rl.Listener.(*net.TCPListener).AcceptTCP()
 	if err != nil {
 		return
@@ -63,15 +62,16 @@ func (rl *restListener) Accept() (c net.Conn, err error) {
 	return
 }
 
-func (rl *restListener) Close() error {
+func (rl *TcpListener) Close() error {
 	if rl.closed {
 		return syscall.EINVAL
 	}
+	rl.closed = true
 	rl.stopCh <- nil
 	return <-rl.stopCh
 }
 
-func (rl *restListener) File() *os.File {
+func (rl *TcpListener) File() *os.File {
 	tl := rl.Listener.(*net.TCPListener)
 	fl, _ := tl.File()
 	return fl
diff --git a/pkg/rest/roa.go b/pkg/rest/roa.go
index 63d01c3..f217fad 100644
--- a/pkg/rest/roa.go
+++ b/pkg/rest/roa.go
@@ -40,31 +40,31 @@ func initROAServerHandler() *ROAServerHandler {
 }
 
 // servant must be an pointer to service object
-func RegisterServent(servant interface{}) {
+func RegisterServant(servant interface{}) {
 	val := reflect.ValueOf(servant)
 	ind := reflect.Indirect(val)
 	typ := ind.Type()
-	name := typ.PkgPath() + "." + typ.Name()
+	name := util.FileLastName(typ.PkgPath() + "." + typ.Name())
 	if val.Kind() != reflect.Ptr {
-		util.Logger().Errorf(nil, "<rest.RegisterServent> cannot use non-ptr servant struct `%s`", name)
+		util.Logger().Errorf(nil, "<rest.RegisterServant> cannot use non-ptr servant struct `%s`", name)
 		return
 	}
 
 	urlPatternFunc := val.MethodByName("URLPatterns")
 	if !urlPatternFunc.IsValid() {
-		util.Logger().Errorf(nil, "<rest.RegisterServent> no 'URLPatterns' function in servant struct `%s`", name)
+		util.Logger().Errorf(nil, "<rest.RegisterServant> no 'URLPatterns' function in servant struct `%s`", name)
 		return
 	}
 
 	vals := urlPatternFunc.Call([]reflect.Value{})
 	if len(vals) <= 0 {
-		util.Logger().Errorf(nil, "<rest.RegisterServent> call 'URLPatterns' function failed in servant struct `%s`", name)
+		util.Logger().Errorf(nil, "<rest.RegisterServant> call 'URLPatterns' function failed in servant struct `%s`", name)
 		return
 	}
 
 	val0 := vals[0]
 	if !val.CanInterface() {
-		util.Logger().Errorf(nil, "<rest.RegisterServent> result of 'URLPatterns' function not interface type in servant struct `%s`", name)
+		util.Logger().Errorf(nil, "<rest.RegisterServant> result of 'URLPatterns' function not interface type in servant struct `%s`", name)
 		return
 	}
 
@@ -77,7 +77,7 @@ func RegisterServent(servant interface{}) {
 			}
 		}
 	} else {
-		util.Logger().Errorf(nil, "<rest.RegisterServent> result of 'URLPatterns' function not []*Route type in servant struct `%s`", name)
+		util.Logger().Errorf(nil, "<rest.RegisterServant> result of 'URLPatterns' function not []*Route type in servant struct `%s`", name)
 	}
 }
 
diff --git a/pkg/rest/server.go b/pkg/rest/server.go
index 4dd7e86..06bbcaa 100644
--- a/pkg/rest/server.go
+++ b/pkg/rest/server.go
@@ -89,9 +89,9 @@ type Server struct {
 	KeepaliveTimeout time.Duration
 	GraceTimeout     time.Duration
 
-	registerListener net.Listener
-	restListener     net.Listener
-	innerListener    *restListener
+	Listener    net.Listener
+	netListener net.Listener
+	tcpListener *TcpListener
 
 	conns int64
 	wg    sync.WaitGroup
@@ -104,7 +104,7 @@ func (srv *Server) Serve() (err error) {
 	}()
 	defer util.RecoverAndReport()
 	srv.state = serverStateRunning
-	err = srv.Server.Serve(srv.restListener)
+	err = srv.Server.Serve(srv.Listener)
 	util.Logger().Debugf("server serve failed(%s)", err)
 	srv.wg.Wait()
 	return
@@ -136,12 +136,12 @@ func (srv *Server) Listen() error {
 		addr = ":http"
 	}
 
-	l, err := srv.getListener(addr)
+	l, err := srv.getOrCreateListener(addr)
 	if err != nil {
 		return err
 	}
 
-	srv.restListener = newRestListener(l, srv)
+	srv.Listener = NewTcpListener(l, srv)
 	grace.RegisterFiles(addr, srv.File())
 	return nil
 }
@@ -152,13 +152,13 @@ func (srv *Server) ListenTLS() error {
 		addr = ":https"
 	}
 
-	l, err := srv.getListener(addr)
+	l, err := srv.getOrCreateListener(addr)
 	if err != nil {
 		return err
 	}
 
-	srv.innerListener = newRestListener(l, srv)
-	srv.restListener = tls.NewListener(srv.innerListener, srv.TLSConfig)
+	srv.tcpListener = NewTcpListener(l, srv)
+	srv.Listener = tls.NewListener(srv.tcpListener, srv.TLSConfig)
 	grace.RegisterFiles(addr, srv.File())
 	return nil
 }
@@ -181,7 +181,7 @@ func (srv *Server) ListenAndServeTLS(certFile, keyFile string) (err error) {
 		}
 	}
 	if srv.TLSConfig.NextProtos == nil {
-		srv.TLSConfig.NextProtos = []string{"http/1.1"}
+		srv.TLSConfig.NextProtos = []string{"h2", "http/1.1"}
 	}
 
 	err = srv.ListenTLS()
@@ -191,22 +191,19 @@ func (srv *Server) ListenAndServeTLS(certFile, keyFile string) (err error) {
 	return srv.Serve()
 }
 
+// RegisterListener register the instance created outside by net.Listen() in server
 func (srv *Server) RegisterListener(l net.Listener) {
-	srv.registerListener = l
+	srv.netListener = l
 }
 
-func (srv *Server) getListener(addr string) (l net.Listener, err error) {
-	l = srv.registerListener
-	if l != nil {
-		return
-	}
+func (srv *Server) getOrCreateListener(addr string) (l net.Listener, err error) {
 	if !grace.IsFork() {
-		return net.Listen(srv.Network, addr)
+		return srv.newListener(addr)
 	}
 
 	offset := grace.ExtraFileOrder(addr)
 	if offset < 0 {
-		return net.Listen(srv.Network, addr)
+		return srv.newListener(addr)
 	}
 
 	f := os.NewFile(uintptr(3+offset), "")
@@ -218,13 +215,21 @@ func (srv *Server) getListener(addr string) (l net.Listener, err error) {
 	return
 }
 
+func (srv *Server) newListener(addr string) (net.Listener, error) {
+	l := srv.netListener
+	if l != nil {
+		return l, nil
+	}
+	return net.Listen(srv.Network, addr)
+}
+
 func (srv *Server) Shutdown() {
 	if srv.state != serverStateRunning {
 		return
 	}
 
 	srv.state = serverStateTerminating
-	err := srv.restListener.Close()
+	err := srv.Listener.Close()
 	if err != nil {
 		util.Logger().Errorf(err, "server listener close failed")
 	}
@@ -264,10 +269,10 @@ func (srv *Server) gracefulStop(d time.Duration) {
 }
 
 func (srv *Server) File() *os.File {
-	switch srv.restListener.(type) {
-	case *restListener:
-		return srv.restListener.(*restListener).File()
+	switch srv.Listener.(type) {
+	case *TcpListener:
+		return srv.Listener.(*TcpListener).File()
 	default:
-		return srv.innerListener.File()
+		return srv.tcpListener.File()
 	}
 }
diff --git a/pkg/rpc/grpc.go b/pkg/rpc/grpc.go
index bc47949..eaa9ec7 100644
--- a/pkg/rpc/grpc.go
+++ b/pkg/rpc/grpc.go
@@ -30,7 +30,7 @@ func RegisterService(f RegisterServiceFunc) {
 	registerFuncs = append(registerFuncs, f)
 }
 
-func RegisterServer(s *grpc.Server) {
+func RegisterGRpcServer(s *grpc.Server) {
 	for _, f := range registerFuncs {
 		f(s)
 	}
diff --git a/pkg/async/executor.go b/pkg/task/executor.go
similarity index 99%
copy from pkg/async/executor.go
copy to pkg/task/executor.go
index d8845e3..6e24285 100644
--- a/pkg/async/executor.go
+++ b/pkg/task/executor.go
@@ -14,7 +14,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package async
+package task
 
 import (
 	"errors"
diff --git a/pkg/async/async.go b/pkg/task/service.go
similarity index 93%
rename from pkg/async/async.go
rename to pkg/task/service.go
index 87cc07b..10dad53 100644
--- a/pkg/async/async.go
+++ b/pkg/task/service.go
@@ -14,12 +14,12 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package async
+package task
 
 import "sync"
 
 var (
-	service *TaskService
+	service TaskService
 	once    sync.Once
 )
 
@@ -27,7 +27,7 @@ func init() {
 	service = NewTaskService()
 }
 
-func Service() *TaskService {
+func Service() TaskService {
 	once.Do(service.Run)
 	return service
 }
diff --git a/pkg/async/service.go b/pkg/task/service_async.go
similarity index 85%
rename from pkg/async/service.go
rename to pkg/task/service_async.go
index 3551e56..53f8007 100644
--- a/pkg/async/service.go
+++ b/pkg/task/service_async.go
@@ -14,7 +14,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package async
+package task
 
 import (
 	"errors"
@@ -35,11 +35,10 @@ const (
 
 type executorWithTTL struct {
 	*Executor
-
 	TTL int64
 }
 
-type TaskService struct {
+type AsyncTaskService struct {
 	executors map[string]*executorWithTTL
 	goroutine *util.GoRoutine
 	lock      sync.RWMutex
@@ -47,7 +46,7 @@ type TaskService struct {
 	isClose   bool
 }
 
-func (lat *TaskService) getOrNewExecutor(task Task) (s *Executor, isNew bool) {
+func (lat *AsyncTaskService) getOrNewExecutor(task Task) (s *Executor, isNew bool) {
 	var (
 		ok  bool
 		key = task.Key()
@@ -73,7 +72,7 @@ func (lat *TaskService) getOrNewExecutor(task Task) (s *Executor, isNew bool) {
 	return se.Executor, isNew
 }
 
-func (lat *TaskService) Add(ctx context.Context, task Task) error {
+func (lat *AsyncTaskService) Add(ctx context.Context, task Task) error {
 	if task == nil || ctx == nil {
 		return errors.New("invalid parameters")
 	}
@@ -86,14 +85,14 @@ func (lat *TaskService) Add(ctx context.Context, task Task) error {
 	return s.AddTask(task)
 }
 
-func (lat *TaskService) removeExecutor(key string) {
+func (lat *AsyncTaskService) removeExecutor(key string) {
 	if s, ok := lat.executors[key]; ok {
 		s.Close()
 		delete(lat.executors, key)
 	}
 }
 
-func (lat *TaskService) LatestHandled(key string) (Task, error) {
+func (lat *AsyncTaskService) LatestHandled(key string) (Task, error) {
 	lat.lock.RLock()
 	s, ok := lat.executors[key]
 	lat.lock.RUnlock()
@@ -103,7 +102,7 @@ func (lat *TaskService) LatestHandled(key string) (Task, error) {
 	return s.latestTask, nil
 }
 
-func (lat *TaskService) daemon(ctx context.Context) {
+func (lat *AsyncTaskService) daemon(ctx context.Context) {
 	util.SafeCloseChan(lat.ready)
 	ticker := time.NewTicker(removeExecutorInterval)
 	max := 0
@@ -112,7 +111,7 @@ func (lat *TaskService) daemon(ctx context.Context) {
 	for {
 		select {
 		case <-ctx.Done():
-			util.Logger().Debugf("daemon thread exited for TaskService is stopped")
+			util.Logger().Debugf("daemon thread exited for AsyncTaskService stopped")
 			return
 		case <-timer.C:
 			lat.lock.RLock()
@@ -166,7 +165,7 @@ func (lat *TaskService) daemon(ctx context.Context) {
 	}
 }
 
-func (lat *TaskService) Run() {
+func (lat *AsyncTaskService) Run() {
 	lat.lock.Lock()
 	if !lat.isClose {
 		lat.lock.Unlock()
@@ -177,7 +176,7 @@ func (lat *TaskService) Run() {
 	lat.goroutine.Do(lat.daemon)
 }
 
-func (lat *TaskService) Stop() {
+func (lat *AsyncTaskService) Stop() {
 	lat.lock.Lock()
 	if lat.isClose {
 		lat.lock.Unlock()
@@ -196,11 +195,11 @@ func (lat *TaskService) Stop() {
 	util.SafeCloseChan(lat.ready)
 }
 
-func (lat *TaskService) Ready() <-chan struct{} {
+func (lat *AsyncTaskService) Ready() <-chan struct{} {
 	return lat.ready
 }
 
-func (lat *TaskService) renew() {
+func (lat *AsyncTaskService) renew() {
 	newExecutor := make(map[string]*executorWithTTL)
 	for k, e := range lat.executors {
 		newExecutor[k] = e
@@ -208,12 +207,12 @@ func (lat *TaskService) renew() {
 	lat.executors = newExecutor
 }
 
-func NewTaskService() (lat *TaskService) {
-	lat = &TaskService{
+func NewTaskService() TaskService {
+	lat := &AsyncTaskService{
 		goroutine: util.NewGo(context.Background()),
 		ready:     make(chan struct{}),
 		isClose:   true,
 	}
 	lat.renew()
-	return
+	return lat
 }
diff --git a/pkg/async/async_test.go b/pkg/task/service_test.go
similarity index 99%
rename from pkg/async/async_test.go
rename to pkg/task/service_test.go
index 77593d2..6b4bfe6 100644
--- a/pkg/async/async_test.go
+++ b/pkg/task/service_test.go
@@ -14,7 +14,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package async
+package task
 
 import (
 	"testing"
@@ -58,6 +58,7 @@ func (tt *testTask) Do(ctx context.Context) error {
 func TestBaseAsyncTasker_AddTask(t *testing.T) {
 	at := NewTaskService()
 	at.Run()
+	<-at.Ready()
 	defer at.Stop()
 
 	ctx, cancel := context.WithCancel(context.Background())
diff --git a/pkg/async/task.go b/pkg/task/task.go
similarity index 84%
copy from pkg/async/task.go
copy to pkg/task/task.go
index f4a884f..bff9211 100644
--- a/pkg/async/task.go
+++ b/pkg/task/task.go
@@ -14,7 +14,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package async
+package task
 
 import "golang.org/x/net/context"
 
@@ -23,3 +23,12 @@ type Task interface {
 	Do(ctx context.Context) error
 	Err() error
 }
+
+type TaskService interface {
+	Add(ctx context.Context, task Task) error
+	LatestHandled(key string) (Task, error)
+
+	Run()
+	Stop()
+	Ready() <-chan struct{}
+}
diff --git a/pkg/tlsutil/tlsutil.go b/pkg/tlsutil/tlsutil.go
index 063b30f..b50acd1 100644
--- a/pkg/tlsutil/tlsutil.go
+++ b/pkg/tlsutil/tlsutil.go
@@ -98,8 +98,6 @@ func LoadTLSCertificate(certFile, keyFile, plainPassphase string) (tlsCert []tls
 	if x509.IsEncryptedPEMBlock(keyBlock) {
 		plainPassphaseBytes := util.StringToBytesWithNoCopy(plainPassphase)
 		keyData, err := x509.DecryptPEMBlock(keyBlock, plainPassphaseBytes)
-		util.ClearStringMemory(&plainPassphase)
-		util.ClearByteMemory(plainPassphaseBytes)
 		if err != nil {
 			util.Logger().Errorf(err, "decrypt key file %s failed.", keyFile)
 			return nil, err
@@ -186,10 +184,12 @@ func GetServerTLSConfig(opts ...SSLConfigOption) (tlsConfig *tls.Config, err err
 		ClientCAs:                pool,
 		Certificates:             certs,
 		CipherSuites:             cfg.CipherSuites,
+		CurvePreferences:         []tls.CurveID{tls.X25519, tls.CurveP256},
 		PreferServerCipherSuites: true,
 		ClientAuth:               clientAuthMode,
 		MinVersion:               cfg.MinVersion,
 		MaxVersion:               cfg.MaxVersion,
+		NextProtos:               []string{"h2", "http/1.1"},
 	}
 
 	return tlsConfig, nil
diff --git a/pkg/tlsutil/tlsutil_test.go b/pkg/tlsutil/tlsutil_test.go
index 4a51f74..fb2dc7d 100644
--- a/pkg/tlsutil/tlsutil_test.go
+++ b/pkg/tlsutil/tlsutil_test.go
@@ -22,6 +22,8 @@ import (
 	"testing"
 )
 
+const sslRoot = "../../examples/service_center/ssl/"
+
 func TestParseDefaultSSLCipherSuites(t *testing.T) {
 	c := ParseDefaultSSLCipherSuites("")
 	if c != nil {
@@ -42,7 +44,6 @@ func TestParseDefaultSSLCipherSuites(t *testing.T) {
 }
 
 func TestGetServerTLSConfig(t *testing.T) {
-	sslRoot := "../../etc/ssl/"
 	pw, _ := ioutil.ReadFile(sslRoot + "cert_pwd")
 	opts := append(DefaultServerTLSOptions(),
 		WithVerifyPeer(true),
@@ -78,7 +79,6 @@ func TestGetServerTLSConfig(t *testing.T) {
 }
 
 func TestGetClientTLSConfig(t *testing.T) {
-	sslRoot := "../../etc/ssl/"
 	pw, _ := ioutil.ReadFile(sslRoot + "cert_pwd")
 	opts := append(DefaultServerTLSOptions(),
 		WithVerifyPeer(true),
diff --git a/pkg/util/context.go b/pkg/util/context.go
index 565cf69..79fb515 100644
--- a/pkg/util/context.go
+++ b/pkg/util/context.go
@@ -44,7 +44,10 @@ func (c *StringContext) Value(key interface{}) interface{} {
 	if !ok {
 		return c.parentCtx.Value(key)
 	}
-	v, _ := c.kv.Get(k)
+	v, ok := c.kv.Get(k)
+	if !ok {
+		return c.parentCtx.Value(key)
+	}
 	return v
 }
 
@@ -57,7 +60,7 @@ func NewStringContext(ctx context.Context) *StringContext {
 	if !ok {
 		strCtx = &StringContext{
 			parentCtx: ctx,
-			kv:        NewConcurrentMap(10),
+			kv:        NewConcurrentMap(0),
 		}
 	}
 	return strCtx
@@ -74,13 +77,13 @@ func CloneContext(ctx context.Context) context.Context {
 	if !ok {
 		return &StringContext{
 			parentCtx: ctx,
-			kv:        NewConcurrentMap(10),
+			kv:        NewConcurrentMap(0),
 		}
 	}
 
 	strCtx := &StringContext{
 		parentCtx: ctx,
-		kv:        NewConcurrentMap(old.kv.Size()),
+		kv:        NewConcurrentMap(0),
 	}
 
 	old.kv.ForEach(func(item MapItem) bool {
diff --git a/pkg/util/context_test.go b/pkg/util/context_test.go
new file mode 100644
index 0000000..4c079b9
--- /dev/null
+++ b/pkg/util/context_test.go
@@ -0,0 +1,77 @@
+/*
+ * 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"
+)
+
+func TestSetContext(t *testing.T) {
+	ctx := context.WithValue(context.Background(), "z", "z")
+	ctx = context.WithValue(ctx, 1, 1)
+	ctx = SetDomainProject(ctx, "x", "y")
+	if ParseDomainProject(ctx) != "x/y" {
+		t.Fatalf("TestSetContext failed")
+	}
+	if ctx.Value("z") != "z" {
+		t.Fatalf("TestSetContext failed")
+	}
+	if ctx.Value(1) != 1 {
+		t.Fatalf("TestSetContext failed")
+	}
+
+	nctx := CloneContext(ctx)
+	if nctx == ctx {
+		t.Fatalf("TestSetContext failed")
+	}
+	if ParseDomainProject(nctx) != "x/y" {
+		t.Fatalf("TestSetContext failed")
+	}
+	nctx = SetDomainProject(nctx, "x", "x")
+	if ParseDomainProject(ctx) != "x/y" {
+		t.Fatalf("TestSetContext failed")
+	}
+	if ParseDomainProject(nctx) != "x/x" {
+		t.Fatalf("TestSetContext failed")
+	}
+	if nctx.Value("z") != "z" {
+		t.Fatalf("TestSetContext failed")
+	}
+	if nctx.Value(1) != 1 {
+		t.Fatalf("TestSetContext failed")
+	}
+
+	ctx = SetTargetDomainProject(ctx, "x", "x")
+	if ParseTargetDomainProject(ctx) != "x/x" {
+		t.Fatalf("TestSetContext failed")
+	}
+	if ctx.Value("z") != "z" {
+		t.Fatalf("TestSetContext failed")
+	}
+	if ctx.Value(1) != 1 {
+		t.Fatalf("TestSetContext failed")
+	}
+
+	req, _ := http.NewRequest(http.MethodGet, "http://127.0.0.1:30100", nil)
+	ctx = req.Context()
+	SetRequestContext(req, "x", "y")
+	if req.Context() == ctx {
+		t.Fatalf("TestSetContext failed")
+	}
+}
diff --git a/pkg/util/goroutines.go b/pkg/util/goroutines.go
index 74689f3..03d3d43 100644
--- a/pkg/util/goroutines.go
+++ b/pkg/util/goroutines.go
@@ -22,26 +22,50 @@ import (
 	"time"
 )
 
-var GlobalPoolConfig = &PoolConfig{
-	Concurrent:  1000,
-	WaitTimeout: time.Second,
-	IdleTimeout: 60 * time.Second,
+var GlobalPoolConfig = PoolConfigure()
+
+var defaultGo *GoRoutine
+
+func init() {
+	defaultGo = NewGo(context.Background())
 }
 
 type PoolConfig struct {
 	Concurrent  int
-	WaitTimeout time.Duration
 	IdleTimeout time.Duration
 }
 
+func (c *PoolConfig) Workers(max int) *PoolConfig {
+	c.Concurrent = max
+	return c
+}
+
+func (c *PoolConfig) Idle(time time.Duration) *PoolConfig {
+	c.IdleTimeout = time
+	return c
+}
+
+func PoolConfigure() *PoolConfig {
+	return &PoolConfig{
+		Concurrent:  1000,
+		IdleTimeout: 60 * time.Second,
+	}
+}
+
 type GoRoutine struct {
-	ctx        context.Context
-	cancel     context.CancelFunc
-	wg         sync.WaitGroup
-	mux        sync.RWMutex
-	closed     bool
-	task       chan func(ctx context.Context)
-	concurrent chan struct{}
+	Cfg *PoolConfig
+
+	// job context
+	ctx    context.Context
+	cancel context.CancelFunc
+	// pending is the chan to block GoRoutine.Do() when go pool is full
+	pending chan func(ctx context.Context)
+	// workers is the counter of the worker
+	workers chan struct{}
+
+	mux    sync.RWMutex
+	wg     sync.WaitGroup
+	closed bool
 }
 
 func (g *GoRoutine) execute(f func(ctx context.Context)) {
@@ -49,22 +73,22 @@ func (g *GoRoutine) execute(f func(ctx context.Context)) {
 	f(g.ctx)
 }
 
-func (g *GoRoutine) Do(f func(context.Context)) {
+func (g *GoRoutine) Do(f func(context.Context)) *GoRoutine {
 	defer RecoverAndReport()
 	select {
-	case g.task <- f:
-		return
-	case g.concurrent <- struct{}{}:
+	case g.pending <- f:
+	case g.workers <- struct{}{}:
+		g.wg.Add(1)
 		go g.loop(f)
 	}
+	return g
 }
 
 func (g *GoRoutine) loop(f func(context.Context)) {
-	g.wg.Add(1)
 	defer g.wg.Done()
-	defer func() { <-g.concurrent }()
+	defer func() { <-g.workers }()
 
-	timer := time.NewTimer(GlobalPoolConfig.IdleTimeout)
+	timer := time.NewTimer(g.Cfg.IdleTimeout)
 	defer timer.Stop()
 	for {
 		g.execute(f)
@@ -72,16 +96,17 @@ func (g *GoRoutine) loop(f func(context.Context)) {
 		select {
 		case <-timer.C:
 			return
-		case f = <-g.task:
+		case f = <-g.pending:
 			if f == nil {
 				return
 			}
-			ResetTimer(timer, GlobalPoolConfig.IdleTimeout)
+			ResetTimer(timer, g.Cfg.IdleTimeout)
 		}
 	}
 }
 
-func (g *GoRoutine) Close(wait bool) {
+// Close will call context.Cancel(), so all goroutines maybe exit when job does not complete
+func (g *GoRoutine) Close(grace bool) {
 	g.mux.Lock()
 	if g.closed {
 		g.mux.Unlock()
@@ -90,22 +115,43 @@ func (g *GoRoutine) Close(wait bool) {
 	g.closed = true
 	g.mux.Unlock()
 
-	close(g.task)
-	close(g.concurrent)
+	close(g.pending)
+	close(g.workers)
 	g.cancel()
-	if wait {
-		g.Wait()
+	if grace {
+		g.wg.Wait()
 	}
 }
 
-func (g *GoRoutine) Wait() {
+// Done will wait for all goroutines complete the jobs and then close the pool
+func (g *GoRoutine) Done() {
+	g.mux.Lock()
+	if g.closed {
+		g.mux.Unlock()
+		return
+	}
+	g.closed = true
+	g.mux.Unlock()
+
+	close(g.pending)
+	close(g.workers)
 	g.wg.Wait()
 }
 
-var defaultGo *GoRoutine
-
-func init() {
-	defaultGo = NewGo(context.Background())
+func NewGo(ctx context.Context, cfgs ...*PoolConfig) *GoRoutine {
+	ctx, cancel := context.WithCancel(ctx)
+	if len(cfgs) == 0 {
+		cfgs = append(cfgs, GlobalPoolConfig)
+	}
+	cfg := cfgs[0]
+	gr := &GoRoutine{
+		Cfg:     cfg,
+		ctx:     ctx,
+		cancel:  cancel,
+		pending: make(chan func(context.Context)),
+		workers: make(chan struct{}, cfg.Concurrent),
+	}
+	return gr
 }
 
 func Go(f func(context.Context)) {
@@ -116,14 +162,3 @@ func GoCloseAndWait() {
 	defaultGo.Close(true)
 	Logger().Debugf("all goroutines exited")
 }
-
-func NewGo(ctx context.Context) *GoRoutine {
-	ctx, cancel := context.WithCancel(ctx)
-	gr := &GoRoutine{
-		ctx:        ctx,
-		cancel:     cancel,
-		task:       make(chan func(context.Context)),
-		concurrent: make(chan struct{}, GlobalPoolConfig.Concurrent),
-	}
-	return gr
-}
diff --git a/pkg/util/goroutines_test.go b/pkg/util/goroutines_test.go
index fe14e19..997ca95 100644
--- a/pkg/util/goroutines_test.go
+++ b/pkg/util/goroutines_test.go
@@ -55,12 +55,10 @@ func TestGoRoutine_Do(t *testing.T) {
 }
 
 func TestGoRoutine_Wait(t *testing.T) {
-	GlobalPoolConfig.IdleTimeout = time.Second
-
 	var mux sync.Mutex
 	MAX := 10
 	resultArr := make([]int, 0, MAX)
-	test := NewGo(context.Background())
+	test := NewGo(context.Background(), PoolConfigure().Idle(time.Second).Workers(5))
 	for i := 0; i < MAX; i++ {
 		test.Do(func(ctx context.Context) {
 			select {
@@ -75,14 +73,14 @@ func TestGoRoutine_Wait(t *testing.T) {
 	}
 	<-time.After(time.Second)
 	fmt.Println("waiting for all goroutines finish.")
-	test.Wait()
+	test.Done()
 	fmt.Println(resultArr)
 	if len(resultArr) != MAX {
 		t.Fatalf("fail to wait all goroutines finish. expected %d to %d", len(resultArr), MAX)
 	}
 }
 
-func TestGoRoutine_Close(t *testing.T) {
+func TestGoRoutine_Exception1(t *testing.T) {
 	test := NewGo(context.Background())
 	test.Do(func(ctx context.Context) {
 		select {
@@ -98,11 +96,11 @@ func TestGoRoutine_Close(t *testing.T) {
 			t.Fatalf("can not execute f after closed.")
 		}
 	})
-	test.Wait()
+	test.Done()
 	test.Close(true)
 }
 
-func TestGo(t *testing.T) {
+func TestGoRoutine_Exception2(t *testing.T) {
 	Go(func(ctx context.Context) {
 		for {
 			select {
diff --git a/pkg/util/log.go b/pkg/util/log.go
index bc82a89..38d8051 100644
--- a/pkg/util/log.go
+++ b/pkg/util/log.go
@@ -31,10 +31,10 @@ import (
 
 //log var
 var (
-	LOGGER             lager.Logger
-	defaultLagerConfig = stlager.DefaultConfig()
-	loggerConfig       LoggerConfig
-	logLevel           lager.LogLevel
+	globalLogger     lager.Logger
+	globalConfig     LoggerConfig
+	innerLagerConfig = stlager.DefaultConfig()
+	logLevel         lager.LogLevel
 
 	loggers     map[string]lager.Logger
 	loggerNames map[string]string
@@ -57,8 +57,8 @@ type LoggerConfig struct {
 func init() {
 	loggers = make(map[string]lager.Logger, 10)
 	loggerNames = make(map[string]string, 10)
-	// make LOGGER do not be nil, new a stdout logger
-	LOGGER = NewLogger(fromLagerConfig(defaultLagerConfig))
+	// make globalLogger do not be nil, new a stdout for it
+	globalLogger = NewLogger(fromLagerConfig(innerLagerConfig))
 }
 
 func fromLagerConfig(c *stlager.Config) LoggerConfig {
@@ -89,14 +89,12 @@ func NewLogger(cfg LoggerConfig) lager.Logger {
 }
 
 func InitGlobalLogger(cfg LoggerConfig) {
-	// renew the global logger
+	// renew the global globalLogger
 	if len(cfg.LoggerLevel) == 0 {
-		cfg.LoggerLevel = defaultLagerConfig.LoggerLevel
+		cfg.LoggerLevel = innerLagerConfig.LoggerLevel
 	}
-	loggerConfig = cfg
-	LOGGER = NewLogger(cfg)
-	// log rotate
-	RunLogDirRotate(cfg)
+	globalConfig = cfg
+	globalLogger = NewLogger(cfg)
 	// recreate the deleted log file
 	switch strings.ToUpper(cfg.LoggerLevel) {
 	case "INFO":
@@ -110,12 +108,15 @@ func InitGlobalLogger(cfg LoggerConfig) {
 	default:
 		logLevel = lager.DEBUG
 	}
+
+	RunLogDirRotate(cfg)
+
 	monitorLogFile()
 }
 
 func Logger() lager.Logger {
 	if len(loggerNames) == 0 {
-		return LOGGER
+		return globalLogger
 	}
 	funcFullName := getCalleeFuncName()
 
@@ -141,19 +142,19 @@ func Logger() lager.Logger {
 		loggersMux.Lock()
 		logger, ok = loggers[logFile]
 		if !ok {
-			cfg := loggerConfig
+			cfg := globalConfig
 			if len(cfg.LoggerFile) != 0 {
 				cfg.LoggerFile = filepath.Join(filepath.Dir(cfg.LoggerFile), logFile+".log")
 			}
 			logger = NewLogger(cfg)
 			loggers[logFile] = logger
-			LOGGER.Warnf(nil, "match %s, new logger %s for %s", prefix, logFile, funcFullName)
+			logger.Warnf(nil, "match %s, new globalLogger %s for %s", prefix, logFile, funcFullName)
 		}
 		loggersMux.Unlock()
 		return logger
 	}
 
-	return LOGGER
+	return globalLogger
 }
 
 func getCalleeFuncName() string {
@@ -188,7 +189,7 @@ func CustomLogger(pkgOrFunc, fileName string) {
 }
 
 func monitorLogFile() {
-	if len(loggerConfig.LoggerFile) == 0 {
+	if len(globalConfig.LoggerFile) == 0 {
 		return
 	}
 	Go(func(ctx context.Context) {
@@ -198,18 +199,20 @@ func monitorLogFile() {
 				return
 			case <-time.After(time.Minute):
 				Logger().Debug(fmt.Sprintf("Check log file at %s", time.Now()))
+				if PathExist(globalConfig.LoggerFile) {
+					continue
+				}
 
-				if !PathExist(loggerConfig.LoggerFile) {
-					file, err := os.OpenFile(loggerConfig.LoggerFile, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0600)
-					if err != nil {
-						Logger().Errorf(err, "Create log file failed.")
-						return
-					}
-					// TODO Here will lead to file handle leak
-					sink := lager.NewReconfigurableSink(lager.NewWriterSink("file", file, lager.DEBUG), logLevel)
-					Logger().RegisterSink(sink)
-					Logger().Errorf(nil, "log file is removed, create again.")
+				file, err := os.OpenFile(globalConfig.LoggerFile, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0600)
+				if err != nil {
+					Logger().Errorf(err, "Create log file failed.")
+					continue
 				}
+
+				// TODO Here will lead to file handle leak
+				sink := lager.NewReconfigurableSink(lager.NewWriterSink("file", file, lager.DEBUG), logLevel)
+				Logger().RegisterSink(sink)
+				Logger().Errorf(nil, "log file is removed, create again.")
 			}
 		}
 	})
diff --git a/pkg/util/log_test.go b/pkg/util/log_test.go
index d513e22..9d0bdbf 100644
--- a/pkg/util/log_test.go
+++ b/pkg/util/log_test.go
@@ -18,29 +18,42 @@ package util
 
 import (
 	"testing"
+	"time"
 )
 
 func TestLogger(t *testing.T) {
+	InitGlobalLogger(LoggerConfig{
+		LoggerLevel: "DEBUG",
+	})
+
 	CustomLogger("Not Exist", "testDefaultLOGGER")
 	l := Logger()
-	if l != LOGGER {
-		t.Fatalf("should equal to LOGGER")
+	if l != globalLogger {
+		t.Fatalf("should equal to globalLogger")
 	}
 	CustomLogger("TestLogger", "testFuncName")
 	l = Logger()
-	if l == LOGGER || l == nil {
+	if l == globalLogger || l == nil {
 		t.Fatalf("should create a new instance for 'TestLogger'")
 	}
 	s := Logger()
 	if l != s {
-		t.Fatalf("should be the same logger")
+		t.Fatalf("should be the same globalLogger")
 	}
 	CustomLogger("github.com/apache/incubator-servicecomb-service-center/pkg/util", "testPkgPath")
 	l = Logger()
-	if l == LOGGER || l == nil {
+	if l == globalLogger || l == nil {
 		t.Fatalf("should create a new instance for 'util'")
 	}
 	// l.Infof("OK")
+
+	LogDebugOrWarnf(time.Now().Add(-time.Second), "x")
+	LogNilOrWarnf(time.Now().Add(-time.Second), "x")
+	LogInfoOrWarnf(time.Now().Add(-time.Second), "x")
+
+	LogDebugOrWarnf(time.Now(), "x")
+	LogNilOrWarnf(time.Now(), "x")
+	LogInfoOrWarnf(time.Now(), "x")
 }
 
 func BenchmarkLogger(b *testing.B) {
diff --git a/pkg/util/logrotate.go b/pkg/util/logrotate.go
index 919ee72..138677d 100644
--- a/pkg/util/logrotate.go
+++ b/pkg/util/logrotate.go
@@ -295,6 +295,9 @@ func CopyFile(srcFile, destFile string) error {
 }
 
 func RunLogDirRotate(cfg LoggerConfig) {
+	if len(cfg.LoggerFile) == 0 {
+		return
+	}
 	Go(func(ctx context.Context) {
 		for {
 			select {
diff --git a/pkg/util/logrotate_test.go b/pkg/util/logrotate_test.go
index 407baa5..4ffad2f 100644
--- a/pkg/util/logrotate_test.go
+++ b/pkg/util/logrotate_test.go
@@ -17,6 +17,7 @@
 package util
 
 import (
+	"os"
 	"testing"
 )
 
@@ -25,4 +26,20 @@ func TestLogRotate(t *testing.T) {
 	if s != "./sc.log" {
 		t.Fatal("pathReplacer failed", s)
 	}
+
+	LogRotate("../../etc", 1, 1)
+
+	LogRotateFile("../../etc/conf/app.conf", 1, 1)
+
+	if err := compressFile(
+		"../../etc/conf/app.conf",
+		"app",
+		false); err != nil {
+		t.Fatal("TestLogRotate failed", err)
+	}
+
+	os.Chmod("../../etc/conf/app.conf.zip", 0640)
+	if err := removeFile("../../etc/conf/app.conf.zip"); err != nil {
+		t.Fatal("TestLogRotate failed", err)
+	}
 }
diff --git a/pkg/util/net.go b/pkg/util/net.go
index 6082506..c304933 100644
--- a/pkg/util/net.go
+++ b/pkg/util/net.go
@@ -38,18 +38,6 @@ func GetIPFromContext(ctx context.Context) string {
 	return v
 }
 
-func UrlEncode(keys map[string]string) string {
-	l := len(keys)
-	if l == 0 {
-		return ""
-	}
-	arr := make([]string, 0, l)
-	for k, v := range keys {
-		arr = append(arr, url.QueryEscape(k)+"="+url.QueryEscape(v))
-	}
-	return StringJoin(arr, "&")
-}
-
 func ParseEndpoint(ep string) (string, error) {
 	u, err := url.Parse(ep)
 	if err != nil {
@@ -79,11 +67,7 @@ func GetRealIP(r *http.Request) string {
 			return ip
 		}
 	}
-	addrs := strings.Split(r.RemoteAddr, ":")
-	if len(addrs) > 0 {
-		return addrs[0]
-	}
-	return ""
+	return strings.Split(r.RemoteAddr, ":")[0]
 }
 
 func InetNtoIP(ipnr uint32) net.IP {
diff --git a/pkg/util/net_test.go b/pkg/util/net_test.go
index 0116f3d..a5dbfdf 100644
--- a/pkg/util/net_test.go
+++ b/pkg/util/net_test.go
@@ -16,7 +16,10 @@
  */
 package util
 
-import "testing"
+import (
+	"net/http"
+	"testing"
+)
 
 const (
 	ip1 = "127.0.0.1"       // 2130706433
@@ -94,3 +97,45 @@ func TestParseEndpoint(t *testing.T) {
 		t.Fatalf("ParseEndpoint(\"rest://[fe80::f816:3eff:fe17:c38b%%25eht0]:30100/?a=b\") failed, err = %s, ep = %s", err, ep)
 	}
 }
+
+func TestParseRequestURL(t *testing.T) {
+	req, _ := http.NewRequest(http.MethodGet, "https://127.0.0.1:30100/x/?a=b&c=d#e", nil)
+	url := ParseRequestURL(req)
+	if url != "https://127.0.0.1:30100/x/?a=b&c=d#e" {
+		t.Fatalf("TestParseRequestURL failed")
+	}
+	req.URL.Scheme = ""
+	req.Host = "127.0.0.1:30100"
+	req.RequestURI = "/x/?a=b&c=d#e"
+	url = ParseRequestURL(req)
+	if url != "http://127.0.0.1:30100/x/?a=b&c=d#e" {
+		t.Fatalf("TestParseRequestURL failed")
+	}
+}
+
+func TestGetRealIP(t *testing.T) {
+	req, _ := http.NewRequest(http.MethodGet, "https://127.0.0.1:30100/x/?a=b&c=d#e", nil)
+	req.RemoteAddr = "127.0.0.1:30100"
+	ip := GetRealIP(req)
+	if ip != "127.0.0.1" {
+		t.Fatalf("TestGetRealIP failed")
+	}
+
+	req.Header.Set("X-Real-Ip", "255.255.255.255")
+	ip = GetRealIP(req)
+	if ip != "127.0.0.1" {
+		t.Fatalf("TestGetRealIP failed")
+	}
+
+	req.Header.Set("X-Real-Ip", "4.4.4.4")
+	ip = GetRealIP(req)
+	if ip != "4.4.4.4" {
+		t.Fatalf("TestGetRealIP failed")
+	}
+
+	req.Header.Set("X-Forwarded-For", "1.1.1.1, 2.2.2.2, 3.3.3.3")
+	ip = GetRealIP(req)
+	if ip != "1.1.1.1" {
+		t.Fatalf("TestGetRealIP failed")
+	}
+}
diff --git a/pkg/util/reflect.go b/pkg/util/reflect.go
index 695a7b9..73a5466 100644
--- a/pkg/util/reflect.go
+++ b/pkg/util/reflect.go
@@ -18,6 +18,8 @@ package util
 
 import (
 	"reflect"
+	"runtime"
+	"strings"
 	"sync"
 	"unsafe"
 )
@@ -26,25 +28,34 @@ var (
 	reflector      *Reflector
 	sliceTypeSize  = uint64(reflect.TypeOf(reflect.SliceHeader{}).Size())
 	stringTypeSize = uint64(reflect.TypeOf(reflect.StringHeader{}).Size())
+	unknown        = new(reflectObject)
 )
 
 func init() {
 	reflector = &Reflector{
-		types: make(map[*uintptr]reflectObject, 100),
+		types: make(map[*uintptr]*reflectObject),
 	}
 }
 
 type reflectObject struct {
-	Type   reflect.Type
+	// full name
+	FullName string
+	Type     reflect.Type
+	// if type is not struct, Fields is nil
 	Fields []reflect.StructField
 }
 
+// Name returns a short name of the object type
+func (o *reflectObject) Name() string {
+	return FileLastName(o.FullName)
+}
+
 type Reflector struct {
-	types map[*uintptr]reflectObject
+	types map[*uintptr]*reflectObject
 	mux   sync.RWMutex
 }
 
-func (r *Reflector) Load(obj interface{}) reflectObject {
+func (r *Reflector) Load(obj interface{}) *reflectObject {
 	r.mux.RLock()
 	itab := *(**uintptr)(unsafe.Pointer(&obj))
 	t, ok := r.types[itab]
@@ -60,38 +71,48 @@ func (r *Reflector) Load(obj interface{}) reflectObject {
 		return t
 	}
 
+	t = new(reflectObject)
 	v := reflect.ValueOf(obj)
 	if !v.IsValid() {
 		r.mux.Unlock()
-		return reflectObject{}
+		return unknown
 	}
 	switch v.Kind() {
 	case reflect.Ptr:
-		if v.IsNil() {
-			r.mux.Unlock()
-			return reflectObject{}
-		}
 		fallthrough
 	case reflect.Interface:
 		r.mux.Unlock()
-		return r.Load(v.Elem().Interface())
-	default:
-		t = reflectObject{
-			Type: reflect.TypeOf(obj),
+		if v.IsNil() {
+			return unknown
 		}
-	}
-
-	if v.Kind() != reflect.Struct {
-		r.mux.Unlock()
-		return t
-	}
+		e := v.Elem()
+		if e.CanInterface() {
+			return r.Load(e.Interface())
+		}
+		return unknown
+	default:
+		t.Type = reflect.TypeOf(obj)
 
-	fl := t.Type.NumField()
-	if fl > 0 {
-		t.Fields = make([]reflect.StructField, fl)
-		for i := 0; i < fl; i++ {
-			f := t.Type.Field(i)
-			t.Fields[i] = f
+		switch v.Kind() {
+		case reflect.Func:
+			r.mux.Unlock()
+			f := runtime.FuncForPC(v.Pointer())
+			if f == nil {
+				return unknown
+			}
+			t.FullName = f.Name()
+			return t
+		case reflect.Struct:
+			if fl := t.Type.NumField(); fl > 0 {
+				t.Fields = make([]reflect.StructField, fl)
+				for i := 0; i < fl; i++ {
+					f := t.Type.Field(i)
+					t.Fields[i] = f
+				}
+			}
+			fallthrough
+		default:
+			t.FullName = t.Type.PkgPath() + "." + t.Type.Name()
 		}
 	}
 	r.types[itab] = t
@@ -99,7 +120,7 @@ func (r *Reflector) Load(obj interface{}) reflectObject {
 	return t
 }
 
-func ReflectObject(obj interface{}) (s reflectObject) {
+func Reflect(obj interface{}) *reflectObject {
 	return reflector.Load(obj)
 }
 
@@ -181,3 +202,18 @@ func isValueType(kind reflect.Kind) bool {
 		return false
 	}
 }
+
+func FormatFuncName(f string) string {
+	i := strings.LastIndex(f, "/")
+	j := strings.Index(f[i+1:], ".")
+	if j < 1 {
+		return "???"
+	}
+	_, fun := f[:i+j+1], f[i+j+2:]
+	i = strings.LastIndex(fun, ".")
+	return fun[i+1:]
+}
+
+func FuncName(f interface{}) string {
+	return Reflect(f).Name()
+}
diff --git a/pkg/util/reflect_test.go b/pkg/util/reflect_test.go
index f5a4c51..d6706ca 100644
--- a/pkg/util/reflect_test.go
+++ b/pkg/util/reflect_test.go
@@ -18,7 +18,6 @@ package util
 
 import (
 	"fmt"
-	"reflect"
 	"testing"
 )
 
@@ -34,47 +33,69 @@ type testField struct {
 
 func TestLoadStruct(t *testing.T) {
 	obj1 := testStru{}
-	v := ReflectObject(obj1)
+	v := Reflect(obj1)
 	if v.Type.String() != "util.testStru" {
 		t.Fatalf("TestLoadStruct failed, %s != 'testStru'", v.Type.String())
 	}
 	if len(v.Fields) != 4 {
 		t.Fatalf("TestLoadStruct failed, wrong count of fields")
 	}
+	if v.Name() != "pkg/util.testStru" || v.FullName != "github.com/apache/incubator-servicecomb-service-center/pkg/util.testStru" {
+		t.Fatalf("TestLoadStruct failed")
+	}
 	for _, f := range v.Fields {
 		fmt.Println(f.Name, f.Type.String())
 	}
 
 	obj2 := testStru{}
-	v = ReflectObject(obj2)
-	v = ReflectObject(&obj2)
-	v = ReflectObject(nil)
+	v1 := Reflect(obj2)
+	if v1.FullName != v.FullName {
+		t.Fatalf("TestLoadStruct failed")
+	}
+	v2 := Reflect(&obj2)
+	if v2.FullName != v.FullName {
+		t.Fatalf("TestLoadStruct failed")
+	}
+	v = Reflect(nil)
+	if v.FullName != "" {
+		t.Fatalf("TestLoadStruct failed")
+	}
+
+	if FuncName(TestLoadStruct) != "pkg/util.TestLoadStruct" {
+		t.Fatalf("TestLoadStruct failed")
+	}
+	f := TestLoadStruct
+	if FormatFuncName(FuncName(f)) != "TestLoadStruct" {
+		t.Fatalf("TestLoadStruct failed")
+	}
+}
+
+func TestSizeof(t *testing.T) {
+	s := &S{}
+	if Sizeof(s) != 8+152 {
+		t.Fatalf("TestSizeof failed")
+	}
 }
 
 func BenchmarkLoadStruct(b *testing.B) {
 	b.RunParallel(func(pb *testing.PB) {
 		for pb.Next() {
-			ReflectObject(testStru{})
+			Reflect(testStru{})
 		}
 	})
 	b.ReportAllocs()
 	// 20000000	        86.9 ns/op	      32 B/op	       1 allocs/op
 }
 
-var (
-	sliceSize  = uint64(reflect.TypeOf(reflect.SliceHeader{}).Size())
-	stringSize = uint64(reflect.TypeOf(reflect.StringHeader{}).Size())
-)
-
 type S struct {
-	a  int
-	s  string
-	p  *S
-	m  map[int32]uint32
-	u  []uint64
-	ua [8]uint64
-	ch chan int
-	i  interface{}
+	a  int              // 8
+	s  string           // 16
+	p  *S               // 8
+	m  map[int32]uint32 // 8
+	u  []uint64         // 24
+	ua [8]uint64        // 64
+	ch chan int         // 8
+	i  interface{}      // 16
 }
 
 func BenchmarkSizeof(b *testing.B) {
diff --git a/pkg/util/util.go b/pkg/util/util.go
index 5c3b3f0..d1dfd0c 100644
--- a/pkg/util/util.go
+++ b/pkg/util/util.go
@@ -17,11 +17,8 @@
 package util
 
 import (
-	"bytes"
-	"encoding/gob"
 	"fmt"
 	"os"
-	"reflect"
 	"runtime"
 	"runtime/debug"
 	"strings"
@@ -29,45 +26,11 @@ import (
 	"unsafe"
 )
 
-func MinInt(x, y int) int {
-	if x <= y {
-		return x
-	} else {
-		return y
-	}
-}
-
-func ClearStringMemory(src *string) {
-	p := (*struct {
-		ptr uintptr
-		len int
-	})(unsafe.Pointer(src))
-
-	l := MinInt(p.len, 32)
-	ptr := p.ptr
-	for idx := 0; idx < l; idx = idx + 1 {
-		b := (*byte)(unsafe.Pointer(ptr))
-		*b = 0
-		ptr += 1
-	}
-}
-
-func ClearByteMemory(src []byte) {
-	l := MinInt(len(src), 32)
-	for idx := 0; idx < l; idx = idx + 1 {
-		src[idx] = 0
+func SafeCloseChan(c chan struct{}) {
+	if c == nil {
+		return
 	}
-}
 
-func DeepCopy(dst, src interface{}) error {
-	var buf bytes.Buffer
-	if err := gob.NewEncoder(&buf).Encode(src); err != nil {
-		return err
-	}
-	return gob.NewDecoder(bytes.NewBuffer(buf.Bytes())).Decode(dst)
-}
-
-func SafeCloseChan(c chan struct{}) {
 	select {
 	case _, ok := <-c:
 		if ok {
@@ -133,6 +96,12 @@ func RecoverAndReport() (r interface{}) {
 	return
 }
 
+func GetCaller(skip int) (string, string, int, bool) {
+	pc, file, line, ok := runtime.Caller(skip + 1)
+	method := FormatFuncName(runtime.FuncForPC(pc).Name())
+	return file, method, line, ok
+}
+
 // this function can only be called in recover().
 func LogPanic(args ...interface{}) {
 	for i := 2; i < 10; i++ {
@@ -153,21 +122,6 @@ func LogPanic(args ...interface{}) {
 	fmt.Fprintln(os.Stderr, BytesToStringWithNoCopy(debug.Stack()))
 }
 
-func FileLastName(file string) string {
-	if sp1 := strings.LastIndex(file, "/"); sp1 >= 0 {
-		if sp2 := strings.LastIndex(file[:sp1], "/"); sp2 >= 0 {
-			file = file[sp2+1:]
-		}
-	}
-	return file
-}
-
-func GetCaller(skip int) (string, string, int, bool) {
-	pc, file, line, ok := runtime.Caller(skip + 1)
-	method := FormatFuncName(runtime.FuncForPC(pc).Name())
-	return file, method, line, ok
-}
-
 func Int16ToInt64(bs []int16) (in int64) {
 	l := len(bs)
 	if l > 4 || l == 0 {
@@ -188,19 +142,13 @@ func Int16ToInt64(bs []int16) (in int64) {
 	return
 }
 
-func FormatFuncName(f string) string {
-	i := strings.LastIndex(f, "/")
-	j := strings.Index(f[i+1:], ".")
-	if j < 1 {
-		return "???"
+func FileLastName(file string) string {
+	if sp1 := strings.LastIndex(file, "/"); sp1 >= 0 {
+		if sp2 := strings.LastIndex(file[:sp1], "/"); sp2 >= 0 {
+			file = file[sp2+1:]
+		}
 	}
-	_, fun := f[:i+j+1], f[i+j+2:]
-	i = strings.LastIndex(fun, ".")
-	return fun[i+1:]
-}
-
-func FuncName(f interface{}) string {
-	return runtime.FuncForPC(reflect.ValueOf(f).Pointer()).Name()
+	return file
 }
 
 func SliceHave(arr []string, str string) bool {
diff --git a/pkg/util/util_test.go b/pkg/util/util_test.go
index c50ae81..852851f 100644
--- a/pkg/util/util_test.go
+++ b/pkg/util/util_test.go
@@ -80,3 +80,45 @@ func TestResetTimer(t *testing.T) {
 	ResetTimer(timer, time.Second)
 	<-timer.C
 }
+
+func TestStringJoin(t *testing.T) {
+	if StringJoin([]string{"a", "b", "c"}, ",") != "a,b,c" {
+		t.Fatalf("TestStringJoin failed")
+	}
+	if StringJoin([]string{"a"}, ",") != "a" {
+		t.Fatalf("TestStringJoin failed")
+	}
+	if StringJoin([]string{"a", "b", "c"}, "") != "abc" {
+		t.Fatalf("TestStringJoin failed")
+	}
+	if StringJoin([]string{}, ",") != "" {
+		t.Fatalf("TestStringJoin failed")
+	}
+	if StringJoin(nil, ",") != "" {
+		t.Fatalf("TestStringJoin failed")
+	}
+}
+
+func TestStringToBytesWithNoCopy(t *testing.T) {
+	b := StringToBytesWithNoCopy("ab")
+	if b[0] != 'a' || b[1] != 'b' {
+		t.Fatalf("TestStringToBytesWithNoCopy failed")
+	}
+}
+
+func TestSafeCloseChan(t *testing.T) {
+	var ch chan struct{}
+	SafeCloseChan(ch)
+	ch = make(chan struct{})
+	SafeCloseChan(ch)
+	SafeCloseChan(ch)
+}
+
+func TestSystemPackage(t *testing.T) {
+	if HostName() == "" {
+		t.Fatalf("TestSystemPackage failed")
+	}
+	if !PathExist("../../etc/conf/app.conf") {
+		t.Fatalf("TestSystemPackage failed")
+	}
+}
diff --git a/pkg/util/logrotate_test.go b/pkg/util/uuid_test.go
similarity index 83%
copy from pkg/util/logrotate_test.go
copy to pkg/util/uuid_test.go
index 407baa5..392db1c 100644
--- a/pkg/util/logrotate_test.go
+++ b/pkg/util/uuid_test.go
@@ -17,12 +17,13 @@
 package util
 
 import (
+	"strings"
 	"testing"
 )
 
-func TestLogRotate(t *testing.T) {
-	s := pathReplacer.Replace("./sc.log")
-	if s != "./sc.log" {
-		t.Fatal("pathReplacer failed", s)
+func TestGenerateUuid(t *testing.T) {
+	uuid := GenerateUuid()
+	if len(uuid) == 0 || strings.Contains(uuid, "-") {
+		t.Fatalf("TestGenerateUuid failed")
 	}
 }
diff --git a/pkg/validate/url.go b/pkg/validate/url.go
index f41eaa4..824d0a4 100644
--- a/pkg/validate/url.go
+++ b/pkg/validate/url.go
@@ -17,53 +17,24 @@
 package validate
 
 import (
-	"net/url"
-	"regexp"
 	"strings"
 )
 
-const (
-	PATTERN_URI      string = `#%`
-	PATTERN_URL             = "^(https|http):\\/\\/((?:(?:25[0-5]|2[0-4]\\d|((1\\d{2})|([1-9]?\\d)))\\.){3}(?:25[0-5]|2[0-4]\\d|((1\\d{2})|([1-9]?\\d)))):([0-9]+)$"
-	PATTERN_HOSTNAME string = `^(([1-9]\d?|1\d\d|2[01]\d|22[0-3])(\.(1?\d{1,2}|2[0-4]\d|25[0-5])){2}(\.([0-9]\d?|1\d\d|2[0-4]\d|25[0-4])))(:(\d{1,5}))$`
-)
-
-var (
-	rxURI      = regexp.MustCompile(PATTERN_URI)
-	rxURL      = regexp.MustCompile(PATTERN_URL)
-	rxHostName = regexp.MustCompile(PATTERN_HOSTNAME)
-)
-
-// IsURL check if the string is an URL.
-func IsURL(str string) bool {
-	if str == "" || len(str) >= 2083 || len(str) <= 3 || strings.HasPrefix(str, ".") {
-		return false
-	}
-	u, err := url.Parse(str)
-	if err != nil {
-		return false
-	}
-	if strings.HasPrefix(u.Host, ".") {
-		return false
-	}
-	if u.Host == "" && (u.Path != "" && !strings.Contains(u.Path, ".")) {
-		return false
-	}
-	return rxHostName.MatchString(str)
-
-}
-
+// IsRequestURI check if the string is an URL.
 func IsRequestURI(uri string) bool {
-	if uri == "" || len(uri) >= 2048 || strings.HasPrefix(uri, ".") {
+	if uri == "" || len(uri) >= 2048 {
 		return false
 	}
-	if strings.HasSuffix(uri, ";") || strings.HasSuffix(uri, "&") || strings.HasSuffix(uri, "?") || strings.HasSuffix(uri, "+") || strings.HasSuffix(uri, "@") || strings.Contains(uri, "//") {
+	if strings.HasSuffix(uri, ";") ||
+		strings.HasSuffix(uri, "&") ||
+		strings.HasSuffix(uri, "?") ||
+		strings.HasSuffix(uri, "+") ||
+		strings.HasSuffix(uri, "@") ||
+		//
+		strings.HasPrefix(uri, ".") ||
+		//
+		strings.Contains(uri, "//") {
 		return false
 	}
-	return !rxURI.MatchString(uri)
-}
-
-//format : https://10.21.119.167:30100 or http://10.21.119.167:30100
-func URLChecker(url string) bool {
-	return rxURL.MatchString(url)
+	return true
 }
diff --git a/pkg/validate/validator.go b/pkg/validate/validator.go
index d7f5c70..7a68301 100644
--- a/pkg/validate/validator.go
+++ b/pkg/validate/validator.go
@@ -105,7 +105,7 @@ func (v *Validator) Validate(s interface{}) error {
 		return fmt.Errorf("not support validate type '%s'", k)
 	}
 
-	st := util.ReflectObject(s)
+	st := util.Reflect(s)
 	for i, l := 0, sv.NumField(); i < l; i++ {
 		field := sv.Field(i)
 		fieldName := st.Fields[i].Name
diff --git a/scripts/prepare_env_ut.sh b/scripts/prepare_env_ut.sh
index a92980f..2868ee1 100755
--- a/scripts/prepare_env_ut.sh
+++ b/scripts/prepare_env_ut.sh
@@ -14,6 +14,5 @@
 # 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.
-cp -r etc/conf server/interceptor/ratelimiter/
-cp -r etc/conf server/service/
+cp -r etc/conf server/plugin/infra/tls/buildin
 echo "mode: atomic" > coverage.txt
diff --git a/scripts/ut_test_in_docker.sh b/scripts/ut_test_in_docker.sh
index fed3fbe..944e163 100755
--- a/scripts/ut_test_in_docker.sh
+++ b/scripts/ut_test_in_docker.sh
@@ -37,9 +37,14 @@ echo "${green}Preparing the env for UT....${reset}"
 ./scripts/prepare_env_ut.sh
 
 echo "${green}Running UT for Service-Center server"
-bash -x ./scripts/ut.sh server/service
-  
-if [ $? == 0 ]; then
+bash -x ./scripts/ut.sh pkg
+ret=$?
+if [ ${ret} == 0 ]; then
+    bash -x ./scripts/ut.sh server
+    ret=$?
+fi
+
+if [ ${ret} == 0 ]; then
 	echo "${green}All the unit test passed..${reset}"
 	echo "${green}Coverage is created in the file ./coverage.txt${reset}"
 else
diff --git a/server/broker/broker.go b/server/admin/admin.go
similarity index 93%
copy from server/broker/broker.go
copy to server/admin/admin.go
index fc807be..4a7da27 100644
--- a/server/broker/broker.go
+++ b/server/admin/admin.go
@@ -14,7 +14,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package broker
+package admin
 
 import (
 	roa "github.com/apache/incubator-servicecomb-service-center/pkg/rest"
@@ -25,5 +25,5 @@ func init() {
 }
 
 func registerREST() {
-	roa.RegisterServent(&BrokerController{})
+	roa.RegisterServant(&AdminServiceControllerV4{})
 }
diff --git a/server/govern/govern_suite_test.go b/server/admin/admin_suite_test.go
similarity index 76%
copy from server/govern/govern_suite_test.go
copy to server/admin/admin_suite_test.go
index 8a71d2e..d2444ea 100644
--- a/server/govern/govern_suite_test.go
+++ b/server/admin/admin_suite_test.go
@@ -14,16 +14,13 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package govern_test
+package admin
 
 import (
 	"github.com/apache/incubator-servicecomb-service-center/pkg/util"
-	pb "github.com/apache/incubator-servicecomb-service-center/server/core/proto"
-	"github.com/apache/incubator-servicecomb-service-center/server/govern"
 	_ "github.com/apache/incubator-servicecomb-service-center/server/plugin/infra/quota/buildin"
 	_ "github.com/apache/incubator-servicecomb-service-center/server/plugin/infra/registry/etcd"
 	_ "github.com/apache/incubator-servicecomb-service-center/server/plugin/infra/uuid/buildin"
-	"github.com/apache/incubator-servicecomb-service-center/server/service"
 	. "github.com/onsi/ginkgo"
 	"github.com/onsi/ginkgo/reporters"
 	. "github.com/onsi/gomega"
@@ -31,20 +28,14 @@ import (
 	"testing"
 )
 
-func TestGovern(t *testing.T) {
+func TestAdmin(t *testing.T) {
 	RegisterFailHandler(Fail)
 	junitReporter := reporters.NewJUnitReporter("model.junit.xml")
 	RunSpecsWithDefaultAndCustomReporters(t, "model Suite", []Reporter{junitReporter})
 }
 
-var serviceResource pb.ServiceCtrlServer
-var instanceResource pb.SerivceInstanceCtrlServerEx
-var governService pb.GovernServiceCtrlServerEx
-
 var _ = BeforeSuite(func() {
 	//init plugin
-	serviceResource, instanceResource = service.AssembleResources()
-	governService = govern.GovernServiceAPI
 })
 
 func getContext() context.Context {
diff --git a/main.go b/server/admin/controller_v4.go
similarity index 54%
copy from main.go
copy to server/admin/controller_v4.go
index 3d7ac97..5fd786a 100644
--- a/main.go
+++ b/server/admin/controller_v4.go
@@ -14,22 +14,33 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package main
+package admin
 
-// plugins
-import _ "github.com/apache/incubator-servicecomb-service-center/server/bootstrap"
 import (
-	"github.com/apache/incubator-servicecomb-service-center/pkg/util"
-	"github.com/apache/incubator-servicecomb-service-center/server"
-	"github.com/apache/incubator-servicecomb-service-center/server/core/backend"
+	"net/http"
+
+	"github.com/apache/incubator-servicecomb-service-center/pkg/rest"
+	"github.com/apache/incubator-servicecomb-service-center/server/admin/model"
+	"github.com/apache/incubator-servicecomb-service-center/server/rest/controller"
 )
 
-func main() {
-	server.Run()
+// AdminService 治理相关接口服务
+type AdminServiceControllerV4 struct {
+}
 
-	util.GoCloseAndWait()
+// URLPatterns 路由
+func (ctrl *AdminServiceControllerV4) URLPatterns() []rest.Route {
+	return []rest.Route{
+		{rest.HTTP_METHOD_GET, "/v4/:project/admin/dump", ctrl.Dump},
+	}
+}
 
-	backend.Registry().Close()
+func (ctrl *AdminServiceControllerV4) Dump(w http.ResponseWriter, r *http.Request) {
+	request := &model.DumpRequest{}
+	ctx := r.Context()
+	resp, _ := AdminServiceAPI.Dump(ctx, request)
 
-	util.Logger().Warn("service center exited", nil)
+	respInternal := resp.Response
+	resp.Response = nil
+	controller.WriteResponse(w, respInternal, resp)
 }
diff --git a/server/admin/model/dump.go b/server/admin/model/dump.go
new file mode 100644
index 0000000..fb91411
--- /dev/null
+++ b/server/admin/model/dump.go
@@ -0,0 +1,185 @@
+/*
+ * 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 model
+
+import (
+	pb "github.com/apache/incubator-servicecomb-service-center/server/core/proto"
+)
+
+type Getter interface {
+	ForEach(i func(i int, v *KV))
+}
+
+type Setter interface {
+	SetValue(v *KV)
+}
+
+type MicroserviceSlice []*Microservice
+type MicroserviceIndexSlice []*MicroserviceIndex
+type MicroserviceAliasSlice []*MicroserviceAlias
+type TagSlice []*Tag
+type MicroServiceRuleSlice []*MicroServiceRule
+type MicroServiceDependencyRuleSlice []*MicroServiceDependencyRule
+type SummarySlice []*Summary
+type InstanceSlice []*Instance
+
+func (s *MicroserviceSlice) ForEach(f func(i int, v *KV)) {
+	for i, v := range *s {
+		v.KV.Value = v.Value
+		f(i, v.KV)
+	}
+}
+func (s *MicroserviceIndexSlice) ForEach(f func(i int, v *KV)) {
+	for i, v := range *s {
+		v.KV.Value = v.Value
+		f(i, v.KV)
+	}
+}
+func (s *MicroserviceAliasSlice) ForEach(f func(i int, v *KV)) {
+	for i, v := range *s {
+		v.KV.Value = v.Value
+		f(i, v.KV)
+	}
+}
+func (s *TagSlice) ForEach(f func(i int, v *KV)) {
+	for i, v := range *s {
+		v.KV.Value = v.Value
+		f(i, v.KV)
+	}
+}
+func (s *MicroServiceRuleSlice) ForEach(f func(i int, v *KV)) {
+	for i, v := range *s {
+		v.KV.Value = v.Value
+		f(i, v.KV)
+	}
+}
+func (s *MicroServiceDependencyRuleSlice) ForEach(f func(i int, v *KV)) {
+	for i, v := range *s {
+		v.KV.Value = v.Value
+		f(i, v.KV)
+	}
+}
+func (s *SummarySlice) ForEach(f func(i int, v *KV)) {
+	for i, v := range *s {
+		v.KV.Value = v.Value
+		f(i, v.KV)
+	}
+}
+func (s *InstanceSlice) ForEach(f func(i int, v *KV)) {
+	for i, v := range *s {
+		v.KV.Value = v.Value
+		f(i, v.KV)
+	}
+}
+
+func (s *MicroserviceSlice) SetValue(v *KV)      { *s = append(*s, NewMicroservice(v)) }
+func (s *MicroserviceIndexSlice) SetValue(v *KV) { *s = append(*s, NewMicroserviceIndex(v)) }
+func (s *MicroserviceAliasSlice) SetValue(v *KV) { *s = append(*s, NewMicroserviceAlias(v)) }
+func (s *TagSlice) SetValue(v *KV)               { *s = append(*s, NewTag(v)) }
+func (s *MicroServiceRuleSlice) SetValue(v *KV)  { *s = append(*s, NewMicroServiceRule(v)) }
+func (s *MicroServiceDependencyRuleSlice) SetValue(v *KV) {
+	*s = append(*s, NewMicroServiceDependencyRule(v))
+}
+func (s *SummarySlice) SetValue(v *KV)  { *s = append(*s, NewSummary(v)) }
+func (s *InstanceSlice) SetValue(v *KV) { *s = append(*s, NewInstance(v)) }
+
+func NewMicroservice(kv *KV) *Microservice {
+	return &Microservice{kv, kv.Value.(*pb.MicroService)}
+}
+func NewMicroserviceIndex(kv *KV) *MicroserviceIndex {
+	return &MicroserviceIndex{kv, kv.Value.(string)}
+}
+func NewMicroserviceAlias(kv *KV) *MicroserviceAlias {
+	return &MicroserviceAlias{kv, kv.Value.(string)}
+}
+func NewTag(kv *KV) *Tag { return &Tag{kv, kv.Value.(map[string]string)} }
+func NewMicroServiceRule(kv *KV) *MicroServiceRule {
+	return &MicroServiceRule{kv, kv.Value.(*pb.ServiceRule)}
+}
+func NewMicroServiceDependencyRule(kv *KV) *MicroServiceDependencyRule {
+	return &MicroServiceDependencyRule{kv, kv.Value.(*pb.MicroServiceDependency)}
+}
+func NewSummary(kv *KV) *Summary { return &Summary{kv, kv.Value.(string)} }
+func NewInstance(kv *KV) *Instance {
+	return &Instance{kv, kv.Value.(*pb.MicroServiceInstance)}
+}
+
+type Cache struct {
+	Microservices   MicroserviceSlice               `json:"services,omitempty"`
+	Indexes         MicroserviceIndexSlice          `json:"serviceIndexes,omitempty"`
+	Aliases         MicroserviceAliasSlice          `json:"serviceAliases,omitempty"`
+	Tags            TagSlice                        `json:"serviceTags,omitempty"`
+	Rules           MicroServiceRuleSlice           `json:"serviceRules,omitempty"`
+	DependencyRules MicroServiceDependencyRuleSlice `json:"dependencyRules,omitempty"`
+	Summaries       SummarySlice                    `json:"summaries,omitempty"`
+	Instances       InstanceSlice                   `json:"instances,omitempty"`
+}
+
+type KV struct {
+	Key   string      `json:"key"`
+	Rev   int64       `json:"rev"`
+	Value interface{} `json:"-"`
+}
+
+type Microservice struct {
+	*KV
+	Value *pb.MicroService `json:"value,omitempty"`
+}
+
+type MicroserviceIndex struct {
+	*KV
+	Value string `json:"value,omitempty"`
+}
+
+type MicroserviceAlias struct {
+	*KV
+	Value string `json:"value,omitempty"`
+}
+
+type MicroServiceDependencyRule struct {
+	*KV
+	Value *pb.MicroServiceDependency `json:"value,omitempty"`
+}
+
+type MicroServiceRule struct {
+	*KV
+	Value *pb.ServiceRule `json:"value,omitempty"`
+}
+
+type Summary struct {
+	*KV
+	Value string `json:"value,omitempty"`
+}
+
+type Tag struct {
+	*KV
+	Value map[string]string `json:"value,omitempty"`
+}
+
+type Instance struct {
+	*KV
+	Value *pb.MicroServiceInstance `json:"value,omitempty"`
+}
+
+type DumpRequest struct {
+	Options []string
+}
+
+type DumpResponse struct {
+	Response *pb.Response `json:"response,omitempty"`
+	Cache    *Cache       `json:"cache,omitempty"`
+}
diff --git a/server/admin/service.go b/server/admin/service.go
new file mode 100644
index 0000000..166a057
--- /dev/null
+++ b/server/admin/service.go
@@ -0,0 +1,71 @@
+/*
+ * 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 admin
+
+import (
+	"github.com/apache/incubator-servicecomb-service-center/pkg/util"
+	"github.com/apache/incubator-servicecomb-service-center/server/admin/model"
+	"github.com/apache/incubator-servicecomb-service-center/server/core"
+	"github.com/apache/incubator-servicecomb-service-center/server/core/backend"
+	pb "github.com/apache/incubator-servicecomb-service-center/server/core/proto"
+	scerr "github.com/apache/incubator-servicecomb-service-center/server/error"
+	"golang.org/x/net/context"
+)
+
+var AdminServiceAPI = &AdminService{}
+
+type AdminService struct {
+}
+
+func (service *AdminService) Dump(ctx context.Context, in *model.DumpRequest) (*model.DumpResponse, error) {
+
+	domainProject := util.ParseDomainProject(ctx)
+	var cache model.Cache
+
+	if !core.IsDefaultDomainProject(domainProject) {
+		return &model.DumpResponse{
+			Response: pb.CreateResponse(scerr.ErrForbidden, "Required admin permission"),
+		}, nil
+	}
+
+	service.dumpAll(ctx, &cache)
+
+	return &model.DumpResponse{
+		Response: pb.CreateResponse(pb.Response_SUCCESS, "Admin dump successfully"),
+		Cache:    &cache,
+	}, nil
+}
+
+func (service *AdminService) dumpAll(ctx context.Context, cache *model.Cache) {
+	util.NewGo(ctx, util.PoolConfigure().Workers(2)).
+		Do(func(_ context.Context) { setValue(backend.Store().Service(), &cache.Microservices) }).
+		Do(func(_ context.Context) { setValue(backend.Store().ServiceIndex(), &cache.Indexes) }).
+		Do(func(_ context.Context) { setValue(backend.Store().ServiceAlias(), &cache.Aliases) }).
+		Do(func(_ context.Context) { setValue(backend.Store().ServiceTag(), &cache.Tags) }).
+		Do(func(_ context.Context) { setValue(backend.Store().Rule(), &cache.Rules) }).
+		Do(func(_ context.Context) { setValue(backend.Store().DependencyRule(), &cache.DependencyRules) }).
+		Do(func(_ context.Context) { setValue(backend.Store().SchemaSummary(), &cache.Summaries) }).
+		Do(func(_ context.Context) { setValue(backend.Store().Instance(), &cache.Instances) }).
+		Done()
+}
+
+func setValue(e backend.Entity, setter model.Setter) {
+	e.Cache().ForEach(func(k string, kv *backend.KeyValue) (next bool) {
+		setter.SetValue(&model.KV{Key: k, Rev: kv.ModRevision, Value: kv.Value})
+		return true
+	})
+}
diff --git a/server/broker/broker_suite_test.go b/server/admin/service_test.go
similarity index 53%
copy from server/broker/broker_suite_test.go
copy to server/admin/service_test.go
index 8bc652e..ff32bdf 100644
--- a/server/broker/broker_suite_test.go
+++ b/server/admin/service_test.go
@@ -14,32 +14,35 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package broker
+package admin
 
 import (
+	"github.com/apache/incubator-servicecomb-service-center/pkg/util"
+	"github.com/apache/incubator-servicecomb-service-center/server/admin/model"
 	pb "github.com/apache/incubator-servicecomb-service-center/server/core/proto"
-	_ "github.com/apache/incubator-servicecomb-service-center/server/plugin/infra/quota/buildin"
-	_ "github.com/apache/incubator-servicecomb-service-center/server/plugin/infra/registry/etcd"
-	_ "github.com/apache/incubator-servicecomb-service-center/server/plugin/infra/tracing/buildin"
-	_ "github.com/apache/incubator-servicecomb-service-center/server/plugin/infra/uuid/buildin"
-	"github.com/apache/incubator-servicecomb-service-center/server/service"
+	scerr "github.com/apache/incubator-servicecomb-service-center/server/error"
 	. "github.com/onsi/ginkgo"
-	"github.com/onsi/ginkgo/reporters"
 	. "github.com/onsi/gomega"
-	"testing"
+	"golang.org/x/net/context"
 )
 
-var serviceResource pb.ServiceCtrlServer
-var instanceResource pb.SerivceInstanceCtrlServerEx
-var brokerResource = BrokerServiceAPI
-
-var _ = BeforeSuite(func() {
-	//init plugin
-	serviceResource, instanceResource = service.AssembleResources()
+var _ = Describe("'Admin' service", func() {
+	Describe("execute 'dump' operation", func() {
+		Context("when get all", func() {
+			It("should be passed", func() {
+				resp, err := AdminServiceAPI.Dump(getContext(), &model.DumpRequest{})
+				Expect(err).To(BeNil())
+				Expect(resp.Response.Code).To(Equal(pb.Response_SUCCESS))
+			})
+		})
+		Context("when get by domain project", func() {
+			It("should be passed", func() {
+				resp, err := AdminServiceAPI.Dump(
+					util.SetDomainProject(context.Background(), "x", "x"),
+					&model.DumpRequest{})
+				Expect(err).To(BeNil())
+				Expect(resp.Response.Code).To(Equal(scerr.ErrForbidden))
+			})
+		})
+	})
 })
-
-func TestBroker(t *testing.T) {
-	RegisterFailHandler(Fail)
-	junitReporter := reporters.NewJUnitReporter("model.junit.xml")
-	RunSpecsWithDefaultAndCustomReporters(t, "model Suite", []Reporter{junitReporter})
-}
diff --git a/server/api.go b/server/api.go
index f606fee..c694535 100644
--- a/server/api.go
+++ b/server/api.go
@@ -27,6 +27,7 @@ import (
 	"github.com/apache/incubator-servicecomb-service-center/server/rpc"
 	"github.com/apache/incubator-servicecomb-service-center/server/service"
 	"golang.org/x/net/context"
+	"strconv"
 	"time"
 )
 
@@ -55,7 +56,7 @@ func (t APIType) String() string {
 	case REST:
 		return "rest"
 	default:
-		return fmt.Sprintf("SCHEME%d", t)
+		return "SCHEME" + strconv.Itoa(int(t))
 	}
 }
 
@@ -215,7 +216,7 @@ func (s *APIServer) startRESTServer() (err error) {
 	if err != nil {
 		return
 	}
-	util.Logger().Infof("Local listen address: %s, host: %s", addr, s.HostName)
+	util.Logger().Infof("listen address: %s://%s, host: %s.", REST, addr, s.HostName)
 
 	s.goroutine.Do(func(_ context.Context) {
 		err := s.restSrv.Serve()
@@ -238,7 +239,7 @@ func (s *APIServer) startRPCServer() (err error) {
 	if err != nil {
 		return
 	}
-	util.Logger().Infof("Local listen address: %s, host: %s.", addr, s.HostName)
+	util.Logger().Infof("listen address: %s://%s, host: %s.", RPC, addr, s.HostName)
 
 	s.goroutine.Do(func(_ context.Context) {
 		err := s.rpcSrv.Serve()
@@ -279,10 +280,11 @@ func (s *APIServer) Start() {
 		s.err <- err
 		return
 	}
-
 	// 心跳
 	s.startHeartBeatService()
 
+	ReportScInstance()
+
 	util.Logger().Info("api server is ready")
 }
 
diff --git a/server/bootstrap/bootstrap.go b/server/bootstrap/bootstrap.go
index 184cb6d..f0efb35 100644
--- a/server/bootstrap/bootstrap.go
+++ b/server/bootstrap/bootstrap.go
@@ -16,8 +16,6 @@
  */
 package bootstrap
 
-import _ "github.com/apache/incubator-servicecomb-service-center/server/core" // initialize
-
 // rest
 import _ "github.com/apache/incubator-servicecomb-service-center/server/rest/controller/v3"
 import _ "github.com/apache/incubator-servicecomb-service-center/server/rest/controller/v4"
@@ -51,6 +49,9 @@ import _ "github.com/apache/incubator-servicecomb-service-center/server/govern"
 // module 'broker'
 import _ "github.com/apache/incubator-servicecomb-service-center/server/broker"
 
+// module 'admin'
+import _ "github.com/apache/incubator-servicecomb-service-center/server/admin"
+
 // metrics
 import _ "github.com/apache/incubator-servicecomb-service-center/server/metric"
 
diff --git a/server/broker/broker.go b/server/broker/broker.go
index fc807be..54840ae 100644
--- a/server/broker/broker.go
+++ b/server/broker/broker.go
@@ -25,5 +25,5 @@ func init() {
 }
 
 func registerREST() {
-	roa.RegisterServent(&BrokerController{})
+	roa.RegisterServant(&BrokerController{})
 }
diff --git a/server/broker/broker_suite_test.go b/server/broker/broker_suite_test.go
index 8bc652e..2bdfa72 100644
--- a/server/broker/broker_suite_test.go
+++ b/server/broker/broker_suite_test.go
@@ -17,7 +17,7 @@
 package broker
 
 import (
-	pb "github.com/apache/incubator-servicecomb-service-center/server/core/proto"
+	"github.com/apache/incubator-servicecomb-service-center/server/core"
 	_ "github.com/apache/incubator-servicecomb-service-center/server/plugin/infra/quota/buildin"
 	_ "github.com/apache/incubator-servicecomb-service-center/server/plugin/infra/registry/etcd"
 	_ "github.com/apache/incubator-servicecomb-service-center/server/plugin/infra/tracing/buildin"
@@ -29,13 +29,12 @@ import (
 	"testing"
 )
 
-var serviceResource pb.ServiceCtrlServer
-var instanceResource pb.SerivceInstanceCtrlServerEx
 var brokerResource = BrokerServiceAPI
 
 var _ = BeforeSuite(func() {
 	//init plugin
-	serviceResource, instanceResource = service.AssembleResources()
+	core.ServerInfo.Config.EnableCache = false
+	core.ServiceAPI, core.InstanceAPI = service.AssembleResources()
 })
 
 func TestBroker(t *testing.T) {
diff --git a/server/broker/broker.pb.go b/server/broker/brokerpb/broker.pb.go
similarity index 99%
rename from server/broker/broker.pb.go
rename to server/broker/brokerpb/broker.pb.go
index c2709cd..d61f9d8 100644
--- a/server/broker/broker.pb.go
+++ b/server/broker/brokerpb/broker.pb.go
@@ -49,7 +49,7 @@ It has these top-level messages:
 	BrokerAPIInfoEntry
 	BrokerHomeResponse
 */
-package broker
+package brokerpb
 
 import proto "github.com/golang/protobuf/proto"
 import fmt "fmt"
diff --git a/server/broker/broker.proto b/server/broker/brokerpb/broker.proto
similarity index 100%
rename from server/broker/broker.proto
rename to server/broker/brokerpb/broker.proto
diff --git a/server/broker/controller.go b/server/broker/controller.go
index 05101f0..dc64522 100644
--- a/server/broker/controller.go
+++ b/server/broker/controller.go
@@ -23,6 +23,7 @@ import (
 	"strconv"
 
 	"github.com/apache/incubator-servicecomb-service-center/pkg/rest"
+	"github.com/apache/incubator-servicecomb-service-center/server/broker/brokerpb"
 	scerr "github.com/apache/incubator-servicecomb-service-center/server/error"
 	"github.com/apache/incubator-servicecomb-service-center/server/rest/controller"
 )
@@ -60,7 +61,7 @@ func (brokerService *BrokerController) URLPatterns() []rest.Route {
 }
 
 func (brokerService *BrokerController) GetHome(w http.ResponseWriter, r *http.Request) {
-	request := &BaseBrokerRequest{
+	request := &brokerpb.BaseBrokerRequest{
 		HostAddress: r.Host,
 		Scheme:      getScheme(r),
 	}
@@ -79,7 +80,7 @@ func (*BrokerController) PublishPact(w http.ResponseWriter, r *http.Request) {
 		return
 	}
 	query := r.URL.Query()
-	request := &PublishPactRequest{
+	request := &brokerpb.PublishPactRequest{
 		ProviderId: query.Get(":providerId"),
 		ConsumerId: query.Get(":consumerId"),
 		Version:    query.Get(":number"),
@@ -95,9 +96,9 @@ func (*BrokerController) PublishPact(w http.ResponseWriter, r *http.Request) {
 }
 
 func (*BrokerController) GetAllProviderPacts(w http.ResponseWriter, r *http.Request) {
-	request := &GetAllProviderPactsRequest{
+	request := &brokerpb.GetAllProviderPactsRequest{
 		ProviderId: r.URL.Query().Get(":providerId"),
-		BaseUrl: &BaseBrokerRequest{
+		BaseUrl: &brokerpb.BaseBrokerRequest{
 			HostAddress: r.Host,
 			Scheme:      getScheme(r),
 		},
@@ -115,11 +116,11 @@ func (*BrokerController) GetAllProviderPacts(w http.ResponseWriter, r *http.Requ
 
 func (*BrokerController) GetPactsOfProvider(w http.ResponseWriter, r *http.Request) {
 	query := r.URL.Query()
-	request := &GetProviderConsumerVersionPactRequest{
+	request := &brokerpb.GetProviderConsumerVersionPactRequest{
 		ProviderId: query.Get(":providerId"),
 		ConsumerId: query.Get(":consumerId"),
 		Version:    query.Get(":number"),
-		BaseUrl: &BaseBrokerRequest{
+		BaseUrl: &brokerpb.BaseBrokerRequest{
 			HostAddress: r.Host,
 			Scheme:      getScheme(r),
 		},
@@ -133,7 +134,7 @@ func (*BrokerController) GetPactsOfProvider(w http.ResponseWriter, r *http.Reque
 }
 
 func (*BrokerController) DeletePacts(w http.ResponseWriter, r *http.Request) {
-	resp, _ := BrokerServiceAPI.DeletePacts(r.Context(), &BaseBrokerRequest{
+	resp, _ := BrokerServiceAPI.DeletePacts(r.Context(), &brokerpb.BaseBrokerRequest{
 		HostAddress: r.Host,
 		Scheme:      getScheme(r),
 	})
@@ -147,7 +148,7 @@ func (*BrokerController) PublishVerificationResults(w http.ResponseWriter, r *ht
 		controller.WriteError(w, scerr.ErrInvalidParams, err.Error())
 		return
 	}
-	request := &PublishVerificationRequest{}
+	request := &brokerpb.PublishVerificationRequest{}
 	err = json.Unmarshal(requestBody, request)
 	if err != nil {
 		PactLogger.Error("Unmarshal error", err)
@@ -175,7 +176,7 @@ func (*BrokerController) PublishVerificationResults(w http.ResponseWriter, r *ht
 }
 
 func (*BrokerController) RetrieveVerificationResults(w http.ResponseWriter, r *http.Request) {
-	request := &RetrieveVerificationRequest{}
+	request := &brokerpb.RetrieveVerificationRequest{}
 	query := r.URL.Query()
 	request.ConsumerId = query.Get(":consumerId")
 	request.ConsumerVersion = query.Get(":consumerVersion")
diff --git a/server/broker/broker.go b/server/broker/controller_test.go
similarity index 60%
copy from server/broker/broker.go
copy to server/broker/controller_test.go
index fc807be..fe42bf4 100644
--- a/server/broker/broker.go
+++ b/server/broker/controller_test.go
@@ -17,13 +17,33 @@
 package broker
 
 import (
-	roa "github.com/apache/incubator-servicecomb-service-center/pkg/rest"
+	"bytes"
+	"net/http"
+	"net/http/httptest"
+	"testing"
 )
 
-func init() {
-	registerREST()
+var (
+	ctrl = &BrokerController{}
+	num  int
+)
+
+type mockBrokerHandler struct {
 }
 
-func registerREST() {
-	roa.RegisterServent(&BrokerController{})
+func (b *mockBrokerHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+	route := ctrl.URLPatterns()[num]
+	r.Method = route.Method
+	r.URL.RawQuery = ":sha=1"
+	route.Func(w, r)
+	num++
+}
+
+func TestBrokerController_GetHome(t *testing.T) {
+	svr := httptest.NewServer(&mockBrokerHandler{})
+	defer svr.Close()
+
+	for range ctrl.URLPatterns() {
+		http.Post(svr.URL, "application/json", bytes.NewBuffer([]byte("{}")))
+	}
 }
diff --git a/server/broker/service.go b/server/broker/service.go
index c36cb3e..ec0a96a 100644
--- a/server/broker/service.go
+++ b/server/broker/service.go
@@ -19,13 +19,13 @@ package broker
 import (
 	"crypto/sha1"
 	"encoding/json"
-	"fmt"
 	"math"
 	"strconv"
 	"strings"
 	"time"
 
 	"github.com/apache/incubator-servicecomb-service-center/pkg/util"
+	"github.com/apache/incubator-servicecomb-service-center/server/broker/brokerpb"
 	apt "github.com/apache/incubator-servicecomb-service-center/server/core"
 	pb "github.com/apache/incubator-servicecomb-service-center/server/core/proto"
 	scerr "github.com/apache/incubator-servicecomb-service-center/server/error"
@@ -40,11 +40,11 @@ type BrokerService struct {
 }
 
 func (*BrokerService) GetBrokerHome(ctx context.Context,
-	in *BaseBrokerRequest) (*BrokerHomeResponse, error) {
+	in *brokerpb.BaseBrokerRequest) (*brokerpb.BrokerHomeResponse, error) {
 
 	if in == nil || len(in.HostAddress) == 0 {
 		PactLogger.Errorf(nil, "Get Participant versions request failed: invalid params.")
-		return &BrokerHomeResponse{
+		return &brokerpb.BrokerHomeResponse{
 			Response: pb.CreateResponse(scerr.ErrInvalidParams, "Request format invalid."),
 		}, nil
 	}
@@ -53,15 +53,18 @@ func (*BrokerService) GetBrokerHome(ctx context.Context,
 }
 
 func (*BrokerService) GetPactsOfProvider(ctx context.Context,
-	in *GetProviderConsumerVersionPactRequest) (*GetProviderConsumerVersionPactResponse, error) {
+	in *brokerpb.GetProviderConsumerVersionPactRequest) (*brokerpb.GetProviderConsumerVersionPactResponse, error) {
 	PactLogger.Infof("GetPactsOfProvider: (%s, %s, %s)\n",
 		in.ProviderId, in.ConsumerId, in.Version)
 
 	resp, pactId, err := RetrieveProviderConsumerPact(ctx, in)
 	if err != nil || resp.GetPact() == nil || pactId == -1 {
-		PactLogger.Errorf(nil, "Get pacts of provider failed: %s\n",
-			resp.Response.Message)
-		return &GetProviderConsumerVersionPactResponse{
+		var message string
+		if resp != nil {
+			message = resp.Response.Message
+		}
+		PactLogger.Errorf(err, "Get pacts of provider failed: %s\n", message)
+		return &brokerpb.GetProviderConsumerVersionPactResponse{
 			Response: resp.GetResponse(),
 		}, err
 	}
@@ -70,7 +73,7 @@ func (*BrokerService) GetPactsOfProvider(ctx context.Context,
 		BROKER_PUBLISH_VERIFICATION_URL,
 		strings.NewReplacer(":providerId", in.ProviderId,
 			":consumerId", in.ConsumerId,
-			":pact", fmt.Sprint(pactId)))
+			":pact", strconv.FormatInt(int64(pactId), 10)))
 
 	links := ",\"_links\": {" +
 		"\"pb:publish-verification-results\": {" +
@@ -85,7 +88,7 @@ func (*BrokerService) GetPactsOfProvider(ctx context.Context,
 	sliceOfResp := pactBytes[0 : len(pactBytes)-2]
 	finalBytes := append(sliceOfResp, linksBytes...)
 
-	return &GetProviderConsumerVersionPactResponse{
+	return &brokerpb.GetProviderConsumerVersionPactResponse{
 		Response: pb.CreateResponse(pb.Response_SUCCESS, "Success."),
 		Pact:     finalBytes,
 	}, nil
@@ -94,7 +97,7 @@ func (*BrokerService) GetPactsOfProvider(ctx context.Context,
 }
 
 func (*BrokerService) DeletePacts(ctx context.Context,
-	in *BaseBrokerRequest) (*pb.Response, error) {
+	in *brokerpb.BaseBrokerRequest) (*pb.Response, error) {
 
 	resp, err := DeletePactData(ctx, in)
 
@@ -102,10 +105,10 @@ func (*BrokerService) DeletePacts(ctx context.Context,
 }
 
 func (*BrokerService) RetrieveProviderPacts(ctx context.Context,
-	in *GetAllProviderPactsRequest) (*GetAllProviderPactsResponse, error) {
+	in *brokerpb.GetAllProviderPactsRequest) (*brokerpb.GetAllProviderPactsResponse, error) {
 	if in == nil || len(in.ProviderId) == 0 {
 		PactLogger.Errorf(nil, "all provider pact retrieve request failed: invalid params.")
-		return &GetAllProviderPactsResponse{
+		return &brokerpb.GetAllProviderPactsResponse{
 			Response: pb.CreateResponse(scerr.ErrInvalidParams, "Request format invalid."),
 		}, nil
 	}
@@ -114,13 +117,13 @@ func (*BrokerService) RetrieveProviderPacts(ctx context.Context,
 	provider, err := serviceUtil.GetService(ctx, tenant, in.ProviderId)
 	if err != nil {
 		PactLogger.Errorf(err, "all provider pact retrieve failed, providerId is %s: query provider failed.", in.ProviderId)
-		return &GetAllProviderPactsResponse{
+		return &brokerpb.GetAllProviderPactsResponse{
 			Response: pb.CreateResponse(scerr.ErrInvalidParams, "Query provider failed."),
 		}, err
 	}
 	if provider == nil {
 		PactLogger.Errorf(nil, "all provider pact retrieve failed, providerId is %s: provider not exist.", in.ProviderId)
-		return &GetAllProviderPactsResponse{
+		return &brokerpb.GetAllProviderPactsResponse{
 			Response: pb.CreateResponse(scerr.ErrInvalidParams, "Provider does not exist."),
 		}, nil
 	}
@@ -129,7 +132,7 @@ func (*BrokerService) RetrieveProviderPacts(ctx context.Context,
 	providerParticipant, err := GetParticipant(ctx, tenant, provider.AppId, provider.ServiceName)
 	if err != nil || providerParticipant == nil {
 		PactLogger.Errorf(nil, "all provider pact retrieve failed, provider participant cannot be searched.", in.ProviderId)
-		return &GetAllProviderPactsResponse{
+		return &brokerpb.GetAllProviderPactsResponse{
 			Response: pb.CreateResponse(scerr.ErrInvalidParams, "Provider participant cannot be searched."),
 		}, err
 	}
@@ -148,9 +151,9 @@ func (*BrokerService) RetrieveProviderPacts(ctx context.Context,
 		return nil, nil
 	}
 	// Store versions in a map
-	versionObjects := make(map[int32]Version)
+	versionObjects := make(map[int32]brokerpb.Version)
 	for i := 0; i < len(versions.Kvs); i++ {
-		version := &Version{}
+		version := &brokerpb.Version{}
 		err = json.Unmarshal(versions.Kvs[i].Value.([]byte), version)
 		if err != nil {
 			return nil, err
@@ -171,9 +174,9 @@ func (*BrokerService) RetrieveProviderPacts(ctx context.Context,
 		PactLogger.Info("[RetrieveProviderPacts] No pact version found, sorry")
 		return nil, nil
 	}
-	participantToVersionObj := make(map[int32]Version)
+	participantToVersionObj := make(map[int32]brokerpb.Version)
 	for i := 0; i < len(pactVersions.Kvs); i++ {
-		pactVersion := &PactVersion{}
+		pactVersion := &brokerpb.PactVersion{}
 		err = json.Unmarshal(pactVersions.Kvs[i].Value.([]byte), pactVersion)
 		if err != nil {
 			return nil, err
@@ -203,9 +206,9 @@ func (*BrokerService) RetrieveProviderPacts(ctx context.Context,
 	if len(participants.Kvs) == 0 {
 		return nil, nil
 	}
-	consumerInfoArr := make([]*ConsumerInfo, 0)
+	consumerInfoArr := make([]*brokerpb.ConsumerInfo, 0)
 	for i := 0; i < len(participants.Kvs); i++ {
-		participant := &Participant{}
+		participant := &brokerpb.Participant{}
 		err = json.Unmarshal(participants.Kvs[i].Value.([]byte), participant)
 		if err != nil {
 			return nil, err
@@ -232,13 +235,13 @@ func (*BrokerService) RetrieveProviderPacts(ctx context.Context,
 				":consumerId", consumerId,
 				":number", consumerVersion))
 
-		consumerInfo := &ConsumerInfo{
+		consumerInfo := &brokerpb.ConsumerInfo{
 			Href: urlValue,
 			Name: consumerId,
 		}
 		consumerInfoArr = append(consumerInfoArr, consumerInfo)
 	}
-	links := &Links{
+	links := &brokerpb.Links{
 		Pacts: consumerInfoArr,
 	}
 	resJson, err := json.Marshal(links)
@@ -246,7 +249,7 @@ func (*BrokerService) RetrieveProviderPacts(ctx context.Context,
 		return nil, err
 	}
 	PactLogger.Infof("Json : %s", string(resJson))
-	response := &GetAllProviderPactsResponse{
+	response := &brokerpb.GetAllProviderPactsResponse{
 		Response: pb.CreateResponse(pb.Response_SUCCESS, "retrieve provider pact info succeeded."),
 		XLinks:   links,
 	}
@@ -254,11 +257,11 @@ func (*BrokerService) RetrieveProviderPacts(ctx context.Context,
 }
 
 func (*BrokerService) GetAllProviderPacts(ctx context.Context,
-	in *GetAllProviderPactsRequest) (*GetAllProviderPactsResponse, error) {
+	in *brokerpb.GetAllProviderPactsRequest) (*brokerpb.GetAllProviderPactsResponse, error) {
 
 	if in == nil || len(in.ProviderId) == 0 {
 		PactLogger.Errorf(nil, "all provider pact retrieve request failed: invalid params.")
-		return &GetAllProviderPactsResponse{
+		return &brokerpb.GetAllProviderPactsResponse{
 			Response: pb.CreateResponse(scerr.ErrInvalidParams, "Request format invalid."),
 		}, nil
 	}
@@ -267,13 +270,13 @@ func (*BrokerService) GetAllProviderPacts(ctx context.Context,
 	provider, err := serviceUtil.GetService(ctx, tenant, in.ProviderId)
 	if err != nil {
 		PactLogger.Errorf(err, "all provider pact retrieve failed, providerId is %s: query provider failed.", in.ProviderId)
-		return &GetAllProviderPactsResponse{
+		return &brokerpb.GetAllProviderPactsResponse{
 			Response: pb.CreateResponse(scerr.ErrInvalidParams, "Query provider failed."),
 		}, err
 	}
 	if provider == nil {
 		PactLogger.Errorf(nil, "all provider pact retrieve failed, providerId is %s: provider not exist.", in.ProviderId)
-		return &GetAllProviderPactsResponse{
+		return &brokerpb.GetAllProviderPactsResponse{
 			Response: pb.CreateResponse(scerr.ErrInvalidParams, "Provider does not exist."),
 		}, nil
 	}
@@ -282,7 +285,7 @@ func (*BrokerService) GetAllProviderPacts(ctx context.Context,
 	providerParticipant, err := GetParticipant(ctx, tenant, provider.AppId, provider.ServiceName)
 	if err != nil || providerParticipant == nil {
 		PactLogger.Errorf(nil, "all provider pact retrieve failed, provider participant cannot be searched.", in.ProviderId)
-		return &GetAllProviderPactsResponse{
+		return &brokerpb.GetAllProviderPactsResponse{
 			Response: pb.CreateResponse(scerr.ErrInvalidParams, "Provider participant cannot be searched."),
 		}, err
 	}
@@ -301,9 +304,9 @@ func (*BrokerService) GetAllProviderPacts(ctx context.Context,
 		return nil, nil
 	}
 	// Store versions in a map
-	versionObjects := make(map[int32]Version)
+	versionObjects := make(map[int32]brokerpb.Version)
 	for i := 0; i < len(versions.Kvs); i++ {
-		version := &Version{}
+		version := &brokerpb.Version{}
 		err = json.Unmarshal(versions.Kvs[i].Value.([]byte), version)
 		if err != nil {
 			return nil, err
@@ -324,9 +327,9 @@ func (*BrokerService) GetAllProviderPacts(ctx context.Context,
 		PactLogger.Info("[RetrieveProviderPacts] No pact version found, sorry")
 		return nil, nil
 	}
-	participantToVersionObj := make(map[int32]Version)
+	participantToVersionObj := make(map[int32]brokerpb.Version)
 	for i := 0; i < len(pactVersions.Kvs); i++ {
-		pactVersion := &PactVersion{}
+		pactVersion := &brokerpb.PactVersion{}
 		err = json.Unmarshal(pactVersions.Kvs[i].Value.([]byte), pactVersion)
 		if err != nil {
 			return nil, err
@@ -356,9 +359,9 @@ func (*BrokerService) GetAllProviderPacts(ctx context.Context,
 	if len(participants.Kvs) == 0 {
 		return nil, nil
 	}
-	consumerInfoArr := make([]*ConsumerInfo, 0)
+	consumerInfoArr := make([]*brokerpb.ConsumerInfo, 0)
 	for i := 0; i < len(participants.Kvs); i++ {
-		participant := &Participant{}
+		participant := &brokerpb.Participant{}
 		err = json.Unmarshal(participants.Kvs[i].Value.([]byte), participant)
 		if err != nil {
 			return nil, err
@@ -385,13 +388,13 @@ func (*BrokerService) GetAllProviderPacts(ctx context.Context,
 				":consumerId", consumerId,
 				":number", consumerVersion))
 
-		consumerInfo := &ConsumerInfo{
+		consumerInfo := &brokerpb.ConsumerInfo{
 			Href: urlValue,
 			Name: consumerId,
 		}
 		consumerInfoArr = append(consumerInfoArr, consumerInfo)
 	}
-	links := &Links{
+	links := &brokerpb.Links{
 		Pacts: consumerInfoArr,
 	}
 	resJson, err := json.Marshal(links)
@@ -399,17 +402,17 @@ func (*BrokerService) GetAllProviderPacts(ctx context.Context,
 		return nil, err
 	}
 	PactLogger.Infof("Json : %s", string(resJson))
-	response := &GetAllProviderPactsResponse{
+	response := &brokerpb.GetAllProviderPactsResponse{
 		Response: pb.CreateResponse(pb.Response_SUCCESS, "retrieve provider pact info succeeded."),
 		XLinks:   links,
 	}
 	return response, nil
 }
 
-func (*BrokerService) RetrieveVerificationResults(ctx context.Context, in *RetrieveVerificationRequest) (*RetrieveVerificationResponse, error) {
+func (*BrokerService) RetrieveVerificationResults(ctx context.Context, in *brokerpb.RetrieveVerificationRequest) (*brokerpb.RetrieveVerificationResponse, error) {
 	if in == nil || len(in.ConsumerId) == 0 || len(in.ConsumerVersion) == 0 {
 		PactLogger.Errorf(nil, "verification result retrieve request failed: invalid params.")
-		return &RetrieveVerificationResponse{
+		return &brokerpb.RetrieveVerificationResponse{
 			Response: pb.CreateResponse(scerr.ErrInvalidParams, "Request format invalid."),
 		}, nil
 	}
@@ -417,13 +420,13 @@ func (*BrokerService) RetrieveVerificationResults(ctx context.Context, in *Retri
 	consumer, err := serviceUtil.GetService(ctx, tenant, in.ConsumerId)
 	if err != nil {
 		PactLogger.Errorf(err, "verification result retrieve request failed, consumerId is %s: query consumer failed.", in.ConsumerId)
-		return &RetrieveVerificationResponse{
+		return &brokerpb.RetrieveVerificationResponse{
 			Response: pb.CreateResponse(scerr.ErrInvalidParams, "Query consumer failed."),
 		}, err
 	}
 	if consumer == nil {
 		PactLogger.Errorf(nil, "verification result retrieve request failed, consumerId is %s: consumer not exist.", in.ConsumerId)
-		return &RetrieveVerificationResponse{
+		return &brokerpb.RetrieveVerificationResponse{
 			Response: pb.CreateResponse(scerr.ErrInvalidParams, "Consumer does not exist."),
 		}, nil
 	}
@@ -432,7 +435,7 @@ func (*BrokerService) RetrieveVerificationResults(ctx context.Context, in *Retri
 	consumerParticipant, err := GetParticipant(ctx, tenant, consumer.AppId, consumer.ServiceName)
 	if err != nil || consumerParticipant == nil {
 		PactLogger.Errorf(nil, "verification result retrieve request failed, consumer participant cannot be searched.", in.ConsumerId)
-		return &RetrieveVerificationResponse{
+		return &brokerpb.RetrieveVerificationResponse{
 			Response: pb.CreateResponse(scerr.ErrInvalidParams, "consumer participant cannot be searched."),
 		}, err
 	}
@@ -441,7 +444,7 @@ func (*BrokerService) RetrieveVerificationResults(ctx context.Context, in *Retri
 	version, err := GetVersion(ctx, tenant, consumer.Version, consumerParticipant.Id)
 	if err != nil || version == nil {
 		PactLogger.Errorf(nil, "verification result retrieve request failed, version cannot be searched.")
-		return &RetrieveVerificationResponse{
+		return &brokerpb.RetrieveVerificationResponse{
 			Response: pb.CreateResponse(scerr.ErrInvalidParams, "version cannot be searched."),
 		}, err
 	}
@@ -453,7 +456,7 @@ func (*BrokerService) RetrieveVerificationResults(ctx context.Context, in *Retri
 
 	if err != nil || len(pactVersions.Kvs) == 0 {
 		PactLogger.Errorf(nil, "verification result publish request failed, pact version cannot be searched.")
-		return &RetrieveVerificationResponse{
+		return &brokerpb.RetrieveVerificationResponse{
 			Response: pb.CreateResponse(scerr.ErrInvalidParams, "pact version cannot be searched."),
 		}, err
 	}
@@ -463,13 +466,13 @@ func (*BrokerService) RetrieveVerificationResults(ctx context.Context, in *Retri
 	fails := make([]string, 0)
 	unknowns := make([]string, 0)
 
-	verificationDetailsArr := make([]*VerificationDetail, 0)
+	verificationDetailsArr := make([]*brokerpb.VerificationDetail, 0)
 	for j := 0; j < len(pactVersions.Kvs); j++ {
-		pactVersion := &PactVersion{}
+		pactVersion := &brokerpb.PactVersion{}
 		err = json.Unmarshal(pactVersions.Kvs[j].Value.([]byte), &pactVersion)
 		if err != nil {
 			PactLogger.Errorf(nil, "verification result retrieve request failed, pact version cannot be searched.")
-			return &RetrieveVerificationResponse{
+			return &brokerpb.RetrieveVerificationResponse{
 				Response: pb.CreateResponse(scerr.ErrInvalidParams, "pact version cannot be searched."),
 			}, err
 		}
@@ -480,18 +483,18 @@ func (*BrokerService) RetrieveVerificationResults(ctx context.Context, in *Retri
 
 		if err != nil || len(verifications.Kvs) == 0 {
 			PactLogger.Errorf(nil, "verification result retrieve request failed, verification results cannot be searched.")
-			return &RetrieveVerificationResponse{
+			return &brokerpb.RetrieveVerificationResponse{
 				Response: pb.CreateResponse(scerr.ErrInvalidParams, "verification results cannot be searched."),
 			}, err
 		}
 		lastNumber := int32(math.MinInt32)
-		var lastVerificationResult *Verification
+		var lastVerificationResult *brokerpb.Verification
 		for i := 0; i < len(verifications.Kvs); i++ {
-			verification := &Verification{}
+			verification := &brokerpb.Verification{}
 			err = json.Unmarshal(verifications.Kvs[i].Value.([]byte), &verification)
 			if err != nil {
 				PactLogger.Errorf(nil, "verification result retrieve request failed, verification result unmarshall error.")
-				return &RetrieveVerificationResponse{
+				return &brokerpb.RetrieveVerificationResponse{
 					Response: pb.CreateResponse(scerr.ErrInvalidParams, "verification result unmarshall error."),
 				}, err
 			}
@@ -502,7 +505,7 @@ func (*BrokerService) RetrieveVerificationResults(ctx context.Context, in *Retri
 		}
 		if lastVerificationResult == nil {
 			PactLogger.Errorf(nil, "verification result retrieve request failed, verification result cannot be found.")
-			return &RetrieveVerificationResponse{
+			return &brokerpb.RetrieveVerificationResponse{
 				Response: pb.CreateResponse(scerr.ErrInvalidParams, "verification result cannot be found."),
 			}, err
 		}
@@ -518,17 +521,17 @@ func (*BrokerService) RetrieveVerificationResults(ctx context.Context, in *Retri
 
 		if err != nil || len(participants.Kvs) == 0 {
 			PactLogger.Errorf(nil, "verification result retrieve request failed, provider participant cannot be searched.")
-			return &RetrieveVerificationResponse{
+			return &brokerpb.RetrieveVerificationResponse{
 				Response: pb.CreateResponse(scerr.ErrInvalidParams, "provider participant cannot be searched."),
 			}, err
 		}
-		var providerParticipant *Participant
+		var providerParticipant *brokerpb.Participant
 		for i := 0; i < len(participants.Kvs); i++ {
-			participant := &Participant{}
+			participant := &brokerpb.Participant{}
 			err = json.Unmarshal(participants.Kvs[i].Value.([]byte), &participant)
 			if err != nil {
 				PactLogger.Errorf(nil, "verification result retrieve request failed, verification result unmarshall error.")
-				return &RetrieveVerificationResponse{
+				return &brokerpb.RetrieveVerificationResponse{
 					Response: pb.CreateResponse(scerr.ErrInvalidParams, "verification result unmarshall error."),
 				}, err
 			}
@@ -539,7 +542,7 @@ func (*BrokerService) RetrieveVerificationResults(ctx context.Context, in *Retri
 		}
 		if providerParticipant == nil {
 			PactLogger.Errorf(nil, "verification result retrieve request failed, verification result unmarshall error.")
-			return &RetrieveVerificationResponse{
+			return &brokerpb.RetrieveVerificationResponse{
 				Response: pb.CreateResponse(scerr.ErrInvalidParams, "verification result unmarshall error."),
 			}, err
 		}
@@ -552,12 +555,12 @@ func (*BrokerService) RetrieveVerificationResults(ctx context.Context, in *Retri
 		resp, err := apt.ServiceAPI.Exist(ctx, serviceFindReq)
 		if err != nil {
 			PactLogger.Errorf(nil, "verification result retrieve request failed, provider service cannot be found.")
-			return &RetrieveVerificationResponse{
+			return &brokerpb.RetrieveVerificationResponse{
 				Response: pb.CreateResponse(scerr.ErrInvalidParams, "provider service cannot be found."),
 			}, err
 		}
 		providerName := resp.ServiceId
-		verificationDetail := &VerificationDetail{
+		verificationDetail := &brokerpb.VerificationDetail{
 			ProviderName:               providerName,
 			ProviderApplicationVersion: lastVerificationResult.ProviderVersion,
 			Success:                    lastVerificationResult.Success,
@@ -571,20 +574,20 @@ func (*BrokerService) RetrieveVerificationResults(ctx context.Context, in *Retri
 		}
 		overAllSuccess = overAllSuccess && verificationDetail.Success
 	}
-	verificationDetails := &VerificationDetails{VerificationResults: verificationDetailsArr}
-	verificationSummary := &VerificationSummary{Successful: successfuls, Failed: fails, Unknown: unknowns}
-	verificationResult := &VerificationResult{Success: overAllSuccess, ProviderSummary: verificationSummary, XEmbedded: verificationDetails}
+	verificationDetails := &brokerpb.VerificationDetails{VerificationResults: verificationDetailsArr}
+	verificationSummary := &brokerpb.VerificationSummary{Successful: successfuls, Failed: fails, Unknown: unknowns}
+	verificationResult := &brokerpb.VerificationResult{Success: overAllSuccess, ProviderSummary: verificationSummary, XEmbedded: verificationDetails}
 	PactLogger.Infof("Verification result retrieved successfully ...")
-	return &RetrieveVerificationResponse{
+	return &brokerpb.RetrieveVerificationResponse{
 		Response: pb.CreateResponse(pb.Response_SUCCESS, "Verification result retrieved successfully."),
 		Result:   verificationResult,
 	}, nil
 }
 
-func (*BrokerService) PublishVerificationResults(ctx context.Context, in *PublishVerificationRequest) (*PublishVerificationResponse, error) {
+func (*BrokerService) PublishVerificationResults(ctx context.Context, in *brokerpb.PublishVerificationRequest) (*brokerpb.PublishVerificationResponse, error) {
 	if in == nil || len(in.ProviderId) == 0 || len(in.ConsumerId) == 0 {
 		PactLogger.Errorf(nil, "verification result publish request failed: invalid params.")
-		return &PublishVerificationResponse{
+		return &brokerpb.PublishVerificationResponse{
 			Response: pb.CreateResponse(scerr.ErrInvalidParams, "Request format invalid."),
 		}, nil
 	}
@@ -592,13 +595,13 @@ func (*BrokerService) PublishVerificationResults(ctx context.Context, in *Publis
 	consumer, err := serviceUtil.GetService(ctx, tenant, in.ConsumerId)
 	if err != nil {
 		PactLogger.Errorf(err, "verification result publish request failed, consumerId is %s: query consumer failed.", in.ConsumerId)
-		return &PublishVerificationResponse{
+		return &brokerpb.PublishVerificationResponse{
 			Response: pb.CreateResponse(scerr.ErrInvalidParams, "Query consumer failed."),
 		}, err
 	}
 	if consumer == nil {
 		PactLogger.Errorf(nil, "verification result publish request failed, consumerId is %s: consumer not exist.", in.ConsumerId)
-		return &PublishVerificationResponse{
+		return &brokerpb.PublishVerificationResponse{
 			Response: pb.CreateResponse(scerr.ErrInvalidParams, "Consumer does not exist."),
 		}, nil
 	}
@@ -607,7 +610,7 @@ func (*BrokerService) PublishVerificationResults(ctx context.Context, in *Publis
 	consumerParticipant, err := GetParticipant(ctx, tenant, consumer.AppId, consumer.ServiceName)
 	if err != nil || consumerParticipant == nil {
 		PactLogger.Errorf(nil, "verification result publish request failed, consumer participant cannot be searched.", in.ConsumerId)
-		return &PublishVerificationResponse{
+		return &brokerpb.PublishVerificationResponse{
 			Response: pb.CreateResponse(scerr.ErrInvalidParams, "consumer participant cannot be searched."),
 		}, err
 	}
@@ -616,7 +619,7 @@ func (*BrokerService) PublishVerificationResults(ctx context.Context, in *Publis
 	version, err := GetVersion(ctx, tenant, consumer.Version, consumerParticipant.Id)
 	if err != nil || version == nil {
 		PactLogger.Errorf(nil, "verification result publish request failed, version cannot be searched.")
-		return &PublishVerificationResponse{
+		return &brokerpb.PublishVerificationResponse{
 			Response: pb.CreateResponse(scerr.ErrInvalidParams, "version cannot be searched."),
 		}, err
 	}
@@ -628,17 +631,17 @@ func (*BrokerService) PublishVerificationResults(ctx context.Context, in *Publis
 
 	if err != nil || len(pacts.Kvs) == 0 {
 		PactLogger.Errorf(nil, "verification result publish request failed, pact cannot be searched.")
-		return &PublishVerificationResponse{
+		return &brokerpb.PublishVerificationResponse{
 			Response: pb.CreateResponse(scerr.ErrInvalidParams, "pact cannot be searched."),
 		}, err
 	}
 	pactExists := false
 	for i := 0; i < len(pacts.Kvs); i++ {
-		pact := &Pact{}
+		pact := &brokerpb.Pact{}
 		err = json.Unmarshal(pacts.Kvs[i].Value.([]byte), &pact)
 		if err != nil {
 			PactLogger.Errorf(nil, "verification result publish request failed, pact cannot be searched.")
-			return &PublishVerificationResponse{
+			return &brokerpb.PublishVerificationResponse{
 				Response: pb.CreateResponse(scerr.ErrInvalidParams, "pact cannot be searched."),
 			}, err
 		}
@@ -648,14 +651,14 @@ func (*BrokerService) PublishVerificationResults(ctx context.Context, in *Publis
 	}
 	if pactExists == false {
 		PactLogger.Errorf(nil, "verification result publish request failed, pact does not exists.")
-		return &PublishVerificationResponse{
+		return &brokerpb.PublishVerificationResponse{
 			Response: pb.CreateResponse(scerr.ErrInvalidParams, "pact does not exists."),
 		}, err
 	}
 	pactVersion, err := GetPactVersion(ctx, tenant, version.Id, in.PactId)
 	if err != nil || pactVersion == nil {
 		PactLogger.Errorf(nil, "verification result publish request failed, pact version cannot be searched.")
-		return &PublishVerificationResponse{
+		return &brokerpb.PublishVerificationResponse{
 			Response: pb.CreateResponse(scerr.ErrInvalidParams, "pact version cannot be searched."),
 		}, err
 	}
@@ -667,18 +670,18 @@ func (*BrokerService) PublishVerificationResults(ctx context.Context, in *Publis
 
 	if err != nil {
 		PactLogger.Errorf(nil, "verification result publish request failed, verification result cannot be searched.")
-		return &PublishVerificationResponse{
+		return &brokerpb.PublishVerificationResponse{
 			Response: pb.CreateResponse(scerr.ErrInvalidParams, "verification result cannot be searched."),
 		}, err
 	}
 	lastNumber := int32(math.MinInt32)
 	if len(verifications.Kvs) != 0 {
 		for i := 0; i < len(verifications.Kvs); i++ {
-			verification := &Verification{}
+			verification := &brokerpb.Verification{}
 			err = json.Unmarshal(verifications.Kvs[i].Value.([]byte), &verification)
 			if err != nil {
 				PactLogger.Errorf(nil, "verification result publish request failed, verification result unmarshall error.")
-				return &PublishVerificationResponse{
+				return &brokerpb.PublishVerificationResponse{
 					Response: pb.CreateResponse(scerr.ErrInvalidParams, "verification result unmarshall error."),
 				}, err
 			}
@@ -695,7 +698,7 @@ func (*BrokerService) PublishVerificationResults(ctx context.Context, in *Publis
 	verificationDate := time.Now().Format(time.RFC3339)
 	verificationKey := GenerateBrokerVerificationKey(tenant, pactVersion.Id, lastNumber)
 	id, err := GetData(ctx, GetBrokerLatestVerificationIDKey())
-	verification := &Verification{
+	verification := &brokerpb.Verification{
 		Id:               int32(id) + 1,
 		Number:           lastNumber,
 		PactVersionId:    pactVersion.Id,
@@ -711,23 +714,23 @@ func (*BrokerService) PublishVerificationResults(ctx context.Context, in *Publis
 	PactLogger.Infof("Verification result inserted: (%d, %d, %d, %t, %s, %s, %s)",
 		verification.Id, verification.Number, verification.PactVersionId,
 		verification.Success, verification.ProviderVersion, verification.BuildUrl, verification.VerificationDate)
-	verificationResponse := &VerificationDetail{
+	verificationResponse := &brokerpb.VerificationDetail{
 		ProviderName:               in.ProviderId,
 		ProviderApplicationVersion: verification.ProviderVersion,
 		Success:                    verification.Success,
 		VerificationDate:           verification.VerificationDate,
 	}
 	PactLogger.Infof("Verification result published successfully ...")
-	return &PublishVerificationResponse{
+	return &brokerpb.PublishVerificationResponse{
 		Response:     pb.CreateResponse(pb.Response_SUCCESS, "Verification result published successfully."),
 		Confirmation: verificationResponse,
 	}, nil
 }
 
-func (*BrokerService) PublishPact(ctx context.Context, in *PublishPactRequest) (*PublishPactResponse, error) {
+func (*BrokerService) PublishPact(ctx context.Context, in *brokerpb.PublishPactRequest) (*brokerpb.PublishPactResponse, error) {
 	if in == nil || len(in.ProviderId) == 0 || len(in.ConsumerId) == 0 || len(in.Version) == 0 || len(in.Pact) == 0 {
 		PactLogger.Errorf(nil, "pact publish request failed: invalid params.")
-		return &PublishPactResponse{
+		return &brokerpb.PublishPactResponse{
 			Response: pb.CreateResponse(scerr.ErrInvalidParams, "Request format invalid."),
 		}, nil
 	}
@@ -736,13 +739,13 @@ func (*BrokerService) PublishPact(ctx context.Context, in *PublishPactRequest) (
 	provider, err := serviceUtil.GetService(ctx, tenant, in.ProviderId)
 	if err != nil {
 		PactLogger.Errorf(err, "pact publish failed, providerId is %s: query provider failed.", in.ProviderId)
-		return &PublishPactResponse{
+		return &brokerpb.PublishPactResponse{
 			Response: pb.CreateResponse(scerr.ErrInvalidParams, "Query provider failed."),
 		}, err
 	}
 	if provider == nil {
 		PactLogger.Errorf(nil, "pact publish failed, providerId is %s: provider not exist.", in.ProviderId)
-		return &PublishPactResponse{
+		return &brokerpb.PublishPactResponse{
 			Response: pb.CreateResponse(scerr.ErrInvalidParams, "Provider does not exist."),
 		}, nil
 	}
@@ -750,13 +753,13 @@ func (*BrokerService) PublishPact(ctx context.Context, in *PublishPactRequest) (
 	consumer, err := serviceUtil.GetService(ctx, tenant, in.ConsumerId)
 	if err != nil {
 		PactLogger.Errorf(err, "pact publish failed, consumerId is %s: query consumer failed.", in.ConsumerId)
-		return &PublishPactResponse{
+		return &brokerpb.PublishPactResponse{
 			Response: pb.CreateResponse(scerr.ErrInvalidParams, "Query consumer failed."),
 		}, err
 	}
 	if consumer == nil {
 		PactLogger.Errorf(nil, "pact publish failed, consumerId is %s: consumer not exist.", in.ConsumerId)
-		return &PublishPactResponse{
+		return &brokerpb.PublishPactResponse{
 			Response: pb.CreateResponse(scerr.ErrInvalidParams, "Consumer does not exist."),
 		}, nil
 	}
@@ -765,7 +768,7 @@ func (*BrokerService) PublishPact(ctx context.Context, in *PublishPactRequest) (
 	if strings.Compare(consumer.GetVersion(), in.Version) != 0 {
 		util.Logger().Errorf(nil,
 			"pact publish failed, version (%s) does not exist for consmer", in.Version)
-		return &PublishPactResponse{
+		return &brokerpb.PublishPactResponse{
 			Response: pb.CreateResponse(scerr.ErrInvalidParams, "Consumer Version does not exist."),
 		}, nil
 	}
@@ -776,13 +779,13 @@ func (*BrokerService) PublishPact(ctx context.Context, in *PublishPactRequest) (
 	providerParticipant, err := GetParticipant(ctx, tenant, provider.AppId, provider.ServiceName)
 	if err != nil {
 		PactLogger.Errorf(nil, "pact publish failed, provider participant cannot be searched.", in.ProviderId)
-		return &PublishPactResponse{
+		return &brokerpb.PublishPactResponse{
 			Response: pb.CreateResponse(scerr.ErrInvalidParams, "Provider participant cannot be searched."),
 		}, err
 	}
 	if providerParticipant == nil {
 		id, err := GetData(ctx, GetBrokerLatestParticipantIDKey())
-		providerParticipant = &Participant{Id: int32(id) + 1, AppId: provider.AppId, ServiceName: provider.ServiceName}
+		providerParticipant = &brokerpb.Participant{Id: int32(id) + 1, AppId: provider.AppId, ServiceName: provider.ServiceName}
 		response, err := CreateParticipant(PactLogger, ctx, providerParticipantKey, *providerParticipant)
 		if err != nil {
 			return response, err
@@ -794,13 +797,13 @@ func (*BrokerService) PublishPact(ctx context.Context, in *PublishPactRequest) (
 	consumerParticipant, err := GetParticipant(ctx, tenant, consumer.AppId, consumer.ServiceName)
 	if err != nil {
 		PactLogger.Errorf(nil, "pact publish failed, consumer participant cannot be searched.", in.ConsumerId)
-		return &PublishPactResponse{
+		return &brokerpb.PublishPactResponse{
 			Response: pb.CreateResponse(scerr.ErrInvalidParams, "consumer participant cannot be searched."),
 		}, err
 	}
 	if consumerParticipant == nil {
 		id, err := GetData(ctx, GetBrokerLatestParticipantIDKey())
-		consumerParticipant = &Participant{Id: int32(id) + 1, AppId: consumer.AppId, ServiceName: consumer.ServiceName}
+		consumerParticipant = &brokerpb.Participant{Id: int32(id) + 1, AppId: consumer.AppId, ServiceName: consumer.ServiceName}
 		response, err := CreateParticipant(PactLogger, ctx, consumerParticipantKey, *consumerParticipant)
 		if err != nil {
 			return response, err
@@ -812,7 +815,7 @@ func (*BrokerService) PublishPact(ctx context.Context, in *PublishPactRequest) (
 	version, err := GetVersion(ctx, tenant, in.Version, consumerParticipant.Id)
 	if err != nil {
 		PactLogger.Errorf(nil, "pact publish failed, version cannot be searched.")
-		return &PublishPactResponse{
+		return &brokerpb.PublishPactResponse{
 			Response: pb.CreateResponse(scerr.ErrInvalidParams, "version cannot be searched."),
 		}, err
 	}
@@ -821,7 +824,7 @@ func (*BrokerService) PublishPact(ctx context.Context, in *PublishPactRequest) (
 		PactLogger.Infof("Old version order: %d", order)
 		order++
 		id, err := GetData(ctx, GetBrokerLatestVersionIDKey())
-		version = &Version{Id: int32(id) + 1, Number: in.Version, ParticipantId: consumerParticipant.Id, Order: order}
+		version = &brokerpb.Version{Id: int32(id) + 1, Number: in.Version, ParticipantId: consumerParticipant.Id, Order: order}
 		response, err := CreateVersion(PactLogger, ctx, versionKey, *version)
 		if err != nil {
 			return response, err
@@ -835,13 +838,13 @@ func (*BrokerService) PublishPact(ctx context.Context, in *PublishPactRequest) (
 	pact, err := GetPact(ctx, tenant, consumerParticipant.Id, providerParticipant.Id, sha)
 	if err != nil {
 		PactLogger.Errorf(nil, "pact publish failed, pact cannot be searched.")
-		return &PublishPactResponse{
+		return &brokerpb.PublishPactResponse{
 			Response: pb.CreateResponse(scerr.ErrInvalidParams, "pact cannot be searched."),
 		}, err
 	}
 	if pact == nil {
 		id, err := GetData(ctx, GetBrokerLatestPactIDKey())
-		pact = &Pact{Id: int32(id) + 1, ConsumerParticipantId: consumerParticipant.Id,
+		pact = &brokerpb.Pact{Id: int32(id) + 1, ConsumerParticipantId: consumerParticipant.Id,
 			ProviderParticipantId: providerParticipant.Id, Sha: sha, Content: in.Pact}
 		response, err := CreatePact(PactLogger, ctx, pactKey, *pact)
 		if err != nil {
@@ -854,13 +857,13 @@ func (*BrokerService) PublishPact(ctx context.Context, in *PublishPactRequest) (
 	pactVersion, err := GetPactVersion(ctx, tenant, version.Id, pact.Id)
 	if err != nil {
 		PactLogger.Errorf(nil, "pact publish failed, pact version cannot be searched.")
-		return &PublishPactResponse{
+		return &brokerpb.PublishPactResponse{
 			Response: pb.CreateResponse(scerr.ErrInvalidParams, "pact version cannot be searched."),
 		}, err
 	}
 	if pactVersion == nil {
 		id, err := GetData(ctx, GetBrokerLatestPactVersionIDKey())
-		pactVersion = &PactVersion{Id: int32(id) + 1, VersionId: version.Id, PactId: pact.Id, ProviderParticipantId: providerParticipant.Id}
+		pactVersion = &brokerpb.PactVersion{Id: int32(id) + 1, VersionId: version.Id, PactId: pact.Id, ProviderParticipantId: providerParticipant.Id}
 		response, err := CreatePactVersion(PactLogger, ctx, pactVersionKey, *pactVersion)
 		if err != nil {
 			return response, err
@@ -868,7 +871,7 @@ func (*BrokerService) PublishPact(ctx context.Context, in *PublishPactRequest) (
 	}
 	PactLogger.Infof("PactVersion found/create: (%d, %d, %d, %d)", pactVersion.Id, pactVersion.VersionId, pactVersion.PactId, pactVersion.ProviderParticipantId)
 	PactLogger.Infof("Pact published successfully ...")
-	return &PublishPactResponse{
+	return &brokerpb.PublishPactResponse{
 		Response: pb.CreateResponse(pb.Response_SUCCESS, "Pact published successfully."),
 	}, nil
 }
diff --git a/server/broker/service_test.go b/server/broker/service_test.go
index ee27320..001bfa5 100644
--- a/server/broker/service_test.go
+++ b/server/broker/service_test.go
@@ -20,6 +20,8 @@ import (
 	"fmt"
 
 	"github.com/apache/incubator-servicecomb-service-center/pkg/util"
+	"github.com/apache/incubator-servicecomb-service-center/server/broker/brokerpb"
+	"github.com/apache/incubator-servicecomb-service-center/server/core"
 	pb "github.com/apache/incubator-servicecomb-service-center/server/core/proto"
 	serviceUtil "github.com/apache/incubator-servicecomb-service-center/server/service/util"
 	. "github.com/onsi/ginkgo"
@@ -28,9 +30,8 @@ import (
 )
 
 const (
-	TEST_BROKER_NO_SERVICE_ID      = "noServiceId"
-	TEST_BROKER_NO_VERSION         = "noVersion"
-	TEST_BROKER_TOO_LONG_SERVICEID = "addasdfasaddasdfasaddasdfasaddasdfasaddasdfasaddasdfasaddasdfasadafd"
+	TEST_BROKER_NO_SERVICE_ID = "noServiceId"
+	TEST_BROKER_NO_VERSION    = "noVersion"
 	//Consumer
 	TEST_BROKER_CONSUMER_VERSION = "4.0.0"
 	TEST_BROKER_CONSUMER_NAME    = "broker_name_consumer"
@@ -51,7 +52,7 @@ var _ = Describe("BrokerController", func() {
 				fmt.Println("UT===========PublishPact")
 
 				//(1) create consumer service
-				resp, err := serviceResource.Create(getContext(), &pb.CreateServiceRequest{
+				resp, err := core.ServiceAPI.Create(getContext(), &pb.CreateServiceRequest{
 					Service: &pb.MicroService{
 						ServiceName: TEST_BROKER_CONSUMER_NAME,
 						AppId:       TEST_BROKER_CONSUMER_APP,
@@ -69,7 +70,7 @@ var _ = Describe("BrokerController", func() {
 				Expect(resp.GetResponse().Code).To(Equal(pb.Response_SUCCESS))
 
 				//(2) create provider service
-				resp, err = serviceResource.Create(getContext(), &pb.CreateServiceRequest{
+				resp, err = core.ServiceAPI.Create(getContext(), &pb.CreateServiceRequest{
 					Service: &pb.MicroService{
 						ServiceName: TEST_BROKER_PROVIDER_NAME,
 						AppId:       TEST_BROKER_PROVIDER_APP,
@@ -88,7 +89,7 @@ var _ = Describe("BrokerController", func() {
 
 				//(3) publish a pact between two services
 				respPublishPact, err := brokerResource.PublishPact(getContext(),
-					&PublishPactRequest{
+					&brokerpb.PublishPactRequest{
 						ProviderId: providerServiceId,
 						ConsumerId: consumerServiceId,
 						Version:    TEST_BROKER_CONSUMER_VERSION,
@@ -103,7 +104,7 @@ var _ = Describe("BrokerController", func() {
 				fmt.Println("UT===========PublishPact, no provider serviceID")
 
 				//publish a pact between two services
-				respPublishPact, _ := brokerResource.PublishPact(getContext(), &PublishPactRequest{
+				respPublishPact, _ := brokerResource.PublishPact(getContext(), &brokerpb.PublishPactRequest{
 					ProviderId: TEST_BROKER_NO_SERVICE_ID,
 					ConsumerId: consumerServiceId,
 					Version:    TEST_BROKER_CONSUMER_VERSION,
@@ -117,7 +118,7 @@ var _ = Describe("BrokerController", func() {
 				fmt.Println("UT===========PublishPact, no consumer serviceID")
 
 				//publish a pact between two services
-				respPublishPact, _ := brokerResource.PublishPact(getContext(), &PublishPactRequest{
+				respPublishPact, _ := brokerResource.PublishPact(getContext(), &brokerpb.PublishPactRequest{
 					ProviderId: providerServiceId,
 					ConsumerId: TEST_BROKER_NO_SERVICE_ID,
 					Version:    TEST_BROKER_CONSUMER_VERSION,
@@ -131,7 +132,7 @@ var _ = Describe("BrokerController", func() {
 				fmt.Println("UT===========PublishPact, no consumer Version")
 
 				//publish a pact between two services
-				respPublishPact, _ := brokerResource.PublishPact(getContext(), &PublishPactRequest{
+				respPublishPact, _ := brokerResource.PublishPact(getContext(), &brokerpb.PublishPactRequest{
 					ProviderId: providerServiceId,
 					ConsumerId: consumerServiceId,
 					Version:    TEST_BROKER_NO_VERSION,
@@ -144,7 +145,7 @@ var _ = Describe("BrokerController", func() {
 			It("GetBrokerHome", func() {
 				fmt.Println("UT===========GetBrokerHome")
 
-				respGetHome, _ := brokerResource.GetBrokerHome(getContext(), &BaseBrokerRequest{
+				respGetHome, _ := brokerResource.GetBrokerHome(getContext(), &brokerpb.BaseBrokerRequest{
 					HostAddress: "localhost",
 					Scheme:      "http",
 				})
@@ -157,9 +158,9 @@ var _ = Describe("BrokerController", func() {
 				fmt.Println("UT===========GetBrokerAllProviderPacts")
 
 				respGetAllProviderPacts, _ := brokerResource.GetAllProviderPacts(getContext(),
-					&GetAllProviderPactsRequest{
+					&brokerpb.GetAllProviderPactsRequest{
 						ProviderId: providerServiceId,
-						BaseUrl: &BaseBrokerRequest{
+						BaseUrl: &brokerpb.BaseBrokerRequest{
 							HostAddress: "localhost",
 							Scheme:      "http",
 						}})
@@ -172,11 +173,11 @@ var _ = Describe("BrokerController", func() {
 				fmt.Println("UT===========GetBrokerPactsOfProvider")
 
 				respGetAllProviderPacts, _ := brokerResource.GetPactsOfProvider(getContext(),
-					&GetProviderConsumerVersionPactRequest{
+					&brokerpb.GetProviderConsumerVersionPactRequest{
 						ProviderId: providerServiceId,
 						ConsumerId: consumerServiceId,
 						Version:    TEST_BROKER_CONSUMER_VERSION,
-						BaseUrl: &BaseBrokerRequest{
+						BaseUrl: &brokerpb.BaseBrokerRequest{
 							HostAddress: "localhost",
 							Scheme:      "http",
 						}})
@@ -185,6 +186,51 @@ var _ = Describe("BrokerController", func() {
 				Expect(respGetAllProviderPacts.GetResponse().Code).To(Equal(pb.Response_SUCCESS))
 			})
 
+			It("PublishVerificationResults", func() {
+				fmt.Println("UT===========PublishVerificationResults")
+
+				id, err := GetData(context.Background(), GetBrokerLatestPactIDKey())
+				Expect(err).To(BeNil())
+				respResults, err := brokerResource.PublishVerificationResults(getContext(),
+					&brokerpb.PublishVerificationRequest{
+						ProviderId: providerServiceId,
+						ConsumerId: consumerServiceId,
+						PactId:     int32(id),
+						ProviderApplicationVersion: TEST_BROKER_PROVIDER_VERSION,
+					})
+
+				Expect(respResults).NotTo(BeNil())
+				Expect(respResults.GetResponse().Code).To(Equal(pb.Response_SUCCESS))
+			})
+
+			It("RetrieveVerificationResults", func() {
+				fmt.Println("UT===========RetrieveVerificationResults")
+
+				respVerification, _ := brokerResource.RetrieveVerificationResults(getContext(),
+					&brokerpb.RetrieveVerificationRequest{
+						ConsumerId:      consumerServiceId,
+						ConsumerVersion: TEST_BROKER_CONSUMER_VERSION,
+					})
+
+				Expect(respVerification).NotTo(BeNil())
+				Expect(respVerification.GetResponse().Code).To(Equal(pb.Response_SUCCESS))
+			})
+
+			It("RetrieveProviderPacts", func() {
+				fmt.Println("UT===========RetrieveProviderPacts")
+
+				respProviderPact, _ := brokerResource.RetrieveProviderPacts(getContext(),
+					&brokerpb.GetAllProviderPactsRequest{
+						ProviderId: providerServiceId,
+						BaseUrl: &brokerpb.BaseBrokerRequest{
+							HostAddress: "localhost",
+							Scheme:      "http",
+						},
+					})
+
+				Expect(respProviderPact).NotTo(BeNil())
+				Expect(respProviderPact.GetResponse().Code).To(Equal(pb.Response_SUCCESS))
+			})
 		})
 	})
 })
diff --git a/server/broker/store.go b/server/broker/store.go
index cb73923..0754c0c 100644
--- a/server/broker/store.go
+++ b/server/broker/store.go
@@ -33,13 +33,13 @@ var (
 var brokerKvStore = &BKvStore{}
 
 func init() {
-	PARTICIPANT = backend.Store().MustInstall(backend.NewEntity("PARTICIPANT", backend.DefaultConfig().WithPrefix(GetBrokerParticipantKey(""))))
-	VERSION = backend.Store().MustInstall(backend.NewEntity("VERSION", backend.DefaultConfig().WithPrefix(GetBrokerVersionKey(""))))
-	PACT = backend.Store().MustInstall(backend.NewEntity("PACT", backend.DefaultConfig().WithPrefix(GetBrokerPactKey(""))))
-	PACT_VERSION = backend.Store().MustInstall(backend.NewEntity("PACT_VERSION", backend.DefaultConfig().WithPrefix(GetBrokerPactVersionKey(""))))
-	PACT_TAG = backend.Store().MustInstall(backend.NewEntity("PACT_TAG", backend.DefaultConfig().WithPrefix(GetBrokerTagKey(""))))
-	VERIFICATION = backend.Store().MustInstall(backend.NewEntity("VERIFICATION", backend.DefaultConfig().WithPrefix(GetBrokerVerificationKey(""))))
-	PACT_LATEST = backend.Store().MustInstall(backend.NewEntity("PACT_LATEST", backend.DefaultConfig().WithPrefix(GetBrokerLatestKey(""))))
+	PARTICIPANT = backend.Store().MustInstall(backend.NewExtension("PARTICIPANT", backend.Configure().WithPrefix(GetBrokerParticipantKey(""))))
+	VERSION = backend.Store().MustInstall(backend.NewExtension("VERSION", backend.Configure().WithPrefix(GetBrokerVersionKey(""))))
+	PACT = backend.Store().MustInstall(backend.NewExtension("PACT", backend.Configure().WithPrefix(GetBrokerPactKey(""))))
+	PACT_VERSION = backend.Store().MustInstall(backend.NewExtension("PACT_VERSION", backend.Configure().WithPrefix(GetBrokerPactVersionKey(""))))
+	PACT_TAG = backend.Store().MustInstall(backend.NewExtension("PACT_TAG", backend.Configure().WithPrefix(GetBrokerTagKey(""))))
+	VERIFICATION = backend.Store().MustInstall(backend.NewExtension("VERIFICATION", backend.Configure().WithPrefix(GetBrokerVerificationKey(""))))
+	PACT_LATEST = backend.Store().MustInstall(backend.NewExtension("PACT_LATEST", backend.Configure().WithPrefix(GetBrokerLatestKey(""))))
 
 }
 
@@ -47,31 +47,31 @@ type BKvStore struct {
 }
 
 func (s *BKvStore) Participant() backend.Indexer {
-	return backend.Store().Entity(PARTICIPANT)
+	return backend.Store().Entities(PARTICIPANT)
 }
 
 func (s *BKvStore) Version() backend.Indexer {
-	return backend.Store().Entity(VERSION)
+	return backend.Store().Entities(VERSION)
 }
 
 func (s *BKvStore) Pact() backend.Indexer {
-	return backend.Store().Entity(PACT)
+	return backend.Store().Entities(PACT)
 }
 
 func (s *BKvStore) PactVersion() backend.Indexer {
-	return backend.Store().Entity(PACT_VERSION)
+	return backend.Store().Entities(PACT_VERSION)
 }
 
 func (s *BKvStore) PactTag() backend.Indexer {
-	return backend.Store().Entity(PACT_TAG)
+	return backend.Store().Entities(PACT_TAG)
 }
 
 func (s *BKvStore) Verification() backend.Indexer {
-	return backend.Store().Entity(VERIFICATION)
+	return backend.Store().Entities(VERIFICATION)
 }
 
 func (s *BKvStore) PactLatest() backend.Indexer {
-	return backend.Store().Entity(PACT_LATEST)
+	return backend.Store().Entities(PACT_LATEST)
 }
 
 func Store() *BKvStore {
diff --git a/server/broker/util.go b/server/broker/util.go
index 3d398b5..8f8e70a 100644
--- a/server/broker/util.go
+++ b/server/broker/util.go
@@ -19,7 +19,6 @@ package broker
 import (
 	"context"
 	"encoding/json"
-	"errors"
 	"math"
 	"net/url"
 	"strconv"
@@ -27,6 +26,7 @@ import (
 
 	"github.com/ServiceComb/paas-lager/third_party/forked/cloudfoundry/lager"
 	"github.com/apache/incubator-servicecomb-service-center/pkg/util"
+	"github.com/apache/incubator-servicecomb-service-center/server/broker/brokerpb"
 	"github.com/apache/incubator-servicecomb-service-center/server/core"
 	"github.com/apache/incubator-servicecomb-service-center/server/core/backend"
 	pb "github.com/apache/incubator-servicecomb-service-center/server/core/proto"
@@ -132,27 +132,27 @@ func GetBrokerHomeLinksAPIS(scheme string, host string, apiKey string) string {
 }
 
 //CreateBrokerHomeResponse create the templated broker home response
-func CreateBrokerHomeResponse(host string, scheme string) *BrokerHomeResponse {
+func CreateBrokerHomeResponse(host string, scheme string) *brokerpb.BrokerHomeResponse {
 
-	var apiEntries map[string]*BrokerAPIInfoEntry
-	apiEntries = make(map[string]*BrokerAPIInfoEntry)
+	var apiEntries map[string]*brokerpb.BrokerAPIInfoEntry
+	apiEntries = make(map[string]*brokerpb.BrokerAPIInfoEntry)
 
 	for k := range brokerAPILinksValues {
-		apiEntries[k] = &BrokerAPIInfoEntry{
+		apiEntries[k] = &brokerpb.BrokerAPIInfoEntry{
 			Href:      GetBrokerHomeLinksAPIS(scheme, host, k),
 			Title:     brokerAPILinksTitles[k],
 			Templated: brokerAPILinksTempl[k],
 		}
 	}
 
-	curies := []*BrokerAPIInfoEntry{}
-	curies = append(curies, &BrokerAPIInfoEntry{
+	curies := []*brokerpb.BrokerAPIInfoEntry{}
+	curies = append(curies, &brokerpb.BrokerAPIInfoEntry{
 		Name: "pb",
 		Href: GenerateBrokerAPIPath(scheme, host, BROKER_CURIES_URL,
 			strings.NewReplacer(":rel", "{rel}")),
 	})
 
-	return &BrokerHomeResponse{
+	return &brokerpb.BrokerHomeResponse{
 		Response: pb.CreateResponse(pb.Response_SUCCESS, "Broker Home."),
 		XLinks:   apiEntries,
 		Curies:   curies,
@@ -160,7 +160,7 @@ func CreateBrokerHomeResponse(host string, scheme string) *BrokerHomeResponse {
 }
 
 //GetBrokerHomeResponse gets the homeResponse from cache if it exists
-func GetBrokerHomeResponse(host string, scheme string) *BrokerHomeResponse {
+func GetBrokerHomeResponse(host string, scheme string) *brokerpb.BrokerHomeResponse {
 	brokerResp := CreateBrokerHomeResponse(host, scheme)
 	if brokerResp == nil {
 		return nil
@@ -168,87 +168,8 @@ func GetBrokerHomeResponse(host string, scheme string) *BrokerHomeResponse {
 	return brokerResp
 }
 
-//GetBrokerParticipantUtils returns the participant from ETCD
-func GetBrokerParticipantUtils(ctx context.Context, tenant string, appId string,
-	serviceName string, opts ...registry.PluginOpOption) (*Participant, error) {
-
-	key := GenerateBrokerParticipantKey(tenant, appId, serviceName)
-	opts = append(opts, registry.WithStrKey(key))
-	participants, err := Store().Participant().Search(ctx, opts...)
-
-	if err != nil {
-		PactLogger.Errorf(nil, "pact publish failed, participant with, could not be searched.")
-		return nil, err
-	}
-
-	if len(participants.Kvs) == 0 {
-		PactLogger.Info("GetParticipant found no participant")
-		return nil, nil
-	}
-
-	participant := &Participant{}
-	err = json.Unmarshal(participants.Kvs[0].Value.([]byte), participant)
-	if err != nil {
-		return nil, err
-	}
-	PactLogger.Infof("GetParticipant: (%d, %s, %s)", participant.Id, participant.AppId,
-		participant.ServiceName)
-	return participant, nil
-}
-
-//GetBrokerParticipantFromServiceId returns the participant and the service from ETCD
-func GetBrokerParticipantFromServiceId(ctx context.Context, serviceId string) (*Participant,
-	*pb.MicroService, error, error) {
-
-	tenant := GetDefaultTenantProject()
-	serviceParticipant, err := serviceUtil.GetService(ctx, tenant, serviceId)
-	if err != nil {
-		PactLogger.Errorf(err,
-			"get participant failed, serviceId is %s: query provider failed.", serviceId)
-		return nil, nil, nil, err
-	}
-	if serviceParticipant == nil {
-		PactLogger.Errorf(nil,
-			"get participant failed, serviceId is %s: service not exist.", serviceId)
-		return nil, nil, nil, errors.New("get participant, serviceId not exist.")
-	}
-	// Get or create provider participant
-	participant, errBroker := GetBrokerParticipantUtils(ctx, tenant, serviceParticipant.AppId,
-		serviceParticipant.ServiceName)
-	if errBroker != nil {
-		PactLogger.Errorf(errBroker,
-			"get participant failed, serviceId %s: query participant failed.", serviceId)
-		return nil, serviceParticipant, errBroker, err
-	}
-	if participant == nil {
-		PactLogger.Errorf(nil,
-			"get participant failed, particpant does not exist for serviceId %s", serviceId)
-		return nil, serviceParticipant, errors.New("particpant does not exist for serviceId."), err
-	}
-
-	return participant, serviceParticipant, errBroker, nil
-}
-
-//GetBrokerParticipantFromService returns the participant given the microservice
-func GetBrokerParticipantFromService(ctx context.Context,
-	microservice *pb.MicroService) (*Participant, error) {
-	if microservice == nil {
-		return nil, nil
-	}
-	tenant := GetDefaultTenantProject()
-	participant, errBroker := GetBrokerParticipantUtils(ctx, tenant, microservice.AppId,
-		microservice.ServiceName)
-	if errBroker != nil {
-		PactLogger.Errorf(errBroker,
-			"get participant failed, serviceId %s: query participant failed.",
-			microservice.ServiceId)
-		return nil, errBroker
-	}
-	return participant, errBroker
-}
-
 func GetParticipant(ctx context.Context, domain string, appId string,
-	serviceName string) (*Participant, error) {
+	serviceName string) (*brokerpb.Participant, error) {
 	key := GenerateBrokerParticipantKey(domain, appId, serviceName)
 	participants, err := Store().Participant().Search(ctx, registry.WithStrKey(key))
 	if err != nil {
@@ -258,7 +179,7 @@ func GetParticipant(ctx context.Context, domain string, appId string,
 		PactLogger.Info("GetParticipant found no participant")
 		return nil, nil
 	}
-	participant := &Participant{}
+	participant := &brokerpb.Participant{}
 	err = json.Unmarshal(participants.Kvs[0].Value.([]byte), participant)
 	if err != nil {
 		return nil, err
@@ -268,7 +189,7 @@ func GetParticipant(ctx context.Context, domain string, appId string,
 }
 
 func GetVersion(ctx context.Context, domain string, number string,
-	participantId int32) (*Version, error) {
+	participantId int32) (*brokerpb.Version, error) {
 	key := GenerateBrokerVersionKey(domain, number, participantId)
 	versions, err := Store().Version().Search(ctx, registry.WithStrKey(key))
 	if err != nil {
@@ -277,7 +198,7 @@ func GetVersion(ctx context.Context, domain string, number string,
 	if len(versions.Kvs) == 0 {
 		return nil, nil
 	}
-	version := &Version{}
+	version := &brokerpb.Version{}
 	err = json.Unmarshal(versions.Kvs[0].Value.([]byte), version)
 	if err != nil {
 		return nil, err
@@ -286,7 +207,7 @@ func GetVersion(ctx context.Context, domain string, number string,
 	return version, nil
 }
 
-func GetPact(ctx context.Context, domain string, consumerParticipantId int32, producerParticipantId int32, sha []byte) (*Pact, error) {
+func GetPact(ctx context.Context, domain string, consumerParticipantId int32, producerParticipantId int32, sha []byte) (*brokerpb.Pact, error) {
 	key := GenerateBrokerPactKey(domain, consumerParticipantId, producerParticipantId, sha)
 	versions, err := Store().Pact().Search(ctx, registry.WithStrKey(key))
 	if err != nil {
@@ -295,7 +216,7 @@ func GetPact(ctx context.Context, domain string, consumerParticipantId int32, pr
 	if len(versions.Kvs) == 0 {
 		return nil, nil
 	}
-	pact := &Pact{}
+	pact := &brokerpb.Pact{}
 	err = json.Unmarshal(versions.Kvs[0].Value.([]byte), pact)
 	if err != nil {
 		return nil, err
@@ -305,7 +226,7 @@ func GetPact(ctx context.Context, domain string, consumerParticipantId int32, pr
 }
 
 func GetPactVersion(ctx context.Context, domain string, versionId int32,
-	pactId int32) (*PactVersion, error) {
+	pactId int32) (*brokerpb.PactVersion, error) {
 	key := GenerateBrokerPactVersionKey(domain, versionId, pactId)
 	versions, err := Store().PactVersion().Search(ctx, registry.WithStrKey(key))
 	if err != nil {
@@ -314,7 +235,7 @@ func GetPactVersion(ctx context.Context, domain string, versionId int32,
 	if len(versions.Kvs) == 0 {
 		return nil, nil
 	}
-	pactVersion := &PactVersion{}
+	pactVersion := &brokerpb.PactVersion{}
 	err = json.Unmarshal(versions.Kvs[0].Value.([]byte), pactVersion)
 	if err != nil {
 		return nil, err
@@ -345,11 +266,11 @@ func StoreData(ctx context.Context, key string, value string) error {
 	return err
 }
 
-func CreateParticipant(pactLogger lager.Logger, ctx context.Context, participantKey string, participant Participant) (*PublishPactResponse, error) {
+func CreateParticipant(pactLogger lager.Logger, ctx context.Context, participantKey string, participant brokerpb.Participant) (*brokerpb.PublishPactResponse, error) {
 	data, err := json.Marshal(participant)
 	if err != nil {
 		PactLogger.Errorf(nil, "pact publish failed, participant cannot be created.")
-		return &PublishPactResponse{
+		return &brokerpb.PublishPactResponse{
 			Response: pb.CreateResponse(scerr.ErrInternal, "participant cannot be created."),
 		}, err
 	}
@@ -360,7 +281,7 @@ func CreateParticipant(pactLogger lager.Logger, ctx context.Context, participant
 
 	if err != nil {
 		PactLogger.Errorf(nil, "pact publish failed, participant cannot be created.")
-		return &PublishPactResponse{
+		return &brokerpb.PublishPactResponse{
 			Response: pb.CreateResponse(scerr.ErrInternal, "participant cannot be created."),
 		}, err
 	}
@@ -371,7 +292,7 @@ func CreateParticipant(pactLogger lager.Logger, ctx context.Context, participant
 	err = StoreData(ctx, k, v)
 	if err != nil {
 		PactLogger.Errorf(nil, "pact publish failed, participant cannot be created.")
-		return &PublishPactResponse{
+		return &brokerpb.PublishPactResponse{
 			Response: pb.CreateResponse(scerr.ErrInternal, "participant cannot be created."),
 		}, err
 	}
@@ -380,11 +301,11 @@ func CreateParticipant(pactLogger lager.Logger, ctx context.Context, participant
 }
 
 func CreateVersion(pactLogger lager.Logger, ctx context.Context, versionKey string,
-	version Version) (*PublishPactResponse, error) {
+	version brokerpb.Version) (*brokerpb.PublishPactResponse, error) {
 	data, err := json.Marshal(version)
 	if err != nil {
 		PactLogger.Errorf(nil, "pact publish failed, version cannot be created.")
-		return &PublishPactResponse{
+		return &brokerpb.PublishPactResponse{
 			Response: pb.CreateResponse(scerr.ErrInternal, "version cannot be created."),
 		}, err
 	}
@@ -394,7 +315,7 @@ func CreateVersion(pactLogger lager.Logger, ctx context.Context, versionKey stri
 		registry.WithValue(data))
 	if err != nil {
 		PactLogger.Errorf(nil, "pact publish failed, version cannot be created.")
-		return &PublishPactResponse{
+		return &brokerpb.PublishPactResponse{
 			Response: pb.CreateResponse(scerr.ErrInternal, "version cannot be created."),
 		}, err
 	}
@@ -404,7 +325,7 @@ func CreateVersion(pactLogger lager.Logger, ctx context.Context, versionKey stri
 	err = StoreData(ctx, k, v)
 	if err != nil {
 		PactLogger.Errorf(nil, "pact publish failed, version cannot be created.")
-		return &PublishPactResponse{
+		return &brokerpb.PublishPactResponse{
 			Response: pb.CreateResponse(scerr.ErrInternal, "version cannot be created."),
 		}, err
 	}
@@ -413,11 +334,11 @@ func CreateVersion(pactLogger lager.Logger, ctx context.Context, versionKey stri
 }
 
 func CreatePact(pactLogger lager.Logger, ctx context.Context,
-	pactKey string, pact Pact) (*PublishPactResponse, error) {
+	pactKey string, pact brokerpb.Pact) (*brokerpb.PublishPactResponse, error) {
 	data, err := json.Marshal(pact)
 	if err != nil {
 		PactLogger.Errorf(nil, "pact publish failed, pact cannot be created.")
-		return &PublishPactResponse{
+		return &brokerpb.PublishPactResponse{
 			Response: pb.CreateResponse(scerr.ErrInternal, "pact cannot be created."),
 		}, err
 	}
@@ -429,7 +350,7 @@ func CreatePact(pactLogger lager.Logger, ctx context.Context,
 
 	if err != nil {
 		PactLogger.Errorf(nil, "pact publish failed, pact cannot be created.")
-		return &PublishPactResponse{
+		return &brokerpb.PublishPactResponse{
 			Response: pb.CreateResponse(scerr.ErrInternal, "pact cannot be created."),
 		}, err
 	}
@@ -439,7 +360,7 @@ func CreatePact(pactLogger lager.Logger, ctx context.Context,
 	err = StoreData(ctx, k, v)
 	if err != nil {
 		PactLogger.Errorf(nil, "pact publish failed, pact cannot be created.")
-		return &PublishPactResponse{
+		return &brokerpb.PublishPactResponse{
 			Response: pb.CreateResponse(scerr.ErrInternal, "pact cannot be created."),
 		}, err
 	}
@@ -447,11 +368,11 @@ func CreatePact(pactLogger lager.Logger, ctx context.Context,
 	return nil, nil
 }
 
-func CreatePactVersion(pactLogger lager.Logger, ctx context.Context, pactVersionKey string, pactVersion PactVersion) (*PublishPactResponse, error) {
+func CreatePactVersion(pactLogger lager.Logger, ctx context.Context, pactVersionKey string, pactVersion brokerpb.PactVersion) (*brokerpb.PublishPactResponse, error) {
 	data, err := json.Marshal(pactVersion)
 	if err != nil {
 		PactLogger.Errorf(nil, "pact publish failed, pact version cannot be created.")
-		return &PublishPactResponse{
+		return &brokerpb.PublishPactResponse{
 			Response: pb.CreateResponse(scerr.ErrInternal, "pact version cannot be created."),
 		}, err
 	}
@@ -460,7 +381,7 @@ func CreatePactVersion(pactLogger lager.Logger, ctx context.Context, pactVersion
 		registry.PUT, registry.WithValue(data), registry.WithStrKey(pactVersionKey))
 	if err != nil {
 		PactLogger.Errorf(nil, "pact publish failed, pact version cannot be created.")
-		return &PublishPactResponse{
+		return &brokerpb.PublishPactResponse{
 			Response: pb.CreateResponse(scerr.ErrInternal, "pact version cannot be created."),
 		}, err
 	}
@@ -470,7 +391,7 @@ func CreatePactVersion(pactLogger lager.Logger, ctx context.Context, pactVersion
 	err = StoreData(ctx, k, v)
 	if err != nil {
 		PactLogger.Errorf(nil, "pact publish failed, pact version cannot be created.")
-		return &PublishPactResponse{
+		return &brokerpb.PublishPactResponse{
 			Response: pb.CreateResponse(scerr.ErrInternal, "pact version cannot be created."),
 		}, err
 	}
@@ -479,11 +400,11 @@ func CreatePactVersion(pactLogger lager.Logger, ctx context.Context, pactVersion
 }
 
 func CreateVerification(pactLogger lager.Logger, ctx context.Context,
-	verificationKey string, verification Verification) (*PublishVerificationResponse, error) {
+	verificationKey string, verification brokerpb.Verification) (*brokerpb.PublishVerificationResponse, error) {
 	data, err := json.Marshal(verification)
 	if err != nil {
 		PactLogger.Errorf(nil, "verification result publish failed, verification result marshal error.")
-		return &PublishVerificationResponse{
+		return &brokerpb.PublishVerificationResponse{
 			Response: pb.CreateResponse(scerr.ErrInternal, "verification result marshal error."),
 		}, err
 	}
@@ -493,7 +414,7 @@ func CreateVerification(pactLogger lager.Logger, ctx context.Context,
 		registry.WithValue(data))
 	if err != nil {
 		PactLogger.Errorf(nil, "verification result publish failed, verification result cannot be created.")
-		return &PublishVerificationResponse{
+		return &brokerpb.PublishVerificationResponse{
 			Response: pb.CreateResponse(scerr.ErrInternal, "verification result cannot be created."),
 		}, err
 	}
@@ -503,7 +424,7 @@ func CreateVerification(pactLogger lager.Logger, ctx context.Context,
 	err = StoreData(ctx, k, v)
 	if err != nil {
 		PactLogger.Errorf(nil, "verification result publish failed, verification result cannot be created.")
-		return &PublishVerificationResponse{
+		return &brokerpb.PublishVerificationResponse{
 			Response: pb.CreateResponse(scerr.ErrInternal, "verification result cannot be created."),
 		}, err
 	}
@@ -524,7 +445,7 @@ func GetLastestVersionNumberForParticipant(ctx context.Context,
 	}
 	order := int32(math.MinInt32)
 	for i := 0; i < len(versions.Kvs); i++ {
-		version := &Version{}
+		version := &brokerpb.Version{}
 		err = json.Unmarshal(versions.Kvs[i].Value.([]byte), &version)
 		if err != nil {
 			return -1
@@ -540,10 +461,10 @@ func GetLastestVersionNumberForParticipant(ctx context.Context,
 }
 
 func RetrieveProviderConsumerPact(ctx context.Context,
-	in *GetProviderConsumerVersionPactRequest) (*GetProviderConsumerVersionPactResponse, int32, error) {
+	in *brokerpb.GetProviderConsumerVersionPactRequest) (*brokerpb.GetProviderConsumerVersionPactResponse, int32, error) {
 	if in == nil || len(in.ProviderId) == 0 || len(in.ConsumerId) == 0 || len(in.Version) == 0 {
 		PactLogger.Errorf(nil, "pact retrieve request failed: invalid params.")
-		return &GetProviderConsumerVersionPactResponse{
+		return &brokerpb.GetProviderConsumerVersionPactResponse{
 			Response: pb.CreateResponse(scerr.ErrInternal, "Request format invalid."),
 		}, -1, nil
 	}
@@ -552,13 +473,13 @@ func RetrieveProviderConsumerPact(ctx context.Context,
 	provider, err := serviceUtil.GetService(ctx, tenant, in.ProviderId)
 	if err != nil {
 		PactLogger.Errorf(err, "pact retrieve failed, providerId is %s: query provider failed.", in.ProviderId)
-		return &GetProviderConsumerVersionPactResponse{
+		return &brokerpb.GetProviderConsumerVersionPactResponse{
 			Response: pb.CreateResponse(scerr.ErrInternal, "Query provider failed."),
 		}, -1, err
 	}
 	if provider == nil {
 		PactLogger.Errorf(nil, "pact retrieve failed, providerId is %s: provider not exist.", in.ProviderId)
-		return &GetProviderConsumerVersionPactResponse{
+		return &brokerpb.GetProviderConsumerVersionPactResponse{
 			Response: pb.CreateResponse(scerr.ErrInternal, "Provider does not exist."),
 		}, -1, nil
 	}
@@ -566,13 +487,13 @@ func RetrieveProviderConsumerPact(ctx context.Context,
 	consumer, err := serviceUtil.GetService(ctx, tenant, in.ConsumerId)
 	if err != nil {
 		PactLogger.Errorf(err, "pact retrieve failed, consumerId is %s: query consumer failed.", in.ConsumerId)
-		return &GetProviderConsumerVersionPactResponse{
+		return &brokerpb.GetProviderConsumerVersionPactResponse{
 			Response: pb.CreateResponse(scerr.ErrInternal, "Query consumer failed."),
 		}, -1, err
 	}
 	if consumer == nil {
 		PactLogger.Errorf(nil, "pact retrieve failed, consumerId is %s: consumer not exist.", in.ConsumerId)
-		return &GetProviderConsumerVersionPactResponse{
+		return &brokerpb.GetProviderConsumerVersionPactResponse{
 			Response: pb.CreateResponse(scerr.ErrInternal, "Consumer does not exist."),
 		}, -1, nil
 	}
@@ -581,7 +502,7 @@ func RetrieveProviderConsumerPact(ctx context.Context,
 	providerParticipant, err := GetParticipant(ctx, tenant, provider.AppId, provider.ServiceName)
 	if err != nil || providerParticipant == nil {
 		PactLogger.Errorf(nil, "pact retrieve failed, provider participant %s cannot be searched.", in.ProviderId)
-		return &GetProviderConsumerVersionPactResponse{
+		return &brokerpb.GetProviderConsumerVersionPactResponse{
 			Response: pb.CreateResponse(scerr.ErrInternal, "Provider participant cannot be searched."),
 		}, -1, err
 	}
@@ -590,7 +511,7 @@ func RetrieveProviderConsumerPact(ctx context.Context,
 	consumerParticipant, err := GetParticipant(ctx, tenant, consumer.AppId, consumer.ServiceName)
 	if err != nil || consumerParticipant == nil {
 		PactLogger.Errorf(nil, "pact retrieve failed, consumer participant %s cannot be searched.", in.ConsumerId)
-		return &GetProviderConsumerVersionPactResponse{
+		return &brokerpb.GetProviderConsumerVersionPactResponse{
 			Response: pb.CreateResponse(scerr.ErrInternal, "consumer participant cannot be searched."),
 		}, -1, err
 	}
@@ -599,7 +520,7 @@ func RetrieveProviderConsumerPact(ctx context.Context,
 	version, err := GetVersion(ctx, tenant, in.Version, consumerParticipant.Id)
 	if err != nil || version == nil {
 		PactLogger.Errorf(nil, "pact retrieve failed, version cannot be searched.")
-		return &GetProviderConsumerVersionPactResponse{
+		return &brokerpb.GetProviderConsumerVersionPactResponse{
 			Response: pb.CreateResponse(scerr.ErrInternal, "version cannot be searched."),
 		}, -1, err
 	}
@@ -621,7 +542,7 @@ func RetrieveProviderConsumerPact(ctx context.Context,
 	}
 	pactIds := make(map[int32]int32)
 	for i := 0; i < len(pactVersions.Kvs); i++ {
-		pactVersion := &PactVersion{}
+		pactVersion := &brokerpb.PactVersion{}
 		err = json.Unmarshal(pactVersions.Kvs[i].Value.([]byte), pactVersion)
 		if err != nil {
 			return nil, -1, err
@@ -634,7 +555,7 @@ func RetrieveProviderConsumerPact(ctx context.Context,
 	}
 	if len(pactIds) == 0 {
 		PactLogger.Errorf(nil, "pact retrieve failed, pact cannot be found.")
-		return &GetProviderConsumerVersionPactResponse{
+		return &brokerpb.GetProviderConsumerVersionPactResponse{
 			Response: pb.CreateResponse(scerr.ErrInternal, "pact cannot be found."),
 		}, -1, err
 	}
@@ -643,7 +564,7 @@ func RetrieveProviderConsumerPact(ctx context.Context,
 		strconv.Itoa(int(consumerParticipant.Id)),
 		strconv.Itoa(int(providerParticipant.Id))},
 		"/")
-	pacts, err := Store().PactVersion().Search(ctx,
+	pacts, err := Store().Pact().Search(ctx,
 		registry.WithStrKey(pactKey),
 		registry.WithPrefix())
 
@@ -655,27 +576,27 @@ func RetrieveProviderConsumerPact(ctx context.Context,
 		return nil, -1, nil
 	}
 	for i := 0; i < len(pacts.Kvs); i++ {
-		pactObj := &Pact{}
+		pactObj := &brokerpb.Pact{}
 		err = json.Unmarshal(pacts.Kvs[i].Value.([]byte), pactObj)
 		if err != nil {
 			return nil, -1, err
 		}
 		if _, ok := pactIds[pactObj.Id]; ok {
 			//PactLogger.Infof("pact retrieve succeeded, found pact: %s", string(pactObj.Content))
-			return &GetProviderConsumerVersionPactResponse{
+			return &brokerpb.GetProviderConsumerVersionPactResponse{
 				Response: pb.CreateResponse(pb.Response_SUCCESS, "pact found."),
 				Pact:     pactObj.Content,
 			}, pactObj.Id, nil
 		}
 	}
 	PactLogger.Errorf(nil, "pact retrieve failed, pact cannot be found.")
-	return &GetProviderConsumerVersionPactResponse{
+	return &brokerpb.GetProviderConsumerVersionPactResponse{
 		Response: pb.CreateResponse(scerr.ErrInternal, "pact cannot be found."),
 	}, -1, nil
 }
 
 func DeletePactData(ctx context.Context,
-	in *BaseBrokerRequest) (*pb.Response, error) {
+	in *brokerpb.BaseBrokerRequest) (*pb.Response, error) {
 	//tenant := util.ParseTenantProject(ctx)
 	allPactKey := GetBrokerRootKey() //GetBrokerVerificationKey("default") //util.StringJoin([]string{ apt.GetRootKey(), apt.REGISTRY_PACT_ROOT_KEY }, "/")
 
diff --git a/server/core/backend/cache.go b/server/core/backend/cache.go
index 2f9107e..acf9b99 100644
--- a/server/core/backend/cache.go
+++ b/server/core/backend/cache.go
@@ -18,10 +18,11 @@ package backend
 
 type Cache interface {
 	Name() string
-	Size() int
+	Size() int // the bytes size of the cache
 
 	Get(k string) *KeyValue
-	GetAll(prefix string, arr *[]*KeyValue) int
+	GetAll(arr *[]*KeyValue) int
+	GetPrefix(prefix string, arr *[]*KeyValue) int
 	ForEach(iter func(k string, v *KeyValue) (next bool))
 
 	Put(k string, v *KeyValue)
@@ -30,7 +31,4 @@ type Cache interface {
 
 type Cacher interface {
 	Cache() Cache
-	Run()
-	Stop()
-	Ready() <-chan struct{}
 }
diff --git a/server/core/backend/cache_kv.go b/server/core/backend/cache_kv.go
index b001544..8b5d865 100644
--- a/server/core/backend/cache_kv.go
+++ b/server/core/backend/cache_kv.go
@@ -17,6 +17,7 @@
 package backend
 
 import (
+	"github.com/apache/incubator-servicecomb-service-center/pkg/util"
 	"strings"
 	"sync"
 	"time"
@@ -36,7 +37,9 @@ func (c *KvCache) Name() string {
 }
 
 func (c *KvCache) Size() (l int) {
-	l = c.GetAll(c.Cfg.Prefix, nil)
+	c.rwMux.RLock()
+	l = int(util.Sizeof(c.store))
+	c.rwMux.RUnlock()
 	return
 }
 
@@ -50,7 +53,14 @@ func (c *KvCache) Get(key string) (v *KeyValue) {
 	return
 }
 
-func (c *KvCache) GetAll(prefix string, arr *[]*KeyValue) (count int) {
+func (c *KvCache) GetAll(arr *[]*KeyValue) (count int) {
+	c.rwMux.RLock()
+	count = c.getPrefixKey(arr, c.Cfg.Key)
+	c.rwMux.RUnlock()
+	return
+}
+
+func (c *KvCache) GetPrefix(prefix string, arr *[]*KeyValue) (count int) {
 	c.rwMux.RLock()
 	count = c.getPrefixKey(arr, prefix)
 	c.rwMux.RUnlock()
@@ -116,7 +126,7 @@ func (c *KvCache) getPrefixKey(arr *[]*KeyValue, prefix string) (count int) {
 }
 
 func (c *KvCache) addPrefixKey(key string, val *KeyValue) {
-	if len(c.Cfg.Prefix) >= len(key) {
+	if len(c.Cfg.Key) >= len(key) {
 		return
 	}
 	prefix := c.prefix(key)
@@ -155,12 +165,6 @@ func (c *KvCache) deletePrefixKey(key string) {
 	}
 }
 
-func (c *KvCache) ReportMetrics() {
-	c.rwMux.RLock()
-	ReportCacheMetrics(c.Name(), "raw", c.store)
-	c.rwMux.RUnlock()
-}
-
 func NewKvCache(name string, cfg *Config) *KvCache {
 	return &KvCache{
 		Cfg:         cfg,
diff --git a/server/core/backend/cache_null.go b/server/core/backend/cache_null.go
index cce930e..8d538d6 100644
--- a/server/core/backend/cache_null.go
+++ b/server/core/backend/cache_null.go
@@ -24,22 +24,17 @@ var (
 type nullCache struct {
 }
 
-func (n *nullCache) Name() string                                         { return "null" }
+func (n *nullCache) Name() string                                         { return "NULL" }
 func (n *nullCache) Size() int                                            { return 0 }
-func (n *nullCache) RLock()                                               {}
-func (n *nullCache) RUnlock()                                             {}
 func (n *nullCache) Get(k string) *KeyValue                               { return nil }
-func (n *nullCache) GetAll(prefix string, arr *[]*KeyValue) int           { return 0 }
+func (n *nullCache) GetAll(arr *[]*KeyValue) int                          { return 0 }
+func (n *nullCache) GetPrefix(prefix string, arr *[]*KeyValue) int        { return 0 }
 func (n *nullCache) ForEach(iter func(k string, v *KeyValue) (next bool)) {}
-func (n *nullCache) Lock()                                                {}
-func (n *nullCache) Unlock()                                              {}
 func (n *nullCache) Put(k string, v *KeyValue)                            {}
 func (n *nullCache) Remove(k string)                                      {}
 
 type nullCacher struct {
 }
 
-func (n *nullCacher) Cache() Cache           { return NullCache }
-func (n *nullCacher) Run()                   {}
-func (n *nullCacher) Stop()                  {}
-func (n *nullCacher) Ready() <-chan struct{} { return closedCh }
+func (n *nullCacher) Config() *Config { return nil }
+func (n *nullCacher) Cache() Cache    { return NullCache }
diff --git a/server/core/backend/cache_test.go b/server/core/backend/cache_test.go
index e15ba9c..b959322 100644
--- a/server/core/backend/cache_test.go
+++ b/server/core/backend/cache_test.go
@@ -35,7 +35,7 @@ func BenchmarkFilter(b *testing.B) {
 	}
 	v, _ := json.Marshal(inst)
 
-	cfg := DefaultConfig().WithParser(InstanceParser)
+	cfg := Configure().WithParser(InstanceParser)
 
 	n := 300 * 1000 // 30w
 	cache := NewKvCache("test", cfg)
@@ -83,8 +83,36 @@ func BenchmarkFilter(b *testing.B) {
 	//20	  82367261 ns/op	37964987 B/op	   80132 allocs/op
 }
 
+func TestNullCache_Name(t *testing.T) {
+	NullCache.Put("", nil)
+	if NullCache.Name() != "NULL" {
+		t.Fatalf("TestNullCache_Name failed")
+	}
+	if NullCache.Size() != 0 {
+		t.Fatalf("TestNullCache_Name failed")
+	}
+	if NullCache.Get("") != nil {
+		t.Fatalf("TestNullCache_Name failed")
+	}
+	if NullCache.GetAll(nil) != 0 {
+		t.Fatalf("TestNullCache_Name failed")
+	}
+	if NullCache.GetPrefix("", nil) != 0 {
+		t.Fatalf("TestNullCache_Name failed")
+	}
+	NullCache.ForEach(func(k string, v *KeyValue) (next bool) {
+		t.Fatalf("TestNullCache_Name failed")
+		return false
+	})
+	NullCache.Remove("")
+
+	if NullCacher.Cache() != NullCache || NullCacher.Config() != nil {
+		t.Fatalf("TestNullCache_Name failed")
+	}
+}
+
 func TestKvCache_Get(t *testing.T) {
-	c := NewKvCache("test", DefaultConfig())
+	c := NewKvCache("test", Configure())
 	c.Put("", &KeyValue{Version: 1})
 	c.Put("/", &KeyValue{Version: 1})
 	c.Put("/a/b/c/d/e/1", &KeyValue{Version: 1})
@@ -92,21 +120,25 @@ func TestKvCache_Get(t *testing.T) {
 	c.Put("/a/b/d/d/f/3", &KeyValue{Version: 3})
 	c.Put("/a/b/e/d/g/4", &KeyValue{Version: 4})
 
-	if l := c.Size(); l != 4 {
-		t.Fatalf("TestKvCache Size() failed, %d", l)
+	if s := c.Size(); s == 0 {
+		t.Fatalf("TestKvCache Size() failed, %d", s)
+	}
+
+	if l := c.GetAll(nil); l != 4 {
+		t.Fatalf("TestKvCache GetAll() failed, %d", l)
 	}
 
 	if kv := c.Get("/a/b/c/d/e/2"); kv == nil || kv.Version != 2 {
 		t.Fatalf("TestKvCache Get() failed, %v", kv)
 	}
 
-	if l := c.GetAll("/", nil); l != 4 {
-		t.Fatalf("TestKvCache GetAll() failed, %d", l)
+	if l := c.GetPrefix("/", nil); l != 4 {
+		t.Fatalf("TestKvCache GetPrefix() failed, %d", l)
 	}
 
 	var arr []*KeyValue
-	if l := c.GetAll("/a/b/c/", &arr); l != 2 || (arr[0].Version != 1 && arr[1].Version != 1) {
-		t.Fatalf("TestKvCache GetAll() failed, %d, %v", l, arr)
+	if l := c.GetPrefix("/a/b/c/", &arr); l != 2 || (arr[0].Version != 1 && arr[1].Version != 1) {
+		t.Fatalf("TestKvCache GetPrefix() failed, %d, %v", l, arr)
 	}
 
 	l, b := -1, false
@@ -134,7 +166,12 @@ func TestKvCache_Get(t *testing.T) {
 	c.Remove("/")
 	c.Remove("/a/b/c/d/e/2")
 	c.Remove("/a/b/d/d/f/3")
-	if l := c.Size(); l != 2 {
-		t.Fatalf("TestKvCache Size() failed, %d", l)
+	if l := c.GetAll(nil); l != 2 {
+		t.Fatalf("TestKvCache GetAll() failed, %d", l)
+	}
+
+	c.Put("/a/b/c/d/e/1", &KeyValue{Version: 2})
+	if kv := c.Get("/a/b/c/d/e/1"); kv == nil || kv.Version != 2 {
+		t.Fatalf("TestKvCache Put() failed, %v", kv)
 	}
 }
diff --git a/server/core/backend/cacher_kv.go b/server/core/backend/cacher_kv.go
index 3d8a793..9be17aa 100644
--- a/server/core/backend/cacher_kv.go
+++ b/server/core/backend/cacher_kv.go
@@ -18,6 +18,7 @@ package backend
 
 import (
 	"errors"
+	"fmt"
 	"github.com/apache/incubator-servicecomb-service-center/pkg/util"
 	"github.com/apache/incubator-servicecomb-service-center/server/core"
 	"github.com/apache/incubator-servicecomb-service-center/server/core/proto"
@@ -31,37 +32,39 @@ import (
 type KvCacher struct {
 	Cfg *Config
 
-	lastRev      int64
-	noEventCount int
+	latestListRev  int64
+	noEventPeriods int
 
 	ready     chan struct{}
-	lw        ListWatcher
+	lw        ListWatch
 	mux       sync.Mutex
 	once      sync.Once
-	cache     *KvCache
+	cache     Cache
 	goroutine *util.GoRoutine
 }
 
+func (c *KvCacher) Config() *Config {
+	return c.Cfg
+}
+
 func (c *KvCacher) needList() bool {
 	rev := c.lw.Revision()
-	defer func() { c.lastRev = rev }()
-
 	if rev == 0 {
-		c.noEventCount = 0
+		c.noEventPeriods = 0
 		return true
 	}
-	if c.lastRev != rev {
-		c.noEventCount = 0
+	if c.latestListRev != rev {
+		c.noEventPeriods = 0
 		return false
 	}
-	c.noEventCount++
-	if c.noEventCount < c.Cfg.NoEventMaxInterval {
+	c.noEventPeriods++
+	if c.Cfg.NoEventPeriods == 0 || c.noEventPeriods < c.Cfg.NoEventPeriods {
 		return false
 	}
 
 	util.Logger().Debugf("no events come in more then %s, need to list key %s, rev: %d",
-		time.Duration(c.noEventCount)*c.Cfg.Timeout, c.Cfg.Prefix, rev)
-	c.noEventCount = 0
+		time.Duration(c.noEventPeriods)*c.Cfg.Timeout, c.Cfg.Key, rev)
+	c.noEventPeriods = 0
 	return true
 }
 
@@ -70,24 +73,28 @@ func (c *KvCacher) doList(cfg ListWatchConfig) error {
 	if err != nil {
 		return err
 	}
+	c.latestListRev = c.lw.Revision()
 
 	kvs := resp.Kvs
 	start := time.Now()
 	evts := c.filter(c.lw.Revision(), kvs)
 	if ec, kc := len(evts), len(kvs); c.Cfg.DeferHandler != nil && ec == 0 && kc != 0 &&
 		c.Cfg.DeferHandler.Reset() {
-		util.Logger().Warnf(nil, "most of the protected data(%d/%d) are recovered", kc, c.cache.Size())
+		util.Logger().Warnf(nil, "most of the protected data(%d/%d) are recovered",
+			kc, c.cache.GetAll(nil))
 	}
 	c.sync(evts)
 	util.LogDebugOrWarnf(start, "finish to cache key %s, %d items, rev: %d",
-		c.Cfg.Prefix, len(kvs), c.lw.Revision())
+		c.Cfg.Key, len(kvs), c.lw.Revision())
 
 	return nil
 }
 
 func (c *KvCacher) doWatch(cfg ListWatchConfig) error {
-	watcher := c.lw.Watch(cfg)
-	return c.handleWatcher(watcher)
+	if watcher := c.lw.Watch(cfg); watcher != nil {
+		return c.handleWatcher(watcher)
+	}
+	return fmt.Errorf("handle a nil watcher")
 }
 
 func (c *KvCacher) ListAndWatch(ctx context.Context) error {
@@ -99,7 +106,10 @@ func (c *KvCacher) ListAndWatch(ctx context.Context) error {
 		Context: ctx,
 	}
 	if c.needList() {
-		c.doList(cfg)
+		if err := c.doList(cfg); err != nil && !c.IsReady() {
+			// cacher is not ready, so it need to retry util the cache is created
+			return err
+		}
 	}
 
 	util.SafeCloseChan(c.ready)
@@ -107,7 +117,7 @@ func (c *KvCacher) ListAndWatch(ctx context.Context) error {
 	return c.doWatch(cfg)
 }
 
-func (c *KvCacher) handleWatcher(watcher *Watcher) error {
+func (c *KvCacher) handleWatcher(watcher Watcher) error {
 	defer watcher.Stop()
 	for resp := range watcher.EventBus() {
 		if resp == nil {
@@ -115,9 +125,10 @@ func (c *KvCacher) handleWatcher(watcher *Watcher) error {
 		}
 
 		start := time.Now()
+		rev := resp.Revision
 		evts := make([]KvEvent, 0, len(resp.Kvs))
 		for _, kv := range resp.Kvs {
-			evt := KvEvent{Prefix: c.lw.Prefix, Revision: kv.ModRevision}
+			evt := KvEvent{Prefix: c.Cfg.Key, Revision: kv.ModRevision}
 			switch {
 			case resp.Action == registry.Put && kv.Version == 1:
 				evt.Type, evt.KV = proto.EVT_CREATE, c.doParse(kv)
@@ -142,7 +153,7 @@ func (c *KvCacher) handleWatcher(watcher *Watcher) error {
 		}
 		c.sync(evts)
 		util.LogDebugOrWarnf(start, "finish to handle %d events, prefix: %s, rev: %d",
-			len(evts), c.Cfg.Prefix, c.lw.Revision())
+			len(evts), c.Cfg.Key, rev)
 	}
 	return nil
 }
@@ -240,7 +251,7 @@ func (c *KvCacher) filterDelete(newStore map[string]*mvccpb.KeyValue,
 		block[i] = KvEvent{
 			Revision: rev,
 			Type:     proto.EVT_DELETE,
-			Prefix:   c.Cfg.Prefix,
+			Prefix:   c.Cfg.Key,
 			KV:       v,
 		}
 		i++
@@ -272,7 +283,7 @@ func (c *KvCacher) filterCreateOrUpdate(newStore map[string]*mvccpb.KeyValue,
 				block[i] = KvEvent{
 					Revision: rev,
 					Type:     proto.EVT_CREATE,
-					Prefix:   c.Cfg.Prefix,
+					Prefix:   c.Cfg.Key,
 					KV:       kv,
 				}
 				i++
@@ -294,7 +305,7 @@ func (c *KvCacher) filterCreateOrUpdate(newStore map[string]*mvccpb.KeyValue,
 			block[i] = KvEvent{
 				Revision: rev,
 				Type:     proto.EVT_UPDATE,
-				Prefix:   c.Cfg.Prefix,
+				Prefix:   c.Cfg.Key,
 				KV:       kv,
 			}
 			i++
@@ -447,8 +458,7 @@ func (c *KvCacher) IsReady() bool {
 }
 
 func (c *KvCacher) reportMetrics(ctx context.Context) {
-	if !core.ServerInfo.Config.EnablePProf ||
-		!core.ServerInfo.Config.EnableCache {
+	if !core.ServerInfo.Config.EnablePProf {
 		return
 	}
 	timer := time.NewTimer(DEFAULT_METRICS_INTERVAL)
@@ -458,8 +468,7 @@ func (c *KvCacher) reportMetrics(ctx context.Context) {
 		case <-ctx.Done():
 			return
 		case <-timer.C:
-			c.cache.ReportMetrics()
-
+			ReportCacheSize(c.cache.Name(), "raw", c.cache.Size())
 			timer.Reset(DEFAULT_METRICS_INTERVAL)
 		}
 	}
@@ -469,9 +478,9 @@ func NewKvCacher(name string, cfg *Config) *KvCacher {
 	cacher := &KvCacher{
 		Cfg:   cfg,
 		ready: make(chan struct{}),
-		lw: ListWatcher{
+		lw: &innerListWatch{
 			Client: Registry(),
-			Prefix: cfg.Prefix,
+			Prefix: cfg.Key,
 		},
 		goroutine: util.NewGo(context.Background()),
 	}
diff --git a/server/core/backend/cacher_kv_test.go b/server/core/backend/cacher_kv_test.go
new file mode 100644
index 0000000..82455ec
--- /dev/null
+++ b/server/core/backend/cacher_kv_test.go
@@ -0,0 +1,340 @@
+/*
+ * 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 backend
+
+import (
+	"github.com/apache/incubator-servicecomb-service-center/pkg/util"
+	"github.com/apache/incubator-servicecomb-service-center/server/core/proto"
+	"github.com/apache/incubator-servicecomb-service-center/server/infra/registry"
+	"github.com/coreos/etcd/mvcc/mvccpb"
+	"golang.org/x/net/context"
+	"strconv"
+	"testing"
+)
+
+type mockCache struct {
+	*nullCache
+	Key string
+	KV  *KeyValue
+}
+
+func (n *mockCache) Get(k string) *KeyValue {
+	if k == n.Key {
+		return n.KV
+	}
+	return nil
+}
+func (n *mockCache) GetPrefix(prefix string, arr *[]*KeyValue) int {
+	if prefix == n.Key {
+		if arr != nil {
+			*arr = append(*arr, n.KV)
+		}
+		return 1
+	}
+	return 0
+}
+func (n *mockCache) ForEach(iter func(k string, v *KeyValue) (next bool)) {
+	iter(n.Key, n.KV)
+}
+func (n *mockCache) Put(k string, v *KeyValue) {
+	n.Key = k
+	n.KV = v
+}
+func (n *mockCache) Remove(k string) {
+	if k == n.Key {
+		n.Key = ""
+		n.KV = nil
+	}
+}
+
+func TestNewKvCacher(t *testing.T) {
+	w := &mockWatcher{}
+	lw := &mockListWatch{
+		Bus: make(chan *registry.PluginResponse, 100),
+	}
+	w.lw = lw
+
+	cr := &KvCacher{
+		Cfg:       Configure(),
+		ready:     make(chan struct{}),
+		lw:        lw,
+		goroutine: util.NewGo(context.Background()),
+		cache:     &mockCache{},
+	}
+
+	ctx, cancel := context.WithCancel(context.Background())
+	cancel()
+
+	// case: cause list internal error
+	cr.refresh(ctx)
+	if cr.IsReady() {
+		t.Fatalf("TestNewKvCacher failed")
+	}
+
+	// prepare data
+	var evt KvEvent
+	cr = &KvCacher{
+		Cfg: Configure().
+			WithNoEventPeriods(0).
+			WithEventFunc(func(e KvEvent) {
+				evt = e
+			}),
+		ready:     make(chan struct{}),
+		lw:        lw,
+		goroutine: util.NewGo(context.Background()),
+		cache:     &mockCache{},
+	}
+
+	lw.Watcher = w
+	data := &mvccpb.KeyValue{Key: []byte("ka"), Value: []byte("va"), Version: 1, ModRevision: 2}
+	test := &registry.PluginResponse{
+		Action:   registry.Put,
+		Revision: 3,
+		Kvs:      []*mvccpb.KeyValue{data}}
+
+	// case: list 1 resp and watch 0 event
+	cr.cache.Remove("ka")
+	lw.ListResponse = test
+	lw.Bus <- nil
+
+	cr.refresh(ctx)
+	// check ready
+	if !cr.IsReady() {
+		t.Fatalf("TestNewKvCacher failed")
+	}
+	// check event
+	if evt.Type != proto.EVT_INIT || evt.Revision != 3 || evt.KV.ModRevision != 2 || string(evt.KV.Key) != "ka" || string(evt.KV.Value.([]byte)) != "va" {
+		t.Fatalf("TestNewKvCacher failed, %v", evt)
+	}
+	// check cache
+	kv := cr.cache.Get("ka")
+	if kv == nil || kv.ModRevision != 2 || string(kv.Key) != "ka" || string(kv.Value.([]byte)) != "va" {
+		t.Fatalf("TestNewKvCacher failed")
+	}
+
+	test.Revision = 4
+	data.ModRevision = 3
+
+	// case: re-list and should be no event
+	lw.Bus <- nil
+	evt.KV = nil
+	cr.refresh(ctx)
+	if evt.KV != nil {
+		t.Fatalf("TestNewKvCacher failed")
+	}
+	// check cache
+	kv = cr.cache.Get("ka")
+	if kv == nil || kv.ModRevision != 2 || string(kv.Key) != "ka" || string(kv.Value.([]byte)) != "va" {
+		t.Fatalf("TestNewKvCacher failed")
+	}
+
+	// case re-list and over no event times
+	lw.Bus <- nil
+	evt.KV = nil
+	old := *cr.Cfg
+	cr.Cfg.WithNoEventPeriods(1)
+	cr.refresh(ctx)
+	// check event
+	if evt.Type != proto.EVT_UPDATE || evt.Revision != 4 || evt.KV.ModRevision != 3 || string(evt.KV.Key) != "ka" || string(evt.KV.Value.([]byte)) != "va" {
+		t.Fatalf("TestNewKvCacher failed, %v", evt)
+	}
+	// check cache
+	kv = cr.cache.Get("ka")
+	if kv == nil || kv.ModRevision != 3 || string(kv.Key) != "ka" || string(kv.Value.([]byte)) != "va" {
+		t.Fatalf("TestNewKvCacher failed")
+	}
+
+	lw.ListResponse = &registry.PluginResponse{Revision: 5}
+	lw.Bus <- nil
+	evt.KV = nil
+	cr.refresh(ctx)
+	*cr.Cfg = old
+	// check event
+	if evt.Type != proto.EVT_DELETE || evt.Revision != 5 || evt.KV.ModRevision != 3 || string(evt.KV.Key) != "ka" || string(evt.KV.Value.([]byte)) != "va" {
+		t.Fatalf("TestNewKvCacher failed, %v", evt)
+	}
+	// check cache
+	kv = cr.cache.Get("ka")
+	if kv != nil {
+		t.Fatalf("TestNewKvCacher failed")
+	}
+
+	// case: no list and watch 1 event
+	test.Revision = 6
+	data.ModRevision = 5
+	lw.Bus <- test
+	lw.Bus <- nil
+
+	cr.refresh(ctx)
+	// check event
+	if evt.Type != proto.EVT_CREATE || evt.Revision != 5 || evt.KV.ModRevision != 5 || string(evt.KV.Key) != "ka" || string(evt.KV.Value.([]byte)) != "va" {
+		t.Fatalf("TestNewKvCacher failed, %v", evt)
+	}
+	// check cache
+	kv = cr.cache.Get("ka")
+	if kv == nil || kv.ModRevision != 5 || string(kv.Key) != "ka" || string(kv.Value.([]byte)) != "va" {
+		t.Fatalf("TestNewKvCacher failed")
+	}
+
+	test.Revision = 7
+	data.Version = 2
+	data.ModRevision = 6
+	lw.Bus <- test
+	lw.Bus <- nil
+
+	cr.refresh(ctx)
+	// check event
+	if evt.Type != proto.EVT_UPDATE || evt.Revision != 6 || evt.KV.ModRevision != 6 || string(evt.KV.Key) != "ka" || string(evt.KV.Value.([]byte)) != "va" {
+		t.Fatalf("TestNewKvCacher failed, %v", evt)
+	}
+	// check cache
+	kv = cr.cache.Get("ka")
+	if kv == nil || kv.ModRevision != 6 || string(kv.Key) != "ka" || string(kv.Value.([]byte)) != "va" {
+		t.Fatalf("TestNewKvCacher failed")
+	}
+
+	test.Revision = 8
+	test.Action = registry.Delete
+	data.Version = 0
+	data.ModRevision = 6
+	lw.Bus <- test
+	lw.Bus <- nil
+
+	cr.refresh(ctx)
+	// check event
+	if evt.Type != proto.EVT_DELETE || evt.Revision != 6 || evt.KV.ModRevision != 6 || string(evt.KV.Key) != "ka" || string(evt.KV.Value.([]byte)) != "va" {
+		t.Fatalf("TestNewKvCacher failed, %v", evt)
+	}
+	// check cache
+	kv = cr.cache.Get("ka")
+	if kv != nil {
+		t.Fatalf("TestNewKvCacher failed")
+	}
+
+	// case: list 1 item and watch no event
+	lw.Rev = 0
+	test.Revision = 9
+	data.Version = 1
+	data.ModRevision = 1
+	lw.ListResponse = test
+	lw.Bus <- nil
+	evt.KV = nil
+	cr.refresh(ctx)
+	// check event
+	if evt.Type != proto.EVT_CREATE || evt.Revision != 9 || evt.KV.ModRevision != 1 || string(evt.KV.Key) != "ka" || string(evt.KV.Value.([]byte)) != "va" {
+		t.Fatalf("TestNewKvCacher failed, %v", evt)
+	}
+	// check cache
+	kv = cr.cache.Get("ka")
+	if kv == nil || kv.ModRevision != 1 || string(kv.Key) != "ka" || string(kv.Value.([]byte)) != "va" {
+		t.Fatalf("TestNewKvCacher failed")
+	}
+
+	// case: caught delete event but value is nil
+	test.Revision = 10
+	test.Action = registry.Delete
+	data.Version = 0
+	data.ModRevision = 1
+	data.Value = nil
+	lw.Bus <- test
+	lw.Bus <- nil
+
+	cr.refresh(ctx)
+	data.Value = []byte("va")
+	// check event
+	if evt.Type != proto.EVT_DELETE || evt.Revision != 1 || evt.KV.ModRevision != 1 || string(evt.KV.Key) != "ka" || string(evt.KV.Value.([]byte)) != "va" {
+		t.Fatalf("TestNewKvCacher failed, %v", evt)
+	}
+	// check cache
+	kv = cr.cache.Get("ka")
+	if kv != nil {
+		t.Fatalf("TestNewKvCacher failed")
+	}
+
+	// case: parse failed
+	lw.Rev = 0
+	test.Revision = 1
+	data.Version = 1
+	data.ModRevision = 1
+	lw.ListResponse = test
+	lw.Bus <- nil
+	evt.KV = nil
+	old = *cr.Cfg
+	cr.Cfg.WithParser(MapParser)
+	cr.refresh(ctx)
+	// check event
+	if evt.KV != nil {
+		t.Fatalf("TestNewKvCacher failed, %v", evt)
+	}
+	// check cache
+	kv = cr.cache.Get("ka")
+	if kv != nil {
+		t.Fatalf("TestNewKvCacher failed")
+	}
+
+	lw.ListResponse = test
+	lw.Bus <- test
+	lw.Bus <- nil
+	cr.refresh(ctx)
+	*cr.Cfg = old
+	// check event
+	if evt.KV != nil {
+		t.Fatalf("TestNewKvCacher failed, %v", evt)
+	}
+	// check cache
+	kv = cr.cache.Get("ka")
+	if kv != nil {
+		t.Fatalf("TestNewKvCacher failed")
+	}
+
+	// case: list result is too large
+	var evts = make(map[string]KvEvent)
+	lw.Rev = 0
+	test.Revision = 3
+	test.Kvs = nil
+	for i := 0; i < eventBlockSize+1; i++ {
+		kv := *data
+		kv.Key = []byte(strconv.Itoa(i))
+		kv.Value = []byte(strconv.Itoa(i))
+		kv.Version = int64(i)
+		kv.ModRevision = int64(i)
+		test.Kvs = append(test.Kvs, &kv)
+	}
+	data.ModRevision = 2
+	test.Kvs = append(test.Kvs, data)
+	lw.ListResponse = test
+	lw.Bus <- nil
+	evt.KV = nil
+	old = *cr.Cfg
+	cr.Cfg.WithEventFunc(func(evt KvEvent) {
+		evts[string(evt.KV.Key)] = evt
+	})
+	cr.refresh(ctx)
+	// check all events
+	for i := 0; i < eventBlockSize+1; i++ {
+		s := strconv.Itoa(i)
+		if evt, ok := evts[s]; !ok || evt.Type != proto.EVT_CREATE || evt.KV.ModRevision != int64(i) || string(evt.KV.Value.([]byte)) != s {
+			t.Fatalf("TestNewKvCacher failed, %v", evt)
+		}
+		delete(evts, s)
+	}
+	evt = evts[string(data.Key)]
+	if len(evts) != 1 || evt.Type != proto.EVT_CREATE || evt.Revision != 3 || evt.KV.ModRevision != 2 {
+		t.Fatalf("TestNewKvCacher failed, %v %v", evts, evt)
+	}
+	delete(evts, string(data.Key))
+}
diff --git a/server/core/backend/common.go b/server/core/backend/common.go
index 1ae79d3..8c0eeee 100644
--- a/server/core/backend/common.go
+++ b/server/core/backend/common.go
@@ -17,6 +17,7 @@
 package backend
 
 import (
+	"errors"
 	apt "github.com/apache/incubator-servicecomb-service-center/server/core"
 	"strconv"
 	"time"
@@ -46,6 +47,11 @@ const TIME_FORMAT = "15:04:05.000"
 
 const EVENT_BUS_MAX_SIZE = 1000
 
+// errors
+var (
+	ErrNoImpl = errors.New("no implement")
+)
+
 var closedCh = make(chan struct{})
 
 func init() {
@@ -56,7 +62,7 @@ type StoreType int
 
 func (st StoreType) String() string {
 	if int(st) < 0 {
-		return "NONEXIST"
+		return "TypeError"
 	}
 	if int(st) < len(TypeNames) {
 		return TypeNames[st]
@@ -64,7 +70,7 @@ func (st StoreType) String() string {
 	return "TYPE" + strconv.Itoa(int(st))
 }
 
-const NONEXIST = StoreType(-1)
+const TypeError = StoreType(-1)
 
 const (
 	DOMAIN StoreType = iota
@@ -105,49 +111,49 @@ var TypeNames = []string{
 }
 
 var TypeConfig = map[StoreType]*Config{
-	SERVICE: DefaultConfig().WithPrefix(apt.GetServiceRootKey("")).
+	SERVICE: Configure().WithPrefix(apt.GetServiceRootKey("")).
 		WithInitSize(500).WithParser(ServiceParser),
 
-	INSTANCE: DefaultConfig().WithPrefix(apt.GetInstanceRootKey("")).
+	INSTANCE: Configure().WithPrefix(apt.GetInstanceRootKey("")).
 		WithInitSize(1000).WithParser(InstanceParser).
 		WithDeferHandler(NewInstanceEventDeferHandler()),
 
-	DOMAIN: DefaultConfig().WithPrefix(apt.GetDomainRootKey() + "/").
+	DOMAIN: Configure().WithPrefix(apt.GetDomainRootKey() + "/").
 		WithInitSize(100).WithParser(StringParser),
 
-	SCHEMA: DefaultConfig().WithPrefix(apt.GetServiceSchemaRootKey("")).
+	SCHEMA: Configure().WithPrefix(apt.GetServiceSchemaRootKey("")).
 		WithInitSize(0),
 
-	SCHEMA_SUMMARY: DefaultConfig().WithPrefix(apt.GetServiceSchemaSummaryRootKey("")).
+	SCHEMA_SUMMARY: Configure().WithPrefix(apt.GetServiceSchemaSummaryRootKey("")).
 		WithInitSize(100).WithParser(StringParser),
 
-	RULE: DefaultConfig().WithPrefix(apt.GetServiceRuleRootKey("")).
+	RULE: Configure().WithPrefix(apt.GetServiceRuleRootKey("")).
 		WithInitSize(100).WithParser(RuleParser),
 
-	LEASE: DefaultConfig().WithPrefix(apt.GetInstanceLeaseRootKey("")).
+	LEASE: Configure().WithPrefix(apt.GetInstanceLeaseRootKey("")).
 		WithInitSize(1000).WithParser(StringParser),
 
-	SERVICE_INDEX: DefaultConfig().WithPrefix(apt.GetServiceIndexRootKey("")).
+	SERVICE_INDEX: Configure().WithPrefix(apt.GetServiceIndexRootKey("")).
 		WithInitSize(500).WithParser(StringParser),
 
-	SERVICE_ALIAS: DefaultConfig().WithPrefix(apt.GetServiceAliasRootKey("")).
+	SERVICE_ALIAS: Configure().WithPrefix(apt.GetServiceAliasRootKey("")).
 		WithInitSize(100).WithParser(StringParser),
 
-	SERVICE_TAG: DefaultConfig().WithPrefix(apt.GetServiceTagRootKey("")).
+	SERVICE_TAG: Configure().WithPrefix(apt.GetServiceTagRootKey("")).
 		WithInitSize(100).WithParser(MapParser),
 
-	RULE_INDEX: DefaultConfig().WithPrefix(apt.GetServiceRuleIndexRootKey("")).
+	RULE_INDEX: Configure().WithPrefix(apt.GetServiceRuleIndexRootKey("")).
 		WithInitSize(100).WithParser(StringParser),
 
-	DEPENDENCY: DefaultConfig().WithPrefix(apt.GetServiceDependencyRootKey("")).
+	DEPENDENCY: Configure().WithPrefix(apt.GetServiceDependencyRootKey("")).
 		WithInitSize(100),
 
-	DEPENDENCY_RULE: DefaultConfig().WithPrefix(apt.GetServiceDependencyRuleRootKey("")).
+	DEPENDENCY_RULE: Configure().WithPrefix(apt.GetServiceDependencyRuleRootKey("")).
 		WithInitSize(100).WithParser(DependencyRuleParser),
 
-	DEPENDENCY_QUEUE: DefaultConfig().WithPrefix(apt.GetServiceDependencyQueueRootKey("")).
+	DEPENDENCY_QUEUE: Configure().WithPrefix(apt.GetServiceDependencyQueueRootKey("")).
 		WithInitSize(100).WithParser(DependencyQueueParser),
 
-	PROJECT: DefaultConfig().WithPrefix(apt.GetProjectRootKey("")).
+	PROJECT: Configure().WithPrefix(apt.GetProjectRootKey("")).
 		WithInitSize(100).WithParser(StringParser),
 }
diff --git a/server/core/backend/config.go b/server/core/backend/config.go
index 32c2e41..7f1870f 100644
--- a/server/core/backend/config.go
+++ b/server/core/backend/config.go
@@ -23,23 +23,23 @@ import (
 )
 
 type Config struct {
-	Prefix             string
-	InitSize           int
-	NoEventMaxInterval int
-	Timeout            time.Duration
-	Period             time.Duration
-	DeferHandler       DeferHandler
-	OnEvent            KvEventFunc
-	Parser             *Parser
+	Key            string
+	InitSize       int
+	NoEventPeriods int
+	Timeout        time.Duration
+	Period         time.Duration
+	DeferHandler   DeferHandler
+	OnEvent        KvEventFunc
+	Parser         Parser
 }
 
 func (cfg *Config) String() string {
-	return fmt.Sprintf("{prefix: %s, timeout: %s, period: %s}",
-		cfg.Prefix, cfg.Timeout, cfg.Period)
+	return fmt.Sprintf("{key: %s, timeout: %s, period: %s}",
+		cfg.Key, cfg.Timeout, cfg.Period)
 }
 
 func (cfg *Config) WithPrefix(key string) *Config {
-	cfg.Prefix = key
+	cfg.Key = key
 	return cfg
 }
 
@@ -68,6 +68,11 @@ func (cfg *Config) WithEventFunc(f KvEventFunc) *Config {
 	return cfg
 }
 
+func (cfg *Config) WithNoEventPeriods(p int) *Config {
+	cfg.NoEventPeriods = p
+	return cfg
+}
+
 func (cfg *Config) AppendEventFunc(f KvEventFunc) *Config {
 	if prev := cfg.OnEvent; prev != nil {
 		next := f
@@ -80,19 +85,19 @@ func (cfg *Config) AppendEventFunc(f KvEventFunc) *Config {
 	return cfg
 }
 
-func (cfg *Config) WithParser(parser *Parser) *Config {
+func (cfg *Config) WithParser(parser Parser) *Config {
 	cfg.Parser = parser
 	return cfg
 }
 
-func DefaultConfig() *Config {
+func Configure() *Config {
 	return &Config{
-		Prefix:             "/",
-		Timeout:            DEFAULT_LISTWATCH_TIMEOUT,
-		Period:             time.Second,
-		NoEventMaxInterval: DEFAULT_MAX_NO_EVENT_INTERVAL,
-		InitSize:           DEFAULT_CACHE_INIT_SIZE,
-		Parser:             BytesParser,
+		Key:            "/",
+		Timeout:        DEFAULT_LISTWATCH_TIMEOUT,
+		Period:         time.Second,
+		NoEventPeriods: DEFAULT_MAX_NO_EVENT_INTERVAL,
+		InitSize:       DEFAULT_CACHE_INIT_SIZE,
+		Parser:         BytesParser,
 	}
 }
 
diff --git a/server/core/backend/defer_instance.go b/server/core/backend/defer_instance.go
index fea9485..b89d511 100644
--- a/server/core/backend/defer_instance.go
+++ b/server/core/backend/defer_instance.go
@@ -104,17 +104,25 @@ func (iedh *InstanceEventDeferHandler) check(ctx context.Context) {
 			}
 
 			del := len(iedh.items)
-			if del > 0 && !n {
-				util.ResetTimer(t, DEFAULT_CHECK_WINDOW)
-				n = true
+			if del == 0 {
+				continue
+			}
+
+			if iedh.enabled {
+				continue
 			}
 
-			total := iedh.cache.Size()
-			if !iedh.enabled && del > 0 && total > 5 && float64(del) >= float64(total)*iedh.Percent {
+			total := iedh.cache.GetAll(nil)
+			if total > 5 && float64(del) >= float64(total)*iedh.Percent {
 				iedh.enabled = true
 				util.Logger().Warnf(nil, "self preservation is enabled, caught %d/%d(>=%.0f%%) DELETE events",
 					del, total, iedh.Percent*100)
 			}
+
+			if !n {
+				util.ResetTimer(t, DEFAULT_CHECK_WINDOW)
+				n = true
+			}
 		case <-t.C:
 			n = false
 
diff --git a/server/core/backend/defer_test.go b/server/core/backend/defer_test.go
index 42a43e8..b8b3ebf 100644
--- a/server/core/backend/defer_test.go
+++ b/server/core/backend/defer_test.go
@@ -42,7 +42,7 @@ func TestInstanceEventDeferHandler_OnCondition(t *testing.T) {
 func TestInstanceEventDeferHandler_HandleChan(t *testing.T) {
 	b := &pb.MicroServiceInstance{
 		HealthCheck: &pb.HealthCheck{
-			Interval: 4,
+			Interval: 3,
 			Times:    0,
 		},
 	}
@@ -71,7 +71,7 @@ func TestInstanceEventDeferHandler_HandleChan(t *testing.T) {
 		Value: b,
 	}
 
-	cache := NewKvCache("test", DefaultConfig())
+	cache := NewKvCache("test", Configure())
 	cache.Put("/1", kv1)
 	cache.Put("/2", kv2)
 	cache.Put("/3", kv3)
@@ -140,7 +140,7 @@ func TestInstanceEventDeferHandler_HandleChan(t *testing.T) {
 
 	getEvents(t, iedh)
 
-	iedh.Percent = 0.8
+	iedh.Percent = 0.9
 	iedh.OnCondition(cache, evts1)
 	iedh.OnCondition(cache, evts2)
 	iedh.OnCondition(cache, evts3)
@@ -150,12 +150,12 @@ func TestInstanceEventDeferHandler_HandleChan(t *testing.T) {
 
 func getEvents(t *testing.T, iedh *InstanceEventDeferHandler) {
 	fmt.Println(time.Now())
-	c := time.After(3 * time.Second)
+	c := time.After(3500 * time.Millisecond)
 	var evt3 *KvEvent
 	for {
 		select {
 		case evt := <-iedh.HandleChan():
-			fmt.Println(time.Now(), evt)
+			fmt.Println(time.Now(), evt.Type, string(evt.KV.Key))
 			if string(evt.KV.Key) == "/3" {
 				evt3 = &evt
 				if iedh.Percent == 0.01 && evt.Type == pb.EVT_DELETE {
@@ -164,8 +164,8 @@ func getEvents(t *testing.T, iedh *InstanceEventDeferHandler) {
 			}
 			continue
 		case <-c:
-			if iedh.Percent == 0.8 && evt3 == nil {
-				t.Fatalf(`TestInstanceEventDeferHandler_HandleChan with 80%% failed`)
+			if iedh.Percent == 0.9 && evt3 == nil {
+				t.Fatalf(`TestInstanceEventDeferHandler_HandleChan with 90%% failed`)
 			}
 		}
 		break
diff --git a/pkg/async/task.go b/server/core/backend/entity.go
similarity index 86%
copy from pkg/async/task.go
copy to server/core/backend/entity.go
index f4a884f..0d152e5 100644
--- a/pkg/async/task.go
+++ b/server/core/backend/entity.go
@@ -14,12 +14,10 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package async
+package backend
 
-import "golang.org/x/net/context"
-
-type Task interface {
-	Key() string
-	Do(ctx context.Context) error
-	Err() error
+type Entity interface {
+	Runnable
+	Indexer
+	Cacher
 }
diff --git a/server/core/backend/entity_kv.go b/server/core/backend/entity_kv.go
new file mode 100644
index 0000000..4496137
--- /dev/null
+++ b/server/core/backend/entity_kv.go
@@ -0,0 +1,76 @@
+/*
+ * 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 backend
+
+import (
+	"github.com/apache/incubator-servicecomb-service-center/pkg/util"
+	"github.com/apache/incubator-servicecomb-service-center/server/core"
+	"sync"
+)
+
+var (
+	defaultKvEntity *KvEntity
+	newKvEntityOnce sync.Once
+)
+
+type KvEntity struct {
+	Cacher
+	Indexer
+}
+
+func (se *KvEntity) Run() {
+	if r, ok := se.Cacher.(Runnable); ok {
+		r.Run()
+	}
+}
+
+func (se *KvEntity) Stop() {
+	if r, ok := se.Cacher.(Runnable); ok {
+		r.Stop()
+	}
+}
+
+func (se *KvEntity) Ready() <-chan struct{} {
+	if r, ok := se.Cacher.(Runnable); ok {
+		return r.Ready()
+	}
+	return closedCh
+}
+
+func NewKvEntity(name string, cfg *Config) *KvEntity {
+	var entity KvEntity
+	switch {
+	case core.ServerInfo.Config.EnableCache && cfg.InitSize > 0:
+		entity.Cacher = NewKvCacher(name, cfg)
+		entity.Indexer = NewCacheIndexer(cfg, entity.Cache())
+	default:
+		util.Logger().Infof(
+			"core will not cache '%s' and ignore all events of it, cache enabled: %v, init size: %d",
+			name, core.ServerInfo.Config.EnableCache, cfg.InitSize)
+		entity.Indexer = NewCommonIndexer(cfg.Key, cfg.Parser)
+	}
+	return &entity
+}
+
+func DefaultKvEntity() *KvEntity {
+	newKvEntityOnce.Do(func() {
+		defaultKvEntity = &KvEntity{
+			Indexer: NewCommonIndexer(Configure().Key, BytesParser),
+		}
+	})
+	return defaultKvEntity
+}
diff --git a/main.go b/server/core/backend/entity_test.go
similarity index 57%
copy from main.go
copy to server/core/backend/entity_test.go
index 3d7ac97..1b6541f 100644
--- a/main.go
+++ b/server/core/backend/entity_test.go
@@ -14,22 +14,35 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package main
+package backend
 
-// plugins
-import _ "github.com/apache/incubator-servicecomb-service-center/server/bootstrap"
 import (
-	"github.com/apache/incubator-servicecomb-service-center/pkg/util"
-	"github.com/apache/incubator-servicecomb-service-center/server"
-	"github.com/apache/incubator-servicecomb-service-center/server/core/backend"
+	"github.com/apache/incubator-servicecomb-service-center/server/core"
+	"testing"
 )
 
-func main() {
-	server.Run()
+func TestNewKvEntity(t *testing.T) {
+	core.ServerInfo.Config.EnableCache = false
+	i := NewKvEntity("a", Configure().WithInitSize(1))
+	if _, ok := i.Indexer.(*CommonIndexer); !ok {
+		t.Fatalf("TestNewIndexer failed")
+	}
+	core.ServerInfo.Config.EnableCache = true
 
-	util.GoCloseAndWait()
+	i.Run()
+	<-i.Ready()
+	i.Stop()
 
-	backend.Registry().Close()
+	i = NewKvEntity("a", Configure().WithInitSize(0))
+	if _, ok := i.Indexer.(*CommonIndexer); !ok {
+		t.Fatalf("TestNewIndexer failed")
+	}
 
-	util.Logger().Warn("service center exited", nil)
+	i = NewKvEntity("a", Configure())
+	if _, ok := i.Indexer.(*CacheIndexer); !ok {
+		t.Fatalf("TestNewIndexer failed")
+	}
+	if _, ok := i.Cacher.(*KvCacher); !ok {
+		t.Fatalf("TestNewIndexer failed")
+	}
 }
diff --git a/server/core/backend/event_proxy.go b/server/core/backend/event_proxy.go
index 3b02287..f3c77cb 100644
--- a/server/core/backend/event_proxy.go
+++ b/server/core/backend/event_proxy.go
@@ -16,16 +16,18 @@
  */
 package backend
 
-import "sync"
+import (
+	"sync"
+)
 
 var (
-	EventProxies map[StoreType]*KvEventProxy
+	eventProxies map[StoreType]*KvEventProxy
 )
 
 func init() {
-	EventProxies = make(map[StoreType]*KvEventProxy, typeEnd)
+	eventProxies = make(map[StoreType]*KvEventProxy)
 	for i := StoreType(0); i != typeEnd; i++ {
-		EventProxies[i] = NewEventProxy()
+		NewEventProxy(i)
 	}
 }
 
@@ -48,10 +50,21 @@ func (h *KvEventProxy) OnEvent(evt KvEvent) {
 	h.lock.RUnlock()
 }
 
-func NewEventProxy() *KvEventProxy {
-	return &KvEventProxy{}
+func (h *KvEventProxy) injectConfig(t StoreType) *Config {
+	return TypeConfig[t].AppendEventFunc(h.OnEvent)
+}
+
+// unsafe
+func NewEventProxy(t StoreType) *KvEventProxy {
+	if proxy, ok := eventProxies[t]; ok {
+		return proxy
+	}
+	proxy := &KvEventProxy{}
+	proxy.injectConfig(t)
+	eventProxies[t] = proxy
+	return proxy
 }
 
 func EventProxy(t StoreType) *KvEventProxy {
-	return EventProxies[t]
+	return eventProxies[t]
 }
diff --git a/server/core/backend/extend_test.go b/server/core/backend/event_test.go
similarity index 58%
copy from server/core/backend/extend_test.go
copy to server/core/backend/event_test.go
index 3f1e1af..97632cb 100644
--- a/server/core/backend/extend_test.go
+++ b/server/core/backend/event_test.go
@@ -18,28 +18,35 @@ package backend
 
 import "testing"
 
-type extend struct {
+type mockEventHandler struct {
+	StoreType StoreType
+	Evt       KvEvent
 }
 
-func (e *extend) Name() string {
-	return "test"
+func (h *mockEventHandler) Type() StoreType {
+	return h.StoreType
 }
-
-func (e *extend) Config() *Config {
-	return DefaultConfig().WithPrefix("/test")
+func (h *mockEventHandler) OnEvent(evt KvEvent) {
+	h.Evt = evt
 }
 
-func TestInstallType(t *testing.T) {
-	id, err := InstallType(&extend{})
-	if err != nil {
-		t.Fatal(err)
+func TestAddEventHandler(t *testing.T) {
+	h := &mockEventHandler{StoreType: SERVICE}
+	evt := KvEvent{Revision: 1}
+
+	// case: add
+	proxy := EventProxy(SERVICE)
+	if nil == proxy {
+		t.Fatalf("TestAddEventHandler failed")
 	}
-	if id == NONEXIST {
-		t.Fatal(err)
+	if NewEventProxy(SERVICE) != proxy {
+		t.Fatalf("TestAddEventHandler failed")
 	}
 
-	id, err = InstallType(&extend{})
-	if id != NONEXIST || err == nil {
-		t.Fatal("InstallType fail", err)
+	// case: normal
+	AddEventHandler(h)
+	proxy.OnEvent(evt)
+	if h.Evt != evt {
+		t.Fatalf("TestAddEventHandler failed")
 	}
 }
diff --git a/server/core/backend/extend.go b/server/core/backend/extend.go
index dbc0cd1..83d16d5 100644
--- a/server/core/backend/extend.go
+++ b/server/core/backend/extend.go
@@ -16,12 +16,7 @@
  */
 package backend
 
-import (
-	"errors"
-	"fmt"
-)
-
-type Entity interface {
+type Extension interface {
 	Name() string
 	Config() *Config
 }
@@ -39,29 +34,7 @@ func (e *entity) Config() *Config {
 	return e.cfg
 }
 
-func InstallType(e Entity) (id StoreType, err error) {
-	if e == nil {
-		return NONEXIST, errors.New("invalid parameter")
-	}
-	for _, n := range TypeNames {
-		if n == e.Name() {
-			return NONEXIST, fmt.Errorf("redeclare store type '%s'", n)
-		}
-	}
-	for _, r := range TypeConfig {
-		if r.Prefix == e.Config().Prefix {
-			return NONEXIST, fmt.Errorf("redeclare store root '%s'", r)
-		}
-	}
-
-	id = StoreType(len(TypeNames))
-	TypeNames = append(TypeNames, e.Name())
-	TypeConfig[id] = e.Config()
-	EventProxies[id] = NewEventProxy()
-	return
-}
-
-func NewEntity(name string, cfg *Config) Entity {
+func NewExtension(name string, cfg *Config) Extension {
 	return &entity{
 		name: name,
 		cfg:  cfg,
diff --git a/server/core/backend/indexer.go b/server/core/backend/indexer.go
index 4f47a72..7333381 100644
--- a/server/core/backend/indexer.go
+++ b/server/core/backend/indexer.go
@@ -17,78 +17,10 @@
 package backend
 
 import (
-	"fmt"
-	"github.com/apache/incubator-servicecomb-service-center/pkg/util"
 	"github.com/apache/incubator-servicecomb-service-center/server/infra/registry"
 	"golang.org/x/net/context"
-	"strings"
 )
 
-type Response struct {
-	Kvs   []*KeyValue
-	Count int64
-}
-
-func (pr *Response) MaxModRevision() (max int64) {
-	for _, kv := range pr.Kvs {
-		if max < kv.ModRevision {
-			max = kv.ModRevision
-		}
-	}
-	return
-}
-
 type Indexer interface {
 	Search(ctx context.Context, opts ...registry.PluginOpOption) (*Response, error)
-	Run()
-	Stop()
-	Ready() <-chan struct{}
-}
-
-type baseIndexer struct {
-	Cfg *Config
-}
-
-func (i *baseIndexer) Search(ctx context.Context, opts ...registry.PluginOpOption) (r *Response, err error) {
-	op := registry.OpGet(opts...)
-	key := util.BytesToStringWithNoCopy(op.Key)
-	if strings.Index(key, i.Cfg.Prefix) != 0 {
-		return nil, fmt.Errorf("search %s mismatch pattern %s", key, i.Cfg.Prefix)
-	}
-
-	resp, err := Registry().Do(ctx, opts...)
-	if err != nil {
-		return nil, err
-	}
-
-	r = new(Response)
-	r.Count = resp.Count
-	if len(resp.Kvs) == 0 {
-		return
-	}
-
-	kvs := make([]*KeyValue, 0, len(resp.Kvs))
-	for _, src := range resp.Kvs {
-		kv := new(KeyValue)
-		if err = kv.From(i.Cfg.Parser, src); err != nil {
-			continue
-		}
-		kvs = append(kvs, kv)
-	}
-	r.Kvs = kvs
-	return
-}
-
-func (i *baseIndexer) Run() {
-}
-
-func (i *baseIndexer) Stop() {
-}
-
-func (i *baseIndexer) Ready() <-chan struct{} {
-	return closedCh
-}
-
-func NewBaseIndexer(cfg *Config) (indexer *baseIndexer) {
-	return &baseIndexer{Cfg: cfg}
 }
diff --git a/server/core/backend/indexer.go b/server/core/backend/indexer_base.go
similarity index 58%
copy from server/core/backend/indexer.go
copy to server/core/backend/indexer_base.go
index 4f47a72..b2ba5bd 100644
--- a/server/core/backend/indexer.go
+++ b/server/core/backend/indexer_base.go
@@ -24,53 +24,48 @@ import (
 	"strings"
 )
 
-type Response struct {
-	Kvs   []*KeyValue
-	Count int64
+type CommonIndexer struct {
+	Client registry.Registry
+	Parser Parser
+	Root   string
 }
 
-func (pr *Response) MaxModRevision() (max int64) {
-	for _, kv := range pr.Kvs {
-		if max < kv.ModRevision {
-			max = kv.ModRevision
-		}
+func (i *CommonIndexer) CheckPrefix(key string) error {
+	if strings.Index(key, i.Root) != 0 {
+		return fmt.Errorf("search '%s' mismatch pattern %s", key, i.Root)
 	}
-	return
+	return nil
 }
 
-type Indexer interface {
-	Search(ctx context.Context, opts ...registry.PluginOpOption) (*Response, error)
-	Run()
-	Stop()
-	Ready() <-chan struct{}
-}
-
-type baseIndexer struct {
-	Cfg *Config
-}
-
-func (i *baseIndexer) Search(ctx context.Context, opts ...registry.PluginOpOption) (r *Response, err error) {
+func (i *CommonIndexer) Search(ctx context.Context, opts ...registry.PluginOpOption) (r *Response, err error) {
 	op := registry.OpGet(opts...)
+
 	key := util.BytesToStringWithNoCopy(op.Key)
-	if strings.Index(key, i.Cfg.Prefix) != 0 {
-		return nil, fmt.Errorf("search %s mismatch pattern %s", key, i.Cfg.Prefix)
+
+	if err := i.CheckPrefix(key); err != nil {
+		return nil, err
 	}
 
-	resp, err := Registry().Do(ctx, opts...)
+	resp, err := i.Client.Do(ctx, opts...)
 	if err != nil {
 		return nil, err
 	}
 
 	r = new(Response)
 	r.Count = resp.Count
-	if len(resp.Kvs) == 0 {
+	if len(resp.Kvs) == 0 || op.CountOnly {
 		return
 	}
 
+	p := i.Parser
+	if op.KeyOnly {
+		p = nil
+	}
+
 	kvs := make([]*KeyValue, 0, len(resp.Kvs))
 	for _, src := range resp.Kvs {
 		kv := new(KeyValue)
-		if err = kv.From(i.Cfg.Parser, src); err != nil {
+		if err = kv.From(p, src); err != nil {
 			continue
 		}
 		kvs = append(kvs, kv)
@@ -79,16 +74,6 @@ func (i *baseIndexer) Search(ctx context.Context, opts ...registry.PluginOpOptio
 	return
 }
 
-func (i *baseIndexer) Run() {
-}
-
-func (i *baseIndexer) Stop() {
-}
-
-func (i *baseIndexer) Ready() <-chan struct{} {
-	return closedCh
-}
-
-func NewBaseIndexer(cfg *Config) (indexer *baseIndexer) {
-	return &baseIndexer{Cfg: cfg}
+func NewCommonIndexer(root string, p Parser) (indexer *CommonIndexer) {
+	return &CommonIndexer{Client: Registry(), Parser: p, Root: root}
 }
diff --git a/server/core/backend/indexer_kv.go b/server/core/backend/indexer_kv.go
index 7cf2443..d1fb766 100644
--- a/server/core/backend/indexer_kv.go
+++ b/server/core/backend/indexer_kv.go
@@ -19,37 +19,36 @@ package backend
 import (
 	"fmt"
 	"github.com/apache/incubator-servicecomb-service-center/pkg/util"
-	"github.com/apache/incubator-servicecomb-service-center/server/core"
 	"github.com/apache/incubator-servicecomb-service-center/server/infra/registry"
 	"golang.org/x/net/context"
-	"strings"
 	"sync"
 	"time"
 )
 
 type CacheIndexer struct {
-	*baseIndexer
+	*CommonIndexer
 
-	cacher  Cacher
-	lock    sync.Mutex
-	isClose bool
+	Cache Cache
+
+	lock sync.Mutex
 }
 
 func (i *CacheIndexer) Search(ctx context.Context, opts ...registry.PluginOpOption) (*Response, error) {
 	op := registry.OpGet(opts...)
+
 	key := util.BytesToStringWithNoCopy(op.Key)
-	if strings.Index(key, i.baseIndexer.Cfg.Prefix) != 0 {
-		return nil, fmt.Errorf("search %s mismatch %s pattern %s",
-			key, i.cacher.Cache().Name(), i.baseIndexer.Cfg.Prefix)
-	}
 
-	if !core.ServerInfo.Config.EnableCache ||
+	if i.Cache == nil ||
 		op.Mode == registry.MODE_NO_CACHE ||
 		op.Revision > 0 ||
 		(op.Offset >= 0 && op.Limit > 0) {
-		util.Logger().Debugf("search %s match special options, request etcd server, opts: %s",
-			i.cacher.Cache().Name(), op)
-		return i.baseIndexer.Search(ctx, opts...)
+		util.Logger().Debugf("search '%s' match special options, request etcd server, opts: %s",
+			key, op)
+		return i.CommonIndexer.Search(ctx, opts...)
+	}
+
+	if err := i.CheckPrefix(key); err != nil {
+		return nil, fmt.Errorf("%s, cache is '%s'", err.Error(), i.Cache.Name())
 	}
 
 	var resp *Response
@@ -63,9 +62,9 @@ func (i *CacheIndexer) Search(ctx context.Context, opts ...registry.PluginOpOpti
 		return resp, nil
 	}
 
-	util.Logger().Debugf("can not find any key from %s cache with prefix, request etcd server, key: %s",
-		i.cacher.Cache().Name(), key)
-	return i.baseIndexer.Search(ctx, opts...)
+	util.Logger().Debugf("can not find any key from %s cache, request etcd server, key: %s",
+		i.Cache.Name(), key)
+	return i.CommonIndexer.Search(ctx, opts...)
 }
 
 func (i *CacheIndexer) search(op registry.PluginOp) *Response {
@@ -73,7 +72,7 @@ func (i *CacheIndexer) search(op registry.PluginOp) *Response {
 
 	key := util.BytesToStringWithNoCopy(op.Key)
 
-	kv := i.cacher.Cache().Get(key)
+	kv := i.Cache.Get(key)
 	if kv != nil {
 		resp.Count = 1
 	}
@@ -90,61 +89,24 @@ func (i *CacheIndexer) searchByPrefix(op registry.PluginOp) *Response {
 
 	prefix := util.BytesToStringWithNoCopy(op.Key)
 
-	resp.Count = int64(i.cacher.Cache().GetAll(prefix, nil))
+	resp.Count = int64(i.Cache.GetPrefix(prefix, nil))
 	if resp.Count == 0 || op.CountOnly {
 		return resp
 	}
 
 	t := time.Now()
 	kvs := make([]*KeyValue, 0, resp.Count)
-	i.cacher.Cache().GetAll(prefix, &kvs)
+	i.Cache.GetPrefix(prefix, &kvs)
 
-	util.LogNilOrWarnf(t, "too long to index data[%d] from cache '%s'", len(kvs), i.cacher.Cache().Name())
+	util.LogNilOrWarnf(t, "too long to index data[%d] from cache '%s'", len(kvs), i.Cache.Name())
 
 	resp.Kvs = kvs
 	return resp
 }
 
-func (i *CacheIndexer) Run() {
-	i.lock.Lock()
-	if !i.isClose {
-		i.lock.Unlock()
-		return
-	}
-	i.isClose = false
-	i.lock.Unlock()
-
-	i.cacher.Run()
-}
-
-func (i *CacheIndexer) Stop() {
-	i.lock.Lock()
-	if i.isClose {
-		i.lock.Unlock()
-		return
-	}
-	i.isClose = true
-	i.lock.Unlock()
-
-	i.cacher.Stop()
-}
-
-func (i *CacheIndexer) Ready() <-chan struct{} {
-	return i.cacher.Ready()
-}
-
-func NewCacheIndexer(name string, cfg *Config) (indexer *CacheIndexer) {
-	indexer = &CacheIndexer{
-		baseIndexer: NewBaseIndexer(cfg),
-		cacher:      NullCacher,
-		isClose:     true,
-	}
-
-	switch {
-	case core.ServerInfo.Config.EnableCache && cfg.InitSize > 0:
-		indexer.cacher = NewKvCacher(name, cfg)
-	default:
-		util.Logger().Infof("service center will not cache '%s'", name)
+func NewCacheIndexer(cfg *Config, cache Cache) *CacheIndexer {
+	return &CacheIndexer{
+		CommonIndexer: NewCommonIndexer(cfg.Key, cfg.Parser),
+		Cache:         cache,
 	}
-	return
 }
diff --git a/server/core/backend/indexer_test.go b/server/core/backend/indexer_test.go
new file mode 100644
index 0000000..c38e727
--- /dev/null
+++ b/server/core/backend/indexer_test.go
@@ -0,0 +1,178 @@
+/*
+ * 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 backend
+
+import (
+	"context"
+	"github.com/apache/incubator-servicecomb-service-center/server/infra/registry"
+	"github.com/coreos/etcd/mvcc/mvccpb"
+	"testing"
+)
+
+func TestCommonIndexer_Search(t *testing.T) {
+	data := &registry.PluginResponse{Revision: 1}
+	c := &mockRegistry{}
+	i := &CommonIndexer{Client: c, Root: "/", Parser: BytesParser}
+
+	// case: key does not contain prefix
+	resp, err := i.Search(context.Background(), registry.WithStrKey("a"))
+	if err == nil || resp != nil {
+		t.Fatalf("TestBaseIndexer_Search failed")
+	}
+
+	// case: client return err
+	resp, err = i.Search(context.Background(), registry.WithStrKey("/a"))
+	if err == nil || resp != nil {
+		t.Fatalf("TestBaseIndexer_Search failed")
+	}
+
+	// case: kvs is empty
+	c.Response = data
+	resp, err = i.Search(context.Background(), registry.WithStrKey("/a"))
+	if err != nil || resp == nil || resp.Count != 0 {
+		t.Fatalf("TestBaseIndexer_Search failed")
+	}
+
+	// case: parse error
+	data.Count = 2
+	data.Kvs = []*mvccpb.KeyValue{{Key: []byte("/a/b"), Value: []byte("abc")}, {Key: []byte("/a/c"), Value: []byte("{}")}}
+	old := i.Parser
+	i.Parser = MapParser
+	c.Response = data
+	resp, err = i.Search(context.Background(), registry.WithStrKey("/a"))
+	if err != nil || resp == nil || resp.Count != 2 || len(resp.Kvs) != 1 {
+		t.Fatalf("TestBaseIndexer_Search failed, %v, %v", err, resp)
+	}
+	i.Parser = old
+
+	// case: normal
+	data.Count = 2
+	data.Kvs = []*mvccpb.KeyValue{{Key: []byte("/a/b"), Value: []byte("abc")}, {Key: []byte("/a/c"), Value: []byte("{}")}}
+	c.Response = data
+	resp, err = i.Search(context.Background(), registry.WithStrKey("/a"))
+	if err != nil || resp == nil || resp.Count != 2 || len(resp.Kvs) != 2 {
+		t.Fatalf("TestBaseIndexer_Search failed, %v, %v", err, resp)
+	}
+	resp, err = i.Search(context.Background(), registry.WithStrKey("/a"), registry.WithKeyOnly())
+	if err != nil || resp == nil || resp.Count != 2 || len(resp.Kvs) != 2 {
+		t.Fatalf("TestBaseIndexer_Search failed, %v, %v", err, resp)
+	}
+	resp, err = i.Search(context.Background(), registry.WithStrKey("/a"), registry.WithCountOnly())
+	if err != nil || resp == nil || resp.Count != 2 || len(resp.Kvs) != 0 {
+		t.Fatalf("TestBaseIndexer_Search failed, %v, %v", err, resp)
+	}
+}
+
+func TestCacheIndexer_Search(t *testing.T) {
+	c := &mockCache{}
+	cli := &mockRegistry{Response: &registry.PluginResponse{
+		Revision: 1,
+		Kvs:      []*mvccpb.KeyValue{{Key: []byte("/a/b"), Value: []byte("abc")}},
+		Count:    1,
+	}}
+	i := &CacheIndexer{
+		CommonIndexer: &CommonIndexer{
+			Root:   "/",
+			Client: cli,
+		},
+		Cache: c,
+	}
+
+	// case: key does not contain prefix
+	resp, err := i.Search(context.Background(), registry.WithStrKey("a"))
+	if err == nil || resp != nil {
+		t.Fatalf("TestBaseIndexer_Search failed, %v, %v", err, resp)
+	}
+
+	// case: not match cache search remote
+	resp, err = i.Search(context.Background(), registry.WithStrKey("/a"))
+	if err != nil || resp == nil || resp.Count != 1 || string(resp.Kvs[0].Key) != "/a/b" {
+		t.Fatalf("TestBaseIndexer_Search failed, %v, %v", err, resp)
+	}
+
+	// no cache
+	resp, err = i.Search(context.Background(), registry.WithStrKey("/a"), registry.WithNoCache())
+	if err != nil || resp == nil || resp.Count != 1 || string(resp.Kvs[0].Key) != "/a/b" {
+		t.Fatalf("TestBaseIndexer_Search failed, %v, %v", err, resp)
+	}
+
+	// rev > 0 or paging
+	resp, err = i.Search(context.Background(), registry.WithStrKey("/a"), registry.WithRev(1))
+	if err != nil || resp == nil || resp.Count != 1 || string(resp.Kvs[0].Key) != "/a/b" {
+		t.Fatalf("TestBaseIndexer_Search failed, %v, %v", err, resp)
+	}
+	resp, err = i.Search(context.Background(), registry.WithStrKey("/a"), registry.WithOffset(0), registry.WithLimit(1))
+	if err != nil || resp == nil || resp.Count != 1 || string(resp.Kvs[0].Key) != "/a/b" {
+		t.Fatalf("TestBaseIndexer_Search failed, %v, %v", err, resp)
+	}
+
+	// not match cache
+	c.Put("ka", &KeyValue{Key: []byte("ka"), Value: []byte("va"), Version: 1, ModRevision: 1})
+	resp, err = i.Search(context.Background(), registry.WithStrKey("/a"))
+	if err != nil || resp == nil || resp.Count != 1 || string(resp.Kvs[0].Key) != "/a/b" {
+		t.Fatalf("TestBaseIndexer_Search failed, %v, %v", err, resp)
+	}
+	resp, err = i.Search(context.Background(), registry.WithStrKey("/a"), registry.WithPrefix())
+	if err != nil || resp == nil || resp.Count != 1 || string(resp.Kvs[0].Key) != "/a/b" {
+		t.Fatalf("TestBaseIndexer_Search failed, %v, %v", err, resp)
+	}
+	resp, err = i.Search(context.Background(), registry.WithStrKey("/a"), registry.WithCountOnly())
+	if err != nil || resp == nil || resp.Count != 1 {
+		t.Fatalf("TestBaseIndexer_Search failed, %v, %v", err, resp)
+	}
+
+	// remote err
+	oldResp := cli.Response
+	cli.Response = nil
+	resp, err = i.Search(context.Background(), registry.WithStrKey("/a"))
+	if err == nil || resp != nil {
+		t.Fatalf("TestBaseIndexer_Search failed, %v, %v", err, resp)
+	}
+	cli.Response = oldResp
+
+	// case: use cache index
+	c.Put("/a", &KeyValue{Key: []byte("/a"), Value: []byte("va"), Version: 1, ModRevision: 1})
+
+	// exact match
+	resp, err = i.Search(context.Background(), registry.WithStrKey("/a"))
+	if err != nil || resp == nil || resp.Count != 1 || string(resp.Kvs[0].Value.([]byte)) != "va" {
+		t.Fatalf("TestBaseIndexer_Search failed, %v, %v", err, resp)
+	}
+	if resp.MaxModRevision() != 1 {
+		t.Fatalf("TestBaseIndexer_Search failed, %v, %v", err, resp)
+	}
+	resp, err = i.Search(context.Background(), registry.WithStrKey("/a"), registry.WithCountOnly())
+	if err != nil || resp == nil || resp.Count != 1 || len(resp.Kvs) != 0 {
+		t.Fatalf("TestBaseIndexer_Search failed, %v, %v", err, resp)
+	}
+
+	// prefix match
+	resp, err = i.Search(context.Background(), registry.WithStrKey("/a"), registry.WithPrefix())
+	if err != nil || resp == nil || resp.Count != 1 || string(resp.Kvs[0].Value.([]byte)) != "va" {
+		t.Fatalf("TestBaseIndexer_Search failed, %v, %v", err, resp)
+	}
+	resp, err = i.Search(context.Background(), registry.WithStrKey("/a"), registry.WithPrefix(), registry.WithCountOnly())
+	if err != nil || resp == nil || resp.Count != 1 || len(resp.Kvs) != 0 {
+		t.Fatalf("TestBaseIndexer_Search failed, %v, %v", err, resp)
+	}
+
+	// mismatch cache but cacheonly
+	resp, err = i.Search(context.Background(), registry.WithStrKey("/a/b"), registry.WithCacheOnly())
+	if err != nil || resp == nil || resp.Count != 0 || len(resp.Kvs) != 0 {
+		t.Fatalf("TestBaseIndexer_Search failed, %v, %v", err, resp)
+	}
+}
diff --git a/server/core/backend/lease.go b/server/core/backend/lease.go
index 89fcb2e..d3e7e8e 100644
--- a/server/core/backend/lease.go
+++ b/server/core/backend/lease.go
@@ -25,6 +25,8 @@ import (
 )
 
 type LeaseTask struct {
+	Client registry.Registry
+
 	key     string
 	LeaseID int64
 	TTL     int64
@@ -40,7 +42,7 @@ func (lat *LeaseTask) Key() string {
 
 func (lat *LeaseTask) Do(ctx context.Context) (err error) {
 	recv, start := lat.ReceiveTime(), time.Now()
-	lat.TTL, err = Registry().LeaseRenew(ctx, lat.LeaseID)
+	lat.TTL, err = lat.Client.LeaseRenew(ctx, lat.LeaseID)
 	if err != nil {
 		util.Logger().Errorf(err, "[%s]renew lease %d failed(recv: %s, send: %s), key %s",
 			time.Now().Sub(recv),
@@ -79,6 +81,7 @@ func (lat *LeaseTask) ReceiveTime() time.Time {
 func NewLeaseAsyncTask(op registry.PluginOp) *LeaseTask {
 	now := time.Now().UTC()
 	return &LeaseTask{
+		Client:   Registry(),
 		key:      ToLeaseAsyncTaskKey(util.BytesToStringWithNoCopy(op.Key)),
 		LeaseID:  op.Lease,
 		recvSec:  now.Unix(),
diff --git a/server/plugin/infra/tracing/buildin/file_collector_test.go b/server/core/backend/lease_test.go
similarity index 55%
copy from server/plugin/infra/tracing/buildin/file_collector_test.go
copy to server/core/backend/lease_test.go
index 92956db..62e8a88 100644
--- a/server/plugin/infra/tracing/buildin/file_collector_test.go
+++ b/server/core/backend/lease_test.go
@@ -14,37 +14,36 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package buildin
+package backend
 
 import (
-	"github.com/apache/incubator-servicecomb-service-center/pkg/util"
-	"github.com/openzipkin/zipkin-go-opentracing/thrift/gen-go/zipkincore"
-	"golang.org/x/net/context"
-	"os"
+	"context"
+	"fmt"
+	errorsEx "github.com/apache/incubator-servicecomb-service-center/pkg/errors"
 	"testing"
 	"time"
 )
 
-func TestFileCollector_Collect(t *testing.T) {
-	fc := &FileCollector{
-		Fd:        os.Stdout,
-		Timeout:   1 * time.Second,
-		Interval:  100 * time.Second,
-		BatchSize: 2,
-		c:         make(chan *zipkincore.Span, 100),
-		goroutine: util.NewGo(context.Background()),
+func TestLeaseTask_Do(t *testing.T) {
+	now := time.Now().UTC()
+	c := &mockRegistry{}
+	lt := &LeaseTask{
+		Client:   c,
+		key:      ToLeaseAsyncTaskKey("/a"),
+		LeaseID:  1,
+		recvSec:  now.Unix(),
+		recvNsec: int64(now.Nanosecond()),
 	}
-	defer func() {
-		fc.Close()
-	}()
-	fc.Run()
 
-	for i := 0; i < 10; i++ {
-		err := fc.Collect(&zipkincore.Span{})
-		if err != nil {
-			t.Fatal(err)
-		}
+	c.LeaseErr = errorsEx.InternalError("lease not found")
+	err := lt.Do(context.Background())
+	if err != nil || lt.Err() != nil {
+		t.Fatalf("TestLeaseTask_Do failed")
 	}
 
-	<-time.After(time.Second)
+	c.LeaseErr = fmt.Errorf("network error")
+	err = lt.Do(context.Background())
+	if err == nil || lt.Err() == nil {
+		t.Fatalf("TestLeaseTask_Do failed")
+	}
 }
diff --git a/server/core/backend/listwatch.go b/server/core/backend/listwatch.go
index 469a8d1..0286b2f 100644
--- a/server/core/backend/listwatch.go
+++ b/server/core/backend/listwatch.go
@@ -17,124 +17,15 @@
 package backend
 
 import (
-	"fmt"
-	"github.com/apache/incubator-servicecomb-service-center/pkg/util"
 	"github.com/apache/incubator-servicecomb-service-center/server/infra/registry"
 	"golang.org/x/net/context"
-	"sync"
 )
 
-type ListWatcher struct {
-	Client registry.Registry
-	Prefix string
-
-	rev int64
-}
-
-func (lw *ListWatcher) List(op ListWatchConfig) (*registry.PluginResponse, error) {
-	otCtx, _ := context.WithTimeout(op.Context, op.Timeout)
-	resp, err := lw.Client.Do(otCtx, registry.WatchPrefixOpOptions(lw.Prefix)...)
-	if err != nil {
-		util.Logger().Errorf(err, "list prefix %s failed, current rev: %d", lw.Prefix, lw.Revision())
-		return nil, err
-	}
-	lw.setRevision(resp.Revision)
-	return resp, nil
-}
-
-func (lw *ListWatcher) Revision() int64 {
-	return lw.rev
-}
-
-func (lw *ListWatcher) setRevision(rev int64) {
-	lw.rev = rev
-}
-
-func (lw *ListWatcher) Watch(op ListWatchConfig) *Watcher {
-	return newWatcher(lw, op)
-}
-
-func (lw *ListWatcher) doWatch(ctx context.Context, f func(*registry.PluginResponse)) error {
-	rev := lw.Revision()
-	opts := append(
-		registry.WatchPrefixOpOptions(lw.Prefix),
-		registry.WithRev(rev+1),
-		registry.WithWatchCallback(
-			func(message string, resp *registry.PluginResponse) error {
-				if resp == nil || len(resp.Kvs) == 0 {
-					return fmt.Errorf("unknown event %s, watch prefix %s", resp, lw.Prefix)
-				}
-
-				lw.setRevision(resp.Revision)
-
-				f(resp)
-				return nil
-			}))
-
-	err := lw.Client.Watch(ctx, opts...)
-	if err != nil { // compact可能会导致watch失败 or message body size lager than 4MB
-		util.Logger().Errorf(err, "watch prefix %s failed, start rev: %d+1->%d->0", lw.Prefix, rev, lw.Revision())
-
-		lw.setRevision(0)
-		f(nil)
-	}
-	return err
-}
-
-type Watcher struct {
-	ListOps ListWatchConfig
-	lw      *ListWatcher
-	bus     chan *registry.PluginResponse
-	stopCh  chan struct{}
-	stop    bool
-	mux     sync.Mutex
-}
-
-func (w *Watcher) EventBus() <-chan *registry.PluginResponse {
-	return w.bus
-}
-
-func (w *Watcher) process(_ context.Context) {
-	stopCh := make(chan struct{})
-	ctx, cancel := context.WithTimeout(w.ListOps.Context, w.ListOps.Timeout)
-	util.Go(func(_ context.Context) {
-		defer close(stopCh)
-		w.lw.doWatch(ctx, w.sendEvent)
-	})
-
-	select {
-	case <-stopCh:
-		// timed out or exception
-		w.Stop()
-	case <-w.stopCh:
-		cancel()
-	}
-}
-
-func (w *Watcher) sendEvent(resp *registry.PluginResponse) {
-	defer util.RecoverAndReport()
-	w.bus <- resp
-}
-
-func (w *Watcher) Stop() {
-	w.mux.Lock()
-	if w.stop {
-		w.mux.Unlock()
-		return
-	}
-	w.stop = true
-	close(w.stopCh)
-	close(w.bus)
-	w.mux.Unlock()
-}
-
-func newWatcher(lw *ListWatcher, listOps ListWatchConfig) *Watcher {
-	w := &Watcher{
-		ListOps: listOps,
-		lw:      lw,
-		bus:     make(chan *registry.PluginResponse, EVENT_BUS_MAX_SIZE),
-		stopCh:  make(chan struct{}),
-	}
-	util.Go(w.process)
-	return w
+type ListWatch interface {
+	List(op ListWatchConfig) (*registry.PluginResponse, error)
+	// not support new multiple watchers
+	Watch(op ListWatchConfig) Watcher
+	//
+	DoWatch(ctx context.Context, f func(*registry.PluginResponse)) error
+	Revision() int64
 }
diff --git a/server/core/backend/listwatch.go b/server/core/backend/listwatch_inner.go
similarity index 58%
copy from server/core/backend/listwatch.go
copy to server/core/backend/listwatch_inner.go
index 469a8d1..70b7234 100644
--- a/server/core/backend/listwatch.go
+++ b/server/core/backend/listwatch_inner.go
@@ -21,17 +21,16 @@ import (
 	"github.com/apache/incubator-servicecomb-service-center/pkg/util"
 	"github.com/apache/incubator-servicecomb-service-center/server/infra/registry"
 	"golang.org/x/net/context"
-	"sync"
 )
 
-type ListWatcher struct {
+type innerListWatch struct {
 	Client registry.Registry
 	Prefix string
 
 	rev int64
 }
 
-func (lw *ListWatcher) List(op ListWatchConfig) (*registry.PluginResponse, error) {
+func (lw *innerListWatch) List(op ListWatchConfig) (*registry.PluginResponse, error) {
 	otCtx, _ := context.WithTimeout(op.Context, op.Timeout)
 	resp, err := lw.Client.Do(otCtx, registry.WatchPrefixOpOptions(lw.Prefix)...)
 	if err != nil {
@@ -42,19 +41,19 @@ func (lw *ListWatcher) List(op ListWatchConfig) (*registry.PluginResponse, error
 	return resp, nil
 }
 
-func (lw *ListWatcher) Revision() int64 {
+func (lw *innerListWatch) Revision() int64 {
 	return lw.rev
 }
 
-func (lw *ListWatcher) setRevision(rev int64) {
+func (lw *innerListWatch) setRevision(rev int64) {
 	lw.rev = rev
 }
 
-func (lw *ListWatcher) Watch(op ListWatchConfig) *Watcher {
-	return newWatcher(lw, op)
+func (lw *innerListWatch) Watch(op ListWatchConfig) Watcher {
+	return newInnerWatcher(lw, op)
 }
 
-func (lw *ListWatcher) doWatch(ctx context.Context, f func(*registry.PluginResponse)) error {
+func (lw *innerListWatch) DoWatch(ctx context.Context, f func(*registry.PluginResponse)) error {
 	rev := lw.Revision()
 	opts := append(
 		registry.WatchPrefixOpOptions(lw.Prefix),
@@ -80,61 +79,3 @@ func (lw *ListWatcher) doWatch(ctx context.Context, f func(*registry.PluginRespo
 	}
 	return err
 }
-
-type Watcher struct {
-	ListOps ListWatchConfig
-	lw      *ListWatcher
-	bus     chan *registry.PluginResponse
-	stopCh  chan struct{}
-	stop    bool
-	mux     sync.Mutex
-}
-
-func (w *Watcher) EventBus() <-chan *registry.PluginResponse {
-	return w.bus
-}
-
-func (w *Watcher) process(_ context.Context) {
-	stopCh := make(chan struct{})
-	ctx, cancel := context.WithTimeout(w.ListOps.Context, w.ListOps.Timeout)
-	util.Go(func(_ context.Context) {
-		defer close(stopCh)
-		w.lw.doWatch(ctx, w.sendEvent)
-	})
-
-	select {
-	case <-stopCh:
-		// timed out or exception
-		w.Stop()
-	case <-w.stopCh:
-		cancel()
-	}
-}
-
-func (w *Watcher) sendEvent(resp *registry.PluginResponse) {
-	defer util.RecoverAndReport()
-	w.bus <- resp
-}
-
-func (w *Watcher) Stop() {
-	w.mux.Lock()
-	if w.stop {
-		w.mux.Unlock()
-		return
-	}
-	w.stop = true
-	close(w.stopCh)
-	close(w.bus)
-	w.mux.Unlock()
-}
-
-func newWatcher(lw *ListWatcher, listOps ListWatchConfig) *Watcher {
-	w := &Watcher{
-		ListOps: listOps,
-		lw:      lw,
-		bus:     make(chan *registry.PluginResponse, EVENT_BUS_MAX_SIZE),
-		stopCh:  make(chan struct{}),
-	}
-	util.Go(w.process)
-	return w
-}
diff --git a/server/core/backend/listwatch_test.go b/server/core/backend/listwatch_test.go
new file mode 100644
index 0000000..1a7b9a9
--- /dev/null
+++ b/server/core/backend/listwatch_test.go
@@ -0,0 +1,119 @@
+/*
+ * 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 backend
+
+import (
+	"fmt"
+	"github.com/apache/incubator-servicecomb-service-center/server/infra/registry"
+	"github.com/apache/incubator-servicecomb-service-center/server/plugin/infra/registry/buildin"
+	"github.com/coreos/etcd/mvcc/mvccpb"
+	"golang.org/x/net/context"
+	"testing"
+	"time"
+)
+
+type mockRegistry struct {
+	*buildin.BuildinRegistry
+	Response *registry.PluginResponse
+	LeaseErr error
+}
+
+func (c *mockRegistry) Do(ctx context.Context, opts ...registry.PluginOpOption) (*registry.PluginResponse, error) {
+	if c.Response == nil {
+		return nil, fmt.Errorf("error")
+	}
+	return c.Response, nil
+}
+func (c *mockRegistry) Watch(ctx context.Context, opts ...registry.PluginOpOption) error {
+	op := registry.OptionsToOp(opts...)
+	if c.Response == nil {
+		return fmt.Errorf("error")
+	}
+	resp := *c.Response
+	if len(c.Response.Kvs) > 0 {
+		resp.Revision = c.Response.Kvs[0].ModRevision
+	}
+	err := op.WatchCallback("ok", &resp)
+	if err != nil {
+		return err
+	}
+	<-ctx.Done()
+	return nil
+}
+func (c *mockRegistry) LeaseRenew(ctx context.Context, leaseID int64) (TTL int64, err error) {
+	if c.LeaseErr != nil {
+		return 0, c.LeaseErr
+	}
+	return 1, nil
+}
+
+func TestPrefixListWatch(t *testing.T) {
+	lw := &innerListWatch{
+		Client: &mockRegistry{},
+		Prefix: "a",
+		rev:    1,
+	}
+	resp, err := lw.List(ListWatchConfig{Timeout: time.Second, Context: context.Background()})
+	if resp != nil || err == nil || lw.Revision() != 1 {
+		t.Fatalf("TestPrefixListWatch failed")
+	}
+	w := lw.Watch(ListWatchConfig{Timeout: time.Second, Context: context.Background()})
+	resp = <-w.EventBus()
+	if resp != nil || lw.Revision() != 0 {
+		t.Fatalf("TestPrefixListWatch failed")
+	}
+	w.Stop()
+
+	test := &registry.PluginResponse{
+		Revision: 2,
+	}
+	lw = &innerListWatch{
+		Client: &mockRegistry{Response: test},
+		Prefix: "a",
+		rev:    1,
+	}
+	resp, err = lw.List(ListWatchConfig{Timeout: time.Second, Context: context.Background()})
+	if resp == nil || err != nil || lw.Revision() != 2 {
+		t.Fatalf("TestPrefixListWatch failed")
+	}
+	w = lw.Watch(ListWatchConfig{Timeout: time.Second, Context: context.Background()})
+	resp = <-w.EventBus()
+	if resp != nil || lw.Revision() != 0 {
+		t.Fatalf("TestPrefixListWatch failed")
+	}
+	w.Stop()
+
+	test = &registry.PluginResponse{
+		Kvs:      []*mvccpb.KeyValue{{ModRevision: 3}},
+		Revision: 4,
+	}
+	lw = &innerListWatch{
+		Client: &mockRegistry{Response: test},
+		Prefix: "a",
+		rev:    1,
+	}
+	resp, err = lw.List(ListWatchConfig{Timeout: time.Second, Context: context.Background()})
+	if resp == nil || err != nil || lw.Revision() != 4 {
+		t.Fatalf("TestPrefixListWatch failed")
+	}
+	w = lw.Watch(ListWatchConfig{Timeout: time.Second, Context: context.Background()})
+	resp = <-w.EventBus()
+	if resp == nil || lw.Revision() != 3 {
+		t.Fatalf("TestPrefixListWatch failed")
+	}
+	w.Stop()
+}
diff --git a/server/core/backend/metrics.go b/server/core/backend/metrics.go
index 2423a7a..2b5f4e8 100644
--- a/server/core/backend/metrics.go
+++ b/server/core/backend/metrics.go
@@ -17,40 +17,31 @@
 package backend
 
 import (
-	"github.com/apache/incubator-servicecomb-service-center/pkg/util"
-	"github.com/apache/incubator-servicecomb-service-center/server/core"
+	"github.com/apache/incubator-servicecomb-service-center/server/metric"
 	"github.com/prometheus/client_golang/prometheus"
-	"sync"
 )
 
 var (
 	cacheSizeGauge = prometheus.NewGaugeVec(
 		prometheus.GaugeOpts{
-			Namespace: "service_center",
+			Namespace: metric.FamilyName,
 			Subsystem: "local",
 			Name:      "cache_size_bytes",
 			Help:      "Local cache size summary of backend store",
 		}, []string{"instance", "resource", "type"})
 )
 
-var (
-	instance string
-	once     sync.Once
-)
-
 func init() {
 	prometheus.MustRegister(cacheSizeGauge)
 }
 
-func ReportCacheMetrics(resource, t string, obj interface{}) {
-	if len(core.Instance.Endpoints) == 0 || len(resource) == 0 {
+func ReportCacheSize(resource, t string, s int) {
+	instance := metric.InstanceName()
+	if len(instance) == 0 || len(resource) == 0 {
 		// endpoints list will be empty when initializing
 		// resource may be empty when report SCHEMA
 		return
 	}
 
-	once.Do(func() {
-		instance, _ = util.ParseEndpoint(core.Instance.Endpoints[0])
-	})
-	cacheSizeGauge.WithLabelValues(instance, resource, t).Set(float64(util.Sizeof(obj)))
+	cacheSizeGauge.WithLabelValues(instance, resource, t).Set(float64(s))
 }
diff --git a/server/core/backend/extend_test.go b/server/core/backend/metrics_test.go
similarity index 65%
copy from server/core/backend/extend_test.go
copy to server/core/backend/metrics_test.go
index 3f1e1af..60766e9 100644
--- a/server/core/backend/extend_test.go
+++ b/server/core/backend/metrics_test.go
@@ -16,30 +16,23 @@
  */
 package backend
 
-import "testing"
+import (
+	"github.com/apache/incubator-servicecomb-service-center/server/metric"
+	"github.com/astaxie/beego"
+	"testing"
+)
 
-type extend struct {
+func init() {
+	beego.AppConfig.Set("httpaddr", "127.0.0.1")
 }
 
-func (e *extend) Name() string {
-	return "test"
-}
-
-func (e *extend) Config() *Config {
-	return DefaultConfig().WithPrefix("/test")
-}
-
-func TestInstallType(t *testing.T) {
-	id, err := InstallType(&extend{})
+func TestReportCacheSize(t *testing.T) {
+	ReportCacheSize("a", "b", 100)
+	err := metric.Gatherer.Collect()
 	if err != nil {
-		t.Fatal(err)
-	}
-	if id == NONEXIST {
-		t.Fatal(err)
+		t.Fatalf("TestReportCacheSize failed")
 	}
-
-	id, err = InstallType(&extend{})
-	if id != NONEXIST || err == nil {
-		t.Fatal("InstallType fail", err)
+	if metric.Gatherer.Records.Get("local_cache_size_bytes") != 100 {
+		t.Fatalf("TestReportCacheSize failed")
 	}
 }
diff --git a/server/core/backend/kv.go b/server/core/backend/model.go
similarity index 79%
rename from server/core/backend/kv.go
rename to server/core/backend/model.go
index f7b6688..2340dd9 100644
--- a/server/core/backend/kv.go
+++ b/server/core/backend/model.go
@@ -28,11 +28,28 @@ type KeyValue struct {
 	ModRevision    int64
 }
 
-func (kv *KeyValue) From(p *Parser, s *mvccpb.KeyValue) (err error) {
+func (kv *KeyValue) From(p Parser, s *mvccpb.KeyValue) (err error) {
 	kv.Key = s.Key
 	kv.Version = s.Version
 	kv.CreateRevision = s.CreateRevision
 	kv.ModRevision = s.ModRevision
+	if p == nil {
+		return
+	}
 	kv.Value, err = p.Unmarshal(s.Value)
 	return
 }
+
+type Response struct {
+	Kvs   []*KeyValue
+	Count int64
+}
+
+func (pr *Response) MaxModRevision() (max int64) {
+	for _, kv := range pr.Kvs {
+		if max < kv.ModRevision {
+			max = kv.ModRevision
+		}
+	}
+	return
+}
diff --git a/server/core/backend/parser.go b/server/core/backend/parser.go
index dff9a2f..26b291d 100644
--- a/server/core/backend/parser.go
+++ b/server/core/backend/parser.go
@@ -66,28 +66,32 @@ var (
 	}
 )
 
-type Parser struct {
-	c CreateValueFunc
-	p ParseValueFunc
+type Parser interface {
+	Unmarshal(src []byte) (interface{}, error)
 }
 
-func (p *Parser) Unmarshal(src []byte) (interface{}, error) {
-	v := p.c()
-	if err := p.p(src, &v); err != nil {
+type CommonParser struct {
+	NewFunc  CreateValueFunc
+	FromFunc ParseValueFunc
+}
+
+func (p *CommonParser) Unmarshal(src []byte) (interface{}, error) {
+	v := p.NewFunc()
+	if err := p.FromFunc(src, &v); err != nil {
 		return nil, err
 	}
 	return v, nil
 }
 
 var (
... 5385 lines suppressed ...