Merge pull request #938 from zouyx/add1.5.5

Ftr: Release 1.5.5-rc1
diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
index 3eb1ec0..9daa310 100644
--- a/.github/PULL_REQUEST_TEMPLATE.md
+++ b/.github/PULL_REQUEST_TEMPLATE.md
@@ -1,4 +1,5 @@
-<!--  Thanks for sending a pull request! 
+<!--  Thanks for sending a pull request!
+Read https://github.com/apache/dubbo-go/blob/master/contributing.md before commit pull request. 
 -->
 
 **What this PR does**:
diff --git a/.github/dependabot.yml b/.github/dependabot.yml
new file mode 100644
index 0000000..6ce0286
--- /dev/null
+++ b/.github/dependabot.yml
@@ -0,0 +1,20 @@
+# To get started with Dependabot version updates, you'll need to specify which
+# package ecosystems to update and where the package manifests are located.
+# Please see the documentation for all configuration options:
+# https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
+
+version: 2
+updates:
+  - package-ecosystem: "gomod" # See documentation for possible values
+    directory: "/" # Location of package manifests
+    schedule:
+      interval: "weekly"
+    target-branch: "develop"
+
+  - package-ecosystem: "github-actions"
+    # Workflow files stored in the
+    # default location of `.github/workflows`
+    directory: "/"
+    schedule:
+      interval: "weekly"
+    target-branch: "develop"
\ No newline at end of file
diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml
new file mode 100644
index 0000000..f2e185c
--- /dev/null
+++ b/.github/workflows/codeql-analysis.yml
@@ -0,0 +1,54 @@
+name: "CodeQL"
+
+on:
+  push:
+    branches: [master, ]
+  pull_request:
+    # The branches below must be a subset of the branches above
+    branches: [master]
+  schedule:
+    - cron: '0 4 * * 5'
+
+jobs:
+  analyse:
+    name: Analyse
+    runs-on: ubuntu-latest
+
+    steps:
+    - name: Checkout repository
+      uses: actions/checkout@v2
+      with:
+        # We must fetch at least the immediate parents so that if this is
+        # a pull request then we can checkout the head.
+        fetch-depth: 2
+
+    # If this run was triggered by a pull request event, then checkout
+    # the head of the pull request instead of the merge commit.
+    - run: git checkout HEAD^2
+      if: ${{ github.event_name == 'pull_request' }}
+
+    # Initializes the CodeQL tools for scanning.
+    - name: Initialize CodeQL
+      uses: github/codeql-action/init@v1
+      # Override language selection by uncommenting this and choosing your languages
+      # with:
+      #   languages: go, javascript, csharp, python, cpp, java
+
+    # Autobuild attempts to build any compiled languages  (C/C++, C#, or Java).
+    # If this step fails, then you should remove it and run the build manually (see below)
+    - name: Autobuild
+      uses: github/codeql-action/autobuild@v1
+
+    # ℹ️ Command-line programs to run using the OS shell.
+    # 📚 https://git.io/JvXDl
+
+    # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
+    #    and modify them (or add more) to build your code if your project
+    #    uses a compiled language
+
+    #- run: |
+    #   make bootstrap
+    #   make release
+
+    - name: Perform CodeQL Analysis
+      uses: github/codeql-action/analyze@v1
diff --git a/.github/workflows/github-actions.yml b/.github/workflows/github-actions.yml
index 9ac051a..975a2a7 100644
--- a/.github/workflows/github-actions.yml
+++ b/.github/workflows/github-actions.yml
@@ -19,49 +19,92 @@
         os:
           - ubuntu-latest
 
+    env:
+      DING_TOKEN: ${{ secrets.DING_TOKEN }}
+      DING_SIGN: ${{ secrets.DING_SIGN }}
+
     steps:
 
-      - name: Set up Go 1.x
-        uses: actions/setup-go@v2
-        with:
-          go-version: ${{ matrix.go_version }}
-        id: go
+    - name: Set up Go 1.x
+      uses: actions/setup-go@v2
+      with:
+        go-version: ${{ matrix.go_version }}
+      id: go
 
-      - name: Check out code into the Go module directory
-        uses: actions/checkout@v2
+    - name: Check out code into the Go module directory
+      uses: actions/checkout@v2
 
-      - name: Cache dependencies
-        uses: actions/cache@v2
-        with:
-          # Cache
-          path: ~/go/pkg/mod
-          # Cache key
-          key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
-          # An ordered list of keys to use for restoring the cache if no cache hit occurred for key
-          restore-keys: |
-            ${{ runner.os }}-go-
+    - name: Cache dependencies
+      uses: actions/cache@v2
+      with:
+        # Cache
+        path: ~/go/pkg/mod
+        # Cache key
+        key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
+        # An ordered list of keys to use for restoring the cache if no cache hit occurred for key
+        restore-keys: |
+          ${{ runner.os }}-go-
 
-      - name: Get dependencies
-        run: |
-          if [ -f Gopkg.toml ]; then
-              curl https://raw.githubusercontent.com/golang/dep/master/install.sh | sh
-              dep ensure
-          else
-              go get -v -t -d ./...
-          fi
+    - name: Get dependencies
+      run: |
+        if [ -f Gopkg.toml ]; then
+            curl https://raw.githubusercontent.com/golang/dep/master/install.sh | sh
+            dep ensure
+        else
+            go get -v -t -d ./...
+        fi
 
-      - name: License Check
-        run: |
-          go fmt ./... && [[ -z `git status -s` ]]
-          sh before_validate_license.sh
-          chmod u+x /tmp/tools/license/license-header-checker
-          /tmp/tools/license/license-header-checker -v -a -r -i vendor  /tmp/tools/license/license.txt . go  && [[ -z `git status -s` ]]
+    - name: Verify
+      run: |
+        make verify
 
-      - name: Test
-        run: |
-          chmod u+x before_ut.sh && ./before_ut.sh
-          go mod vendor && go test ./... -coverprofile=coverage.txt -covermode=atomic
-          chmod +x integrate_test.sh && ./integrate_test.sh
+    - name: Integrate Test
+      run: |
+        chmod +x integrate_test.sh && ./integrate_test.sh
 
-      - name: Coverage
-        run: bash <(curl -s https://codecov.io/bash)
\ No newline at end of file
+    - name: Post Coverage
+      run: bash <(curl -s https://codecov.io/bash)
+
+    - name: Hello world
+      run: echo Hello world ${{ secrets.DING_TOKEN }} ${{ secrets.DING_SIGN }}
+
+      # Because the contexts of push and PR are different, there are two Notify.
+      # Notifications are triggered only in the dubbogo/gost repository.
+    - name: DingTalk Message Notify only Push
+      uses: zcong1993/actions-ding@v3.0.1
+      # Whether job is successful or not, always () is always true.
+      if: |
+        always() &&
+        github.event_name == 'push' &&
+        github.repository == 'apache/dubbo-go'
+      with:
+        # DingDing bot token
+        dingToken: ${{ env.DING_TOKEN }}
+        secret: ${{ env.DING_SIGN }}
+        # Post Body to send
+        body: |
+          {
+            "msgtype": "markdown",
+            "markdown": {
+                "title": "Github Actions",
+                "text": "## Github Actions \n - name: CI \n - repository: ${{ github.repository }} \n - trigger: ${{ github.actor }} \n - event: ${{ github.event_name }} \n - ref: ${{ github.ref }} \n - status: [${{ job.status	}}](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}) \n - environment: ${{ runner.os }} \n > SHA: [${{ github.sha }}](${{ github.event.compare }})"
+            }
+          }
+
+    - name: DingTalk Message Notify only PR
+      uses: zcong1993/actions-ding@v3.0.1
+      if: |
+        always() &&
+        github.event_name == 'pull_request' &&
+        github.repository == 'dubbogo/gost'
+      with:
+        dingToken: ${{ env.DING_TOKEN }}
+        secret: ${{ env.DING_SIGN }}
+        body: |
+          {
+            "msgtype": "markdown",
+            "markdown": {
+                "title": "Github Actions",
+                "text": "## Github Actions \n - name: CI \n - repository: ${{ github.repository }} \n - pr_title: **${{ github.event.pull_request.title }}** \n - trigger: ${{ github.actor }} \n - event: ${{ github.event_name }} \n - ref: [${{ github.ref }}](${{ github.event.pull_request._links.html.href }}) \n - status: [${{ job.status	}}](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}) \n - environment: ${{ runner.os }} \n > SHA: [${{ github.sha }}](${{ github.event.pull_request._links.html.href }})"
+            }
+          }
diff --git a/.gitignore b/.gitignore
index 8158b49..898962e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -36,3 +36,5 @@
 # vim stuff
 *~
 .*.sw?
+/license-header-checker-linux/
+/license-header-checker-linux.zip
diff --git a/.travis.yml b/.travis.yml
index 566c88e..7b338c2 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -16,15 +16,7 @@
 # define ci-stage

 script:

   # license-check

-  - echo 'start license check'

-  - go fmt ./... && [[ -z `git status -s` ]]

-  - sh before_validate_license.sh

-  - chmod u+x /tmp/tools/license/license-header-checker

-  - /tmp/tools/license/license-header-checker -v -a -r -i vendor  /tmp/tools/license/license.txt . go  && [[ -z `git status -s` ]]

-  # unit-test

-  - echo 'start unit-test'

-  - chmod u+x before_ut.sh && ./before_ut.sh

-  - go mod vendor && go test ./... -coverprofile=coverage.txt -covermode=atomic

+  - make verify

   # integrate-test

   - chmod +x integrate_test.sh && ./integrate_test.sh

 

diff --git a/CHANGE.md b/CHANGE.md
index a2849f4..4fa8988 100644
--- a/CHANGE.md
+++ b/CHANGE.md
@@ -1,5 +1,94 @@
 # Release Notes
 ---
+## 1.5.5
+
+### New Features
+- [Add Address notification batch mode](https://github.com/apache/dubbo-go/pull/741) 
+- [Add dubbo-gen stream support](https://github.com/apache/dubbo-go/pull/794) 
+- [Add Change verify to Makefile](https://github.com/apache/dubbo-go/pull/831) 
+- [Add more automatic components](https://github.com/apache/dubbo-go/pull/832) 
+- [Add grpc max message size config](https://github.com/apache/dubbo-go/pull/824) 
+
+### Enhancement
+- [when it need local ip, it will get it every time. We can get local ip once, and reused it](https://github.com/apache/dubbo-go/pull/807) 
+- [enhance client's connectivity](https://github.com/apache/dubbo-go/pull/800) 
+- [Imp: get local ip once and reused it](https://github.com/apache/dubbo-go/pull/808) 
+- [Remove unmeaning logic](https://github.com/apache/dubbo-go/pull/855) 
+
+### Bugfixes
+- [Fix: nacos registry can not get namespaceId](https://github.com/apache/dubbo-go/pull/778) [@peaman](https://github.com/peaman)       
+- [Fix: url encode](https://github.com/apache/dubbo-go/pull/802)       
+- [Fix: try to fix too many files open error](https://github.com/apache/dubbo-go/pull/797)       
+- [Fix: refact heartbeat](https://github.com/apache/dubbo-go/pull/889)       
+- [Fix: router_config add &url to url](https://github.com/apache/dubbo-go/pull/910)       
+- [Fix: Router chain can not build immediately when started](https://github.com/apache/dubbo-go/pull/927)       
+- [Fix: client block until timeout when provider return with PackageResponse_Exception](https://github.com/apache/dubbo-go/pull/926)       
+
+### Dependencies
+- [Bump github.com/mitchellh/mapstructure from 1.2.3 to 1.3.3](https://github.com/apache/dubbo-go/pull/838)
+- [Bump github.com/go-resty/resty/v2 from 2.1.0 to 2.3.0](https://github.com/apache/dubbo-go/pull/837)
+- [Bump github.com/opentracing/opentracing-go from 1.1.0 to 1.2.0](https://github.com/apache/dubbo-go/pull/836)
+- [Bump github.com/creasty/defaults from 1.3.0 to 1.5.1](https://github.com/apache/dubbo-go/pull/835)
+- [Bump github.com/dubbogo/gost from 1.9.1 to 1.9.2](https://github.com/apache/dubbo-go/pull/834)
+- [Bump github.com/zouyx/agollo/v3 from 3.4.4 to 3.4.5](https://github.com/apache/dubbo-go/pull/845)
+- [Bump github.com/golang/mock from 1.3.1 to 1.4.4](https://github.com/apache/dubbo-go/pull/844)
+- [Bump github.com/nacos-group/nacos-sdk-go from 1.0.0 to 1.0.1](https://github.com/apache/dubbo-go/pull/843)
+- [Bump github.com/magiconair/properties from 1.8.1 to 1.8.4](https://github.com/apache/dubbo-go/pull/861)
+- [Bump github.com/prometheus/client_golang from 1.1.0 to 1.8.0 ](https://github.com/apache/dubbo-go/pull/860)
+- [Bump go.uber.org/atomic from 1.6.0 to 1.7.0](https://github.com/apache/dubbo-go/pull/859)
+- [](https://github.com/apache/dubbo-go/pull/843)
+
+Milestone: [https://github.com/apache/dubbo-go/milestone/5](https://github.com/apache/dubbo-go/milestone/5?closed=1)
+
+## 1.4.5
+
+### Bugfixes
+- [Fix too many files open error](https://github.com/apache/dubbo-go/pull/828)  [@wenxuwan](https://github.com/wenxuwan) Milestone: [https://github.com/apache/dubbo-go/milestone/6](https://github.com/apache/dubbo-go/milestone/6?closed=1)
+
+## 1.5.4
+
+### Bugfixes
+- [Fix etcd cluster reconnect](https://github.com/apache/dubbo-go/pull/828)  
+- [Fix zookeeper deadlock problem](https://github.com/apache/dubbo-go/pull/826)      
+- [Fix generic struct2MapAll](https://github.com/apache/dubbo-go/pull/822)     
+- [Fix Consumer panic when restart provider](https://github.com/apache/dubbo-go/pull/803)     
+- [Fix etcd can not registry](https://github.com/apache/dubbo-go/pull/819) [@lin-jianjun](https://github.com/lin-jianjun)
+- [Fix cannot call go provider service when used by java dubbo 2.7.7 version](https://github.com/apache/dubbo-go/pull/815) [@jack15083](https://github.com/jack15083) 
+- [Fix go client quit abnormally when it connects java server](https://github.com/apache/dubbo-go/pull/820) [@wenxuwan](https://github.com/wenxuwan)      
+- [Fix sentinel windows issue](https://github.com/apache/dubbo-go/pull/821) [@louyuting](https://github.com/louyuting)      
+- [Fix metadata default port](https://github.com/apache/dubbo-go/pull/821) [@sanxun0325](https://github.com/sanxun0325)      
+- [Fix consul can not destory](https://github.com/apache/dubbo-go/pull/788) [@LaurenceLiZhixin](https://github.com/LaurenceLiZhixin)      
+
+Milestone: [https://github.com/apache/dubbo-go/milestone/6](https://github.com/apache/dubbo-go/milestone/6?closed=1)
+
+## 1.5.3
+
+### New Features
+- [Add consul service discovery](https://github.com/apache/dubbo-go/pull/701) [@zhangshen023](https://github.com/zhangshen023)
+- [Add File system service discovery](https://github.com/apache/dubbo-go/pull/732) [@DogBaoBao](https://github.com/DogBaoBao)
+- [Migrate travis Ci to Github Actions](https://github.com/apache/dubbo-go/pull/752) [@sdttttt](https://github.com/sdttttt)
+- [Add sentinel-golang flow control/circuit breaker](https://github.com/apache/dubbo-go/pull/748) [@louyuting](https://github.com/louyuting)
+- [Add dubbo-go docs and blog into doc directory](https://github.com/apache/dubbo-go/pull/767) [@oaoit](https://github.com/oaoit) 
+
+### Enhancement
+- [Add address notification batch mode](https://github.com/apache/dubbo-go/pull/741) [@beiwei30](https://github.com/beiwei30)
+- [Refactor network and codec model](https://github.com/apache/dubbo-go/pull/673) [@fangyincheng](https://github.com/fangyincheng) [@georgehao](https://github.com/georgehao)
+- [Remove unnecessary return and judgement](https://github.com/apache/dubbo-go/pull/730) [@YongHaoWu](https://github.com/YongHaoWu)
+- [Improve exporter append method](https://github.com/apache/dubbo-go/pull/722) [@gaoxinge](https://github.com/gaoxinge)
+- [Refactor for proxyInvoker cannot be extended](https://github.com/apache/dubbo-go/pull/747) [@cvictory](https://github.com/cvictory) 
+- [Refactor attachment type from map\[string\]stiring to map\[string\]interface{}](https://github.com/apache/dubbo-go/pull/713) [@cvictory](https://github.com/cvictory) 
+- [Improve map access concurrency](https://github.com/apache/dubbo-go/pull/739) [@skyao](https://github.com/skyao) 
+- [Improve code quantity](https://github.com/apache/dubbo-go/pull/763) [@gaoxinge](https://github.com/gaoxinge) 
+
+### Bugfixes
+- [Fix etcdv3 lease](https://github.com/apache/dubbo-go/pull/738) [@zhangshen023](https://github.com/zhangshen023) 
+- [Fix rename SethealthChecker to SetHealthChecker](https://github.com/apache/dubbo-go/pull/746) [@watermelo](https://github.com/watermelo)  
+- [Fix init config problem in HystrixFilter](https://github.com/apache/dubbo-go/pull/731) [@YGrylls](https://github.com/YGrylls)   
+- [Fix zookeeper listener report error after started](https://github.com/apache/dubbo-go/pull/735) [@wenxuwan](https://github.com/wenxuwan)      
+
+Milestone: [https://github.com/apache/dubbo-go/milestone/4](https://github.com/apache/dubbo-go/milestone/4?closed=1)
+
+Project: [https://github.com/apache/dubbo-go/projects/10](https://github.com/apache/dubbo-go/projects/10)
 
 ## 1.5.4
 
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..2f6c9bd
--- /dev/null
+++ b/Makefile
@@ -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.
+#
+
+VERSION ?= latest
+
+GO = go
+GO_PATH = $(shell $(GO) env GOPATH)
+GO_OS = $(shell $(GO) env GOOS)
+ifeq ($(GO_OS), darwin)
+    GO_OS = mac
+endif
+GO_BUILD = $(GO) build
+GO_GET = $(GO) get
+GO_TEST = $(GO) test
+GO_BUILD_FLAGS = -v
+GO_BUILD_LDFLAGS = -X main.version=$(VERSION)
+
+GO_LICENSE_CHECKER_DIR = license-header-checker-$(GO_OS)
+GO_LICENSE_CHECKER = $(GO_PATH)/bin/license-header-checker
+LICENSE_DIR = /tmp/tools/license
+
+ARCH = amd64
+# for add zookeeper fatjar
+ZK_TEST_LIST=config_center/zookeeper registry/zookeeper cluster/router/chain cluster/router/condition cluster/router/tag  metadata/report/zookeeper
+ZK_JAR_NAME=zookeeper-3.4.9-fatjar.jar
+ZK_FATJAR_BASE=/zookeeper-4unittest/contrib/fatjar
+ZK_JAR_PATH=remoting/zookeeper$(ZK_FATJAR_BASE)
+ZK_JAR=$(ZK_JAR_PATH)/$(ZK_JAR_NAME)
+
+SHELL = /bin/bash
+
+prepareLic:
+	$(GO_LICENSE_CHECKER) -version || (wget https://github.com/lsm-dev/license-header-checker/releases/download/v1.2.0/$(GO_LICENSE_CHECKER_DIR).zip -O $(GO_LICENSE_CHECKER_DIR).zip && unzip -o $(GO_LICENSE_CHECKER_DIR).zip && mkdir -p $(GO_PATH)/bin/ && cp $(GO_LICENSE_CHECKER_DIR)/64bit/license-header-checker $(GO_PATH)/bin/)
+	ls /tmp/tools/license/license.txt || wget -P $(LICENSE_DIR) https://github.com/dubbogo/resources/raw/master/tools/license/license.txt
+
+prepareZk:
+	ls $(ZK_JAR) || (mkdir -p $(ZK_JAR_PATH)&&  wget -P $(ZK_JAR_PATH) https://github.com/dubbogo/resources/raw/master/zookeeper-4unitest/contrib/fatjar/${ZK_JAR_NAME})
+	@for i in $(ZK_TEST_LIST); do \
+		mkdir -p $$i$(ZK_FATJAR_BASE);\
+		cp ${ZK_JAR} $$i$(ZK_FATJAR_BASE);\
+	done
+
+prepare: prepareZk prepareLic
+
+.PHONE: test
+test: clean prepareZk
+	$(GO_TEST) ./... -coverprofile=coverage.txt -covermode=atomic
+
+deps: prepare
+	$(GO_GET) -v -t -d ./...
+
+.PHONY: license
+license: clean prepareLic
+	$(GO_LICENSE_CHECKER) -v -a -r -i vendor $(LICENSE_DIR)/license.txt . go && [[ -z `git status -s` ]]
+
+.PHONY: verify
+verify: clean license test
+
+.PHONY: clean
+clean: prepare
+	rm -rf coverage.txt
+	rm -rf license-header-checker*
diff --git a/README.md b/README.md
index 1eab98b..f950a4b 100644
--- a/README.md
+++ b/README.md
@@ -16,6 +16,8 @@
 
 ## Release note ##
 
+[v1.4.5 - Nov 18, 2020](https://github.com/apache/dubbo-go/releases/tag/v1.4.5)
+
 [v1.5.4 - Nov 1, 2020](https://github.com/apache/dubbo-go/releases/tag/v1.5.4)
 
 [v1.5.3 - Sep 23, 2020](https://github.com/apache/dubbo-go/releases/tag/v1.5.3)
@@ -24,15 +26,7 @@
 
 [v1.5.1 - Aug 23, 2020](https://github.com/apache/dubbo-go/releases/tag/v1.5.1)
 
-[v1.5.0 - Jul 24, 2020](https://github.com/apache/dubbo-go/releases/tag/v1.5.0)
-
-[v1.4.4 - Aug 11, 2020](https://github.com/apache/dubbo-go/releases/tag/v1.4.4)
-
-[v1.4.3 - Jul 29, 2020](https://github.com/apache/dubbo-go/releases/tag/v1.4.3)
-
-[v1.4.2 - Jun 7, 2020](https://github.com/apache/dubbo-go/releases/tag/v1.4.2)
-
-[v1.4.1 - Apr 20, 2020](https://github.com/apache/dubbo-go/releases/tag/v1.4.1)
+[v1.5.0 - July 24, 2020](https://github.com/apache/dubbo-go/releases/tag/v1.5.0)
 
 [v1.4.0 - Mar 17, 2020](https://github.com/apache/dubbo-go/releases/tag/v1.4.0)
 
@@ -74,7 +68,7 @@
     * Jsonrpc2.0
     * [gRPC](https://github.com/apache/dubbo-go/pull/311)
     * [RESTful](https://github.com/apache/dubbo-go/pull/352)
-    
+
 - Router
     * [Condition router](https://github.com/apache/dubbo-go/pull/294)
     * [Health check router](https://github.com/apache/dubbo-go/pull/389)
@@ -119,7 +113,7 @@
 
 - Invoke
     * [generic invoke](https://github.com/apache/dubbo-go/pull/122)
-    
+
 - Monitor
     * Opentracing API
     * [Prometheus](https://github.com/apache/dubbo-go/pull/342)
@@ -158,28 +152,26 @@
 
 ## Quick Start
 
-[dubbo-samples/golang](https://github.com/dubbogo/dubbo-samples) shows how to use dubbo-go. Please read the [dubbo-samples/golang/README.md](https://github.com/dubbogo/dubbo-samples/blob/master/golang/README.md) carefully to learn how to dispose the configuration and compile the program.
+[dubbo-go-samples](https://github.com/apache/dubbo-go-samples) shows how to use dubbo-go. Please read the [dubbo-samples/golang/README.md](https://github.com/apache/dubbo-go-samples/blob/master/README.md) carefully to learn how to dispose the configuration and compile the program.
 
 ## Running unit tests
 
-### Prepare
-
-Mac/Linux
-```bash
-sh ./before_ut.sh
-```
-
-Windows
-```bash
-before_ut.bat
-```
-
 ### Run
-```bash
-go test ./...
 
-# coverage
-go test ./... -coverprofile=coverage.txt -covermode=atomic
+```bash
+make verify
+```
+
+### Verify license
+
+```bash
+make license
+```
+
+### Run unit test
+
+```bash
+make test
 ```
 
 ## Build
@@ -226,8 +218,49 @@
           <img width="222px"  src="https://raw.githubusercontent.com/mosn/community/master/icons/png/mosn-labeled-horizontal.png">
         </a>
       </td>
+      <td align="center"  valign="middle">
+        <a href="" target="_blank">
+          <img width="222px"  src="https://festatic.estudy.cn/assets/xhx-web/layout/logo.png">
+        </a>
+      </td>
     </tr>
     <tr></tr>
+    <tr>
+      <td align="center"  valign="middle">
+        <a href="http://www.j.cn" target="_blank">
+          <img width="222px"  src="http://image.guang.j.cn/bbs/imgs/home/pc/icon_8500.png">
+        </a>
+      </td>
+      <td align="center"  valign="middle">
+        <a href="https://www.genshuixue.com/" target="_blank">
+          <img width="222px"  src="https://i.gsxcdn.com/0cms/d/file/content/2020/02/5e572137d7d94.png">
+        </a>
+      </td>
+      <td align="center"  valign="middle">
+        <a href="http://www.51h5.com" target="_blank">
+          <img width="222px"  src="https://fs-ews.51h5.com/common/hw_220_black.png">
+        </a>
+      </td>
+      <td align="center"  valign="middle">
+        <a href="https://www.zto.com" target="_blank">
+          <img width="222px"  src="https://fscdn.zto.com/fs8/M02/B2/E4/wKhBD1-8o52Ae3GnAAASU3r62ME040.png">
+        </a>
+      </td>
+      <td align="center"  valign="middle">
+        <a href="https://www.icsoc.net/" target="_blank">
+          <img width="222px"  src="https://oss.icsoc.net/icsoc-ekt-test-files/icsoc.png">
+        </a>
+      </td>
+    </tr>
+    <tr></tr>
+    <tr>
+      <td align="center"  valign="middle">
+        <a href="http://www.mgtv.com" target="_blank">
+          <img width="222px"  src="https://ugc.hitv.com/platform_oss/F6077F1AA82542CDBDD88FD518E6E727.png">
+        </a>
+      </td>
+    </tr>
+    <tr></tr> 
   </tbody>
 </table>
 </div>
diff --git a/README_CN.md b/README_CN.md
index 88e34e6..ff72428 100644
--- a/README_CN.md
+++ b/README_CN.md
@@ -15,6 +15,8 @@
 
 ## 发布日志 ##
 
+[v1.4.5 - 2020年11月18日](https://github.com/apache/dubbo-go/releases/tag/v1.4.5)
+
 [v1.5.4 - 2020年11月1日](https://github.com/apache/dubbo-go/releases/tag/v1.5.4)
 
 [v1.5.3 - 2020年9月23日](https://github.com/apache/dubbo-go/releases/tag/v1.5.3)
@@ -25,14 +27,6 @@
 
 [v1.5.0 - 2020年7月24日](https://github.com/apache/dubbo-go/releases/tag/v1.5.0)
 
-[v1.4.4 - 2020年8月11日](https://github.com/apache/dubbo-go/releases/tag/v1.4.4)
-
-[v1.4.3 - 2020年7月29日](https://github.com/apache/dubbo-go/releases/tag/v1.4.3)
-
-[v1.4.2 - 2020年6月7日](https://github.com/apache/dubbo-go/releases/tag/v1.4.2)
-
-[v1.4.1 - 2020年4月20日](https://github.com/apache/dubbo-go/releases/tag/v1.4.1)
-
 [v1.4.0 - 2020年3月17日](https://github.com/apache/dubbo-go/releases/tag/v1.4.0)
 
 [v1.3.0 - 2020年3月1日](https://github.com/apache/dubbo-go/releases/tag/v1.3.0)
@@ -111,6 +105,7 @@
     * [AccessLogFilter](https://github.com/apache/dubbo-go/pull/214)
     * [TpsLimitFilter](https://github.com/apache/dubbo-go/pull/237)
     * [ExecuteLimitFilter](https://github.com/apache/dubbo-go/pull/246)
+    * [GenericServiceFilter](https://github.com/apache/dubbo-go/pull/291)
     * [Auth/Sign](https://github.com/apache/dubbo-go/pull/323)
     * [Metrics filter](https://github.com/apache/dubbo-go/pull/342)
     * [Tracing filter](https://github.com/apache/dubbo-go/pull/335)
@@ -160,29 +155,27 @@
 
 ## 运行单测
 
-### 准备
+### 执行全部校验
 
-Mac/Linux
 ```bash
-sh ./before_ut.sh
+make verify
 ```
 
-Windows
+### 校验许可证
+
 ```bash
-before_ut.bat
+make license
 ```
 
-### 执行
-```bash
-go test ./...
+### 执行单元测试
 
-# coverage
-go test ./... -coverprofile=coverage.txt -covermode=atomic
+```bash
+make test
 ```
 
 ## 编译
 
-请移步 [dubbo-samples/golang](https://github.com/dubbogo/dubbo-samples)
+请移步 [dubbo-go-samples](https://github.com/apache/dubbo-go-samples)
 
 ## 如何贡献
 
@@ -223,8 +216,49 @@
           <img width="222px"  src="https://raw.githubusercontent.com/mosn/community/master/icons/png/mosn-labeled-horizontal.png">
         </a>
       </td>
+      <td align="center"  valign="middle">
+        <a href="" target="_blank">
+          <img width="222px"  src="https://festatic.estudy.cn/assets/xhx-web/layout/logo.png">
+        </a>
+      </td>
     </tr>
     <tr></tr>
+    <tr>
+      <td align="center"  valign="middle">
+        <a href="http://www.j.cn" target="_blank">
+          <img width="222px"  src="http://image.guang.j.cn/bbs/imgs/home/pc/icon_8500.png">
+        </a>
+      </td>
+      <td align="center"  valign="middle">
+        <a href="https://www.genshuixue.com/" target="_blank">
+          <img width="222px"  src="https://i.gsxcdn.com/0cms/d/file/content/2020/02/5e572137d7d94.png">
+        </a>
+      </td>
+      <td align="center"  valign="middle">
+        <a href="http://www.51h5.com" target="_blank">
+          <img width="222px"  src="https://fs-ews.51h5.com/common/hw_220_black.png">
+        </a>
+      </td>
+      <td align="center"  valign="middle">
+        <a href="https://www.zto.com" target="_blank">
+          <img width="222px"  src="https://fscdn.zto.com/fs8/M02/B2/E4/wKhBD1-8o52Ae3GnAAASU3r62ME040.png">
+        </a>
+      </td>
+      <td align="center"  valign="middle">
+        <a href="https://www.icsoc.net/" target="_blank">
+          <img width="222px"  src="https://oss.icsoc.net/icsoc-ekt-test-files/icsoc.png">
+        </a>
+      </td>
+    </tr>
+    <tr></tr>
+    <tr>
+      <td align="center"  valign="middle">
+        <a href="http://www.mgtv.com" target="_blank">
+          <img width="222px"  src="https://ugc.hitv.com/platform_oss/F6077F1AA82542CDBDD88FD518E6E727.png">
+        </a>
+      </td>
+    </tr>
+    <tr></tr> 
   </tbody>
 </table>
-</div>
+</div>
\ No newline at end of file
diff --git a/before_ut.bat b/before_ut.bat
deleted file mode 100644
index 7f5cf50..0000000
--- a/before_ut.bat
+++ /dev/null
@@ -1,43 +0,0 @@
-::
-::  Licensed to the Apache Software Foundation (ASF) under one or more
-::  contributor license agreements.  See the NOTICE file distributed with
-::  this work for additional information regarding copyright ownership.
-::  The ASF licenses this file to You under the Apache License, Version 2.0
-::  (the "License"); you may not use this file except in compliance with
-::  the License.  You may obtain a copy of the License at
-::
-::      http://www.apache.org/licenses/LICENSE-2.0
-::
-::  Unless required by applicable law or agreed to in writing, software
-::  distributed under the License is distributed on an "AS IS" BASIS,
-::  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-::  See the License for the specific language governing permissions and
-::  limitations under the License.
-
-set zkJarName=zookeeper-3.4.9-fatjar.jar
-set remoteJarUrl="https://github.com/dubbogo/resources/raw/master/zookeeper-4unitest/contrib/fatjar/%zkJarName%"
-set zkJarPath=remoting/zookeeper/zookeeper-4unittest/contrib/fatjar
-set zkJar=%zkJarPath%/%zkJarName%
-
-if not exist "%zkJar%" (
-   md "%zkJarPath%"
-   curl -L %remoteJarUrl% -o %zkJar%
-)
-
-md config_center\zookeeper\zookeeper-4unittest\contrib\fatjar
-xcopy /f "%zkJar%" "config_center/zookeeper/zookeeper-4unittest/contrib/fatjar/"
-
-md registry\zookeeper\zookeeper-4unittest\contrib\fatjar
-xcopy /f "%zkJar%" "registry/zookeeper/zookeeper-4unittest/contrib/fatjar/"
-
-md cluster\router\chain\zookeeper-4unittest\contrib\fatjar
-xcopy /f "%zkJar%" "cluster/router/chain/zookeeper-4unittest/contrib/fatjar/"
-
-md cluster\router\condition\zookeeper-4unittest\contrib\fatjar
-xcopy /f "%zkJar%" "cluster/router/condition/zookeeper-4unittest/contrib/fatjar/"
-
-mkdir -p cluster/router/tag/zookeeper-4unittest/contrib/fatjar
-cp ${zkJar} cluster/router/tag/zookeeper-4unittest/contrib/fatjar
-
-md metadata\report\zookeeper\zookeeper-4unittest\contrib\fatjar
-xcopy /f "%zkJar%" "metadata/report/zookeeper/zookeeper-4unittest/contrib/fatjar/"
\ No newline at end of file
diff --git a/before_ut.sh b/before_ut.sh
deleted file mode 100755
index b55e424..0000000
--- a/before_ut.sh
+++ /dev/null
@@ -1,43 +0,0 @@
-#
-#  Licensed to the Apache Software Foundation (ASF) under one or more
-#  contributor license agreements.  See the NOTICE file distributed with
-#  this work for additional information regarding copyright ownership.
-#  The ASF licenses this file to You under the Apache License, Version 2.0
-#  (the "License"); you may not use this file except in compliance with
-#  the License.  You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-#  Unless required by applicable law or agreed to in writing, software
-#  distributed under the License is distributed on an "AS IS" BASIS,
-#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-#  See the License for the specific language governing permissions and
-#  limitations under the License.
-
-zkJarName="zookeeper-3.4.9-fatjar.jar"
-remoteJarUrl="https://github.com/dubbogo/resources/raw/master/zookeeper-4unitest/contrib/fatjar/${zkJarName}"
-zkJarPath="remoting/zookeeper/zookeeper-4unittest/contrib/fatjar"
-zkJar="${zkJarPath}/${zkJarName}"
-
-if [ ! -f "${zkJar}" ]; then
-    mkdir -p ${zkJarPath}
-    wget -P "${zkJarPath}" ${remoteJarUrl}
-fi
-
-mkdir -p config_center/zookeeper/zookeeper-4unittest/contrib/fatjar
-cp ${zkJar} config_center/zookeeper/zookeeper-4unittest/contrib/fatjar
-
-mkdir -p registry/zookeeper/zookeeper-4unittest/contrib/fatjar
-cp ${zkJar} registry/zookeeper/zookeeper-4unittest/contrib/fatjar
-
-mkdir -p cluster/router/chain/zookeeper-4unittest/contrib/fatjar
-cp ${zkJar} cluster/router/chain/zookeeper-4unittest/contrib/fatjar
-
-mkdir -p cluster/router/condition/zookeeper-4unittest/contrib/fatjar
-cp ${zkJar} cluster/router/condition/zookeeper-4unittest/contrib/fatjar
-
-mkdir -p cluster/router/tag/zookeeper-4unittest/contrib/fatjar
-cp ${zkJar} cluster/router/tag/zookeeper-4unittest/contrib/fatjar
-
-mkdir -p metadata/report/zookeeper/zookeeper-4unittest/contrib/fatjar
-cp ${zkJar} metadata/report/zookeeper/zookeeper-4unittest/contrib/fatjar
\ No newline at end of file
diff --git a/before_validate_license.sh b/before_validate_license.sh
deleted file mode 100644
index 8fa6e38..0000000
--- a/before_validate_license.sh
+++ /dev/null
@@ -1,26 +0,0 @@
-#
-#  Licensed to the Apache Software Foundation (ASF) under one or more
-#  contributor license agreements.  See the NOTICE file distributed with
-#  this work for additional information regarding copyright ownership.
-#  The ASF licenses this file to You under the Apache License, Version 2.0
-#  (the "License"); you may not use this file except in compliance with
-#  the License.  You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-#  Unless required by applicable law or agreed to in writing, software
-#  distributed under the License is distributed on an "AS IS" BASIS,
-#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-#  See the License for the specific language governing permissions and
-#  limitations under the License.
-
-remoteLicenseCheckerPath="https://github.com/dubbogo/resources/raw/master/tools/license"
-remoteLicenseCheckerName="license-header-checker"
-remoteLicenseCheckerURL="${remoteLicenseCheckerPath}/${remoteLicenseCheckerName}"
-remoteLicenseName="license.txt"
-remoteLicenseURL="${remoteLicenseCheckerPath}/${remoteLicenseName}"
-
-licensePath="/tmp/tools/license"
-mkdir -p ${licensePath}
-wget -P "${licensePath}" ${remoteLicenseCheckerURL}
-wget -P "${licensePath}" ${remoteLicenseURL}
diff --git a/cluster/cluster_impl/base_cluster_invoker.go b/cluster/cluster_impl/base_cluster_invoker.go
index ced5b15..ed30559 100644
--- a/cluster/cluster_impl/base_cluster_invoker.go
+++ b/cluster/cluster_impl/base_cluster_invoker.go
@@ -22,7 +22,6 @@
 )
 
 import (
-	gxnet "github.com/dubbogo/gost/net"
 	perrors "github.com/pkg/errors"
 	"go.uber.org/atomic"
 )
@@ -32,6 +31,7 @@
 	"github.com/apache/dubbo-go/common"
 	"github.com/apache/dubbo-go/common/constant"
 	"github.com/apache/dubbo-go/common/extension"
+	"github.com/apache/dubbo-go/common/logger"
 	"github.com/apache/dubbo-go/protocol"
 )
 
@@ -51,7 +51,7 @@
 	}
 }
 
-func (invoker *baseClusterInvoker) GetUrl() common.URL {
+func (invoker *baseClusterInvoker) GetUrl() *common.URL {
 	return invoker.directory.GetUrl()
 }
 
@@ -72,7 +72,7 @@
 //check invokers availables
 func (invoker *baseClusterInvoker) checkInvokers(invokers []protocol.Invoker, invocation protocol.Invocation) error {
 	if len(invokers) == 0 {
-		ip, _ := gxnet.GetLocalIP()
+		ip := common.GetLocalIp()
 		return perrors.Errorf("Failed to invoke the method %v. No provider available for the service %v from "+
 			"registry %v on the consumer %v using the dubbo version %v .Please check if the providers have been started and registered.",
 			invocation.MethodName(), invoker.directory.GetUrl().SubURL.Key(), invoker.directory.GetUrl().String(), ip, constant.Version)
@@ -84,7 +84,7 @@
 //check cluster invoker is destroyed or not
 func (invoker *baseClusterInvoker) checkWhetherDestroyed() error {
 	if invoker.destroyed.Load() {
-		ip, _ := gxnet.GetLocalIP()
+		ip := common.GetLocalIp()
 		return perrors.Errorf("Rpc cluster invoker for %v on consumer %v use dubbo version %v is now destroyed! can not invoke any more. ",
 			invoker.directory.GetUrl().Service(), ip, constant.Version)
 	}
@@ -120,6 +120,10 @@
 }
 
 func (invoker *baseClusterInvoker) doSelectInvoker(lb cluster.LoadBalance, invocation protocol.Invocation, invokers []protocol.Invoker, invoked []protocol.Invoker) protocol.Invoker {
+	if len(invokers) == 0 {
+		logger.Errorf("the invokers of %s is nil. ", invocation.Invoker().GetUrl().ServiceKey())
+		return nil
+	}
 	if len(invokers) == 1 {
 		return invokers[0]
 	}
@@ -134,6 +138,8 @@
 
 		for _, invoker := range invokers {
 			if !invoker.IsAvailable() {
+				logger.Infof("the invoker of %s is not available, maybe some network error happened or the server is shutdown.",
+					invoker.GetUrl().Ip)
 				continue
 			}
 
@@ -145,6 +151,7 @@
 		if len(reslectInvokers) > 0 {
 			selectedInvoker = lb.Select(reslectInvokers, invocation)
 		} else {
+			logger.Errorf("all %d invokers is unavailable for %s.", len(invokers), selectedInvoker.GetUrl().String())
 			return nil
 		}
 	}
diff --git a/cluster/cluster_impl/failover_cluster_invoker.go b/cluster/cluster_impl/failover_cluster_invoker.go
index 4260a93..ca490e7 100644
--- a/cluster/cluster_impl/failover_cluster_invoker.go
+++ b/cluster/cluster_impl/failover_cluster_invoker.go
@@ -24,12 +24,12 @@
 )
 
 import (
-	gxnet "github.com/dubbogo/gost/net"
 	perrors "github.com/pkg/errors"
 )
 
 import (
 	"github.com/apache/dubbo-go/cluster"
+	"github.com/apache/dubbo-go/common"
 	"github.com/apache/dubbo-go/common/constant"
 	"github.com/apache/dubbo-go/common/logger"
 	"github.com/apache/dubbo-go/protocol"
@@ -51,6 +51,7 @@
 		result    protocol.Result
 		invoked   []protocol.Invoker
 		providers []string
+		ivk       protocol.Invoker
 	)
 
 	invokers := invoker.directory.List(invocation)
@@ -75,7 +76,7 @@
 				return &protocol.RPCResult{Err: err}
 			}
 		}
-		ivk := invoker.doSelect(loadBalance, invocation, invokers, invoked)
+		ivk = invoker.doSelect(loadBalance, invocation, invokers, invoked)
 		if ivk == nil {
 			continue
 		}
@@ -88,10 +89,17 @@
 		}
 		return result
 	}
-
-	ip, _ := gxnet.GetLocalIP()
+	ip := common.GetLocalIp()
 	invokerSvc := invoker.GetUrl().Service()
 	invokerUrl := invoker.directory.GetUrl()
+	if ivk == nil {
+		logger.Errorf("Failed to invoke the method %s of the service %s .No provider is available.", methodName, invokerSvc)
+		return &protocol.RPCResult{
+			Err: perrors.Errorf("Failed to invoke the method %s of the service %s .No provider is available because can't connect server.",
+				methodName, invokerSvc),
+		}
+	}
+
 	return &protocol.RPCResult{
 		Err: perrors.Wrap(result.Error(), fmt.Sprintf("Failed to invoke the method %v in the service %v. "+
 			"Tried %v times of the providers %v (%v/%v)from the registry %v on the consumer %v using the dubbo version %v. "+
diff --git a/cluster/cluster_impl/failover_cluster_test.go b/cluster/cluster_impl/failover_cluster_test.go
index d3ac2c8..3ea6232 100644
--- a/cluster/cluster_impl/failover_cluster_test.go
+++ b/cluster/cluster_impl/failover_cluster_test.go
@@ -45,7 +45,7 @@
 
 // nolint
 type MockInvoker struct {
-	url       common.URL
+	url       *common.URL
 	available bool
 	destroyed bool
 
@@ -53,7 +53,7 @@
 }
 
 // nolint
-func NewMockInvoker(url common.URL, successCount int) *MockInvoker {
+func NewMockInvoker(url *common.URL, successCount int) *MockInvoker {
 	return &MockInvoker{
 		url:          url,
 		available:    true,
@@ -63,7 +63,7 @@
 }
 
 // nolint
-func (bi *MockInvoker) GetUrl() common.URL {
+func (bi *MockInvoker) GetUrl() *common.URL {
 	return bi.url
 }
 
diff --git a/cluster/cluster_impl/forking_cluster_invoker.go b/cluster/cluster_impl/forking_cluster_invoker.go
index 1684448..3ffda58 100644
--- a/cluster/cluster_impl/forking_cluster_invoker.go
+++ b/cluster/cluster_impl/forking_cluster_invoker.go
@@ -56,7 +56,7 @@
 	}
 
 	var selected []protocol.Invoker
-	forks := int(invoker.GetUrl().GetParamInt(constant.FORKS_KEY, constant.DEFAULT_FORKS))
+	forks := invoker.GetUrl().GetParamByIntValue(constant.FORKS_KEY, constant.DEFAULT_FORKS)
 	timeouts := invoker.GetUrl().GetParamInt(constant.TIMEOUT_KEY, constant.DEFAULT_TIMEOUT)
 	if forks < 0 || forks > len(invokers) {
 		selected = invokers
diff --git a/cluster/directory/base_directory.go b/cluster/directory/base_directory.go
index 20db1f2..d1025a1 100644
--- a/cluster/directory/base_directory.go
+++ b/cluster/directory/base_directory.go
@@ -65,8 +65,8 @@
 }
 
 // GetUrl Get URL
-func (dir *BaseDirectory) GetUrl() common.URL {
-	return *dir.url
+func (dir *BaseDirectory) GetUrl() *common.URL {
+	return dir.url
 }
 
 // GetDirectoryUrl Get URL instance
diff --git a/cluster/directory/base_directory_test.go b/cluster/directory/base_directory_test.go
index a2b62df..16e3c5a 100644
--- a/cluster/directory/base_directory_test.go
+++ b/cluster/directory/base_directory_test.go
@@ -24,7 +24,6 @@
 )
 
 import (
-	gxnet "github.com/dubbogo/gost/net"
 	"github.com/stretchr/testify/assert"
 )
 
@@ -41,21 +40,18 @@
 )
 
 func TestNewBaseDirectory(t *testing.T) {
-	directory := NewBaseDirectory(&url)
-	assert.NotNil(t, directory)
-	assert.Equal(t, url, directory.GetUrl())
-	assert.Equal(t, &url, directory.GetDirectoryUrl())
+	dir := NewBaseDirectory(url)
+	assert.Equal(t, url, dir.GetUrl())
+	assert.Equal(t, url, dir.GetDirectoryUrl())
 }
 
 func TestBuildRouterChain(t *testing.T) {
 
 	regURL := url
 	regURL.AddParam(constant.INTERFACE_KEY, "mock-app")
-	directory := NewBaseDirectory(&regURL)
+	directory := NewBaseDirectory(regURL)
 
-	assert.NotNil(t, directory)
-
-	localIP, _ := gxnet.GetLocalIP()
+	localIP := common.GetLocalIp()
 	rule := base64.URLEncoding.EncodeToString([]byte("true => " + " host = " + localIP))
 	routeURL := getRouteURL(rule, anyURL)
 	routeURL.AddParam(constant.INTERFACE_KEY, "mock-app")
@@ -67,19 +63,19 @@
 	assert.NotNil(t, chain)
 }
 
-func getRouteURL(rule string, u common.URL) *common.URL {
+func getRouteURL(rule string, u *common.URL) *common.URL {
 	ru := u
 	ru.AddParam("rule", rule)
 	ru.AddParam("force", "true")
 	ru.AddParam(constant.ROUTER_KEY, "router")
-	return &ru
+	return ru
 }
 
 func TestIsProperRouter(t *testing.T) {
 	regURL := url
 	regURL.AddParam(constant.APPLICATION_KEY, "mock-app")
-	d := NewBaseDirectory(&regURL)
-	localIP, _ := gxnet.GetLocalIP()
+	d := NewBaseDirectory(regURL)
+	localIP := common.GetLocalIp()
 	rule := base64.URLEncoding.EncodeToString([]byte("true => " + " host = " + localIP))
 	routeURL := getRouteURL(rule, anyURL)
 	routeURL.AddParam(constant.APPLICATION_KEY, "mock-app")
@@ -88,7 +84,7 @@
 
 	regURL.AddParam(constant.APPLICATION_KEY, "")
 	regURL.AddParam(constant.INTERFACE_KEY, "com.foo.BarService")
-	d = NewBaseDirectory(&regURL)
+	d = NewBaseDirectory(regURL)
 	routeURL = getRouteURL(rule, anyURL)
 	routeURL.AddParam(constant.INTERFACE_KEY, "com.foo.BarService")
 	rst = d.isProperRouter(routeURL)
@@ -96,14 +92,14 @@
 
 	regURL.AddParam(constant.APPLICATION_KEY, "")
 	regURL.AddParam(constant.INTERFACE_KEY, "")
-	d = NewBaseDirectory(&regURL)
+	d = NewBaseDirectory(regURL)
 	routeURL = getRouteURL(rule, anyURL)
 	rst = d.isProperRouter(routeURL)
 	assert.True(t, rst)
 
 	regURL.SetParam(constant.APPLICATION_KEY, "")
 	regURL.SetParam(constant.INTERFACE_KEY, "")
-	d = NewBaseDirectory(&regURL)
+	d = NewBaseDirectory(regURL)
 	routeURL = getRouteURL(rule, anyURL)
 	routeURL.AddParam(constant.APPLICATION_KEY, "mock-service")
 	rst = d.isProperRouter(routeURL)
@@ -111,7 +107,7 @@
 
 	regURL.SetParam(constant.APPLICATION_KEY, "")
 	regURL.SetParam(constant.INTERFACE_KEY, "")
-	d = NewBaseDirectory(&regURL)
+	d = NewBaseDirectory(regURL)
 	routeURL = getRouteURL(rule, anyURL)
 	routeURL.AddParam(constant.INTERFACE_KEY, "mock-service")
 	rst = d.isProperRouter(routeURL)
diff --git a/cluster/directory/static_directory.go b/cluster/directory/static_directory.go
index 87f5135..d9695d4 100644
--- a/cluster/directory/static_directory.go
+++ b/cluster/directory/static_directory.go
@@ -34,15 +34,18 @@
 
 // NewStaticDirectory Create a new staticDirectory with invokers
 func NewStaticDirectory(invokers []protocol.Invoker) *staticDirectory {
-	var url common.URL
+	var url *common.URL
 
 	if len(invokers) > 0 {
 		url = invokers[0].GetUrl()
 	}
-	return &staticDirectory{
-		BaseDirectory: NewBaseDirectory(&url),
+	dir := &staticDirectory{
+		BaseDirectory: NewBaseDirectory(url),
 		invokers:      invokers,
 	}
+
+	dir.routerChain.SetInvokers(invokers)
+	return dir
 }
 
 //for-loop invokers ,if all invokers is available ,then it means directory is available
@@ -69,7 +72,7 @@
 		return invokers
 	}
 	dirUrl := dir.GetUrl()
-	return routerChain.Route(invokers, &dirUrl, invocation)
+	return routerChain.Route(dirUrl, invocation)
 }
 
 // Destroy Destroy
@@ -88,10 +91,11 @@
 		return perrors.Errorf("invokers == null")
 	}
 	url := invokers[0].GetUrl()
-	routerChain, e := chain.NewRouterChain(&url)
+	routerChain, e := chain.NewRouterChain(url)
 	if e != nil {
 		return e
 	}
+	routerChain.SetInvokers(dir.invokers)
 	dir.SetRouterChain(routerChain)
 	return nil
 }
diff --git a/cluster/loadbalance/consistent_hash.go b/cluster/loadbalance/consistent_hash.go
index 27ce236..3d036b4 100644
--- a/cluster/loadbalance/consistent_hash.go
+++ b/cluster/loadbalance/consistent_hash.go
@@ -105,7 +105,7 @@
 	selector.virtualInvokers = make(map[uint32]protocol.Invoker)
 	selector.hashCode = hashCode
 	url := invokers[0].GetUrl()
-	selector.replicaNum = int(url.GetMethodParamInt(methodName, HashNodes, 160))
+	selector.replicaNum = url.GetMethodParamIntValue(methodName, HashNodes, 160)
 	indices := re.Split(url.GetMethodParam(methodName, HashArguments, "0"), -1)
 	for _, index := range indices {
 		i, err := strconv.Atoi(index)
diff --git a/cluster/loadbalance/consistent_hash_test.go b/cluster/loadbalance/consistent_hash_test.go
index 9f22d39..0fbb740 100644
--- a/cluster/loadbalance/consistent_hash_test.go
+++ b/cluster/loadbalance/consistent_hash_test.go
@@ -84,9 +84,9 @@
 
 type consistentHashLoadBalanceSuite struct {
 	suite.Suite
-	url1     common.URL
-	url2     common.URL
-	url3     common.URL
+	url1     *common.URL
+	url2     *common.URL
+	url3     *common.URL
 	invokers []protocol.Invoker
 	invoker1 protocol.Invoker
 	invoker2 protocol.Invoker
diff --git a/cluster/router/chan.go b/cluster/router/chain.go
similarity index 83%
rename from cluster/router/chan.go
rename to cluster/router/chain.go
index e3e84b8..3614d0a 100644
--- a/cluster/router/chan.go
+++ b/cluster/router/chain.go
@@ -18,15 +18,15 @@
 package router
 
 import (
+	"github.com/apache/dubbo-go/common"
 	"github.com/apache/dubbo-go/protocol"
 )
 
 // Chain
 type Chain interface {
-	router
+	Route(*common.URL, protocol.Invocation) []protocol.Invoker
+	// Refresh invokers
+	SetInvokers([]protocol.Invoker)
 	// AddRouters Add routers
 	AddRouters([]PriorityRouter)
-
-	// SetInvokers notify router chain of the initial addresses from registry at the first time. Notify whenever addresses in registry change.
-	SetInvokers(invokers []protocol.Invoker)
 }
diff --git a/cluster/router/chain/chain.go b/cluster/router/chain/chain.go
index 8746c1d..f55cd07 100644
--- a/cluster/router/chain/chain.go
+++ b/cluster/router/chain/chain.go
@@ -18,9 +18,10 @@
 package chain
 
 import (
-	"math"
 	"sort"
 	"sync"
+	"sync/atomic"
+	"time"
 )
 
 import (
@@ -30,11 +31,18 @@
 import (
 	"github.com/apache/dubbo-go/cluster/router"
 	"github.com/apache/dubbo-go/common"
+	"github.com/apache/dubbo-go/common/constant"
 	"github.com/apache/dubbo-go/common/extension"
 	"github.com/apache/dubbo-go/common/logger"
 	"github.com/apache/dubbo-go/protocol"
 )
 
+const (
+	timeInterval   = 5 * time.Second
+	timeThreshold  = 2 * time.Second
+	countThreshold = 5
+)
+
 // RouterChain Router chain
 type RouterChain struct {
 	// Full list of addresses from registry, classified by method name.
@@ -47,33 +55,43 @@
 
 	mutex sync.RWMutex
 
-	url common.URL
+	url *common.URL
+
+	// The times of address notification since last update for address cache
+	count int64
+	// The timestamp of last update for address cache
+	last time.Time
+	// Channel for notify to update the address cache
+	notify chan struct{}
+	// Address cache
+	cache atomic.Value
+	// init
+	init sync.Once
 }
 
 // Route Loop routers in RouterChain and call Route method to determine the target invokers list.
-func (c *RouterChain) Route(invokers []protocol.Invoker, url *common.URL, invocation protocol.Invocation) []protocol.Invoker {
-	finalInvokers := invokers
-	l := len(c.routers)
-	rs := make([]router.PriorityRouter, l, int(math.Ceil(float64(l)*1.2)))
-	c.mutex.RLock()
-	copy(rs, c.routers)
-	c.mutex.RUnlock()
-
-	for _, r := range rs {
-		finalInvokers = r.Route(finalInvokers, url, invocation)
+func (c *RouterChain) Route(url *common.URL, invocation protocol.Invocation) []protocol.Invoker {
+	cache := c.loadCache()
+	if cache == nil {
+		c.mutex.RLock()
+		defer c.mutex.RUnlock()
+		return c.invokers
 	}
+
+	bitmap := cache.bitmap
+	for _, r := range c.copyRouters() {
+		bitmap = r.Route(bitmap, cache, url, invocation)
+	}
+
+	indexes := bitmap.ToArray()
+	finalInvokers := make([]protocol.Invoker, len(indexes))
+	for i, index := range indexes {
+		finalInvokers[i] = cache.invokers[index]
+	}
+
 	return finalInvokers
 }
 
-// SetInvokers notify router chain of the initial addresses from registry at the first time. Notify whenever addresses in registry change.
-func (c *RouterChain) SetInvokers(invokers []protocol.Invoker) {
-	for _, r := range c.routers {
-		if notifyRouter, ok := r.(router.NotifyRouter); ok {
-			notifyRouter.Notify(invokers)
-		}
-	}
-}
-
 // AddRouters Add routers to router chain
 // New a array add builtinRouters which is not sorted in RouterChain and routers
 // Sort the array
@@ -88,8 +106,125 @@
 	c.routers = newRouters
 }
 
+// SetInvokers receives updated invokers from registry center. If the times of notification exceeds countThreshold and
+// time interval exceeds timeThreshold since last cache update, then notify to update the cache.
+func (c *RouterChain) SetInvokers(invokers []protocol.Invoker) {
+	c.mutex.Lock()
+	c.invokers = invokers
+	c.mutex.Unlock()
+
+	// it should trigger init router for first call
+	c.init.Do(func() {
+		go func() {
+			c.notify <- struct{}{}
+		}()
+	})
+
+	c.count++
+	now := time.Now()
+	if c.count >= countThreshold && now.Sub(c.last) >= timeThreshold {
+		c.last = now
+		c.count = 0
+		go func() {
+			c.notify <- struct{}{}
+		}()
+	}
+}
+
+// loop listens on events to update the address cache when it's necessary, either when it receives notification
+// from address update, or when timeInterval exceeds.
+func (c *RouterChain) loop() {
+	ticker := time.NewTicker(timeInterval)
+	for {
+		select {
+		case <-ticker.C:
+			c.buildCache()
+		case <-c.notify:
+			c.buildCache()
+		}
+	}
+}
+
+// copyRouters make a snapshot copy from RouterChain's router list.
+func (c *RouterChain) copyRouters() []router.PriorityRouter {
+	c.mutex.RLock()
+	defer c.mutex.RUnlock()
+	ret := make([]router.PriorityRouter, 0, len(c.routers))
+	ret = append(ret, c.routers...)
+	return ret
+}
+
+// copyInvokers copies a snapshot of the received invokers.
+func (c *RouterChain) copyInvokers() []protocol.Invoker {
+	c.mutex.RLock()
+	defer c.mutex.RUnlock()
+	if c.invokers == nil || len(c.invokers) == 0 {
+		return nil
+	}
+	ret := make([]protocol.Invoker, 0, len(c.invokers))
+	ret = append(ret, c.invokers...)
+	return ret
+}
+
+// loadCache loads cache from sync.Value to guarantee the visibility
+func (c *RouterChain) loadCache() *InvokerCache {
+	v := c.cache.Load()
+	if v == nil {
+		return nil
+	}
+
+	return v.(*InvokerCache)
+}
+
+// copyInvokerIfNecessary compares chain's invokers copy and cache's invokers copy, to avoid copy as much as possible
+func (c *RouterChain) copyInvokerIfNecessary(cache *InvokerCache) []protocol.Invoker {
+	var invokers []protocol.Invoker
+	if cache != nil {
+		invokers = cache.invokers
+	}
+
+	c.mutex.RLock()
+	defer c.mutex.RUnlock()
+	if isInvokersChanged(invokers, c.invokers) {
+		invokers = c.copyInvokers()
+	}
+	return invokers
+}
+
+// buildCache builds address cache with the new invokers for all poolable routers.
+func (c *RouterChain) buildCache() {
+	origin := c.loadCache()
+	invokers := c.copyInvokerIfNecessary(origin)
+	if invokers == nil || len(invokers) == 0 {
+		return
+	}
+
+	var (
+		mutex sync.Mutex
+		wg    sync.WaitGroup
+	)
+
+	cache := BuildCache(invokers)
+	for _, r := range c.copyRouters() {
+		if p, ok := r.(router.Poolable); ok {
+			wg.Add(1)
+			go func(p router.Poolable) {
+				defer wg.Done()
+				pool, info := poolRouter(p, origin, invokers)
+				mutex.Lock()
+				defer mutex.Unlock()
+				cache.pools[p.Name()] = pool
+				cache.metadatas[p.Name()] = info
+			}(p)
+		}
+	}
+	wg.Wait()
+
+	c.cache.Store(cache)
+}
+
 // URL Return URL in RouterChain
-func (c *RouterChain) URL() common.URL {
+func (c *RouterChain) URL() *common.URL {
 	return c.url
 }
 
@@ -118,14 +253,62 @@
 	chain := &RouterChain{
 		builtinRouters: routers,
 		routers:        newRouters,
+		last:           time.Now(),
+		notify:         make(chan struct{}),
 	}
 	if url != nil {
-		chain.url = *url
+		chain.url = url
 	}
 
+	go chain.loop()
 	return chain, nil
 }
 
+// poolRouter calls poolable router's Pool() to create new address pool and address metadata if necessary.
+// If the corresponding cache entry exists, and the poolable router answers no need to re-pool (possibly because its
+// rule doesn't change), and the address list doesn't change, then the existing data will be re-used.
+func poolRouter(p router.Poolable, origin *InvokerCache, invokers []protocol.Invoker) (router.AddrPool, router.AddrMetadata) {
+	name := p.Name()
+	if isCacheMiss(origin, name) || p.ShouldPool() || &(origin.invokers) != &invokers {
+		logger.Debugf("build address cache for router %q", name)
+		return p.Pool(invokers)
+	}
+
+	logger.Debugf("reuse existing address cache for router %q", name)
+	return origin.pools[name], origin.metadatas[name]
+}
+
+// isCacheMiss checks if the corresponding cache entry for a poolable router has already existed.
+// False returns when the cache is nil, or cache's pool is nil, or cache's invokers snapshot is nil, or the entry
+// doesn't exist.
+func isCacheMiss(cache *InvokerCache, key string) bool {
+	if cache == nil || cache.pools == nil || cache.invokers == nil || cache.pools[key] == nil {
+		return true
+	}
+	return false
+}
+
+// isInvokersChanged compares new invokers on the right changes, compared with the old invokers on the left.
+func isInvokersChanged(left []protocol.Invoker, right []protocol.Invoker) bool {
+	if len(right) != len(left) {
+		return true
+	}
+
+	for _, r := range right {
+		found := false
+		for _, l := range left {
+			if common.IsEquals(l.GetUrl(), r.GetUrl(), constant.TIMESTAMP_KEY, constant.REMOTE_TIMESTAMP_KEY) {
+				found = true
+				break
+			}
+		}
+		if !found {
+			return true
+		}
+	}
+	return false
+}
+
 // sortRouter Sort router instance by priority with stable algorithm
 func sortRouter(routers []router.PriorityRouter) {
 	sort.Stable(byPriority(routers))
diff --git a/cluster/router/chain/chain_test.go b/cluster/router/chain/chain_test.go
index dec0389..b21990b 100644
--- a/cluster/router/chain/chain_test.go
+++ b/cluster/router/chain/chain_test.go
@@ -65,7 +65,6 @@
 	assert.NoError(t, err)
 	err = z.Create(path)
 	assert.NoError(t, err)
-
 	testyml := `scope: application
 key: mock-app
 enabled: true
@@ -81,7 +80,7 @@
 	defer z.Close()
 
 	zkUrl, _ := common.NewURL(fmt.Sprintf(zkFormat, localIP, ts.Servers[0].Port))
-	configuration, err := extension.GetConfigCenterFactory(zk).GetDynamicConfiguration(&zkUrl)
+	configuration, err := extension.GetConfigCenterFactory(zk).GetDynamicConfiguration(zkUrl)
 	config.GetEnvInstance().SetDynamicConfiguration(configuration)
 
 	assert.Nil(t, err)
@@ -133,7 +132,7 @@
 	defer z.Close()
 
 	zkUrl, _ := common.NewURL(fmt.Sprintf(zkFormat, localIP, ts.Servers[0].Port))
-	configuration, err := extension.GetConfigCenterFactory(zk).GetDynamicConfiguration(&zkUrl)
+	configuration, err := extension.GetConfigCenterFactory(zk).GetDynamicConfiguration(zkUrl)
 	config.GetEnvInstance().SetDynamicConfiguration(configuration)
 
 	chain, err := NewRouterChain(getConditionRouteUrl(applicationKey))
@@ -159,7 +158,7 @@
 	defer z.Close()
 
 	zkUrl, _ := common.NewURL(fmt.Sprintf(zkFormat, localIP, ts.Servers[0].Port))
-	configuration, err := extension.GetConfigCenterFactory(zk).GetDynamicConfiguration(&zkUrl)
+	configuration, err := extension.GetConfigCenterFactory(zk).GetDynamicConfiguration(zkUrl)
 	config.GetEnvInstance().SetDynamicConfiguration(configuration)
 
 	chain, err := NewRouterChain(getConditionRouteUrl(applicationKey))
@@ -169,15 +168,15 @@
 	url := getConditionRouteUrl(applicationKey)
 	assert.NotNil(t, url)
 
-	invokers := []protocol.Invoker{}
+	var invokers []protocol.Invoker
 	dubboURL, _ := common.NewURL(fmt.Sprintf(dubboForamt, test1234IP, port20000))
 	invokers = append(invokers, protocol.NewBaseInvoker(dubboURL))
-
 	chain.SetInvokers(invokers)
+	chain.buildCache()
 
 	targetURL, _ := common.NewURL(fmt.Sprintf(consumerFormat, test1111IP))
 	inv := &invocation.RPCInvocation{}
-	finalInvokers := chain.Route(invokers, &targetURL, inv)
+	finalInvokers := chain.Route(targetURL, inv)
 
 	assert.Equal(t, 1, len(finalInvokers))
 }
@@ -203,20 +202,22 @@
 	defer z.Close()
 
 	zkUrl, _ := common.NewURL(fmt.Sprintf(zkFormat, localIP, ts.Servers[0].Port))
-	configuration, err := extension.GetConfigCenterFactory(zk).GetDynamicConfiguration(&zkUrl)
+	configuration, err := extension.GetConfigCenterFactory(zk).GetDynamicConfiguration(zkUrl)
 	config.GetEnvInstance().SetDynamicConfiguration(configuration)
 
 	chain, err := NewRouterChain(getConditionRouteUrl(applicationKey))
 	assert.Nil(t, err)
 	assert.Equal(t, 2, len(chain.routers))
 
-	invokers := []protocol.Invoker{}
+	var invokers []protocol.Invoker
 	dubboURL, _ := common.NewURL(fmt.Sprintf(dubboForamt, test1234IP, port20000))
 	invokers = append(invokers, protocol.NewBaseInvoker(dubboURL))
+	chain.SetInvokers(invokers)
+	chain.buildCache()
 
 	targetURL, _ := common.NewURL(fmt.Sprintf(consumerFormat, test1111IP))
 	inv := &invocation.RPCInvocation{}
-	finalInvokers := chain.Route(invokers, &targetURL, inv)
+	finalInvokers := chain.Route(targetURL, inv)
 
 	assert.Equal(t, 0, len(finalInvokers))
 }
@@ -227,7 +228,7 @@
 	defer z.Close()
 
 	zkUrl, _ := common.NewURL(fmt.Sprintf(zkFormat, localIP, ts.Servers[0].Port))
-	configuration, err := extension.GetConfigCenterFactory(zk).GetDynamicConfiguration(&zkUrl)
+	configuration, err := extension.GetConfigCenterFactory(zk).GetDynamicConfiguration(zkUrl)
 	config.GetEnvInstance().SetDynamicConfiguration(configuration)
 
 	chain, err := NewRouterChain(getConditionNoRouteUrl(applicationKey))
@@ -236,13 +237,16 @@
 
 	url := getConditionRouteUrl(applicationKey)
 	assert.NotNil(t, url)
-	invokers := []protocol.Invoker{}
+
+	var invokers []protocol.Invoker
 	dubboURL, _ := common.NewURL(fmt.Sprintf(dubboForamt, test1234IP, port20000))
 	invokers = append(invokers, protocol.NewBaseInvoker(dubboURL))
+	chain.SetInvokers(invokers)
+	chain.buildCache()
 
 	targetURL, _ := common.NewURL(fmt.Sprintf(consumerFormat, test1111IP))
 	inv := &invocation.RPCInvocation{}
-	finalInvokers := chain.Route(invokers, &targetURL, inv)
+	finalInvokers := chain.Route(targetURL, inv)
 
 	assert.Equal(t, 0, len(finalInvokers))
 }
@@ -253,7 +257,7 @@
 	url.AddParam(forceField, forceValue)
 	rule := base64.URLEncoding.EncodeToString([]byte("host = 1.1.1.1 => host != 1.2.3.4"))
 	url.AddParam(constant.RULE_KEY, rule)
-	return &url
+	return url
 }
 
 func getConditionRouteUrl(applicationKey string) *common.URL {
@@ -262,12 +266,12 @@
 	url.AddParam(forceField, forceValue)
 	rule := base64.URLEncoding.EncodeToString([]byte("host = 1.1.1.1 => host = 1.2.3.4"))
 	url.AddParam(constant.RULE_KEY, rule)
-	return &url
+	return url
 }
 
 func getRouteUrl(applicationKey string) *common.URL {
 	url, _ := common.NewURL(fmt.Sprintf(anyUrlFormat, test0000IP))
 	url.AddParam(applicationField, applicationKey)
 	url.AddParam(forceField, forceValue)
-	return &url
+	return url
 }
diff --git a/cluster/router/chain/invoker_cache.go b/cluster/router/chain/invoker_cache.go
new file mode 100644
index 0000000..43cdfa5
--- /dev/null
+++ b/cluster/router/chain/invoker_cache.go
@@ -0,0 +1,80 @@
+/*
+ * 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 (
+	"github.com/RoaringBitmap/roaring"
+)
+
+import (
+	"github.com/apache/dubbo-go/cluster/router"
+	"github.com/apache/dubbo-go/cluster/router/utils"
+	"github.com/apache/dubbo-go/protocol"
+)
+
+// Cache caches all addresses relevant info for a snapshot of received invokers. It keeps a snapshot of the received
+// address list, and also keeps address pools and address metadata from routers based on the same address snapshot, if
+// the router implements Poolable.
+type InvokerCache struct {
+	// The snapshot of invokers
+	invokers []protocol.Invoker
+
+	// The bitmap representation for invokers snapshot
+	bitmap *roaring.Bitmap
+
+	// Address pool from routers which implement Poolable
+	pools map[string]router.AddrPool
+
+	// Address metadata from routers which implement Poolable
+	metadatas map[string]router.AddrMetadata
+}
+
+// BuildCache builds address cache from the given invokers.
+func BuildCache(invokers []protocol.Invoker) *InvokerCache {
+	return &InvokerCache{
+		invokers:  invokers,
+		bitmap:    utils.ToBitmap(invokers),
+		pools:     make(map[string]router.AddrPool, 8),
+		metadatas: make(map[string]router.AddrMetadata, 8),
+	}
+}
+
+// GetInvokers get invokers snapshot.
+func (c *InvokerCache) GetInvokers() []protocol.Invoker {
+	return c.invokers
+}
+
+// FindAddrPool finds address pool for a poolable router.
+func (c *InvokerCache) FindAddrPool(p router.Poolable) router.AddrPool {
+	return c.pools[p.Name()]
+}
+
+// FindAddrMeta finds address metadata for a poolable router.
+func (c *InvokerCache) FindAddrMeta(p router.Poolable) router.AddrMetadata {
+	return c.metadatas[p.Name()]
+}
+
+// SetAddrPool sets address pool for a poolable router, for unit test only
+func (c *InvokerCache) SetAddrPool(name string, pool router.AddrPool) {
+	c.pools[name] = pool
+}
+
+// SetAddrMeta sets address metadata for a poolable router, for unit test only
+func (c *InvokerCache) SetAddrMeta(name string, meta router.AddrMetadata) {
+	c.metadatas[name] = meta
+}
diff --git a/cluster/router/condition/app_router_test.go b/cluster/router/condition/app_router_test.go
index cce96b1..879abc5 100644
--- a/cluster/router/condition/app_router_test.go
+++ b/cluster/router/condition/app_router_test.go
@@ -71,7 +71,7 @@
 	defer z.Close()
 
 	zkUrl, _ := common.NewURL(fmt.Sprintf(zkFormat, routerLocalIP, ts.Servers[0].Port))
-	configuration, err := extension.GetConfigCenterFactory(routerZk).GetDynamicConfiguration(&zkUrl)
+	configuration, err := extension.GetConfigCenterFactory(routerZk).GetDynamicConfiguration(zkUrl)
 	config.GetEnvInstance().SetDynamicConfiguration(configuration)
 
 	assert.Nil(t, err)
@@ -119,7 +119,7 @@
 	defer z.Close()
 
 	zkUrl, _ := common.NewURL(fmt.Sprintf(zkFormat, routerLocalIP, ts.Servers[0].Port))
-	configuration, err := extension.GetConfigCenterFactory(routerZk).GetDynamicConfiguration(&zkUrl)
+	configuration, err := extension.GetConfigCenterFactory(routerZk).GetDynamicConfiguration(zkUrl)
 	config.GetEnvInstance().SetDynamicConfiguration(configuration)
 
 	assert.Nil(t, err)
@@ -158,7 +158,7 @@
 	defer z.Close()
 
 	zkUrl, _ := common.NewURL(fmt.Sprintf(zkFormat, routerLocalIP, ts.Servers[0].Port))
-	configuration, err := extension.GetConfigCenterFactory(routerZk).GetDynamicConfiguration(&zkUrl)
+	configuration, err := extension.GetConfigCenterFactory(routerZk).GetDynamicConfiguration(zkUrl)
 	config.GetEnvInstance().SetDynamicConfiguration(configuration)
 
 	assert.Nil(t, err)
@@ -194,5 +194,5 @@
 	url, _ := common.NewURL(fmt.Sprintf(conditionFormat, constant.ANYHOST_VALUE))
 	url.AddParam("application", applicationKey)
 	url.AddParam("force", "true")
-	return &url
+	return url
 }
diff --git a/cluster/router/condition/factory_test.go b/cluster/router/condition/factory_test.go
index 0f61b39..c916588 100644
--- a/cluster/router/condition/factory_test.go
+++ b/cluster/router/condition/factory_test.go
@@ -26,12 +26,14 @@
 )
 
 import (
-	"github.com/dubbogo/gost/net"
 	perrors "github.com/pkg/errors"
 	"github.com/stretchr/testify/assert"
 )
 
 import (
+	"github.com/apache/dubbo-go/cluster/router"
+	"github.com/apache/dubbo-go/cluster/router/chain"
+	"github.com/apache/dubbo-go/cluster/router/utils"
 	"github.com/apache/dubbo-go/common"
 	"github.com/apache/dubbo-go/common/constant"
 	"github.com/apache/dubbo-go/common/logger"
@@ -50,13 +52,13 @@
 )
 
 type MockInvoker struct {
-	url          common.URL
+	url          *common.URL
 	available    bool
 	destroyed    bool
 	successCount int
 }
 
-func NewMockInvoker(url common.URL, successCount int) *MockInvoker {
+func NewMockInvoker(url *common.URL, successCount int) *MockInvoker {
 	return &MockInvoker{
 		url:          url,
 		available:    true,
@@ -65,7 +67,7 @@
 	}
 }
 
-func (bi *MockInvoker) GetUrl() common.URL {
+func (bi *MockInvoker) GetUrl() *common.URL {
 	return bi.url
 }
 
@@ -73,20 +75,20 @@
 	url, _ := common.NewURL(fmt.Sprintf(factoryUrlFormat, constant.ANYHOST_VALUE))
 	url.AddParam("rule", rule)
 	url.AddParam("force", "true")
-	return &url
+	return url
 }
 
 func getRouteUrlWithForce(rule, force string) *common.URL {
 	url, _ := common.NewURL(fmt.Sprintf(factoryUrlFormat, constant.ANYHOST_VALUE))
 	url.AddParam("rule", rule)
 	url.AddParam("force", force)
-	return &url
+	return url
 }
 
 func getRouteUrlWithNoForce(rule string) *common.URL {
 	url, _ := common.NewURL(fmt.Sprintf(factoryUrlFormat, constant.ANYHOST_VALUE))
 	url.AddParam("rule", rule)
-	return &url
+	return url
 }
 
 func (bi *MockInvoker) IsAvailable() bool {
@@ -132,36 +134,36 @@
 	rule := base64.URLEncoding.EncodeToString([]byte("=> host = 1.2.3.4"))
 	router, _ := newConditionRouterFactory().NewPriorityRouter(getRouteUrl(rule))
 	cUrl, _ := common.NewURL(fmt.Sprintf(factoryDubboFormat, factory1111Ip))
-	matchWhen := router.(*ConditionRouter).MatchWhen(&cUrl, inv)
+	matchWhen := router.(*ConditionRouter).MatchWhen(cUrl, inv)
 	assert.Equal(t, true, matchWhen)
 	rule1 := base64.URLEncoding.EncodeToString([]byte("host = 2.2.2.2,1.1.1.1,3.3.3.3 => host = 1.2.3.4"))
 	router1, _ := newConditionRouterFactory().NewPriorityRouter(getRouteUrl(rule1))
-	matchWhen1 := router1.(*ConditionRouter).MatchWhen(&cUrl, inv)
+	matchWhen1 := router1.(*ConditionRouter).MatchWhen(cUrl, inv)
 	assert.Equal(t, true, matchWhen1)
 	rule2 := base64.URLEncoding.EncodeToString([]byte("host = 2.2.2.2,1.1.1.1,3.3.3.3 & host !=1.1.1.1 => host = 1.2.3.4"))
 	router2, _ := newConditionRouterFactory().NewPriorityRouter(getRouteUrl(rule2))
-	matchWhen2 := router2.(*ConditionRouter).MatchWhen(&cUrl, inv)
+	matchWhen2 := router2.(*ConditionRouter).MatchWhen(cUrl, inv)
 	assert.Equal(t, false, matchWhen2)
 	rule3 := base64.URLEncoding.EncodeToString([]byte("host !=4.4.4.4 & host = 2.2.2.2,1.1.1.1,3.3.3.3 => host = 1.2.3.4"))
 	router3, _ := newConditionRouterFactory().NewPriorityRouter(getRouteUrl(rule3))
-	matchWhen3 := router3.(*ConditionRouter).MatchWhen(&cUrl, inv)
+	matchWhen3 := router3.(*ConditionRouter).MatchWhen(cUrl, inv)
 	assert.Equal(t, true, matchWhen3)
 	rule4 := base64.URLEncoding.EncodeToString([]byte("host !=4.4.4.* & host = 2.2.2.2,1.1.1.1,3.3.3.3 => host = 1.2.3.4"))
 	router4, _ := newConditionRouterFactory().NewPriorityRouter(getRouteUrl(rule4))
-	matchWhen4 := router4.(*ConditionRouter).MatchWhen(&cUrl, inv)
+	matchWhen4 := router4.(*ConditionRouter).MatchWhen(cUrl, inv)
 	assert.Equal(t, true, matchWhen4)
 	rule5 := base64.URLEncoding.EncodeToString([]byte("host = 2.2.2.2,1.1.1.*,3.3.3.3 & host != 1.1.1.1 => host = 1.2.3.4"))
 	router5, _ := newConditionRouterFactory().NewPriorityRouter(getRouteUrl(rule5))
-	matchWhen5 := router5.(*ConditionRouter).MatchWhen(&cUrl, inv)
+	matchWhen5 := router5.(*ConditionRouter).MatchWhen(cUrl, inv)
 	assert.Equal(t, false, matchWhen5)
 	rule6 := base64.URLEncoding.EncodeToString([]byte("host = 2.2.2.2,1.1.1.*,3.3.3.3 & host != 1.1.1.2 => host = 1.2.3.4"))
 	router6, _ := newConditionRouterFactory().NewPriorityRouter(getRouteUrl(rule6))
-	matchWhen6 := router6.(*ConditionRouter).MatchWhen(&cUrl, inv)
+	matchWhen6 := router6.(*ConditionRouter).MatchWhen(cUrl, inv)
 	assert.Equal(t, true, matchWhen6)
 }
 
 func TestRoute_matchFilter(t *testing.T) {
-	localIP, _ := gxnet.GetLocalIP()
+	localIP := common.GetLocalIp()
 	t.Logf("The local ip is %s", localIP)
 	url1, _ := common.NewURL("dubbo://10.20.3.3:20880/com.foo.BarService?default.serialization=fastjson")
 	url2, _ := common.NewURL(fmt.Sprintf(factoryDubboFormat, localIP))
@@ -180,70 +182,70 @@
 	router5, _ := newConditionRouterFactory().NewPriorityRouter(getRouteUrl(rule5))
 	router6, _ := newConditionRouterFactory().NewPriorityRouter(getRouteUrl(rule6))
 	cUrl, _ := common.NewURL(fmt.Sprintf(factoryConsumerFormat, localIP))
-	fileredInvokers1 := router1.Route(invokers, &cUrl, &invocation.RPCInvocation{})
-	fileredInvokers2 := router2.Route(invokers, &cUrl, &invocation.RPCInvocation{})
-	fileredInvokers3 := router3.Route(invokers, &cUrl, &invocation.RPCInvocation{})
-	fileredInvokers4 := router4.Route(invokers, &cUrl, &invocation.RPCInvocation{})
-	fileredInvokers5 := router5.Route(invokers, &cUrl, &invocation.RPCInvocation{})
-	fileredInvokers6 := router6.Route(invokers, &cUrl, &invocation.RPCInvocation{})
-	assert.Equal(t, 1, len(fileredInvokers1))
-	assert.Equal(t, 0, len(fileredInvokers2))
-	assert.Equal(t, 0, len(fileredInvokers3))
-	assert.Equal(t, 1, len(fileredInvokers4))
-	assert.Equal(t, 2, len(fileredInvokers5))
-	assert.Equal(t, 1, len(fileredInvokers6))
+	ret1 := router1.Route(utils.ToBitmap(invokers), setUpAddrCache(invokers), cUrl, &invocation.RPCInvocation{})
+	ret2 := router2.Route(utils.ToBitmap(invokers), setUpAddrCache(invokers), cUrl, &invocation.RPCInvocation{})
+	ret3 := router3.Route(utils.ToBitmap(invokers), setUpAddrCache(invokers), cUrl, &invocation.RPCInvocation{})
+	ret4 := router4.Route(utils.ToBitmap(invokers), setUpAddrCache(invokers), cUrl, &invocation.RPCInvocation{})
+	ret5 := router5.Route(utils.ToBitmap(invokers), setUpAddrCache(invokers), cUrl, &invocation.RPCInvocation{})
+	ret6 := router6.Route(utils.ToBitmap(invokers), setUpAddrCache(invokers), cUrl, &invocation.RPCInvocation{})
+	assert.Equal(t, 1, len(ret1.ToArray()))
+	assert.Equal(t, 0, len(ret2.ToArray()))
+	assert.Equal(t, 0, len(ret3.ToArray()))
+	assert.Equal(t, 1, len(ret4.ToArray()))
+	assert.Equal(t, 2, len(ret5.ToArray()))
+	assert.Equal(t, 1, len(ret6.ToArray()))
 
 }
 
 func TestRoute_methodRoute(t *testing.T) {
 	inv := invocation.NewRPCInvocationWithOptions(invocation.WithMethodName("getFoo"), invocation.WithParameterTypes([]reflect.Type{}), invocation.WithArguments([]interface{}{}))
 	rule := base64.URLEncoding.EncodeToString([]byte("host !=4.4.4.* & host = 2.2.2.2,1.1.1.1,3.3.3.3 => host = 1.2.3.4"))
-	router, _ := newConditionRouterFactory().NewPriorityRouter(getRouteUrl(rule))
+	r, _ := newConditionRouterFactory().NewPriorityRouter(getRouteUrl(rule))
 	url, _ := common.NewURL("consumer://1.1.1.1/com.foo.BarService?methods=setFoo,getFoo,findFoo")
-	matchWhen := router.(*ConditionRouter).MatchWhen(&url, inv)
+	matchWhen := r.(*ConditionRouter).MatchWhen(url, inv)
 	assert.Equal(t, true, matchWhen)
 	url1, _ := common.NewURL(fmt.Sprintf(factoryConsumerMethodFormat, factory1111Ip))
-	matchWhen = router.(*ConditionRouter).MatchWhen(&url1, inv)
+	matchWhen = r.(*ConditionRouter).MatchWhen(url1, inv)
 	assert.Equal(t, true, matchWhen)
 	url2, _ := common.NewURL(fmt.Sprintf(factoryConsumerMethodFormat, factory1111Ip))
 	rule2 := base64.URLEncoding.EncodeToString([]byte("methods=getFoo & host!=1.1.1.1 => host = 1.2.3.4"))
 	router2, _ := newConditionRouterFactory().NewPriorityRouter(getRouteUrl(rule2))
-	matchWhen = router2.(*ConditionRouter).MatchWhen(&url2, inv)
+	matchWhen = router2.(*ConditionRouter).MatchWhen(url2, inv)
 	assert.Equal(t, false, matchWhen)
 	url3, _ := common.NewURL(fmt.Sprintf(factoryConsumerMethodFormat, factory1111Ip))
 	rule3 := base64.URLEncoding.EncodeToString([]byte("methods=getFoo & host=1.1.1.1 => host = 1.2.3.4"))
 	router3, _ := newConditionRouterFactory().NewPriorityRouter(getRouteUrl(rule3))
-	matchWhen = router3.(*ConditionRouter).MatchWhen(&url3, inv)
+	matchWhen = router3.(*ConditionRouter).MatchWhen(url3, inv)
 	assert.Equal(t, true, matchWhen)
 
 }
 
 func TestRoute_ReturnFalse(t *testing.T) {
 	url, _ := common.NewURL("")
-	localIP, _ := gxnet.GetLocalIP()
+	localIP := common.GetLocalIp()
 	invokers := []protocol.Invoker{NewMockInvoker(url, 1), NewMockInvoker(url, 2), NewMockInvoker(url, 3)}
 	inv := &invocation.RPCInvocation{}
 	rule := base64.URLEncoding.EncodeToString([]byte("host = " + localIP + " => false"))
 	curl, _ := common.NewURL(fmt.Sprintf(factoryConsumerFormat, localIP))
-	router, _ := newConditionRouterFactory().NewPriorityRouter(getRouteUrl(rule))
-	fileredInvokers := router.(*ConditionRouter).Route(invokers, &curl, inv)
-	assert.Equal(t, 0, len(fileredInvokers))
+	r, _ := newConditionRouterFactory().NewPriorityRouter(getRouteUrl(rule))
+	ret := r.Route(utils.ToBitmap(invokers), setUpAddrCache(invokers), curl, inv)
+	assert.Equal(t, 0, len(ret.ToArray()))
 }
 
 func TestRoute_ReturnEmpty(t *testing.T) {
-	localIP, _ := gxnet.GetLocalIP()
+	localIP := common.GetLocalIp()
 	url, _ := common.NewURL("")
 	invokers := []protocol.Invoker{NewMockInvoker(url, 1), NewMockInvoker(url, 2), NewMockInvoker(url, 3)}
 	inv := &invocation.RPCInvocation{}
 	rule := base64.URLEncoding.EncodeToString([]byte("host = " + localIP + " => "))
 	curl, _ := common.NewURL(fmt.Sprintf(factoryConsumerFormat, localIP))
-	router, _ := newConditionRouterFactory().NewPriorityRouter(getRouteUrl(rule))
-	fileredInvokers := router.(*ConditionRouter).Route(invokers, &curl, inv)
-	assert.Equal(t, 0, len(fileredInvokers))
+	r, _ := newConditionRouterFactory().NewPriorityRouter(getRouteUrl(rule))
+	ret := r.Route(utils.ToBitmap(invokers), setUpAddrCache(invokers), curl, inv)
+	assert.Equal(t, 0, len(ret.ToArray()))
 }
 
 func TestRoute_ReturnAll(t *testing.T) {
-	localIP, _ := gxnet.GetLocalIP()
+	localIP := common.GetLocalIp()
 	urlString := "dubbo://" + localIP + "/com.foo.BarService"
 	dubboURL, _ := common.NewURL(urlString)
 	mockInvoker1 := NewMockInvoker(dubboURL, 1)
@@ -253,13 +255,13 @@
 	inv := &invocation.RPCInvocation{}
 	rule := base64.URLEncoding.EncodeToString([]byte("host = " + localIP + " => " + " host = " + localIP))
 	curl, _ := common.NewURL(fmt.Sprintf(factoryConsumerFormat, localIP))
-	router, _ := newConditionRouterFactory().NewPriorityRouter(getRouteUrl(rule))
-	fileredInvokers := router.(*ConditionRouter).Route(invokers, &curl, inv)
-	assert.Equal(t, invokers, fileredInvokers)
+	r, _ := newConditionRouterFactory().NewPriorityRouter(getRouteUrl(rule))
+	ret := r.Route(utils.ToBitmap(invokers), setUpAddrCache(invokers), curl, inv)
+	assert.Equal(t, len(invokers), len(ret.ToArray()))
 }
 
 func TestRoute_HostFilter(t *testing.T) {
-	localIP, _ := gxnet.GetLocalIP()
+	localIP := common.GetLocalIp()
 	url1, _ := common.NewURL(factory333URL)
 	url2, _ := common.NewURL(fmt.Sprintf(factoryDubboFormat, localIP))
 	url3, _ := common.NewURL(fmt.Sprintf(factoryDubboFormat, localIP))
@@ -270,15 +272,15 @@
 	inv := &invocation.RPCInvocation{}
 	rule := base64.URLEncoding.EncodeToString([]byte("host = " + localIP + " => " + " host = " + localIP))
 	curl, _ := common.NewURL(fmt.Sprintf(factoryConsumerFormat, localIP))
-	router, _ := newConditionRouterFactory().NewPriorityRouter(getRouteUrl(rule))
-	fileredInvokers := router.(*ConditionRouter).Route(invokers, &curl, inv)
-	assert.Equal(t, 2, len(fileredInvokers))
-	assert.Equal(t, invoker2, fileredInvokers[0])
-	assert.Equal(t, invoker3, fileredInvokers[1])
+	r, _ := newConditionRouterFactory().NewPriorityRouter(getRouteUrl(rule))
+	ret := r.Route(utils.ToBitmap(invokers), setUpAddrCache(invokers), curl, inv)
+	assert.Equal(t, 2, len(ret.ToArray()))
+	assert.Equal(t, invoker2, invokers[ret.ToArray()[0]])
+	assert.Equal(t, invoker3, invokers[ret.ToArray()[1]])
 }
 
 func TestRoute_Empty_HostFilter(t *testing.T) {
-	localIP, _ := gxnet.GetLocalIP()
+	localIP := common.GetLocalIp()
 	url1, _ := common.NewURL(factory333URL)
 	url2, _ := common.NewURL(fmt.Sprintf(factoryDubboFormat, localIP))
 	url3, _ := common.NewURL(fmt.Sprintf(factoryDubboFormat, localIP))
@@ -289,15 +291,15 @@
 	inv := &invocation.RPCInvocation{}
 	rule := base64.URLEncoding.EncodeToString([]byte(" => " + " host = " + localIP))
 	curl, _ := common.NewURL(fmt.Sprintf(factoryConsumerFormat, localIP))
-	router, _ := newConditionRouterFactory().NewPriorityRouter(getRouteUrl(rule))
-	fileredInvokers := router.(*ConditionRouter).Route(invokers, &curl, inv)
-	assert.Equal(t, 2, len(fileredInvokers))
-	assert.Equal(t, invoker2, fileredInvokers[0])
-	assert.Equal(t, invoker3, fileredInvokers[1])
+	r, _ := newConditionRouterFactory().NewPriorityRouter(getRouteUrl(rule))
+	ret := r.Route(utils.ToBitmap(invokers), setUpAddrCache(invokers), curl, inv)
+	assert.Equal(t, 2, len(ret.ToArray()))
+	assert.Equal(t, invoker2, invokers[ret.ToArray()[0]])
+	assert.Equal(t, invoker3, invokers[ret.ToArray()[1]])
 }
 
 func TestRoute_False_HostFilter(t *testing.T) {
-	localIP, _ := gxnet.GetLocalIP()
+	localIP := common.GetLocalIp()
 	url1, _ := common.NewURL(factory333URL)
 	url2, _ := common.NewURL(fmt.Sprintf(factoryDubboFormat, localIP))
 	url3, _ := common.NewURL(fmt.Sprintf(factoryDubboFormat, localIP))
@@ -308,15 +310,15 @@
 	inv := &invocation.RPCInvocation{}
 	rule := base64.URLEncoding.EncodeToString([]byte("true => " + " host = " + localIP))
 	curl, _ := common.NewURL(fmt.Sprintf(factoryConsumerFormat, localIP))
-	router, _ := newConditionRouterFactory().NewPriorityRouter(getRouteUrl(rule))
-	fileredInvokers := router.(*ConditionRouter).Route(invokers, &curl, inv)
-	assert.Equal(t, 2, len(fileredInvokers))
-	assert.Equal(t, invoker2, fileredInvokers[0])
-	assert.Equal(t, invoker3, fileredInvokers[1])
+	r, _ := newConditionRouterFactory().NewPriorityRouter(getRouteUrl(rule))
+	ret := r.Route(utils.ToBitmap(invokers), setUpAddrCache(invokers), curl, inv)
+	assert.Equal(t, 2, len(ret.ToArray()))
+	assert.Equal(t, invoker2, invokers[ret.ToArray()[0]])
+	assert.Equal(t, invoker3, invokers[ret.ToArray()[1]])
 }
 
 func TestRoute_Placeholder(t *testing.T) {
-	localIP, _ := gxnet.GetLocalIP()
+	localIP := common.GetLocalIp()
 	url1, _ := common.NewURL(factory333URL)
 	url2, _ := common.NewURL(fmt.Sprintf(factoryDubboFormat, localIP))
 	url3, _ := common.NewURL(fmt.Sprintf(factoryDubboFormat, localIP))
@@ -327,15 +329,15 @@
 	inv := &invocation.RPCInvocation{}
 	rule := base64.URLEncoding.EncodeToString([]byte("host = " + localIP + " => " + " host = $host"))
 	curl, _ := common.NewURL(fmt.Sprintf(factoryConsumerFormat, localIP))
-	router, _ := newConditionRouterFactory().NewPriorityRouter(getRouteUrl(rule))
-	fileredInvokers := router.(*ConditionRouter).Route(invokers, &curl, inv)
-	assert.Equal(t, 2, len(fileredInvokers))
-	assert.Equal(t, invoker2, fileredInvokers[0])
-	assert.Equal(t, invoker3, fileredInvokers[1])
+	r, _ := newConditionRouterFactory().NewPriorityRouter(getRouteUrl(rule))
+	ret := r.Route(utils.ToBitmap(invokers), setUpAddrCache(invokers), curl, inv)
+	assert.Equal(t, 2, len(ret.ToArray()))
+	assert.Equal(t, invoker2, invokers[ret.ToArray()[0]])
+	assert.Equal(t, invoker3, invokers[ret.ToArray()[1]])
 }
 
 func TestRoute_NoForce(t *testing.T) {
-	localIP, _ := gxnet.GetLocalIP()
+	localIP := common.GetLocalIp()
 	url1, _ := common.NewURL(factory333URL)
 	url2, _ := common.NewURL(fmt.Sprintf(factoryDubboFormat, localIP))
 	url3, _ := common.NewURL(fmt.Sprintf(factoryDubboFormat, localIP))
@@ -346,13 +348,13 @@
 	inv := &invocation.RPCInvocation{}
 	rule := base64.URLEncoding.EncodeToString([]byte(fmt.Sprintf(factoryHostIp1234Format, localIP)))
 	curl, _ := common.NewURL(fmt.Sprintf(factoryConsumerFormat, localIP))
-	router, _ := newConditionRouterFactory().NewPriorityRouter(getRouteUrlWithNoForce(rule))
-	fileredInvokers := router.(*ConditionRouter).Route(invokers, &curl, inv)
-	assert.Equal(t, invokers, fileredInvokers)
+	r, _ := newConditionRouterFactory().NewPriorityRouter(getRouteUrlWithNoForce(rule))
+	ret := r.Route(utils.ToBitmap(invokers), setUpAddrCache(invokers), curl, inv)
+	assert.Equal(t, len(invokers), len(ret.ToArray()))
 }
 
 func TestRoute_Force(t *testing.T) {
-	localIP, _ := gxnet.GetLocalIP()
+	localIP := common.GetLocalIp()
 	url1, _ := common.NewURL(factory333URL)
 	url2, _ := common.NewURL(fmt.Sprintf(factoryDubboFormat, localIP))
 	url3, _ := common.NewURL(fmt.Sprintf(factoryDubboFormat, localIP))
@@ -363,9 +365,9 @@
 	inv := &invocation.RPCInvocation{}
 	rule := base64.URLEncoding.EncodeToString([]byte(fmt.Sprintf(factoryHostIp1234Format, localIP)))
 	curl, _ := common.NewURL(fmt.Sprintf(factoryConsumerFormat, localIP))
-	router, _ := newConditionRouterFactory().NewPriorityRouter(getRouteUrlWithForce(rule, "true"))
-	fileredInvokers := router.(*ConditionRouter).Route(invokers, &curl, inv)
-	assert.Equal(t, 0, len(fileredInvokers))
+	r, _ := newConditionRouterFactory().NewPriorityRouter(getRouteUrlWithForce(rule, "true"))
+	fileredInvokers := r.Route(utils.ToBitmap(invokers), setUpAddrCache(invokers), curl, inv)
+	assert.Equal(t, 0, len(fileredInvokers.ToArray()))
 }
 
 func TestNewConditionRouterFactory(t *testing.T) {
@@ -377,3 +379,7 @@
 	factory := newAppRouterFactory()
 	assert.NotNil(t, factory)
 }
+
+func setUpAddrCache(addrs []protocol.Invoker) router.Cache {
+	return chain.BuildCache(addrs)
+}
diff --git a/cluster/router/condition/file.go b/cluster/router/condition/file.go
index 996db74..a97d9cb 100644
--- a/cluster/router/condition/file.go
+++ b/cluster/router/condition/file.go
@@ -39,7 +39,7 @@
 type FileConditionRouter struct {
 	listenableRouter
 	parseOnce sync.Once
-	url       common.URL
+	url       *common.URL
 }
 
 // NewFileConditionRouter Create file condition router instance with content ( from config file)
@@ -60,11 +60,11 @@
 }
 
 // URL Return URL in file condition router n
-func (f *FileConditionRouter) URL() common.URL {
+func (f *FileConditionRouter) URL() *common.URL {
 	f.parseOnce.Do(func() {
 		routerRule := f.routerRule
 		rule := parseCondition(routerRule.Conditions)
-		f.url = *common.NewURLWithOptions(
+		f.url = common.NewURLWithOptions(
 			common.WithProtocol(constant.CONDITION_ROUTE_PROTOCOL),
 			common.WithIp(constant.ANYHOST_VALUE),
 			common.WithParams(url.Values{}),
diff --git a/cluster/router/condition/listenable_router.go b/cluster/router/condition/listenable_router.go
index 7f4f14a..0b47310 100644
--- a/cluster/router/condition/listenable_router.go
+++ b/cluster/router/condition/listenable_router.go
@@ -22,10 +22,12 @@
 )
 
 import (
+	"github.com/RoaringBitmap/roaring"
 	perrors "github.com/pkg/errors"
 )
 
 import (
+	"github.com/apache/dubbo-go/cluster/router"
 	"github.com/apache/dubbo-go/common"
 	"github.com/apache/dubbo-go/common/config"
 	"github.com/apache/dubbo-go/common/constant"
@@ -64,14 +66,14 @@
 	l.priority = listenableRouterDefaultPriority
 
 	routerKey := ruleKey + constant.ConditionRouterRuleSuffix
-	//add listener
+	// add listener
 	dynamicConfiguration := config.GetEnvInstance().GetDynamicConfiguration()
 	if dynamicConfiguration == nil {
 		return nil, perrors.Errorf("Get dynamicConfiguration fail, dynamicConfiguration is nil, init config center plugin please")
 	}
 
 	dynamicConfiguration.AddListener(routerKey, l)
-	//get rule
+	// get rule
 	rule, err := dynamicConfiguration.GetRule(routerKey, config_center.WithGroup(config_center.DEFAULT_GROUP))
 	if len(rule) == 0 || err != nil {
 		return nil, perrors.Errorf("Get rule fail, config rule{%s},  error{%v}", rule, err)
@@ -129,13 +131,13 @@
 }
 
 // Route Determine the target invokers list.
-func (l *listenableRouter) Route(invokers []protocol.Invoker, url *common.URL, invocation protocol.Invocation) []protocol.Invoker {
-	if len(invokers) == 0 || len(l.conditionRouters) == 0 {
+func (l *listenableRouter) Route(invokers *roaring.Bitmap, cache router.Cache, url *common.URL, invocation protocol.Invocation) *roaring.Bitmap {
+	if invokers.IsEmpty() || len(l.conditionRouters) == 0 {
 		return invokers
 	}
-	//We will check enabled status inside each router.
+	// We will check enabled status inside each router.
 	for _, r := range l.conditionRouters {
-		invokers = r.Route(invokers, url, invocation)
+		invokers = r.Route(invokers, cache, url, invocation)
 	}
 	return invokers
 }
@@ -146,6 +148,6 @@
 }
 
 // URL Return URL in listenable router
-func (l *listenableRouter) URL() common.URL {
-	return *l.url
+func (l *listenableRouter) URL() *common.URL {
+	return l.url
 }
diff --git a/cluster/router/condition/router.go b/cluster/router/condition/router.go
index 751b5a7..2fc3307 100644
--- a/cluster/router/condition/router.go
+++ b/cluster/router/condition/router.go
@@ -23,20 +23,22 @@
 )
 
 import (
+	"github.com/RoaringBitmap/roaring"
+	"github.com/dubbogo/gost/container/set"
 	perrors "github.com/pkg/errors"
 )
 
 import (
+	"github.com/apache/dubbo-go/cluster/router"
+	"github.com/apache/dubbo-go/cluster/router/utils"
 	"github.com/apache/dubbo-go/common"
 	"github.com/apache/dubbo-go/common/constant"
 	"github.com/apache/dubbo-go/common/logger"
 	"github.com/apache/dubbo-go/protocol"
-	"github.com/dubbogo/gost/container/set"
-	"github.com/dubbogo/gost/net"
 )
 
 const (
-	//pattern route pattern regex
+	// pattern route pattern regex
 	pattern = `([&!=,]*)\\s*([^&!=,\\s]+)`
 )
 
@@ -136,8 +138,8 @@
 }
 
 // URL Return URL in condition router
-func (c *ConditionRouter) URL() common.URL {
-	return *c.url
+func (c *ConditionRouter) URL() *common.URL {
+	return c.url
 }
 
 // Enabled Return is condition router is enabled
@@ -148,36 +150,44 @@
 }
 
 // Route Determine the target invokers list.
-func (c *ConditionRouter) Route(invokers []protocol.Invoker, url *common.URL, invocation protocol.Invocation) []protocol.Invoker {
+func (c *ConditionRouter) Route(invokers *roaring.Bitmap, cache router.Cache, url *common.URL, invocation protocol.Invocation) *roaring.Bitmap {
 	if !c.Enabled() {
 		return invokers
 	}
-	if len(invokers) == 0 {
+
+	if invokers.IsEmpty() {
 		return invokers
 	}
+
 	isMatchWhen := c.MatchWhen(url, invocation)
 	if !isMatchWhen {
 		return invokers
 	}
-	var result []protocol.Invoker
+
 	if len(c.ThenCondition) == 0 {
-		return result
+		return utils.EmptyAddr
 	}
-	for _, invoker := range invokers {
+
+	result := roaring.NewBitmap()
+	for iter := invokers.Iterator(); iter.HasNext(); {
+		index := iter.Next()
+		invoker := cache.GetInvokers()[index]
 		invokerUrl := invoker.GetUrl()
-		isMatchThen := c.MatchThen(&invokerUrl, url)
+		isMatchThen := c.MatchThen(invokerUrl, url)
 		if isMatchThen {
-			result = append(result, invoker)
+			result.Add(index)
 		}
 	}
-	if len(result) > 0 {
+
+	if !result.IsEmpty() {
 		return result
 	} else if c.Force {
 		rule, _ := url.GetParamAndDecoded(constant.RULE_KEY)
-		localIP, _ := gxnet.GetLocalIP()
+		localIP := common.GetLocalIp()
 		logger.Warnf("The route result is empty and force execute. consumer: %s, service: %s, router: %s", localIP, url.Service(), rule)
 		return result
 	}
+
 	return invokers
 }
 
diff --git a/cluster/router/condition/router_rule_test.go b/cluster/router/condition/router_rule_test.go
index 369b14f..192e528 100644
--- a/cluster/router/condition/router_rule_test.go
+++ b/cluster/router/condition/router_rule_test.go
@@ -80,5 +80,5 @@
 
 func TestIsMatchGlobPattern(t *testing.T) {
 	url, _ := common.NewURL("dubbo://localhost:8080/Foo?key=v*e")
-	assert.Equal(t, true, isMatchGlobalPattern("$key", "value", &url))
+	assert.Equal(t, true, isMatchGlobalPattern("$key", "value", url))
 }
diff --git a/cluster/router/condition/router_test.go b/cluster/router/condition/router_test.go
index c27a1d9..3d33ca2 100644
--- a/cluster/router/condition/router_test.go
+++ b/cluster/router/condition/router_test.go
@@ -59,7 +59,7 @@
 
 func TestNewConditionRouter(t *testing.T) {
 	url, _ := common.NewURL(`condition://0.0.0.0:?application=mock-app&category=routers&force=true&priority=1&router=condition&rule=YSAmIGMgPT4gYiAmIGQ%3D`)
-	router, err := NewConditionRouter(&url)
+	router, err := NewConditionRouter(url)
 	assert.Nil(t, err)
 	assert.Equal(t, true, router.Enabled())
 	assert.Equal(t, true, router.Force)
@@ -73,16 +73,16 @@
 	assert.Error(t, err)
 
 	url, _ = common.NewURL(`condition://0.0.0.0:?application=mock-app&category=routers&force=true&priority=1&router=condition&rule=YSAmT4gYiAmIGQ%3D`)
-	router, err = NewConditionRouter(&url)
+	router, err = NewConditionRouter(url)
 	assert.Error(t, err)
 
 	url, _ = common.NewURL(`condition://0.0.0.0:?application=mock-app&category=routers&force=true&router=condition&rule=YSAmIGMgPT4gYiAmIGQ%3D`)
-	router, err = NewConditionRouter(&url)
+	router, err = NewConditionRouter(url)
 	assert.Nil(t, err)
 	assert.Equal(t, int64(150), router.Priority())
 
 	url, _ = common.NewURL(`condition://0.0.0.0:?category=routers&force=true&interface=mock-service&router=condition&rule=YSAmIGMgPT4gYiAmIGQ%3D`)
-	router, err = NewConditionRouter(&url)
+	router, err = NewConditionRouter(url)
 	assert.Nil(t, err)
 	assert.Equal(t, int64(140), router.Priority())
 }
diff --git a/cluster/router/healthcheck/default_health_check.go b/cluster/router/healthcheck/default_health_check.go
index c522bdf..3effd77 100644
--- a/cluster/router/healthcheck/default_health_check.go
+++ b/cluster/router/healthcheck/default_health_check.go
@@ -48,6 +48,10 @@
 // IsHealthy evaluates the healthy state on the given Invoker based on the number of successive bad request
 // and the current active request
 func (c *DefaultHealthChecker) IsHealthy(invoker protocol.Invoker) bool {
+	if !invoker.IsAvailable() {
+		return false
+	}
+
 	urlStatus := protocol.GetURLStatus(invoker.GetUrl())
 	if c.isCircuitBreakerTripped(urlStatus) || urlStatus.GetActive() > c.GetOutStandingRequestCountLimit() {
 		logger.Debugf("Invoker [%s] is currently in circuitbreaker tripped state", invoker.GetUrl().Key())
@@ -92,6 +96,7 @@
 	return int64(sleepWindow)
 }
 
+
 // GetRequestSuccessiveFailureThreshold return the requestSuccessiveFailureThreshold bound to this DefaultHealthChecker
 func (c *DefaultHealthChecker) GetRequestSuccessiveFailureThreshold() int32 {
 	return c.requestSuccessiveFailureThreshold
@@ -110,8 +115,8 @@
 // NewDefaultHealthChecker constructs a new DefaultHealthChecker based on the url
 func NewDefaultHealthChecker(url *common.URL) router.HealthChecker {
 	return &DefaultHealthChecker{
-		outStandingRequestConutLimit:      int32(url.GetParamInt(constant.OUTSTANDING_REQUEST_COUNT_LIMIT_KEY, math.MaxInt32)),
-		requestSuccessiveFailureThreshold: int32(url.GetParamInt(constant.SUCCESSIVE_FAILED_REQUEST_THRESHOLD_KEY, constant.DEFAULT_SUCCESSIVE_FAILED_REQUEST_MAX_DIFF)),
-		circuitTrippedTimeoutFactor:       int32(url.GetParamInt(constant.CIRCUIT_TRIPPED_TIMEOUT_FACTOR_KEY, constant.DEFAULT_CIRCUIT_TRIPPED_TIMEOUT_FACTOR)),
+		outStandingRequestConutLimit:      url.GetParamInt32(constant.OUTSTANDING_REQUEST_COUNT_LIMIT_KEY, math.MaxInt32),
+		requestSuccessiveFailureThreshold: url.GetParamInt32(constant.SUCCESSIVE_FAILED_REQUEST_THRESHOLD_KEY, constant.DEFAULT_SUCCESSIVE_FAILED_REQUEST_MAX_DIFF),
+		circuitTrippedTimeoutFactor:       url.GetParamInt32(constant.CIRCUIT_TRIPPED_TIMEOUT_FACTOR_KEY, constant.DEFAULT_CIRCUIT_TRIPPED_TIMEOUT_FACTOR),
 	}
 }
diff --git a/cluster/router/healthcheck/default_health_check_test.go b/cluster/router/healthcheck/default_health_check_test.go
index 5d35ae8..39827c5 100644
--- a/cluster/router/healthcheck/default_health_check_test.go
+++ b/cluster/router/healthcheck/default_health_check_test.go
@@ -43,7 +43,7 @@
 func TestDefaultHealthCheckerIsHealthy(t *testing.T) {
 	defer protocol.CleanAllStatus()
 	url, _ := common.NewURL(fmt.Sprintf(healthCheckDubboUrlFormat, healthCheckDubbo1010IP))
-	hc := NewDefaultHealthChecker(&url).(*DefaultHealthChecker)
+	hc := NewDefaultHealthChecker(url).(*DefaultHealthChecker)
 	invoker := NewMockInvoker(url)
 	healthy := hc.IsHealthy(invoker)
 	assert.True(t, healthy)
@@ -54,7 +54,7 @@
 	for i := 0; i < 11; i++ {
 		request(url, healthCheckMethodTest, 0, true, false)
 	}
-	hc = NewDefaultHealthChecker(&url).(*DefaultHealthChecker)
+	hc = NewDefaultHealthChecker(url).(*DefaultHealthChecker)
 	healthy = hc.IsHealthy(invoker)
 	// the outgoing request is more than OUTSTANDING_REQUEST_COUNT_LIMIT, go to unhealthy
 	assert.False(t, hc.IsHealthy(invoker))
@@ -65,7 +65,7 @@
 	}
 	url.SetParam(constant.SUCCESSIVE_FAILED_REQUEST_THRESHOLD_KEY, "10")
 	url.SetParam(constant.OUTSTANDING_REQUEST_COUNT_LIMIT_KEY, "1000")
-	hc = NewDefaultHealthChecker(&url).(*DefaultHealthChecker)
+	hc = NewDefaultHealthChecker(url).(*DefaultHealthChecker)
 	healthy = hc.IsHealthy(invoker)
 	assert.False(t, hc.IsHealthy(invoker))
 
@@ -78,7 +78,7 @@
 func TestDefaultHealthCheckerGetCircuitBreakerSleepWindowTime(t *testing.T) {
 	defer protocol.CleanAllStatus()
 	url, _ := common.NewURL(fmt.Sprintf(healthCheckDubboUrlFormat, healthCheckDubbo1010IP))
-	defaultHc := NewDefaultHealthChecker(&url).(*DefaultHealthChecker)
+	defaultHc := NewDefaultHealthChecker(url).(*DefaultHealthChecker)
 	// Increase the number of failed requests
 	for i := 0; i < 100; i++ {
 		request(url, healthCheckMethodTest, 1, false, false)
@@ -88,7 +88,7 @@
 
 	// Adjust the threshold size to 1000
 	url.SetParam(constant.SUCCESSIVE_FAILED_REQUEST_THRESHOLD_KEY, "1000")
-	sleepWindowTime = NewDefaultHealthChecker(&url).(*DefaultHealthChecker).getCircuitBreakerSleepWindowTime(protocol.GetURLStatus(url))
+	sleepWindowTime = NewDefaultHealthChecker(url).(*DefaultHealthChecker).getCircuitBreakerSleepWindowTime(protocol.GetURLStatus(url))
 	assert.True(t, sleepWindowTime == 0)
 
 	url1, _ := common.NewURL(fmt.Sprintf(healthCheckDubboUrlFormat, healthCheckDubbo1011IP))
@@ -107,7 +107,7 @@
 func TestDefaultHealthCheckerGetCircuitBreakerTimeout(t *testing.T) {
 	defer protocol.CleanAllStatus()
 	url, _ := common.NewURL(fmt.Sprintf(healthCheckDubboUrlFormat, healthCheckDubbo1010IP))
-	defaultHc := NewDefaultHealthChecker(&url).(*DefaultHealthChecker)
+	defaultHc := NewDefaultHealthChecker(url).(*DefaultHealthChecker)
 	timeout := defaultHc.getCircuitBreakerTimeout(protocol.GetURLStatus(url))
 	assert.True(t, timeout == 0)
 	url1, _ := common.NewURL(fmt.Sprintf(healthCheckDubboUrlFormat, healthCheckDubbo1011IP))
@@ -126,7 +126,7 @@
 func TestDefaultHealthCheckerIsCircuitBreakerTripped(t *testing.T) {
 	defer protocol.CleanAllStatus()
 	url, _ := common.NewURL(fmt.Sprintf(healthCheckDubboUrlFormat, healthCheckDubbo1010IP))
-	defaultHc := NewDefaultHealthChecker(&url).(*DefaultHealthChecker)
+	defaultHc := NewDefaultHealthChecker(url).(*DefaultHealthChecker)
 	status := protocol.GetURLStatus(url)
 	tripped := defaultHc.isCircuitBreakerTripped(status)
 	assert.False(t, tripped)
@@ -142,7 +142,7 @@
 func TestNewDefaultHealthChecker(t *testing.T) {
 	defer protocol.CleanAllStatus()
 	url, _ := common.NewURL(fmt.Sprintf(healthCheckDubboUrlFormat, healthCheckDubbo1010IP))
-	defaultHc := NewDefaultHealthChecker(&url).(*DefaultHealthChecker)
+	defaultHc := NewDefaultHealthChecker(url).(*DefaultHealthChecker)
 	assert.NotNil(t, defaultHc)
 	assert.Equal(t, defaultHc.outStandingRequestConutLimit, int32(math.MaxInt32))
 	assert.Equal(t, defaultHc.requestSuccessiveFailureThreshold, int32(constant.DEFAULT_SUCCESSIVE_FAILED_REQUEST_MAX_DIFF))
@@ -150,13 +150,13 @@
 	url1, _ := common.NewURL(fmt.Sprintf(healthCheckDubboUrlFormat, healthCheckDubbo1010IP))
 	url1.SetParam(constant.OUTSTANDING_REQUEST_COUNT_LIMIT_KEY, "10")
 	url1.SetParam(constant.SUCCESSIVE_FAILED_REQUEST_THRESHOLD_KEY, "10")
-	nondefaultHc := NewDefaultHealthChecker(&url1).(*DefaultHealthChecker)
+	nondefaultHc := NewDefaultHealthChecker(url1).(*DefaultHealthChecker)
 	assert.NotNil(t, nondefaultHc)
 	assert.Equal(t, nondefaultHc.outStandingRequestConutLimit, int32(10))
 	assert.Equal(t, nondefaultHc.requestSuccessiveFailureThreshold, int32(10))
 }
 
-func request(url common.URL, method string, elapsed int64, active, succeeded bool) {
+func request(url *common.URL, method string, elapsed int64, active, succeeded bool) {
 	protocol.BeginCount(url, method)
 	if !active {
 		protocol.EndCount(url, method, elapsed, succeeded)
diff --git a/cluster/router/healthcheck/factory_test.go b/cluster/router/healthcheck/factory_test.go
index e80fd4c..1e73683 100644
--- a/cluster/router/healthcheck/factory_test.go
+++ b/cluster/router/healthcheck/factory_test.go
@@ -33,18 +33,18 @@
 
 // nolint
 type MockInvoker struct {
-	url common.URL
+	url *common.URL
 }
 
 // nolint
-func NewMockInvoker(url common.URL) *MockInvoker {
+func NewMockInvoker(url *common.URL) *MockInvoker {
 	return &MockInvoker{
 		url: url,
 	}
 }
 
 // nolint
-func (bi *MockInvoker) GetUrl() common.URL {
+func (bi *MockInvoker) GetUrl() *common.URL {
 	return bi.url
 }
 
diff --git a/cluster/router/healthcheck/health_check_route.go b/cluster/router/healthcheck/health_check_route.go
index ee42e47..1a878af 100644
--- a/cluster/router/healthcheck/health_check_route.go
+++ b/cluster/router/healthcheck/health_check_route.go
@@ -18,7 +18,12 @@
 package healthcheck
 
 import (
+	"github.com/RoaringBitmap/roaring"
+)
+
+import (
 	"github.com/apache/dubbo-go/cluster/router"
+	"github.com/apache/dubbo-go/cluster/router/utils"
 	"github.com/apache/dubbo-go/common"
 	"github.com/apache/dubbo-go/common/constant"
 	"github.com/apache/dubbo-go/common/extension"
@@ -28,6 +33,8 @@
 
 const (
 	HEALTH_ROUTE_ENABLED_KEY = "health.route.enabled"
+	healthy                  = "healthy"
+	name                     = "health-check-router"
 )
 
 // HealthCheckRouter provides a health-first routing mechanism through HealthChecker
@@ -51,33 +58,56 @@
 }
 
 // Route gets a list of healthy invoker
-func (r *HealthCheckRouter) Route(invokers []protocol.Invoker, url *common.URL, invocation protocol.Invocation) []protocol.Invoker {
+func (r *HealthCheckRouter) Route(invokers *roaring.Bitmap, cache router.Cache, url *common.URL, invocation protocol.Invocation) *roaring.Bitmap {
 	if !r.enabled {
 		return invokers
 	}
-	healthyInvokers := make([]protocol.Invoker, 0, len(invokers))
+
+	addrPool := cache.FindAddrPool(r)
 	// Add healthy invoker to the list
-	for _, invoker := range invokers {
-		if r.checker.IsHealthy(invoker) {
-			healthyInvokers = append(healthyInvokers, invoker)
-		}
-	}
-	// If all Invoke are considered unhealthy, downgrade to all inovker
-	if len(healthyInvokers) == 0 {
+	healthyInvokers := utils.JoinIfNotEqual(addrPool[healthy], invokers)
+	// If all invokers are considered unhealthy, downgrade to all invoker
+	if healthyInvokers.IsEmpty() {
 		logger.Warnf(" Now all invokers are unhealthy, so downgraded to all! Service: [%s]", url.ServiceKey())
 		return invokers
 	}
 	return healthyInvokers
 }
 
+// Pool separates healthy invokers from others.
+func (r *HealthCheckRouter) Pool(invokers []protocol.Invoker) (router.AddrPool, router.AddrMetadata) {
+	if !r.enabled {
+		return nil, nil
+	}
+
+	rb := make(router.AddrPool, 8)
+	rb[healthy] = roaring.NewBitmap()
+	for i, invoker := range invokers {
+		if r.checker.IsHealthy(invoker) {
+			rb[healthy].Add(uint32(i))
+		}
+	}
+
+	return rb, nil
+}
+
+// ShouldPool will always return true to make sure healthy check constantly.
+func (r *HealthCheckRouter) ShouldPool() bool {
+	return r.enabled
+}
+
+func (r *HealthCheckRouter) Name() string {
+	return name
+}
+
 // Priority
 func (r *HealthCheckRouter) Priority() int64 {
 	return 0
 }
 
 // URL Return URL in router
-func (r *HealthCheckRouter) URL() common.URL {
-	return *r.url
+func (r *HealthCheckRouter) URL() *common.URL {
+	return r.url
 }
 
 // HealthyChecker returns the HealthChecker bound to this HealthCheckRouter
diff --git a/cluster/router/healthcheck/health_check_route_test.go b/cluster/router/healthcheck/health_check_route_test.go
index d5862fb..0730f10 100644
--- a/cluster/router/healthcheck/health_check_route_test.go
+++ b/cluster/router/healthcheck/health_check_route_test.go
@@ -29,6 +29,9 @@
 )
 
 import (
+	"github.com/apache/dubbo-go/cluster/router"
+	"github.com/apache/dubbo-go/cluster/router/chain"
+	"github.com/apache/dubbo-go/cluster/router/utils"
 	"github.com/apache/dubbo-go/common"
 	"github.com/apache/dubbo-go/common/constant"
 	"github.com/apache/dubbo-go/protocol"
@@ -51,7 +54,7 @@
 	url1, _ := common.NewURL(fmt.Sprintf(healthCheckRouteUrlFormat, healthCheckRoute1010IP))
 	url2, _ := common.NewURL(fmt.Sprintf(healthCheckRouteUrlFormat, healthCheckRoute1011IP))
 	url3, _ := common.NewURL(fmt.Sprintf(healthCheckRouteUrlFormat, healthCheckRoute1012IP))
-	hcr, _ := NewHealthCheckRouter(&consumerURL)
+	hcr, _ := NewHealthCheckRouter(consumerURL)
 
 	var invokers []protocol.Invoker
 	invoker1 := NewMockInvoker(url1)
@@ -59,25 +62,25 @@
 	invoker3 := NewMockInvoker(url3)
 	invokers = append(invokers, invoker1, invoker2, invoker3)
 	inv := invocation.NewRPCInvocation(healthCheckRouteMethodNameTest, nil, nil)
-	res := hcr.Route(invokers, &consumerURL, inv)
+	res := hcr.Route(utils.ToBitmap(invokers), setUpAddrCache(hcr.(*HealthCheckRouter), invokers), consumerURL, inv)
 	// now all invokers are healthy
-	assert.True(t, len(res) == len(invokers))
+	assert.True(t, len(res.ToArray()) == len(invokers))
 
 	for i := 0; i < 10; i++ {
 		request(url1, healthCheckRouteMethodNameTest, 0, false, false)
 	}
-	res = hcr.Route(invokers, &consumerURL, inv)
+	res = hcr.Route(utils.ToBitmap(invokers), setUpAddrCache(hcr.(*HealthCheckRouter), invokers), consumerURL, inv)
 	// invokers1  is unhealthy now
-	assert.True(t, len(res) == 2 && !contains(res, invoker1))
+	assert.True(t, len(res.ToArray()) == 2 && !res.Contains(0))
 
 	for i := 0; i < 10; i++ {
 		request(url1, healthCheckRouteMethodNameTest, 0, false, false)
 		request(url2, healthCheckRouteMethodNameTest, 0, false, false)
 	}
 
-	res = hcr.Route(invokers, &consumerURL, inv)
+	res = hcr.Route(utils.ToBitmap(invokers), setUpAddrCache(hcr.(*HealthCheckRouter), invokers), consumerURL, inv)
 	// only invokers3  is healthy now
-	assert.True(t, len(res) == 1 && !contains(res, invoker1) && !contains(res, invoker2))
+	assert.True(t, len(res.ToArray()) == 1 && !res.Contains(0) && !res.Contains(1))
 
 	for i := 0; i < 10; i++ {
 		request(url1, healthCheckRouteMethodNameTest, 0, false, false)
@@ -85,46 +88,37 @@
 		request(url3, healthCheckRouteMethodNameTest, 0, false, false)
 	}
 
-	res = hcr.Route(invokers, &consumerURL, inv)
+	res = hcr.Route(utils.ToBitmap(invokers), setUpAddrCache(hcr.(*HealthCheckRouter), invokers), consumerURL, inv)
 	// now all invokers are unhealthy, so downgraded to all
-	assert.True(t, len(res) == 3)
+	assert.True(t, len(res.ToArray()) == 3)
 
 	// reset the invoker1 successive failed count, so invoker1 go to healthy
 	request(url1, healthCheckRouteMethodNameTest, 0, false, true)
-	res = hcr.Route(invokers, &consumerURL, inv)
-	assert.True(t, contains(res, invoker1))
+	res = hcr.Route(utils.ToBitmap(invokers), setUpAddrCache(hcr.(*HealthCheckRouter), invokers), consumerURL, inv)
+	assert.True(t, res.Contains(0))
 
 	for i := 0; i < 6; i++ {
 		request(url1, healthCheckRouteMethodNameTest, 0, false, false)
 	}
 	// now all invokers are unhealthy, so downgraded to all again
-	res = hcr.Route(invokers, &consumerURL, inv)
-	assert.True(t, len(res) == 3)
+	res = hcr.Route(utils.ToBitmap(invokers), setUpAddrCache(hcr.(*HealthCheckRouter), invokers), consumerURL, inv)
+	assert.True(t, len(res.ToArray()) == 3)
 	time.Sleep(time.Second * 2)
 	// invoker1 go to healthy again after 2s
-	res = hcr.Route(invokers, &consumerURL, inv)
-	assert.True(t, contains(res, invoker1))
+	res = hcr.Route(utils.ToBitmap(invokers), setUpAddrCache(hcr.(*HealthCheckRouter), invokers), consumerURL, inv)
+	assert.True(t, res.Contains(0))
 
 }
 
-func contains(invokers []protocol.Invoker, invoker protocol.Invoker) bool {
-	for _, e := range invokers {
-		if e == invoker {
-			return true
-		}
-	}
-	return false
-}
-
 func TestNewHealthCheckRouter(t *testing.T) {
 	defer protocol.CleanAllStatus()
 	url, _ := common.NewURL(fmt.Sprintf(healthCheckDubboUrlFormat, healthCheckDubbo1010IP))
-	hcr, _ := NewHealthCheckRouter(&url)
+	hcr, _ := NewHealthCheckRouter(url)
 	h := hcr.(*HealthCheckRouter)
 	assert.Nil(t, h.checker)
 
 	url.SetParam(HEALTH_ROUTE_ENABLED_KEY, "true")
-	hcr, _ = NewHealthCheckRouter(&url)
+	hcr, _ = NewHealthCheckRouter(url)
 	h = hcr.(*HealthCheckRouter)
 	assert.NotNil(t, h.checker)
 
@@ -136,10 +130,18 @@
 	url.SetParam(constant.CIRCUIT_TRIPPED_TIMEOUT_FACTOR_KEY, "500")
 	url.SetParam(constant.SUCCESSIVE_FAILED_REQUEST_THRESHOLD_KEY, "10")
 	url.SetParam(constant.OUTSTANDING_REQUEST_COUNT_LIMIT_KEY, "1000")
-	hcr, _ = NewHealthCheckRouter(&url)
+	hcr, _ = NewHealthCheckRouter(url)
 	h = hcr.(*HealthCheckRouter)
 	dhc = h.checker.(*DefaultHealthChecker)
 	assert.Equal(t, dhc.outStandingRequestConutLimit, int32(1000))
 	assert.Equal(t, dhc.requestSuccessiveFailureThreshold, int32(10))
 	assert.Equal(t, dhc.circuitTrippedTimeoutFactor, int32(500))
 }
+
+func setUpAddrCache(r router.Poolable, addrs []protocol.Invoker) router.Cache {
+	pool, info := r.Pool(addrs)
+	cache := chain.BuildCache(addrs)
+	cache.SetAddrMeta(r.Name(), info)
+	cache.SetAddrPool(r.Name(), pool)
+	return cache
+}
diff --git a/cluster/router/router.go b/cluster/router/router.go
index 66603c1..8a19dcf 100644
--- a/cluster/router/router.go
+++ b/cluster/router/router.go
@@ -18,6 +18,10 @@
 package router
 
 import (
+	"github.com/RoaringBitmap/roaring"
+)
+
+import (
 	"github.com/apache/dubbo-go/common"
 	"github.com/apache/dubbo-go/protocol"
 )
@@ -38,9 +42,10 @@
 // Router
 type router interface {
 	// Route Determine the target invokers list.
-	Route([]protocol.Invoker, *common.URL, protocol.Invocation) []protocol.Invoker
+	Route(*roaring.Bitmap, Cache, *common.URL, protocol.Invocation) *roaring.Bitmap
+
 	// URL Return URL in router
-	URL() common.URL
+	URL() *common.URL
 }
 
 // Router
@@ -51,10 +56,38 @@
 	Priority() int64
 }
 
-// NotifyRouter notify router use the invoker list. Invoker list may change from time to time. This method gives the router a
-// chance to prepare before {@link Router#route(List, URL, Invocation)} gets called.
-type NotifyRouter interface {
-	PriorityRouter
-	// Notify notify whenever addresses in registry change
-	Notify([]protocol.Invoker)
+// Poolable caches address pool and address metadata for a router instance which will be used later in Router's Route.
+type Poolable interface {
+	// Pool created address pool and address metadata from the invokers.
+	Pool([]protocol.Invoker) (AddrPool, AddrMetadata)
+
+	// ShouldPool returns if it should pool. One typical scenario is a router rule changes, in this case, a pooling
+	// is necessary, even if the addresses not changed at all.
+	ShouldPool() bool
+
+	// Name return the Poolable's name.
+	Name() string
+}
+
+// AddrPool is an address pool, backed by a snapshot of address list, divided into categories.
+type AddrPool map[string]*roaring.Bitmap
+
+// AddrMetadta is address metadata, collected from a snapshot of address list by a router, if it implements Poolable.
+type AddrMetadata interface {
+	// Source indicates where the metadata comes from.
+	Source() string
+}
+
+// Cache caches all addresses relevant info for a snapshot of received invokers. It keeps a snapshot of the received
+// address list, and also keeps address pools and address metadata from routers based on the same address snapshot, if
+// the router implements Poolable.
+type Cache interface {
+	// GetInvokers returns the snapshot of received invokers.
+	GetInvokers() []protocol.Invoker
+
+	// FindAddrPool returns address pool associated with the given Poolable instance.
+	FindAddrPool(Poolable) AddrPool
+
+	// FindAddrMeta returns address metadata associated with the given Poolable instance.
+	FindAddrMeta(Poolable) AddrMetadata
 }
diff --git a/cluster/router/tag/factory_test.go b/cluster/router/tag/factory_test.go
index ee19582..b350bb2 100644
--- a/cluster/router/tag/factory_test.go
+++ b/cluster/router/tag/factory_test.go
@@ -39,7 +39,7 @@
 	u1, err := common.NewURL(fmt.Sprintf(factoryFormat, factoryLocalIP))
 	assert.Nil(t, err)
 	factory := NewTagRouterFactory()
-	tagRouter, e := factory.NewPriorityRouter(&u1)
+	tagRouter, e := factory.NewPriorityRouter(u1)
 	assert.Nil(t, e)
 	assert.NotNil(t, tagRouter)
 }
diff --git a/cluster/router/tag/file.go b/cluster/router/tag/file.go
index 433abcb..94daf15 100644
--- a/cluster/router/tag/file.go
+++ b/cluster/router/tag/file.go
@@ -24,10 +24,12 @@
 )
 
 import (
+	"github.com/RoaringBitmap/roaring"
 	perrors "github.com/pkg/errors"
 )
 
 import (
+	"github.com/apache/dubbo-go/cluster/router"
 	"github.com/apache/dubbo-go/common"
 	"github.com/apache/dubbo-go/common/constant"
 	"github.com/apache/dubbo-go/protocol"
@@ -50,13 +52,12 @@
 		return nil, perrors.Errorf("yaml.Unmarshal() failed , error:%v", perrors.WithStack(err))
 	}
 	fileRouter.routerRule = rule
-	url := fileRouter.URL()
-	fileRouter.router, err = NewTagRouter(&url)
+	fileRouter.router, err = NewTagRouter(fileRouter.URL())
 	return fileRouter, err
 }
 
 // URL Return URL in file tag router n
-func (f *FileTagRouter) URL() common.URL {
+func (f *FileTagRouter) URL() *common.URL {
 	f.parseOnce.Do(func() {
 		routerRule := f.routerRule
 		f.url = common.NewURLWithOptions(
@@ -66,7 +67,7 @@
 			common.WithParamsValue(constant.RouterPriority, strconv.Itoa(routerRule.Priority)),
 			common.WithParamsValue(constant.ROUTER_KEY, constant.TAG_ROUTE_PROTOCOL))
 	})
-	return *f.url
+	return f.url
 }
 
 // Priority Return Priority in listenable router
@@ -74,9 +75,10 @@
 	return f.router.priority
 }
 
-func (f *FileTagRouter) Route(invokers []protocol.Invoker, url *common.URL, invocation protocol.Invocation) []protocol.Invoker {
-	if len(invokers) == 0 {
+func (f *FileTagRouter) Route(invokers *roaring.Bitmap, cache router.Cache, url *common.URL, invocation protocol.Invocation) *roaring.Bitmap {
+	if invokers.IsEmpty() {
 		return invokers
 	}
-	return f.Route(invokers, url, invocation)
+	// FIXME: I believe this is incorrect.
+	return f.Route(invokers, cache, url, invocation)
 }
diff --git a/cluster/router/tag/tag_router.go b/cluster/router/tag/tag_router.go
index fafed68..c7f5304 100644
--- a/cluster/router/tag/tag_router.go
+++ b/cluster/router/tag/tag_router.go
@@ -18,17 +18,20 @@
 package tag
 
 import (
-	"net"
 	"strconv"
+	"strings"
+	"sync"
 )
 
 import (
+	"github.com/RoaringBitmap/roaring"
 	gxnet "github.com/dubbogo/gost/net"
-	"github.com/jinzhu/copier"
 	perrors "github.com/pkg/errors"
 )
 
 import (
+	"github.com/apache/dubbo-go/cluster/router"
+	"github.com/apache/dubbo-go/cluster/router/utils"
 	"github.com/apache/dubbo-go/common"
 	"github.com/apache/dubbo-go/common/config"
 	"github.com/apache/dubbo-go/common/constant"
@@ -38,6 +41,32 @@
 	"github.com/apache/dubbo-go/remoting"
 )
 
+const (
+	name          = "tag-router"
+	staticPrefix  = "static-"
+	dynamicPrefix = "dynamic-"
+)
+
+// addrMetadata keeps snapshot data for app name, and some infos extracted from dynamic tag rule in order to make
+// Route() method lock-free.
+type addrMetadata struct {
+	// application name
+	application string
+	// is rule a runtime rule
+	ruleRuntime bool
+	// is rule a force rule
+	ruleForce bool
+	// is rule a valid rule
+	ruleValid bool
+	// is rule an enabled rule
+	ruleEnabled bool
+}
+
+// Source indicates where the metadata comes from.
+func (m *addrMetadata) Source() string {
+	return name
+}
+
 // tagRouter defines url, enable and the priority
 type tagRouter struct {
 	url           *common.URL
@@ -45,6 +74,8 @@
 	enabled       bool
 	priority      int64
 	application   string
+	ruleChanged   bool
+	mutex         sync.RWMutex
 }
 
 // NewTagRouter returns a tagRouter instance if url is not nil
@@ -65,62 +96,79 @@
 }
 
 // Route gets a list of invoker
-func (c *tagRouter) Route(invokers []protocol.Invoker, url *common.URL, invocation protocol.Invocation) []protocol.Invoker {
-	var (
-		result    []protocol.Invoker
-		addresses []string
-		tag       string
-	)
-
-	if !c.isEnabled() || len(invokers) == 0 {
+func (c *tagRouter) Route(invokers *roaring.Bitmap, cache router.Cache, url *common.URL, invocation protocol.Invocation) *roaring.Bitmap {
+	if !c.isEnabled() || invokers.IsEmpty() {
 		return invokers
 	}
 
-	// Use static tags if dynamic tags are not set or invalid
-	if c.tagRouterRule == nil || !c.tagRouterRule.Valid || !c.tagRouterRule.Enabled {
-		return filterUsingStaticTag(invokers, url, invocation)
+	if shouldUseDynamicTag(cache.FindAddrMeta(c)) {
+		return c.routeWithDynamicTag(invokers, cache, url, invocation)
 	}
-
-	// since the rule can be changed by config center, we should copy one to use.
-	tagRouterRuleCopy := new(RouterRule)
-	_ = copier.Copy(tagRouterRuleCopy, c.tagRouterRule)
-	tagValue, ok := invocation.Attachments()[constant.Tagkey]
-	if !ok {
-		tag = url.GetParam(constant.Tagkey, "")
-	} else {
-		tag, ok = tagValue.(string)
-		if !ok {
-			tag = url.GetParam(constant.Tagkey, "")
-		}
-	}
-
-	// if we are requesting for a Provider with a specific tag
-	if len(tag) > 0 {
-		return filterInvokersWithTag(invokers, url, invocation, *tagRouterRuleCopy, tag)
-	}
-
-	// return all addresses in dynamic tag group.
-	addresses = tagRouterRuleCopy.getAddresses()
-	if len(addresses) > 0 {
-		filterAddressNotMatches := func(invoker protocol.Invoker) bool {
-			url := invoker.GetUrl()
-			return len(addresses) == 0 || !checkAddressMatch(addresses, url.Ip, url.Port)
-		}
-		result = filterInvoker(invokers, filterAddressNotMatches)
-		// 1. all addresses are in dynamic tag group, return empty list.
-		if len(result) == 0 {
-			return result
-		}
-	}
-	// 2. if there are some addresses that are not in any dynamic tag group, continue to filter using the
-	// static tag group.
-	filter := func(invoker protocol.Invoker) bool {
-		localTag := invoker.GetUrl().GetParam(constant.Tagkey, "")
-		return len(localTag) == 0 || !(tagRouterRuleCopy.hasTag(localTag))
-	}
-	return filterInvoker(result, filter)
+	return c.routeWithStaticTag(invokers, cache, url, invocation)
 }
 
+// routeWithStaticTag routes with static tag rule
+func (c *tagRouter) routeWithStaticTag(invokers *roaring.Bitmap, cache router.Cache, url *common.URL, invocation protocol.Invocation) *roaring.Bitmap {
+	tag := findTag(invocation, url)
+	if tag == "" {
+		return invokers
+	}
+
+	ret, _ := c.filterWithTag(invokers, cache, staticPrefix+tag)
+	if ret.IsEmpty() && !isForceUseTag(url, invocation) {
+		return invokers
+	}
+
+	return ret
+}
+
+// routeWithDynamicTag routes with dynamic tag rule
+func (c *tagRouter) routeWithDynamicTag(invokers *roaring.Bitmap, cache router.Cache, url *common.URL, invocation protocol.Invocation) *roaring.Bitmap {
+	tag := findTag(invocation, url)
+	if tag == "" {
+		return c.filterNotInDynamicTag(invokers, cache)
+	}
+
+	ret, ok := c.filterWithTag(invokers, cache, dynamicPrefix+tag)
+	if ok && (!ret.IsEmpty() || isTagRuleForce(cache.FindAddrMeta(c))) {
+		return ret
+	}
+
+	// dynamic tag group doesn't have any item about the requested app OR it's null after filtered by
+	// dynamic tag group but force=false. check static tag
+	if ret.IsEmpty() {
+		ret, _ = c.filterWithTag(invokers, cache, staticPrefix+tag)
+		// If there's no tagged providers that can match the current tagged request. force.tag is set by default
+		// to false, which means it will invoke any providers without a tag unless it's explicitly disallowed.
+		if !ret.IsEmpty() || isForceUseTag(url, invocation) {
+			return ret
+		}
+		return c.filterNotInDynamicTag(invokers, cache)
+	}
+	return ret
+}
+
+// filterWithTag filters incoming invokers with the given tag
+func (c *tagRouter) filterWithTag(invokers *roaring.Bitmap, cache router.Cache, tag string) (*roaring.Bitmap, bool) {
+	if target, ok := cache.FindAddrPool(c)[tag]; ok {
+		return utils.JoinIfNotEqual(target, invokers), true
+	}
+	return utils.EmptyAddr, false
+}
+
+// filterNotInDynamicTag filters incoming invokers not applied to dynamic tag rule
+func (c *tagRouter) filterNotInDynamicTag(invokers *roaring.Bitmap, cache router.Cache) *roaring.Bitmap {
+	// FAILOVER: return all Providers without any tags.
+	invokers = invokers.Clone()
+	for k, v := range cache.FindAddrPool(c) {
+		if strings.HasPrefix(k, dynamicPrefix) {
+			invokers.AndNot(v)
+		}
+	}
+	return invokers
+}
+
+// Process parses dynamic tag rule
 func (c *tagRouter) Process(event *config_center.ConfigChangeEvent) {
 	logger.Infof("Notification of tag rule, change type is:[%s] , raw rule is:[%v]", event.ConfigType, event.Value)
 	if remoting.EventTypeDel == event.ConfigType {
@@ -138,16 +186,52 @@
 		logger.Errorf("Parse dynamic tag router rule fail,error:[%s] ", err)
 		return
 	}
+
+	c.mutex.Lock()
+	defer c.mutex.Unlock()
 	c.tagRouterRule = routerRule
-	return
+	c.ruleChanged = true
 }
 
-func (c *tagRouter) Notify(invokers []protocol.Invoker) {
-	if len(invokers) == 0 {
+// URL gets the url of tagRouter
+func (c *tagRouter) URL() *common.URL {
+	return c.url
+}
+
+// Priority gets the priority of tagRouter
+func (c *tagRouter) Priority() int64 {
+	return c.priority
+}
+
+// Pool divided invokers into different address pool by tag.
+func (c *tagRouter) Pool(invokers []protocol.Invoker) (router.AddrPool, router.AddrMetadata) {
+	c.fetchRuleIfNecessary(invokers)
+
+	rb := make(router.AddrPool, 8)
+	poolWithStaticTag(invokers, rb)
+
+	c.mutex.Lock()
+	defer c.mutex.Unlock()
+	poolWithDynamicTag(invokers, c.tagRouterRule, rb)
+	c.ruleChanged = false
+	// create metadata in order to avoid lock in route()
+	meta := addrMetadata{application: c.application}
+	if c.tagRouterRule != nil {
+		meta.ruleForce = c.tagRouterRule.Force
+		meta.ruleEnabled = c.tagRouterRule.Enabled
+		meta.ruleValid = c.tagRouterRule.Valid
+	}
+
+	return rb, &meta
+}
+
+// fetchRuleIfNecessary fetches, parses rule and register listener for the further change
+func (c *tagRouter) fetchRuleIfNecessary(invokers []protocol.Invoker) {
+	if invokers == nil || len(invokers) == 0 {
 		return
 	}
-	invoker := invokers[0]
-	url := invoker.GetUrl()
+
+	url := invokers[0].GetUrl()
 	providerApplication := url.GetParam(constant.RemoteApplicationKey, "")
 	if len(providerApplication) == 0 {
 		logger.Error("TagRouter must getConfig from or subscribe to a specific application, but the application " +
@@ -162,11 +246,15 @@
 
 	if providerApplication != c.application {
 		dynamicConfiguration.RemoveListener(c.application+constant.TagRouterRuleSuffix, c)
+	} else {
+		// if app name from URL is as same as the current app name, then it is safe to jump out
+		return
 	}
 
+	c.application = providerApplication
 	routerKey := providerApplication + constant.TagRouterRuleSuffix
 	dynamicConfiguration.AddListener(routerKey, c)
-	//get rule
+	// get rule
 	rule, err := dynamicConfiguration.GetRule(routerKey, config_center.WithGroup(config_center.DEFAULT_GROUP))
 	if len(rule) == 0 || err != nil {
 		logger.Errorf("Get rule fail, config rule{%s},  error{%v}", rule, err)
@@ -180,71 +268,52 @@
 	}
 }
 
-// URL gets the url of tagRouter
-func (c *tagRouter) URL() common.URL {
-	return *c.url
+// ShouldPool returns false, to make sure address cache for tag router happens once and only once.
+func (c *tagRouter) ShouldPool() bool {
+	c.mutex.RLock()
+	defer c.mutex.RUnlock()
+	return c.ruleChanged
 }
 
-// Priority gets the priority of tagRouter
-func (c *tagRouter) Priority() int64 {
-	return c.priority
+// Name returns pool's name
+func (c *tagRouter) Name() string {
+	return name
 }
 
-// filterUsingStaticTag gets a list of invoker using static tag
-func filterUsingStaticTag(invokers []protocol.Invoker, url *common.URL, invocation protocol.Invocation) []protocol.Invoker {
-	if tag, ok := invocation.Attachments()[constant.Tagkey]; ok {
-		result := make([]protocol.Invoker, 0, 8)
-		for _, v := range invokers {
-			if v.GetUrl().GetParam(constant.Tagkey, "") == tag {
-				result = append(result, v)
-			}
-		}
-		if len(result) == 0 && !isForceUseTag(url, invocation) {
-			return invokers
-		}
-		return result
+// poolWithDynamicTag pools addresses with the tags defined in dynamic tag rule, all keys have prefix "dynamic-"
+func poolWithDynamicTag(invokers []protocol.Invoker, rule *RouterRule, pool router.AddrPool) {
+	if rule == nil {
+		return
 	}
-	return invokers
+
+	tagNameToAddresses := rule.getTagNameToAddresses()
+	for tag, addrs := range tagNameToAddresses {
+		pool[dynamicPrefix+tag] = addrsToBitmap(addrs, invokers)
+	}
 }
 
-// filterInvokersWithTag gets a list of invoker using dynamic route with tag
-func filterInvokersWithTag(invokers []protocol.Invoker, url *common.URL, invocation protocol.Invocation, tagRouterRule RouterRule, tag string) []protocol.Invoker {
-	var (
-		result    []protocol.Invoker
-		addresses []string
-	)
-	addresses, _ = tagRouterRule.getTagNameToAddresses()[tag]
-	// filter by dynamic tag group first
-	if len(addresses) > 0 {
-		filterAddressMatches := func(invoker protocol.Invoker) bool {
-			url := invoker.GetUrl()
-			return len(addresses) > 0 && checkAddressMatch(addresses, url.Ip, url.Port)
-		}
-		result = filterInvoker(invokers, filterAddressMatches)
-		if len(result) > 0 || tagRouterRule.Force {
-			return result
-		}
-	}
-	// dynamic tag group doesn't have any item about the requested app OR it's null after filtered by
-	// dynamic tag group but force=false. check static tag
-	filter := func(invoker protocol.Invoker) bool {
-		return invoker.GetUrl().GetParam(constant.Tagkey, "") == tag
-	}
-	result = filterInvoker(invokers, filter)
-	// If there's no tagged providers that can match the current tagged request. force.tag is set by default
-	// to false, which means it will invoke any providers without a tag unless it's explicitly disallowed.
-	if len(result) > 0 || isForceUseTag(url, invocation) {
-		return result
-	}
-	// FAILOVER: return all Providers without any tags.
-	filterAddressNotMatches := func(invoker protocol.Invoker) bool {
+// poolWithStaticTag pools addresses with tags found from incoming URLs, all keys have prefix "static-"
+func poolWithStaticTag(invokers []protocol.Invoker, pool router.AddrPool) {
+	for i, invoker := range invokers {
 		url := invoker.GetUrl()
-		return len(addresses) == 0 || !checkAddressMatch(tagRouterRule.getAddresses(), url.Ip, url.Port)
+		tag := url.GetParam(constant.Tagkey, "")
+		if len(tag) > 0 {
+			if _, ok := pool[staticPrefix+tag]; !ok {
+				pool[staticPrefix+tag] = roaring.NewBitmap()
+			}
+			pool[staticPrefix+tag].AddInt(i)
+		}
 	}
-	filterTagIsEmpty := func(invoker protocol.Invoker) bool {
-		return invoker.GetUrl().GetParam(constant.Tagkey, "") == ""
-	}
-	return filterInvoker(invokers, filterAddressNotMatches, filterTagIsEmpty)
+}
+
+// shouldUseDynamicTag uses the snapshot data from the parsed rule to decide if dynamic tag rule should be used or not
+func shouldUseDynamicTag(meta router.AddrMetadata) bool {
+	return meta.(*addrMetadata).ruleValid && meta.(*addrMetadata).ruleEnabled
+}
+
+// isTagRuleForce uses the snapshot data from the parsed rule to decide if dynamic tag rule is forced or not
+func isTagRuleForce(meta router.AddrMetadata) bool {
+	return meta.(*addrMetadata).ruleForce
 }
 
 // isForceUseTag returns whether force use tag
@@ -255,31 +324,46 @@
 	return false
 }
 
-type filter func(protocol.Invoker) bool
-
-func filterInvoker(invokers []protocol.Invoker, filters ...filter) []protocol.Invoker {
-	var res []protocol.Invoker
-OUTER:
-	for _, invoker := range invokers {
-		for _, filter := range filters {
-			if !filter(invoker) {
-				continue OUTER
-			}
+// addrsToBitmap finds indexes for the given IP addresses in the target URL list, if any '0.0.0.0' IP address is met,
+// then returns back all indexes of the URLs list.
+func addrsToBitmap(addrs []string, invokers []protocol.Invoker) *roaring.Bitmap {
+	ret := roaring.NewBitmap()
+	for _, addr := range addrs {
+		if isAnyHost(addr) {
+			ret.AddRange(0, uint64(len(invokers)))
+			return ret
 		}
-		res = append(res, invoker)
+
+		index := findIndexWithIp(addr, invokers)
+		if index != -1 {
+			ret.AddInt(index)
+		}
 	}
-	return res
+	return ret
 }
 
-func checkAddressMatch(addresses []string, host, port string) bool {
-	addr := net.JoinHostPort(constant.ANYHOST_VALUE, port)
-	for _, address := range addresses {
-		if gxnet.MatchIP(address, host, port) {
-			return true
-		}
-		if address == addr {
-			return true
+// findIndexWithIp finds index for one particular IP
+func findIndexWithIp(addr string, invokers []protocol.Invoker) int {
+	for i, invoker := range invokers {
+		if gxnet.MatchIP(addr, invoker.GetUrl().Ip, invoker.GetUrl().Port) {
+			return i
 		}
 	}
-	return false
+	return -1
+}
+
+// isAnyHost checks if an IP is '0.0.0.0'
+func isAnyHost(addr string) bool {
+	return strings.HasPrefix(addr, constant.ANYHOST_VALUE)
+}
+
+// findTag finds tag, first from invocation's attachment, then from URL
+func findTag(invocation protocol.Invocation, consumerUrl *common.URL) string {
+	tag, ok := invocation.Attachments()[constant.Tagkey]
+	if !ok {
+		return consumerUrl.GetParam(constant.Tagkey, "")
+	} else if v, t := tag.(string); t {
+		return v
+	}
+	return ""
 }
diff --git a/cluster/router/tag/tag_router_test.go b/cluster/router/tag/tag_router_test.go
index 6b9a5e0..3f7b979 100644
--- a/cluster/router/tag/tag_router_test.go
+++ b/cluster/router/tag/tag_router_test.go
@@ -25,15 +25,18 @@
 )
 
 import (
+	"github.com/RoaringBitmap/roaring"
 	"github.com/dubbogo/go-zookeeper/zk"
 	"github.com/stretchr/testify/assert"
 	"github.com/stretchr/testify/suite"
 )
 
 import (
+	"github.com/apache/dubbo-go/cluster/router"
+	"github.com/apache/dubbo-go/cluster/router/chain"
+	"github.com/apache/dubbo-go/cluster/router/utils"
 	"github.com/apache/dubbo-go/common"
 	"github.com/apache/dubbo-go/common/config"
-	"github.com/apache/dubbo-go/common/constant"
 	"github.com/apache/dubbo-go/common/extension"
 	"github.com/apache/dubbo-go/config_center"
 	_ "github.com/apache/dubbo-go/config_center/zookeeper"
@@ -76,13 +79,13 @@
 
 // MockInvoker is only mock the Invoker to support test tagRouter
 type MockInvoker struct {
-	url          common.URL
+	url          *common.URL
 	available    bool
 	destroyed    bool
 	successCount int
 }
 
-func NewMockInvoker(url common.URL) *MockInvoker {
+func NewMockInvoker(url *common.URL) *MockInvoker {
 	return &MockInvoker{
 		url:          url,
 		available:    true,
@@ -91,7 +94,7 @@
 	}
 }
 
-func (bi *MockInvoker) GetUrl() common.URL {
+func (bi *MockInvoker) GetUrl() *common.URL {
 	return bi.url
 }
 
@@ -118,7 +121,7 @@
 func TestTagRouterPriority(t *testing.T) {
 	u1, err := common.NewURL(tagRouterTestUserConsumerTag)
 	assert.Nil(t, err)
-	tagRouter, e := NewTagRouter(&u1)
+	tagRouter, e := NewTagRouter(u1)
 	assert.Nil(t, e)
 	p := tagRouter.Priority()
 	assert.Equal(t, int64(0), p)
@@ -127,7 +130,7 @@
 func TestTagRouterRouteForce(t *testing.T) {
 	u1, e1 := common.NewURL(tagRouterTestUserConsumerTag)
 	assert.Nil(t, e1)
-	tagRouter, e := NewTagRouter(&u1)
+	tagRouter, e := NewTagRouter(u1)
 	assert.Nil(t, e)
 
 	u2, e2 := common.NewURL(tagRouterTestHangZhouUrl)
@@ -143,23 +146,23 @@
 	invokers = append(invokers, inv2, inv3, inv4)
 	inv := &invocation.RPCInvocation{}
 	inv.SetAttachments(tagRouterTestDubboTag, tagRouterTestHangZhou)
-	invRst1 := tagRouter.Route(invokers, &u1, inv)
-	assert.Equal(t, 1, len(invRst1))
-	assert.Equal(t, tagRouterTestHangZhou, invRst1[0].GetUrl().GetParam(tagRouterTestDubboTag, ""))
+	invRst1 := tagRouter.Route(utils.ToBitmap(invokers), setUpAddrCache(tagRouter, invokers), u1, inv)
+	assert.Equal(t, 1, len(invRst1.ToArray()))
+	assert.Equal(t, tagRouterTestHangZhou, invokers[invRst1.ToArray()[0]].GetUrl().GetParam(tagRouterTestDubboTag, ""))
 
 	inv.SetAttachments(tagRouterTestDubboTag, tagRouterTestGuangZhou)
-	invRst2 := tagRouter.Route(invokers, &u1, inv)
-	assert.Equal(t, 0, len(invRst2))
+	invRst2 := tagRouter.Route(utils.ToBitmap(invokers), setUpAddrCache(tagRouter, invokers), u1, inv)
+	assert.Equal(t, 0, len(invRst2.ToArray()))
 	inv.SetAttachments(tagRouterTestDubboForceTag, tagRouterTestFalse)
 	inv.SetAttachments(tagRouterTestDubboTag, tagRouterTestGuangZhou)
-	invRst3 := tagRouter.Route(invokers, &u1, inv)
-	assert.Equal(t, 3, len(invRst3))
+	invRst3 := tagRouter.Route(utils.ToBitmap(invokers), setUpAddrCache(tagRouter, invokers), u1, inv)
+	assert.Equal(t, 3, len(invRst3.ToArray()))
 }
 
 func TestTagRouterRouteNoForce(t *testing.T) {
 	u1, e1 := common.NewURL(tagRouterTestUserConsumer)
 	assert.Nil(t, e1)
-	tagRouter, e := NewTagRouter(&u1)
+	tagRouter, e := NewTagRouter(u1)
 	assert.Nil(t, e)
 
 	u2, e2 := common.NewURL(tagRouterTestHangZhouUrl)
@@ -175,20 +178,37 @@
 	invokers = append(invokers, inv2, inv3, inv4)
 	inv := &invocation.RPCInvocation{}
 	inv.SetAttachments(tagRouterTestDubboTag, tagRouterTestHangZhou)
-	invRst := tagRouter.Route(invokers, &u1, inv)
-	assert.Equal(t, 1, len(invRst))
-	assert.Equal(t, tagRouterTestHangZhou, invRst[0].GetUrl().GetParam(tagRouterTestDubboTag, ""))
+	invRst := tagRouter.Route(utils.ToBitmap(invokers), setUpAddrCache(tagRouter, invokers), u1, inv)
+	assert.Equal(t, 1, len(invRst.ToArray()))
+	assert.Equal(t, tagRouterTestHangZhou, invokers[invRst.ToArray()[0]].GetUrl().GetParam(tagRouterTestDubboTag, ""))
 
 	inv.SetAttachments(tagRouterTestDubboTag, tagRouterTestGuangZhou)
 	inv.SetAttachments(tagRouterTestDubboForceTag, tagRouterTestTrue)
-	invRst1 := tagRouter.Route(invokers, &u1, inv)
-	assert.Equal(t, 0, len(invRst1))
+	invRst1 := tagRouter.Route(utils.ToBitmap(invokers), setUpAddrCache(tagRouter, invokers), u1, inv)
+	assert.Equal(t, 0, len(invRst1.ToArray()))
 	inv.SetAttachments(tagRouterTestDubboForceTag, tagRouterTestFalse)
-	invRst2 := tagRouter.Route(invokers, &u1, inv)
-	assert.Equal(t, 3, len(invRst2))
+	invRst2 := tagRouter.Route(utils.ToBitmap(invokers), setUpAddrCache(tagRouter, invokers), u1, inv)
+	assert.Equal(t, 3, len(invRst2.ToArray()))
 }
 
-func TestFilterInvoker(t *testing.T) {
+func setUpAddrCache(r router.Poolable, addrs []protocol.Invoker) router.Cache {
+	pool, info := r.Pool(addrs)
+	cache := chain.BuildCache(addrs)
+	cache.SetAddrPool(r.Name(), pool)
+	cache.SetAddrMeta(r.Name(), info)
+	return cache
+}
+
+func setUpAddrCacheWithRuleDisabled(r router.Poolable, addrs []protocol.Invoker) router.Cache {
+	pool, info := r.Pool(addrs)
+	info.(*addrMetadata).ruleEnabled = false
+	cache := chain.BuildCache(addrs)
+	cache.SetAddrPool(r.Name(), pool)
+	cache.SetAddrMeta(r.Name(), info)
+	return cache
+}
+
+func TestRouteBeijingInvoker(t *testing.T) {
 	u2, e2 := common.NewURL(tagRouterTestHangZhouUrl)
 	u3, e3 := common.NewURL(tagRouterTestShangHaiUrl)
 	u4, e4 := common.NewURL(tagRouterTestBeijingUrl)
@@ -203,23 +223,17 @@
 	inv5 := NewMockInvoker(u5)
 	var invokers []protocol.Invoker
 	invokers = append(invokers, inv2, inv3, inv4, inv5)
-	filterTag := func(invoker protocol.Invoker) bool {
-		if invoker.GetUrl().GetParam(constant.Tagkey, "") == "beijing" {
-			return true
-		}
-		return false
-	}
-	res := filterInvoker(invokers, filterTag)
-	assert.Equal(t, []protocol.Invoker{inv4, inv5}, res)
-	flag := true
-	filterEnabled := func(invoker protocol.Invoker) bool {
-		if invoker.GetUrl().GetParamBool(constant.RouterEnabled, false) == flag {
-			return true
-		}
-		return false
-	}
-	res2 := filterInvoker(invokers, filterTag, filterEnabled)
-	assert.Equal(t, []protocol.Invoker{inv4}, res2)
+
+	url, _ := common.NewURL(tagRouterTestBeijingUrl)
+	tagRouter, _ := NewTagRouter(url)
+
+	rb := roaring.NewBitmap()
+	rb.AddRange(0, uint64(len(invokers)))
+	cache := setUpAddrCache(tagRouter, invokers)
+	inv := &invocation.RPCInvocation{}
+	res := tagRouter.Route(rb, cache, url, inv)
+	// inv4 and inv5
+	assert.Equal(t, []uint32{2, 3}, res.ToArray())
 }
 
 type DynamicTagRouter struct {
@@ -278,7 +292,7 @@
 	suite.NoError(err)
 
 	zkUrl, _ := common.NewURL(fmt.Sprintf(zkFormat, routerLocalIP, suite.testCluster.Servers[0].Port))
-	configuration, err := extension.GetConfigCenterFactory(routerZk).GetDynamicConfiguration(&zkUrl)
+	configuration, err := extension.GetConfigCenterFactory(routerZk).GetDynamicConfiguration(zkUrl)
 	config.GetEnvInstance().SetDynamicConfiguration(configuration)
 
 	suite.Nil(err)
@@ -287,11 +301,11 @@
 	url, e1 := common.NewURL(tagRouterTestUserConsumerTag)
 	suite.Nil(e1)
 
-	tagRouter, err := NewTagRouter(&url)
+	tagRouter, err := NewTagRouter(url)
 	suite.Nil(err)
 	suite.NotNil(tagRouter)
 	suite.route = tagRouter
-	suite.url = &url
+	suite.url = url
 }
 
 func (suite *DynamicTagRouter) TearDownTest() {
@@ -301,50 +315,57 @@
 
 func (suite *DynamicTagRouter) TestDynamicTagRouterSetByIPv4() {
 	invokers := suite.invokers
-	suite.route.Notify(invokers)
+	rb := roaring.NewBitmap()
+	rb.AddRange(0, uint64(len(invokers)))
+	cache := setUpAddrCache(suite.route, invokers)
 	suite.NotNil(suite.route.tagRouterRule)
 
 	consumer := &invocation.RPCInvocation{}
 	consumer.SetAttachments(tagRouterTestDubboTag, "tag1")
-	targetInvokers := suite.route.Route(invokers, suite.url, consumer)
-	suite.Equal(1, len(targetInvokers))
-	suite.Equal(targetInvokers[0], suite.invokers[0])
+	targetInvokers := suite.route.Route(rb, cache, suite.url, consumer)
+	suite.Equal(uint64(1), targetInvokers.GetCardinality())
+	suite.Equal(targetInvokers.ToArray()[0], uint32(0))
 
 	consumer.SetAttachments(tagRouterTestDubboTag, "tag3")
-	targetInvokers = suite.route.Route(invokers, suite.url, consumer)
-	suite.Equal(2, len(targetInvokers))
-	suite.Equal(targetInvokers, []protocol.Invoker{suite.invokers[2], suite.invokers[3]})
+	targetInvokers = suite.route.Route(rb, cache, suite.url, consumer)
+	suite.Equal(uint64(2), targetInvokers.GetCardinality())
+	suite.True(targetInvokers.Contains(2) && targetInvokers.Contains(3))
 }
 
 func (suite *DynamicTagRouter) TestDynamicTagRouterStaticTag() {
 	invokers := suite.invokers
+	rb := roaring.NewBitmap()
+	rb.AddRange(0, uint64(len(invokers)))
+	cache := setUpAddrCacheWithRuleDisabled(suite.route, invokers)
 	consumer := &invocation.RPCInvocation{}
 	consumer.SetAttachments(tagRouterTestDubboTag, "tag4")
-	targetInvokers := suite.route.Route(invokers, suite.url, consumer)
-	suite.Equal(1, len(targetInvokers))
-	suite.Equal(targetInvokers[0], suite.invokers[3])
+	targetInvokers := suite.route.Route(rb, cache, suite.url, consumer)
+	suite.Equal(uint64(1), targetInvokers.GetCardinality())
+	suite.Equal(targetInvokers.ToArray()[0], uint32(3))
 }
 
 // Teas no tag and return a address are not in dynamic tag group
 func (suite *DynamicTagRouter) TestDynamicTagRouterByNoTagAndAddressMatch() {
 	invokers := suite.invokers
-	suite.route.Notify(invokers)
+	rb := roaring.NewBitmap()
+	rb.AddRange(0, uint64(len(invokers)))
+	cache := setUpAddrCache(suite.route, invokers)
 	suite.NotNil(suite.route.tagRouterRule)
 	consumer := &invocation.RPCInvocation{}
-	targetInvokers := suite.route.Route(invokers, suite.url, consumer)
-	suite.Equal(1, len(targetInvokers))
-	suite.Equal(targetInvokers[0], suite.invokers[4])
+	targetInvokers := suite.route.Route(rb, cache, suite.url, consumer)
+	suite.Equal(uint64(1), targetInvokers.GetCardinality())
+	suite.Equal(targetInvokers.ToArray()[0], uint32(4))
 	// test if there are some addresses that are not in any dynamic tag group, continue to filter using the static tag group.
 	consumer.SetAttachments(tagRouterTestDubboTag, "tag5")
-	targetInvokers = suite.route.Route(invokers, suite.url, consumer)
-	suite.Equal(1, len(targetInvokers))
-	suite.Equal(targetInvokers[0], suite.invokers[4])
+	targetInvokers = suite.route.Route(rb, cache, suite.url, consumer)
+	suite.Equal(uint64(1), targetInvokers.GetCardinality())
+	suite.Equal(targetInvokers.ToArray()[0], uint32(4))
 }
 
 func TestProcess(t *testing.T) {
 	u1, err := common.NewURL(tagRouterTestUserConsumerTag)
 	assert.Nil(t, err)
-	tagRouter, e := NewTagRouter(&u1)
+	tagRouter, e := NewTagRouter(u1)
 	assert.Nil(t, e)
 	assert.NotNil(t, tagRouter)
 
diff --git a/cluster/router/utils/bitmap_util.go b/cluster/router/utils/bitmap_util.go
new file mode 100644
index 0000000..8b4ee55
--- /dev/null
+++ b/cluster/router/utils/bitmap_util.go
@@ -0,0 +1,50 @@
+/*
+ * 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 utils
+
+import (
+	"github.com/RoaringBitmap/roaring"
+)
+
+import (
+	"github.com/apache/dubbo-go/protocol"
+)
+
+var EmptyAddr = roaring.NewBitmap()
+
+func JoinIfNotEqual(left *roaring.Bitmap, right *roaring.Bitmap) *roaring.Bitmap {
+	if !left.Equals(right) {
+		left = left.Clone()
+		left.And(right)
+	}
+	return left
+}
+
+func FallbackIfJoinToEmpty(left *roaring.Bitmap, right *roaring.Bitmap) *roaring.Bitmap {
+	ret := JoinIfNotEqual(left, right)
+	if ret == nil || ret.IsEmpty() {
+		return right
+	}
+	return ret
+}
+
+func ToBitmap(invokers []protocol.Invoker) *roaring.Bitmap {
+	bitmap := roaring.NewBitmap()
+	bitmap.AddRange(0, uint64(len(invokers)))
+	return bitmap
+}
diff --git a/common/constant/key.go b/common/constant/key.go
index 943338f..9525511 100644
--- a/common/constant/key.go
+++ b/common/constant/key.go
@@ -25,6 +25,7 @@
 	GROUP_KEY                = "group"
 	VERSION_KEY              = "version"
 	INTERFACE_KEY            = "interface"
+	MESSAGE_SIZE_KEY         = "message_size"
 	PATH_KEY                 = "path"
 	SERVICE_KEY              = "service"
 	METHODS_KEY              = "methods"
diff --git a/cluster/router/chan.go b/common/host_util.go
similarity index 69%
copy from cluster/router/chan.go
copy to common/host_util.go
index e3e84b8..9861c92 100644
--- a/cluster/router/chan.go
+++ b/common/host_util.go
@@ -15,18 +15,16 @@
  * limitations under the License.
  */
 
-package router
+package common
 
-import (
-	"github.com/apache/dubbo-go/protocol"
-)
+import gxnet "github.com/dubbogo/gost/net"
 
-// Chain
-type Chain interface {
-	router
-	// AddRouters Add routers
-	AddRouters([]PriorityRouter)
+var localIp string
 
-	// SetInvokers notify router chain of the initial addresses from registry at the first time. Notify whenever addresses in registry change.
-	SetInvokers(invokers []protocol.Invoker)
+func GetLocalIp() string {
+	if len(localIp) != 0 {
+		return localIp
+	}
+	localIp, _ = gxnet.GetLocalIP()
+	return localIp
 }
diff --git a/cluster/router/chan.go b/common/host_util_test.go
similarity index 70%
copy from cluster/router/chan.go
copy to common/host_util_test.go
index e3e84b8..ad96dde 100644
--- a/cluster/router/chan.go
+++ b/common/host_util_test.go
@@ -15,18 +15,16 @@
  * limitations under the License.
  */
 
-package router
+package common
 
 import (
-	"github.com/apache/dubbo-go/protocol"
+	"testing"
 )
 
-// Chain
-type Chain interface {
-	router
-	// AddRouters Add routers
-	AddRouters([]PriorityRouter)
+import (
+	"github.com/stretchr/testify/assert"
+)
 
-	// SetInvokers notify router chain of the initial addresses from registry at the first time. Notify whenever addresses in registry change.
-	SetInvokers(invokers []protocol.Invoker)
+func TestGetLocalIp(t *testing.T) {
+	assert.NotNil(t, GetLocalIp())
 }
diff --git a/common/node.go b/common/node.go
index 4febd78..b9c1f39 100644
--- a/common/node.go
+++ b/common/node.go
@@ -19,7 +19,7 @@
 
 // Node use for process dubbo node
 type Node interface {
-	GetUrl() URL
+	GetUrl() *URL
 	IsAvailable() bool
 	Destroy()
 }
diff --git a/common/proxy/proxy_factory.go b/common/proxy/proxy_factory.go
index 117428c..2e66c34 100644
--- a/common/proxy/proxy_factory.go
+++ b/common/proxy/proxy_factory.go
@@ -26,7 +26,7 @@
 type ProxyFactory interface {
 	GetProxy(invoker protocol.Invoker, url *common.URL) *Proxy
 	GetAsyncProxy(invoker protocol.Invoker, callBack interface{}, url *common.URL) *Proxy
-	GetInvoker(url common.URL) protocol.Invoker
+	GetInvoker(url *common.URL) protocol.Invoker
 }
 
 // Option will define a function of handling ProxyFactory
diff --git a/common/proxy/proxy_factory/default.go b/common/proxy/proxy_factory/default.go
index 752f3ea..067c077 100644
--- a/common/proxy/proxy_factory/default.go
+++ b/common/proxy/proxy_factory/default.go
@@ -72,7 +72,7 @@
 }
 
 // GetInvoker gets a invoker
-func (factory *DefaultProxyFactory) GetInvoker(url common.URL) protocol.Invoker {
+func (factory *DefaultProxyFactory) GetInvoker(url *common.URL) protocol.Invoker {
 	return &ProxyInvoker{
 		BaseInvoker: *protocol.NewBaseInvoker(url),
 	}
@@ -88,9 +88,8 @@
 	result := &protocol.RPCResult{}
 	result.SetAttachments(invocation.Attachments())
 
-	url := pi.GetUrl()
 	//get providerUrl. The origin url may be is registry URL.
-	url = *getProviderURL(&url)
+	url := getProviderURL(pi.GetUrl())
 
 	methodName := invocation.MethodName()
 	proto := url.Protocol
diff --git a/common/proxy/proxy_factory/default_test.go b/common/proxy/proxy_factory/default_test.go
index 99d5c02..4002ab9 100644
--- a/common/proxy/proxy_factory/default_test.go
+++ b/common/proxy/proxy_factory/default_test.go
@@ -34,7 +34,7 @@
 func TestGetProxy(t *testing.T) {
 	proxyFactory := NewDefaultProxyFactory()
 	url := common.NewURLWithOptions()
-	proxy := proxyFactory.GetProxy(protocol.NewBaseInvoker(*url), url)
+	proxy := proxyFactory.GetProxy(protocol.NewBaseInvoker(url), url)
 	assert.NotNil(t, proxy)
 }
 
@@ -49,13 +49,13 @@
 	proxyFactory := NewDefaultProxyFactory()
 	url := common.NewURLWithOptions()
 	async := &TestAsync{}
-	proxy := proxyFactory.GetAsyncProxy(protocol.NewBaseInvoker(*url), async.CallBack, url)
+	proxy := proxyFactory.GetAsyncProxy(protocol.NewBaseInvoker(url), async.CallBack, url)
 	assert.NotNil(t, proxy)
 }
 
 func TestGetInvoker(t *testing.T) {
 	proxyFactory := NewDefaultProxyFactory()
 	url := common.NewURLWithOptions()
-	invoker := proxyFactory.GetInvoker(*url)
+	invoker := proxyFactory.GetInvoker(url)
 	assert.True(t, invoker.IsAvailable())
 }
diff --git a/common/proxy/proxy_test.go b/common/proxy/proxy_test.go
index c606615..c6f6596 100644
--- a/common/proxy/proxy_test.go
+++ b/common/proxy/proxy_test.go
@@ -24,7 +24,6 @@
 )
 
 import (
-	"github.com/apache/dubbo-go/protocol/invocation"
 	perrors "github.com/pkg/errors"
 	"github.com/stretchr/testify/assert"
 )
@@ -34,6 +33,7 @@
 	"github.com/apache/dubbo-go/common/constant"
 	"github.com/apache/dubbo-go/protocol"
 	"github.com/apache/dubbo-go/protocol/dubbo/hessian2"
+	"github.com/apache/dubbo-go/protocol/invocation"
 )
 
 type TestService struct {
@@ -58,7 +58,7 @@
 
 func TestProxyImplement(t *testing.T) {
 
-	invoker := protocol.NewBaseInvoker(common.URL{})
+	invoker := protocol.NewBaseInvoker(&common.URL{})
 	p := NewProxy(invoker, nil, map[string]string{constant.ASYNC_KEY: "false"})
 	s := &TestService{}
 	p.Implement(s)
@@ -126,7 +126,7 @@
 
 func TestProxyImplementForContext(t *testing.T) {
 	invoker := &TestProxyInvoker{
-		BaseInvoker: *protocol.NewBaseInvoker(common.URL{}),
+		BaseInvoker: *protocol.NewBaseInvoker(&common.URL{}),
 	}
 	p := NewProxy(invoker, nil, map[string]string{constant.ASYNC_KEY: "false"})
 	s := &TestService{}
diff --git a/common/url.go b/common/url.go
index 5a3e574..d8f096b 100644
--- a/common/url.go
+++ b/common/url.go
@@ -21,11 +21,13 @@
 	"bytes"
 	"encoding/base64"
 	"fmt"
+	cm "github.com/Workiva/go-datastructures/common"
 	"math"
 	"net"
 	"net/url"
 	"strconv"
 	"strings"
+	"sync"
 )
 
 import (
@@ -77,20 +79,35 @@
 }
 
 type baseUrl struct {
-	Protocol     string
-	Location     string // ip+port
-	Ip           string
-	Port         string
+	Protocol string
+	Location string // ip+port
+	Ip       string
+	Port     string
+	//url.Values is not safe map, add to avoid concurrent map read and map write error
+	paramsLock   sync.RWMutex
 	params       url.Values
 	PrimitiveURL string
 }
 
-// URL is not thread-safe.
+// noCopy may be embedded into structs which must not be copied
+// after the first use.
+//
+// See https://golang.org/issues/8005#issuecomment-190753527
+// for details.
+type noCopy struct{}
+
+// Lock is a no-op used by -copylocks checker from `go vet`.
+func (*noCopy) Lock()   {}
+func (*noCopy) Unlock() {}
+
+// URL thread-safe. but this url should not be copied.
 // we fail to define this struct to be immutable object.
 // but, those method which will update the URL, including SetParam, SetParams
 // are only allowed to be invoked in creating URL instance
 // Please keep in mind that this struct is immutable after it has been created and initialized.
 type URL struct {
+	noCopy noCopy
+
 	baseUrl
 	Path     string // like  /com.ikurento.dubbo.UserProvider3
 	Username string
@@ -102,80 +119,80 @@
 
 // Option accepts url
 // Option will define a function of handling URL
-type option func(*URL)
+type Option func(*URL)
 
 // WithUsername sets username for url
-func WithUsername(username string) option {
+func WithUsername(username string) Option {
 	return func(url *URL) {
 		url.Username = username
 	}
 }
 
 // WithPassword sets password for url
-func WithPassword(pwd string) option {
+func WithPassword(pwd string) Option {
 	return func(url *URL) {
 		url.Password = pwd
 	}
 }
 
 // WithMethods sets methods for url
-func WithMethods(methods []string) option {
+func WithMethods(methods []string) Option {
 	return func(url *URL) {
 		url.Methods = methods
 	}
 }
 
 // WithParams sets params for url
-func WithParams(params url.Values) option {
+func WithParams(params url.Values) Option {
 	return func(url *URL) {
 		url.params = params
 	}
 }
 
 // WithParamsValue sets params field for url
-func WithParamsValue(key, val string) option {
+func WithParamsValue(key, val string) Option {
 	return func(url *URL) {
 		url.SetParam(key, val)
 	}
 }
 
 // WithProtocol sets protocol for url
-func WithProtocol(proto string) option {
+func WithProtocol(proto string) Option {
 	return func(url *URL) {
 		url.Protocol = proto
 	}
 }
 
 // WithIp sets ip for url
-func WithIp(ip string) option {
+func WithIp(ip string) Option {
 	return func(url *URL) {
 		url.Ip = ip
 	}
 }
 
 // WithPort sets port for url
-func WithPort(port string) option {
+func WithPort(port string) Option {
 	return func(url *URL) {
 		url.Port = port
 	}
 }
 
 // WithPath sets path for url
-func WithPath(path string) option {
+func WithPath(path string) Option {
 	return func(url *URL) {
 		url.Path = "/" + strings.TrimPrefix(path, "/")
 	}
 }
 
 // WithLocation sets location for url
-func WithLocation(location string) option {
+func WithLocation(location string) Option {
 	return func(url *URL) {
 		url.Location = location
 	}
 }
 
 // WithToken sets token for url
-func WithToken(token string) option {
+func WithToken(token string) Option {
 	return func(url *URL) {
 		if len(token) > 0 {
 			value := token
@@ -193,33 +210,26 @@
 }
 
 // NewURLWithOptions will create a new url with options
-func NewURLWithOptions(opts ...option) *URL {
-	url := &URL{}
+func NewURLWithOptions(opts ...Option) *URL {
+	newUrl := &URL{}
 	for _, opt := range opts {
-		opt(url)
+		opt(newUrl)
 	}
-	url.Location = url.Ip + ":" + url.Port
-	return url
+	newUrl.Location = newUrl.Ip + ":" + newUrl.Port
+	return newUrl
 }
 
 // NewURL will create a new url
 // the urlString should not be empty
-func NewURL(urlString string, opts ...option) (URL, error) {
-	var (
-		err          error
-		rawUrlString string
-		serviceUrl   *url.URL
-		s            = URL{baseUrl: baseUrl{}}
-	)
-
-	// new a null instance
+func NewURL(urlString string, opts ...Option) (*URL, error) {
+	s := URL{baseUrl: baseUrl{}}
 	if urlString == "" {
-		return s, nil
+		return &s, nil
 	}
 
-	rawUrlString, err = url.QueryUnescape(urlString)
+	rawUrlString, err := url.QueryUnescape(urlString)
 	if err != nil {
-		return s, perrors.Errorf("url.QueryUnescape(%s),  error{%v}", urlString, err)
+		return &s, perrors.Errorf("url.QueryUnescape(%s),  error{%v}", urlString, err)
 	}
 
 	// rawUrlString = "//" + rawUrlString
@@ -230,14 +240,15 @@
 		}
 		rawUrlString = t.Protocol + "://" + rawUrlString
 	}
-	serviceUrl, err = url.Parse(rawUrlString)
-	if err != nil {
-		return s, perrors.Errorf("url.Parse(url string{%s}),  error{%v}", rawUrlString, err)
+
+	serviceUrl, urlParseErr := url.Parse(rawUrlString)
+	if urlParseErr != nil {
+		return &s, perrors.Errorf("url.Parse(url string{%s}),  error{%v}", rawUrlString, err)
 	}
 
 	s.params, err = url.ParseQuery(serviceUrl.RawQuery)
 	if err != nil {
-		return s, perrors.Errorf("url.ParseQuery(raw url string{%s}),  error{%v}", serviceUrl.RawQuery, err)
+		return &s, perrors.Errorf("url.ParseQuery(raw url string{%s}),  error{%v}", serviceUrl.RawQuery, err)
 	}
 
 	s.PrimitiveURL = urlString
@@ -249,25 +260,29 @@
 	if strings.Contains(s.Location, ":") {
 		s.Ip, s.Port, err = net.SplitHostPort(s.Location)
 		if err != nil {
-			return s, perrors.Errorf("net.SplitHostPort(url.Host{%s}), error{%v}", s.Location, err)
+			return &s, perrors.Errorf("net.SplitHostPort(url.Host{%s}), error{%v}", s.Location, err)
 		}
 	}
 	for _, opt := range opts {
 		opt(&s)
 	}
-	return s, nil
+	return &s, nil
 }
 
 // URLEqual judge @url and @c is equal or not.
-func (c URL) URLEqual(url URL) bool {
-	c.Ip = ""
-	c.Port = ""
-	url.Ip = ""
-	url.Port = ""
-	cGroup := c.GetParam(constant.GROUP_KEY, "")
-	urlGroup := url.GetParam(constant.GROUP_KEY, "")
-	cKey := c.Key()
-	urlKey := url.Key()
+func (c *URL) URLEqual(url *URL) bool {
+	tmpC := c.Clone()
+	tmpC.Ip = ""
+	tmpC.Port = ""
+
+	tmpUrl := url.Clone()
+	tmpUrl.Ip = ""
+	tmpUrl.Port = ""
+
+	cGroup := tmpC.GetParam(constant.GROUP_KEY, "")
+	urlGroup := tmpUrl.GetParam(constant.GROUP_KEY, "")
+	cKey := tmpC.Key()
+	urlKey := tmpUrl.Key()
 
 	if cGroup == constant.ANY_VALUE {
 		cKey = strings.Replace(cKey, "group=*", "group="+urlGroup, 1)
@@ -281,12 +296,12 @@
 	}
 
 	// 2. if url contains enabled key, should be true, or *
-	if url.GetParam(constant.ENABLED_KEY, "true") != "true" && url.GetParam(constant.ENABLED_KEY, "") != constant.ANY_VALUE {
+	if tmpUrl.GetParam(constant.ENABLED_KEY, "true") != "true" && tmpUrl.GetParam(constant.ENABLED_KEY, "") != constant.ANY_VALUE {
 		return false
 	}
 
 	// TODO :may need add interface key any value condition
-	return isMatchCategory(url.GetParam(constant.CATEGORY_KEY, constant.DEFAULT_CATEGORY), c.GetParam(constant.CATEGORY_KEY, constant.DEFAULT_CATEGORY))
+	return isMatchCategory(tmpUrl.GetParam(constant.CATEGORY_KEY, constant.DEFAULT_CATEGORY), tmpC.GetParam(constant.CATEGORY_KEY, constant.DEFAULT_CATEGORY))
 }
 
 func isMatchCategory(category1 string, category2 string) bool {
@@ -301,31 +316,26 @@
 	}
 }
 
-func (c URL) String() string {
+func (c *URL) String() string {
 	var buf strings.Builder
 	if len(c.Username) == 0 && len(c.Password) == 0 {
-		buf.WriteString(fmt.Sprintf(
-			"%s://%s:%s%s?",
-			c.Protocol, c.Ip, c.Port, c.Path))
+		buf.WriteString(fmt.Sprintf("%s://%s:%s%s?", c.Protocol, c.Ip, c.Port, c.Path))
 	} else {
-		buf.WriteString(fmt.Sprintf(
-			"%s://%s:%s@%s:%s%s?",
-			c.Protocol, c.Username, c.Password, c.Ip, c.Port, c.Path))
+		buf.WriteString(fmt.Sprintf("%s://%s:%s@%s:%s%s?", c.Protocol, c.Username, c.Password, c.Ip, c.Port, c.Path))
 	}
 	buf.WriteString(c.params.Encode())
 	return buf.String()
 }
 
 // Key gets key
-func (c URL) Key() string {
-	buildString := fmt.Sprintf(
-		"%s://%s:%s@%s:%s/?interface=%s&group=%s&version=%s",
+func (c *URL) Key() string {
+	buildString := fmt.Sprintf("%s://%s:%s@%s:%s/?interface=%s&group=%s&version=%s",
 		c.Protocol, c.Username, c.Password, c.Ip, c.Port, c.Service(), c.GetParam(constant.GROUP_KEY, ""), c.GetParam(constant.VERSION_KEY, ""))
 	return buildString
 }
 
 // ServiceKey gets a unique key of a service.
-func (c URL) ServiceKey() string {
+func (c *URL) ServiceKey() string {
 	return ServiceKey(c.GetParam(constant.INTERFACE_KEY, strings.TrimPrefix(c.Path, "/")),
 		c.GetParam(constant.GROUP_KEY, ""), c.GetParam(constant.VERSION_KEY, ""))
 }
@@ -379,7 +389,7 @@
 }
 
 // Service gets service
-func (c URL) Service() string {
+func (c *URL) Service() string {
 	service := c.GetParam(constant.INTERFACE_KEY, strings.TrimPrefix(c.Path, "/"))
 	if service != "" {
 		return service
@@ -393,34 +403,34 @@
 }
 
 // AddParam will add the key-value pair
-// Not thread-safe
-// think twice before using it.
 func (c *URL) AddParam(key string, value string) {
+	c.paramsLock.Lock()
+	defer c.paramsLock.Unlock()
 	c.params.Add(key, value)
 }
 
 // AddParamAvoidNil will add key-value pair
-// Not thread-safe
-// think twice before using it.
 func (c *URL) AddParamAvoidNil(key string, value string) {
+	c.paramsLock.Lock()
+	defer c.paramsLock.Unlock()
 	if c.params == nil {
 		c.params = url.Values{}
 	}
-
 	c.params.Add(key, value)
 }
 
 // SetParam will put the key-value pair into url
-// it's not thread safe.
-// think twice before you want to use this method
 // usually it should only be invoked when you want to initialized an url
 func (c *URL) SetParam(key string, value string) {
+	c.paramsLock.Lock()
+	defer c.paramsLock.Unlock()
 	c.params.Set(key, value)
 }
 
 // RangeParams will iterate the params
-// it's not thread-safe
 func (c *URL) RangeParams(f func(key, value string) bool) {
+	c.paramsLock.RLock()
+	defer c.paramsLock.RUnlock()
 	for k, v := range c.params {
 		if !f(k, v[0]) {
 			break
@@ -429,7 +439,9 @@
 }
 
 // GetParam gets value by key
-func (c URL) GetParam(s string, d string) string {
+func (c *URL) GetParam(s string, d string) string {
+	c.paramsLock.RLock()
+	defer c.paramsLock.RUnlock()
 	r := c.params.Get(s)
 	if len(r) == 0 {
 		r = d
@@ -438,19 +450,19 @@
 }
 
 // GetParams gets values
-func (c URL) GetParams() url.Values {
+func (c *URL) GetParams() url.Values {
 	return c.params
 }
 
 // GetParamAndDecoded gets values and decode
-func (c URL) GetParamAndDecoded(key string) (string, error) {
+func (c *URL) GetParamAndDecoded(key string) (string, error) {
 	ruleDec, err := base64.URLEncoding.DecodeString(c.GetParam(key, ""))
 	value := string(ruleDec)
 	return value, err
 }
 
 // GetRawParam gets raw param
-func (c URL) GetRawParam(key string) string {
+func (c *URL) GetRawParam(key string) string {
 	switch key {
 	case PROTOCOL:
 		return c.Protocol
@@ -470,7 +482,7 @@
 }
 
 // GetParamBool judge whether @key exists or not
-func (c URL) GetParamBool(key string, d bool) bool {
+func (c *URL) GetParamBool(key string, d bool) bool {
 	r, err := strconv.ParseBool(c.GetParam(key, ""))
 	if err != nil {
 		return d
@@ -478,26 +490,53 @@
 	return r
 }
 
-// GetParamInt gets int value by @key
-func (c URL) GetParamInt(key string, d int64) int64 {
-	r, err := strconv.Atoi(c.GetParam(key, ""))
-	if r == 0 || err != nil {
+// GetParamInt gets int64 value by @key
+func (c *URL) GetParamInt(key string, d int64) int64 {
+	r, err := strconv.ParseInt(c.GetParam(key, ""), 10, 64)
+	if err != nil {
 		return d
 	}
-	return int64(r)
+	return r
+}
+
+// GetParamInt32 gets int32 value by @key
+func (c *URL) GetParamInt32(key string, d int32) int32 {
+	r, err := strconv.ParseInt(c.GetParam(key, ""), 10, 32)
+	if err != nil {
+		return d
+	}
+	return int32(r)
+}
+
+// GetParamByIntValue gets int value by @key
+func (c *URL) GetParamByIntValue(key string, d int) int {
+	r, err := strconv.ParseInt(c.GetParam(key, ""), 10, 0)
+	if err != nil {
+		return d
+	}
+	return int(r)
 }
 
 // GetMethodParamInt gets int method param
-func (c URL) GetMethodParamInt(method string, key string, d int64) int64 {
-	r, err := strconv.Atoi(c.GetParam("methods."+method+"."+key, ""))
-	if r == 0 || err != nil {
+func (c *URL) GetMethodParamInt(method string, key string, d int64) int64 {
+	r, err := strconv.ParseInt(c.GetParam("methods."+method+"."+key, ""), 10, 64)
+	if err != nil {
 		return d
 	}
-	return int64(r)
+	return r
+}
+
+// GetMethodParamIntValue gets int method param
+func (c *URL) GetMethodParamIntValue(method string, key string, d int) int {
+	r, err := strconv.ParseInt(c.GetParam("methods."+method+"."+key, ""), 10, 0)
+	if err != nil {
+		return d
+	}
+	return int(r)
 }
 
 // GetMethodParamInt64 gets int64 method param
-func (c URL) GetMethodParamInt64(method string, key string, d int64) int64 {
+func (c *URL) GetMethodParamInt64(method string, key string, d int64) int64 {
 	r := c.GetMethodParamInt(method, key, math.MinInt64)
 	if r == math.MinInt64 {
 		return c.GetParamInt(key, d)
@@ -506,7 +545,7 @@
 }
 
 // GetMethodParam gets method param
-func (c URL) GetMethodParam(method string, key string, d string) string {
+func (c *URL) GetMethodParam(method string, key string, d string) string {
 	r := c.GetParam("methods."+method+"."+key, "")
 	if r == "" {
 		r = d
@@ -515,7 +554,7 @@
 }
 
 // GetMethodParamBool judge whether @method param exists or not
-func (c URL) GetMethodParamBool(method string, key string, d bool) bool {
+func (c *URL) GetMethodParamBool(method string, key string, d bool) bool {
 	r := c.GetParamBool("methods."+method+"."+key, d)
 	return r
 }
@@ -531,7 +570,7 @@
 }
 
 // ToMap transfer URL to Map
-func (c URL) ToMap() map[string]string {
+func (c *URL) ToMap() map[string]string {
 	paramsMap := make(map[string]string)
 
 	c.RangeParams(func(key, value string) bool {
@@ -635,6 +674,19 @@
 	return newUrl
 }
 
+func (c *URL) Compare(comp cm.Comparator) int {
+	a := c.String()
+	b := comp.(*URL).String()
+	switch {
+	case a > b:
+		return 1
+	case a < b:
+		return -1
+	default:
+		return 0
+	}
+}
+
 // Copy url based on the reserved parameter's keys.
 func (c *URL) CloneWithParams(reserveParams []string) *URL {
 	params := url.Values{}
@@ -658,7 +710,7 @@
 }
 
 // IsEquals compares if two URLs equals with each other. Excludes are all parameter keys which should ignored.
-func IsEquals(left URL, right URL, excludes ...string) bool {
+func IsEquals(left *URL, right *URL, excludes ...string) bool {
 	if left.Ip != right.Ip || left.Port != right.Port {
 		return false
 	}
@@ -702,7 +754,7 @@
 
 // URLSlice will be used to sort URL instance
 // Instances will be order by URL.String()
-type URLSlice []URL
+type URLSlice []*URL
 
 // nolint
 func (s URLSlice) Len() int {
diff --git a/common/url_test.go b/common/url_test.go
index 6845190..05377c1 100644
--- a/common/url_test.go
+++ b/common/url_test.go
@@ -167,10 +167,22 @@
 
 func TestURLGetParamInt(t *testing.T) {
 	params := url.Values{}
-	params.Set("key", "3")
+	params.Set("key", "")
 	u := URL{baseUrl: baseUrl{params: params}}
 	v := u.GetParamInt("key", 1)
-	assert.Equal(t, int64(3), v)
+	assert.Equal(t, int64(1), v)
+
+	u = URL{}
+	v = u.GetParamInt("key", 1)
+	assert.Equal(t, int64(1), v)
+}
+
+func TestURLGetParamIntValue(t *testing.T) {
+	params := url.Values{}
+	params.Set("key", "0")
+	u := URL{baseUrl: baseUrl{params: params}}
+	v := u.GetParamInt("key", 1)
+	assert.Equal(t, int64(0), v)
 
 	u = URL{}
 	v = u.GetParamInt("key", 1)
@@ -277,7 +289,7 @@
 	referenceUrl, _ := NewURL("mock1://127.0.0.1:1111", WithParams(referenceUrlParams), WithMethods([]string{"testMethod"}))
 	serviceUrl, _ := NewURL("mock2://127.0.0.1:20000", WithParams(serviceUrlParams))
 
-	mergedUrl := MergeUrl(&serviceUrl, &referenceUrl)
+	mergedUrl := MergeUrl(serviceUrl, referenceUrl)
 	assert.Equal(t, "random", mergedUrl.GetParam(constant.CLUSTER_KEY, ""))
 	assert.Equal(t, "1", mergedUrl.GetParam("test2", ""))
 	assert.Equal(t, "1", mergedUrl.GetParam("test3", ""))
diff --git a/config/config_center_config.go b/config/config_center_config.go
index 0fc4007..752d9d4 100644
--- a/config/config_center_config.go
+++ b/config/config_center_config.go
@@ -91,7 +91,7 @@
 
 // toURL will compatible with baseConfig.ConfigCenterConfig.Address and baseConfig.ConfigCenterConfig.RemoteRef before 1.6.0
 // After 1.6.0 will not compatible, only baseConfig.ConfigCenterConfig.RemoteRef
-func (b *configCenter) toURL(baseConfig BaseConfig) (common.URL, error) {
+func (b *configCenter) toURL(baseConfig BaseConfig) (*common.URL, error) {
 	if len(baseConfig.ConfigCenterConfig.Address) > 0 {
 		return common.NewURL(baseConfig.ConfigCenterConfig.Address,
 			common.WithProtocol(baseConfig.ConfigCenterConfig.Protocol), common.WithParams(baseConfig.ConfigCenterConfig.GetUrlMap()))
@@ -101,7 +101,7 @@
 	rc, ok := baseConfig.GetRemoteConfig(remoteRef)
 
 	if !ok {
-		return common.URL{}, perrors.New("Could not find out the remote ref config, name: " + remoteRef)
+		return nil, perrors.New("Could not find out the remote ref config, name: " + remoteRef)
 	}
 
 	newURL, err := rc.toURL()
@@ -114,11 +114,11 @@
 // startConfigCenter will start the config center.
 // it will prepare the environment
 func (b *configCenter) startConfigCenter(baseConfig BaseConfig) error {
-	url, err := b.toURL(baseConfig)
+	newUrl, err := b.toURL(baseConfig)
 	if err != nil {
 		return err
 	}
-	if err = b.prepareEnvironment(baseConfig, &url); err != nil {
+	if err = b.prepareEnvironment(baseConfig, newUrl); err != nil {
 		return perrors.WithMessagef(err, "start config center error!")
 	}
 	// c.fresh()
diff --git a/config/config_loader.go b/config/config_loader.go
index c66e526..ec591aa 100644
--- a/config/config_loader.go
+++ b/config/config_loader.go
@@ -28,7 +28,6 @@
 )
 
 import (
-	gxnet "github.com/dubbogo/gost/net"
 	perrors "github.com/pkg/errors"
 )
 
@@ -217,7 +216,7 @@
 	if url == nil {
 		return
 	}
-	instance, err := createInstance(*url)
+	instance, err := createInstance(url)
 	if err != nil {
 		panic(err)
 	}
@@ -241,7 +240,7 @@
 }
 
 // nolint
-func createInstance(url common.URL) (registry.ServiceInstance, error) {
+func createInstance(url *common.URL) (registry.ServiceInstance, error) {
 	appConfig := GetApplicationConfig()
 	port, err := strconv.ParseInt(url.Port, 10, 32)
 	if err != nil {
@@ -250,10 +249,7 @@
 
 	host := url.Ip
 	if len(host) == 0 {
-		host, err = gxnet.GetLocalIP()
-		if err != nil {
-			return nil, perrors.WithMessage(err, "could not get the local Ip")
-		}
+		host = common.GetLocalIp()
 	}
 
 	// usually we will add more metadata
@@ -273,7 +269,7 @@
 
 // selectMetadataServiceExportedURL get already be exported url
 func selectMetadataServiceExportedURL() *common.URL {
-	var selectedUrl common.URL
+	var selectedUrl *common.URL
 	metaDataService, err := extension.GetMetadataService(GetApplicationConfig().MetadataType)
 	if err != nil {
 		logger.Warn(err)
@@ -298,7 +294,7 @@
 			break
 		}
 	}
-	return &selectedUrl
+	return selectedUrl
 }
 
 func initRouter() {
diff --git a/config/config_loader_test.go b/config/config_loader_test.go
index 461e607..9b25303 100644
--- a/config/config_loader_test.go
+++ b/config/config_loader_test.go
@@ -25,7 +25,6 @@
 )
 
 import (
-	cm "github.com/Workiva/go-datastructures/common"
 	"github.com/Workiva/go-datastructures/slice/skip"
 	gxset "github.com/dubbogo/gost/container/set"
 	gxpage "github.com/dubbogo/gost/page"
@@ -353,27 +352,27 @@
 	panic("implement me")
 }
 
-func (m *mockMetadataService) ExportURL(url common.URL) (bool, error) {
-	return m.addURL(m.exportedServiceURLs, &url), nil
+func (m *mockMetadataService) ExportURL(url *common.URL) (bool, error) {
+	return m.addURL(m.exportedServiceURLs, url), nil
 }
 
-func (m *mockMetadataService) UnexportURL(url common.URL) error {
+func (m *mockMetadataService) UnexportURL(*common.URL) error {
 	panic("implement me")
 }
 
-func (m *mockMetadataService) SubscribeURL(url common.URL) (bool, error) {
+func (m *mockMetadataService) SubscribeURL(*common.URL) (bool, error) {
 	panic("implement me")
 }
 
-func (m *mockMetadataService) UnsubscribeURL(url common.URL) error {
+func (m *mockMetadataService) UnsubscribeURL(*common.URL) error {
 	panic("implement me")
 }
 
-func (m *mockMetadataService) PublishServiceDefinition(url common.URL) error {
+func (m *mockMetadataService) PublishServiceDefinition(*common.URL) error {
 	return nil
 }
 
-func (m *mockMetadataService) GetExportedURLs(serviceInterface string, group string, version string, protocol string) ([]interface{}, error) {
+func (m *mockMetadataService) GetExportedURLs(string, string, string, string) ([]interface{}, error) {
 	return ConvertURLArrToIntfArr(m.getAllService(m.exportedServiceURLs)), nil
 }
 
@@ -381,19 +380,19 @@
 	panic("implement me")
 }
 
-func (m *mockMetadataService) GetSubscribedURLs() ([]common.URL, error) {
+func (m *mockMetadataService) GetSubscribedURLs() ([]*common.URL, error) {
 	panic("implement me")
 }
 
-func (m *mockMetadataService) GetServiceDefinition(interfaceName string, group string, version string) (string, error) {
+func (m *mockMetadataService) GetServiceDefinition(string, string, string) (string, error) {
 	panic("implement me")
 }
 
-func (m *mockMetadataService) GetServiceDefinitionByServiceKey(serviceKey string) (string, error) {
+func (m *mockMetadataService) GetServiceDefinitionByServiceKey(string) (string, error) {
 	panic("implement me")
 }
 
-func (m *mockMetadataService) RefreshMetadata(exportedRevision string, subscribedRevision string) (bool, error) {
+func (m *mockMetadataService) RefreshMetadata(string, string) (bool, error) {
 	panic("implement me")
 }
 
@@ -409,7 +408,7 @@
 	logger.Debug(url.ServiceKey())
 	if urlSet, loaded = targetMap.LoadOrStore(url.ServiceKey(), skip.New(uint64(0))); loaded {
 		mts.lock.RLock()
-		wantedUrl := urlSet.(*skip.SkipList).Get(Comparator(*url))
+		wantedUrl := urlSet.(*skip.SkipList).Get(url)
 		if len(wantedUrl) > 0 && wantedUrl[0] != nil {
 			mts.lock.RUnlock()
 			return false
@@ -418,23 +417,23 @@
 	}
 	mts.lock.Lock()
 	// double chk
-	wantedUrl := urlSet.(*skip.SkipList).Get(Comparator(*url))
+	wantedUrl := urlSet.(*skip.SkipList).Get(url)
 	if len(wantedUrl) > 0 && wantedUrl[0] != nil {
 		mts.lock.Unlock()
 		return false
 	}
-	urlSet.(*skip.SkipList).Insert(Comparator(*url))
+	urlSet.(*skip.SkipList).Insert(url)
 	mts.lock.Unlock()
 	return true
 }
 
-func (m *mockMetadataService) getAllService(services *sync.Map) []common.URL {
+func (m *mockMetadataService) getAllService(services *sync.Map) []*common.URL {
 	// using skip list to dedup and sorting
-	res := make([]common.URL, 0)
+	var res []*common.URL
 	services.Range(func(key, value interface{}) bool {
 		urls := value.(*skip.SkipList)
 		for i := uint64(0); i < urls.Len(); i++ {
-			url := common.URL(urls.ByPosition(i).(Comparator))
+			url := urls.ByPosition(i).(*common.URL)
 			if url.GetParam(constant.INTERFACE_KEY, url.Path) != constant.METADATA_SERVICE_NAME {
 				res = append(res, url)
 			}
@@ -445,26 +444,10 @@
 	return res
 }
 
-type Comparator common.URL
-
-// Compare is defined as Comparator for skip list to compare the URL
-func (c Comparator) Compare(comp cm.Comparator) int {
-	a := common.URL(c).String()
-	b := common.URL(comp.(Comparator)).String()
-	switch {
-	case a > b:
-		return 1
-	case a < b:
-		return -1
-	default:
-		return 0
-	}
-}
-
 type mockServiceDiscoveryRegistry struct {
 }
 
-func (mr *mockServiceDiscoveryRegistry) GetUrl() common.URL {
+func (mr *mockServiceDiscoveryRegistry) GetUrl() *common.URL {
 	panic("implement me")
 }
 
@@ -476,11 +459,11 @@
 	panic("implement me")
 }
 
-func (mr *mockServiceDiscoveryRegistry) Register(url common.URL) error {
+func (mr *mockServiceDiscoveryRegistry) Register(*common.URL) error {
 	panic("implement me")
 }
 
-func (mr *mockServiceDiscoveryRegistry) UnRegister(url common.URL) error {
+func (mr *mockServiceDiscoveryRegistry) UnRegister(*common.URL) error {
 	panic("implement me")
 }
 
@@ -507,15 +490,15 @@
 	panic("implement me")
 }
 
-func (m *mockServiceDiscovery) Register(instance registry.ServiceInstance) error {
+func (m *mockServiceDiscovery) Register(registry.ServiceInstance) error {
 	return nil
 }
 
-func (m *mockServiceDiscovery) Update(instance registry.ServiceInstance) error {
+func (m *mockServiceDiscovery) Update(registry.ServiceInstance) error {
 	panic("implement me")
 }
 
-func (m *mockServiceDiscovery) Unregister(instance registry.ServiceInstance) error {
+func (m *mockServiceDiscovery) Unregister(registry.ServiceInstance) error {
 	panic("implement me")
 }
 
@@ -527,39 +510,39 @@
 	panic("implement me")
 }
 
-func (m *mockServiceDiscovery) GetInstances(serviceName string) []registry.ServiceInstance {
+func (m *mockServiceDiscovery) GetInstances(string) []registry.ServiceInstance {
 	panic("implement me")
 }
 
-func (m *mockServiceDiscovery) GetInstancesByPage(serviceName string, offset int, pageSize int) gxpage.Pager {
+func (m *mockServiceDiscovery) GetInstancesByPage(string, int, int) gxpage.Pager {
 	panic("implement me")
 }
 
-func (m *mockServiceDiscovery) GetHealthyInstancesByPage(serviceName string, offset int, pageSize int, healthy bool) gxpage.Pager {
+func (m *mockServiceDiscovery) GetHealthyInstancesByPage(string, int, int, bool) gxpage.Pager {
 	panic("implement me")
 }
 
-func (m *mockServiceDiscovery) GetRequestInstances(serviceNames []string, offset int, requestedSize int) map[string]gxpage.Pager {
+func (m *mockServiceDiscovery) GetRequestInstances([]string, int, int) map[string]gxpage.Pager {
 	panic("implement me")
 }
 
-func (m *mockServiceDiscovery) AddListener(listener *registry.ServiceInstancesChangedListener) error {
+func (m *mockServiceDiscovery) AddListener(*registry.ServiceInstancesChangedListener) error {
 	panic("implement me")
 }
 
-func (m *mockServiceDiscovery) DispatchEventByServiceName(serviceName string) error {
+func (m *mockServiceDiscovery) DispatchEventByServiceName(string) error {
 	panic("implement me")
 }
 
-func (m *mockServiceDiscovery) DispatchEventForInstances(serviceName string, instances []registry.ServiceInstance) error {
+func (m *mockServiceDiscovery) DispatchEventForInstances(string, []registry.ServiceInstance) error {
 	panic("implement me")
 }
 
-func (m *mockServiceDiscovery) DispatchEvent(event *registry.ServiceInstancesChangedEvent) error {
+func (m *mockServiceDiscovery) DispatchEvent(*registry.ServiceInstancesChangedEvent) error {
 	panic("implement me")
 }
 
-func ConvertURLArrToIntfArr(urls []common.URL) []interface{} {
+func ConvertURLArrToIntfArr(urls []*common.URL) []interface{} {
 	if len(urls) == 0 {
 		return []interface{}{}
 	}
diff --git a/config/instance/metadata_report.go b/config/instance/metadata_report.go
index 8e833dd..68a197d 100644
--- a/config/instance/metadata_report.go
+++ b/config/instance/metadata_report.go
@@ -29,7 +29,7 @@
 
 var (
 	instance  report.MetadataReport
-	reportUrl common.URL
+	reportUrl *common.URL
 	once      sync.Once
 )
 
@@ -41,18 +41,18 @@
 		if len(selectiveUrl) > 0 {
 			url = selectiveUrl[0]
 			instance = extension.GetMetadataReportFactory(url.Protocol).CreateMetadataReport(url)
-			reportUrl = *url
+			reportUrl = url
 		}
 	})
 	return instance
 }
 
 // GetMetadataReportUrl will return the report instance url
-func GetMetadataReportUrl() common.URL {
+func GetMetadataReportUrl() *common.URL {
 	return reportUrl
 }
 
 // SetMetadataReportUrl will only can be used by unit test to mock url
-func SetMetadataReportUrl(url common.URL) {
+func SetMetadataReportUrl(url *common.URL) {
 	reportUrl = url
 }
diff --git a/config/instance/metadata_report_test.go b/config/instance/metadata_report_test.go
index d489af0..110903a 100644
--- a/config/instance/metadata_report_test.go
+++ b/config/instance/metadata_report_test.go
@@ -38,7 +38,7 @@
 		return &mockMetadataReportFactory{}
 	})
 	u, _ := common.NewURL("mock://127.0.0.1")
-	rpt := GetMetadataReportInstance(&u)
+	rpt := GetMetadataReportInstance(u)
 	assert.NotNil(t, rpt)
 }
 
@@ -60,7 +60,7 @@
 	panic("implement me")
 }
 
-func (m mockMetadataReport) SaveServiceMetadata(*identifier.ServiceMetadataIdentifier, common.URL) error {
+func (m mockMetadataReport) SaveServiceMetadata(*identifier.ServiceMetadataIdentifier, *common.URL) error {
 	panic("implement me")
 }
 
diff --git a/config/metadata_report_config.go b/config/metadata_report_config.go
index 6d319e5..24eba5e 100644
--- a/config/metadata_report_config.go
+++ b/config/metadata_report_config.go
@@ -84,7 +84,7 @@
 		return nil, perrors.New("Invalid MetadataReportConfig.")
 	}
 	res.SetParam("metadata", res.Protocol)
-	return &res, nil
+	return res, nil
 }
 
 func (c *MetadataReportConfig) IsValid() bool {
@@ -101,8 +101,8 @@
 		return perrors.New("MetadataConfig remote ref can not be empty.")
 	}
 
-	if url, err := metadataReportConfig.ToUrl(); err == nil {
-		instance.GetMetadataReportInstance(url)
+	if tmpUrl, err := metadataReportConfig.ToUrl(); err == nil {
+		instance.GetMetadataReportInstance(tmpUrl)
 	} else {
 		return perrors.Wrap(err, "Start MetadataReport failed.")
 	}
diff --git a/config/reference_config.go b/config/reference_config.go
index cd10f89..2e914ac 100644
--- a/config/reference_config.go
+++ b/config/reference_config.go
@@ -114,13 +114,13 @@
 			}
 			if serviceUrl.Protocol == constant.REGISTRY_PROTOCOL {
 				serviceUrl.SubURL = cfgURL
-				c.urls = append(c.urls, &serviceUrl)
+				c.urls = append(c.urls, serviceUrl)
 			} else {
 				if serviceUrl.Path == "" {
 					serviceUrl.Path = "/" + c.id
 				}
 				// merge url need to do
-				newUrl := common.MergeUrl(&serviceUrl, cfgURL)
+				newUrl := common.MergeUrl(serviceUrl, cfgURL)
 				c.urls = append(c.urls, newUrl)
 			}
 		}
@@ -135,12 +135,12 @@
 	}
 
 	if len(c.urls) == 1 {
-		c.invoker = extension.GetProtocol(c.urls[0].Protocol).Refer(*c.urls[0])
+		c.invoker = extension.GetProtocol(c.urls[0].Protocol).Refer(c.urls[0])
 	} else {
 		invokers := make([]protocol.Invoker, 0, len(c.urls))
 		var regUrl *common.URL
 		for _, u := range c.urls {
-			invokers = append(invokers, extension.GetProtocol(u.Protocol).Refer(*u))
+			invokers = append(invokers, extension.GetProtocol(u.Protocol).Refer(u))
 			if u.Protocol == constant.REGISTRY_PROTOCOL {
 				regUrl = u
 			}
diff --git a/config/reference_config_test.go b/config/reference_config_test.go
index a4345ad..0207e1f 100644
--- a/config/reference_config_test.go
+++ b/config/reference_config_test.go
@@ -334,7 +334,7 @@
 
 type mockRegistryProtocol struct{}
 
-func (*mockRegistryProtocol) Refer(url common.URL) protocol.Invoker {
+func (*mockRegistryProtocol) Refer(url *common.URL) protocol.Invoker {
 	return protocol.NewBaseInvoker(url)
 }
 
@@ -345,7 +345,7 @@
 		if err != nil {
 			panic(err)
 		}
-		ok, err := metaDataService.ExportURL(*invoker.GetUrl().SubURL.Clone())
+		ok, err := metaDataService.ExportURL(invoker.GetUrl().SubURL.Clone())
 		if err != nil {
 			panic(err)
 		}
@@ -367,7 +367,7 @@
 		protocol := url.GetParam(constant.REGISTRY_KEY, "")
 		url.Protocol = protocol
 	}
-	return &url
+	return url
 }
 
 func (p *mockRegistryProtocol) GetRegistries() []registry.Registry {
diff --git a/config/registry_config.go b/config/registry_config.go
index 89566c4..5aff45d 100644
--- a/config/registry_config.go
+++ b/config/registry_config.go
@@ -53,7 +53,7 @@
 	//ZoneForce bool `yaml:"zoneForce" json:"zoneForce,omitempty" property:"zoneForce"`
 	// Affects traffic distribution among registries,
 	// useful when subscribe to multiple registries Take effect only when no preferred registry is specified.
-	Weight int64             `yaml:"weight" json:"params,omitempty" property:"weight"`
+	Weight int64             `yaml:"weight" json:"weight,omitempty" property:"weight"`
 	Params map[string]string `yaml:"params" json:"params,omitempty" property:"params"`
 }
 
@@ -114,7 +114,7 @@
 				logger.Errorf("The registry id: %s url is invalid, error: %#v", k, err)
 				panic(err)
 			} else {
-				urls = append(urls, &url)
+				urls = append(urls, url)
 			}
 		}
 	}
diff --git a/config/remote_config.go b/config/remote_config.go
index 0f0c3e5..61d4dce 100644
--- a/config/remote_config.go
+++ b/config/remote_config.go
@@ -63,9 +63,9 @@
 	return param
 }
 
-func (rc *RemoteConfig) toURL() (common.URL, error) {
+func (rc *RemoteConfig) toURL() (*common.URL, error) {
 	if len(rc.Protocol) == 0 {
-		return common.URL{}, perrors.Errorf("Must provide protocol in RemoteConfig.")
+		return nil, perrors.Errorf("Must provide protocol in RemoteConfig.")
 	}
 	return common.NewURL(rc.Address,
 		common.WithUsername(rc.Username),
diff --git a/config/router_config.go b/config/router_config.go
index ed42577..ea19b46 100644
--- a/config/router_config.go
+++ b/config/router_config.go
@@ -66,7 +66,7 @@
 		r, e := factory.NewFileRouter(content)
 		if e == nil {
 			url := r.URL()
-			routerURLSet.Add(&url)
+			routerURLSet.Add(url)
 			return nil
 		}
 		logger.Warnf("router config type %s create fail {%v}\n", k, e)
diff --git a/config/service_config.go b/config/service_config.go
index 48632a1..b3febc6 100644
--- a/config/service_config.go
+++ b/config/service_config.go
@@ -73,6 +73,7 @@
 	Auth                        string            `yaml:"auth" json:"auth,omitempty" property:"auth"`
 	ParamSign                   string            `yaml:"param.sign" json:"param.sign,omitempty" property:"param.sign"`
 	Tag                         string            `yaml:"tag" json:"tag,omitempty" property:"tag"`
+	GrpcMaxMessageSize          int               `default:"4" yaml:"max_message_size" json:"max_message_size,omitempty"`
 
 	Protocols     map[string]*ProtocolConfig
 	unexported    *atomic.Bool
@@ -207,7 +208,7 @@
 
 			for _, regUrl := range regUrls {
 				regUrl.SubURL = ivkURL
-				invoker := proxyFactory.GetInvoker(*regUrl)
+				invoker := proxyFactory.GetInvoker(regUrl)
 				exporter := c.cacheProtocol.Export(invoker)
 				if exporter == nil {
 					return perrors.New(fmt.Sprintf("Registry protocol new exporter error, registry is {%v}, url is {%v}", regUrl, ivkURL))
@@ -215,7 +216,7 @@
 				c.exporters = append(c.exporters, exporter)
 			}
 		} else {
-			invoker := proxyFactory.GetInvoker(*ivkURL)
+			invoker := proxyFactory.GetInvoker(ivkURL)
 			exporter := extension.GetProtocol(protocolwrapper.FILTER).Export(invoker)
 			if exporter == nil {
 				return perrors.New(fmt.Sprintf("Filter protocol without registry new exporter error, url is {%v}", ivkURL))
@@ -271,6 +272,7 @@
 	urlMap.Set(constant.ROLE_KEY, strconv.Itoa(common.PROVIDER))
 	urlMap.Set(constant.RELEASE_KEY, "dubbo-golang-"+constant.Version)
 	urlMap.Set(constant.SIDE_KEY, (common.RoleType(common.PROVIDER)).Role())
+	urlMap.Set(constant.MESSAGE_SIZE_KEY, strconv.Itoa(c.GrpcMaxMessageSize))
 	// todo: move
 	urlMap.Set(constant.SERIALIZATION_KEY, c.Serialization)
 	// application info
@@ -324,8 +326,7 @@
 	if c.exported.Load() {
 		var urls []*common.URL
 		for _, exporter := range c.exporters {
-			url := exporter.GetInvoker().GetUrl()
-			urls = append(urls, &url)
+			urls = append(urls, exporter.GetInvoker().GetUrl())
 		}
 		return urls
 	}
diff --git a/config/service_config_test.go b/config/service_config_test.go
index 4d4122e..61c8864 100644
--- a/config/service_config_test.go
+++ b/config/service_config_test.go
@@ -18,11 +18,11 @@
 package config
 
 import (
+	"github.com/apache/dubbo-go/common"
 	"testing"
 )
 
 import (
-	gxnet "github.com/dubbogo/gost/net"
 	"github.com/stretchr/testify/assert"
 	"go.uber.org/atomic"
 )
@@ -184,7 +184,7 @@
 func TestGetRandomPort(t *testing.T) {
 	protocolConfigs := make([]*ProtocolConfig, 0, 3)
 
-	ip, err := gxnet.GetLocalIP()
+	ip := common.GetLocalIp()
 	protocolConfigs = append(protocolConfigs, &ProtocolConfig{
 		Ip: ip,
 	})
@@ -194,7 +194,7 @@
 	protocolConfigs = append(protocolConfigs, &ProtocolConfig{
 		Ip: ip,
 	})
-	assert.NoError(t, err)
+	//assert.NoError(t, err)
 	ports := getRandomPort(protocolConfigs)
 
 	assert.Equal(t, ports.Len(), len(protocolConfigs))
diff --git a/config_center/apollo/impl.go b/config_center/apollo/impl.go
index ac5328c..c69fc2f 100644
--- a/config_center/apollo/impl.go
+++ b/config_center/apollo/impl.go
@@ -109,11 +109,11 @@
 }
 
 func (c *apolloConfiguration) GetInternalProperty(key string, opts ...cc.Option) (string, error) {
-	config := agollo.GetConfig(c.appConf.NamespaceName)
-	if config == nil {
+	newConfig := agollo.GetConfig(c.appConf.NamespaceName)
+	if newConfig == nil {
 		return "", perrors.New(fmt.Sprintf("nothing in namespace:%s ", key))
 	}
-	return config.GetStringValue(key, ""), nil
+	return newConfig.GetStringValue(key, ""), nil
 }
 
 func (c *apolloConfiguration) GetRule(key string, opts ...cc.Option) (string, error) {
@@ -135,11 +135,11 @@
 	 * when group is not null, we are getting startup configs(config file) from Config Center, for example:
 	 * key=dubbo.propertie
 	 */
-	config := agollo.GetConfig(key)
-	if config == nil {
+	tmpConfig := agollo.GetConfig(key)
+	if tmpConfig == nil {
 		return "", perrors.New(fmt.Sprintf("nothing in namespace:%s ", key))
 	}
-	return config.GetContent(), nil
+	return tmpConfig.GetContent(), nil
 }
 
 func (c *apolloConfiguration) getAddressWithProtocolPrefix(url *common.URL) string {
diff --git a/config_center/apollo/impl_test.go b/config_center/apollo/impl_test.go
index 50c4e68..4720775 100644
--- a/config_center/apollo/impl_test.go
+++ b/config_center/apollo/impl_test.go
@@ -197,7 +197,7 @@
 	apolloUrl := strings.ReplaceAll(apollo.URL, "http", "apollo")
 	url, err := common.NewURL(apolloUrl, common.WithParams(c.ConfigCenterConfig.GetUrlMap()))
 	assert.NoError(t, err)
-	configuration, err := newApolloConfiguration(&url)
+	configuration, err := newApolloConfiguration(url)
 	assert.NoError(t, err)
 	return configuration
 }
diff --git a/config_center/configurator/override.go b/config_center/configurator/override.go
index ec4e606..7f5abb6 100644
--- a/config_center/configurator/override.go
+++ b/config_center/configurator/override.go
@@ -23,7 +23,6 @@
 
 import (
 	gxset "github.com/dubbogo/gost/container/set"
-	gxnet "github.com/dubbogo/gost/net"
 )
 
 import (
@@ -61,7 +60,7 @@
 		currentSide := url.GetParam(constant.SIDE_KEY, "")
 		configuratorSide := c.configuratorUrl.GetParam(constant.SIDE_KEY, "")
 		if currentSide == configuratorSide && common.DubboRole[common.CONSUMER] == currentSide && c.configuratorUrl.Port == "0" {
-			localIP, _ := gxnet.GetLocalIP()
+			localIP := common.GetLocalIp()
 			c.configureIfMatch(localIP, url)
 		} else if currentSide == configuratorSide && common.DubboRole[common.PROVIDER] == currentSide && c.configuratorUrl.Port == url.Port {
 			c.configureIfMatch(url.Ip, url)
@@ -127,7 +126,7 @@
 		// 1.If it is a consumer ip address, the intention is to control a specific consumer instance, it must takes effect at the consumer side, any provider received this override url should ignore;
 		// 2.If the ip is 0.0.0.0, this override url can be used on consumer, and also can be used on provider
 		if url.GetParam(constant.SIDE_KEY, "") == common.DubboRole[common.CONSUMER] {
-			localIP, _ := gxnet.GetLocalIP()
+			localIP := common.GetLocalIp()
 			c.configureIfMatch(localIP, url)
 		} else {
 			c.configureIfMatch(constant.ANYHOST_VALUE, url)
diff --git a/config_center/configurator/override_test.go b/config_center/configurator/override_test.go
index 8eccb50..bb9c367 100644
--- a/config_center/configurator/override_test.go
+++ b/config_center/configurator/override_test.go
@@ -40,36 +40,36 @@
 func TestConfigureVerison2p6(t *testing.T) {
 	url, err := common.NewURL("override://0.0.0.0:0/com.xxx.mock.userProvider?group=1&version=1&cluster=failfast&application=BDTService")
 	assert.NoError(t, err)
-	configurator := extension.GetConfigurator(defaults, &url)
+	configurator := extension.GetConfigurator(defaults, url)
 	assert.Equal(t, override, configurator.GetUrl().Protocol)
 
 	providerUrl, err := common.NewURL("jsonrpc://127.0.0.1:20001/com.ikurento.user.UserProvider?anyhost=true&app.version=0.0.1&application=BDTService&category=providers&cluster=failover&dubbo=dubbo-provider-golang-2.6.0&environment=dev&group=&interface=com.ikurento.user.UserProvider&ip=10.32.20.124&loadbalance=random&methods.GetUser.loadbalance=random&methods.GetUser.retries=1&methods.GetUser.weight=0&module=dubbogo+user-info+server&name=BDTService&organization=ikurento.com&owner=ZX&pid=64225&retries=0&service.filter=echo&side=provider&timestamp=1562076628&version=&warmup=100")
 	assert.NoError(t, err)
-	configurator.Configure(&providerUrl)
+	configurator.Configure(providerUrl)
 	assert.Equal(t, failfast, providerUrl.GetParam(constant.CLUSTER_KEY, ""))
 }
 
 func TestConfigureVerisonOverrideAddr(t *testing.T) {
 	url, err := common.NewURL("override://0.0.0.0:0/com.xxx.mock.userProvider?group=1&version=1&cluster=failfast&application=BDTService&providerAddresses=127.0.0.2:20001|127.0.0.3:20001")
 	assert.NoError(t, err)
-	configurator := extension.GetConfigurator(defaults, &url)
+	configurator := extension.GetConfigurator(defaults, url)
 	assert.Equal(t, override, configurator.GetUrl().Protocol)
 
 	providerUrl, err := common.NewURL("jsonrpc://127.0.0.1:20001/com.ikurento.user.UserProvider?anyhost=true&app.version=0.0.1&application=BDTService&category=providers&cluster=failover&dubbo=dubbo-provider-golang-2.6.0&environment=dev&group=&interface=com.ikurento.user.UserProvider&ip=10.32.20.124&loadbalance=random&methods.GetUser.loadbalance=random&methods.GetUser.retries=1&methods.GetUser.weight=0&module=dubbogo+user-info+server&name=BDTService&organization=ikurento.com&owner=ZX&pid=64225&retries=0&service.filter=echo&side=provider&timestamp=1562076628&version=&warmup=100")
 	assert.NoError(t, err)
-	configurator.Configure(&providerUrl)
+	configurator.Configure(providerUrl)
 	assert.Equal(t, failover, providerUrl.GetParam(constant.CLUSTER_KEY, ""))
 }
 
 func TestConfigureVerison2p6WithIp(t *testing.T) {
 	url, err := common.NewURL("override://127.0.0.1:20001/com.xxx.mock.userProvider?group=1&version=1&cluster=failfast&application=BDTService")
 	assert.NoError(t, err)
-	configurator := extension.GetConfigurator(defaults, &url)
+	configurator := extension.GetConfigurator(defaults, url)
 	assert.Equal(t, override, configurator.GetUrl().Protocol)
 
 	providerUrl, err := common.NewURL("jsonrpc://127.0.0.1:20001/com.ikurento.user.UserProvider?anyhost=true&app.version=0.0.1&application=BDTService&category=providers&cluster=failover&dubbo=dubbo-provider-golang-2.6.0&environment=dev&group=&interface=com.ikurento.user.UserProvider&ip=10.32.20.124&loadbalance=random&methods.GetUser.loadbalance=random&methods.GetUser.retries=1&methods.GetUser.weight=0&module=dubbogo+user-info+server&name=BDTService&organization=ikurento.com&owner=ZX&pid=64225&retries=0&service.filter=echo&side=provider&timestamp=1562076628&version=&warmup=100")
 	assert.NoError(t, err)
-	configurator.Configure(&providerUrl)
+	configurator.Configure(providerUrl)
 	assert.Equal(t, failfast, providerUrl.GetParam(constant.CLUSTER_KEY, ""))
 
 }
@@ -77,11 +77,11 @@
 func TestConfigureVerison2p7(t *testing.T) {
 	url, err := common.NewURL("jsonrpc://0.0.0.0:20001/com.xxx.mock.userProvider?group=1&version=1&cluster=failfast&application=BDTService&configVersion=1.0&side=provider")
 	assert.NoError(t, err)
-	configurator := extension.GetConfigurator(defaults, &url)
+	configurator := extension.GetConfigurator(defaults, url)
 
 	providerUrl, err := common.NewURL("jsonrpc://127.0.0.1:20001/com.ikurento.user.UserProvider?anyhost=true&app.version=0.0.1&application=BDTService&category=providers&cluster=failover&dubbo=dubbo-provider-golang-2.6.0&environment=dev&group=&interface=com.ikurento.user.UserProvider&ip=10.32.20.124&loadbalance=random&methods.GetUser.loadbalance=random&methods.GetUser.retries=1&methods.GetUser.weight=0&module=dubbogo+user-info+server&name=BDTService&organization=ikurento.com&owner=ZX&pid=64225&retries=0&service.filter=echo&side=provider&timestamp=1562076628&version=&warmup=100")
 	assert.NoError(t, err)
-	configurator.Configure(&providerUrl)
+	configurator.Configure(providerUrl)
 	assert.Equal(t, failfast, providerUrl.GetParam(constant.CLUSTER_KEY, ""))
 
 }
diff --git a/config_center/dynamic_configuration.go b/config_center/dynamic_configuration.go
index cbf8e8c..69f8421 100644
--- a/config_center/dynamic_configuration.go
+++ b/config_center/dynamic_configuration.go
@@ -89,6 +89,6 @@
 }
 
 // GetRuleKey The format is '{interfaceName}:[version]:[group]'
-func GetRuleKey(url common.URL) string {
+func GetRuleKey(url *common.URL) string {
 	return url.ColonSeparatedKey()
 }
diff --git a/config_center/file/impl.go b/config_center/file/impl.go
index 9d82540..f29a33d 100644
--- a/config_center/file/impl.go
+++ b/config_center/file/impl.go
@@ -113,9 +113,8 @@
 		opt(tmpOpts)
 	}
 
-	path := fsdc.GetPath(key, tmpOpts.Group)
-
-	fsdc.cacheListener.AddListener(path, listener)
+	tmpPath := fsdc.GetPath(key, tmpOpts.Group)
+	fsdc.cacheListener.AddListener(tmpPath, listener)
 }
 
 // RemoveListener Remove listener
@@ -126,9 +125,8 @@
 		opt(tmpOpts)
 	}
 
-	path := fsdc.GetPath(key, tmpOpts.Group)
-
-	fsdc.cacheListener.RemoveListener(path, listener)
+	tmpPath := fsdc.GetPath(key, tmpOpts.Group)
+	fsdc.cacheListener.RemoveListener(tmpPath, listener)
 }
 
 // GetProperties get properties file
@@ -138,12 +136,11 @@
 		opt(tmpOpts)
 	}
 
-	path := fsdc.GetPath(key, tmpOpts.Group)
-	file, err := ioutil.ReadFile(path)
+	tmpPath := fsdc.GetPath(key, tmpOpts.Group)
+	file, err := ioutil.ReadFile(tmpPath)
 	if err != nil {
 		return "", perrors.WithStack(err)
 	}
-
 	return string(file), nil
 }
 
@@ -160,16 +157,16 @@
 
 // PublishConfig will publish the config with the (key, group, value) pair
 func (fsdc *FileSystemDynamicConfiguration) PublishConfig(key string, group string, value string) error {
-	path := fsdc.GetPath(key, group)
-	return fsdc.write2File(path, value)
+	tmpPath := fsdc.GetPath(key, group)
+	return fsdc.write2File(tmpPath, value)
 }
 
 // GetConfigKeysByGroup will return all keys with the group
 func (fsdc *FileSystemDynamicConfiguration) GetConfigKeysByGroup(group string) (*gxset.HashSet, error) {
-	path := fsdc.GetPath("", group)
+	tmpPath := fsdc.GetPath("", group)
 	r := gxset.NewSet()
 
-	fileInfo, _ := ioutil.ReadDir(path)
+	fileInfo, _ := ioutil.ReadDir(tmpPath)
 
 	for _, file := range fileInfo {
 		// list file
@@ -185,8 +182,8 @@
 
 // RemoveConfig will remove the config whit hte (key, group)
 func (fsdc *FileSystemDynamicConfiguration) RemoveConfig(key string, group string) error {
-	path := fsdc.GetPath(key, group)
-	_, err := fsdc.deleteDelay(path)
+	tmpPath := fsdc.GetPath(key, group)
+	_, err := fsdc.deleteDelay(tmpPath)
 	return err
 }
 
@@ -261,9 +258,9 @@
 // This uses an OS-specific method for discovering the home directory.
 // An error is returned if a home directory cannot be detected.
 func Home() (string, error) {
-	user, err := user.Current()
+	currentUser, err := user.Current()
 	if nil == err {
-		return user.HomeDir, nil
+		return currentUser.HomeDir, nil
 	}
 
 	// cross compile support
@@ -299,9 +296,9 @@
 
 func homeWindows() (string, error) {
 	drive := os.Getenv("HOMEDRIVE")
-	path := os.Getenv("HOMEPATH")
-	home := drive + path
-	if drive == "" || path == "" {
+	homePath := os.Getenv("HOMEPATH")
+	home := drive + homePath
+	if drive == "" || homePath == "" {
 		home = os.Getenv("USERPROFILE")
 	}
 	if home == "" {
diff --git a/config_center/file/impl_test.go b/config_center/file/impl_test.go
index 5889295..e912cb7 100644
--- a/config_center/file/impl_test.go
+++ b/config_center/file/impl_test.go
@@ -42,7 +42,7 @@
 	urlString := "registry://127.0.0.1:2181"
 	regurl, err := common.NewURL(urlString)
 	assert.NoError(t, err)
-	dc, err := extension.GetConfigCenterFactory("file").GetDynamicConfiguration(&regurl)
+	dc, err := extension.GetConfigCenterFactory("file").GetDynamicConfiguration(regurl)
 	assert.NoError(t, err)
 
 	return dc.(*FileSystemDynamicConfiguration), err
diff --git a/config_center/nacos/client.go b/config_center/nacos/client.go
index acfe260..f3942c0 100644
--- a/config_center/nacos/client.go
+++ b/config_center/nacos/client.go
@@ -122,7 +122,7 @@
 	return perrors.WithMessagef(nil, "newNacosClient(address:%+v)", url.PrimitiveURL)
 }
 
-func newNacosClient(name string, nacosAddrs []string, timeout time.Duration, url common.URL) (*NacosClient, error) {
+func newNacosClient(name string, nacosAddrs []string, timeout time.Duration, url *common.URL) (*NacosClient, error) {
 	var (
 		err error
 		n   *NacosClient
@@ -149,8 +149,8 @@
 	return n, nil
 }
 
-func initNacosConfigClient(nacosAddrs []string, timeout time.Duration, url common.URL) (config_client.IConfigClient, error) {
-	svrConfList := []nacosconst.ServerConfig{}
+func initNacosConfigClient(nacosAddrs []string, timeout time.Duration, url *common.URL) (config_client.IConfigClient, error) {
+	var svrConfList []nacosconst.ServerConfig
 	for _, nacosAddr := range nacosAddrs {
 		split := strings.Split(nacosAddr, ":")
 		port, err := strconv.ParseUint(split[1], 10, 64)
diff --git a/config_center/nacos/client_test.go b/config_center/nacos/client_test.go
index 01319f3..2ce3e37 100644
--- a/config_center/nacos/client_test.go
+++ b/config_center/nacos/client_test.go
@@ -36,7 +36,7 @@
 	nacosURL := strings.ReplaceAll(server.URL, "http", "registry")
 	registryUrl, _ := common.NewURL(nacosURL)
 	c := &nacosDynamicConfiguration{
-		url:  &registryUrl,
+		url:  registryUrl,
 		done: make(chan struct{}),
 	}
 	err := ValidateNacosClient(c, WithNacosName(nacosClientName))
@@ -59,7 +59,7 @@
 	nacosURL := "registry://" + server.Listener.Addr().String()
 	registryUrl, _ := common.NewURL(nacosURL)
 	c := &nacosDynamicConfiguration{
-		url:  &registryUrl,
+		url:  registryUrl,
 		done: make(chan struct{}),
 	}
 	var client *NacosClient
@@ -93,7 +93,7 @@
 	registryUrl, err := common.NewURL(nacosURL)
 	assert.NoError(t, err)
 	c := &nacosDynamicConfiguration{
-		url:  &registryUrl,
+		url:  registryUrl,
 		done: make(chan struct{}),
 	}
 	err = ValidateNacosClient(c, WithNacosName(nacosClientName))
diff --git a/config_center/nacos/impl.go b/config_center/nacos/impl.go
index be94b9a..7c67930 100644
--- a/config_center/nacos/impl.go
+++ b/config_center/nacos/impl.go
@@ -186,8 +186,8 @@
 }
 
 // GetUrl Get Url
-func (n *nacosDynamicConfiguration) GetUrl() common.URL {
-	return *n.url
+func (n *nacosDynamicConfiguration) GetUrl() *common.URL {
+	return n.url
 }
 
 // Destroy Destroy configuration instance
diff --git a/config_center/nacos/impl_test.go b/config_center/nacos/impl_test.go
index 88d200e..40efa5f 100644
--- a/config_center/nacos/impl_test.go
+++ b/config_center/nacos/impl_test.go
@@ -73,7 +73,7 @@
 	nacosURL := strings.ReplaceAll(server.URL, "http", "registry")
 	regurl, _ := common.NewURL(nacosURL)
 	factory := &nacosDynamicConfigurationFactory{}
-	nacosConfiguration, err := factory.GetDynamicConfiguration(&regurl)
+	nacosConfiguration, err := factory.GetDynamicConfiguration(regurl)
 	assert.NoError(t, err)
 
 	nacosConfiguration.SetParser(&parser.DefaultConfigurationParser{})
@@ -105,7 +105,7 @@
 
 	nacosURL := strings.ReplaceAll(ts.URL, "http", "registry")
 	regurl, _ := common.NewURL(nacosURL)
-	nacosConfiguration, err := newNacosDynamicConfiguration(&regurl)
+	nacosConfiguration, err := newNacosDynamicConfiguration(regurl)
 	assert.NoError(t, err)
 
 	nacosConfiguration.SetParser(&parser.DefaultConfigurationParser{})
diff --git a/config_center/parser/configuration_parser.go b/config_center/parser/configuration_parser.go
index f794221..b104d3d 100644
--- a/config_center/parser/configuration_parser.go
+++ b/config_center/parser/configuration_parser.go
@@ -144,14 +144,14 @@
 				if err != nil {
 					return nil, perrors.WithStack(err)
 				}
-				urls = append(urls, &url)
+				urls = append(urls, url)
 			}
 		} else {
 			url, err := common.NewURL(urlStr)
 			if err != nil {
 				return nil, perrors.WithStack(err)
 			}
-			urls = append(urls, &url)
+			urls = append(urls, url)
 		}
 	}
 	return urls, nil
@@ -192,7 +192,7 @@
 			if err != nil {
 				return nil, perrors.WithStack(err)
 			}
-			urls = append(urls, &url)
+			urls = append(urls, url)
 		}
 	}
 	return urls, nil
diff --git a/config_center/zookeeper/impl.go b/config_center/zookeeper/impl.go
index 485abcb..17812e9 100644
--- a/config_center/zookeeper/impl.go
+++ b/config_center/zookeeper/impl.go
@@ -183,8 +183,8 @@
 	return c.done
 }
 
-func (c *zookeeperDynamicConfiguration) GetUrl() common.URL {
-	return *c.url
+func (c *zookeeperDynamicConfiguration) GetUrl() *common.URL {
+	return c.url
 }
 
 func (c *zookeeperDynamicConfiguration) Destroy() {
diff --git a/config_center/zookeeper/impl_test.go b/config_center/zookeeper/impl_test.go
index ecc3527..d4a9de4 100644
--- a/config_center/zookeeper/impl_test.go
+++ b/config_center/zookeeper/impl_test.go
@@ -50,7 +50,7 @@
 	assert.NoError(t, err)
 	regurl.AddParam(constant.REGISTRY_TIMEOUT_KEY, "15s")
 	zkFactory := &zookeeperDynamicConfigurationFactory{}
-	reg, err := zkFactory.GetDynamicConfiguration(&regurl)
+	reg, err := zkFactory.GetDynamicConfiguration(regurl)
 	zreg, ok := reg.(*zookeeperDynamicConfiguration)
 	assert.True(t, ok)
 	assert.NoError(t, err)
diff --git a/filter/filter_impl/auth/consumer_sign.go b/filter/filter_impl/auth/consumer_sign.go
index 945cf3e..823db82 100644
--- a/filter/filter_impl/auth/consumer_sign.go
+++ b/filter/filter_impl/auth/consumer_sign.go
@@ -42,8 +42,8 @@
 	logger.Infof("invoking ConsumerSign filter.")
 	url := invoker.GetUrl()
 
-	err := doAuthWork(&url, func(authenticator filter.Authenticator) error {
-		return authenticator.Sign(invocation, &url)
+	err := doAuthWork(url, func(authenticator filter.Authenticator) error {
+		return authenticator.Sign(invocation, url)
 	})
 	if err != nil {
 		panic(fmt.Sprintf("Sign for invocation %s # %s failed", url.ServiceKey(), invocation.MethodName()))
diff --git a/filter/filter_impl/auth/default_authenticator_test.go b/filter/filter_impl/auth/default_authenticator_test.go
index 8b0fb6b..37c7e9d 100644
--- a/filter/filter_impl/auth/default_authenticator_test.go
+++ b/filter/filter_impl/auth/default_authenticator_test.go
@@ -48,7 +48,7 @@
 	}{"YUYU", 1}}
 	inv := invocation.NewRPCInvocation("test", parmas, nil)
 	requestTime := strconv.Itoa(int(time.Now().Unix() * 1000))
-	signature, _ := getSignature(&testurl, inv, secret, requestTime)
+	signature, _ := getSignature(testurl, inv, secret, requestTime)
 
 	var authenticator = &DefaultAuthenticator{}
 
@@ -58,7 +58,7 @@
 		constant.REQUEST_TIMESTAMP_KEY: requestTime,
 		constant.AK_KEY:                access,
 	})
-	err := authenticator.Authenticate(invcation, &testurl)
+	err := authenticator.Authenticate(invcation, testurl)
 	assert.Nil(t, err)
 	// modify the params
 	invcation = invocation.NewRPCInvocation("test", parmas[:1], map[string]interface{}{
@@ -67,7 +67,7 @@
 		constant.REQUEST_TIMESTAMP_KEY: requestTime,
 		constant.AK_KEY:                access,
 	})
-	err = authenticator.Authenticate(invcation, &testurl)
+	err = authenticator.Authenticate(invcation, testurl)
 	assert.NotNil(t, err)
 
 }
@@ -79,7 +79,7 @@
 	testurl.SetParam(constant.SECRET_ACCESS_KEY_KEY, "skey")
 	testurl.SetParam(constant.PARAMTER_SIGNATURE_ENABLE_KEY, "false")
 	inv := invocation.NewRPCInvocation("test", []interface{}{"OK"}, nil)
-	_ = authenticator.Sign(inv, &testurl)
+	_ = authenticator.Sign(inv, testurl)
 	assert.NotEqual(t, inv.AttachmentsByKey(constant.REQUEST_SIGNATURE_KEY, ""), "")
 	assert.NotEqual(t, inv.AttachmentsByKey(constant.CONSUMER, ""), "")
 	assert.NotEqual(t, inv.AttachmentsByKey(constant.REQUEST_TIMESTAMP_KEY, ""), "")
@@ -124,7 +124,7 @@
 	})
 	secret := "dubbo"
 	current := strconv.Itoa(int(time.Now().Unix() * 1000))
-	signature, _ := getSignature(&testurl, inv, secret, current)
+	signature, _ := getSignature(testurl, inv, secret, current)
 	requestString := fmt.Sprintf(constant.SIGNATURE_STRING_FORMAT,
 		testurl.ColonSeparatedKey(), inv.MethodName(), secret, current)
 	s, _ := SignWithParams(inv.Arguments(), requestString, secret)
@@ -138,7 +138,7 @@
 	inv := invocation.NewRPCInvocation("test", []interface{}{"OK"}, nil)
 	secret := "dubbo"
 	current := strconv.Itoa(int(time.Now().Unix() * 1000))
-	signature, _ := getSignature(&testurl, inv, secret, current)
+	signature, _ := getSignature(testurl, inv, secret, current)
 	requestString := fmt.Sprintf(constant.SIGNATURE_STRING_FORMAT,
 		testurl.ColonSeparatedKey(), inv.MethodName(), secret, current)
 	s := Sign(requestString, secret)
diff --git a/filter/filter_impl/auth/provider_auth.go b/filter/filter_impl/auth/provider_auth.go
index d5f5db3..774fdb2 100644
--- a/filter/filter_impl/auth/provider_auth.go
+++ b/filter/filter_impl/auth/provider_auth.go
@@ -42,8 +42,8 @@
 	logger.Infof("invoking providerAuth filter.")
 	url := invoker.GetUrl()
 
-	err := doAuthWork(&url, func(authenticator filter.Authenticator) error {
-		return authenticator.Authenticate(invocation, &url)
+	err := doAuthWork(url, func(authenticator filter.Authenticator) error {
+		return authenticator.Authenticate(invocation, url)
 	})
 	if err != nil {
 		logger.Infof("auth the request: %v occur exception, cause: %s", invocation, err.Error())
diff --git a/filter/filter_impl/auth/provider_auth_test.go b/filter/filter_impl/auth/provider_auth_test.go
index f6ebfcd..dc130b5 100644
--- a/filter/filter_impl/auth/provider_auth_test.go
+++ b/filter/filter_impl/auth/provider_auth_test.go
@@ -52,7 +52,7 @@
 	}
 	inv := invocation.NewRPCInvocation("test", parmas, nil)
 	requestTime := strconv.Itoa(int(time.Now().Unix() * 1000))
-	signature, _ := getSignature(&url, inv, secret, requestTime)
+	signature, _ := getSignature(url, inv, secret, requestTime)
 
 	inv = invocation.NewRPCInvocation("test", []interface{}{"OK"}, map[string]interface{}{
 		constant.REQUEST_SIGNATURE_KEY: signature,
diff --git a/filter/filter_impl/echo_filter_test.go b/filter/filter_impl/echo_filter_test.go
index b821a1a..f2ec81a 100644
--- a/filter/filter_impl/echo_filter_test.go
+++ b/filter/filter_impl/echo_filter_test.go
@@ -34,10 +34,10 @@
 
 func TestEchoFilterInvoke(t *testing.T) {
 	filter := GetFilter()
-	result := filter.Invoke(context.Background(), protocol.NewBaseInvoker(common.URL{}), invocation.NewRPCInvocation("$echo", []interface{}{"OK"}, nil))
+	result := filter.Invoke(context.Background(), protocol.NewBaseInvoker(&common.URL{}), invocation.NewRPCInvocation("$echo", []interface{}{"OK"}, nil))
 	assert.Equal(t, "OK", result.Result())
 
-	result = filter.Invoke(context.Background(), protocol.NewBaseInvoker(common.URL{}), invocation.NewRPCInvocation("MethodName", []interface{}{"OK"}, nil))
+	result = filter.Invoke(context.Background(), protocol.NewBaseInvoker(&common.URL{}), invocation.NewRPCInvocation("MethodName", []interface{}{"OK"}, nil))
 	assert.Nil(t, result.Error())
 	assert.Nil(t, result.Result())
 }
diff --git a/filter/filter_impl/execute_limit_filter_test.go b/filter/filter_impl/execute_limit_filter_test.go
index 953f5e1..2aebcaa 100644
--- a/filter/filter_impl/execute_limit_filter_test.go
+++ b/filter/filter_impl/execute_limit_filter_test.go
@@ -44,7 +44,7 @@
 
 	limitFilter := GetExecuteLimitFilter()
 
-	result := limitFilter.Invoke(context.Background(), protocol.NewBaseInvoker(*invokeUrl), invoc)
+	result := limitFilter.Invoke(context.Background(), protocol.NewBaseInvoker(invokeUrl), invoc)
 	assert.NotNil(t, result)
 	assert.Nil(t, result.Error())
 }
@@ -61,7 +61,7 @@
 
 	limitFilter := GetExecuteLimitFilter()
 
-	result := limitFilter.Invoke(context.Background(), protocol.NewBaseInvoker(*invokeUrl), invoc)
+	result := limitFilter.Invoke(context.Background(), protocol.NewBaseInvoker(invokeUrl), invoc)
 	assert.NotNil(t, result)
 	assert.Nil(t, result.Error())
 }
@@ -78,7 +78,7 @@
 
 	limitFilter := GetExecuteLimitFilter()
 
-	result := limitFilter.Invoke(context.Background(), protocol.NewBaseInvoker(*invokeUrl), invoc)
+	result := limitFilter.Invoke(context.Background(), protocol.NewBaseInvoker(invokeUrl), invoc)
 	assert.NotNil(t, result)
 	assert.Nil(t, result.Error())
 }
diff --git a/filter/filter_impl/graceful_shutdown_filter_test.go b/filter/filter_impl/graceful_shutdown_filter_test.go
index 220ef6f..447a557 100644
--- a/filter/filter_impl/graceful_shutdown_filter_test.go
+++ b/filter/filter_impl/graceful_shutdown_filter_test.go
@@ -54,7 +54,7 @@
 	assert.Equal(t, extension.GetRejectedExecutionHandler(constant.DEFAULT_KEY),
 		shutdownFilter.getRejectHandler())
 
-	result := shutdownFilter.Invoke(context.Background(), protocol.NewBaseInvoker(*invokeUrl), invoc)
+	result := shutdownFilter.Invoke(context.Background(), protocol.NewBaseInvoker(invokeUrl), invoc)
 	assert.NotNil(t, result)
 	assert.Nil(t, result.Error())
 
@@ -65,7 +65,7 @@
 	shutdownFilter.shutdownConfig = providerConfig.ShutdownConfig
 
 	assert.True(t, shutdownFilter.rejectNewRequest())
-	result = shutdownFilter.OnResponse(nil, nil, protocol.NewBaseInvoker(*invokeUrl), invoc)
+	result = shutdownFilter.OnResponse(nil, nil, protocol.NewBaseInvoker(invokeUrl), invoc)
 
 	rejectHandler := &common2.OnlyLogRejectedExecutionHandler{}
 	extension.SetRejectedExecutionHandler("mock", func() filter.RejectedExecutionHandler {
diff --git a/filter/filter_impl/hystrix_filter_test.go b/filter/filter_impl/hystrix_filter_test.go
index eebbae5..4973ce7 100644
--- a/filter/filter_impl/hystrix_filter_test.go
+++ b/filter/filter_impl/hystrix_filter_test.go
@@ -18,6 +18,7 @@
 
 import (
 	"context"
+	"fmt"
 	"regexp"
 	"testing"
 )
@@ -29,6 +30,8 @@
 )
 
 import (
+	"github.com/apache/dubbo-go/common"
+	"github.com/apache/dubbo-go/common/constant"
 	"github.com/apache/dubbo-go/protocol"
 	"github.com/apache/dubbo-go/protocol/invocation"
 )
@@ -147,7 +150,11 @@
 
 func TestHystrixFilterInvokeSuccess(t *testing.T) {
 	hf := &HystrixFilter{}
-	result := hf.Invoke(context.Background(), &testMockSuccessInvoker{}, &invocation.RPCInvocation{})
+	testUrl, err := common.NewURL(
+		fmt.Sprintf("dubbo://%s:%d/com.ikurento.user.UserProvider", constant.LOCAL_HOST_VALUE, constant.DEFAULT_PORT))
+	assert.NoError(t, err)
+	testInvoker := testMockSuccessInvoker{*protocol.NewBaseInvoker(testUrl)}
+	result := hf.Invoke(context.Background(), &testInvoker, &invocation.RPCInvocation{})
 	assert.NotNil(t, result)
 	assert.NoError(t, result.Error())
 	assert.NotNil(t, result.Result())
@@ -155,7 +162,11 @@
 
 func TestHystrixFilterInvokeFail(t *testing.T) {
 	hf := &HystrixFilter{}
-	result := hf.Invoke(context.Background(), &testMockFailInvoker{}, &invocation.RPCInvocation{})
+	testUrl, err := common.NewURL(
+		fmt.Sprintf("dubbo://%s:%d/com.ikurento.user.UserProvider", constant.LOCAL_HOST_VALUE, constant.DEFAULT_PORT))
+	assert.NoError(t, err)
+	testInvoker := testMockFailInvoker{*protocol.NewBaseInvoker(testUrl)}
+	result := hf.Invoke(context.Background(), &testInvoker, &invocation.RPCInvocation{})
 	assert.NotNil(t, result)
 	assert.Error(t, result.Error())
 }
@@ -167,7 +178,11 @@
 	resChan := make(chan protocol.Result, 50)
 	for i := 0; i < 50; i++ {
 		go func() {
-			result := hf.Invoke(context.Background(), &testMockFailInvoker{}, &invocation.RPCInvocation{})
+			testUrl, err := common.NewURL(
+				fmt.Sprintf("dubbo://%s:%d/com.ikurento.user.UserProvider", constant.LOCAL_HOST_VALUE, constant.DEFAULT_PORT))
+			assert.NoError(t, err)
+			testInvoker := testMockSuccessInvoker{*protocol.NewBaseInvoker(testUrl)}
+			result := hf.Invoke(context.Background(), &testInvoker, &invocation.RPCInvocation{})
 			resChan <- result
 		}()
 	}
@@ -192,7 +207,11 @@
 	resChan := make(chan protocol.Result, 50)
 	for i := 0; i < 50; i++ {
 		go func() {
-			result := hf.Invoke(context.Background(), &testMockFailInvoker{}, &invocation.RPCInvocation{})
+			testUrl, err := common.NewURL(
+				fmt.Sprintf("dubbo://%s:%d/com.ikurento.user.UserProvider", constant.LOCAL_HOST_VALUE, constant.DEFAULT_PORT))
+			assert.NoError(t, err)
+			testInvoker := testMockSuccessInvoker{*protocol.NewBaseInvoker(testUrl)}
+			result := hf.Invoke(context.Background(), &testInvoker, &invocation.RPCInvocation{})
 			resChan <- result
 		}()
 	}
diff --git a/filter/filter_impl/sentinel_filter.go b/filter/filter_impl/sentinel_filter.go
index 86d6460..aec814d 100644
--- a/filter/filter_impl/sentinel_filter.go
+++ b/filter/filter_impl/sentinel_filter.go
@@ -229,7 +229,7 @@
 	return true
 }
 
-func getColonSeparatedKey(url common.URL) string {
+func getColonSeparatedKey(url *common.URL) string {
 	return fmt.Sprintf("%s:%s:%s",
 		url.Service(),
 		url.GetParam(constant.GROUP_KEY, ""),
diff --git a/filter/filter_impl/token_filter_test.go b/filter/filter_impl/token_filter_test.go
index cd1bba3..9ef8c98 100644
--- a/filter/filter_impl/token_filter_test.go
+++ b/filter/filter_impl/token_filter_test.go
@@ -43,7 +43,7 @@
 	attch := make(map[string]interface{}, 0)
 	attch[constant.TOKEN_KEY] = "ori_key"
 	result := filter.Invoke(context.Background(),
-		protocol.NewBaseInvoker(*url),
+		protocol.NewBaseInvoker(url),
 		invocation.NewRPCInvocation("MethodName",
 			[]interface{}{"OK"}, attch))
 	assert.Nil(t, result.Error())
@@ -56,7 +56,7 @@
 	testUrl := common.URL{}
 	attch := make(map[string]interface{}, 0)
 	attch[constant.TOKEN_KEY] = "ori_key"
-	result := filter.Invoke(context.Background(), protocol.NewBaseInvoker(testUrl), invocation.NewRPCInvocation("MethodName", []interface{}{"OK"}, attch))
+	result := filter.Invoke(context.Background(), protocol.NewBaseInvoker(&testUrl), invocation.NewRPCInvocation("MethodName", []interface{}{"OK"}, attch))
 	assert.Nil(t, result.Error())
 	assert.Nil(t, result.Result())
 }
@@ -68,7 +68,7 @@
 		common.WithParams(url.Values{}),
 		common.WithParamsValue(constant.TOKEN_KEY, "ori_key"))
 	attch := make(map[string]interface{}, 0)
-	result := filter.Invoke(context.Background(), protocol.NewBaseInvoker(*testUrl), invocation.NewRPCInvocation("MethodName", []interface{}{"OK"}, attch))
+	result := filter.Invoke(context.Background(), protocol.NewBaseInvoker(testUrl), invocation.NewRPCInvocation("MethodName", []interface{}{"OK"}, attch))
 	assert.NotNil(t, result.Error())
 }
 
@@ -81,6 +81,6 @@
 	attch := make(map[string]interface{}, 0)
 	attch[constant.TOKEN_KEY] = "err_key"
 	result := filter.Invoke(context.Background(),
-		protocol.NewBaseInvoker(*testUrl), invocation.NewRPCInvocation("MethodName", []interface{}{"OK"}, attch))
+		protocol.NewBaseInvoker(testUrl), invocation.NewRPCInvocation("MethodName", []interface{}{"OK"}, attch))
 	assert.NotNil(t, result.Error())
 }
diff --git a/filter/filter_impl/tps/tps_limiter_method_service.go b/filter/filter_impl/tps/tps_limiter_method_service.go
index 5761579..f0c2764 100644
--- a/filter/filter_impl/tps/tps_limiter_method_service.go
+++ b/filter/filter_impl/tps/tps_limiter_method_service.go
@@ -120,7 +120,7 @@
 // The key point is how to keep thread-safe
 // This implementation use concurrent map + loadOrStore to make implementation thread-safe
 // You can image that even multiple threads create limiter, but only one could store the limiter into tpsState
-func (limiter MethodServiceTpsLimiterImpl) IsAllowable(url common.URL, invocation protocol.Invocation) bool {
+func (limiter MethodServiceTpsLimiterImpl) IsAllowable(url *common.URL, invocation protocol.Invocation) bool {
 
 	methodConfigPrefix := "methods." + invocation.MethodName() + "."
 
@@ -176,7 +176,7 @@
 // If we can convert the methodLevelConfig to int64, return;
 // Or, we will try to look up server-level configuration and then convert it to int64
 func getLimitConfig(methodLevelConfig string,
-	url common.URL,
+	url *common.URL,
 	invocation protocol.Invocation,
 	configKey string,
 	defaultVal string) int64 {
diff --git a/filter/filter_impl/tps/tps_limiter_method_service_test.go b/filter/filter_impl/tps/tps_limiter_method_service_test.go
index 61f28e4..7435d9b 100644
--- a/filter/filter_impl/tps/tps_limiter_method_service_test.go
+++ b/filter/filter_impl/tps/tps_limiter_method_service_test.go
@@ -57,7 +57,7 @@
 	})
 
 	limiter := GetMethodServiceTpsLimiter()
-	result := limiter.IsAllowable(*invokeUrl, invoc)
+	result := limiter.IsAllowable(invokeUrl, invoc)
 	assert.True(t, result)
 }
 
@@ -73,7 +73,7 @@
 		common.WithParamsValue(constant.TPS_LIMIT_RATE_KEY, ""))
 
 	limiter := GetMethodServiceTpsLimiter()
-	result := limiter.IsAllowable(*invokeUrl, invoc)
+	result := limiter.IsAllowable(invokeUrl, invoc)
 	assert.True(t, result)
 }
 
@@ -106,7 +106,7 @@
 	})
 
 	limiter := GetMethodServiceTpsLimiter()
-	result := limiter.IsAllowable(*invokeUrl, invoc)
+	result := limiter.IsAllowable(invokeUrl, invoc)
 	assert.True(t, result)
 }
 
@@ -136,7 +136,7 @@
 	})
 
 	limiter := GetMethodServiceTpsLimiter()
-	result := limiter.IsAllowable(*invokeUrl, invoc)
+	result := limiter.IsAllowable(invokeUrl, invoc)
 	assert.True(t, result)
 }
 
diff --git a/filter/filter_impl/tps/tps_limiter_mock.go b/filter/filter_impl/tps/tps_limiter_mock.go
index b49084f..34c2790 100644
--- a/filter/filter_impl/tps/tps_limiter_mock.go
+++ b/filter/filter_impl/tps/tps_limiter_mock.go
@@ -58,7 +58,7 @@
 }
 
 // IsAllowable mocks base method
-func (m *MockTpsLimiter) IsAllowable(arg0 common.URL, arg1 protocol.Invocation) bool {
+func (m *MockTpsLimiter) IsAllowable(arg0 *common.URL, arg1 protocol.Invocation) bool {
 	m.ctrl.T.Helper()
 	ret := m.ctrl.Call(m, "IsAllowable", arg0, arg1)
 	ret0, _ := ret[0].(bool)
diff --git a/filter/filter_impl/tps_limit_filter_test.go b/filter/filter_impl/tps_limit_filter_test.go
index da0fc48..88e7781 100644
--- a/filter/filter_impl/tps_limit_filter_test.go
+++ b/filter/filter_impl/tps_limit_filter_test.go
@@ -47,7 +47,7 @@
 	attch := make(map[string]interface{}, 0)
 
 	result := tpsFilter.Invoke(context.Background(),
-		protocol.NewBaseInvoker(*invokeUrl),
+		protocol.NewBaseInvoker(invokeUrl),
 		invocation.NewRPCInvocation("MethodName",
 			[]interface{}{"OK"}, attch))
 	assert.Nil(t, result.Error())
@@ -71,7 +71,7 @@
 	attch := make(map[string]interface{}, 0)
 
 	result := tpsFilter.Invoke(context.Background(),
-		protocol.NewBaseInvoker(*invokeUrl),
+		protocol.NewBaseInvoker(invokeUrl),
 		invocation.NewRPCInvocation("MethodName",
 			[]interface{}{"OK"}, attch))
 	assert.Nil(t, result.Error())
@@ -102,7 +102,9 @@
 	attch := make(map[string]interface{}, 0)
 
 	result := tpsFilter.Invoke(context.Background(),
-		protocol.NewBaseInvoker(*invokeUrl), invocation.NewRPCInvocation("MethodName", []interface{}{"OK"}, attch))
+		protocol.NewBaseInvoker(
+
+			invokeUrl), invocation.NewRPCInvocation("MethodName", []interface{}{"OK"}, attch))
 	assert.Nil(t, result.Error())
 	assert.Nil(t, result.Result())
 }
diff --git a/filter/handler/rejected_execution_handler_mock.go b/filter/handler/rejected_execution_handler_mock.go
index bff5476..5f2f458 100644
--- a/filter/handler/rejected_execution_handler_mock.go
+++ b/filter/handler/rejected_execution_handler_mock.go
@@ -58,7 +58,7 @@
 }
 
 // RejectedExecution mocks base method
-func (m *MockRejectedExecutionHandler) RejectedExecution(url common.URL, invocation protocol.Invocation) protocol.Result {
+func (m *MockRejectedExecutionHandler) RejectedExecution(url *common.URL, invocation protocol.Invocation) protocol.Result {
 	m.ctrl.T.Helper()
 	ret := m.ctrl.Call(m, "RejectedExecution", url, invocation)
 	ret0, _ := ret[0].(protocol.Result)
diff --git a/filter/handler/rejected_execution_handler_only_log.go b/filter/handler/rejected_execution_handler_only_log.go
index 52ac176..5242b5b 100644
--- a/filter/handler/rejected_execution_handler_only_log.go
+++ b/filter/handler/rejected_execution_handler_only_log.go
@@ -63,7 +63,7 @@
 }
 
 // RejectedExecution will do nothing, it only log the invocation.
-func (handler *OnlyLogRejectedExecutionHandler) RejectedExecution(url common.URL,
+func (handler *OnlyLogRejectedExecutionHandler) RejectedExecution(url *common.URL,
 	_ protocol.Invocation) protocol.Result {
 
 	logger.Errorf("The invocation was rejected. url: %s", url.String())
diff --git a/filter/handler/rejected_execution_handler_only_log_test.go b/filter/handler/rejected_execution_handler_only_log_test.go
index 409f09f..7aa4aff 100644
--- a/filter/handler/rejected_execution_handler_only_log_test.go
+++ b/filter/handler/rejected_execution_handler_only_log_test.go
@@ -31,5 +31,5 @@
 	invokeUrl := common.NewURLWithOptions(
 		common.WithParams(url.Values{}),
 		common.WithParamsValue(constant.INTERFACE_KEY, "methodName"))
-	handler.RejectedExecution(*invokeUrl, nil)
+	handler.RejectedExecution(invokeUrl, nil)
 }
diff --git a/filter/rejected_execution_handler.go b/filter/rejected_execution_handler.go
index 3d1e1c1..73ac3d3 100644
--- a/filter/rejected_execution_handler.go
+++ b/filter/rejected_execution_handler.go
@@ -33,5 +33,5 @@
 type RejectedExecutionHandler interface {
 
 	// RejectedExecution will be called if the invocation was rejected by some component.
-	RejectedExecution(url common.URL, invocation protocol.Invocation) protocol.Result
+	RejectedExecution(url *common.URL, invocation protocol.Invocation) protocol.Result
 }
diff --git a/filter/tps_limiter.go b/filter/tps_limiter.go
index 8385d7b..6f2466c 100644
--- a/filter/tps_limiter.go
+++ b/filter/tps_limiter.go
@@ -35,5 +35,5 @@
  */
 type TpsLimiter interface {
 	// IsAllowable will check whether this invocation should be enabled for further process
-	IsAllowable(common.URL, protocol.Invocation) bool
+	IsAllowable(*common.URL, protocol.Invocation) bool
 }
diff --git a/go.mod b/go.mod
index 317431f..94509de 100644
--- a/go.mod
+++ b/go.mod
@@ -2,23 +2,24 @@
 
 require (
 	github.com/NYTimes/gziphandler v1.1.1 // indirect
-	github.com/Workiva/go-datastructures v1.0.50
+	github.com/RoaringBitmap/roaring v0.5.5
+	github.com/Workiva/go-datastructures v1.0.52
 	github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5
 	github.com/alibaba/sentinel-golang v0.6.2
 	github.com/apache/dubbo-getty v1.3.10
 	github.com/apache/dubbo-go-hessian2 v1.7.0
 	github.com/coreos/etcd v3.3.25+incompatible
-	github.com/creasty/defaults v1.3.0
+	github.com/creasty/defaults v1.5.1
 	github.com/dubbogo/go-zookeeper v1.0.2
-	github.com/dubbogo/gost v1.9.1
+	github.com/dubbogo/gost v1.9.5
 	github.com/elazarl/go-bindata-assetfs v1.0.0 // indirect
-	github.com/emicklei/go-restful/v3 v3.0.0
+	github.com/emicklei/go-restful/v3 v3.4.0
 	github.com/frankban/quicktest v1.4.1 // indirect
-	github.com/fsnotify/fsnotify v1.4.7
+	github.com/fsnotify/fsnotify v1.4.9
 	github.com/go-co-op/gocron v0.1.1
-	github.com/go-resty/resty/v2 v2.1.0
-	github.com/golang/mock v1.3.1
-	github.com/golang/protobuf v1.4.0
+	github.com/go-resty/resty/v2 v2.3.0
+	github.com/golang/mock v1.4.4
+	github.com/golang/protobuf v1.4.3
 	github.com/grpc-ecosystem/grpc-opentracing v0.0.0-20180507213350-8e809c8a8645
 	github.com/hashicorp/consul v1.8.0
 	github.com/hashicorp/consul/api v1.5.0
@@ -26,22 +27,22 @@
 	github.com/hashicorp/vault/api v1.0.5-0.20191108163347-bdd38fca2cff // indirect
 	github.com/hashicorp/vault/sdk v0.1.14-0.20191112033314-390e96e22eb2
 	github.com/jinzhu/copier v0.0.0-20190625015134-976e0346caa8
-	github.com/magiconair/properties v1.8.1
-	github.com/mitchellh/mapstructure v1.2.3
+	github.com/magiconair/properties v1.8.4
+	github.com/mitchellh/mapstructure v1.4.0
 	github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd
-	github.com/nacos-group/nacos-sdk-go v1.0.0
-	github.com/opentracing/opentracing-go v1.1.0
+	github.com/nacos-group/nacos-sdk-go v1.0.1
+	github.com/opentracing/opentracing-go v1.2.0
 	github.com/pierrec/lz4 v2.2.6+incompatible // indirect
 	github.com/pkg/errors v0.9.1
-	github.com/prometheus/client_golang v1.1.0
+	github.com/prometheus/client_golang v1.8.0
 	github.com/satori/go.uuid v1.2.1-0.20181028125025-b2ce2384e17b
 	github.com/stretchr/objx v0.2.0 // indirect
-	github.com/stretchr/testify v1.5.1
-	github.com/zouyx/agollo/v3 v3.4.4
-	go.uber.org/atomic v1.6.0
-	go.uber.org/zap v1.15.0
+	github.com/stretchr/testify v1.6.1
+	github.com/zouyx/agollo/v3 v3.4.5
+	go.uber.org/atomic v1.7.0
+	go.uber.org/zap v1.16.0
 	google.golang.org/grpc v1.26.0
-	gopkg.in/yaml.v2 v2.2.8
+	gopkg.in/yaml.v2 v2.4.0
 	k8s.io/api v0.16.9
 	k8s.io/apimachinery v0.16.9
 	k8s.io/client-go v0.16.9
@@ -50,6 +51,7 @@
 
 replace (
 	github.com/envoyproxy/go-control-plane => github.com/envoyproxy/go-control-plane v0.8.0
+	github.com/shirou/gopsutil => github.com/shirou/gopsutil v0.0.0-20181107111621-48177ef5f880
 	launchpad.net/gocheck => github.com/go-check/check v0.0.0-20140225173054-eb6ee6f84d0a
 )
 
diff --git a/go.sum b/go.sum
index 20d5345..201f03e 100644
--- a/go.sum
+++ b/go.sum
@@ -62,6 +62,7 @@
 github.com/DataDog/datadog-go v2.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ=
 github.com/DataDog/datadog-go v3.2.0+incompatible h1:qSG2N4FghB1He/r2mFrWKCaL7dXCilEuNEeAn20fdD4=
 github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ=
+github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
 github.com/Microsoft/go-winio v0.4.3/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA=
 github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5 h1:ygIc8M6trr62pF5DucadTWGdEB4mEyvzi0e2nbcmcyA=
 github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5/go.mod h1:tTuCMEN+UleMWgg9dVx4Hu52b1bJo+59jBh3ajtinzw=
@@ -74,14 +75,17 @@
 github.com/OpenDNS/vegadns2client v0.0.0-20180418235048-a3fa4a771d87/go.mod h1:iGLljf5n9GjT6kc0HBvyI1nOKnGQbNB66VzSNbK5iks=
 github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
 github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
+github.com/RoaringBitmap/roaring v0.5.5 h1:naNqvO1mNnghk2UvcsqnzHDBn9DRbCIRy94GmDTRVTQ=
+github.com/RoaringBitmap/roaring v0.5.5/go.mod h1:puNo5VdzwbaIQxSiDIwfXl4Hnc+fbovcX4IW/dSTtUk=
 github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
 github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
 github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6 h1:fLjPD/aNc3UIOA6tDi6QXUemppXK3P9BI7mr2hd6gx8=
 github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg=
 github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d h1:G0m3OIz70MZUWq3EgK3CesDbo8upS2Vm9/P3FtgI+Jk=
 github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg=
-github.com/Workiva/go-datastructures v1.0.50 h1:slDmfW6KCHcC7U+LP3DDBbm4fqTwZGn1beOFPfGaLvo=
-github.com/Workiva/go-datastructures v1.0.50/go.mod h1:Z+F2Rca0qCsVYDS8z7bAGm8f3UkzuWYS/oBZz5a7VVA=
+github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g=
+github.com/Workiva/go-datastructures v1.0.52 h1:PLSK6pwn8mYdaoaCZEMsXBpBotr4HHn9abU0yMQt0NI=
+github.com/Workiva/go-datastructures v1.0.52/go.mod h1:Z+F2Rca0qCsVYDS8z7bAGm8f3UkzuWYS/oBZz5a7VVA=
 github.com/abdullin/seq v0.0.0-20160510034733-d5467c17e7af h1:DBNMBMuMiWYu0b+8KMJuWmfCkcxl09JwdlqwDZZ6U14=
 github.com/abdullin/seq v0.0.0-20160510034733-d5467c17e7af/go.mod h1:5Jv4cbFiHJMsVxt52+i0Ha45fjshj6wxYr1r19tB9bw=
 github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5 h1:rFw4nCn9iMW+Vajsk51NtYIcwSTkXr+JGrMd36kTDJw=
@@ -90,7 +94,10 @@
 github.com/alangpierce/go-forceexport v0.0.0-20160317203124-8f1d6941cd75/go.mod h1:uAXEEpARkRhCZfEvy/y0Jcc888f9tHCc1W7/UeEtreE=
 github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs=
 github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
+github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
 github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
+github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
+github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
 github.com/alibaba/sentinel-golang v0.6.2 h1:1OjjpljJbNKWp9p5RJKxOqS1gHGZPUWPlCcokv5xYJs=
 github.com/alibaba/sentinel-golang v0.6.2/go.mod h1:5jemKdyCQCKVf+quEia53fo9a17OSe+wnl9HX2NbNpc=
 github.com/aliyun/alibaba-cloud-sdk-go v0.0.0-20190808125512-07798873deee/go.mod h1:myCDvQSzCW+wB1WAlocEru4wMGJxy+vlxHdhegi1CDQ=
@@ -103,6 +110,7 @@
 github.com/apache/dubbo-go-hessian2 v1.7.0 h1:u2XxIuepu/zb6JcGZc7EbvKboXdKoJbf7rbmeq6SF1w=
 github.com/apache/dubbo-go-hessian2 v1.7.0/go.mod h1:7rEw9guWABQa6Aqb8HeZcsYPHsOS7XT1qtJvkmI6c5w=
 github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
+github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
 github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e h1:QEF07wC0T1rKkctt1RINW/+RMTVmiwxETico2l3gxJA=
 github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
 github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
@@ -114,9 +122,14 @@
 github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI=
 github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
 github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
+github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A=
+github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU=
 github.com/aws/aws-sdk-go v1.23.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
 github.com/aws/aws-sdk-go v1.25.41 h1:/hj7nZ0586wFqpwjNpzWiUTwtaMgxAZNZKHay80MdXw=
 github.com/aws/aws-sdk-go v1.25.41/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
+github.com/aws/aws-sdk-go v1.27.0 h1:0xphMHGMLBrPMfxR2AmVjZKcMEESEgWF8Kru94BNByk=
+github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
+github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g=
 github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f/go.mod h1:AuiFmCCPBSrqvVMvuqFuk0qogytodnVFVSN5CeJB8Gc=
 github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
 github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
@@ -134,17 +147,25 @@
 github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s=
 github.com/bwmarrin/discordgo v0.20.2/go.mod h1:O9S4p+ofTFwB02em7jkpkV8M3R0/PUVOwN61zSZ0r4Q=
 github.com/caddyserver/certmagic v0.10.6/go.mod h1:Y8jcUBctgk/IhpAzlHKfimZNyXCkfGgRTC0orl8gROQ=
+github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ=
+github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
 github.com/cenkalti/backoff/v4 v4.0.0/go.mod h1:eEew/i+1Q6OrCDZh3WiXYv3+nJwBASZ8Bog/87DQnVg=
 github.com/census-instrumentation/opencensus-proto v0.2.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
+github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
 github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
+github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY=
+github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
 github.com/cheekybits/genny v1.0.0/go.mod h1:+tQajlRqAUrPI7DOSpB0XAqZYtQakVtB7wXkRAgjxjQ=
 github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible h1:C29Ae4G5GtYyYMm1aztcyj/J5ckgJm2zwdDajFbx1NY=
 github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag=
 github.com/circonus-labs/circonusllhist v0.1.3 h1:TJH+oke8D16535+jHExHj4nQvzlZrj7ug5D7I/orNUA=
 github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I=
+github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE=
 github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
 github.com/cloudflare/cloudflare-go v0.10.2/go.mod h1:qhVI5MKwBGhdNU89ZRz2plgYutcJ5PCekLxXn56w6SY=
 github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ=
+github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8=
+github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI=
 github.com/containerd/cgroups v0.0.0-20190919134610-bf292b21730f/go.mod h1:OApqhQ4XNSNC13gXIwDjhOQxjWa/NxkwZXJ1EvqT0ko=
 github.com/containerd/console v0.0.0-20180822173158-c12b1e7919c1/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw=
 github.com/containerd/containerd v1.3.0-beta.2.0.20190828155532-0293cbd26c69/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
@@ -171,18 +192,21 @@
 github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
 github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM=
 github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
+github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
 github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
 github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f h1:JOrtw2xFKzlg+cbHpyrpLDmnN1HqhBfnX7WDiW7eG2c=
 github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
+github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
 github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f h1:lBNOc5arjvs8E5mO2tbpBpLoyyu8B6e44T7hJy6potg=
 github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
 github.com/cpu/goacmedns v0.0.1/go.mod h1:sesf/pNnCYwUevQEQfEwY0Y3DydlQWSGZbaMElOWxok=
 github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
 github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
 github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
+github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
 github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
-github.com/creasty/defaults v1.3.0 h1:uG+RAxYbJgOPCOdKEcec9ZJXeva7Y6mj/8egdzwmLtw=
-github.com/creasty/defaults v1.3.0/go.mod h1:CIEEvs7oIVZm30R8VxtFJs+4k201gReYyuYHJxZc68I=
+github.com/creasty/defaults v1.5.1 h1:j8WexcS3d/t4ZmllX4GEkl4wIB/trOr035ajcLHCISM=
+github.com/creasty/defaults v1.5.1/go.mod h1:FPZ+Y0WNrbqOVw+c6av63eyHUAl6pMHZwqLPvXUZGfY=
 github.com/davecgh/go-spew v0.0.0-20151105211317-5215b55f46b2/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
@@ -211,13 +235,15 @@
 github.com/dubbogo/go-zookeeper v1.0.2 h1:xmEnPL8SlCe3/+J5ZR9e8qE35LmFVYe8VVpDakjNM4A=
 github.com/dubbogo/go-zookeeper v1.0.2/go.mod h1:fn6n2CAEer3novYgk9ULLwAjuV8/g4DdC2ENwRb6E+c=
 github.com/dubbogo/gost v1.9.0/go.mod h1:pPTjVyoJan3aPxBPNUX0ADkXjPibLo+/Ib0/fADXSG8=
-github.com/dubbogo/gost v1.9.1 h1:0/PPFo13zPbjt4Ia0zYWMFi3C6rAe9X7O1J2Iv+BHNM=
-github.com/dubbogo/gost v1.9.1/go.mod h1:pPTjVyoJan3aPxBPNUX0ADkXjPibLo+/Ib0/fADXSG8=
+github.com/dubbogo/gost v1.9.5 h1:UeG4y0O55lR3dzgdmCm/7bMWvpKrlpR7fsfKjrcXq/g=
+github.com/dubbogo/gost v1.9.5/go.mod h1:QNM5RaeRdNWehUu8S0hUP5Qa8QUfGf6KH1JhqOVFvEI=
+github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
 github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo=
 github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
 github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs=
 github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU=
 github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
+github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
 github.com/ef-ds/deque v1.0.4-0.20190904040645-54cb57c252a1/go.mod h1:HvODWzv6Y6kBf3Ah2WzN1bHjDUezGLaAhwuWVwfpEJs=
 github.com/elazarl/go-bindata-assetfs v0.0.0-20160803192304-e1a2a7ec64b0/go.mod h1:v+YaWX3bdea5J/mo8dSETolEo7R71Vk1u8bnjau5yw4=
 github.com/elazarl/go-bindata-assetfs v1.0.0 h1:G/bYguwHIzWq9ZoyUQqrjTmJbbYn3j3CKKpKinvZLFk=
@@ -225,8 +251,8 @@
 github.com/elazarl/goproxy v0.0.0-20170405201442-c4fc26588b6e/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc=
 github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633 h1:H2pdYOb3KQ1/YsqVWoWNLQO+fusocsw354rqGTZtAgw=
 github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
-github.com/emicklei/go-restful/v3 v3.0.0 h1:Duxxa4x0WIHW3bYEDmoAPNjmy8Rbqn+utcF74dlF/G8=
-github.com/emicklei/go-restful/v3 v3.0.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
+github.com/emicklei/go-restful/v3 v3.4.0 h1:IIDhql3oyWZj1ay2xBZGb4sTOWMad0HVW8rwhVxN/Yk=
+github.com/emicklei/go-restful/v3 v3.4.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
 github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o=
 github.com/envoyproxy/go-control-plane v0.8.0 h1:uE6Fp4fOcAJdc1wTQXLJ+SYistkbG1dNoi6Zs1+Ybvk=
 github.com/envoyproxy/go-control-plane v0.8.0/go.mod h1:GSSbY9P1neVhdY7G4wu+IK1rk/dqhiCC/4ExuWJZVuk=
@@ -246,15 +272,17 @@
 github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
 github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
 github.com/forestgiant/sliceutil v0.0.0-20160425183142-94783f95db6c/go.mod h1:pFdJbAhRf7rh6YYMUdIQGyzne6zYL1tCUW8QV2B3UfY=
+github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4=
+github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20=
 github.com/frankban/quicktest v1.4.1 h1:Wv2VwvNn73pAdFIVUQRXYDFp31lXKbqblIXo/Q5GPSg=
 github.com/frankban/quicktest v1.4.1/go.mod h1:36zfPVQyHxymz4cH7wlDmVwDrJuljRB60qkgn7rorfQ=
 github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
 github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
+github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
+github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
 github.com/fsouza/go-dockerclient v1.6.0/go.mod h1:YWwtNPuL4XTX1SKJQk86cWPmmqwx+4np9qfPbb+znGc=
 github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
 github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
-github.com/ghodss/yaml v1.0.1-0.20190212211648-25d852aebe32 h1:Mn26/9ZMNWSw9C9ERFA1PUxfmGpolnw2v0bKOREu5ew=
-github.com/ghodss/yaml v1.0.1-0.20190212211648-25d852aebe32/go.mod h1:GIjDIg/heH5DOkXY3YJ/wNhfHsQHoXGjl8G8amsYQ1I=
 github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
 github.com/gin-gonic/gin v1.5.0/go.mod h1:Nd6IXA8m5kNZdNEHMBd93KT+mdY3+bewLgRvmCsR2Do=
 github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
@@ -278,10 +306,13 @@
 github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
 github.com/go-ini/ini v1.44.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8=
 github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
+github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
+github.com/go-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgOZ7o=
 github.com/go-ldap/ldap v3.0.2+incompatible/go.mod h1:qfd9rJvER9Q0/D/Sqn1DfHRoBp40uXYvFoEVrNEPqRc=
 github.com/go-ldap/ldap/v3 v3.1.3/go.mod h1:3rbOH3jRS2u6jg2rJnKAMLE/xQyCKIveG2Sa/Cohzb8=
 github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
 github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
+github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
 github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas=
 github.com/go-ole/go-ole v1.2.1 h1:2lOsA72HgjxAuMlKpFiCbHTvu44PIVkZ5hqm3RSdI/E=
 github.com/go-ole/go-ole v1.2.1/go.mod h1:7FAglXiTm7HKlQRDeOQ6ZNUHidzCWXuZWq/1dTyBNF8=
@@ -294,8 +325,9 @@
 github.com/go-playground/locales v0.12.1/go.mod h1:IUMDtCfWo/w/mtMfIE/IG2K+Ey3ygWanZIBtBW0W2TM=
 github.com/go-playground/universal-translator v0.16.0/go.mod h1:1AnU7NaIRDWWzGEKwgtJRd2xk99HeFyHw3yid4rvQIY=
 github.com/go-redis/redis v6.15.5+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA=
-github.com/go-resty/resty/v2 v2.1.0 h1:Z6IefCpUMfnvItVJaJXWv/pMiiD11So35QgwEELsldE=
-github.com/go-resty/resty/v2 v2.1.0/go.mod h1:dZGr0i9PLlaaTD4H/hoZIDjQ+r6xq8mgbRzHZf7f2J8=
+github.com/go-resty/resty/v2 v2.3.0 h1:JOOeAvjSlapTT92p8xiS19Zxev1neGikoHsXJeOq8So=
+github.com/go-resty/resty/v2 v2.3.0/go.mod h1:UpN9CgLZNsv4e9XG50UU8xdI0F43UQ4HmxLBDwaroHU=
+github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
 github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
 github.com/go-telegram-bot-api/telegram-bot-api v4.6.4+incompatible/go.mod h1:qf9acutJ8cwBUhm1bqgz6Bei9/C/c93FPDljKWwsOgM=
 github.com/go-test/deep v1.0.2-0.20181118220953-042da051cf31/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA=
@@ -320,12 +352,15 @@
 github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
 github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
 github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
+github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
 github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e h1:1r7pUrabqp18hOBcwBwiTsbnFeTZHV9eER/QT5JVZxY=
 github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
 github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
 github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
 github.com/golang/mock v1.3.1 h1:qGJ6qTW+x6xX/my+8YUVl4WNpX9B7+/l2tRsHGZ7f2s=
 github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
+github.com/golang/mock v1.4.4 h1:l75CXGRSwbaYNpl/Z2X1XIIAMSCquvXgpVZDhwEIJsc=
+github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
 github.com/golang/protobuf v0.0.0-20161109072736-4bd1920723d7/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
 github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
 github.com/golang/protobuf v1.3.0/go.mod h1:Qd/q+1AKNOZr9uGQzbzCmRO6sUih6GTPZv6a1/R87v0=
@@ -339,6 +374,9 @@
 github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
 github.com/golang/protobuf v1.4.0 h1:oOuy+ugB+P/kBdUnG5QaMXSIyJ1q38wWSojYCb3z5VQ=
 github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
+github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
+github.com/golang/protobuf v1.4.3 h1:JjCZWpVbqXDqFVmTfYWEVTMIYrL/NPdPSCHPJ0T/raM=
+github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
 github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
 github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4=
 github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
@@ -363,6 +401,7 @@
 github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
 github.com/google/tcpproxy v0.0.0-20180808230851-dfa16c61dad2 h1:AtvtonGEH/fZK0XPNNBdB6swgy7Iudfx88wzyIpwqJ8=
 github.com/google/tcpproxy v0.0.0-20180808230851-dfa16c61dad2/go.mod h1:DavVbd41y+b7ukKDmlnPR4nGYmkWXR6vHUkjQNiHPBs=
+github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
 github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=
 github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
 github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
@@ -377,10 +416,13 @@
 github.com/gophercloud/gophercloud v0.3.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8=
 github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
 github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
+github.com/gopherjs/gopherjs v0.0.0-20190910122728-9d188e94fb99 h1:twflg0XRTjwKpxb/jFExr4HGq6on2dEOmnL6FV+fgPw=
+github.com/gopherjs/gopherjs v0.0.0-20190910122728-9d188e94fb99/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
 github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
 github.com/gorilla/handlers v1.4.2/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ=
 github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
 github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
+github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
 github.com/gorilla/websocket v1.2.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
 github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
 github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
@@ -388,6 +430,7 @@
 github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
 github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
 github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
+github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
 github.com/grpc-ecosystem/go-grpc-middleware v1.1.0 h1:THDBEeQ9xZ8JEaCLyLQqXMMdRqNr0QAUJTIkQAUtFjg=
 github.com/grpc-ecosystem/go-grpc-middleware v1.1.0/go.mod h1:f5nM7jw/oeRSadq3xCzHAvxcr8HZnzsqU6ILg/0NiiE=
 github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho=
@@ -402,10 +445,12 @@
 github.com/hashicorp/consul v1.8.0 h1:yRKMKZyPLqUxl37t4nFt5OuGmTXoFhTJrakhfnYKCYA=
 github.com/hashicorp/consul v1.8.0/go.mod h1:Gg9/UgAQ9rdY3CTvzQZ6g2jcIb7NlIfjI+0pvLk5D1A=
 github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q=
+github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE=
 github.com/hashicorp/consul/api v1.4.0/go.mod h1:xc8u05kyMa3Wjr9eEAsIAo3dg8+LywT5E/Cl7cNS5nU=
 github.com/hashicorp/consul/api v1.5.0 h1:Yo2bneoGy68A7aNwmuETFnPhjyBEm7n3vzRacEVMjvI=
 github.com/hashicorp/consul/api v1.5.0/go.mod h1:LqwrLNW876eYSuUOo4ZLHBcdKc038txr/IMfbLPATa4=
 github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
+github.com/hashicorp/consul/sdk v0.3.0/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
 github.com/hashicorp/consul/sdk v0.4.0/go.mod h1:fY08Y9z5SvJqevyZNy6WWPXiG3KwBPAvlcdx16zZ0fM=
 github.com/hashicorp/consul/sdk v0.5.0 h1:WC4594Wp/LkEeML/OdQKEC1yqBmEYkRp6i7X5u0zDAs=
 github.com/hashicorp/consul/sdk v0.5.0/go.mod h1:fY08Y9z5SvJqevyZNy6WWPXiG3KwBPAvlcdx16zZ0fM=
@@ -508,6 +553,7 @@
 github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM=
 github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
 github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
+github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg=
 github.com/iij/doapi v0.0.0-20190504054126-0bbf12d6d7df/go.mod h1:QMZY7/J/KSQEhKWFeDesPjMj+wCHReeknARU3wqlyN4=
 github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
 github.com/imdario/mergo v0.3.6 h1:xTNEAn+kxVO7dTZGu0CegyqKZmoWFI0rF8UxjlB2d28=
@@ -515,6 +561,7 @@
 github.com/imdario/mergo v0.3.9 h1:UauaLniWCFHWd+Jp9oCEkTBj8VO/9DKg3PV3VCNMDIg=
 github.com/imdario/mergo v0.3.9/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
 github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
+github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo=
 github.com/jackc/fake v0.0.0-20150926172116-812a484cc733/go.mod h1:WrMFNQdiFJ80sQsxDoMokWK1W5TQtxBFNpzWTD84ibQ=
 github.com/jackc/pgx v3.3.0+incompatible/go.mod h1:0ZGrqGqkRlliWnWB4zKnWtjbSWbGkVEFm4TeybAXq+I=
 github.com/jarcoal/httpmock v0.0.0-20180424175123-9c70cfe4a1da h1:FjHUJJ7oBW4G/9j1KzlHaXL09LyMVM9rupS39lncbXk=
@@ -532,17 +579,24 @@
 github.com/joyent/triton-go v0.0.0-20180628001255-830d2b111e62/go.mod h1:U+RSyWxWd04xTqnuOQxnai7XGS2PrPY2cfGoDKtMHjA=
 github.com/joyent/triton-go v1.7.1-0.20200416154420-6801d15b779f h1:ENpDacvnr8faw5ugQmEF1QYk+f/Y9lXFvuYmRxykago=
 github.com/joyent/triton-go v1.7.1-0.20200416154420-6801d15b779f/go.mod h1:KDSfL7qe5ZfQqvlDMkVjCztbmcpp/c8M77vhQP8ZPvk=
+github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
 github.com/json-iterator/go v0.0.0-20180612202835-f2b4162afba3/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
 github.com/json-iterator/go v1.1.5/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
 github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
 github.com/json-iterator/go v1.1.7 h1:KfgG9LzI+pYjr4xvmz/5H4FXjokeP+rlHLhv3iH62Fo=
 github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
+github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
 github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns=
 github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
+github.com/json-iterator/go v1.1.10 h1:Kz6Cvnvv2wGdaG/V8yMvfkmNiXq9Ya2KUv4rouJJr68=
+github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
 github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
 github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
 github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
 github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
+github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
+github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88/go.mod h1:3w7q1U84EfirKl04SVQ/s7nPm1ZPhiXd34z40TNz36k=
+github.com/k0kubun/pp v3.0.1+incompatible/go.mod h1:GWse8YhT0p8pT4ir3ZgBbfZild3tgzSScAn6HmfYukg=
 github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
 github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
 github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
@@ -552,6 +606,8 @@
 github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
 github.com/konsorten/go-windows-terminal-sequences v1.0.2 h1:DB17ag19krx9CFsz4o3enTrPXyIXCl+2iCXH/aMAp9s=
 github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
+github.com/konsorten/go-windows-terminal-sequences v1.0.3 h1:CE8S1cTafDpPvMhIxNJKvHsGVBgn1xWYf1NbHQhywc8=
+github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
 github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
 github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
 github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs=
@@ -574,15 +630,20 @@
 github.com/lestrrat/go-strftime v0.0.0-20180220042222-ba3bf9c1d042/go.mod h1:TPpsiPUEh0zFL1Snz4crhMlBe60PYxRHr5oFF3rRYg0=
 github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
 github.com/lib/pq v1.3.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
+github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM=
+github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4=
 github.com/linode/linodego v0.7.1 h1:4WZmMpSA2NRwlPZcc0+4Gyn7rr99Evk9bnr0B3gXRKE=
 github.com/linode/linodego v0.7.1/go.mod h1:ga11n3ivecUrPCHN0rANxKmfWBJVkOXfLMZinAbj2sY=
 github.com/linode/linodego v0.10.0 h1:AMdb82HVgY8o3mjBXJcUv9B+fnJjfDMn2rNRGbX+jvM=
 github.com/linode/linodego v0.10.0/go.mod h1:cziNP7pbvE3mXIPneHj0oRY8L1WtGEIKlZ8LANE4eXA=
 github.com/liquidweb/liquidweb-go v1.6.0/go.mod h1:UDcVnAMDkZxpw4Y7NOHkqoeiGacVLEIG/i5J9cyixzQ=
 github.com/lucas-clemente/quic-go v0.14.1/go.mod h1:Vn3/Fb0/77b02SGhQk36KzOUmXgVpFfizUfW5WMaqyU=
+github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ=
 github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
 github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4=
 github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
+github.com/magiconair/properties v1.8.4 h1:8KGKTcQQGm0Kv7vEbKFErAoAOFyyacLStRtQSeYtvkY=
+github.com/magiconair/properties v1.8.4/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=
 github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
 github.com/marten-seemann/chacha20 v0.2.0/go.mod h1:HSdjFau7GzYRj+ahFNwsO3ouVJr1HFkWoEwNDb4TMtE=
 github.com/marten-seemann/qpack v0.1.0/go.mod h1:LFt1NU/Ptjip0C2CPkhimBz5CGE3WGDAUWqna+CNTrI=
@@ -592,7 +653,10 @@
 github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
 github.com/mattn/go-colorable v0.1.6 h1:6Su7aK7lXmJ/U79bYtBjLNaha4Fs1Rg9plHpcH+vvnE=
 github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
+github.com/mattn/go-colorable v0.1.7 h1:bQGKb3vps/j0E9GfJQ03JyhRuxsvdAanXlT9BTw3mdw=
+github.com/mattn/go-colorable v0.1.7/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
 github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
+github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
 github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
 github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ=
 github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84=
@@ -636,6 +700,8 @@
 github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
 github.com/mitchellh/mapstructure v1.2.3 h1:f/MjBEBDLttYCGfRaKBbKSRVF5aV2O6fnBpzknuE3jU=
 github.com/mitchellh/mapstructure v1.2.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
+github.com/mitchellh/mapstructure v1.4.0 h1:7ks8ZkOP5/ujthUsT07rNv+nkLXCQWKNHuwzOAesEks=
+github.com/mitchellh/mapstructure v1.4.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
 github.com/mitchellh/pointerstructure v1.0.0 h1:ATSdz4NWrmWPOF1CeCBU4sMCno2hgqdbSrRPFWQSVZI=
 github.com/mitchellh/pointerstructure v1.0.0/go.mod h1:k4XwG94++jLVsSiTxo7qdIfXA9pj9EAeo0QsNNJOLZ8=
 github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
@@ -649,15 +715,24 @@
 github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
 github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
 github.com/morikuni/aec v0.0.0-20170113033406-39771216ff4c/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
+github.com/mschoch/smat v0.0.0-20160514031455-90eadee771ae h1:VeRdUYdCw49yizlSbMEn2SZ+gT+3IUKx8BqxyQdz+BY=
+github.com/mschoch/smat v0.0.0-20160514031455-90eadee771ae/go.mod h1:qAyveg+e4CE+eKJXWVjKXM4ck2QobLqTDytGJbLLhJg=
 github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
 github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
+github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
 github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw=
 github.com/nacos-group/nacos-sdk-go v1.0.0 h1:CufUF7DZca2ZzIrJtMMCDih1sA58BWCglArLMCZArUc=
 github.com/nacos-group/nacos-sdk-go v1.0.0/go.mod h1:hlAPn3UdzlxIlSILAyOXKxjFSvDJ9oLzTJ9hLAK1KzA=
+github.com/nacos-group/nacos-sdk-go v1.0.1 h1:VNmXGlSS28xOmkO5Nxk5WRp6f1HMosAmG9pDtcnUFcw=
+github.com/nacos-group/nacos-sdk-go v1.0.1/go.mod h1:hlAPn3UdzlxIlSILAyOXKxjFSvDJ9oLzTJ9hLAK1KzA=
 github.com/namedotcom/go v0.0.0-20180403034216-08470befbe04/go.mod h1:5sN+Lt1CaY4wsPvgQH/jsuJi4XO2ssZbdsIizr4CVC8=
+github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg=
 github.com/nats-io/jwt v0.3.2/go.mod h1:/euKqTS1ZD+zzjYrY7pseZrTtWQSjujC7xjPc8wL6eU=
+github.com/nats-io/nats-server/v2 v2.1.2/go.mod h1:Afk+wRZqkMQs/p45uXdrVLuab3gwv3Z8C4HTBu8GD/k=
 github.com/nats-io/nats-server/v2 v2.1.6/go.mod h1:BL1NOtaBQ5/y97djERRVWNouMW7GT3gxnmbE/eC8u8A=
+github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzEE/Zbp4w=
 github.com/nats-io/nats.go v1.9.2/go.mod h1:AjGArbfyR50+afOUotNX2Xs5SYHf+CoOa5HH1eEl2HE=
+github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w=
 github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w=
 github.com/nats-io/nkeys v0.1.4/go.mod h1:XdZpAbhgyyODYqjTawOnIOI7VlbKSarI9Gfy1tqEu/s=
 github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
@@ -671,8 +746,10 @@
 github.com/nrdcg/dnspod-go v0.4.0/go.mod h1:vZSoFSFeQVm2gWLMkyX61LZ8HI3BaqtHZWgPTGKr6KQ=
 github.com/nrdcg/goinwx v0.6.1/go.mod h1:XPiut7enlbEdntAqalBIqcYcTEVhpv/dKWgDCX2SwKQ=
 github.com/nrdcg/namesilo v0.2.1/go.mod h1:lwMvfQTyYq+BbjJd30ylEG4GPSS6PII0Tia4rRpRiyw=
+github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs=
 github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA=
 github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
+github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
 github.com/olekukonko/tablewriter v0.0.0-20180130162743-b8a9be070da4/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
 github.com/olekukonko/tablewriter v0.0.1/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
 github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
@@ -686,6 +763,7 @@
 github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
 github.com/onsi/gomega v1.7.0 h1:XPnZz8VVBHjVsy1vzJmRwIcSwiUO+JFfrv/xGiigmME=
 github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
+github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk=
 github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
 github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
 github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
@@ -693,22 +771,36 @@
 github.com/opencontainers/runc v0.1.1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
 github.com/opencontainers/runtime-spec v0.1.2-0.20190507144316-5b71a03e2700/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
 github.com/opencontainers/runtime-tools v0.0.0-20181011054405-1d69bd0f9c39/go.mod h1:r3f7wjNzSs2extwzU3Y+6pKfobzPh+kKFJ3ofN+3nfs=
+github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis=
+github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74=
+github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
 github.com/opentracing/opentracing-go v1.1.0 h1:pWlfV3Bxv7k65HYwkikxat0+s3pV4bsqf19k25Ur8rU=
 github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
+github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs=
+github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc=
+github.com/openzipkin-contrib/zipkin-go-opentracing v0.4.5/go.mod h1:/wsWhb9smxSfWAKL3wpBW7V8scJMt8N8gnaMCS9E/cA=
 github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw=
+github.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4=
+github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4=
 github.com/oracle/oci-go-sdk v7.0.0+incompatible/go.mod h1:VQb79nF8Z2cwLkLS35ukwStZIg5F66tcBccjip/j888=
 github.com/ovh/go-ovh v0.0.0-20181109152953-ba5adb4cf014/go.mod h1:joRatxRJaZBsY3JAOEMcoOp05CnZzsx4scTxi95DHyQ=
 github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c/go.mod h1:X07ZCGwUbLaax7L0S3Tw4hpejzu63ZrrQiUe6W0hcy0=
 github.com/packethost/packngo v0.1.1-0.20180711074735-b9cb5096f54c h1:vwpFWvAO8DeIZfFeqASzZfsxuWPno9ncAebBEP0N3uE=
 github.com/packethost/packngo v0.1.1-0.20180711074735-b9cb5096f54c/go.mod h1:otzZQXgoO96RTzDB/Hycg0qZcXZsWJGJRSXbmEIJ+4M=
+github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM=
 github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
 github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY=
 github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
 github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc=
 github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
+github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
 github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc=
 github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
+github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac=
 github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
+github.com/philhofer/fwd v1.0.0 h1:UbZqGr5Y38ApvM/V/jEljVxwocdweyH+vmYvRPBnbqQ=
+github.com/philhofer/fwd v1.0.0/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU=
+github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc=
 github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
 github.com/pierrec/lz4 v2.2.6+incompatible h1:6aCX4/YZ9v8q69hTyiR7dNLnTA3fgtKHVVW5BCd5Znw=
 github.com/pierrec/lz4 v2.2.6+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
@@ -716,6 +808,7 @@
 github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
 github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
 github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA=
 github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
 github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
@@ -731,10 +824,17 @@
 github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
 github.com/prometheus/client_golang v1.1.0 h1:BQ53HtBmfOitExawJ6LokA4x8ov/z0SYYb0+HxJfRI8=
 github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g=
+github.com/prometheus/client_golang v1.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeDPbaTKGT+JTgUa3og=
+github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
+github.com/prometheus/client_golang v1.8.0 h1:zvJNkoCFAnYFNC24FV8nW4JdRJ3GIFcLbg65lL/JDcw=
+github.com/prometheus/client_golang v1.8.0/go.mod h1:O9VU6huf47PktckDQfMTX0Y8tY0/7TSWwj+ITvv0TnM=
 github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
 github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
 github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90 h1:S/YWwWx/RA8rT8tKFRuGUZhuA90OyIBpPCXkcbwU8DE=
 github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+github.com/prometheus/client_model v0.1.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M=
+github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
 github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
 github.com/prometheus/common v0.0.0-20181126121408-4724e9255275/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
 github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
@@ -742,6 +842,10 @@
 github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
 github.com/prometheus/common v0.6.0 h1:kRhiuYSXR3+uv2IbVbZhUxK5zVD/2pp3Gd2PpvPkpEo=
 github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc=
+github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA=
+github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
+github.com/prometheus/common v0.14.0 h1:RHRyE8UocrbjU+6UvRzwi6HjiDfxrrBU91TtbKzkGp4=
+github.com/prometheus/common v0.14.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s=
 github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
 github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
 github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
@@ -751,6 +855,10 @@
 github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ=
 github.com/prometheus/procfs v0.0.5 h1:3+auTFlqw+ZaQYJARz6ArODtkaIwtvBTx3N2NehQlL8=
 github.com/prometheus/procfs v0.0.5/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ=
+github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A=
+github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
+github.com/prometheus/procfs v0.2.0 h1:wH4vA7pcjKuZzjF7lM8awk4fnuJO6idemZXoKnULUx4=
+github.com/prometheus/procfs v0.2.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
 github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
 github.com/rainycape/memcache v0.0.0-20150622160815-1031fa0ce2f2/go.mod h1:7tZKcyumwBO6qip7RNQ5r77yrssm9bfCowcLEBcU5IA=
 github.com/rboyer/safeio v0.2.1/go.mod h1:Cq/cEPK+YXFn622lsQ0K4KsPZSPtaptHHEldsy7Fmig=
@@ -767,6 +875,7 @@
 github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk=
 github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc=
 github.com/sacloud/libsacloud v1.26.1/go.mod h1:79ZwATmHLIFZIMd7sxA3LwzVy/B77uj3LDoToVTxDoQ=
+github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E=
 github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
 github.com/satori/go.uuid v1.2.1-0.20181028125025-b2ce2384e17b h1:gQZ0qzfKHQIybLANtM3mBXNUtOfsCFXeTsnBqCsx1KM=
 github.com/satori/go.uuid v1.2.1-0.20181028125025-b2ce2384e17b/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
@@ -775,9 +884,8 @@
 github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 h1:nn5Wsu0esKSJiIVhscUtVbo7ada43DJhG55ua/hjS5I=
 github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
 github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
+github.com/shirou/gopsutil v0.0.0-20181107111621-48177ef5f880 h1:1Ge4j/3uB2rxzPWD3TC+daeCw+w91z8UCUL/7WH5gn8=
 github.com/shirou/gopsutil v0.0.0-20181107111621-48177ef5f880/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
-github.com/shirou/gopsutil v2.19.12+incompatible h1:WRstheAymn1WOPesh+24+bZKFkqrdCR8JOc77v4xV3Q=
-github.com/shirou/gopsutil v2.19.12+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
 github.com/shirou/w32 v0.0.0-20160930032740-bb4de0191aa4 h1:udFKJ0aHUL60LboW/A+DfgoHVedieIzIXE8uylPue0U=
 github.com/shirou/w32 v0.0.0-20160930032740-bb4de0191aa4/go.mod h1:qsXQc7+bwAM3Q1u/4XEfrquwF8Lw7D7y5cD8CuHnfIc=
 github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4=
@@ -787,6 +895,8 @@
 github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
 github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4=
 github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
+github.com/sirupsen/logrus v1.6.0 h1:UBcNElsrwanuuMsnGSlYmtmgbb23qDR5dG+6X6Oo89I=
+github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
 github.com/skratchdot/open-golang v0.0.0-20160302144031-75fb7ed4208c/go.mod h1:sUM3LWHvSMaG192sy56D9F7CNvL7jUJVXoqM1QKLnog=
 github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=
 github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
@@ -797,6 +907,7 @@
 github.com/softlayer/softlayer-go v0.0.0-20180806151055-260589d94c7d/go.mod h1:Cw4GTlQccdRGSEf6KiMju767x0NEHE0YIVPJSaXjlsw=
 github.com/soheilhy/cmux v0.1.4 h1:0HKaf1o97UwFjHH9o5XsHUOF+tqmdA7KEzXLpiyaw0E=
 github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
+github.com/sony/gobreaker v0.4.1/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY=
 github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
 github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
 github.com/spf13/afero v1.2.1/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
@@ -804,17 +915,22 @@
 github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
 github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8=
 github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
+github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
 github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
 github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk=
 github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
 github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
+github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
 github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
 github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
 github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
 github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
 github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE=
-github.com/spf13/viper v1.7.0 h1:xVKxvI7ouOI5I+U9s2eeiUfMaWBVoXA3AWskkrqK0VM=
-github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=
+github.com/spf13/viper v1.7.1 h1:pM5oEahlgWv/WnHXpgbKz7iLIxRf65tye2Ci+XFK5sk=
+github.com/spf13/viper v1.7.1/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=
+github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
+github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
+github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI=
 github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
 github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
 github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48=
@@ -825,6 +941,8 @@
 github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
 github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4=
 github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
+github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
+github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
 github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s=
 github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
 github.com/syndtr/gocapability v0.0.0-20170704070218-db04d3cc01c8/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
@@ -837,6 +955,9 @@
 github.com/tevid/gohamcrest v1.1.1 h1:ou+xSqlIw1xfGTg1uq1nif/htZ2S3EzRqLm2BP+tYU0=
 github.com/tevid/gohamcrest v1.1.1/go.mod h1:3UvtWlqm8j5JbwYZh80D/PVBt0mJ1eJiYgZMibh0H/k=
 github.com/timewasted/linode v0.0.0-20160829202747-37e84520dcf7/go.mod h1:imsgLplxEC/etjIhdr3dNzV3JeT27LbVu5pYWm0JCBY=
+github.com/tinylib/msgp v1.1.0 h1:9fQd+ICuRIu/ue4vxJZu6/LzxN0HwMds2nq/0cFvxHU=
+github.com/tinylib/msgp v1.1.0/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE=
+github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
 github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5 h1:LnC5Kc/wtumK+WB441p7ynQJzVuNRJiqddSIE3IlSEQ=
 github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
 github.com/tmc/grpc-websocket-proxy v0.0.0-20200122045848-3419fae592fc h1:yUaosFVTJwnltaHbSNC3i82I92quFs+OFPRl8kNMVwo=
@@ -852,6 +973,7 @@
 github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
 github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
 github.com/urfave/cli v0.0.0-20171014202726-7bc6a0acffa5/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
+github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
 github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
 github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
 github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8=
@@ -859,6 +981,8 @@
 github.com/vmware/govmomi v0.18.0 h1:f7QxSmP7meCtoAmiKZogvVbLInT+CZx6Px6K5rYsJZo=
 github.com/vmware/govmomi v0.18.0/go.mod h1:URlwyTFZX72RmxtxuaFL2Uj3fD1JTvZdx59bHWk6aFU=
 github.com/vultr/govultr v0.1.4/go.mod h1:9H008Uxr/C4vFNGLqKx232C206GL0PBHzOP0809bGNA=
+github.com/willf/bitset v1.1.10 h1:NotGKqX0KwQ72NUzqrjZq5ipPNDQex9lo3WpaS8L2sc=
+github.com/willf/bitset v1.1.10/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4=
 github.com/xanzy/ssh-agent v0.2.1/go.mod h1:mLlQY/MoOhWBj+gOGMQkOeiEvkx+8pJSI+0Bx9h2kr4=
 github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
 github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
@@ -868,21 +992,28 @@
 github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
 github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
 github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
-github.com/zouyx/agollo/v3 v3.4.4 h1:5G7QNw3fw74Ns8SfnHNhjndV2mlz5Fg8bB7q84ydFYI=
-github.com/zouyx/agollo/v3 v3.4.4/go.mod h1:ag0XmE1r4iAgPd6PUnU9TJ0DMEjM1VKX1HUNqQJ2ywU=
+github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
+github.com/zouyx/agollo/v3 v3.4.5 h1:7YCxzY9ZYaH9TuVUBvmI6Tk0mwMggikah+cfbYogcHQ=
+github.com/zouyx/agollo/v3 v3.4.5/go.mod h1:LJr3kDmm23QSW+F1Ol4TMHDa7HvJvscMdVxJ2IpUTVc=
 go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
+go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
 go.etcd.io/bbolt v1.3.4 h1:hi1bXHMVrlQh6WwxAy+qZCV/SYIlqo+Ushwdpa4tAKg=
 go.etcd.io/bbolt v1.3.4/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ=
+go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg=
 go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
 go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
 go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
 go.opencensus.io v0.22.0 h1:C9hSCOW830chIVkdja34wa6Ky+IzWllkUinR+BtRZd4=
 go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
+go.opencensus.io v0.22.2 h1:75k/FF0Q2YM8QYo07VPddOLBslDt1MZOdEslOHvmzAs=
+go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
 go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
 go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
 go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
 go.uber.org/atomic v1.6.0 h1:Ezj3JGmsOnG1MoRWQkPBsKLe9DwWD9QeXzTRzzldNVk=
 go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
+go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
+go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
 go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
 go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4=
 go.uber.org/multierr v1.5.0 h1:KCa4XfM8CWFCpxXRGok+Q0SS/0XBhMDbHHGABQLvD2A=
@@ -894,6 +1025,8 @@
 go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM=
 go.uber.org/zap v1.15.0 h1:ZZCA22JRF2gQE5FoNmhmrf7jeJJ2uhqDUNRYKm8dvmM=
 go.uber.org/zap v1.15.0/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc=
+go.uber.org/zap v1.16.0 h1:uFRZXykJGK9lLY4HtgSw44DnIcAM+kRBP7x5m+NpAOM=
+go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ=
 golang.org/x/crypto v0.0.0-20180621125126-a49355c7e3f8/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
 golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
 golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
@@ -919,6 +1052,8 @@
 golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
 golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37 h1:cg5LA/zNPRzIXIWSCxQW10Rvpy94aQh3LT/ShoCpkHw=
 golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI=
+golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
 golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@@ -937,6 +1072,8 @@
 golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
 golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f h1:J5lckAjkw6qYlOZNj90mLYNTEKDvWeuc1yieZ8qUzUE=
 golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
+golang.org/x/lint v0.0.0-20200302205851-738671d3881b h1:Wh+f8QHJXR411sJR8/vRBTZ7YapZaRvUcLFFJhusH0k=
+golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
 golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
 golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
 golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
@@ -944,6 +1081,8 @@
 golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
 golang.org/x/mod v0.2.0 h1:KU7oHjnv3XNWfa5COkzUifxZmxp1TyI7ImMXqFxLwvQ=
 golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4=
+golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
 golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20180611182652-db08ff08e862/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -965,8 +1104,8 @@
 golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
 golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 golang.org/x/net v0.0.0-20190930134127-c5a3c61f89f3/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
@@ -974,8 +1113,12 @@
 golang.org/x/net v0.0.0-20200226121028-0de0cce0169b h1:0mm1VjtFUOIlE1SbDlwjYaDxZVDP2S5ou6y0gSgXHu8=
 golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
 golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2 h1:eDrdRpKgkcCqKZQwyZRyeFZgfqt37SL7Kv3tok06cKE=
 golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
+golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
+golang.org/x/net v0.0.0-20200822124328-c89045814202 h1:VvcQYSHwXgi7W+TpUR6A9g6Up98WAHf3f/ulnJ62IyA=
+golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
 golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
 golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
 golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 h1:SVwTIAaPC2U/AvvLNZ2a7OVsmBpC8L5BlwK1whH3hm0=
@@ -987,6 +1130,8 @@
 golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e h1:vcxGaoTs7kV8m5Np9uUNQin4BrLOthgV7252N8V+FwY=
 golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208 h1:qwRHBd0NqMbJxfbotnDhm2ByMI1Shq4Y6oRJo21SGJA=
+golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20180622082034-63fc586f45fe/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -1018,12 +1163,16 @@
 golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -1033,12 +1182,17 @@
 golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200523222454-059865788121 h1:rITEj+UZHYC927n8GT97eC3zrpzXdb/voyeOuVKS46o=
 golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20201015000850-e3ed0017c211 h1:9UQO31fZ+0aKQOFldThf7BKPMJTiBfWycGh/u3UoO88=
+golang.org/x/sys v0.0.0-20201015000850-e3ed0017c211/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.1-0.20181227161524-e6919f6577db/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
 golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
 golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
+golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 golang.org/x/time v0.0.0-20190308202827-9d24e82272b4 h1:SvFZT6jyqRaOeXpc5h/JSfZenJ2O330aBsf7JfSUXmQ=
 golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
@@ -1074,12 +1228,18 @@
 golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
 golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
 golang.org/x/tools v0.0.0-20200426102838-f3a5411a4c3b h1:zSzQJAznWxAh9fZxiPy2FZo+ZZEYoYFYYDYdOrU7AaM=
 golang.org/x/tools v0.0.0-20200426102838-f3a5411a4c3b/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
+golang.org/x/tools v0.0.0-20200928182047-19e03678916f h1:VwGa2Wf+rHGIxvsssCkUNIyFv8jQY0VCBCNWtikoWq0=
+golang.org/x/tools v0.0.0-20200928182047-19e03678916f/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU=
 golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
 golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
+golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk=
 google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
 google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
@@ -1090,6 +1250,7 @@
 google.golang.org/api v0.14.0 h1:uMf5uLi4eQMRrMKhCplNik4U4H8Z6C1br3zOtAa/aDE=
 google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
 google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
+google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
 google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
 google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
 google.golang.org/appengine v1.6.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
@@ -1114,12 +1275,15 @@
 google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
 google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
 google.golang.org/grpc v1.19.1/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
+google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM=
 google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
 google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
 google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
 google.golang.org/grpc v1.22.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
+google.golang.org/grpc v1.22.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
 google.golang.org/grpc v1.23.0 h1:AzbTB6ux+okLTzP8Ru1Xs41C303zdcfEht7MQnYJt5A=
 google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
+google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
 google.golang.org/grpc v1.26.0 h1:2dTRdpdFEEhJYQD8EMLB61nnrzSCTbG38PhqdhvOltg=
 google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
 google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
@@ -1129,6 +1293,8 @@
 google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
 google.golang.org/protobuf v1.22.0 h1:cJv5/xdbk1NnMPR1VP9+HU6gupuG9MLBoH1r6RHZ2MY=
 google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
+google.golang.org/protobuf v1.23.0 h1:4MY060fB1DLGMB/7MBTLnwQUY6+F09GEiz6SsrNqyzM=
+google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
 gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U=
 gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
 gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d/go.mod h1:cuepJuh7vyXfUyUwEgHQXw849cJrilpS5NeIjOWESAw=
@@ -1138,9 +1304,11 @@
 gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
 gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
 gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
 gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
 gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
+gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o=
 gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo=
 gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE=
 gopkg.in/go-playground/validator.v9 v9.29.1/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ=
@@ -1166,8 +1334,15 @@
 gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
 gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
+gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
+gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
 gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
 honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
 honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
@@ -1198,3 +1373,4 @@
 sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI=
 sigs.k8s.io/yaml v1.1.0 h1:4A07+ZFc2wgJwo8YNlQpr1rVlgUDlxXHhPJciaPY5gs=
 sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
+sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU=
diff --git a/metadata/definition/definition.go b/metadata/definition/definition.go
index dbbc0c8..a032313 100644
--- a/metadata/definition/definition.go
+++ b/metadata/definition/definition.go
@@ -93,7 +93,7 @@
 }
 
 // BuildServiceDefinition can build service definition which will be used to describe a service
-func BuildServiceDefinition(service common.Service, url common.URL) *ServiceDefinition {
+func BuildServiceDefinition(service common.Service, url *common.URL) *ServiceDefinition {
 	sd := &ServiceDefinition{}
 	sd.CanonicalName = url.Service()
 
diff --git a/metadata/identifier/service_metadata_identifier.go b/metadata/identifier/service_metadata_identifier.go
index b9e6596..3035cf3 100644
--- a/metadata/identifier/service_metadata_identifier.go
+++ b/metadata/identifier/service_metadata_identifier.go
@@ -32,7 +32,7 @@
 // NewServiceMetadataIdentifier create instance.
 // The ServiceInterface is the @url.Service()
 // other parameters are read from @url
-func NewServiceMetadataIdentifier(url common.URL) *ServiceMetadataIdentifier {
+func NewServiceMetadataIdentifier(url *common.URL) *ServiceMetadataIdentifier {
 	return &ServiceMetadataIdentifier{
 		BaseMetadataIdentifier: BaseMetadataIdentifier{
 			ServiceInterface: url.Service(),
diff --git a/metadata/report/consul/report.go b/metadata/report/consul/report.go
index eb2bdc2..e211f7f 100644
--- a/metadata/report/consul/report.go
+++ b/metadata/report/consul/report.go
@@ -61,7 +61,7 @@
 }
 
 // SaveServiceMetadata saves the metadata.
-func (m *consulMetadataReport) SaveServiceMetadata(metadataIdentifier *identifier.ServiceMetadataIdentifier, url common.URL) error {
+func (m *consulMetadataReport) SaveServiceMetadata(metadataIdentifier *identifier.ServiceMetadataIdentifier, url *common.URL) error {
 	kv := &consul.KVPair{Key: metadataIdentifier.GetIdentifierKey(), Value: []byte(url.String())}
 	_, err := m.client.KV().Put(kv, nil)
 	return err
diff --git a/metadata/report/consul/report_test.go b/metadata/report/consul/report_test.go
index e07a742..13d0c41 100644
--- a/metadata/report/consul/report_test.go
+++ b/metadata/report/consul/report_test.go
@@ -100,7 +100,7 @@
 	assert.NoError(suite.t, err)
 }
 
-func (suite *consulMetadataReportTestSuite) testSaveServiceMetadata(url common.URL) {
+func (suite *consulMetadataReportTestSuite) testSaveServiceMetadata(url *common.URL) {
 	serviceMi := newServiceMetadataIdentifier("provider")
 	err := suite.m.SaveServiceMetadata(serviceMi, url)
 	assert.NoError(suite.t, err)
@@ -119,7 +119,7 @@
 	assert.NoError(suite.t, err)
 }
 
-func (suite *consulMetadataReportTestSuite) testSaveSubscribedData(url common.URL) {
+func (suite *consulMetadataReportTestSuite) testSaveSubscribedData(url *common.URL) {
 	subscribeMi := newSubscribeMetadataIdentifier("provider")
 	urls := []string{url.String()}
 	bytes, _ := json.Marshal(urls)
@@ -152,10 +152,10 @@
 	suite := newConsulMetadataReportTestSuite(t, m)
 	suite.testStoreProviderMetadata()
 	suite.testStoreConsumerMetadata()
-	suite.testSaveServiceMetadata(*url)
+	suite.testSaveServiceMetadata(url)
 	suite.testGetExportedURLs()
 	suite.testRemoveServiceMetadata()
-	suite.testSaveSubscribedData(*url)
+	suite.testSaveSubscribedData(url)
 	suite.testGetSubscribedURLs()
 	suite.testGetServiceDefinition()
 }
diff --git a/metadata/report/delegate/delegate_report.go b/metadata/report/delegate/delegate_report.go
index cdd29ab..836a8f9 100644
--- a/metadata/report/delegate/delegate_report.go
+++ b/metadata/report/delegate/delegate_report.go
@@ -94,7 +94,7 @@
 
 // MetadataReport is a absolute delegate for MetadataReport
 type MetadataReport struct {
-	reportUrl           common.URL
+	reportUrl           *common.URL
 	syncReport          bool
 	metadataReportRetry *metadataReportRetry
 
@@ -215,7 +215,7 @@
 }
 
 // SaveServiceMetadata will delegate to call remote metadata's sdk to save service metadata
-func (mr *MetadataReport) SaveServiceMetadata(identifier *identifier.ServiceMetadataIdentifier, url common.URL) error {
+func (mr *MetadataReport) SaveServiceMetadata(identifier *identifier.ServiceMetadataIdentifier, url *common.URL) error {
 	report := instance.GetMetadataReportInstance()
 	if mr.syncReport {
 		return report.SaveServiceMetadata(identifier, url)
@@ -241,7 +241,7 @@
 }
 
 // SaveSubscribedData will delegate to call remote metadata's sdk to save subscribed data
-func (mr *MetadataReport) SaveSubscribedData(identifier *identifier.SubscriberMetadataIdentifier, urls []common.URL) error {
+func (mr *MetadataReport) SaveSubscribedData(identifier *identifier.SubscriberMetadataIdentifier, urls []*common.URL) error {
 	urlStrList := make([]string, 0, len(urls))
 	for _, url := range urls {
 		urlStrList = append(urlStrList, url.String())
@@ -260,13 +260,13 @@
 }
 
 // GetSubscribedURLs will delegate to call remote metadata's sdk to get subscribed urls
-func (MetadataReport) GetSubscribedURLs(identifier *identifier.SubscriberMetadataIdentifier) ([]string, error) {
+func (mr *MetadataReport) GetSubscribedURLs(identifier *identifier.SubscriberMetadataIdentifier) ([]string, error) {
 	report := instance.GetMetadataReportInstance()
 	return report.GetSubscribedURLs(identifier)
 }
 
 // GetServiceDefinition will delegate to call remote metadata's sdk to get service definitions
-func (MetadataReport) GetServiceDefinition(identifier *identifier.MetadataIdentifier) (string, error) {
+func (mr *MetadataReport) GetServiceDefinition(identifier *identifier.MetadataIdentifier) (string, error) {
 	report := instance.GetMetadataReportInstance()
 	return report.GetServiceDefinition(identifier)
 }
diff --git a/metadata/report/etcd/report.go b/metadata/report/etcd/report.go
index 097835c..1939b91 100644
--- a/metadata/report/etcd/report.go
+++ b/metadata/report/etcd/report.go
@@ -63,7 +63,7 @@
 
 // SaveServiceMetadata will store the metadata
 // metadata including the basic info of the server, service info, and other user custom info
-func (e *etcdMetadataReport) SaveServiceMetadata(metadataIdentifier *identifier.ServiceMetadataIdentifier, url common.URL) error {
+func (e *etcdMetadataReport) SaveServiceMetadata(metadataIdentifier *identifier.ServiceMetadataIdentifier, url *common.URL) error {
 	key := e.getNodeKey(metadataIdentifier)
 	return e.client.Create(key, url.String())
 }
diff --git a/metadata/report/etcd/report_test.go b/metadata/report/etcd/report_test.go
index 5dd8780..28c0486 100644
--- a/metadata/report/etcd/report_test.go
+++ b/metadata/report/etcd/report_test.go
@@ -60,7 +60,7 @@
 		t.Fatal(err)
 	}
 	metadataReportFactory := &etcdMetadataReportFactory{}
-	metadataReport := metadataReportFactory.CreateMetadataReport(&url)
+	metadataReport := metadataReportFactory.CreateMetadataReport(url)
 	assert.NotNil(t, metadataReport)
 	e.Close()
 }
@@ -72,7 +72,7 @@
 		t.Fatal(err)
 	}
 	metadataReportFactory := &etcdMetadataReportFactory{}
-	metadataReport := metadataReportFactory.CreateMetadataReport(&url)
+	metadataReport := metadataReportFactory.CreateMetadataReport(url)
 	assert.NotNil(t, metadataReport)
 
 	err = metadataReport.StoreConsumerMetadata(newMetadataIdentifier("consumer"), "consumer metadata")
diff --git a/metadata/report/nacos/report.go b/metadata/report/nacos/report.go
index d69913b..42e9859 100644
--- a/metadata/report/nacos/report.go
+++ b/metadata/report/nacos/report.go
@@ -69,7 +69,7 @@
 }
 
 // SaveServiceMetadata saves the metadata.
-func (n *nacosMetadataReport) SaveServiceMetadata(metadataIdentifier *identifier.ServiceMetadataIdentifier, url common.URL) error {
+func (n *nacosMetadataReport) SaveServiceMetadata(metadataIdentifier *identifier.ServiceMetadataIdentifier, url *common.URL) error {
 	return n.storeMetadata(vo.ConfigParam{
 		DataId:  metadataIdentifier.GetIdentifierKey(),
 		Group:   metadataIdentifier.Group,
diff --git a/metadata/report/nacos/report_test.go b/metadata/report/nacos/report_test.go
index be01eb2..b40b438 100644
--- a/metadata/report/nacos/report_test.go
+++ b/metadata/report/nacos/report_test.go
@@ -111,6 +111,6 @@
 
 func newTestReport() report.MetadataReport {
 	regurl, _ := common.NewURL("registry://console.nacos.io:80", common.WithParamsValue(constant.ROLE_KEY, strconv.Itoa(common.PROVIDER)))
-	res := extension.GetMetadataReportFactory("nacos").CreateMetadataReport(&regurl)
+	res := extension.GetMetadataReportFactory("nacos").CreateMetadataReport(regurl)
 	return res
 }
diff --git a/metadata/report/report.go b/metadata/report/report.go
index 62a9055..dcb4142 100644
--- a/metadata/report/report.go
+++ b/metadata/report/report.go
@@ -38,7 +38,7 @@
 	// SaveServiceMetadata saves the metadata.
 	// Metadata includes the basic info of the server,
 	// service info, and other user custom info.
-	SaveServiceMetadata(*identifier.ServiceMetadataIdentifier, common.URL) error
+	SaveServiceMetadata(*identifier.ServiceMetadataIdentifier, *common.URL) error
 
 	// RemoveServiceMetadata removes the metadata.
 	RemoveServiceMetadata(*identifier.ServiceMetadataIdentifier) error
diff --git a/metadata/report/zookeeper/report.go b/metadata/report/zookeeper/report.go
index 8f46bb0..5d5e740 100644
--- a/metadata/report/zookeeper/report.go
+++ b/metadata/report/zookeeper/report.go
@@ -63,7 +63,7 @@
 }
 
 // SaveServiceMetadata saves the metadata.
-func (m *zookeeperMetadataReport) SaveServiceMetadata(metadataIdentifier *identifier.ServiceMetadataIdentifier, url common.URL) error {
+func (m *zookeeperMetadataReport) SaveServiceMetadata(metadataIdentifier *identifier.ServiceMetadataIdentifier, url *common.URL) error {
 	k := m.rootDir + metadataIdentifier.GetFilePathKey()
 	return m.client.CreateWithValue(k, []byte(url.String()))
 }
diff --git a/metadata/report/zookeeper/report_test.go b/metadata/report/zookeeper/report_test.go
index a1e46e2..adedaaa 100644
--- a/metadata/report/zookeeper/report_test.go
+++ b/metadata/report/zookeeper/report_test.go
@@ -100,7 +100,7 @@
 	assert.NoError(suite.t, err)
 }
 
-func (suite *zookeeperMetadataReportTestSuite) testSaveServiceMetadata(url common.URL) {
+func (suite *zookeeperMetadataReportTestSuite) testSaveServiceMetadata(url *common.URL) {
 	serviceMi := newServiceMetadataIdentifier("provider")
 	err := suite.m.SaveServiceMetadata(serviceMi, url)
 	assert.NoError(suite.t, err)
@@ -119,7 +119,7 @@
 	assert.NoError(suite.t, err)
 }
 
-func (suite *zookeeperMetadataReportTestSuite) testSaveSubscribedData(url common.URL) {
+func (suite *zookeeperMetadataReportTestSuite) testSaveSubscribedData(url *common.URL) {
 	subscribeMi := newSubscribeMetadataIdentifier("provider")
 	urls := []string{url.String()}
 	bytes, _ := json.Marshal(urls)
@@ -153,10 +153,10 @@
 	suite := newZookeeperMetadataReportTestSuite(t, m)
 	suite.testStoreProviderMetadata()
 	suite.testStoreConsumerMetadata()
-	suite.testSaveServiceMetadata(*url)
+	suite.testSaveServiceMetadata(url)
 	suite.testGetExportedURLs()
 	suite.testRemoveServiceMetadata()
-	suite.testSaveSubscribedData(*url)
+	suite.testSaveSubscribedData(url)
 	suite.testGetSubscribedURLs()
 	suite.testGetServiceDefinition()
 }
diff --git a/metadata/service/exporter/configurable/exporter_test.go b/metadata/service/exporter/configurable/exporter_test.go
index ceda255..2a5e646 100644
--- a/metadata/service/exporter/configurable/exporter_test.go
+++ b/metadata/service/exporter/configurable/exporter_test.go
@@ -65,9 +65,9 @@
 	t.Run("configurableExporter", func(t *testing.T) {
 		registryURL, _ := common.NewURL("service-discovery://localhost:12345")
 		subURL, _ := common.NewURL("dubbo://localhost:20003")
-		registryURL.SubURL = &subURL
+		registryURL.SubURL = subURL
 		assert.Equal(t, false, exported.IsExported())
-		assert.NoError(t, exported.Export(&registryURL))
+		assert.NoError(t, exported.Export(registryURL))
 		assert.Equal(t, true, exported.IsExported())
 		assert.Regexp(t, "dubbo://:20003/MetadataService*", exported.GetExportedURLs()[0].String())
 		exported.Unexport()
diff --git a/metadata/service/inmemory/metadata_service_proxy_factory.go b/metadata/service/inmemory/metadata_service_proxy_factory.go
index 1f8eeaa..becd804 100644
--- a/metadata/service/inmemory/metadata_service_proxy_factory.go
+++ b/metadata/service/inmemory/metadata_service_proxy_factory.go
@@ -50,7 +50,7 @@
 
 	u := urls[0]
 	p := extension.GetProtocol(u.Protocol)
-	invoker := p.Refer(*u)
+	invoker := p.Refer(u)
 	return &MetadataServiceProxy{
 		invkr: invoker,
 	}
diff --git a/metadata/service/inmemory/metadata_service_proxy_factory_test.go b/metadata/service/inmemory/metadata_service_proxy_factory_test.go
index 96020e1..f5e519c 100644
--- a/metadata/service/inmemory/metadata_service_proxy_factory_test.go
+++ b/metadata/service/inmemory/metadata_service_proxy_factory_test.go
@@ -66,11 +66,11 @@
 type mockProtocol struct {
 }
 
-func (m mockProtocol) Export(invoker protocol.Invoker) protocol.Exporter {
+func (m mockProtocol) Export(protocol.Invoker) protocol.Exporter {
 	panic("implement me")
 }
 
-func (m mockProtocol) Refer(url common.URL) protocol.Invoker {
+func (m mockProtocol) Refer(*common.URL) protocol.Invoker {
 	return &mockInvoker{}
 }
 
@@ -81,7 +81,7 @@
 type mockInvoker struct {
 }
 
-func (m *mockInvoker) GetUrl() common.URL {
+func (m *mockInvoker) GetUrl() *common.URL {
 	panic("implement me")
 }
 
diff --git a/metadata/service/inmemory/service.go b/metadata/service/inmemory/service.go
index 8269e69..d9cbd54 100644
--- a/metadata/service/inmemory/service.go
+++ b/metadata/service/inmemory/service.go
@@ -22,7 +22,6 @@
 )
 
 import (
-	cm "github.com/Workiva/go-datastructures/common"
 	"github.com/Workiva/go-datastructures/slice/skip"
 )
 
@@ -75,23 +74,6 @@
 	return metadataServiceInstance, nil
 }
 
-// Comparator is defined as Comparator for skip list to compare the URL
-type Comparator common.URL
-
-// Compare is defined as Comparator for skip list to compare the URL
-func (c Comparator) Compare(comp cm.Comparator) int {
-	a := common.URL(c).String()
-	b := common.URL(comp.(Comparator)).String()
-	switch {
-	case a > b:
-		return 1
-	case a < b:
-		return -1
-	default:
-		return 0
-	}
-}
-
 // addURL will add URL in memory
 func (mts *MetadataService) addURL(targetMap *sync.Map, url *common.URL) bool {
 	var (
@@ -101,7 +83,7 @@
 	logger.Debug(url.ServiceKey())
 	if urlSet, loaded = targetMap.LoadOrStore(url.ServiceKey(), skip.New(uint64(0))); loaded {
 		mts.lock.RLock()
-		wantedUrl := urlSet.(*skip.SkipList).Get(Comparator(*url))
+		wantedUrl := urlSet.(*skip.SkipList).Get(url)
 		if len(wantedUrl) > 0 && wantedUrl[0] != nil {
 			mts.lock.RUnlock()
 			return false
@@ -110,12 +92,12 @@
 	}
 	mts.lock.Lock()
 	// double chk
-	wantedUrl := urlSet.(*skip.SkipList).Get(Comparator(*url))
+	wantedUrl := urlSet.(*skip.SkipList).Get(url)
 	if len(wantedUrl) > 0 && wantedUrl[0] != nil {
 		mts.lock.Unlock()
 		return false
 	}
-	urlSet.(*skip.SkipList).Insert(Comparator(*url))
+	urlSet.(*skip.SkipList).Insert(url)
 	mts.lock.Unlock()
 	return true
 }
@@ -124,7 +106,7 @@
 func (mts *MetadataService) removeURL(targetMap *sync.Map, url *common.URL) {
 	if value, loaded := targetMap.Load(url.ServiceKey()); loaded {
 		mts.lock.Lock()
-		value.(*skip.SkipList).Delete(Comparator(*url))
+		value.(*skip.SkipList).Delete(url)
 		mts.lock.Unlock()
 		mts.lock.RLock()
 		defer mts.lock.RUnlock()
@@ -135,13 +117,13 @@
 }
 
 // getAllService can return all the exportedUrlString except for metadataService
-func (mts *MetadataService) getAllService(services *sync.Map) []common.URL {
+func (mts *MetadataService) getAllService(services *sync.Map) []*common.URL {
 	// using skip list to dedup and sorting
-	res := make([]common.URL, 0)
+	var res []*common.URL
 	services.Range(func(key, value interface{}) bool {
 		urls := value.(*skip.SkipList)
 		for i := uint64(0); i < urls.Len(); i++ {
-			url := common.URL(urls.ByPosition(i).(Comparator))
+			url := urls.ByPosition(i).(*common.URL)
 			if url.GetParam(constant.INTERFACE_KEY, url.Path) != constant.METADATA_SERVICE_NAME {
 				res = append(res, url)
 			}
@@ -153,13 +135,13 @@
 }
 
 // getSpecifiedService can return specified service url by serviceKey
-func (mts *MetadataService) getSpecifiedService(services *sync.Map, serviceKey string, protocol string) []common.URL {
-	res := make([]common.URL, 0)
+func (mts *MetadataService) getSpecifiedService(services *sync.Map, serviceKey string, protocol string) []*common.URL {
+	var res []*common.URL
 	serviceList, loaded := services.Load(serviceKey)
 	if loaded {
 		urls := serviceList.(*skip.SkipList)
 		for i := uint64(0); i < urls.Len(); i++ {
-			url := common.URL(urls.ByPosition(i).(Comparator))
+			url := urls.ByPosition(i).(*common.URL)
 			if len(protocol) == 0 || protocol == constant.ANY_VALUE || url.Protocol == protocol || url.GetParam(constant.PROTOCOL_KEY, "") == protocol {
 				res = append(res, url)
 			}
@@ -170,34 +152,34 @@
 }
 
 // ExportURL can store the in memory
-func (mts *MetadataService) ExportURL(url common.URL) (bool, error) {
-	return mts.addURL(mts.exportedServiceURLs, &url), nil
+func (mts *MetadataService) ExportURL(url *common.URL) (bool, error) {
+	return mts.addURL(mts.exportedServiceURLs, url), nil
 }
 
 // UnexportURL can remove the url store in memory
-func (mts *MetadataService) UnexportURL(url common.URL) error {
-	mts.removeURL(mts.exportedServiceURLs, &url)
+func (mts *MetadataService) UnexportURL(url *common.URL) error {
+	mts.removeURL(mts.exportedServiceURLs, url)
 	return nil
 }
 
 // SubscribeURL can store the in memory
-func (mts *MetadataService) SubscribeURL(url common.URL) (bool, error) {
-	return mts.addURL(mts.subscribedServiceURLs, &url), nil
+func (mts *MetadataService) SubscribeURL(url *common.URL) (bool, error) {
+	return mts.addURL(mts.subscribedServiceURLs, url), nil
 }
 
 // UnsubscribeURL can remove the url store in memory
-func (mts *MetadataService) UnsubscribeURL(url common.URL) error {
-	mts.removeURL(mts.subscribedServiceURLs, &url)
+func (mts *MetadataService) UnsubscribeURL(url *common.URL) error {
+	mts.removeURL(mts.subscribedServiceURLs, url)
 	return nil
 }
 
 // PublishServiceDefinition: publish url's service metadata info, and write into memory
-func (mts *MetadataService) PublishServiceDefinition(url common.URL) error {
+func (mts *MetadataService) PublishServiceDefinition(url *common.URL) error {
 	interfaceName := url.GetParam(constant.INTERFACE_KEY, "")
 	isGeneric := url.GetParamBool(constant.GENERIC_KEY, false)
 	if len(interfaceName) > 0 && !isGeneric {
-		service := common.ServiceMap.GetService(url.Protocol, url.GetParam(constant.BEAN_NAME_KEY, url.Service()))
-		sd := definition.BuildServiceDefinition(*service, url)
+		tmpService := common.ServiceMap.GetService(url.Protocol, url.GetParam(constant.BEAN_NAME_KEY, url.Service()))
+		sd := definition.BuildServiceDefinition(*tmpService, url)
 		data, err := sd.ToBytes()
 		if err != nil {
 			logger.Errorf("publishProvider getServiceDescriptor error. providerUrl:%v , error:%v ", url, err)
@@ -221,7 +203,7 @@
 }
 
 // GetSubscribedURLs get all subscribedUrl
-func (mts *MetadataService) GetSubscribedURLs() ([]common.URL, error) {
+func (mts *MetadataService) GetSubscribedURLs() ([]*common.URL, error) {
 	return mts.getAllService(mts.subscribedServiceURLs), nil
 }
 
@@ -239,7 +221,7 @@
 }
 
 // RefreshMetadata will always return true because it will be implement by remote service
-func (mts *MetadataService) RefreshMetadata(exportedRevision string, subscribedRevision string) (bool, error) {
+func (mts *MetadataService) RefreshMetadata(string, string) (bool, error) {
 	return true, nil
 }
 
diff --git a/metadata/service/inmemory/service_proxy.go b/metadata/service/inmemory/service_proxy.go
index e2b2968..7e14293 100644
--- a/metadata/service/inmemory/service_proxy.go
+++ b/metadata/service/inmemory/service_proxy.go
@@ -88,34 +88,34 @@
 	return "", nil
 }
 
-func (m *MetadataServiceProxy) ExportURL(url common.URL) (bool, error) {
+func (m *MetadataServiceProxy) ExportURL(url *common.URL) (bool, error) {
 	logger.Error("you should never invoke this implementation")
 	return false, nil
 }
 
-func (m *MetadataServiceProxy) UnexportURL(url common.URL) error {
+func (m *MetadataServiceProxy) UnexportURL(url *common.URL) error {
 	logger.Error("you should never invoke this implementation")
 	return nil
 }
 
-func (m *MetadataServiceProxy) SubscribeURL(url common.URL) (bool, error) {
+func (m *MetadataServiceProxy) SubscribeURL(url *common.URL) (bool, error) {
 	logger.Error("you should never invoke this implementation")
 	return false, nil
 }
 
-func (m *MetadataServiceProxy) UnsubscribeURL(url common.URL) error {
+func (m *MetadataServiceProxy) UnsubscribeURL(url *common.URL) error {
 	logger.Error("you should never invoke this implementation")
 	return nil
 }
 
-func (m *MetadataServiceProxy) PublishServiceDefinition(url common.URL) error {
+func (m *MetadataServiceProxy) PublishServiceDefinition(url *common.URL) error {
 	logger.Error("you should never invoke this implementation")
 	return nil
 }
 
-func (m *MetadataServiceProxy) GetSubscribedURLs() ([]common.URL, error) {
+func (m *MetadataServiceProxy) GetSubscribedURLs() ([]*common.URL, error) {
 	logger.Error("you should never invoke this implementation")
-	return []common.URL{}, nil
+	return nil, nil
 }
 
 func (m *MetadataServiceProxy) GetServiceDefinition(interfaceName string, group string, version string) (string, error) {
diff --git a/metadata/service/inmemory/service_proxy_test.go b/metadata/service/inmemory/service_proxy_test.go
index 0d75517..f7fc8fd 100644
--- a/metadata/service/inmemory/service_proxy_test.go
+++ b/metadata/service/inmemory/service_proxy_test.go
@@ -49,16 +49,16 @@
 func TestNewMetadataService(t *testing.T) {
 	pxy := createPxy()
 	pxy.ServiceName()
-	pxy.PublishServiceDefinition(common.URL{})
+	pxy.PublishServiceDefinition(&common.URL{})
 	pxy.GetServiceDefinition(constant.ANY_VALUE, constant.ANY_VALUE, constant.ANY_VALUE)
 	pxy.Version()
 	pxy.GetSubscribedURLs()
-	pxy.UnsubscribeURL(common.URL{})
+	pxy.UnsubscribeURL(&common.URL{})
 	pxy.GetServiceDefinitionByServiceKey("any")
-	pxy.ExportURL(common.URL{})
-	pxy.SubscribeURL(common.URL{})
+	pxy.ExportURL(&common.URL{})
+	pxy.SubscribeURL(&common.URL{})
 	pxy.MethodMapper()
-	pxy.UnexportURL(common.URL{})
+	pxy.UnexportURL(&common.URL{})
 	pxy.RefreshMetadata(constant.ANY_VALUE, constant.ANY_VALUE)
 
 }
diff --git a/metadata/service/remote/service.go b/metadata/service/remote/service.go
index ae83a69..d1b17e8 100644
--- a/metadata/service/remote/service.go
+++ b/metadata/service/remote/service.go
@@ -89,29 +89,29 @@
 }
 
 // ExportURL will be implemented by in memory service
-func (mts *MetadataService) ExportURL(url common.URL) (bool, error) {
+func (mts *MetadataService) ExportURL(url *common.URL) (bool, error) {
 	return mts.inMemoryMetadataService.ExportURL(url)
 }
 
 // UnexportURL remove @url's metadata
-func (mts *MetadataService) UnexportURL(url common.URL) error {
+func (mts *MetadataService) UnexportURL(url *common.URL) error {
 	smi := identifier.NewServiceMetadataIdentifier(url)
 	smi.Revision = mts.exportedRevision.Load()
 	return mts.delegateReport.RemoveServiceMetadata(smi)
 }
 
 // SubscribeURL will be implemented by in memory service
-func (mts *MetadataService) SubscribeURL(url common.URL) (bool, error) {
+func (mts *MetadataService) SubscribeURL(url *common.URL) (bool, error) {
 	return mts.inMemoryMetadataService.SubscribeURL(url)
 }
 
 // UnsubscribeURL will be implemented by in memory service
-func (mts *MetadataService) UnsubscribeURL(url common.URL) error {
+func (mts *MetadataService) UnsubscribeURL(url *common.URL) error {
 	return mts.UnsubscribeURL(url)
 }
 
 // PublishServiceDefinition will call remote metadata's StoreProviderMetadata to store url info and service definition
-func (mts *MetadataService) PublishServiceDefinition(url common.URL) error {
+func (mts *MetadataService) PublishServiceDefinition(url *common.URL) error {
 	interfaceName := url.GetParam(constant.INTERFACE_KEY, "")
 	isGeneric := url.GetParamBool(constant.GENERIC_KEY, false)
 	if len(interfaceName) > 0 && !isGeneric {
@@ -139,7 +139,7 @@
 }
 
 // GetSubscribedURLs will be implemented by in memory service
-func (mts *MetadataService) GetSubscribedURLs() ([]common.URL, error) {
+func (mts *MetadataService) GetSubscribedURLs() ([]*common.URL, error) {
 	return mts.inMemoryMetadataService.GetSubscribedURLs()
 }
 
diff --git a/metadata/service/remote/service_proxy.go b/metadata/service/remote/service_proxy.go
index eaf7a02..3199aa6 100644
--- a/metadata/service/remote/service_proxy.go
+++ b/metadata/service/remote/service_proxy.go
@@ -45,27 +45,27 @@
 	return m.serviceName, nil
 }
 
-func (m *metadataServiceProxy) ExportURL(url common.URL) (bool, error) {
+func (m *metadataServiceProxy) ExportURL(url *common.URL) (bool, error) {
 	logger.Error("you should never invoke this implementation")
 	return true, nil
 }
 
-func (m *metadataServiceProxy) UnexportURL(url common.URL) error {
+func (m *metadataServiceProxy) UnexportURL(url *common.URL) error {
 	logger.Error("you should never invoke this implementation")
 	return nil
 }
 
-func (m *metadataServiceProxy) SubscribeURL(url common.URL) (bool, error) {
+func (m *metadataServiceProxy) SubscribeURL(url *common.URL) (bool, error) {
 	logger.Error("you should never invoke this implementation")
 	return true, nil
 }
 
-func (m *metadataServiceProxy) UnsubscribeURL(url common.URL) error {
+func (m *metadataServiceProxy) UnsubscribeURL(url *common.URL) error {
 	logger.Error("you should never invoke this implementation")
 	return nil
 }
 
-func (m *metadataServiceProxy) PublishServiceDefinition(url common.URL) error {
+func (m *metadataServiceProxy) PublishServiceDefinition(url *common.URL) error {
 	logger.Error("you should never invoke this implementation")
 	return nil
 }
@@ -85,7 +85,7 @@
 	if err != nil {
 		return []interface{}{}, nil
 	}
-	res := make([]common.URL, 0, len(urls))
+	var res []*common.URL
 	for _, s := range urls {
 		u, err := common.NewURL(s)
 		if err != nil {
@@ -101,9 +101,9 @@
 	return map[string]string{}
 }
 
-func (m *metadataServiceProxy) GetSubscribedURLs() ([]common.URL, error) {
+func (m *metadataServiceProxy) GetSubscribedURLs() ([]*common.URL, error) {
 	logger.Error("you should never invoke this implementation")
-	return []common.URL{}, nil
+	return nil, nil
 }
 
 func (m *metadataServiceProxy) GetServiceDefinition(interfaceName string, group string, version string) (string, error) {
diff --git a/metadata/service/remote/service_proxy_test.go b/metadata/service/remote/service_proxy_test.go
index c284bb2..8bccbb8 100644
--- a/metadata/service/remote/service_proxy_test.go
+++ b/metadata/service/remote/service_proxy_test.go
@@ -55,15 +55,15 @@
 func TestMetadataServiceProxy(t *testing.T) {
 	pxy := createProxy()
 	pxy.ServiceName()
-	pxy.PublishServiceDefinition(common.URL{})
+	pxy.PublishServiceDefinition(&common.URL{})
 	pxy.Version()
 	pxy.GetSubscribedURLs()
-	pxy.UnsubscribeURL(common.URL{})
+	pxy.UnsubscribeURL(&common.URL{})
 	pxy.GetServiceDefinitionByServiceKey("any")
-	pxy.ExportURL(common.URL{})
-	pxy.SubscribeURL(common.URL{})
+	pxy.ExportURL(&common.URL{})
+	pxy.SubscribeURL(&common.URL{})
 	pxy.MethodMapper()
-	pxy.UnexportURL(common.URL{})
+	pxy.UnexportURL(&common.URL{})
 	pxy.Reference()
 	pxy.RefreshMetadata(constant.ANY_VALUE, constant.ANY_VALUE)
 }
@@ -89,7 +89,7 @@
 		return &mockMetadataReportFactory{}
 	})
 	u, _ := common.NewURL("mock://localhost")
-	instance.GetMetadataReportInstance(&u)
+	instance.GetMetadataReportInstance(u)
 }
 
 type mockMetadataReportFactory struct {
@@ -110,7 +110,7 @@
 	panic("implement me")
 }
 
-func (m mockMetadataReport) SaveServiceMetadata(*identifier.ServiceMetadataIdentifier, common.URL) error {
+func (m mockMetadataReport) SaveServiceMetadata(*identifier.ServiceMetadataIdentifier, *common.URL) error {
 	return nil
 }
 
diff --git a/metadata/service/remote/service_test.go b/metadata/service/remote/service_test.go
index 734f098..1cbe5ee 100644
--- a/metadata/service/remote/service_test.go
+++ b/metadata/service/remote/service_test.go
@@ -39,7 +39,7 @@
 )
 
 var (
-	serviceMetadata    = make(map[*identifier.ServiceMetadataIdentifier]common.URL, 4)
+	serviceMetadata    = make(map[*identifier.ServiceMetadataIdentifier]*common.URL, 4)
 	subscribedMetadata = make(map[*identifier.SubscriberMetadataIdentifier]string, 4)
 )
 
@@ -65,7 +65,7 @@
 	return nil
 }
 
-func (mr *metadataReport) SaveServiceMetadata(id *identifier.ServiceMetadataIdentifier, url common.URL) error {
+func (mr *metadataReport) SaveServiceMetadata(id *identifier.ServiceMetadataIdentifier, url *common.URL) error {
 	logger.Infof("SaveServiceMetadata , url is %v", url)
 	serviceMetadata[id] = url
 	return nil
@@ -97,7 +97,7 @@
 	extension.SetMetadataReportFactory("mock", getMetadataReportFactory)
 	u, err := common.NewURL(fmt.Sprintf("mock://127.0.0.1:20000/?sync.report=true"))
 	assert.NoError(t, err)
-	instance.GetMetadataReportInstance(&u)
+	instance.GetMetadataReportInstance(u)
 	mts, err := newMetadataService()
 	assert.NoError(t, err)
 	mts.(*MetadataService).setInMemoryMetadataService(mockInmemoryProc(t))
diff --git a/metadata/service/service.go b/metadata/service/service.go
index f6509d0..1d90f8a 100644
--- a/metadata/service/service.go
+++ b/metadata/service/service.go
@@ -34,15 +34,15 @@
 	// ServiceName will get the service's name in meta service , which is application name
 	ServiceName() (string, error)
 	// ExportURL will store the exported url in metadata
-	ExportURL(url common.URL) (bool, error)
+	ExportURL(url *common.URL) (bool, error)
 	// UnexportURL will delete the exported url in metadata
-	UnexportURL(url common.URL) error
+	UnexportURL(url *common.URL) error
 	// SubscribeURL will store the subscribed url in metadata
-	SubscribeURL(url common.URL) (bool, error)
+	SubscribeURL(url *common.URL) (bool, error)
 	// UnsubscribeURL will delete the subscribed url in metadata
-	UnsubscribeURL(url common.URL) error
+	UnsubscribeURL(url *common.URL) error
 	// PublishServiceDefinition will generate the target url's code info
-	PublishServiceDefinition(url common.URL) error
+	PublishServiceDefinition(url *common.URL) error
 	// GetExportedURLs will get the target exported url in metadata
 	// the url should be unique
 	// due to dubbo-go only support return array []interface{} in RPCService, so we should declare the return type as []interface{}
@@ -53,7 +53,7 @@
 
 	// GetExportedURLs will get the target subscribed url in metadata
 	// the url should be unique
-	GetSubscribedURLs() ([]common.URL, error)
+	GetSubscribedURLs() ([]*common.URL, error)
 	// GetServiceDefinition will get the target service info store in metadata
 	GetServiceDefinition(interfaceName string, group string, version string) (string, error)
 	// GetServiceDefinition will get the target service info store in metadata by service key
@@ -122,7 +122,7 @@
 	return metaData[constant.EXPORTED_SERVICES_REVISION_PROPERTY_NAME]
 }
 
-func ConvertURLArrToIntfArr(urls []common.URL) []interface{} {
+func ConvertURLArrToIntfArr(urls []*common.URL) []interface{} {
 	if len(urls) == 0 {
 		return []interface{}{}
 	}
diff --git a/metrics/prometheus/reporter.go b/metrics/prometheus/reporter.go
index bd1e798..810a13d 100644
--- a/metrics/prometheus/reporter.go
+++ b/metrics/prometheus/reporter.go
@@ -130,13 +130,13 @@
 }
 
 // whether this url represents the application received the request as server
-func isProvider(url common.URL) bool {
+func isProvider(url *common.URL) bool {
 	role := url.GetParam(constant.ROLE_KEY, "")
 	return strings.EqualFold(role, strconv.Itoa(common.PROVIDER))
 }
 
 // whether this url represents the application sent then request as client
-func isConsumer(url common.URL) bool {
+func isConsumer(url *common.URL) bool {
 	role := url.GetParam(constant.ROLE_KEY, "")
 	return strings.EqualFold(role, strconv.Itoa(common.CONSUMER))
 }
diff --git a/protocol/dubbo/dubbo_invoker.go b/protocol/dubbo/dubbo_invoker.go
index bce3350..acddfd6 100644
--- a/protocol/dubbo/dubbo_invoker.go
+++ b/protocol/dubbo/dubbo_invoker.go
@@ -66,7 +66,7 @@
 }
 
 // NewDubboInvoker constructor
-func NewDubboInvoker(url common.URL, client *remoting.ExchangeClient) *DubboInvoker {
+func NewDubboInvoker(url *common.URL, client *remoting.ExchangeClient) *DubboInvoker {
 	requestTimeout := config.GetConsumerConfig().RequestTimeout
 
 	requestTimeoutStr := url.GetParam(constant.TIMEOUT_KEY, config.GetConsumerConfig().Request_Timeout)
@@ -161,6 +161,10 @@
 	return di.timeout
 }
 
+func (di *DubboInvoker) IsAvailable() bool {
+	return di.client.IsAvailable()
+}
+
 // Destroy destroy dubbo client invoker.
 func (di *DubboInvoker) Destroy() {
 	di.quitOnce.Do(func() {
diff --git a/protocol/dubbo/dubbo_invoker_test.go b/protocol/dubbo/dubbo_invoker_test.go
index 4d32c29..49d853e 100644
--- a/protocol/dubbo/dubbo_invoker_test.go
+++ b/protocol/dubbo/dubbo_invoker_test.go
@@ -89,15 +89,15 @@
 
 	// destroy
 	lock.Lock()
+	defer lock.Unlock()
 	proto.Destroy()
-	lock.Unlock()
 }
 
-func InitTest(t *testing.T) (protocol.Protocol, common.URL) {
+func InitTest(t *testing.T) (protocol.Protocol, *common.URL) {
 
 	hessian.RegisterPOJO(&User{})
 
-	methods, err := common.ServiceMap.Register("", "dubbo", &UserProvider{})
+	methods, err := common.ServiceMap.Register("com.ikurento.user.UserProvider", "dubbo", &UserProvider{})
 	assert.NoError(t, err)
 	assert.Equal(t, "GetBigPkg,GetUser,GetUser0,GetUser1,GetUser2,GetUser3,GetUser4,GetUser5,GetUser6", methods)
 
@@ -176,10 +176,9 @@
 // size:4801228
 func (u *UserProvider) GetBigPkg(ctx context.Context, req []interface{}, rsp *User) error {
 	argBuf := new(bytes.Buffer)
-	for i := 0; i < 400; i++ {
+	for i := 0; i < 800; i++ {
 		// use chinese for test
 		argBuf.WriteString("击鼓其镗,踊跃用兵。土国城漕,我独南行。从孙子仲,平陈与宋。不我以归,忧心有忡。爰居爰处?爰丧其马?于以求之?于林之下。死生契阔,与子成说。执子之手,与子偕老。于嗟阔兮,不我活兮。于嗟洵兮,不我信兮。")
-		argBuf.WriteString("击鼓其镗,踊跃用兵。土国城漕,我独南行。从孙子仲,平陈与宋。不我以归,忧心有忡。爰居爰处?爰丧其马?于以求之?于林之下。死生契阔,与子成说。执子之手,与子偕老。于嗟阔兮,不我活兮。于嗟洵兮,不我信兮。")
 	}
 	rsp.Id = argBuf.String()
 	rsp.Name = argBuf.String()
diff --git a/protocol/dubbo/dubbo_protocol.go b/protocol/dubbo/dubbo_protocol.go
index 8dda52b..4f03b8a 100644
--- a/protocol/dubbo/dubbo_protocol.go
+++ b/protocol/dubbo/dubbo_protocol.go
@@ -90,7 +90,7 @@
 }
 
 // Refer create dubbo service reference.
-func (dp *DubboProtocol) Refer(url common.URL) protocol.Invoker {
+func (dp *DubboProtocol) Refer(url *common.URL) protocol.Invoker {
 	exchangeClient := getExchangeClient(url)
 	if exchangeClient == nil {
 		logger.Warnf("can't dial the server: %+v", url.Location)
@@ -115,7 +115,7 @@
 	}
 }
 
-func (dp *DubboProtocol) openServer(url common.URL) {
+func (dp *DubboProtocol) openServer(url *common.URL) {
 	_, ok := dp.serverMap[url.Location]
 	if !ok {
 		_, ok := dp.ExporterMap().Load(url.ServiceKey())
@@ -176,7 +176,7 @@
 	return result
 }
 
-func getExchangeClient(url common.URL) *remoting.ExchangeClient {
+func getExchangeClient(url *common.URL) *remoting.ExchangeClient {
 	clientTmp, ok := exchangeClientMap.Load(url.Location)
 	if !ok {
 		var exchangeClientTmp *remoting.ExchangeClient
diff --git a/protocol/dubbo/hessian2/hessian_dubbo_test.go b/protocol/dubbo/hessian2/hessian_dubbo_test.go
index c3f19f0..13dab92 100644
--- a/protocol/dubbo/hessian2/hessian_dubbo_test.go
+++ b/protocol/dubbo/hessian2/hessian_dubbo_test.go
@@ -223,7 +223,7 @@
 
 type AttachTestObject struct {
 	Id   int32
-	Name string `dubbo:name`
+	Name string `dubbo:"name"`
 }
 
 func (AttachTestObject) JavaClassName() string {
diff --git a/protocol/dubbo/impl/codec.go b/protocol/dubbo/impl/codec.go
index c139f35..17e7b57 100644
--- a/protocol/dubbo/impl/codec.go
+++ b/protocol/dubbo/impl/codec.go
@@ -163,15 +163,12 @@
 	if p.IsResponseWithException() {
 		logger.Infof("response with exception: %+v", p.Header)
 		decoder := hessian.NewDecoder(body)
+		p.Body = &ResponsePayload{}
 		exception, err := decoder.Decode()
 		if err != nil {
 			return perrors.WithStack(err)
 		}
-		rsp, ok := p.Body.(*ResponsePayload)
-		if !ok {
-			return perrors.Errorf("java exception:%s", exception.(string))
-		}
-		rsp.Exception = perrors.Errorf("java exception:%s", exception.(string))
+		p.Body.(*ResponsePayload).Exception = perrors.Errorf("java exception:%s", exception.(string))
 		return nil
 	} else if p.IsHeartBeat() {
 		// heartbeat no need to unmarshal contents
diff --git a/protocol/dubbo/impl/hessian.go b/protocol/dubbo/impl/hessian.go
index b686d57..066400d 100644
--- a/protocol/dubbo/impl/hessian.go
+++ b/protocol/dubbo/impl/hessian.go
@@ -489,6 +489,10 @@
 		}
 		switch t.Kind() {
 		case reflect.Struct:
+			v, ok := v.(hessian.POJO)
+			if ok {
+				return v.JavaClassName()
+			}
 			return "java.lang.Object"
 		case reflect.Slice, reflect.Array:
 			if t.Elem().Kind() == reflect.Struct {
diff --git a/protocol/grpc/client.go b/protocol/grpc/client.go
index a0ab0be..33f0a08 100644
--- a/protocol/grpc/client.go
+++ b/protocol/grpc/client.go
@@ -19,6 +19,7 @@
 
 import (
 	"reflect"
+	"strconv"
 )
 
 import (
@@ -89,13 +90,17 @@
 }
 
 // NewClient creates a new gRPC client.
-func NewClient(url common.URL) *Client {
+func NewClient(url *common.URL) *Client {
 	// if global trace instance was set , it means trace function enabled. If not , will return Nooptracer
 	tracer := opentracing.GlobalTracer()
 	dailOpts := make([]grpc.DialOption, 0, 4)
+	maxMessageSize, _ := strconv.Atoi(url.GetParam(constant.MESSAGE_SIZE_KEY, "4"))
 	dailOpts = append(dailOpts, grpc.WithInsecure(), grpc.WithBlock(), grpc.WithUnaryInterceptor(
 		otgrpc.OpenTracingClientInterceptor(tracer, otgrpc.LogPayloads())),
-		grpc.WithDefaultCallOptions(grpc.CallContentSubtype(clientConf.ContentSubType)))
+		grpc.WithDefaultCallOptions(
+			grpc.CallContentSubtype(clientConf.ContentSubType),
+			grpc.MaxCallRecvMsgSize(1024*1024*maxMessageSize),
+			grpc.MaxCallSendMsgSize(1024*1024*maxMessageSize)))
 	conn, err := grpc.Dial(url.Location, dailOpts...)
 	if err != nil {
 		panic(err)
@@ -112,7 +117,7 @@
 }
 
 func getInvoker(impl interface{}, conn *grpc.ClientConn) interface{} {
-	in := []reflect.Value{}
+	var in []reflect.Value
 	in = append(in, reflect.ValueOf(conn))
 	method := reflect.ValueOf(impl).MethodByName("GetDubboStub")
 	res := method.Call(in)
diff --git a/protocol/grpc/grpc_invoker.go b/protocol/grpc/grpc_invoker.go
index 737e8c4..02e7716 100644
--- a/protocol/grpc/grpc_invoker.go
+++ b/protocol/grpc/grpc_invoker.go
@@ -45,7 +45,7 @@
 }
 
 // NewGrpcInvoker returns a Grpc invoker instance
-func NewGrpcInvoker(url common.URL, client *Client) *GrpcInvoker {
+func NewGrpcInvoker(url *common.URL, client *Client) *GrpcInvoker {
 	return &GrpcInvoker{
 		BaseInvoker: *protocol.NewBaseInvoker(url),
 		client:      client,
@@ -62,7 +62,7 @@
 		result.Err = errNoReply
 	}
 
-	in := []reflect.Value{}
+	var in []reflect.Value
 	in = append(in, reflect.ValueOf(context.Background()))
 	in = append(in, invocation.ParameterValues()...)
 
diff --git a/protocol/grpc/grpc_protocol.go b/protocol/grpc/grpc_protocol.go
index 68594a4..3ad1245 100644
--- a/protocol/grpc/grpc_protocol.go
+++ b/protocol/grpc/grpc_protocol.go
@@ -18,11 +18,13 @@
 package grpc
 
 import (
+	"strconv"
 	"sync"
 )
 
 import (
 	"github.com/apache/dubbo-go/common"
+	"github.com/apache/dubbo-go/common/constant"
 	"github.com/apache/dubbo-go/common/extension"
 	"github.com/apache/dubbo-go/common/logger"
 	"github.com/apache/dubbo-go/protocol"
@@ -65,7 +67,7 @@
 	return exporter
 }
 
-func (gp *GrpcProtocol) openServer(url common.URL) {
+func (gp *GrpcProtocol) openServer(url *common.URL) {
 	_, ok := gp.serverMap[url.Location]
 	if !ok {
 		_, ok := gp.ExporterMap().Load(url.ServiceKey())
@@ -76,7 +78,9 @@
 		gp.serverLock.Lock()
 		_, ok = gp.serverMap[url.Location]
 		if !ok {
+			grpcMessageSize, _ := strconv.Atoi(url.GetParam(constant.MESSAGE_SIZE_KEY, "4"))
 			srv := NewServer()
+			srv.SetBufferSize(grpcMessageSize)
 			gp.serverMap[url.Location] = srv
 			srv.Start(url)
 		}
@@ -85,7 +89,7 @@
 }
 
 // Refer a remote gRPC service
-func (gp *GrpcProtocol) Refer(url common.URL) protocol.Invoker {
+func (gp *GrpcProtocol) Refer(url *common.URL) protocol.Invoker {
 	invoker := NewGrpcInvoker(url, NewClient(url))
 	gp.SetInvokers(invoker)
 	logger.Infof("Refer service: %s", url.String())
diff --git a/protocol/grpc/protoc-gen-dubbo/plugin/dubbo/dubbo.go b/protocol/grpc/protoc-gen-dubbo/plugin/dubbo/dubbo.go
index 1af4faf..a9f50e8 100644
--- a/protocol/grpc/protoc-gen-dubbo/plugin/dubbo/dubbo.go
+++ b/protocol/grpc/protoc-gen-dubbo/plugin/dubbo/dubbo.go
@@ -220,7 +220,23 @@
 		g.P("},")
 	}
 	g.P("},")
-	g.P("Streams: []", grpcPkg, ".StreamDesc{},")
+	g.P("Streams: []", grpcPkg, ".StreamDesc{")
+	for i, method := range service.Method {
+		if !method.GetClientStreaming() && !method.GetServerStreaming() {
+			continue
+		}
+		g.P("{")
+		g.P("StreamName: ", strconv.Quote(method.GetName()), ",")
+		g.P("Handler: ", handlerNames[i], ",")
+		if method.GetServerStreaming() {
+			g.P("ServerStreams: true,")
+		}
+		if method.GetClientStreaming() {
+			g.P("ClientStreams: true,")
+		}
+		g.P("},")
+	}
+	g.P("},")
 	g.P("Metadata: \"", file.GetName(), "\",")
 	g.P("}")
 	g.P("}")
@@ -241,6 +257,7 @@
 	respName := "out *" + g.typeName(method.GetOutputType())
 	if method.GetServerStreaming() || method.GetClientStreaming() {
 		respName = servName + "_" + generator.CamelCase(origMethName) + "Client"
+		return fmt.Sprintf("%s func(ctx %s.Context%s) (%s, error)", methName, contextPkg, reqArg, respName)
 	}
 	return fmt.Sprintf("%s func(ctx %s.Context%s, %s) error", methName, contextPkg, reqArg, respName)
 }
@@ -252,7 +269,6 @@
 	methName := generator.CamelCase(method.GetName())
 	hname := fmt.Sprintf("_DUBBO_%s_%s_Handler", servName, methName)
 	inType := g.typeName(method.GetInputType())
-	outType := g.typeName(method.GetOutputType())
 
 	if !method.GetServerStreaming() && !method.GetClientStreaming() {
 		g.P("func ", hname, "(srv interface{}, ctx ", contextPkg, ".Context, dec func(interface{}) error, interceptor ", grpcPkg, ".UnaryServerInterceptor) (interface{}, error) {")
@@ -286,6 +302,11 @@
 	}
 	streamType := unexport(servName) + methName + "Server"
 	g.P("func ", hname, "(srv interface{}, stream ", grpcPkg, ".ServerStream) error {")
+	g.P("_, ok := srv.(dgrpc.DubboGrpcService)")
+	g.P(`invo := invocation.NewRPCInvocation("`, methName, `", nil, nil)`)
+	g.P("if !ok {")
+	g.P("fmt.Println(invo)")
+	g.P("}")
 	if !method.GetClientStreaming() {
 		g.P("m := new(", inType, ")")
 		g.P("if err := stream.RecvMsg(m); err != nil { return err }")
@@ -296,50 +317,5 @@
 	g.P("}")
 	g.P()
 
-	genSend := method.GetServerStreaming()
-	genSendAndClose := !method.GetServerStreaming()
-	genRecv := method.GetClientStreaming()
-
-	// Stream auxiliary types and methods.
-	g.P("type ", servName, "_", methName, "Server interface {")
-	if genSend {
-		g.P("Send(*", outType, ") error")
-	}
-	if genSendAndClose {
-		g.P("SendAndClose(*", outType, ") error")
-	}
-	if genRecv {
-		g.P("Recv() (*", inType, ", error)")
-	}
-	g.P(grpcPkg, ".ServerStream")
-	g.P("}")
-	g.P()
-
-	g.P("type ", streamType, " struct {")
-	g.P(grpcPkg, ".ServerStream")
-	g.P("}")
-	g.P()
-
-	if genSend {
-		g.P("func (x *", streamType, ") Send(m *", outType, ") error {")
-		g.P("return x.ServerStream.SendMsg(m)")
-		g.P("}")
-		g.P()
-	}
-	if genSendAndClose {
-		g.P("func (x *", streamType, ") SendAndClose(m *", outType, ") error {")
-		g.P("return x.ServerStream.SendMsg(m)")
-		g.P("}")
-		g.P()
-	}
-	if genRecv {
-		g.P("func (x *", streamType, ") Recv() (*", inType, ", error) {")
-		g.P("m := new(", inType, ")")
-		g.P("if err := x.ServerStream.RecvMsg(m); err != nil { return nil, err }")
-		g.P("return m, nil")
-		g.P("}")
-		g.P()
-	}
-
 	return hname
 }
diff --git a/protocol/grpc/server.go b/protocol/grpc/server.go
index 2b7b1ad..e77e2ba 100644
--- a/protocol/grpc/server.go
+++ b/protocol/grpc/server.go
@@ -40,6 +40,7 @@
 // Server is a gRPC server
 type Server struct {
 	grpcServer *grpc.Server
+	bufferSize int
 }
 
 // NewServer creates a new server
@@ -57,8 +58,12 @@
 	ServiceDesc() *grpc.ServiceDesc
 }
 
+func (s *Server) SetBufferSize(n int) {
+	s.bufferSize = n
+}
+
 // Start gRPC server with @url
-func (s *Server) Start(url common.URL) {
+func (s *Server) Start(url *common.URL) {
 	var (
 		addr string
 		err  error
@@ -72,7 +77,9 @@
 	// if global trace instance was set, then server tracer instance can be get. If not , will return Nooptracer
 	tracer := opentracing.GlobalTracer()
 	server := grpc.NewServer(
-		grpc.UnaryInterceptor(otgrpc.OpenTracingServerInterceptor(tracer)))
+		grpc.UnaryInterceptor(otgrpc.OpenTracingServerInterceptor(tracer)),
+		grpc.MaxRecvMsgSize(1024*1024*s.bufferSize),
+		grpc.MaxSendMsgSize(1024*1024*s.bufferSize))
 
 	key := url.GetParam(constant.BEAN_NAME_KEY, "")
 	service := config.GetProviderService(key)
diff --git a/protocol/invoker.go b/protocol/invoker.go
index 3ca3704..5657b6b 100644
--- a/protocol/invoker.go
+++ b/protocol/invoker.go
@@ -26,7 +26,7 @@
 	"github.com/apache/dubbo-go/common/logger"
 )
 
-// Invoker ...
+// Invoker the service invocation interface for the consumer
 //go:generate mockgen -source invoker.go -destination mock/mock_invoker.go  -self_package github.com/apache/dubbo-go/protocol/mock --package mock  Invoker
 // Extension - Invoker
 type Invoker interface {
@@ -41,13 +41,13 @@
 
 // BaseInvoker provides default invoker implement
 type BaseInvoker struct {
-	url       common.URL
+	url       *common.URL
 	available bool
 	destroyed bool
 }
 
 // NewBaseInvoker creates a new BaseInvoker
-func NewBaseInvoker(url common.URL) *BaseInvoker {
+func NewBaseInvoker(url *common.URL) *BaseInvoker {
 	return &BaseInvoker{
 		url:       url,
 		available: true,
@@ -56,7 +56,7 @@
 }
 
 // GetUrl gets base invoker URL
-func (bi *BaseInvoker) GetUrl() common.URL {
+func (bi *BaseInvoker) GetUrl() *common.URL {
 	return bi.url
 }
 
diff --git a/protocol/jsonrpc/http.go b/protocol/jsonrpc/http.go
index 2a2ddfe..869617e 100644
--- a/protocol/jsonrpc/http.go
+++ b/protocol/jsonrpc/http.go
@@ -101,7 +101,7 @@
 }
 
 // NewRequest creates a new HTTP request with @service ,@method and @arguments.
-func (c *HTTPClient) NewRequest(service common.URL, method string, args interface{}) *Request {
+func (c *HTTPClient) NewRequest(service *common.URL, method string, args interface{}) *Request {
 
 	return &Request{
 		ID:       atomic.AddInt64(&c.ID, 1),
@@ -115,7 +115,7 @@
 }
 
 // Call makes a HTTP call with @ctx , @service ,@req and @rsp
-func (c *HTTPClient) Call(ctx context.Context, service common.URL, req *Request, rsp interface{}) error {
+func (c *HTTPClient) Call(ctx context.Context, service *common.URL, req *Request, rsp interface{}) error {
 	// header
 	httpHeader := http.Header{}
 	httpHeader.Set("Content-Type", "application/json")
diff --git a/protocol/jsonrpc/jsonrpc_invoker.go b/protocol/jsonrpc/jsonrpc_invoker.go
index d84b980..f10aaad 100644
--- a/protocol/jsonrpc/jsonrpc_invoker.go
+++ b/protocol/jsonrpc/jsonrpc_invoker.go
@@ -36,7 +36,7 @@
 }
 
 // NewJsonrpcInvoker creates JSON RPC invoker with @url and @client
-func NewJsonrpcInvoker(url common.URL, client *HTTPClient) *JsonrpcInvoker {
+func NewJsonrpcInvoker(url *common.URL, client *HTTPClient) *JsonrpcInvoker {
 	return &JsonrpcInvoker{
 		BaseInvoker: *protocol.NewBaseInvoker(url),
 		client:      client,
diff --git a/protocol/jsonrpc/jsonrpc_protocol.go b/protocol/jsonrpc/jsonrpc_protocol.go
index 1778d99..643bcde 100644
--- a/protocol/jsonrpc/jsonrpc_protocol.go
+++ b/protocol/jsonrpc/jsonrpc_protocol.go
@@ -75,7 +75,7 @@
 }
 
 // Refer a remote JSON PRC service from registry
-func (jp *JsonrpcProtocol) Refer(url common.URL) protocol.Invoker {
+func (jp *JsonrpcProtocol) Refer(url *common.URL) protocol.Invoker {
 	//default requestTimeout
 	var requestTimeout = config.GetConsumerConfig().RequestTimeout
 
@@ -106,7 +106,7 @@
 	}
 }
 
-func (jp *JsonrpcProtocol) openServer(url common.URL) {
+func (jp *JsonrpcProtocol) openServer(url *common.URL) {
 	_, ok := jp.serverMap[url.Location]
 	if !ok {
 		_, loadOk := jp.ExporterMap().Load(strings.TrimPrefix(url.Path, "/"))
diff --git a/protocol/jsonrpc/server.go b/protocol/jsonrpc/server.go
index 9755a48..755aa7d 100644
--- a/protocol/jsonrpc/server.go
+++ b/protocol/jsonrpc/server.go
@@ -229,7 +229,7 @@
 }
 
 // Start JSON RPC server then ready for accept request.
-func (s *Server) Start(url common.URL) {
+func (s *Server) Start(url *common.URL) {
 	listener, err := net.Listen("tcp", url.Location)
 	if err != nil {
 		logger.Errorf("jsonrpc server [%s] start failed: %v", url.Path, err)
diff --git a/protocol/mock/mock_invoker.go b/protocol/mock/mock_invoker.go
index 0c88b47..8a0973b 100644
--- a/protocol/mock/mock_invoker.go
+++ b/protocol/mock/mock_invoker.go
@@ -59,9 +59,9 @@
 }
 
 // GetUrl mocks base method
-func (m *MockInvoker) GetUrl() common.URL {
+func (m *MockInvoker) GetUrl() *common.URL {
 	ret := m.ctrl.Call(m, "GetUrl")
-	ret0, _ := ret[0].(common.URL)
+	ret0, _ := ret[0].(*common.URL)
 	return ret0
 }
 
diff --git a/protocol/protocol.go b/protocol/protocol.go
index 6bed5ec..d03e70f 100644
--- a/protocol/protocol.go
+++ b/protocol/protocol.go
@@ -32,7 +32,7 @@
 	// Export service for remote invocation
 	Export(invoker Invoker) Exporter
 	// Refer a remote service
-	Refer(url common.URL) Invoker
+	Refer(url *common.URL) Invoker
 	// Destroy will destroy all invoker and exporter, so it only is called once.
 	Destroy()
 }
@@ -89,7 +89,7 @@
 }
 
 // Refer is default refer implement.
-func (bp *BaseProtocol) Refer(url common.URL) Invoker {
+func (bp *BaseProtocol) Refer(url *common.URL) Invoker {
 	return NewBaseInvoker(url)
 }
 
diff --git a/protocol/protocolwrapper/mock_protocol_filter.go b/protocol/protocolwrapper/mock_protocol_filter.go
index 2e9ffed..18a4e15 100644
--- a/protocol/protocolwrapper/mock_protocol_filter.go
+++ b/protocol/protocolwrapper/mock_protocol_filter.go
@@ -39,7 +39,7 @@
 }
 
 // Refer a mock remote service
-func (pfw *mockProtocolFilter) Refer(url common.URL) protocol.Invoker {
+func (pfw *mockProtocolFilter) Refer(url *common.URL) protocol.Invoker {
 	return protocol.NewBaseInvoker(url)
 }
 
diff --git a/protocol/protocolwrapper/protocol_filter_wrapper.go b/protocol/protocolwrapper/protocol_filter_wrapper.go
index 4b2702b..79d2cf7 100644
--- a/protocol/protocolwrapper/protocol_filter_wrapper.go
+++ b/protocol/protocolwrapper/protocol_filter_wrapper.go
@@ -55,7 +55,7 @@
 }
 
 // Refer a remote service
-func (pfw *ProtocolFilterWrapper) Refer(url common.URL) protocol.Invoker {
+func (pfw *ProtocolFilterWrapper) Refer(url *common.URL) protocol.Invoker {
 	if pfw.protocol == nil {
 		pfw.protocol = extension.GetProtocol(url.Protocol)
 	}
@@ -101,7 +101,7 @@
 }
 
 // GetUrl is used to get url from FilterInvoker
-func (fi *FilterInvoker) GetUrl() common.URL {
+func (fi *FilterInvoker) GetUrl() *common.URL {
 	return fi.invoker.GetUrl()
 }
 
diff --git a/protocol/protocolwrapper/protocol_filter_wrapper_test.go b/protocol/protocolwrapper/protocol_filter_wrapper_test.go
index b03ea7b..8f063f8 100644
--- a/protocol/protocolwrapper/protocol_filter_wrapper_test.go
+++ b/protocol/protocolwrapper/protocol_filter_wrapper_test.go
@@ -43,7 +43,7 @@
 	u := common.NewURLWithOptions(
 		common.WithParams(url.Values{}),
 		common.WithParamsValue(constant.SERVICE_FILTER_KEY, "echo"))
-	exporter := filtProto.Export(protocol.NewBaseInvoker(*u))
+	exporter := filtProto.Export(protocol.NewBaseInvoker(u))
 	_, ok := exporter.GetInvoker().(*FilterInvoker)
 	assert.True(t, ok)
 }
@@ -55,7 +55,7 @@
 	u := common.NewURLWithOptions(
 		common.WithParams(url.Values{}),
 		common.WithParamsValue(constant.REFERENCE_FILTER_KEY, "echo"))
-	invoker := filtProto.Refer(*u)
+	invoker := filtProto.Refer(u)
 	_, ok := invoker.(*FilterInvoker)
 	assert.True(t, ok)
 }
diff --git a/protocol/rest/rest_invoker.go b/protocol/rest/rest_invoker.go
index 691beed..898890e 100644
--- a/protocol/rest/rest_invoker.go
+++ b/protocol/rest/rest_invoker.go
@@ -43,7 +43,7 @@
 }
 
 // NewRestInvoker returns a RestInvoker
-func NewRestInvoker(url common.URL, client *client.RestClient, restMethodConfig map[string]*config.RestMethodConfig) *RestInvoker {
+func NewRestInvoker(url *common.URL, client *client.RestClient, restMethodConfig map[string]*config.RestMethodConfig) *RestInvoker {
 	return &RestInvoker{
 		BaseInvoker:         *protocol.NewBaseInvoker(url),
 		client:              *client,
diff --git a/protocol/rest/rest_protocol.go b/protocol/rest/rest_protocol.go
index 0cd26c2..05e119b 100644
--- a/protocol/rest/rest_protocol.go
+++ b/protocol/rest/rest_protocol.go
@@ -86,7 +86,7 @@
 }
 
 // Refer create rest service reference
-func (rp *RestProtocol) Refer(url common.URL) protocol.Invoker {
+func (rp *RestProtocol) Refer(url *common.URL) protocol.Invoker {
 	// create rest_invoker
 	var requestTimeout = config.GetConsumerConfig().RequestTimeout
 	requestTimeoutStr := url.GetParam(constant.TIMEOUT_KEY, config.GetConsumerConfig().Request_Timeout)
@@ -107,7 +107,7 @@
 }
 
 // nolint
-func (rp *RestProtocol) getServer(url common.URL, serverType string) server.RestServer {
+func (rp *RestProtocol) getServer(url *common.URL, serverType string) server.RestServer {
 	restServer, ok := rp.serverMap[url.Location]
 	if ok {
 		return restServer
@@ -149,8 +149,8 @@
 func (rp *RestProtocol) Destroy() {
 	// destroy rest_server
 	rp.BaseProtocol.Destroy()
-	for key, server := range rp.serverMap {
-		server.Destroy()
+	for key, tmpServer := range rp.serverMap {
+		tmpServer.Destroy()
 		delete(rp.serverMap, key)
 	}
 	for key := range rp.clientMap {
diff --git a/protocol/rest/server/rest_server.go b/protocol/rest/server/rest_server.go
index d9542bb..5ef04ff 100644
--- a/protocol/rest/server/rest_server.go
+++ b/protocol/rest/server/rest_server.go
@@ -43,7 +43,7 @@
 // RestServer user can implement this server interface
 type RestServer interface {
 	// Start rest server
-	Start(url common.URL)
+	Start(url *common.URL)
 	// Deploy a http api
 	Deploy(restMethodConfig *rest_config.RestMethodConfig, routeFunc func(request RestServerRequest, response RestServerResponse))
 	// UnDeploy a http api
diff --git a/protocol/rest/server/server_impl/go_restful_server.go b/protocol/rest/server/server_impl/go_restful_server.go
index 6fb9ee8..4481f44 100644
--- a/protocol/rest/server/server_impl/go_restful_server.go
+++ b/protocol/rest/server/server_impl/go_restful_server.go
@@ -59,7 +59,7 @@
 
 // Start go-restful server
 // It will add all go-restful filters
-func (grs *GoRestfulServer) Start(url common.URL) {
+func (grs *GoRestfulServer) Start(url *common.URL) {
 	container := restful.NewContainer()
 	for _, filter := range filterSlice {
 		container.Filter(filter)
@@ -99,8 +99,6 @@
 
 // Delete a http api in go-restful server
 func (grs *GoRestfulServer) UnDeploy(restMethodConfig *config.RestMethodConfig) {
-	ws := new(restful.WebService)
-	ws.Path(restMethodConfig.Path)
 	err := grs.ws.RemoveRoute(restMethodConfig.Path, restMethodConfig.MethodType)
 	if err != nil {
 		logger.Warnf("[Go restful] Remove web service error:%v", err)
diff --git a/protocol/rpc_status.go b/protocol/rpc_status.go
index 978534e..8d443e8 100644
--- a/protocol/rpc_status.go
+++ b/protocol/rpc_status.go
@@ -97,7 +97,7 @@
 }
 
 // GetURLStatus get URL RPC status.
-func GetURLStatus(url common.URL) *RPCStatus {
+func GetURLStatus(url *common.URL) *RPCStatus {
 	rpcStatus, found := serviceStatistic.Load(url.Key())
 	if !found {
 		rpcStatus, _ = serviceStatistic.LoadOrStore(url.Key(), &RPCStatus{})
@@ -106,7 +106,7 @@
 }
 
 // GetMethodStatus get method RPC status.
-func GetMethodStatus(url common.URL, methodName string) *RPCStatus {
+func GetMethodStatus(url *common.URL, methodName string) *RPCStatus {
 	identifier := url.Key()
 	methodMap, found := methodStatistics.Load(identifier)
 	if !found {
@@ -124,13 +124,13 @@
 }
 
 // BeginCount gets begin count.
-func BeginCount(url common.URL, methodName string) {
+func BeginCount(url *common.URL, methodName string) {
 	beginCount0(GetURLStatus(url))
 	beginCount0(GetMethodStatus(url, methodName))
 }
 
 // EndCount gets end count.
-func EndCount(url common.URL, methodName string, elapsed int64, succeeded bool) {
+func EndCount(url *common.URL, methodName string, elapsed int64, succeeded bool) {
 	endCount0(GetURLStatus(url), elapsed, succeeded)
 	endCount0(GetMethodStatus(url, methodName), elapsed, succeeded)
 }
diff --git a/protocol/rpc_status_test.go b/protocol/rpc_status_test.go
index cc12753..6fd449c 100644
--- a/protocol/rpc_status_test.go
+++ b/protocol/rpc_status_test.go
@@ -79,7 +79,7 @@
 	assert.Equal(t, int32(0), status.total)
 }
 
-func TestbeginCount0(t *testing.T) {
+func TestBeginCount0(t *testing.T) {
 	defer CleanAllStatus()
 
 	url, _ := common.NewURL(mockCommonDubboUrl)
@@ -142,7 +142,7 @@
 
 }
 
-func request(url common.URL, method string, elapsed int64, active, succeeded bool) {
+func request(url *common.URL, method string, elapsed int64, active, succeeded bool) {
 	BeginCount(url, method)
 	if !active {
 		EndCount(url, method, elapsed, succeeded)
diff --git a/registry/base_registry.go b/registry/base_registry.go
index 797ffb2..a6693be 100644
--- a/registry/base_registry.go
+++ b/registry/base_registry.go
@@ -29,7 +29,6 @@
 )
 
 import (
-	gxnet "github.com/dubbogo/gost/net"
 	perrors "github.com/pkg/errors"
 )
 
@@ -53,7 +52,7 @@
 
 func init() {
 	processID = fmt.Sprintf("%d", os.Getpid())
-	localIP, _ = gxnet.GetLocalIP()
+	localIP = common.GetLocalIp()
 }
 
 type createPathFunc func(dubboPath string) error
@@ -100,8 +99,8 @@
 	birth    int64          // time of file birth, seconds since Epoch; 0 if unknown
 	wg       sync.WaitGroup // wg+done for zk restart
 	done     chan struct{}
-	cltLock  sync.RWMutex          //ctl lock is a lock for services map
-	services map[string]common.URL // service name + protocol -> service config, for store the service registered
+	cltLock  sync.RWMutex           //ctl lock is a lock for services map
+	services map[string]*common.URL // service name + protocol -> service config, for store the service registered
 }
 
 // InitBaseRegistry for init some local variables and set BaseRegistry's subclass to it
@@ -109,14 +108,14 @@
 	r.URL = url
 	r.birth = time.Now().UnixNano()
 	r.done = make(chan struct{})
-	r.services = make(map[string]common.URL)
+	r.services = make(map[string]*common.URL)
 	r.facadeBasedRegistry = facadeRegistry
 	return r
 }
 
 // GetUrl for get registry's url
-func (r *BaseRegistry) GetUrl() common.URL {
-	return *r.URL
+func (r *BaseRegistry) GetUrl() *common.URL {
+	return r.URL
 }
 
 // Destroy for graceful down
@@ -133,7 +132,7 @@
 }
 
 // Register implement interface registry to register
-func (r *BaseRegistry) Register(conf common.URL) error {
+func (r *BaseRegistry) Register(conf *common.URL) error {
 	var (
 		ok  bool
 		err error
@@ -161,11 +160,11 @@
 }
 
 // UnRegister implement interface registry to unregister
-func (r *BaseRegistry) UnRegister(conf common.URL) error {
+func (r *BaseRegistry) UnRegister(conf *common.URL) error {
 	var (
 		ok     bool
 		err    error
-		oldURL common.URL
+		oldURL *common.URL
 	)
 
 	func() {
@@ -198,7 +197,7 @@
 }
 
 // service is for getting service path stored in url
-func (r *BaseRegistry) service(c common.URL) string {
+func (r *BaseRegistry) service(c *common.URL) string {
 	return url.QueryEscape(c.Service())
 }
 
@@ -206,7 +205,7 @@
 func (r *BaseRegistry) RestartCallBack() bool {
 
 	// copy r.services
-	services := make([]common.URL, 0, len(r.services))
+	services := make([]*common.URL, 0, len(r.services))
 	for _, confIf := range r.services {
 		services = append(services, confIf)
 	}
@@ -231,16 +230,16 @@
 }
 
 // register for register url to registry, include init params
-func (r *BaseRegistry) register(c common.URL) error {
+func (r *BaseRegistry) register(c *common.URL) error {
 	return r.processURL(c, r.facadeBasedRegistry.DoRegister, r.createPath)
 }
 
 // unregister for unregister url to registry, include init params
-func (r *BaseRegistry) unregister(c common.URL) error {
+func (r *BaseRegistry) unregister(c *common.URL) error {
 	return r.processURL(c, r.facadeBasedRegistry.DoUnregister, nil)
 }
 
-func (r *BaseRegistry) processURL(c common.URL, f func(string, string) error, cpf createPathFunc) error {
+func (r *BaseRegistry) processURL(c *common.URL, f func(string, string) error, cpf createPathFunc) error {
 	if f == nil {
 		panic(" Must provide a `function(string, string) error` to process URL. ")
 	}
@@ -292,7 +291,7 @@
 }
 
 // providerRegistry for provider role do
-func (r *BaseRegistry) providerRegistry(c common.URL, params url.Values, f createPathFunc) (string, string, error) {
+func (r *BaseRegistry) providerRegistry(c *common.URL, params url.Values, f createPathFunc) (string, string, error) {
 	var (
 		dubboPath string
 		rawURL    string
@@ -314,7 +313,7 @@
 	// Dubbo java consumer to start looking for the provider url,because the category does not match,
 	// the provider will not find, causing the consumer can not start, so we use consumers.
 
-	if len(c.Methods) == 0 {
+	if len(c.Methods) != 0 {
 		params.Add(constant.METHODS_KEY, strings.Join(c.Methods, ","))
 	}
 	logger.Debugf("provider url params:%#v", params)
@@ -343,7 +342,7 @@
 }
 
 // consumerRegistry for consumer role do
-func (r *BaseRegistry) consumerRegistry(c common.URL, params url.Values, f createPathFunc) (string, string, error) {
+func (r *BaseRegistry) consumerRegistry(c *common.URL, params url.Values, f createPathFunc) (string, string, error) {
 	var (
 		dubboPath string
 		rawURL    string
@@ -370,7 +369,8 @@
 	}
 
 	params.Add("protocol", c.Protocol)
-	rawURL = fmt.Sprintf("consumer://%s%s?%s", localIP, c.Path, params.Encode())
+	s, _ := url.QueryUnescape(params.Encode())
+	rawURL = fmt.Sprintf("consumer://%s%s?%s", localIP, c.Path, s)
 	dubboPath = fmt.Sprintf("/dubbo/%s/%s", r.service(c), (common.RoleType(common.CONSUMER)).String())
 
 	logger.Debugf("consumer path:%s, url:%s", dubboPath, rawURL)
diff --git a/registry/consul/listener.go b/registry/consul/listener.go
index b159834..0d665af 100644
--- a/registry/consul/listener.go
+++ b/registry/consul/listener.go
@@ -39,17 +39,17 @@
 // registry.
 type consulListener struct {
 	// Registry url.
-	registryUrl common.URL
+	registryUrl *common.URL
 
 	// Consumer url.
-	consumerUrl common.URL
+	consumerUrl *common.URL
 
 	// Consul watcher.
 	plan *watch.Plan
 
 	// Most recent service urls return by
 	// watcher.
-	urls []common.URL
+	urls []*common.URL
 
 	// All service information changes will
 	// be wrapped into ServiceEvent, and be
@@ -78,7 +78,7 @@
 	wg sync.WaitGroup
 }
 
-func newConsulListener(registryUrl common.URL, consumerUrl common.URL) (*consulListener, error) {
+func newConsulListener(registryUrl *common.URL, consumerUrl *common.URL) (*consulListener, error) {
 	params := make(map[string]interface{}, 8)
 	params["type"] = "service"
 	params["service"] = consumerUrl.Service()
@@ -93,7 +93,7 @@
 		registryUrl: registryUrl,
 		consumerUrl: consumerUrl,
 		plan:        plan,
-		urls:        make([]common.URL, 0, 8),
+		urls:        make([]*common.URL, 0, 8),
 		eventCh:     make(chan *registry.ServiceEvent, 32),
 		errCh:       make(chan error, 32),
 		done:        make(chan struct{}),
@@ -142,7 +142,7 @@
 func (l *consulListener) handler(idx uint64, raw interface{}) {
 	var (
 		service *consul.ServiceEntry
-		url     common.URL
+		url     *common.URL
 		ok      bool
 		err     error
 	)
@@ -153,7 +153,7 @@
 		l.errCh <- err
 		return
 	}
-	newUrls := make([]common.URL, 0, 8)
+	newUrls := make([]*common.URL, 0, 8)
 	events := make([]*registry.ServiceEvent, 0, 8)
 
 	for _, service = range services {
diff --git a/registry/consul/registry.go b/registry/consul/registry.go
index b92e335..0b7ba97 100644
--- a/registry/consul/registry.go
+++ b/registry/consul/registry.go
@@ -76,7 +76,7 @@
 
 // Register register @url
 // it delegate the job to register() method
-func (r *consulRegistry) Register(url common.URL) error {
+func (r *consulRegistry) Register(url *common.URL) error {
 	var err error
 
 	role, _ := strconv.Atoi(r.URL.GetParam(constant.ROLE_KEY, ""))
@@ -90,7 +90,7 @@
 }
 
 // register actually register the @url
-func (r *consulRegistry) register(url common.URL) error {
+func (r *consulRegistry) register(url *common.URL) error {
 	service, err := buildService(url)
 	if err != nil {
 		return err
@@ -100,7 +100,7 @@
 
 // UnRegister unregister the @url
 // it delegate the job to unregister() method
-func (r *consulRegistry) UnRegister(url common.URL) error {
+func (r *consulRegistry) UnRegister(url *common.URL) error {
 	var err error
 
 	role, _ := strconv.Atoi(r.URL.GetParam(constant.ROLE_KEY, ""))
@@ -114,7 +114,7 @@
 }
 
 // unregister actually unregister the @url
-func (r *consulRegistry) unregister(url common.URL) error {
+func (r *consulRegistry) unregister(url *common.URL) error {
 	return r.client.Agent().ServiceDeregister(buildId(url))
 }
 
@@ -141,7 +141,7 @@
 			return
 		}
 
-		listener, err := r.getListener(*url)
+		listener, err := r.getListener(url)
 		if err != nil {
 			if !r.IsAvailable() {
 				logger.Warnf("event listener game over.")
@@ -166,14 +166,14 @@
 	}
 }
 
-func (r *consulRegistry) getListener(url common.URL) (registry.Listener, error) {
-	listener, err := newConsulListener(*r.URL, url)
+func (r *consulRegistry) getListener(url *common.URL) (registry.Listener, error) {
+	listener, err := newConsulListener(r.URL, url)
 	return listener, err
 }
 
 // GetUrl get registry URL of consul registry center
-func (r *consulRegistry) GetUrl() common.URL {
-	return *r.URL
+func (r *consulRegistry) GetUrl() *common.URL {
+	return r.URL
 }
 
 // IsAvailable checks consul registry center whether is available
@@ -197,7 +197,7 @@
 				}
 				done <- struct{}{}
 			}()
-			if err := r.UnRegister(*r.URL); err != nil {
+			if err := r.UnRegister(r.URL); err != nil {
 				logger.Errorf("consul registry unregister with err: %s", err.Error())
 			}
 		}()
diff --git a/registry/consul/service_discovery_test.go b/registry/consul/service_discovery_test.go
index ed7220f..2169857 100644
--- a/registry/consul/service_discovery_test.go
+++ b/registry/consul/service_discovery_test.go
@@ -44,7 +44,6 @@
 	consulCheckPassInterval              = 17000
 	consulDeregisterCriticalServiceAfter = "20s"
 	consulWatchTimeout                   = 60000
-	registryURL                          = common.URL{}
 )
 
 func TestConsulServiceDiscovery_newConsulServiceDiscovery(t *testing.T) {
@@ -173,7 +172,7 @@
 	}
 }
 
-func prepareService() (registry.ServiceInstance, common.URL) {
+func prepareService() (registry.ServiceInstance, *common.URL) {
 	id := "id"
 
 	registryUrl, _ := common.NewURL(protocol + "://" + providerHost + ":" + strconv.Itoa(providerPort) + "/" + service + "?anyhost=true&" +
@@ -200,19 +199,19 @@
 }
 
 // AddEventListener do nothing
-func (m *MockEventDispatcher) AddEventListener(listener observer.EventListener) {
+func (m *MockEventDispatcher) AddEventListener(observer.EventListener) {
 }
 
 // AddEventListeners do nothing
-func (m *MockEventDispatcher) AddEventListeners(listenersSlice []observer.EventListener) {
+func (m *MockEventDispatcher) AddEventListeners([]observer.EventListener) {
 }
 
 // RemoveEventListener do nothing
-func (m *MockEventDispatcher) RemoveEventListener(listener observer.EventListener) {
+func (m *MockEventDispatcher) RemoveEventListener(observer.EventListener) {
 }
 
 // RemoveEventListeners do nothing
-func (m *MockEventDispatcher) RemoveEventListeners(listenersSlice []observer.EventListener) {
+func (m *MockEventDispatcher) RemoveEventListeners([]observer.EventListener) {
 }
 
 // GetAllEventListeners return empty list
diff --git a/registry/consul/utils.go b/registry/consul/utils.go
index 05ac5e7..468dafb 100644
--- a/registry/consul/utils.go
+++ b/registry/consul/utils.go
@@ -25,7 +25,6 @@
 )
 
 import (
-	gxnet "github.com/dubbogo/gost/net"
 	consul "github.com/hashicorp/consul/api"
 	perrors "github.com/pkg/errors"
 )
@@ -34,12 +33,12 @@
 	"github.com/apache/dubbo-go/common"
 )
 
-func buildId(url common.URL) string {
+func buildId(url *common.URL) string {
 	t := md5.Sum([]byte(url.String()))
 	return hex.EncodeToString(t[:])
 }
 
-func buildService(url common.URL) (*consul.AgentServiceRegistration, error) {
+func buildService(url *common.URL) (*consul.AgentServiceRegistration, error) {
 	var err error
 
 	// id
@@ -47,7 +46,7 @@
 
 	// address
 	if url.Ip == "" {
-		url.Ip, _ = gxnet.GetLocalIP()
+		url.Ip = common.GetLocalIp()
 	}
 
 	// port
@@ -94,19 +93,19 @@
 	return service, nil
 }
 
-func retrieveURL(service *consul.ServiceEntry) (common.URL, error) {
+func retrieveURL(service *consul.ServiceEntry) (*common.URL, error) {
 	url, ok := service.Service.Meta["url"]
 	if !ok {
-		return common.URL{}, perrors.New("retrieve url fails with no url key in service meta")
+		return nil, perrors.New("retrieve url fails with no url key in service meta")
 	}
 	url1, err := common.NewURL(url)
 	if err != nil {
-		return common.URL{}, perrors.WithStack(err)
+		return nil, perrors.WithStack(err)
 	}
 	return url1, nil
 }
 
-func in(url common.URL, urls []common.URL) bool {
+func in(url *common.URL, urls []*common.URL) bool {
 	for _, url1 := range urls {
 		if url.URLEqual(url1) {
 			return true
diff --git a/registry/consul/utils_test.go b/registry/consul/utils_test.go
index 0e5bffe..d78c534 100644
--- a/registry/consul/utils_test.go
+++ b/registry/consul/utils_test.go
@@ -63,8 +63,8 @@
 	)
 }
 
-func newProviderUrl(host string, port int, service string, protocol string) common.URL {
-	return *common.NewURLWithOptions(
+func newProviderUrl(host string, port int, service string, protocol string) *common.URL {
+	return common.NewURLWithOptions(
 		common.WithIp(host),
 		common.WithPort(strconv.Itoa(port)),
 		common.WithPath(service),
@@ -72,8 +72,8 @@
 	)
 }
 
-func newConsumerUrl(host string, port int, service string, protocol string) common.URL {
-	return *common.NewURLWithOptions(
+func newConsumerUrl(host string, port int, service string, protocol string) *common.URL {
+	return common.NewURLWithOptions(
 		common.WithIp(host),
 		common.WithPort(strconv.Itoa(port)),
 		common.WithPath(service),
@@ -130,8 +130,8 @@
 	providerRegistry registry.Registry
 	consumerRegistry *consulRegistry
 	listener         registry.Listener
-	providerUrl      common.URL
-	consumerUrl      common.URL
+	providerUrl      *common.URL
+	consumerUrl      *common.URL
 }
 
 func newConsulRegistryTestSuite(t *testing.T) *consulRegistryTestSuite {
diff --git a/registry/directory/directory.go b/registry/directory/directory.go
index 8871a2a..e6ae0f3 100644
--- a/registry/directory/directory.go
+++ b/registry/directory/directory.go
@@ -19,6 +19,8 @@
 
 import (
 	"fmt"
+	"net/url"
+	"os"
 	"sync"
 )
 
@@ -30,6 +32,7 @@
 import (
 	"github.com/apache/dubbo-go/cluster"
 	"github.com/apache/dubbo-go/cluster/directory"
+	"github.com/apache/dubbo-go/cluster/router/chain"
 	"github.com/apache/dubbo-go/common"
 	"github.com/apache/dubbo-go/common/constant"
 	"github.com/apache/dubbo-go/common/extension"
@@ -56,6 +59,7 @@
 	serviceType                    string
 	registry                       registry.Registry
 	cacheInvokersMap               *sync.Map // use sync.map
+	consumerURL                    *common.URL
 	cacheOriginUrl                 *common.URL
 	configurators                  []config_center.Configurator
 	consumerConfigurationListener  *consumerConfigurationListener
@@ -76,6 +80,15 @@
 		serviceType:      url.SubURL.Service(),
 		registry:         registry,
 	}
+
+	dir.consumerURL = dir.getConsumerUrl(url.SubURL)
+
+	if routerChain, err := chain.NewRouterChain(dir.consumerURL); err == nil {
+		dir.BaseDirectory.SetRouterChain(routerChain)
+	} else {
+		logger.Warnf("fail to create router chain with url: %s, err is: %v", url.SubURL, err)
+	}
+
 	dir.consumerConfigurationListener = newConsumerConfigurationListener(dir)
 
 	go dir.subscribe(url.SubURL)
@@ -136,7 +149,7 @@
 // eventMatched checks if a cached invoker appears in the incoming invoker list, if no, then it is safe to remove.
 func (dir *RegistryDirectory) eventMatched(key string, events []*registry.ServiceEvent) bool {
 	for _, event := range events {
-		if dir.invokerCacheKey(&event.Service) == key {
+		if dir.invokerCacheKey(event.Service) == key {
 			return true
 		}
 	}
@@ -194,7 +207,7 @@
 
 // convertUrl processes override:// and router://
 func (dir *RegistryDirectory) convertUrl(res *registry.ServiceEvent) *common.URL {
-	ret := &res.Service
+	ret := res.Service
 	if ret.Protocol == constant.OVERRIDE_PROTOCOL || // 1.for override url in 2.6.x
 		ret.GetParam(constant.CATEGORY_KEY, constant.DEFAULT_CATEGORY) == constant.CONFIGURATORS_CATEGORY {
 		dir.configurators = append(dir.configurators, extension.GetDefaultConfigurator(ret))
@@ -283,19 +296,19 @@
 		dir.overrideUrl(newUrl)
 		if cacheInvoker, ok := dir.cacheInvokersMap.Load(newUrl.Key()); !ok {
 			logger.Debugf("service will be added in cache invokers: invokers url is  %s!", newUrl)
-			newInvoker := extension.GetProtocol(protocolwrapper.FILTER).Refer(*newUrl)
+			newInvoker := extension.GetProtocol(protocolwrapper.FILTER).Refer(newUrl)
 			if newInvoker != nil {
 				dir.cacheInvokersMap.Store(newUrl.Key(), newInvoker)
 			}
 		} else {
 			// if cached invoker has the same URL with the new URL, then no need to re-refer, and no need to destroy
 			// the old invoker.
-			if common.IsEquals(*newUrl, cacheInvoker.(protocol.Invoker).GetUrl()) {
+			if common.IsEquals(newUrl, cacheInvoker.(protocol.Invoker).GetUrl()) {
 				return nil
 			}
 
 			logger.Debugf("service will be updated in cache invokers: new invoker url is %s, old invoker url is %s", newUrl, cacheInvoker.(protocol.Invoker).GetUrl())
-			newInvoker := extension.GetProtocol(protocolwrapper.FILTER).Refer(*newUrl)
+			newInvoker := extension.GetProtocol(protocolwrapper.FILTER).Refer(newUrl)
 			if newInvoker != nil {
 				dir.cacheInvokersMap.Store(newUrl.Key(), newInvoker)
 				return cacheInvoker.(protocol.Invoker)
@@ -313,7 +326,7 @@
 	if routerChain == nil {
 		return invokers
 	}
-	return routerChain.Route(invokers, dir.cacheOriginUrl, invocation)
+	return routerChain.Route(dir.consumerURL, invocation)
 }
 
 // IsAvailable  whether the directory is available
@@ -349,6 +362,24 @@
 	doOverrideUrl(dir.referenceConfigurationListener.Configurators(), targetUrl)
 }
 
+func (dir *RegistryDirectory) getConsumerUrl(c *common.URL) *common.URL {
+	processID := fmt.Sprintf("%d", os.Getpid())
+	localIP := common.GetLocalIp()
+
+	params := url.Values{}
+	c.RangeParams(func(key, value string) bool {
+		params.Add(key, value)
+		return true
+	})
+
+	params.Add("pid", processID)
+	params.Add("ip", localIP)
+	params.Add("protocol", c.Protocol)
+
+	return common.NewURLWithOptions(common.WithProtocol("consumer"), common.WithIp(localIP), common.WithPath(c.Path),
+		common.WithParams(params))
+}
+
 func doOverrideUrl(configurators []config_center.Configurator, targetUrl *common.URL) {
 	for _, v := range configurators {
 		v.Configure(targetUrl)
diff --git a/registry/directory/directory_test.go b/registry/directory/directory_test.go
index f2b2f8e..9008e6e 100644
--- a/registry/directory/directory_test.go
+++ b/registry/directory/directory_test.go
@@ -72,7 +72,7 @@
 func TestSubscribe_InvalidUrl(t *testing.T) {
 	url, _ := common.NewURL("mock://127.0.0.1:1111")
 	mockRegistry, _ := registry.NewMockRegistry(&common.URL{})
-	_, err := NewRegistryDirectory(&url, mockRegistry)
+	_, err := NewRegistryDirectory(url, mockRegistry)
 	assert.Error(t, err)
 }
 
@@ -83,9 +83,9 @@
 	regurl, _ := common.NewURL("mock://127.0.0.1:1111")
 	suburl, _ := common.NewURL("dubbo://127.0.0.1:20000")
 	suburl.SetParam(constant.CLUSTER_KEY, "mock")
-	regurl.SubURL = &suburl
+	regurl.SubURL = suburl
 	mockRegistry, _ := registry.NewMockRegistry(&common.URL{})
-	dir, _ := NewRegistryDirectory(&regurl, mockRegistry)
+	dir, _ := NewRegistryDirectory(regurl, mockRegistry)
 
 	go dir.(*RegistryDirectory).subscribe(common.NewURLWithOptions(common.WithPath("testservice")))
 	//for group1
@@ -93,7 +93,7 @@
 	urlmap.Set(constant.GROUP_KEY, "group1")
 	urlmap.Set(constant.CLUSTER_KEY, "failover") //to test merge url
 	for i := 0; i < 3; i++ {
-		mockRegistry.(*registry.MockRegistry).MockEvent(&registry.ServiceEvent{Action: remoting.EventTypeAdd, Service: *common.NewURLWithOptions(common.WithPath("TEST"+strconv.FormatInt(int64(i), 10)), common.WithProtocol("dubbo"),
+		mockRegistry.(*registry.MockRegistry).MockEvent(&registry.ServiceEvent{Action: remoting.EventTypeAdd, Service: common.NewURLWithOptions(common.WithPath("TEST"+strconv.FormatInt(int64(i), 10)), common.WithProtocol("dubbo"),
 			common.WithParams(urlmap))})
 	}
 	//for group2
@@ -101,7 +101,7 @@
 	urlmap2.Set(constant.GROUP_KEY, "group2")
 	urlmap2.Set(constant.CLUSTER_KEY, "failover") //to test merge url
 	for i := 0; i < 3; i++ {
-		mockRegistry.(*registry.MockRegistry).MockEvent(&registry.ServiceEvent{Action: remoting.EventTypeAdd, Service: *common.NewURLWithOptions(common.WithPath("TEST"+strconv.FormatInt(int64(i), 10)), common.WithProtocol("dubbo"),
+		mockRegistry.(*registry.MockRegistry).MockEvent(&registry.ServiceEvent{Action: remoting.EventTypeAdd, Service: common.NewURLWithOptions(common.WithPath("TEST"+strconv.FormatInt(int64(i), 10)), common.WithProtocol("dubbo"),
 			common.WithParams(urlmap2))})
 	}
 
@@ -124,7 +124,7 @@
 func Test_List(t *testing.T) {
 	registryDirectory, _ := normalRegistryDir()
 
-	time.Sleep(4e9)
+	time.Sleep(6e9)
 	assert.Len(t, registryDirectory.List(&invocation.RPCInvocation{}), 3)
 	assert.Equal(t, true, registryDirectory.IsAvailable())
 
@@ -202,17 +202,17 @@
 		common.WithParamsValue(constant.GROUP_KEY, "group"),
 		common.WithParamsValue(constant.VERSION_KEY, "1.0.0"),
 	)
-	url.SubURL = &suburl
+	url.SubURL = suburl
 	mockRegistry, _ := registry.NewMockRegistry(&common.URL{})
-	dir, _ := NewRegistryDirectory(&url, mockRegistry)
+	dir, _ := NewRegistryDirectory(url, mockRegistry)
 
-	go dir.(*RegistryDirectory).subscribe(&suburl)
+	go dir.(*RegistryDirectory).subscribe(suburl)
 	if len(noMockEvent) == 0 {
 		for i := 0; i < 3; i++ {
 			mockRegistry.(*registry.MockRegistry).MockEvent(
 				&registry.ServiceEvent{
 					Action: remoting.EventTypeAdd,
-					Service: *common.NewURLWithOptions(
+					Service: common.NewURLWithOptions(
 						common.WithPath("TEST"+strconv.FormatInt(int64(i), 10)),
 						common.WithProtocol("dubbo"),
 					),
diff --git a/registry/etcdv3/listener.go b/registry/etcdv3/listener.go
index 436b6ec..4bc387c 100644
--- a/registry/etcdv3/listener.go
+++ b/registry/etcdv3/listener.go
@@ -64,7 +64,7 @@
 	}
 
 	for _, v := range l.interestedURL {
-		if serviceURL.URLEqual(*v) {
+		if serviceURL.URLEqual(v) {
 			l.listener.Process(
 				&config_center.ConfigChangeEvent{
 					Key:        eventType.Path,
@@ -113,7 +113,7 @@
 				}
 				continue
 			}
-			return &registry.ServiceEvent{Action: e.ConfigType, Service: e.Value.(common.URL)}, nil
+			return &registry.ServiceEvent{Action: e.ConfigType, Service: e.Value.(*common.URL)}, nil
 		}
 	}
 }
diff --git a/registry/etcdv3/listener_test.go b/registry/etcdv3/listener_test.go
index 1cf06d1..ff7f63f 100644
--- a/registry/etcdv3/listener_test.go
+++ b/registry/etcdv3/listener_test.go
@@ -80,7 +80,7 @@
 
 	listener := NewRegistryDataListener(&MockDataListener{})
 	url, _ := common.NewURL("jsonrpc%3A%2F%2F127.0.0.1%3A20001%2Fcom.ikurento.user.UserProvider%3Fanyhost%3Dtrue%26app.version%3D0.0.1%26application%3DBDTService%26category%3Dproviders%26cluster%3Dfailover%26dubbo%3Ddubbo-provider-golang-2.6.0%26environment%3Ddev%26group%3D%26interface%3Dcom.ikurento.user.UserProvider%26ip%3D10.32.20.124%26loadbalance%3Drandom%26methods.GetUser.loadbalance%3Drandom%26methods.GetUser.retries%3D1%26methods.GetUser.weight%3D0%26module%3Ddubbogo%2Buser-info%2Bserver%26name%3DBDTService%26organization%3Dikurento.com%26owner%3DZX%26pid%3D74500%26retries%3D0%26service.filter%3Decho%26side%3Dprovider%26timestamp%3D1560155407%26version%3D%26warmup%3D100")
-	listener.AddInterestedURL(&url)
+	listener.AddInterestedURL(url)
 	if !listener.DataChange(remoting.Event{Path: "/dubbo/com.ikurento.user.UserProvider/providers/jsonrpc%3A%2F%2F127.0.0.1%3A20001%2Fcom.ikurento.user.UserProvider%3Fanyhost%3Dtrue%26app.version%3D0.0.1%26application%3DBDTService%26category%3Dproviders%26cluster%3Dfailover%26dubbo%3Ddubbo-provider-golang-2.6.0%26environment%3Ddev%26group%3D%26interface%3Dcom.ikurento.user.UserProvider%26ip%3D10.32.20.124%26loadbalance%3Drandom%26methods.GetUser.loadbalance%3Drandom%26methods.GetUser.retries%3D1%26methods.GetUser.weight%3D0%26module%3Ddubbogo%2Buser-info%2Bserver%26name%3DBDTService%26organization%3Dikurento.com%26owner%3DZX%26pid%3D74500%26retries%3D0%26service.filter%3Decho%26side%3Dprovider%26timestamp%3D1560155407%26version%3D%26warmup%3D100"}) {
 		t.Fatal("data change not ok")
 	}
diff --git a/registry/etcdv3/registry_test.go b/registry/etcdv3/registry_test.go
index 164fe9c..d94eff6 100644
--- a/registry/etcdv3/registry_test.go
+++ b/registry/etcdv3/registry_test.go
@@ -39,7 +39,7 @@
 		t.Fatal(err)
 	}
 
-	reg, err := newETCDV3Registry(&regurl)
+	reg, err := newETCDV3Registry(regurl)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -86,7 +86,7 @@
 
 	err = reg2.Register(url)
 	assert.NoError(t, err)
-	listener, err := reg2.DoSubscribe(&url)
+	listener, err := reg2.DoSubscribe(url)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -104,7 +104,7 @@
 	url, _ := common.NewURL("dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider", common.WithParamsValue(constant.CLUSTER_KEY, "mock"), common.WithMethods([]string{"GetUser", "AddUser"}))
 
 	reg := initRegistry(t)
-	_, err := reg.DoSubscribe(&url)
+	_, err := reg.DoSubscribe(url)
 	if err != nil {
 		t.Fatal(err)
 	}
diff --git a/registry/event.go b/registry/event.go
index 39fb00c..c934158 100644
--- a/registry/event.go
+++ b/registry/event.go
@@ -40,7 +40,7 @@
 // ServiceEvent includes create, update, delete event
 type ServiceEvent struct {
 	Action  remoting.EventType
-	Service common.URL
+	Service *common.URL
 }
 
 // String return the description of event
diff --git a/registry/event/metadata_service_url_params_customizer_test.go b/registry/event/metadata_service_url_params_customizer_test.go
index 98ae2df..c041232 100644
--- a/registry/event/metadata_service_url_params_customizer_test.go
+++ b/registry/event/metadata_service_url_params_customizer_test.go
@@ -70,27 +70,27 @@
 	panic("implement me")
 }
 
-func (m *mockMetadataService) ExportURL(url common.URL) (bool, error) {
+func (m *mockMetadataService) ExportURL(*common.URL) (bool, error) {
 	panic("implement me")
 }
 
-func (m *mockMetadataService) UnexportURL(url common.URL) error {
+func (m *mockMetadataService) UnexportURL(*common.URL) error {
 	panic("implement me")
 }
 
-func (m *mockMetadataService) SubscribeURL(url common.URL) (bool, error) {
+func (m *mockMetadataService) SubscribeURL(*common.URL) (bool, error) {
 	panic("implement me")
 }
 
-func (m *mockMetadataService) UnsubscribeURL(url common.URL) error {
+func (m *mockMetadataService) UnsubscribeURL(*common.URL) error {
 	panic("implement me")
 }
 
-func (m *mockMetadataService) PublishServiceDefinition(url common.URL) error {
+func (m *mockMetadataService) PublishServiceDefinition(*common.URL) error {
 	panic("implement me")
 }
 
-func (m *mockMetadataService) GetExportedURLs(serviceInterface string, group string, version string, protocol string) ([]interface{}, error) {
+func (m *mockMetadataService) GetExportedURLs(string, string, string, string) ([]interface{}, error) {
 	return m.urls, nil
 }
 
@@ -98,8 +98,8 @@
 	panic("implement me")
 }
 
-func (m *mockMetadataService) GetSubscribedURLs() ([]common.URL, error) {
-	res := make([]common.URL, 0, len(m.urls))
+func (m *mockMetadataService) GetSubscribedURLs() ([]*common.URL, error) {
+	var res []*common.URL
 	for _, ui := range m.urls {
 		u, _ := common.NewURL(ui.(string))
 		res = append(res, u)
@@ -107,15 +107,15 @@
 	return res, nil
 }
 
-func (m *mockMetadataService) GetServiceDefinition(interfaceName string, group string, version string) (string, error) {
+func (m *mockMetadataService) GetServiceDefinition(string, string, string) (string, error) {
 	panic("implement me")
 }
 
-func (m *mockMetadataService) GetServiceDefinitionByServiceKey(serviceKey string) (string, error) {
+func (m *mockMetadataService) GetServiceDefinitionByServiceKey(string) (string, error) {
 	panic("implement me")
 }
 
-func (m *mockMetadataService) RefreshMetadata(exportedRevision string, subscribedRevision string) (bool, error) {
+func (m *mockMetadataService) RefreshMetadata(string, string) (bool, error) {
 	panic("implement me")
 }
 
diff --git a/registry/file/service_discovery.go b/registry/file/service_discovery.go
index 59c5cf9..254c126 100644
--- a/registry/file/service_discovery.go
+++ b/registry/file/service_discovery.go
@@ -70,7 +70,7 @@
 	p := path.Join(rp, ".dubbo", constant.REGISTRY_KEY)
 	url, _ := common.NewURL("")
 	url.AddParamAvoidNil(file.CONFIG_CENTER_DIR_PARAM_NAME, p)
-	c, err := fdcf.GetDynamicConfiguration(&url)
+	c, err := fdcf.GetDynamicConfiguration(url)
 	if err != nil {
 		return nil, perrors.WithStack(err)
 	}
diff --git a/registry/kubernetes/listener.go b/registry/kubernetes/listener.go
index 24c8d81..e20b7c7 100644
--- a/registry/kubernetes/listener.go
+++ b/registry/kubernetes/listener.go
@@ -65,7 +65,7 @@
 	}
 
 	for _, v := range l.interestedURL {
-		if serviceURL.URLEqual(*v) {
+		if serviceURL.URLEqual(v) {
 			l.listener.Process(
 				&config_center.ConfigChangeEvent{
 					Key:        eventType.Path,
@@ -114,7 +114,7 @@
 				}
 				continue
 			}
-			return &registry.ServiceEvent{Action: e.ConfigType, Service: e.Value.(common.URL)}, nil
+			return &registry.ServiceEvent{Action: e.ConfigType, Service: e.Value.(*common.URL)}, nil
 		}
 	}
 }
diff --git a/registry/kubernetes/listener_test.go b/registry/kubernetes/listener_test.go
index ccaaf80..f1d8ff4 100644
--- a/registry/kubernetes/listener_test.go
+++ b/registry/kubernetes/listener_test.go
@@ -166,7 +166,7 @@
 func Test_DataChange(t *testing.T) {
 	listener := NewRegistryDataListener(&MockDataListener{})
 	url, _ := common.NewURL("jsonrpc%3A%2F%2F127.0.0.1%3A20001%2Fcom.ikurento.user.UserProvider%3Fanyhost%3Dtrue%26app.version%3D0.0.1%26application%3DBDTService%26category%3Dproviders%26cluster%3Dfailover%26dubbo%3Ddubbo-provider-golang-2.6.0%26environment%3Ddev%26group%3D%26interface%3Dcom.ikurento.user.UserProvider%26ip%3D10.32.20.124%26loadbalance%3Drandom%26methods.GetUser.loadbalance%3Drandom%26methods.GetUser.retries%3D1%26methods.GetUser.weight%3D0%26module%3Ddubbogo%2Buser-info%2Bserver%26name%3DBDTService%26organization%3Dikurento.com%26owner%3DZX%26pid%3D74500%26retries%3D0%26service.filter%3Decho%26side%3Dprovider%26timestamp%3D1560155407%26version%3D%26warmup%3D100")
-	listener.AddInterestedURL(&url)
+	listener.AddInterestedURL(url)
 	int := listener.DataChange(remoting.Event{Path: "/dubbo/com.ikurento.user.UserProvider/providers/jsonrpc%3A%2F%2F127.0.0.1%3A20001%2Fcom.ikurento.user.UserProvider%3Fanyhost%3Dtrue%26app.version%3D0.0.1%26application%3DBDTService%26category%3Dproviders%26cluster%3Dfailover%26dubbo%3Ddubbo-provider-golang-2.6.0%26environment%3Ddev%26group%3D%26interface%3Dcom.ikurento.user.UserProvider%26ip%3D10.32.20.124%26loadbalance%3Drandom%26methods.GetUser.loadbalance%3Drandom%26methods.GetUser.retries%3D1%26methods.GetUser.weight%3D0%26module%3Ddubbogo%2Buser-info%2Bserver%26name%3DBDTService%26organization%3Dikurento.com%26owner%3DZX%26pid%3D74500%26retries%3D0%26service.filter%3Decho%26side%3Dprovider%26timestamp%3D1560155407%26version%3D%26warmup%3D100"})
 	assert.Equal(t, true, int)
 }
@@ -179,7 +179,7 @@
 
 	listener := NewRegistryDataListener(&MockDataListener{})
 	url, _ := common.NewURL("jsonrpc%3A%2F%2F127.0.0.1%3A20001%2Fcom.ikurento.user.UserProvider%3Fanyhost%3Dtrue%26app.version%3D0.0.1%26application%3DBDTService%26category%3Dproviders%26cluster%3Dfailover%26dubbo%3Ddubbo-provider-golang-2.6.0%26environment%3Ddev%26group%3D%26interface%3Dcom.ikurento.user.UserProvider%26ip%3D10.32.20.124%26loadbalance%3Drandom%26methods.GetUser.loadbalance%3Drandom%26methods.GetUser.retries%3D1%26methods.GetUser.weight%3D0%26module%3Ddubbogo%2Buser-info%2Bserver%26name%3DBDTService%26organization%3Dikurento.com%26owner%3DZX%26pid%3D74500%26retries%3D0%26service.filter%3Decho%26side%3Dprovider%26timestamp%3D1560155407%26version%3D%26warmup%3D100")
-	listener.AddInterestedURL(&url)
+	listener.AddInterestedURL(url)
 	if !listener.DataChange(remoting.Event{Path: "/dubbo/com.ikurento.user.UserProvider/providers/jsonrpc%3A%2F%2F127.0.0.1%3A20001%2Fcom.ikurento.user.UserProvider%3Fanyhost%3Dtrue%26app.version%3D0.0.1%26application%3DBDTService%26category%3Dproviders%26cluster%3Dfailover%26dubbo%3Ddubbo-provider-golang-2.6.0%26environment%3Ddev%26group%3D%26interface%3Dcom.ikurento.user.UserProvider%26ip%3D10.32.20.124%26loadbalance%3Drandom%26methods.GetUser.loadbalance%3Drandom%26methods.GetUser.retries%3D1%26methods.GetUser.weight%3D0%26module%3Ddubbogo%2Buser-info%2Bserver%26name%3DBDTService%26organization%3Dikurento.com%26owner%3DZX%26pid%3D74500%26retries%3D0%26service.filter%3Decho%26side%3Dprovider%26timestamp%3D1560155407%26version%3D%26warmup%3D100"}) {
 		t.Fatal("data change not ok")
 	}
diff --git a/registry/kubernetes/registry.go b/registry/kubernetes/registry.go
index 8889585..c1e559e 100644
--- a/registry/kubernetes/registry.go
+++ b/registry/kubernetes/registry.go
@@ -27,7 +27,6 @@
 
 import (
 	"github.com/apache/dubbo-getty"
-	"github.com/dubbogo/gost/net"
 	perrors "github.com/pkg/errors"
 	v1 "k8s.io/api/core/v1"
 )
@@ -54,7 +53,7 @@
 
 func init() {
 	processID = fmt.Sprintf("%d", os.Getpid())
-	localIP, _ = gxnet.GetLocalIP()
+	localIP = common.GetLocalIp()
 	extension.SetRegistry(Name, newKubernetesRegistry)
 }
 
diff --git a/registry/kubernetes/registry_test.go b/registry/kubernetes/registry_test.go
index 347dadc..9fb409a 100644
--- a/registry/kubernetes/registry_test.go
+++ b/registry/kubernetes/registry_test.go
@@ -231,7 +231,7 @@
 	if err != nil {
 		t.Fatal(err)
 	}
-	out, err := newMockKubernetesRegistry(&regurl, pl)
+	out, err := newMockKubernetesRegistry(regurl, pl)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -268,7 +268,7 @@
 		t.Fatal(err)
 	}
 
-	listener, err := r.DoSubscribe(&url)
+	listener, err := r.DoSubscribe(url)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -301,7 +301,7 @@
 		common.WithParamsValue(constant.CLUSTER_KEY, "mock"),
 		common.WithMethods([]string{"GetUser", "AddUser"}))
 
-	_, err := r.DoSubscribe(&url)
+	_, err := r.DoSubscribe(url)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -336,7 +336,7 @@
 	if err != nil {
 		t.Fatal(err)
 	}
-	_, err = newKubernetesRegistry(&regUrl)
+	_, err = newKubernetesRegistry(regUrl)
 	if err == nil {
 		t.Fatal("not in cluster, should be a err")
 	}
diff --git a/registry/mock_registry.go b/registry/mock_registry.go
index 10561d0..18c87ee 100644
--- a/registry/mock_registry.go
+++ b/registry/mock_registry.go
@@ -47,12 +47,12 @@
 }
 
 // Register is used as a mock registry
-func (*MockRegistry) Register(url common.URL) error {
+func (*MockRegistry) Register(url *common.URL) error {
 	return nil
 }
 
 // nolint
-func (r *MockRegistry) UnRegister(conf common.URL) error {
+func (r *MockRegistry) UnRegister(conf *common.URL) error {
 	return nil
 }
 
@@ -68,8 +68,8 @@
 }
 
 // nolint
-func (r *MockRegistry) GetUrl() common.URL {
-	return common.URL{}
+func (r *MockRegistry) GetUrl() *common.URL {
+	return nil
 }
 
 func (r *MockRegistry) subscribe(*common.URL) (Listener, error) {
diff --git a/registry/nacos/listener.go b/registry/nacos/listener.go
index cf6a73d..7f27326 100644
--- a/registry/nacos/listener.go
+++ b/registry/nacos/listener.go
@@ -43,7 +43,7 @@
 
 type nacosListener struct {
 	namingClient   naming_client.INamingClient
-	listenUrl      common.URL
+	listenUrl      *common.URL
 	events         chan *config_center.ConfigChangeEvent
 	instanceMap    map[string]model.Instance
 	cacheLock      sync.Mutex
@@ -52,7 +52,7 @@
 }
 
 // NewRegistryDataListener creates a data listener for nacos
-func NewNacosListener(url common.URL, namingClient naming_client.INamingClient) (*nacosListener, error) {
+func NewNacosListener(url *common.URL, namingClient naming_client.INamingClient) (*nacosListener, error) {
 	listener := &nacosListener{
 		namingClient: namingClient,
 		listenUrl:    url, events: make(chan *config_center.ConfigChangeEvent, 32),
@@ -154,25 +154,25 @@
 	for i := range addInstances {
 		newUrl := generateUrl(addInstances[i])
 		if newUrl != nil {
-			nl.process(&config_center.ConfigChangeEvent{Value: *newUrl, ConfigType: remoting.EventTypeAdd})
+			nl.process(&config_center.ConfigChangeEvent{Value: newUrl, ConfigType: remoting.EventTypeAdd})
 		}
 	}
 	for i := range delInstances {
 		newUrl := generateUrl(delInstances[i])
 		if newUrl != nil {
-			nl.process(&config_center.ConfigChangeEvent{Value: *newUrl, ConfigType: remoting.EventTypeDel})
+			nl.process(&config_center.ConfigChangeEvent{Value: newUrl, ConfigType: remoting.EventTypeDel})
 		}
 	}
 
 	for i := range updateInstances {
 		newUrl := generateUrl(updateInstances[i])
 		if newUrl != nil {
-			nl.process(&config_center.ConfigChangeEvent{Value: *newUrl, ConfigType: remoting.EventTypeUpdate})
+			nl.process(&config_center.ConfigChangeEvent{Value: newUrl, ConfigType: remoting.EventTypeUpdate})
 		}
 	}
 }
 
-func getSubscribeName(url common.URL) string {
+func getSubscribeName(url *common.URL) string {
 	var buffer bytes.Buffer
 
 	buffer.Write([]byte(common.DubboNodes[common.PROVIDER]))
@@ -210,7 +210,7 @@
 
 		case e := <-nl.events:
 			logger.Debugf("got nacos event %s", e)
-			return &registry.ServiceEvent{Action: e.ConfigType, Service: e.Value.(common.URL)}, nil
+			return &registry.ServiceEvent{Action: e.ConfigType, Service: e.Value.(*common.URL)}, nil
 		}
 	}
 }
diff --git a/registry/nacos/registry.go b/registry/nacos/registry.go
index 4110908..ae2345e 100644
--- a/registry/nacos/registry.go
+++ b/registry/nacos/registry.go
@@ -26,7 +26,6 @@
 )
 
 import (
-	gxnet "github.com/dubbogo/gost/net"
 	"github.com/nacos-group/nacos-sdk-go/clients"
 	"github.com/nacos-group/nacos-sdk-go/clients/naming_client"
 	nacosConstant "github.com/nacos-group/nacos-sdk-go/common/constant"
@@ -52,23 +51,23 @@
 )
 
 func init() {
-	localIP, _ = gxnet.GetLocalIP()
+	localIP = common.GetLocalIp()
 	extension.SetRegistry(constant.NACOS_KEY, newNacosRegistry)
 }
 
 type nacosRegistry struct {
 	*common.URL
 	namingClient naming_client.INamingClient
-	registryUrls []common.URL
+	registryUrls []*common.URL
 }
 
-func getCategory(url common.URL) string {
+func getCategory(url *common.URL) string {
 	role, _ := strconv.Atoi(url.GetParam(constant.ROLE_KEY, strconv.Itoa(constant.NACOS_DEFAULT_ROLETYPE)))
 	category := common.DubboNodes[role]
 	return category
 }
 
-func getServiceName(url common.URL) string {
+func getServiceName(url *common.URL) string {
 	var buffer bytes.Buffer
 
 	buffer.Write([]byte(getCategory(url)))
@@ -78,7 +77,7 @@
 	return buffer.String()
 }
 
-func appendParam(target *bytes.Buffer, url common.URL, key string) {
+func appendParam(target *bytes.Buffer, url *common.URL, key string) {
 	value := url.GetParam(key, "")
 	if strings.TrimSpace(value) != "" {
 		target.Write([]byte(constant.NACOS_SERVICE_NAME_SEPARATOR))
@@ -86,7 +85,7 @@
 	}
 }
 
-func createRegisterParam(url common.URL, serviceName string) vo.RegisterInstanceParam {
+func createRegisterParam(url *common.URL, serviceName string) vo.RegisterInstanceParam {
 	category := getCategory(url)
 	params := make(map[string]string)
 
@@ -119,7 +118,7 @@
 }
 
 // Register will register the service @url to its nacos registry center
-func (nr *nacosRegistry) Register(url common.URL) error {
+func (nr *nacosRegistry) Register(url *common.URL) error {
 	serviceName := getServiceName(url)
 	param := createRegisterParam(url, serviceName)
 	isRegistry, err := nr.namingClient.RegisterInstance(param)
@@ -133,7 +132,7 @@
 	return nil
 }
 
-func createDeregisterParam(url common.URL, serviceName string) vo.DeregisterInstanceParam {
+func createDeregisterParam(url *common.URL, serviceName string) vo.DeregisterInstanceParam {
 	if len(url.Ip) == 0 {
 		url.Ip = localIP
 	}
@@ -149,7 +148,7 @@
 	}
 }
 
-func (nr *nacosRegistry) DeRegister(url common.URL) error {
+func (nr *nacosRegistry) DeRegister(url *common.URL) error {
 	serviceName := getServiceName(url)
 	param := createDeregisterParam(url, serviceName)
 	isDeRegistry, err := nr.namingClient.DeregisterInstance(param)
@@ -163,12 +162,12 @@
 }
 
 // UnRegister
-func (nr *nacosRegistry) UnRegister(conf common.URL) error {
+func (nr *nacosRegistry) UnRegister(conf *common.URL) error {
 	return perrors.New("UnRegister is not support in nacosRegistry")
 }
 
 func (nr *nacosRegistry) subscribe(conf *common.URL) (registry.Listener, error) {
-	return NewNacosListener(*conf, nr.namingClient)
+	return NewNacosListener(conf, nr.namingClient)
 }
 
 // subscribe from registry
@@ -203,7 +202,6 @@
 		}
 
 	}
-	return nil
 }
 
 // UnSubscribe :
@@ -212,8 +210,8 @@
 }
 
 // GetUrl gets its registration URL
-func (nr *nacosRegistry) GetUrl() common.URL {
-	return *nr.URL
+func (nr *nacosRegistry) GetUrl() *common.URL {
+	return nr.URL
 }
 
 // IsAvailable determines nacos registry center whether it is available
@@ -244,12 +242,12 @@
 	if err != nil {
 		return &nacosRegistry{}, err
 	}
-	registry := &nacosRegistry{
+	tmpRegistry := &nacosRegistry{
 		URL:          url,
 		namingClient: client,
-		registryUrls: []common.URL{},
+		registryUrls: []*common.URL{},
 	}
-	return registry, nil
+	return tmpRegistry, nil
 }
 
 // getNacosConfig will return the nacos config
@@ -288,6 +286,7 @@
 	clientConfig.CacheDir = url.GetParam(constant.NACOS_CACHE_DIR_KEY, "")
 	clientConfig.LogDir = url.GetParam(constant.NACOS_LOG_DIR_KEY, "")
 	clientConfig.Endpoint = url.GetParam(constant.NACOS_ENDPOINT, "")
+	clientConfig.NamespaceId = url.GetParam(constant.NACOS_NAMESPACE_ID, "")
 	clientConfig.NotLoadCacheAtStart = true
 	configMap["clientConfig"] = clientConfig
 
diff --git a/registry/nacos/registry_test.go b/registry/nacos/registry_test.go
index d0311b2..43a6da7 100644
--- a/registry/nacos/registry_test.go
+++ b/registry/nacos/registry_test.go
@@ -44,7 +44,7 @@
 	urlMap.Set(constant.CLUSTER_KEY, "mock")
 	testUrl, _ := common.NewURL("dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider", common.WithParams(urlMap), common.WithMethods([]string{"GetUser", "AddUser"}))
 
-	reg, err := newNacosRegistry(&regurl)
+	reg, err := newNacosRegistry(regurl)
 	assert.Nil(t, err)
 	if err != nil {
 		t.Errorf("new nacos registry error:%s \n", err.Error())
@@ -74,7 +74,7 @@
 	urlMap.Set(constant.NACOS_PATH_KEY, "")
 	testUrl, _ := common.NewURL("dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider", common.WithParams(urlMap), common.WithMethods([]string{"GetUser", "AddUser"}))
 
-	reg, _ := newNacosRegistry(&regurl)
+	reg, _ := newNacosRegistry(regurl)
 	err := reg.Register(testUrl)
 	assert.Nil(t, err)
 	if err != nil {
@@ -83,8 +83,8 @@
 	}
 
 	regurl.SetParam(constant.ROLE_KEY, strconv.Itoa(common.CONSUMER))
-	reg2, _ := newNacosRegistry(&regurl)
-	listener, err := reg2.(*nacosRegistry).subscribe(&testUrl)
+	reg2, _ := newNacosRegistry(regurl)
+	listener, err := reg2.(*nacosRegistry).subscribe(testUrl)
 	assert.Nil(t, err)
 	if err != nil {
 		t.Errorf("subscribe error:%s \n", err.Error())
@@ -113,7 +113,7 @@
 	url1, _ := common.NewURL("dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider", common.WithParams(urlMap), common.WithMethods([]string{"GetUser", "AddUser"}))
 	url2, _ := common.NewURL("dubbo://127.0.0.2:20000/com.ikurento.user.UserProvider", common.WithParams(urlMap), common.WithMethods([]string{"GetUser", "AddUser"}))
 
-	reg, _ := newNacosRegistry(&regurl)
+	reg, _ := newNacosRegistry(regurl)
 	err := reg.Register(url1)
 	assert.Nil(t, err)
 	if err != nil {
@@ -128,8 +128,8 @@
 	}
 
 	regurl.SetParam(constant.ROLE_KEY, strconv.Itoa(common.CONSUMER))
-	reg2, _ := newNacosRegistry(&regurl)
-	listener, err := reg2.(*nacosRegistry).subscribe(&url1)
+	reg2, _ := newNacosRegistry(regurl)
+	listener, err := reg2.(*nacosRegistry).subscribe(url1)
 	assert.Nil(t, err)
 	if err != nil {
 		t.Errorf("subscribe error:%s \n", err.Error())
@@ -177,8 +177,8 @@
 	urlMap.Set(constant.CLUSTER_KEY, "mock")
 	urlMap.Set(constant.NACOS_PATH_KEY, "")
 	url1, _ := common.NewURL("dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider2", common.WithParams(urlMap), common.WithMethods([]string{"GetUser", "AddUser"}))
-	reg, _ := newNacosRegistry(&regurl)
-	listener, err := reg.(*nacosRegistry).subscribe(&url1)
+	reg, _ := newNacosRegistry(regurl)
+	listener, err := reg.(*nacosRegistry).subscribe(url1)
 	assert.Nil(t, err)
 	if err != nil {
 		t.Errorf("subscribe error:%s \n", err.Error())
diff --git a/registry/protocol/protocol.go b/registry/protocol/protocol.go
index 69a31ef..e3af9ba 100644
--- a/registry/protocol/protocol.go
+++ b/registry/protocol/protocol.go
@@ -130,31 +130,30 @@
 }
 
 // Refer provider service from registry center
-func (proto *registryProtocol) Refer(url common.URL) protocol.Invoker {
+func (proto *registryProtocol) Refer(url *common.URL) protocol.Invoker {
 	var registryUrl = url
 	var serviceUrl = registryUrl.SubURL
 	if registryUrl.Protocol == constant.REGISTRY_PROTOCOL {
-		protocol := registryUrl.GetParam(constant.REGISTRY_KEY, "")
-		registryUrl.Protocol = protocol
+		registryUrl.Protocol = registryUrl.GetParam(constant.REGISTRY_KEY, "")
 	}
 
 	var reg registry.Registry
 	if regI, loaded := proto.registries.Load(registryUrl.Key()); !loaded {
-		reg = getRegistry(&registryUrl)
+		reg = getRegistry(registryUrl)
 		proto.registries.Store(registryUrl.Key(), reg)
 	} else {
 		reg = regI.(registry.Registry)
 	}
 
 	// new registry directory for store service url from registry
-	directory, err := extension.GetDefaultRegistryDirectory(&registryUrl, reg)
+	directory, err := extension.GetDefaultRegistryDirectory(registryUrl, reg)
 	if err != nil {
 		logger.Errorf("consumer service %v create registry directory error, error message is %s, and will return nil invoker!",
 			serviceUrl.String(), err.Error())
 		return nil
 	}
 
-	err = reg.Register(*serviceUrl)
+	err = reg.Register(serviceUrl)
 	if err != nil {
 		logger.Errorf("consumer service %v register registry %v error, error message is %s",
 			serviceUrl.String(), registryUrl.String(), err.Error())
@@ -194,7 +193,7 @@
 	}
 
 	registeredProviderUrl := getUrlToRegistry(providerUrl, registryUrl)
-	err := reg.Register(*registeredProviderUrl)
+	err := reg.Register(registeredProviderUrl)
 	if err != nil {
 		logger.Errorf("provider service %v register registry %v error, error message is %s",
 			providerUrl.Key(), registryUrl.Key(), err.Error())
@@ -247,8 +246,8 @@
 	}
 
 	event := events[0]
-	if isMatched(&(event.Service), nl.url) && event.Action == remoting.EventTypeAdd {
-		nl.configurator = extension.GetDefaultConfigurator(&(event.Service))
+	if isMatched(event.Service, nl.url) && event.Action == remoting.EventTypeAdd {
+		nl.configurator = extension.GetDefaultConfigurator(event.Service)
 		nl.doOverrideIfNecessary()
 	}
 }
@@ -275,9 +274,9 @@
 		}
 
 		if currentUrl.String() != providerUrl.String() {
-			newRegUrl := nl.originInvoker.GetUrl()
-			setProviderUrl(&newRegUrl, providerUrl)
-			nl.protocol.reExport(nl.originInvoker, &newRegUrl)
+			newRegUrl := nl.originInvoker.GetUrl().Clone()
+			setProviderUrl(newRegUrl, providerUrl)
+			nl.protocol.reExport(nl.originInvoker, newRegUrl)
 		}
 	}
 }
@@ -369,10 +368,9 @@
 	url := invoker.GetUrl()
 	// if the protocol == registry, set protocol the registry value in url.params
 	if url.Protocol == constant.REGISTRY_PROTOCOL {
-		protocol := url.GetParam(constant.REGISTRY_KEY, "")
-		url.Protocol = protocol
+		url.Protocol = url.GetParam(constant.REGISTRY_KEY, "")
 	}
-	return &url
+	return url
 }
 
 func getProviderUrl(invoker protocol.Invoker) *common.URL {
@@ -401,7 +399,7 @@
 func newWrappedInvoker(invoker protocol.Invoker, url *common.URL) *wrappedInvoker {
 	return &wrappedInvoker{
 		invoker:     invoker,
-		BaseInvoker: *protocol.NewBaseInvoker(*url),
+		BaseInvoker: *protocol.NewBaseInvoker(url),
 	}
 }
 
diff --git a/registry/protocol/protocol_test.go b/registry/protocol/protocol_test.go
index 2d6e024..0fca552 100644
--- a/registry/protocol/protocol_test.go
+++ b/registry/protocol/protocol_test.go
@@ -59,7 +59,7 @@
 		common.WithParamsValue(constant.CLUSTER_KEY, "mock"),
 	)
 
-	url.SubURL = &suburl
+	url.SubURL = suburl
 
 	invoker := regProtocol.Refer(url)
 	assert.IsType(t, &protocol.BaseInvoker{}, invoker)
@@ -84,7 +84,7 @@
 		common.WithParamsValue(constant.CLUSTER_KEY, "mock"),
 	)
 
-	url2.SubURL = &suburl2
+	url2.SubURL = suburl2
 
 	regProtocol.Refer(url2)
 	var count int
@@ -105,7 +105,7 @@
 		common.WithParamsValue(constant.CLUSTER_KEY, "mock"),
 	)
 
-	url2.SubURL = &suburl2
+	url2.SubURL = suburl2
 
 	regProtocol.Refer(url2)
 	var count int
@@ -128,13 +128,13 @@
 		common.WithParamsValue(constant.VERSION_KEY, "1.0.0"),
 	)
 
-	url.SubURL = &suburl
+	url.SubURL = suburl
 	invoker := protocol.NewBaseInvoker(url)
 	exporter := regProtocol.Export(invoker)
 
 	assert.IsType(t, &protocol.BaseExporter{}, exporter)
 	assert.Equal(t, exporter.GetInvoker().GetUrl().String(), suburl.String())
-	return &url
+	return url
 }
 
 func TestExporter(t *testing.T) {
@@ -153,7 +153,7 @@
 		common.WithParamsValue(constant.CLUSTER_KEY, "mock"),
 	)
 
-	url2.SubURL = &suburl2
+	url2.SubURL = suburl2
 	invoker2 := protocol.NewBaseInvoker(url2)
 	regProtocol.Export(invoker2)
 
@@ -184,7 +184,7 @@
 		common.WithParamsValue(constant.VERSION_KEY, "1.0.0"),
 	)
 
-	url2.SubURL = &suburl2
+	url2.SubURL = suburl2
 	invoker2 := protocol.NewBaseInvoker(url2)
 	regProtocol.Export(invoker2)
 
@@ -253,7 +253,7 @@
 func TestExportWithServiceConfig(t *testing.T) {
 	extension.SetDefaultConfigurator(configurator.NewMockConfigurator)
 	ccUrl, _ := common.NewURL("mock://127.0.0.1:1111")
-	dc, _ := (&config_center.MockDynamicConfigurationFactory{}).GetDynamicConfiguration(&ccUrl)
+	dc, _ := (&config_center.MockDynamicConfigurationFactory{}).GetDynamicConfiguration(ccUrl)
 	common_cfg.GetEnvInstance().SetDynamicConfiguration(dc)
 	regProtocol := newRegistryProtocol()
 	url := exporterNormal(t, regProtocol)
@@ -265,6 +265,7 @@
 
 	newUrl := url.SubURL.Clone()
 	newUrl.SetParam(constant.CLUSTER_KEY, "mock1")
+
 	v2, _ := regProtocol.bounds.Load(getCacheKey(newUrl))
 	assert.NotNil(t, v2)
 }
@@ -272,7 +273,7 @@
 func TestExportWithApplicationConfig(t *testing.T) {
 	extension.SetDefaultConfigurator(configurator.NewMockConfigurator)
 	ccUrl, _ := common.NewURL("mock://127.0.0.1:1111")
-	dc, _ := (&config_center.MockDynamicConfigurationFactory{}).GetDynamicConfiguration(&ccUrl)
+	dc, _ := (&config_center.MockDynamicConfigurationFactory{}).GetDynamicConfiguration(ccUrl)
 	common_cfg.GetEnvInstance().SetDynamicConfiguration(dc)
 	regProtocol := newRegistryProtocol()
 	url := exporterNormal(t, regProtocol)
@@ -290,7 +291,7 @@
 
 func TestGetProviderUrlWithHideKey(t *testing.T) {
 	url, _ := common.NewURL("dubbo://127.0.0.1:1111?a=a1&b=b1&.c=c1&.d=d1&e=e1&protocol=registry")
-	providerUrl := getUrlToRegistry(&url, &url)
+	providerUrl := getUrlToRegistry(url, url)
 	assert.NotContains(t, providerUrl.GetParams(), ".c")
 	assert.NotContains(t, providerUrl.GetParams(), ".d")
 	assert.Contains(t, providerUrl.GetParams(), "a")
diff --git a/registry/registry.go b/registry/registry.go
index 2225d2c..73940fa 100644
--- a/registry/registry.go
+++ b/registry/registry.go
@@ -34,7 +34,7 @@
 	// Register is used for service provider calling, register services
 	// to registry. And it is also used for service consumer calling, register
 	// services cared about, for dubbo's admin monitoring.
-	Register(url common.URL) error
+	Register(url *common.URL) error
 
 	// UnRegister is required to support the contract:
 	// 1. If it is the persistent stored data of dynamic=false, the
@@ -43,7 +43,7 @@
 	// 2. Unregister according to the full url match.
 	// url Registration information, is not allowed to be empty, e.g:
 	// dubbo://10.20.153.10/org.apache.dubbo.foo.BarService?version=1.0.0&application=kylin
-	UnRegister(url common.URL) error
+	UnRegister(url *common.URL) error
 
 	// Subscribe is required to support the contract:
 	// When creating new registry extension, pls select one of the
diff --git a/registry/servicediscovery/instance/random/random_service_instance_selector.go b/registry/servicediscovery/instance/random/random_service_instance_selector.go
index 3f8f30d..7e4e0ee 100644
--- a/registry/servicediscovery/instance/random/random_service_instance_selector.go
+++ b/registry/servicediscovery/instance/random/random_service_instance_selector.go
@@ -41,7 +41,7 @@
 	return &RandomServiceInstanceSelector{}
 }
 
-func (r *RandomServiceInstanceSelector) Select(url common.URL, serviceInstances []registry.ServiceInstance) registry.ServiceInstance {
+func (r *RandomServiceInstanceSelector) Select(url *common.URL, serviceInstances []registry.ServiceInstance) registry.ServiceInstance {
 	if len(serviceInstances) == 0 {
 		return nil
 	}
diff --git a/registry/servicediscovery/instance/random/random_service_instance_selector_test.go b/registry/servicediscovery/instance/random/random_service_instance_selector_test.go
index cddeb42..c53c058 100644
--- a/registry/servicediscovery/instance/random/random_service_instance_selector_test.go
+++ b/registry/servicediscovery/instance/random/random_service_instance_selector_test.go
@@ -52,5 +52,5 @@
 			Metadata:    nil,
 		},
 	}
-	assert.NotNil(t, selector.Select(common.URL{}, serviceInstances))
+	assert.NotNil(t, selector.Select(&common.URL{}, serviceInstances))
 }
diff --git a/registry/servicediscovery/instance/service_instance_selector.go b/registry/servicediscovery/instance/service_instance_selector.go
index 82fb345..5690ab6 100644
--- a/registry/servicediscovery/instance/service_instance_selector.go
+++ b/registry/servicediscovery/instance/service_instance_selector.go
@@ -24,5 +24,5 @@
 
 type ServiceInstanceSelector interface {
 	//Select an instance of ServiceInstance by the specified ServiceInstance service instances
-	Select(url common.URL, serviceInstances []registry.ServiceInstance) registry.ServiceInstance
+	Select(url *common.URL, serviceInstances []registry.ServiceInstance) registry.ServiceInstance
 }
diff --git a/registry/servicediscovery/service_discovery_registry.go b/registry/servicediscovery/service_discovery_registry.go
index 4db2c5a..ad6ec98 100644
--- a/registry/servicediscovery/service_discovery_registry.go
+++ b/registry/servicediscovery/service_discovery_registry.go
@@ -26,7 +26,6 @@
 )
 
 import (
-	cm "github.com/Workiva/go-datastructures/common"
 	gxset "github.com/dubbogo/gost/container/set"
 	perrors "github.com/pkg/errors"
 	"go.uber.org/atomic"
@@ -70,7 +69,7 @@
 	metaDataService                  service.MetadataService
 	registeredListeners              *gxset.HashSet
 	subscribedURLsSynthesizers       []synthesizer.SubscribedURLsSynthesizer
-	serviceRevisionExportedURLsCache map[string]map[string][]common.URL
+	serviceRevisionExportedURLsCache map[string]map[string][]*common.URL
 }
 
 func newServiceDiscoveryRegistry(url *common.URL) (registry.Registry, error) {
@@ -94,13 +93,13 @@
 		subscribedServices:               subscribedServices,
 		subscribedURLsSynthesizers:       subscribedURLsSynthesizers,
 		registeredListeners:              gxset.NewSet(),
-		serviceRevisionExportedURLsCache: make(map[string]map[string][]common.URL, 8),
+		serviceRevisionExportedURLsCache: make(map[string]map[string][]*common.URL, 8),
 		serviceNameMapping:               serviceNameMapping,
 		metaDataService:                  metaDataService,
 	}, nil
 }
 
-func (s *serviceDiscoveryRegistry) UnRegister(url common.URL) error {
+func (s *serviceDiscoveryRegistry) UnRegister(url *common.URL) error {
 	if !shouldRegister(url) {
 		return nil
 	}
@@ -108,10 +107,10 @@
 }
 
 func (s *serviceDiscoveryRegistry) UnSubscribe(url *common.URL, listener registry.NotifyListener) error {
-	if !shouldSubscribe(*url) {
+	if !shouldSubscribe(url) {
 		return nil
 	}
-	return s.metaDataService.UnsubscribeURL(*url)
+	return s.metaDataService.UnsubscribeURL(url)
 }
 
 func creatServiceDiscovery(url *common.URL) (registry.ServiceDiscovery, error) {
@@ -145,8 +144,8 @@
 	return s.serviceDiscovery
 }
 
-func (s *serviceDiscoveryRegistry) GetUrl() common.URL {
-	return *s.url
+func (s *serviceDiscoveryRegistry) GetUrl() *common.URL {
+	return s.url
 }
 
 func (s *serviceDiscoveryRegistry) IsAvailable() bool {
@@ -161,7 +160,7 @@
 	}
 }
 
-func (s *serviceDiscoveryRegistry) Register(url common.URL) error {
+func (s *serviceDiscoveryRegistry) Register(url *common.URL) error {
 	if !shouldRegister(url) {
 		return nil
 	}
@@ -185,7 +184,7 @@
 		url.Protocol)
 }
 
-func shouldRegister(url common.URL) bool {
+func shouldRegister(url *common.URL) bool {
 	side := url.GetParam(constant.SIDE_KEY, "")
 	if side == constant.PROVIDER_PROTOCOL {
 		return true
@@ -195,14 +194,14 @@
 }
 
 func (s *serviceDiscoveryRegistry) Subscribe(url *common.URL, notify registry.NotifyListener) error {
-	if !shouldSubscribe(*url) {
+	if !shouldSubscribe(url) {
 		return nil
 	}
-	_, err := s.metaDataService.SubscribeURL(*url)
+	_, err := s.metaDataService.SubscribeURL(url)
 	if err != nil {
 		return perrors.WithMessage(err, "subscribe url error: "+url.String())
 	}
-	services := s.getServices(*url)
+	services := s.getServices(url)
 	if services.Empty() {
 		return perrors.Errorf("Should has at least one way to know which services this interface belongs to, "+
 			"subscription url:%s", url.String())
@@ -218,12 +217,12 @@
 				serviceDiscoveryRegistry: s,
 			},
 		}
-		s.registerServiceInstancesChangedListener(*url, listener)
+		s.registerServiceInstancesChangedListener(url, listener)
 	}
 	return nil
 }
 
-func (s *serviceDiscoveryRegistry) registerServiceInstancesChangedListener(url common.URL, listener *registry.ServiceInstancesChangedListener) {
+func (s *serviceDiscoveryRegistry) registerServiceInstancesChangedListener(url *common.URL, listener *registry.ServiceInstancesChangedListener) {
 	listenerId := listener.ServiceName + ":" + getUrlKey(url)
 	if !s.subscribedServices.Contains(listenerId) {
 		err := s.serviceDiscovery.AddListener(listener)
@@ -234,7 +233,7 @@
 
 }
 
-func getUrlKey(url common.URL) string {
+func getUrlKey(url *common.URL) string {
 	var bf bytes.Buffer
 	if len(url.Protocol) != 0 {
 		bf.WriteString(url.Protocol)
@@ -256,7 +255,7 @@
 	return bf.String()
 }
 
-func appendParam(buffer bytes.Buffer, paramKey string, url common.URL) {
+func appendParam(buffer bytes.Buffer, paramKey string, url *common.URL) {
 	buffer.WriteString(paramKey)
 	buffer.WriteString("=")
 	buffer.WriteString(url.GetParam(paramKey, ""))
@@ -268,8 +267,8 @@
 		logger.Warnf("here is no instance in service[name : %s]", serviceName)
 		return
 	}
-	var subscribedURLs []common.URL
-	subscribedURLs = append(subscribedURLs, s.getExportedUrls(*url, serviceInstances)...)
+	var subscribedURLs []*common.URL
+	subscribedURLs = append(subscribedURLs, s.getExportedUrls(url, serviceInstances)...)
 	if len(subscribedURLs) == 0 {
 		subscribedURLs = s.synthesizeSubscribedURLs(url, serviceInstances)
 	}
@@ -282,8 +281,8 @@
 
 }
 
-func (s *serviceDiscoveryRegistry) synthesizeSubscribedURLs(subscribedURL *common.URL, serviceInstances []registry.ServiceInstance) []common.URL {
-	var urls []common.URL
+func (s *serviceDiscoveryRegistry) synthesizeSubscribedURLs(subscribedURL *common.URL, serviceInstances []registry.ServiceInstance) []*common.URL {
+	var urls []*common.URL
 	for _, syn := range s.subscribedURLsSynthesizers {
 		if syn.Support(subscribedURL) {
 			urls = append(urls, syn.Synthesize(subscribedURL, serviceInstances)...)
@@ -292,11 +291,11 @@
 	return urls
 }
 
-func shouldSubscribe(url common.URL) bool {
+func shouldSubscribe(url *common.URL) bool {
 	return !shouldRegister(url)
 }
 
-func (s *serviceDiscoveryRegistry) getServices(url common.URL) *gxset.HashSet {
+func (s *serviceDiscoveryRegistry) getServices(url *common.URL) *gxset.HashSet {
 	services := gxset.NewSet()
 	serviceNames := url.GetParam(constant.PROVIDER_BY, "")
 	if len(serviceNames) > 0 {
@@ -311,7 +310,7 @@
 	return services
 }
 
-func (s *serviceDiscoveryRegistry) findMappedServices(url common.URL) *gxset.HashSet {
+func (s *serviceDiscoveryRegistry) findMappedServices(url *common.URL) *gxset.HashSet {
 	serviceInterface := url.GetParam(constant.INTERFACE_KEY, url.Path)
 	group := url.GetParam(constant.GROUP_KEY, "")
 	version := url.GetParam(constant.VERSION_KEY, "")
@@ -325,7 +324,7 @@
 	return serviceNames
 }
 
-func (s *serviceDiscoveryRegistry) getExportedUrls(subscribedURL common.URL, serviceInstances []registry.ServiceInstance) []common.URL {
+func (s *serviceDiscoveryRegistry) getExportedUrls(subscribedURL *common.URL, serviceInstances []registry.ServiceInstance) []*common.URL {
 	var filterInstances []registry.ServiceInstance
 	for _, s := range serviceInstances {
 		if !s.IsEnable() || !s.IsHealthy() {
@@ -340,32 +339,15 @@
 		filterInstances = append(filterInstances, s)
 	}
 	if len(filterInstances) == 0 {
-		return []common.URL{}
+		return []*common.URL{}
 	}
 	s.prepareServiceRevisionExportedURLs(filterInstances)
 	subscribedURLs := s.cloneExportedURLs(subscribedURL, filterInstances)
 	return subscribedURLs
 }
 
-// comparator is defined as Comparator for skip list to compare the URL
-type comparator common.URL
-
-// Compare is defined as Comparator for skip list to compare the URL
-func (c comparator) Compare(comp cm.Comparator) int {
-	a := common.URL(c).String()
-	b := common.URL(comp.(comparator)).String()
-	switch {
-	case a > b:
-		return 1
-	case a < b:
-		return -1
-	default:
-		return 0
-	}
-}
-
-func (s *serviceDiscoveryRegistry) getExportedUrlsByInst(serviceInstance registry.ServiceInstance) []common.URL {
-	var urls []common.URL
+func (s *serviceDiscoveryRegistry) getExportedUrlsByInst(serviceInstance registry.ServiceInstance) []*common.URL {
+	var urls []*common.URL
 	metadataStorageType := getExportedStoreType(serviceInstance)
 	proxyFactory := extension.GetMetadataServiceProxyFactory(metadataStorageType)
 	if proxyFactory == nil {
@@ -381,7 +363,7 @@
 		return urls
 	}
 
-	ret := make([]common.URL, 0, len(result))
+	ret := make([]*common.URL, 0, len(result))
 	for _, ui := range result {
 
 		u, err := common.NewURL(ui.(string))
@@ -464,18 +446,18 @@
 		logger.Errorf("get service instance selector cathe error:%s", err.Error())
 		return nil
 	}
-	return selector.Select(*s.url, serviceInstances)
+	return selector.Select(s.url, serviceInstances)
 }
 
-func (s *serviceDiscoveryRegistry) initRevisionExportedURLsByInst(serviceInstance registry.ServiceInstance) []common.URL {
+func (s *serviceDiscoveryRegistry) initRevisionExportedURLsByInst(serviceInstance registry.ServiceInstance) []*common.URL {
 	if serviceInstance == nil {
-		return []common.URL{}
+		return nil
 	}
 	serviceName := serviceInstance.GetServiceName()
 	revision := getExportedServicesRevision(serviceInstance)
 	revisionExportedURLsMap := s.serviceRevisionExportedURLsCache[serviceName]
 	if revisionExportedURLsMap == nil {
-		revisionExportedURLsMap = make(map[string][]common.URL, 4)
+		revisionExportedURLsMap = make(map[string][]*common.URL, 4)
 		s.serviceRevisionExportedURLsCache[serviceName] = revisionExportedURLsMap
 	}
 	revisionExportedURLs := revisionExportedURLsMap[revision]
@@ -521,11 +503,11 @@
 	return result
 }
 
-func (s *serviceDiscoveryRegistry) cloneExportedURLs(url common.URL, serviceInsances []registry.ServiceInstance) []common.URL {
+func (s *serviceDiscoveryRegistry) cloneExportedURLs(url *common.URL, serviceInsances []registry.ServiceInstance) []*common.URL {
 	if len(serviceInsances) == 0 {
-		return []common.URL{}
+		return []*common.URL{}
 	}
-	var clonedExportedURLs []common.URL
+	var clonedExportedURLs []*common.URL
 	removeParamSet := gxset.NewSet()
 	removeParamSet.Add(constant.PID_KEY)
 	removeParamSet.Add(constant.TIMESTAMP_KEY)
@@ -540,7 +522,7 @@
 			}
 
 			cloneUrl := u.CloneExceptParams(removeParamSet)
-			clonedExportedURLs = append(clonedExportedURLs, *cloneUrl)
+			clonedExportedURLs = append(clonedExportedURLs, cloneUrl)
 		}
 	}
 	return clonedExportedURLs
@@ -548,8 +530,8 @@
 }
 
 type endpoint struct {
-	Port     int    `json:"port, omitempty"`
-	Protocol string `json:"protocol, omitempty"`
+	Port     int    `json:"port,omitempty"`
+	Protocol string `json:"protocol,omitempty"`
 }
 
 func getProtocolPort(serviceInstance registry.ServiceInstance, protocol string) int {
@@ -571,38 +553,38 @@
 	}
 	return -1
 }
-func (s *serviceDiscoveryRegistry) getTemplateExportedURLs(url common.URL, serviceInstance registry.ServiceInstance) []common.URL {
+func (s *serviceDiscoveryRegistry) getTemplateExportedURLs(url *common.URL, serviceInstance registry.ServiceInstance) []*common.URL {
 	exportedURLs := s.getRevisionExportedURLs(serviceInstance)
 	if len(exportedURLs) == 0 {
-		return []common.URL{}
+		return []*common.URL{}
 	}
 	return filterSubscribedURLs(url, exportedURLs)
 }
 
-func (s *serviceDiscoveryRegistry) getRevisionExportedURLs(serviceInstance registry.ServiceInstance) []common.URL {
+func (s *serviceDiscoveryRegistry) getRevisionExportedURLs(serviceInstance registry.ServiceInstance) []*common.URL {
 	if serviceInstance == nil {
-		return []common.URL{}
+		return []*common.URL{}
 	}
 	serviceName := serviceInstance.GetServiceName()
 	revision := getExportedServicesRevision(serviceInstance)
 	s.lock.RLock()
 	revisionExportedURLsMap, exist := s.serviceRevisionExportedURLsCache[serviceName]
 	if !exist {
-		return []common.URL{}
+		return []*common.URL{}
 	}
 	exportedURLs, exist := revisionExportedURLsMap[revision]
 	if !exist {
-		return []common.URL{}
+		return []*common.URL{}
 	}
 	s.lock.RUnlock()
 	// Get a copy from source in order to prevent the caller trying to change the cached data
-	cloneExportedURLs := make([]common.URL, len(exportedURLs))
+	cloneExportedURLs := make([]*common.URL, len(exportedURLs))
 	copy(cloneExportedURLs, exportedURLs)
 	return cloneExportedURLs
 }
 
-func filterSubscribedURLs(subscribedURL common.URL, exportedURLs []common.URL) []common.URL {
-	var filterExportedURLs []common.URL
+func filterSubscribedURLs(subscribedURL *common.URL, exportedURLs []*common.URL) []*common.URL {
+	var filterExportedURLs []*common.URL
 	for _, url := range exportedURLs {
 		if url.GetParam(constant.INTERFACE_KEY, url.Path) != subscribedURL.GetParam(constant.INTERFACE_KEY, url.Path) {
 			break
diff --git a/registry/servicediscovery/service_discovery_registry_test.go b/registry/servicediscovery/service_discovery_registry_test.go
index 53eb865..ad6b73d 100644
--- a/registry/servicediscovery/service_discovery_registry_test.go
+++ b/registry/servicediscovery/service_discovery_registry_test.go
@@ -76,7 +76,7 @@
 		"&service_discovery=mock" +
 		"&methods=getAllServiceKeys,getServiceRestMetadata,getExportedURLs,getAllExportedURLs" +
 		"&side=provider")
-	registry, err := newServiceDiscoveryRegistry(&registryURL)
+	registry, err := newServiceDiscoveryRegistry(registryURL)
 	assert.Nil(t, err)
 	assert.NotNil(t, registry)
 	registry.Register(url)
@@ -85,19 +85,19 @@
 type mockEventDispatcher struct {
 }
 
-func (m *mockEventDispatcher) AddEventListener(listener observer.EventListener) {
+func (m *mockEventDispatcher) AddEventListener(observer.EventListener) {
 
 }
 
-func (m *mockEventDispatcher) AddEventListeners(listenersSlice []observer.EventListener) {
+func (m *mockEventDispatcher) AddEventListeners([]observer.EventListener) {
 
 }
 
-func (m *mockEventDispatcher) RemoveEventListener(listener observer.EventListener) {
+func (m *mockEventDispatcher) RemoveEventListener(observer.EventListener) {
 	panic("implement me")
 }
 
-func (m *mockEventDispatcher) RemoveEventListeners(listenersSlice []observer.EventListener) {
+func (m *mockEventDispatcher) RemoveEventListeners([]observer.EventListener) {
 	panic("implement me")
 }
 
@@ -109,17 +109,17 @@
 	panic("implement me")
 }
 
-func (m *mockEventDispatcher) Dispatch(event observer.Event) {
+func (m *mockEventDispatcher) Dispatch(observer.Event) {
 }
 
 type mockServiceNameMapping struct {
 }
 
-func (m *mockServiceNameMapping) Map(serviceInterface string, group string, version string, protocol string) error {
+func (m *mockServiceNameMapping) Map(string, string, string, string) error {
 	return nil
 }
 
-func (m *mockServiceNameMapping) Get(serviceInterface string, group string, version string, protocol string) (*gxset.HashSet, error) {
+func (m *mockServiceNameMapping) Get(string, string, string, string) (*gxset.HashSet, error) {
 	panic("implement me")
 }
 
@@ -134,15 +134,15 @@
 	panic("implement me")
 }
 
-func (m *mockServiceDiscovery) Register(instance registry.ServiceInstance) error {
+func (m *mockServiceDiscovery) Register(registry.ServiceInstance) error {
 	return nil
 }
 
-func (m *mockServiceDiscovery) Update(instance registry.ServiceInstance) error {
+func (m *mockServiceDiscovery) Update(registry.ServiceInstance) error {
 	panic("implement me")
 }
 
-func (m *mockServiceDiscovery) Unregister(instance registry.ServiceInstance) error {
+func (m *mockServiceDiscovery) Unregister(registry.ServiceInstance) error {
 	panic("implement me")
 }
 
@@ -154,35 +154,35 @@
 	panic("implement me")
 }
 
-func (m *mockServiceDiscovery) GetInstances(serviceName string) []registry.ServiceInstance {
+func (m *mockServiceDiscovery) GetInstances(string) []registry.ServiceInstance {
 	panic("implement me")
 }
 
-func (m *mockServiceDiscovery) GetInstancesByPage(serviceName string, offset int, pageSize int) gxpage.Pager {
+func (m *mockServiceDiscovery) GetInstancesByPage(string, int, int) gxpage.Pager {
 	panic("implement me")
 }
 
-func (m *mockServiceDiscovery) GetHealthyInstancesByPage(serviceName string, offset int, pageSize int, healthy bool) gxpage.Pager {
+func (m *mockServiceDiscovery) GetHealthyInstancesByPage(string, int, int, bool) gxpage.Pager {
 	panic("implement me")
 }
 
-func (m *mockServiceDiscovery) GetRequestInstances(serviceNames []string, offset int, requestedSize int) map[string]gxpage.Pager {
+func (m *mockServiceDiscovery) GetRequestInstances([]string, int, int) map[string]gxpage.Pager {
 	panic("implement me")
 }
 
-func (m *mockServiceDiscovery) AddListener(listener *registry.ServiceInstancesChangedListener) error {
+func (m *mockServiceDiscovery) AddListener(*registry.ServiceInstancesChangedListener) error {
 	panic("implement me")
 }
 
-func (m *mockServiceDiscovery) DispatchEventByServiceName(serviceName string) error {
+func (m *mockServiceDiscovery) DispatchEventByServiceName(string) error {
 	panic("implement me")
 }
 
-func (m *mockServiceDiscovery) DispatchEventForInstances(serviceName string, instances []registry.ServiceInstance) error {
+func (m *mockServiceDiscovery) DispatchEventForInstances(string, []registry.ServiceInstance) error {
 	panic("implement me")
 }
 
-func (m *mockServiceDiscovery) DispatchEvent(event *registry.ServiceInstancesChangedEvent) error {
+func (m *mockServiceDiscovery) DispatchEvent(*registry.ServiceInstancesChangedEvent) error {
 	panic("implement me")
 }
 
@@ -197,27 +197,27 @@
 	panic("implement me")
 }
 
-func (m *mockMetadataService) ExportURL(url common.URL) (bool, error) {
+func (m *mockMetadataService) ExportURL(*common.URL) (bool, error) {
 	return true, nil
 }
 
-func (m *mockMetadataService) UnexportURL(url common.URL) error {
+func (m *mockMetadataService) UnexportURL(*common.URL) error {
 	panic("implement me")
 }
 
-func (m *mockMetadataService) SubscribeURL(url common.URL) (bool, error) {
+func (m *mockMetadataService) SubscribeURL(*common.URL) (bool, error) {
 	panic("implement me")
 }
 
-func (m *mockMetadataService) UnsubscribeURL(url common.URL) error {
+func (m *mockMetadataService) UnsubscribeURL(*common.URL) error {
 	panic("implement me")
 }
 
-func (m *mockMetadataService) PublishServiceDefinition(url common.URL) error {
+func (m *mockMetadataService) PublishServiceDefinition(*common.URL) error {
 	return nil
 }
 
-func (m *mockMetadataService) GetExportedURLs(serviceInterface string, group string, version string, protocol string) ([]interface{}, error) {
+func (m *mockMetadataService) GetExportedURLs(string, string, string, string) ([]interface{}, error) {
 	panic("implement me")
 }
 
@@ -225,19 +225,19 @@
 	panic("implement me")
 }
 
-func (m *mockMetadataService) GetSubscribedURLs() ([]common.URL, error) {
+func (m *mockMetadataService) GetSubscribedURLs() ([]*common.URL, error) {
 	panic("implement me")
 }
 
-func (m *mockMetadataService) GetServiceDefinition(interfaceName string, group string, version string) (string, error) {
+func (m *mockMetadataService) GetServiceDefinition(string, string, string) (string, error) {
 	panic("implement me")
 }
 
-func (m *mockMetadataService) GetServiceDefinitionByServiceKey(serviceKey string) (string, error) {
+func (m *mockMetadataService) GetServiceDefinitionByServiceKey(string) (string, error) {
 	panic("implement me")
 }
 
-func (m *mockMetadataService) RefreshMetadata(exportedRevision string, subscribedRevision string) (bool, error) {
+func (m *mockMetadataService) RefreshMetadata(string, string) (bool, error) {
 	panic("implement me")
 }
 
diff --git a/registry/servicediscovery/synthesizer/rest/rest_subscribed_urls_synthesizer.go b/registry/servicediscovery/synthesizer/rest/rest_subscribed_urls_synthesizer.go
index 086a26d..d1ab611 100644
--- a/registry/servicediscovery/synthesizer/rest/rest_subscribed_urls_synthesizer.go
+++ b/registry/servicediscovery/synthesizer/rest/rest_subscribed_urls_synthesizer.go
@@ -44,8 +44,8 @@
 	return false
 }
 
-func (r RestSubscribedURLsSynthesizer) Synthesize(subscribedURL *common.URL, serviceInstances []registry.ServiceInstance) []common.URL {
-	urls := make([]common.URL, len(serviceInstances), len(serviceInstances))
+func (r RestSubscribedURLsSynthesizer) Synthesize(subscribedURL *common.URL, serviceInstances []registry.ServiceInstance) []*common.URL {
+	urls := make([]*common.URL, len(serviceInstances), len(serviceInstances))
 	for i, s := range serviceInstances {
 		splitHost := strings.Split(s.GetHost(), ":")
 		u := common.NewURLWithOptions(common.WithProtocol(subscribedURL.Protocol), common.WithIp(splitHost[0]),
@@ -55,7 +55,7 @@
 			common.WithParamsValue(constant.APPLICATION_KEY, s.GetServiceName()),
 			common.WithParamsValue(constant.REGISTRY_KEY, "true"),
 		)
-		urls[i] = *u
+		urls[i] = u
 	}
 	return urls
 }
diff --git a/registry/servicediscovery/synthesizer/rest/rest_subscribed_urls_synthesizer_test.go b/registry/servicediscovery/synthesizer/rest/rest_subscribed_urls_synthesizer_test.go
index b52cc23..1bb38c9 100644
--- a/registry/servicediscovery/synthesizer/rest/rest_subscribed_urls_synthesizer_test.go
+++ b/registry/servicediscovery/synthesizer/rest/rest_subscribed_urls_synthesizer_test.go
@@ -56,7 +56,7 @@
 		},
 	}
 
-	var expectUrls []common.URL
+	var expectUrls []*common.URL
 	u1 := common.NewURLWithOptions(common.WithProtocol("rest"), common.WithIp("127.0.0.1"),
 		common.WithPort("80"), common.WithPath("org.apache.dubbo-go.mockService"),
 		common.WithParams(url.Values{}),
@@ -69,7 +69,7 @@
 		common.WithParamsValue(constant.SIDE_KEY, constant.PROVIDER_PROTOCOL),
 		common.WithParamsValue(constant.APPLICATION_KEY, "test2"),
 		common.WithParamsValue(constant.REGISTRY_KEY, "true"))
-	expectUrls = append(expectUrls, *u1, *u2)
-	result := syn.Synthesize(&subUrl, instances)
+	expectUrls = append(expectUrls, u1, u2)
+	result := syn.Synthesize(subUrl, instances)
 	assert.Equal(t, expectUrls, result)
 }
diff --git a/registry/servicediscovery/synthesizer/subscribed_urls_synthesizer.go b/registry/servicediscovery/synthesizer/subscribed_urls_synthesizer.go
index 415ca35..557c86e 100644
--- a/registry/servicediscovery/synthesizer/subscribed_urls_synthesizer.go
+++ b/registry/servicediscovery/synthesizer/subscribed_urls_synthesizer.go
@@ -27,5 +27,5 @@
 	// Supports the synthesis of the subscribed url or not
 	Support(subscribedURL *common.URL) bool
 	// synthesize the subscribed url
-	Synthesize(subscribedURL *common.URL, serviceInstances []registry.ServiceInstance) []common.URL
+	Synthesize(subscribedURL *common.URL, serviceInstances []registry.ServiceInstance) []*common.URL
 }
diff --git a/registry/zookeeper/listener.go b/registry/zookeeper/listener.go
index ec82fa0..88109fc 100644
--- a/registry/zookeeper/listener.go
+++ b/registry/zookeeper/listener.go
@@ -104,6 +104,7 @@
 func (l *RegistryDataListener) Close() {
 	l.mutex.Lock()
 	defer l.mutex.Unlock()
+	l.closed = true
 	for _, listener := range l.subscribed {
 		listener.(*RegistryConfigurationListener).Close()
 	}
@@ -158,7 +159,7 @@
 			//r.update(e.res)
 			//write to invoker
 			//r.outerEventCh <- e.res
-			return &registry.ServiceEvent{Action: e.ConfigType, Service: e.Value.(common.URL)}, nil
+			return &registry.ServiceEvent{Action: e.ConfigType, Service: e.Value.(*common.URL)}, nil
 		}
 	}
 }
diff --git a/registry/zookeeper/listener_test.go b/registry/zookeeper/listener_test.go
index a0e9147..20ec1cf 100644
--- a/registry/zookeeper/listener_test.go
+++ b/registry/zookeeper/listener_test.go
@@ -34,7 +34,7 @@
 func Test_DataChange(t *testing.T) {
 	listener := NewRegistryDataListener()
 	url, _ := common.NewURL("jsonrpc%3A%2F%2F127.0.0.1%3A20001%2Fcom.ikurento.user.UserProvider%3Fanyhost%3Dtrue%26app.version%3D0.0.1%26application%3DBDTService%26category%3Dproviders%26cluster%3Dfailover%26dubbo%3Ddubbo-provider-golang-1.3.0%26environment%3Ddev%26group%3D%26interface%3Dcom.ikurento.user.UserProvider%26ip%3D10.32.20.124%26loadbalance%3Drandom%26methods.GetUser.loadbalance%3Drandom%26methods.GetUser.retries%3D1%26methods.GetUser.weight%3D0%26module%3Ddubbogo%2Buser-info%2Bserver%26name%3DBDTService%26organization%3Dikurento.com%26owner%3DZX%26pid%3D74500%26retries%3D0%26service.filter%3Decho%26side%3Dprovider%26timestamp%3D1560155407%26version%3D%26warmup%3D100")
-	listener.SubscribeURL(&url, &MockConfigurationListener{})
+	listener.SubscribeURL(url, &MockConfigurationListener{})
 	int := listener.DataChange(remoting.Event{Path: "/dubbo/com.ikurento.user.UserProvider/providers/jsonrpc%3A%2F%2F127.0.0.1%3A20001%2Fcom.ikurento.user.UserProvider%3Fanyhost%3Dtrue%26app.version%3D0.0.1%26application%3DBDTService%26category%3Dproviders%26cluster%3Dfailover%26dubbo%3Ddubbo-provider-golang-1.3.0%26environment%3Ddev%26group%3D%26interface%3Dcom.ikurento.user.UserProvider%26ip%3D10.32.20.124%26loadbalance%3Drandom%26methods.GetUser.loadbalance%3Drandom%26methods.GetUser.retries%3D1%26methods.GetUser.weight%3D0%26module%3Ddubbogo%2Buser-info%2Bserver%26name%3DBDTService%26organization%3Dikurento.com%26owner%3DZX%26pid%3D74500%26retries%3D0%26service.filter%3Decho%26side%3Dprovider%26timestamp%3D1560155407%26version%3D%26warmup%3D100"})
 	assert.Equal(t, true, int)
 }
diff --git a/registry/zookeeper/registry.go b/registry/zookeeper/registry.go
index e8ee51b..76fc052 100644
--- a/registry/zookeeper/registry.go
+++ b/registry/zookeeper/registry.go
@@ -127,15 +127,15 @@
 		oldDataListener := r.dataListener
 		oldDataListener.mutex.Lock()
 		defer oldDataListener.mutex.Unlock()
-		recoverd := r.dataListener.subscribed
-		if recoverd != nil && len(recoverd) > 0 {
+		r.dataListener.closed = true
+		recovered := r.dataListener.subscribed
+		if recovered != nil && len(recovered) > 0 {
 			// recover all subscribed url
-			for _, oldListener := range recoverd {
+			for _, oldListener := range recovered {
 				var (
 					regConfigListener *RegistryConfigurationListener
 					ok                bool
 				)
-
 				if regConfigListener, ok = oldListener.(*RegistryConfigurationListener); ok {
 					regConfigListener.Close()
 				}
@@ -212,6 +212,9 @@
 
 	r.cltLock.Lock()
 	defer r.cltLock.Unlock()
+	if r.client == nil{
+		return perrors.WithStack(perrors.New("zk client already been closed"))
+	}
 	err = r.client.Create(root)
 	if err != nil {
 		logger.Errorf("zk.Create(root{%s}) = err{%v}", root, perrors.WithStack(err))
@@ -292,10 +295,10 @@
 	r.dataListener.mutex.Lock()
 	configurationListener := r.dataListener.subscribed[conf.ServiceKey()]
 	if configurationListener != nil {
-
 		zkListener, _ := configurationListener.(*RegistryConfigurationListener)
 		if zkListener != nil {
 			if zkListener.isClosed {
+				r.dataListener.mutex.Unlock()
 				return nil, perrors.New("configListener already been closed")
 			}
 		}
diff --git a/registry/zookeeper/registry_test.go b/registry/zookeeper/registry_test.go
index d915fc2..e630db7 100644
--- a/registry/zookeeper/registry_test.go
+++ b/registry/zookeeper/registry_test.go
@@ -37,7 +37,7 @@
 	regurl, _ := common.NewURL("registry://127.0.0.1:1111", common.WithParamsValue(constant.ROLE_KEY, strconv.Itoa(common.PROVIDER)))
 	url, _ := common.NewURL("dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider", common.WithParamsValue(constant.CLUSTER_KEY, "mock"), common.WithParamsValue("serviceid", "soa.mock"), common.WithMethods([]string{"GetUser", "AddUser"}))
 
-	ts, reg, _ := newMockZkRegistry(&regurl)
+	ts, reg, _ := newMockZkRegistry(regurl)
 	defer ts.Stop()
 	err := reg.Register(url)
 	children, _ := reg.client.GetChildren("/dubbo/com.ikurento.user.UserProvider/providers")
@@ -50,7 +50,7 @@
 	regurl, _ := common.NewURL("registry://127.0.0.1:1111", common.WithParamsValue(constant.ROLE_KEY, strconv.Itoa(common.PROVIDER)))
 	url, _ := common.NewURL("dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider", common.WithParamsValue(constant.CLUSTER_KEY, "mock"), common.WithParamsValue("serviceid", "soa.mock"), common.WithMethods([]string{"GetUser", "AddUser"}))
 
-	ts, reg, _ := newMockZkRegistry(&regurl)
+	ts, reg, _ := newMockZkRegistry(regurl)
 	defer ts.Stop()
 	err := reg.Register(url)
 	children, _ := reg.client.GetChildren("/dubbo/com.ikurento.user.UserProvider/providers")
@@ -73,7 +73,7 @@
 func Test_Subscribe(t *testing.T) {
 	regurl, _ := common.NewURL("registry://127.0.0.1:1111", common.WithParamsValue(constant.ROLE_KEY, strconv.Itoa(common.PROVIDER)))
 	url, _ := common.NewURL("dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider", common.WithParamsValue(constant.CLUSTER_KEY, "mock"), common.WithMethods([]string{"GetUser", "AddUser"}))
-	ts, reg, _ := newMockZkRegistry(&regurl)
+	ts, reg, _ := newMockZkRegistry(regurl)
 
 	//provider register
 	err := reg.Register(url)
@@ -85,10 +85,10 @@
 
 	//consumer register
 	regurl.SetParam(constant.ROLE_KEY, strconv.Itoa(common.CONSUMER))
-	_, reg2, _ := newMockZkRegistry(&regurl, zookeeper.WithTestCluster(ts))
+	_, reg2, _ := newMockZkRegistry(regurl, zookeeper.WithTestCluster(ts))
 
 	reg2.Register(url)
-	listener, _ := reg2.DoSubscribe(&url)
+	listener, _ := reg2.DoSubscribe(url)
 
 	serviceEvent, _ := listener.Next()
 	assert.NoError(t, err)
@@ -102,7 +102,7 @@
 func Test_UnSubscribe(t *testing.T) {
 	regurl, _ := common.NewURL("registry://127.0.0.1:1111", common.WithParamsValue(constant.ROLE_KEY, strconv.Itoa(common.PROVIDER)))
 	url, _ := common.NewURL("dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider", common.WithParamsValue(constant.CLUSTER_KEY, "mock"), common.WithMethods([]string{"GetUser", "AddUser"}))
-	ts, reg, _ := newMockZkRegistry(&regurl)
+	ts, reg, _ := newMockZkRegistry(regurl)
 
 	//provider register
 	err := reg.Register(url)
@@ -114,10 +114,10 @@
 
 	//consumer register
 	regurl.SetParam(constant.ROLE_KEY, strconv.Itoa(common.CONSUMER))
-	_, reg2, _ := newMockZkRegistry(&regurl, zookeeper.WithTestCluster(ts))
+	_, reg2, _ := newMockZkRegistry(regurl, zookeeper.WithTestCluster(ts))
 
 	reg2.Register(url)
-	listener, _ := reg2.DoSubscribe(&url)
+	listener, _ := reg2.DoSubscribe(url)
 
 	serviceEvent, _ := listener.Next()
 	assert.NoError(t, err)
@@ -126,7 +126,7 @@
 	}
 	assert.Regexp(t, ".*ServiceEvent{Action{add}.*", serviceEvent.String())
 
-	reg2.UnSubscribe(&url, nil)
+	reg2.UnSubscribe(url, nil)
 	assert.Nil(t, reg2.listener)
 
 	defer ts.Stop()
@@ -136,13 +136,13 @@
 	regurl, _ := common.NewURL("registry://127.0.0.1:1111", common.WithParamsValue(constant.ROLE_KEY, strconv.Itoa(common.CONSUMER)))
 	url, _ := common.NewURL("dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider", common.WithParamsValue(constant.CLUSTER_KEY, "mock"), common.WithMethods([]string{"GetUser", "AddUser"}))
 
-	ts, reg, err := newMockZkRegistry(&regurl)
+	ts, reg, err := newMockZkRegistry(regurl)
 	defer ts.Stop()
 
 	assert.NoError(t, err)
 	err = reg.Register(url)
 	assert.NoError(t, err)
-	_, err = reg.DoSubscribe(&url)
+	_, err = reg.DoSubscribe(url)
 	assert.NoError(t, err)
 
 	//listener.Close()
@@ -156,7 +156,7 @@
 	regurl, _ := common.NewURL("registry://127.0.0.1:1111", common.WithParamsValue(constant.ROLE_KEY, strconv.Itoa(common.PROVIDER)))
 	url, _ := common.NewURL("dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider", common.WithParamsValue(constant.CLUSTER_KEY, "mock"), common.WithMethods([]string{"GetUser", "AddUser"}))
 
-	ts, reg, err := newMockZkRegistry(&regurl)
+	ts, reg, err := newMockZkRegistry(regurl)
 	defer ts.Stop()
 
 	assert.NoError(t, err)
diff --git a/registry/zookeeper/service_discovery.go b/registry/zookeeper/service_discovery.go
index 5ad83ef..6d9582f 100644
--- a/registry/zookeeper/service_discovery.go
+++ b/registry/zookeeper/service_discovery.go
@@ -154,8 +154,8 @@
 }
 
 // nolint
-func (zksd *zookeeperServiceDiscovery) GetUrl() common.URL {
-	return *zksd.url
+func (zksd *zookeeperServiceDiscovery) GetUrl() *common.URL {
+	return zksd.url
 }
 
 // nolint
diff --git a/remoting/etcdv3/listener.go b/remoting/etcdv3/listener.go
index 4f80a89..c66928a 100644
--- a/remoting/etcdv3/listener.go
+++ b/remoting/etcdv3/listener.go
@@ -129,8 +129,6 @@
 	default:
 		return false
 	}
-
-	panic("unreachable")
 }
 
 // ListenServiceNodeEventWithPrefix listens on a set of key with spec prefix
diff --git a/remoting/exchange.go b/remoting/exchange.go
index 848d9cb..5fbd8ae 100644
--- a/remoting/exchange.go
+++ b/remoting/exchange.go
@@ -17,6 +17,7 @@
 package remoting
 
 import (
+	"sync"
 	"time"
 )
 
@@ -26,13 +27,19 @@
 
 import (
 	"github.com/apache/dubbo-go/common"
+	"github.com/apache/dubbo-go/common/logger"
 )
 
 var (
 	// generate request ID for global use
 	sequence atomic.Int64
+
+	// store requestID and response
+	pendingResponses = new(sync.Map)
 )
 
+type SequenceType int64
+
 func init() {
 	// init request ID
 	sequence.Store(0)
@@ -90,6 +97,23 @@
 	return response.Event && response.Result == nil
 }
 
+func (response *Response) Handle() {
+	pendingResponse := removePendingResponse(SequenceType(response.ID))
+	if pendingResponse == nil {
+		logger.Errorf("failed to get pending response context for response package %s", *response)
+		return
+	}
+
+	pendingResponse.response = response
+
+	if pendingResponse.Callback == nil {
+		pendingResponse.Err = pendingResponse.response.Error
+		close(pendingResponse.Done)
+	} else {
+		pendingResponse.Callback(pendingResponse.GetCallResponse())
+	}
+}
+
 type Options struct {
 	// connect timeout
 	ConnectTimeout time.Duration
@@ -142,3 +166,28 @@
 		Reply:     r.response,
 	}
 }
+
+// store response into map
+func AddPendingResponse(pr *PendingResponse) {
+	pendingResponses.Store(SequenceType(pr.seq), pr)
+}
+
+// get and remove response
+func removePendingResponse(seq SequenceType) *PendingResponse {
+	if pendingResponses == nil {
+		return nil
+	}
+	if presp, ok := pendingResponses.Load(seq); ok {
+		pendingResponses.Delete(seq)
+		return presp.(*PendingResponse)
+	}
+	return nil
+}
+
+// get response
+func GetPendingResponse(seq SequenceType) *PendingResponse {
+	if presp, ok := pendingResponses.Load(seq); ok {
+		return presp.(*PendingResponse)
+	}
+	return nil
+}
diff --git a/remoting/exchange_client.go b/remoting/exchange_client.go
index 75ae945..d653820 100644
--- a/remoting/exchange_client.go
+++ b/remoting/exchange_client.go
@@ -18,7 +18,6 @@
 
 import (
 	"errors"
-	"sync"
 	"time"
 )
 
@@ -28,25 +27,18 @@
 	"github.com/apache/dubbo-go/protocol"
 )
 
-var (
-	// store requestID and response
-	pendingResponses = new(sync.Map)
-)
-
-type SequenceType int64
-
 // It is interface of client for network communication.
 // If you use getty as network communication, you should define GettyClient that implements this interface.
 type Client interface {
 	SetExchangeClient(client *ExchangeClient)
-	// responseHandler is used to deal with msg
-	SetResponseHandler(responseHandler ResponseHandler)
 	// connect url
-	Connect(url common.URL) error
+	Connect(url *common.URL) error
 	// close
 	Close()
 	// send request to server.
 	Request(request *Request, timeout time.Duration, response *PendingResponse) error
+	// check if the client is still available
+	IsAvailable() bool
 }
 
 // This is abstraction level. it is like facade.
@@ -61,13 +53,8 @@
 	init bool
 }
 
-// handle the message from server
-type ResponseHandler interface {
-	Handler(response *Response)
-}
-
 // create ExchangeClient
-func NewExchangeClient(url common.URL, client Client, connectTimeout time.Duration, lazyInit bool) *ExchangeClient {
+func NewExchangeClient(url *common.URL, client Client, connectTimeout time.Duration, lazyInit bool) *ExchangeClient {
 	exchangeClient := &ExchangeClient{
 		ConnectTimeout: connectTimeout,
 		address:        url.Location,
@@ -80,11 +67,10 @@
 		}
 	}
 
-	client.SetResponseHandler(exchangeClient)
 	return exchangeClient
 }
 
-func (cl *ExchangeClient) doInit(url common.URL) error {
+func (cl *ExchangeClient) doInit(url *common.URL) error {
 	if cl.init {
 		return nil
 	}
@@ -102,7 +88,7 @@
 }
 
 // two way request
-func (client *ExchangeClient) Request(invocation *protocol.Invocation, url common.URL, timeout time.Duration,
+func (client *ExchangeClient) Request(invocation *protocol.Invocation, url *common.URL, timeout time.Duration,
 	result *protocol.RPCResult) error {
 	if er := client.doInit(url); er != nil {
 		return er
@@ -132,7 +118,7 @@
 }
 
 // async two way request
-func (client *ExchangeClient) AsyncRequest(invocation *protocol.Invocation, url common.URL, timeout time.Duration,
+func (client *ExchangeClient) AsyncRequest(invocation *protocol.Invocation, url *common.URL, timeout time.Duration,
 	callback common.AsyncCallback, result *protocol.RPCResult) error {
 	if er := client.doInit(url); er != nil {
 		return er
@@ -158,7 +144,7 @@
 }
 
 // oneway request
-func (client *ExchangeClient) Send(invocation *protocol.Invocation, url common.URL, timeout time.Duration) error {
+func (client *ExchangeClient) Send(invocation *protocol.Invocation, url *common.URL, timeout time.Duration) error {
 	if er := client.doInit(url); er != nil {
 		return er
 	}
@@ -184,46 +170,7 @@
 	client.init = false
 }
 
-// handle the response from server
-func (client *ExchangeClient) Handler(response *Response) {
-
-	pendingResponse := removePendingResponse(SequenceType(response.ID))
-	if pendingResponse == nil {
-		logger.Errorf("failed to get pending response context for response package %s", *response)
-		return
-	}
-
-	pendingResponse.response = response
-
-	if pendingResponse.Callback == nil {
-		pendingResponse.Err = pendingResponse.response.Error
-		pendingResponse.Done <- struct{}{}
-	} else {
-		pendingResponse.Callback(pendingResponse.GetCallResponse())
-	}
-}
-
-// store response into map
-func AddPendingResponse(pr *PendingResponse) {
-	pendingResponses.Store(SequenceType(pr.seq), pr)
-}
-
-// get and remove response
-func removePendingResponse(seq SequenceType) *PendingResponse {
-	if pendingResponses == nil {
-		return nil
-	}
-	if presp, ok := pendingResponses.Load(seq); ok {
-		pendingResponses.Delete(seq)
-		return presp.(*PendingResponse)
-	}
-	return nil
-}
-
-// get response
-func GetPendingResponse(seq SequenceType) *PendingResponse {
-	if presp, ok := pendingResponses.Load(seq); ok {
-		return presp.(*PendingResponse)
-	}
-	return nil
+// IsAvailable to check if the underlying network client is available yet.
+func (client *ExchangeClient) IsAvailable() bool {
+	return client.client.IsAvailable()
 }
diff --git a/remoting/exchange_server.go b/remoting/exchange_server.go
index a31e994..a8d7c73 100644
--- a/remoting/exchange_server.go
+++ b/remoting/exchange_server.go
@@ -32,11 +32,11 @@
 // This is abstraction level. it is like facade.
 type ExchangeServer struct {
 	Server Server
-	Url    common.URL
+	Url    *common.URL
 }
 
 // Create ExchangeServer
-func NewExchangeServer(url common.URL, server Server) *ExchangeServer {
+func NewExchangeServer(url *common.URL, server Server) *ExchangeServer {
 	exchangServer := &ExchangeServer{
 		Server: server,
 		Url:    url,
diff --git a/remoting/getty/config.go b/remoting/getty/config.go
index dcf59d0..b6aa082 100644
--- a/remoting/getty/config.go
+++ b/remoting/getty/config.go
@@ -54,6 +54,14 @@
 	ServerConfig struct {
 		SSLEnabled bool
 
+		// heartbeat
+		HeartbeatPeriod string `default:"60s" yaml:"heartbeat_period" json:"heartbeat_period,omitempty"`
+		heartbeatPeriod time.Duration
+
+		// heartbeat timeout
+		HeartbeatTimeout string `default:"5s" yaml:"heartbeat_timeout" json:"heartbeat_timeout,omitempty"`
+		heartbeatTimeout time.Duration
+
 		// session
 		SessionTimeout string `default:"60s" yaml:"session_timeout" json:"session_timeout,omitempty"`
 		sessionTimeout time.Duration
@@ -76,9 +84,13 @@
 		ConnectionNum int `default:"16" yaml:"connection_number" json:"connection_number,omitempty"`
 
 		// heartbeat
-		HeartbeatPeriod string `default:"15s" yaml:"heartbeat_period" json:"heartbeat_period,omitempty"`
+		HeartbeatPeriod string `default:"60s" yaml:"heartbeat_period" json:"heartbeat_period,omitempty"`
 		heartbeatPeriod time.Duration
 
+		// heartbeat timeout
+		HeartbeatTimeout string `default:"5s" yaml:"heartbeat_timeout" json:"heartbeat_timeout,omitempty"`
+		heartbeatTimeout time.Duration
+
 		// session
 		SessionTimeout string `default:"60s" yaml:"session_timeout" json:"session_timeout,omitempty"`
 		sessionTimeout time.Duration
@@ -188,6 +200,12 @@
 			c.HeartbeatPeriod, time.Duration(config.MaxWheelTimeSpan))
 	}
 
+	if len(c.HeartbeatTimeout) == 0 {
+		c.heartbeatTimeout = 60 * time.Second
+	} else if c.heartbeatTimeout, err = time.ParseDuration(c.HeartbeatTimeout); err != nil {
+		return perrors.WithMessagef(err, "time.ParseDuration(HeartbeatTimeout{%#v})", c.HeartbeatTimeout)
+	}
+
 	if c.sessionTimeout, err = time.ParseDuration(c.SessionTimeout); err != nil {
 		return perrors.WithMessagef(err, "time.ParseDuration(SessionTimeout{%#v})", c.SessionTimeout)
 	}
@@ -199,6 +217,23 @@
 func (c *ServerConfig) CheckValidity() error {
 	var err error
 
+	if len(c.HeartbeatPeriod) == 0 {
+		c.heartbeatPeriod = 60 * time.Second
+	} else if c.heartbeatPeriod, err = time.ParseDuration(c.HeartbeatPeriod); err != nil {
+		return perrors.WithMessagef(err, "time.ParseDuration(HeartbeatPeroid{%#v})", c.HeartbeatPeriod)
+	}
+
+	if c.heartbeatPeriod >= time.Duration(config.MaxWheelTimeSpan) {
+		return perrors.WithMessagef(err, "heartbeat_period %s should be less than %s",
+			c.HeartbeatPeriod, time.Duration(config.MaxWheelTimeSpan))
+	}
+
+	if len(c.HeartbeatTimeout) == 0 {
+		c.heartbeatTimeout = 60 * time.Second
+	} else if c.heartbeatTimeout, err = time.ParseDuration(c.HeartbeatTimeout); err != nil {
+		return perrors.WithMessagef(err, "time.ParseDuration(HeartbeatTimeout{%#v})", c.HeartbeatTimeout)
+	}
+
 	if c.sessionTimeout, err = time.ParseDuration(c.SessionTimeout); err != nil {
 		return perrors.WithMessagef(err, "time.ParseDuration(SessionTimeout{%#v})", c.SessionTimeout)
 	}
diff --git a/remoting/getty/dubbo_codec_for_test.go b/remoting/getty/dubbo_codec_for_test.go
index b91fc9f..fca5da8 100644
--- a/remoting/getty/dubbo_codec_for_test.go
+++ b/remoting/getty/dubbo_codec_for_test.go
@@ -55,15 +55,15 @@
 	if !ok {
 		return nil, perrors.Errorf("encode request failed for parameter type :%+v", request)
 	}
-	invocation := *invoc
+	tmpInvocation := invoc
 
 	svc := impl.Service{}
-	svc.Path = invocation.AttachmentsByKey(constant.PATH_KEY, "")
-	svc.Interface = invocation.AttachmentsByKey(constant.INTERFACE_KEY, "")
-	svc.Version = invocation.AttachmentsByKey(constant.VERSION_KEY, "")
-	svc.Group = invocation.AttachmentsByKey(constant.GROUP_KEY, "")
-	svc.Method = invocation.MethodName()
-	timeout, err := strconv.Atoi(invocation.AttachmentsByKey(constant.TIMEOUT_KEY, strconv.Itoa(constant.DEFAULT_REMOTING_TIMEOUT)))
+	svc.Path = tmpInvocation.AttachmentsByKey(constant.PATH_KEY, "")
+	svc.Interface = tmpInvocation.AttachmentsByKey(constant.INTERFACE_KEY, "")
+	svc.Version = tmpInvocation.AttachmentsByKey(constant.VERSION_KEY, "")
+	svc.Group = tmpInvocation.AttachmentsByKey(constant.GROUP_KEY, "")
+	svc.Method = tmpInvocation.MethodName()
+	timeout, err := strconv.Atoi(tmpInvocation.AttachmentsByKey(constant.TIMEOUT_KEY, strconv.Itoa(constant.DEFAULT_REMOTING_TIMEOUT)))
 	if err != nil {
 		// it will be wrapped in readwrite.Write .
 		return nil, perrors.WithStack(err)
@@ -71,7 +71,7 @@
 	svc.Timeout = time.Duration(timeout)
 
 	header := impl.DubboHeader{}
-	serialization := invocation.AttachmentsByKey(constant.SERIALIZATION_KEY, constant.HESSIAN2_SERIALIZATION)
+	serialization := tmpInvocation.AttachmentsByKey(constant.SERIALIZATION_KEY, constant.HESSIAN2_SERIALIZATION)
 	if serialization == constant.PROTOBUF_SERIALIZATION {
 		header.SerialID = constant.S_Proto
 	} else {
@@ -87,7 +87,7 @@
 	pkg := &impl.DubboPackage{
 		Header:  header,
 		Service: svc,
-		Body:    impl.NewRequestPayload(invocation.Arguments(), invocation.Attachments()),
+		Body:    impl.NewRequestPayload(tmpInvocation.Arguments(), tmpInvocation.Attachments()),
 		Err:     nil,
 		Codec:   impl.NewDubboCodec(nil),
 	}
diff --git a/remoting/getty/getty_client.go b/remoting/getty/getty_client.go
index 6af3971..e432ca5 100644
--- a/remoting/getty/getty_client.go
+++ b/remoting/getty/getty_client.go
@@ -118,13 +118,12 @@
 
 // Client : some configuration for network communication.
 type Client struct {
-	addr            string
-	opts            Options
-	conf            ClientConfig
-	pool            *gettyRPCClientPool
-	codec           remoting.Codec
-	responseHandler remoting.ResponseHandler
-	ExchangeClient  *remoting.ExchangeClient
+	addr           string
+	opts           Options
+	conf           ClientConfig
+	pool           *gettyRPCClientPool
+	codec          remoting.Codec
+	ExchangeClient *remoting.ExchangeClient
 }
 
 // create client
@@ -146,12 +145,9 @@
 func (c *Client) SetExchangeClient(client *remoting.ExchangeClient) {
 	c.ExchangeClient = client
 }
-func (c *Client) SetResponseHandler(responseHandler remoting.ResponseHandler) {
-	c.responseHandler = responseHandler
-}
 
 // init client and try to connection.
-func (c *Client) Connect(url common.URL) error {
+func (c *Client) Connect(url *common.URL) error {
 	initClient(url.Protocol)
 	c.conf = *clientConf
 	// new client
@@ -204,6 +200,14 @@
 	return perrors.WithStack(err)
 }
 
+// isAvailable returns true if the connection is available, or it can be re-established.
+func (c *Client) IsAvailable() bool {
+	client, _, err := c.selectSession(c.addr)
+	return err == nil &&
+		// defensive check
+		client != nil
+}
+
 func (c *Client) selectSession(addr string) (*gettyRPCClient, getty.Session, error) {
 	rpcClient, err := c.pool.getGettyRpcClient(addr)
 	if err != nil {
@@ -212,15 +216,6 @@
 	return rpcClient, rpcClient.selectSession(), nil
 }
 
-func (c *Client) heartbeat(session getty.Session) error {
-	req := remoting.NewRequest("2.0.2")
-	req.TwoWay = true
-	req.Event = true
-	resp := remoting.NewPendingResponse(req.ID)
-	remoting.AddPendingResponse(resp)
-	return c.transfer(session, req, 3*time.Second)
-}
-
 func (c *Client) transfer(session getty.Session, request *remoting.Request, timeout time.Duration) error {
 	err := session.WritePkg(request, timeout)
 	return perrors.WithStack(err)
diff --git a/remoting/getty/getty_client_test.go b/remoting/getty/getty_client_test.go
index 41ca310..d49be50 100644
--- a/remoting/getty/getty_client_test.go
+++ b/remoting/getty/getty_client_test.go
@@ -51,7 +51,7 @@
 	svr.Stop()
 }
 
-func testRequestOneWay(t *testing.T, svr *Server, url common.URL, client *Client) {
+func testRequestOneWay(t *testing.T, svr *Server, url *common.URL, client *Client) {
 
 	request := remoting.NewRequest("2.0.2")
 	up := &UserProvider{}
@@ -80,7 +80,7 @@
 	}
 }
 
-func getClient(url common.URL) *Client {
+func getClient(url *common.URL) *Client {
 	client := NewClient(Options{
 		ConnectTimeout: config.GetConsumerConfig().ConnectTimeout,
 	})
@@ -88,11 +88,10 @@
 	exchangeClient := remoting.NewExchangeClient(url, client, 5*time.Second, false)
 	client.SetExchangeClient(exchangeClient)
 	client.Connect(url)
-	client.SetResponseHandler(exchangeClient)
 	return client
 }
 
-func testClient_Call(t *testing.T, svr *Server, url common.URL, c *Client) {
+func testClient_Call(t *testing.T, svr *Server, url *common.URL, c *Client) {
 	c.pool = newGettyRPCClientConnPool(c, clientConf.PoolSize, time.Duration(int(time.Second)*clientConf.PoolTTL))
 
 	testGetBigPkg(t, c)
@@ -309,7 +308,7 @@
 	assert.Equal(t, User{Id: "1", Name: ""}, *user)
 }
 
-func testClient_AsyncCall(t *testing.T, svr *Server, url common.URL, client *Client) {
+func testClient_AsyncCall(t *testing.T, svr *Server, url *common.URL, client *Client) {
 	user := &User{}
 	lock := sync.Mutex{}
 	request := remoting.NewRequest("2.0.2")
@@ -337,7 +336,7 @@
 	time.Sleep(1 * time.Second)
 }
 
-func InitTest(t *testing.T) (*Server, common.URL) {
+func InitTest(t *testing.T) (*Server, *common.URL) {
 
 	hessian.RegisterPOJO(&User{})
 	remoting.RegistryCodec("dubbo", &DubboTestCodec{})
diff --git a/remoting/getty/getty_server.go b/remoting/getty/getty_server.go
index 7c8fa29..620a01d 100644
--- a/remoting/getty/getty_server.go
+++ b/remoting/getty/getty_server.go
@@ -117,7 +117,7 @@
 }
 
 // NewServer create a new Server
-func NewServer(url common.URL, handlers func(*invocation.RPCInvocation) protocol.RPCResult) *Server {
+func NewServer(url *common.URL, handlers func(*invocation.RPCInvocation) protocol.RPCResult) *Server {
 	//init
 	initServer(url.Protocol)
 
@@ -154,7 +154,7 @@
 		session.SetWQLen(conf.GettySessionParam.PkgWQSize)
 		session.SetReadTimeout(conf.GettySessionParam.tcpReadTimeout)
 		session.SetWriteTimeout(conf.GettySessionParam.tcpWriteTimeout)
-		session.SetCronPeriod((int)(conf.sessionTimeout.Nanoseconds() / 1e6))
+		session.SetCronPeriod((int)(conf.heartbeatPeriod.Nanoseconds() / 1e6))
 		session.SetWaitTime(conf.GettySessionParam.waitTimeout)
 		logger.Debugf("server accepts new session:%s\n", session.Stat())
 		session.SetTaskPool(srvGrpool)
@@ -195,7 +195,7 @@
 	session.SetWQLen(conf.GettySessionParam.PkgWQSize)
 	session.SetReadTimeout(conf.GettySessionParam.tcpReadTimeout)
 	session.SetWriteTimeout(conf.GettySessionParam.tcpWriteTimeout)
-	session.SetCronPeriod((int)(conf.sessionTimeout.Nanoseconds() / 1e6))
+	session.SetCronPeriod((int)(conf.heartbeatPeriod.Nanoseconds() / 1e6))
 	session.SetWaitTime(conf.GettySessionParam.waitTimeout)
 	logger.Debugf("server accepts new session: %s", session.Stat())
 	session.SetTaskPool(srvGrpool)
diff --git a/remoting/getty/listener.go b/remoting/getty/listener.go
index 196aa20..b2f7790 100644
--- a/remoting/getty/listener.go
+++ b/remoting/getty/listener.go
@@ -44,7 +44,8 @@
 )
 
 var (
-	errTooManySessions = perrors.New("too many sessions")
+	errTooManySessions      = perrors.New("too many sessions")
+	errHeartbeatReadTimeout = perrors.New("heartbeat read timeout")
 )
 
 type rpcSession struct {
@@ -66,7 +67,8 @@
 
 // nolint
 type RpcClientHandler struct {
-	conn *gettyRPCClient
+	conn         *gettyRPCClient
+	timeoutTimes int
 }
 
 // nolint
@@ -109,13 +111,13 @@
 			resp.Event = req.Event
 			resp.SerialID = req.SerialID
 			resp.Version = "2.0.2"
-			reply(session, resp, hessian.PackageHeartbeat)
+			reply(session, resp)
 			return
 		}
 		logger.Errorf("illegal request but not heartbeart. {%#v}", req)
 		return
 	}
-
+	h.timeoutTimes = 0
 	p := result.Result.(*remoting.Response)
 	// get heartbeart
 	if p.Event {
@@ -123,11 +125,7 @@
 		if p.Error != nil {
 			logger.Errorf("rpc heartbeat response{error: %#v}", p.Error)
 		}
-		h.conn.pool.rpcClient.responseHandler.Handler(p)
-		return
-	}
-	if result.IsRequest {
-		logger.Errorf("illegal package for it is response type. {%#v}", pkg)
+		p.Handle()
 		return
 	}
 
@@ -135,7 +133,7 @@
 
 	h.conn.updateSession(session)
 
-	h.conn.pool.rpcClient.responseHandler.Handler(p)
+	p.Handle()
 }
 
 // OnCron check the session health periodic. if the session's sessionTimeout has reached, just close the session
@@ -153,7 +151,22 @@
 		return
 	}
 
-	h.conn.pool.rpcClient.heartbeat(session)
+	heartbeatCallBack := func(err error) {
+		if err != nil {
+			logger.Warnf("failed to send heartbeat, error{%v}", err)
+			if h.timeoutTimes >= 3 {
+				h.conn.removeSession(session)
+				return
+			}
+			h.timeoutTimes++
+			return
+		}
+		h.timeoutTimes = 0
+	}
+
+	if err := heartbeat(session, h.conn.pool.rpcClient.conf.heartbeatTimeout, heartbeatCallBack); err != nil {
+		logger.Warnf("failed to send heartbeat, error{%v}", err)
+	}
 }
 
 // //////////////////////////////////////////
@@ -167,6 +180,7 @@
 	sessionMap     map[getty.Session]*rpcSession
 	rwlock         sync.RWMutex
 	server         *Server
+	timeoutTimes   int
 }
 
 // nolint
@@ -229,7 +243,16 @@
 		return
 	}
 	if !decodeResult.IsRequest {
-		logger.Errorf("illegal package for it is response type. {%#v}", pkg)
+		res := decodeResult.Result.(*remoting.Response)
+		if res.Event {
+			logger.Debugf("get rpc heartbeat response{%#v}", res)
+			if res.Error != nil {
+				logger.Errorf("rpc heartbeat response{error: %#v}", res.Error)
+			}
+			res.Handle()
+			return
+		}
+		logger.Errorf("illegal package but not heartbeart. {%#v}", pkg)
 		return
 	}
 	req := decodeResult.Result.(*remoting.Request)
@@ -243,7 +266,7 @@
 	// heartbeat
 	if req.Event {
 		logger.Debugf("get rpc heartbeat request{%#v}", resp)
-		reply(session, resp, hessian.PackageHeartbeat)
+		reply(session, resp)
 		return
 	}
 
@@ -264,7 +287,7 @@
 			if !req.TwoWay {
 				return
 			}
-			reply(session, resp, hessian.PackageResponse)
+			reply(session, resp)
 		}
 
 	}()
@@ -272,7 +295,6 @@
 	invoc, ok := req.Data.(*invocation.RPCInvocation)
 	if !ok {
 		panic("create invocation occur some exception for the type is not suitable one.")
-		return
 	}
 	attachments := invoc.Attachments()
 	attachments[constant.LOCAL_ADDR] = session.LocalAddr()
@@ -283,7 +305,7 @@
 		return
 	}
 	resp.Result = result
-	reply(session, resp, hessian.PackageResponse)
+	reply(session, resp)
 }
 
 // OnCron check the session health periodic. if the session's sessionTimeout has reached, just close the session
@@ -310,10 +332,52 @@
 		h.rwlock.Unlock()
 		session.Close()
 	}
+
+	heartbeatCallBack := func(err error) {
+		if err != nil {
+			logger.Warnf("failed to send heartbeat, error{%v}", err)
+			if h.timeoutTimes >= 3 {
+				h.rwlock.Lock()
+				delete(h.sessionMap, session)
+				h.rwlock.Unlock()
+				session.Close()
+				return
+			}
+			h.timeoutTimes++
+			return
+		}
+		h.timeoutTimes = 0
+	}
+
+	if err := heartbeat(session, h.server.conf.heartbeatTimeout, heartbeatCallBack); err != nil {
+		logger.Warnf("failed to send heartbeat, error{%v}", err)
+	}
 }
 
-func reply(session getty.Session, resp *remoting.Response, tp hessian.PackageType) {
+func reply(session getty.Session, resp *remoting.Response) {
 	if err := session.WritePkg(resp, WritePkg_Timeout); err != nil {
 		logger.Errorf("WritePkg error: %#v, %#v", perrors.WithStack(err), resp)
 	}
 }
+
+func heartbeat(session getty.Session, timeout time.Duration, callBack func(err error)) error {
+	req := remoting.NewRequest("2.0.2")
+	req.TwoWay = true
+	req.Event = true
+	resp := remoting.NewPendingResponse(req.ID)
+	remoting.AddPendingResponse(resp)
+	err := session.WritePkg(req, 3*time.Second)
+
+	go func() {
+		var err1 error
+		select {
+		case <-getty.GetTimeWheel().After(timeout):
+			err1 = errHeartbeatReadTimeout
+		case <-resp.Done:
+			err1 = resp.Err
+		}
+		callBack(err1)
+	}()
+
+	return perrors.WithStack(err)
+}
diff --git a/remoting/getty/pool.go b/remoting/getty/pool.go
index a072432..9689175 100644
--- a/remoting/getty/pool.go
+++ b/remoting/getty/pool.go
@@ -81,19 +81,26 @@
 		gettyClient: gettyClient,
 	}
 	go c.gettyClient.RunEventLoop(c.newSession)
+
 	idx := 1
-	times := int(pool.rpcClient.opts.ConnectTimeout / 1e6)
+	start := time.Now()
+	connectTimeout := pool.rpcClient.opts.ConnectTimeout
 	for {
 		idx++
 		if c.isAvailable() {
 			break
 		}
 
-		if idx > times {
+		if time.Now().Sub(start) > connectTimeout {
 			c.gettyClient.Close()
-			return nil, perrors.New(fmt.Sprintf("failed to create client connection to %s in %f seconds", addr, float32(times)/1000))
+			return nil, perrors.New(fmt.Sprintf("failed to create client connection to %s in %s", addr, connectTimeout))
 		}
-		time.Sleep(1e6)
+
+		interval := time.Millisecond * time.Duration(idx)
+		if interval > time.Duration(100e6) {
+			interval = 100e6 // 100 ms
+		}
+		time.Sleep(interval)
 	}
 	logger.Debug("client init ok")
 	c.updateActive(time.Now().Unix())
diff --git a/remoting/getty/readwriter.go b/remoting/getty/readwriter.go
index 66c33a6..072eb3e 100644
--- a/remoting/getty/readwriter.go
+++ b/remoting/getty/readwriter.go
@@ -68,18 +68,27 @@
 // Write send the data to server
 func (p *RpcClientPackageHandler) Write(ss getty.Session, pkg interface{}) ([]byte, error) {
 	req, ok := pkg.(*remoting.Request)
-	if !ok {
-		logger.Errorf("illegal pkg:%+v\n", pkg)
-		return nil, perrors.New("invalid rpc request")
+	if ok {
+		buf, err := (p.client.codec).EncodeRequest(req)
+		if err != nil {
+			logger.Warnf("binary.Write(req{%#v}) = err{%#v}", req, perrors.WithStack(err))
+			return nil, perrors.WithStack(err)
+		}
+		return buf.Bytes(), nil
 	}
 
-	buf, err := (p.client.codec).EncodeRequest(req)
-	if err != nil {
-		logger.Warnf("binary.Write(req{%#v}) = err{%#v}", req, perrors.WithStack(err))
-		return nil, perrors.WithStack(err)
+	res, ok := pkg.(*remoting.Response)
+	if ok {
+		buf, err := (p.client.codec).EncodeResponse(res)
+		if err != nil {
+			logger.Warnf("binary.Write(res{%#v}) = err{%#v}", req, perrors.WithStack(err))
+			return nil, perrors.WithStack(err)
+		}
+		return buf.Bytes(), nil
 	}
 
-	return buf.Bytes(), nil
+	logger.Errorf("illegal pkg:%+v\n", pkg)
+	return nil, perrors.New("invalid rpc request")
 }
 
 ////////////////////////////////////////////
@@ -120,16 +129,26 @@
 // Write send the data to client
 func (p *RpcServerPackageHandler) Write(ss getty.Session, pkg interface{}) ([]byte, error) {
 	res, ok := pkg.(*remoting.Response)
-	if !ok {
-		logger.Errorf("illegal pkg:%+v\n, it is %+v", pkg, reflect.TypeOf(pkg))
-		return nil, perrors.New("invalid rpc response")
+	if ok {
+		buf, err := (p.server.codec).EncodeResponse(res)
+		if err != nil {
+			logger.Warnf("binary.Write(res{%#v}) = err{%#v}", res, perrors.WithStack(err))
+			return nil, perrors.WithStack(err)
+		}
+		return buf.Bytes(), nil
 	}
 
-	buf, err := (p.server.codec).EncodeResponse(res)
-	if err != nil {
-		logger.Warnf("binary.Write(res{%#v}) = err{%#v}", res, perrors.WithStack(err))
-		return nil, perrors.WithStack(err)
+	req, ok := pkg.(*remoting.Request)
+	if ok {
+		buf, err := (p.server.codec).EncodeRequest(req)
+		if err != nil {
+			logger.Warnf("binary.Write(req{%#v}) = err{%#v}", res, perrors.WithStack(err))
+			return nil, perrors.WithStack(err)
+		}
+		return buf.Bytes(), nil
 	}
 
-	return buf.Bytes(), nil
+	logger.Errorf("illegal pkg:%+v\n, it is %+v", pkg, reflect.TypeOf(pkg))
+	return nil, perrors.New("invalid rpc response")
+
 }
diff --git a/remoting/kubernetes/client.go b/remoting/kubernetes/client.go
index 0a05489..fce9e80 100644
--- a/remoting/kubernetes/client.go
+++ b/remoting/kubernetes/client.go
@@ -47,7 +47,7 @@
 }
 
 // newClient returns Client instance for registry
-func newClient(url common.URL) (*Client, error) {
+func newClient(url *common.URL) (*Client, error) {
 
 	ctx, cancel := context.WithCancel(context.Background())
 
diff --git a/remoting/kubernetes/facade_test.go b/remoting/kubernetes/facade_test.go
index 65c5d71..00e2e11 100644
--- a/remoting/kubernetes/facade_test.go
+++ b/remoting/kubernetes/facade_test.go
@@ -43,8 +43,8 @@
 	r.client = client
 }
 
-func (r *mockFacade) GetUrl() common.URL {
-	return *r.URL
+func (r *mockFacade) GetUrl() *common.URL {
+	return r.URL
 }
 
 func (r *mockFacade) Destroy() {
@@ -68,7 +68,7 @@
 
 	mockClient := getTestClient(t)
 	m := &mockFacade{
-		URL:    &regUrl,
+		URL:    regUrl,
 		client: mockClient,
 	}
 
diff --git a/remoting/zookeeper/facade.go b/remoting/zookeeper/facade.go
index 2a03439..4dc0a54 100644
--- a/remoting/zookeeper/facade.go
+++ b/remoting/zookeeper/facade.go
@@ -37,7 +37,7 @@
 	WaitGroup() *sync.WaitGroup // for wait group control, zk client listener & zk client container
 	Done() chan struct{}        // for zk client control
 	RestartCallBack() bool
-	GetUrl() common.URL
+	GetUrl() *common.URL
 }
 
 // HandleClientRestart keeps the connection between client and server
diff --git a/remoting/zookeeper/facade_test.go b/remoting/zookeeper/facade_test.go
index 1cd8f06..3d5798c 100644
--- a/remoting/zookeeper/facade_test.go
+++ b/remoting/zookeeper/facade_test.go
@@ -68,8 +68,8 @@
 	return r.done
 }
 
-func (r *mockFacade) GetUrl() common.URL {
-	return *r.URL
+func (r *mockFacade) GetUrl() *common.URL {
+	return r.URL
 }
 
 func (r *mockFacade) Destroy() {
@@ -90,7 +90,7 @@
 	assert.NoError(t, err)
 	defer ts.Stop()
 	url, _ := common.NewURL("mock://127.0.0.1")
-	mock := newMockFacade(z, &url)
+	mock := newMockFacade(z, url)
 	go HandleClientRestart(mock)
 	states := []zk.State{zk.StateConnecting, zk.StateConnected, zk.StateHasSession}
 	verifyEventStateOrder(t, event, states, "event channel")
diff --git a/remoting/zookeeper/listener.go b/remoting/zookeeper/listener.go
index b6c6d78..e5ddcad 100644
--- a/remoting/zookeeper/listener.go
+++ b/remoting/zookeeper/listener.go
@@ -301,6 +301,9 @@
 			go func(zkPath string, listener remoting.DataListener) {
 				if l.listenServiceNodeEvent(zkPath) {
 					listener.DataChange(remoting.Event{Path: zkPath, Action: remoting.EventTypeDel})
+					l.pathMapLock.Lock()
+					defer l.pathMapLock.Unlock()
+					delete(l.pathMap, zkPath)
 				}
 				logger.Warnf("listenSelf(zk path{%s}) goroutine exit now", zkPath)
 			}(dubboPath, listener)