diff --git a/README.md b/README.md
index 24f9f894adb54e4eb7ff13e3ea128c477d0dc6cf..694f0091533f644b58438c6487dc53348add6e60 100644
--- a/README.md
+++ b/README.md
@@ -15,6 +15,10 @@ Apache License, Version 2.0
 
 [v1.0.0 - May 29, 2019 compatible with dubbo v2.6.5](https://github.com/apache/dubbo-go/releases/tag/v1.0.0)
 
+[v1.1.0 - Sep 7, 2019 the first release after transferred to apache](https://github.com/apache/dubbo-go/releases/tag/v1.1.0)
+
+[v1.2.0 - Nov 15, 2019](https://github.com/apache/dubbo-go/releases/tag/v1.2.0)
+
 ## Project Architecture ##
 
 Both extension module and layered project architecture is according to Apache Dubbo (including protocol layer, registry layer, cluster layer, config layer and so on), the advantage of this arch is as following: you can implement these layered interfaces in your own way, override the default implementation of dubbo-go by calling 'extension.SetXXX' of extension, complete your special needs without modifying the source code. At the same time, you are welcome to contribute implementation of useful extension to the community.
@@ -27,43 +31,94 @@ If you wanna know more about dubbo-go, please visit this reference [Project Arch
 
 Finished List:
 
-- Role: Consumer, Provider
-- Transport: HTTP, TCP
-- Codec: JsonRPC v2, Hessian v2
-- Registry: ZooKeeper/[etcd v3](https://github.com/apache/dubbo-go/pull/148)/[nacos](https://github.com/apache/dubbo-go/pull/151)/[consul](https://github.com/apache/dubbo-go/pull/121)
-- Configure Center: Zookeeper
-- Cluster Strategy: Failover/[Failfast](https://github.com/apache/dubbo-go/pull/140)/[Failsafe/Failback](https://github.com/apache/dubbo-go/pull/136)/[Available](https://github.com/apache/dubbo-go/pull/155)/[Broadcast](https://github.com/apache/dubbo-go/pull/158)/[Forking](https://github.com/apache/dubbo-go/pull/161)
-- Load Balance: Random/[RoundRobin](https://github.com/apache/dubbo-go/pull/66)/[LeastActive](https://github.com/apache/dubbo-go/pull/65)
-- Filter: Echo Health Check/[Circuit break and service downgrade](https://github.com/apache/dubbo-go/pull/133)/[TokenFilter](https://github.com/apache/dubbo-go/pull/202)/[AccessLogFilter](https://github.com/apache/dubbo-go/pull/214)
-- Other feature: [generic invoke](https://github.com/apache/dubbo-go/pull/122)/start check/connecting certain provider/multi-protocols/multi-registries/multi-versions/service group
+- Role
+    * Consumer
+    * Provider
+
+- Transport
+    * HTTP
+    * TCP
+
+- Codec
+    * JsonRPC V2
+    * Hessian V2
+    
+- Registry
+    * ZooKeeper
+    * [etcd v3](https://github.com/apache/dubbo-go/pull/148)
+    * [nacos](https://github.com/apache/dubbo-go/pull/151)
+    * [consul](https://github.com/apache/dubbo-go/pull/121)
+    
+- Dynamic Configure Center & Service Management Configurator
+    * Zookeeper
+    * [apollo](https://github.com/apache/dubbo-go/pull/250)
+
+- Cluster Strategy
+    * Failover
+    * [Failfast](https://github.com/apache/dubbo-go/pull/140)
+    * [Failsafe/Failback](https://github.com/apache/dubbo-go/pull/136)
+    * [Available](https://github.com/apache/dubbo-go/pull/155)
+    * [Broadcast](https://github.com/apache/dubbo-go/pull/158)
+    * [Forking](https://github.com/apache/dubbo-go/pull/161)
+    
+- Load Balance
+    * Random
+    * [RoundRobin](https://github.com/apache/dubbo-go/pull/66)
+    * [LeastActive](https://github.com/apache/dubbo-go/pull/65)
+    
+- Filter
+    * Echo Health Check
+    * [Circuit break and service downgrade](https://github.com/apache/dubbo-go/pull/133)
+    * [TokenFilter](https://github.com/apache/dubbo-go/pull/202)
+    * [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)
+    
+- Invoke
+    * [generic invoke](https://github.com/apache/dubbo-go/pull/122)
+    
+- Others:
+    * start check
+    * connecting certain provider
+    * multi-protocols
+    * multi-registries
+    * multi-versions
+    * service group
 
 Working List:
 
 - Load Balance: ConsistentHash
-- Filter: CountFilter/ExecuteLimitFilter/TpsLimitFilter
 - Registry: k8s
-- Configure Center: apollo
-- Dynamic Configuration Center & Metadata Center (dubbo v2.7.x)
-- Metrics: Promethus(dubbo v2.7.x)
-
-Todo List:
-
-- Registry: kubernetes
-- Routing: istio
-- tracing (dubbo ecosystem)
+- Metadata Center (dubbo v2.7.x)
+- Metrics: Opentracing/Promethus(dubbo v2.7.x)
 
 You can know more about dubbo-go by its [roadmap](https://github.com/apache/dubbo-go/wiki/Roadmap).
 
+![feature](https://raw.githubusercontent.com/wiki/apache/dubbo-go/arch.png)
+
 ## Document
 
-TODO
+https://dubbogo.github.io/dubbo-go-website(**Improving**)
 
 ## Quick Start
 
-[dubbogo-samples](https://github.com/dubbogo/dubbogo-samples) shows how to use dubbo-go. Please read the [dubbogo-samples/README.md](https://github.com/dubbogo/dubbogo-samples/blob/master/README.md) carefully to learn how to dispose the configuration and compile the program.
+[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.
 
 ## Running unit tests
 
+### Prepare
+
+Mac/Linux
+```bash
+sh ./before_ut.sh
+```
+
+Windows
+```bash
+before_ut.bat
+```
+
+# Run
 ```bash
 go test ./...
 
diff --git a/README_CN.md b/README_CN.md
index 28243a9e9e4dc2e03e006451b00360bf3ef19e23..99b26c5357ddb0482faf5a95b5935b0d9603c40b 100644
--- a/README_CN.md
+++ b/README_CN.md
@@ -14,6 +14,10 @@ Apache License, Version 2.0
 
 [v1.0.0 - 2019骞�5鏈�29鏃� 鍏煎dubbo v2.6.5 鐗堟湰](https://github.com/apache/dubbo-go/releases/tag/v1.0.0)
 
+[v1.1.0 - 2019骞�9鏈�7鏃� 鎹愮尞缁橝pache涔嬪悗鐨勭涓€娆elease](https://github.com/apache/dubbo-go/releases/tag/v1.1.0)
+
+[v1.2.0 - 2019骞�11鏈�15鏃(https://github.com/apache/dubbo-go/releases/tag/v1.2.0)
+
 ## 宸ョ▼鏋舵瀯 ##
 
 鍩轰簬dubbo鐨別xtension妯″潡鍜屽垎灞傜殑浠g爜璁捐(鍖呮嫭 protocol layer, registry layer, cluster layer, config 绛夌瓑)銆傛垜浠殑鐩爣鏄細浣犲彲浠ュ杩欎簺鍒嗗眰鎺ュ彛杩涜鏂扮殑瀹炵幇锛屽苟閫氳繃璋冪敤 extension 妯″潡鐨勨€� extension.SetXXX 鈥濇柟娉曟潵瑕嗙洊 dubbo-go [鍚� go-for-apache-dubbo ]鐨勯粯璁ゅ疄鐜帮紝浠ュ畬鎴愯嚜宸辩殑鐗规畩闇€姹傝€屾棤闇€淇敼婧愪唬鐮併€傚悓鏃讹紝娆㈣繋浣犱负绀惧尯璐$尞鏈夌敤鐨勬嫇灞曞疄鐜般€�
@@ -26,48 +30,98 @@ Apache License, Version 2.0
 
 瀹炵幇鍒楄〃:
 
-- 瑙掕壊绔�: Consumer, Provider
-- 浼犺緭鍗忚: HTTP, TCP
-- 搴忓垪鍖栧崗璁�: JsonRPC v2, Hessian v2
-- 娉ㄥ唽涓績: ZooKeeper/[etcd v3](https://github.com/apache/dubbo-go/pull/148)/[nacos](https://github.com/apache/dubbo-go/pull/151)/[consul](https://github.com/apache/dubbo-go/pull/121)
-- 閰嶇疆涓績: Zookeeper
-- 闆嗙兢绛栫暐: Failover/[Failfast](https://github.com/apache/dubbo-go/pull/140)/[Failsafe/Failback](https://github.com/apache/dubbo-go/pull/136)/[Available](https://github.com/apache/dubbo-go/pull/155)/[Broadcast](https://github.com/apache/dubbo-go/pull/158)/[Forking](https://github.com/apache/dubbo-go/pull/161)
-- 璐熻浇鍧囪 绛栫暐: Random/[RoundRobin](https://github.com/apache/dubbo-go/pull/66)/[LeastActive](https://github.com/apache/dubbo-go/pull/65)
-- 杩囨护鍣�: Echo Health Check/[鏈嶅姟鐔旀柇&闄嶇骇](https://github.com/apache/dubbo-go/pull/133)/[TokenFilter](https://github.com/apache/dubbo-go/pull/202)/[AccessLogFilter](https://github.com/apache/dubbo-go/pull/214)
-- 鍏朵粬鍔熻兘鏀寔: [娉涘寲璋冪敤](https://github.com/apache/dubbo-go/pull/122)/鍚姩鏃舵鏌�/鏈嶅姟鐩磋繛/澶氭湇鍔″崗璁�/澶氭敞鍐屼腑蹇�/澶氭湇鍔$増鏈�/鏈嶅姟鍒嗙粍
+- 瑙掕壊绔�
+    * Consumer
+    * Provider
+    
+- 浼犺緭鍗忚
+    * HTTP
+    * TCP
+
+- 搴忓垪鍖栧崗璁�
+    * JsonRPC V2
+    * Hessian V2
+    
+- 娉ㄥ唽涓績
+    * ZooKeeper
+    * [etcd v3](https://github.com/apache/dubbo-go/pull/148)
+    * [nacos](https://github.com/apache/dubbo-go/pull/151)
+    * [consul](https://github.com/apache/dubbo-go/pull/121)
+    
+- 鍔ㄦ€侀厤缃腑蹇冧笌鏈嶅姟娌荤悊閰嶇疆鍣�
+    * Zookeeper
+    * [apollo](https://github.com/apache/dubbo-go/pull/250)
+    
+- 闆嗙兢绛栫暐
+    * Failover
+    * [Failfast](https://github.com/apache/dubbo-go/pull/140)
+    * [Failsafe/Failback](https://github.com/apache/dubbo-go/pull/136)
+    * [Available](https://github.com/apache/dubbo-go/pull/155)
+    * [Broadcast](https://github.com/apache/dubbo-go/pull/158)
+    * [Forking](https://github.com/apache/dubbo-go/pull/161)
+   
+- 璐熻浇鍧囪 绛栫暐
+    * Random
+    * [RoundRobin](https://github.com/apache/dubbo-go/pull/66)
+    * [LeastActive](https://github.com/apache/dubbo-go/pull/65)
+    
+- 杩囨护鍣�
+    * Echo Health Check
+    * [鏈嶅姟鐔旀柇&闄嶇骇](https://github.com/apache/dubbo-go/pull/133)
+    * [TokenFilter](https://github.com/apache/dubbo-go/pull/202)
+    * [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)
+    
+- 璋冪敤
+    * [娉涘寲璋冪敤](https://github.com/apache/dubbo-go/pull/122)
+    
+- 鍏朵粬鍔熻兘鏀寔:
+    * 鍚姩鏃舵鏌�
+    * 鏈嶅姟鐩磋繛
+    * 澶氭湇鍔″崗璁�
+    * 澶氭敞鍐屼腑蹇�
+    * 澶氭湇鍔$増鏈�
+    * 鏈嶅姟鍒嗙粍
 
 寮€鍙戜腑鍒楄〃:
 
-- 闆嗙兢绛栫暐: Forking
 - 璐熻浇鍧囪 绛栫暐: ConsistentHash
-- 杩囨护鍣�: CountFilter/ExecuteLimitFilter/TpsLimitFilter
 - 娉ㄥ唽涓績: k8s
-- 閰嶇疆涓績: apollo
-- 鍔ㄦ€侀厤缃腑蹇� & 鍏冩暟鎹腑蹇� (dubbo v2.7.x)
-- Metrics: Promethus(dubbo v2.7.x)
-
-浠诲姟鍒楄〃:
+- 鍏冩暟鎹腑蹇� (dubbo v2.7.x)
+- Metrics: Opentracing/Promethus(dubbo v2.7.x)
 
-- 娉ㄥ唽涓績: kubernetes
-- Routing: istio
-- tracing (dubbo ecosystem)
+浣犲彲浠ラ€氳繃璁块棶 [roadmap](https://github.com/apache/dubbo-go/wiki/Roadmap) 鐭ラ亾鏇村鍏充簬 dubbo-go 鐨勪俊鎭€�
 
-浣犲彲浠ラ€氳繃璁块棶 [roadmap](https://github.com/apache/dubbo-go/wiki/Roadmap) 鐭ラ亾鏇村鍏充簬 dubbo-go 鐨勪俊鎭�
+![feature](https://raw.githubusercontent.com/wiki/apache/dubbo-go/arch.png)
 
 ## 鏂囨。
 
-TODO
+https://dubbogo.github.io/dubbo-go-website(**瀹屽杽涓�**)
 
 ## 蹇€熷紑濮� ##
 
-[dubbogo-samples](https://github.com/dubbogo/dubbogo-samples)杩欎釜椤圭洰鐨勪簨渚嬪睍绀轰簡濡備綍浣跨敤 dubbo-go 銆傝浠旂粏闃呰 [dubbogo-samples/README.md](https://github.com/dubbogo/dubbogo-samples/blob/master/README.md) 瀛︿範濡備綍澶勭悊閰嶇疆骞剁紪璇戠▼搴忋€�
+[dubbo-samples/golang](https://github.com/dubbogo/dubbo-samples)杩欎釜椤圭洰鐨勪簨渚嬪睍绀轰簡濡備綍浣跨敤 dubbo-go 銆傝浠旂粏闃呰 [dubbo-samples/golang/README.md](https://github.com/dubbogo/dubbo-samples/blob/master/golang/README.md) 瀛︿範濡備綍澶勭悊閰嶇疆骞剁紪璇戠▼搴忋€�
 
 ## 杩愯鍗曟祴
 
+### 鍑嗗
+
+Mac/Linux
+```bash
+sh ./before_ut.sh
+```
+
+Windows
+```bash
+before_ut.bat
+```
+
+# 鎵ц
 ```bash
 go test ./...
 
-# 瑕嗙洊鐜�
+# coverage
 go test ./... -coverprofile=coverage.txt -covermode=atomic
 ```
 
diff --git a/before_ut.bat b/before_ut.bat
new file mode 100644
index 0000000000000000000000000000000000000000..5296d0f8769b7b9f521f82e68bf3b10f4b5d16b4
--- /dev/null
+++ b/before_ut.bat
@@ -0,0 +1,21 @@
+::
+::  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 zkJar=zookeeper-3.4.9-fatjar.jar
+md remoting\zookeeper\zookeeper-4unittest\contrib\fatjar config_center\zookeeper\zookeeper-4unittest\contrib\fatjar registry\zookeeper\zookeeper-4unittest\contrib\fatjar
+curl -L https://github.com/dubbogo/resources/raw/master/zookeeper-4unitest/contrib/fatjar/%zkJar% -o remoting/zookeeper/zookeeper-4unittest/contrib/fatjar/%zkJar%
+xcopy /f "remoting/zookeeper/zookeeper-4unittest/contrib/fatjar/%zkJar%" "config_center/zookeeper/zookeeper-4unittest/contrib/fatjar/"
+xcopy /f "remoting/zookeeper/zookeeper-4unittest/contrib/fatjar/%zkJar%" "registry/zookeeper/zookeeper-4unittest/contrib/fatjar/"
\ No newline at end of file
diff --git a/before_ut.sh b/before_ut.sh
index 7acee76ce5991ac1d06bff6a6325f083904f10b9..323173bcc64c3cbe9916747e10dd3ea8538457ea 100644
--- a/before_ut.sh
+++ b/before_ut.sh
@@ -1,3 +1,20 @@
+#
+#  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.
+
+
 mkdir -p remoting/zookeeper/zookeeper-4unittest/contrib/fatjar config_center/zookeeper/zookeeper-4unittest/contrib/fatjar registry/zookeeper/zookeeper-4unittest/contrib/fatjar
 wget -P "remoting/zookeeper/zookeeper-4unittest/contrib/fatjar" https://github.com/dubbogo/resources/raw/master/zookeeper-4unitest/contrib/fatjar/zookeeper-3.4.9-fatjar.jar
 cp remoting/zookeeper/zookeeper-4unittest/contrib/fatjar/zookeeper-3.4.9-fatjar.jar config_center/zookeeper/zookeeper-4unittest/contrib/fatjar/
diff --git a/cluster/cluster_impl/base_cluster_invoker.go b/cluster/cluster_impl/base_cluster_invoker.go
index d93e9a6a98a8cbf7ee2cb97abd0248353e0c3154..644f67c5244350897bbc3e291e66e2421758fce5 100644
--- a/cluster/cluster_impl/base_cluster_invoker.go
+++ b/cluster/cluster_impl/base_cluster_invoker.go
@@ -35,6 +35,7 @@ type baseClusterInvoker struct {
 	directory      cluster.Directory
 	availablecheck bool
 	destroyed      *atomic.Bool
+	stickyInvoker  protocol.Invoker
 }
 
 func newBaseClusterInvoker(directory cluster.Directory) baseClusterInvoker {
@@ -56,7 +57,9 @@ func (invoker *baseClusterInvoker) Destroy() {
 }
 
 func (invoker *baseClusterInvoker) IsAvailable() bool {
-	//TODO:sticky connection
+	if invoker.stickyInvoker != nil {
+		return invoker.stickyInvoker.IsAvailable()
+	}
 	return invoker.directory.IsAvailable()
 }
 
@@ -83,15 +86,42 @@ func (invoker *baseClusterInvoker) checkWhetherDestroyed() error {
 }
 
 func (invoker *baseClusterInvoker) doSelect(lb cluster.LoadBalance, invocation protocol.Invocation, invokers []protocol.Invoker, invoked []protocol.Invoker) protocol.Invoker {
-	//todo:sticky connect
+
+	var selectedInvoker protocol.Invoker
+	url := invokers[0].GetUrl()
+	sticky := url.GetParamBool(constant.STICKY_KEY, false)
+	//Get the service method sticky config if have
+	sticky = url.GetMethodParamBool(invocation.MethodName(), constant.STICKY_KEY, sticky)
+
+	if invoker.stickyInvoker != nil && !isInvoked(invoker.stickyInvoker, invokers) {
+		invoker.stickyInvoker = nil
+	}
+
+	if sticky && invoker.stickyInvoker != nil && (invoked == nil || !isInvoked(invoker.stickyInvoker, invoked)) {
+		if invoker.availablecheck && invoker.stickyInvoker.IsAvailable() {
+			return invoker.stickyInvoker
+		}
+	}
+
+	selectedInvoker = invoker.doSelectInvoker(lb, invocation, invokers, invoked)
+
+	if sticky {
+		invoker.stickyInvoker = selectedInvoker
+	}
+	return selectedInvoker
+
+}
+
+func (invoker *baseClusterInvoker) doSelectInvoker(lb cluster.LoadBalance, invocation protocol.Invocation, invokers []protocol.Invoker, invoked []protocol.Invoker) protocol.Invoker {
 	if len(invokers) == 1 {
 		return invokers[0]
 	}
+
 	selectedInvoker := lb.Select(invokers, invocation)
 
 	//judge to if the selectedInvoker is invoked
 
-	if !selectedInvoker.IsAvailable() || !invoker.availablecheck || isInvoked(selectedInvoker, invoked) {
+	if (!selectedInvoker.IsAvailable() && invoker.availablecheck) || isInvoked(selectedInvoker, invoked) {
 		// do reselect
 		var reslectInvokers []protocol.Invoker
 
@@ -106,13 +136,12 @@ func (invoker *baseClusterInvoker) doSelect(lb cluster.LoadBalance, invocation p
 		}
 
 		if len(reslectInvokers) > 0 {
-			return lb.Select(reslectInvokers, invocation)
+			selectedInvoker = lb.Select(reslectInvokers, invocation)
 		} else {
 			return nil
 		}
 	}
 	return selectedInvoker
-
 }
 
 func isInvoked(selectedInvoker protocol.Invoker, invoked []protocol.Invoker) bool {
diff --git a/cluster/cluster_impl/base_cluster_invoker_test.go b/cluster/cluster_impl/base_cluster_invoker_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..d06d3cc23e75cf2227fa22894475f141ffe09a96
--- /dev/null
+++ b/cluster/cluster_impl/base_cluster_invoker_test.go
@@ -0,0 +1,66 @@
+/*
+ * 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 cluster_impl
+
+import (
+	"context"
+	"fmt"
+	"testing"
+)
+
+import (
+	"github.com/stretchr/testify/assert"
+)
+
+import (
+	"github.com/apache/dubbo-go/cluster/loadbalance"
+	"github.com/apache/dubbo-go/common"
+	"github.com/apache/dubbo-go/protocol"
+	"github.com/apache/dubbo-go/protocol/invocation"
+)
+
+func Test_StickyNormal(t *testing.T) {
+	invokers := []protocol.Invoker{}
+	for i := 0; i < 10; i++ {
+		url, _ := common.NewURL(context.TODO(), fmt.Sprintf("dubbo://192.168.1.%v:20000/com.ikurento.user.UserProvider", i))
+		url.SetParam("sticky", "true")
+		invokers = append(invokers, NewMockInvoker(url, 1))
+	}
+	base := &baseClusterInvoker{}
+	base.availablecheck = true
+	invoked := []protocol.Invoker{}
+	result := base.doSelect(loadbalance.NewRandomLoadBalance(), invocation.NewRPCInvocation("getUser", nil, nil), invokers, invoked)
+	result1 := base.doSelect(loadbalance.NewRandomLoadBalance(), invocation.NewRPCInvocation("getUser", nil, nil), invokers, invoked)
+	assert.Equal(t, result, result1)
+}
+func Test_StickyNormalWhenError(t *testing.T) {
+	invokers := []protocol.Invoker{}
+	for i := 0; i < 10; i++ {
+		url, _ := common.NewURL(context.TODO(), fmt.Sprintf("dubbo://192.168.1.%v:20000/com.ikurento.user.UserProvider", i))
+		url.SetParam("sticky", "true")
+		invokers = append(invokers, NewMockInvoker(url, 1))
+	}
+	base := &baseClusterInvoker{}
+	base.availablecheck = true
+
+	invoked := []protocol.Invoker{}
+	result := base.doSelect(loadbalance.NewRandomLoadBalance(), invocation.NewRPCInvocation("getUser", nil, nil), invokers, invoked)
+	invoked = append(invoked, result)
+	result1 := base.doSelect(loadbalance.NewRandomLoadBalance(), invocation.NewRPCInvocation("getUser", nil, nil), invokers, invoked)
+	assert.NotEqual(t, result, result1)
+}
diff --git a/cluster/cluster_impl/failback_cluster_test.go b/cluster/cluster_impl/failback_cluster_test.go
index c94347a1251a69a10c0a4d50007ef569bd6dd996..1d2266cabebf591b09188fb723f02126a3f1e0ec 100644
--- a/cluster/cluster_impl/failback_cluster_test.go
+++ b/cluster/cluster_impl/failback_cluster_test.go
@@ -67,7 +67,7 @@ func Test_FailbackSuceess(t *testing.T) {
 	invoker := mock.NewMockInvoker(ctrl)
 	clusterInvoker := registerFailback(t, invoker).(*failbackClusterInvoker)
 
-	invoker.EXPECT().GetUrl().Return(failbackUrl).Times(1)
+	invoker.EXPECT().GetUrl().Return(failbackUrl).AnyTimes()
 
 	mockResult := &protocol.RPCResult{Rest: rest{tried: 0, success: true}}
 	invoker.EXPECT().Invoke(gomock.Any()).Return(mockResult)
diff --git a/cluster/cluster_impl/failfast_cluster_test.go b/cluster/cluster_impl/failfast_cluster_test.go
index 7a19e80ccda15aa13a1c4fcf250e05a6effa7f0b..1a4342e6c2b74fd6b1359646eeb463bb6dc17d0a 100644
--- a/cluster/cluster_impl/failfast_cluster_test.go
+++ b/cluster/cluster_impl/failfast_cluster_test.go
@@ -64,7 +64,7 @@ func Test_FailfastInvokeSuccess(t *testing.T) {
 	invoker := mock.NewMockInvoker(ctrl)
 	clusterInvoker := registerFailfast(t, invoker)
 
-	invoker.EXPECT().GetUrl().Return(failfastUrl)
+	invoker.EXPECT().GetUrl().Return(failfastUrl).AnyTimes()
 
 	mockResult := &protocol.RPCResult{Rest: rest{tried: 0, success: true}}
 
@@ -84,7 +84,7 @@ func Test_FailfastInvokeFail(t *testing.T) {
 	invoker := mock.NewMockInvoker(ctrl)
 	clusterInvoker := registerFailfast(t, invoker)
 
-	invoker.EXPECT().GetUrl().Return(failfastUrl)
+	invoker.EXPECT().GetUrl().Return(failfastUrl).AnyTimes()
 
 	mockResult := &protocol.RPCResult{Err: perrors.New("error")}
 
diff --git a/cluster/cluster_impl/failsafe_cluster_test.go b/cluster/cluster_impl/failsafe_cluster_test.go
index 9ee9d9fee31b0cb24d877ab3dc0e24fb552f5f11..7888b97c3a02bd4679f8ec5267637b8d2a7c12e4 100644
--- a/cluster/cluster_impl/failsafe_cluster_test.go
+++ b/cluster/cluster_impl/failsafe_cluster_test.go
@@ -64,7 +64,7 @@ func Test_FailSafeInvokeSuccess(t *testing.T) {
 	invoker := mock.NewMockInvoker(ctrl)
 	clusterInvoker := register_failsafe(t, invoker)
 
-	invoker.EXPECT().GetUrl().Return(failsafeUrl)
+	invoker.EXPECT().GetUrl().Return(failsafeUrl).AnyTimes()
 
 	mockResult := &protocol.RPCResult{Rest: rest{tried: 0, success: true}}
 
@@ -83,7 +83,7 @@ func Test_FailSafeInvokeFail(t *testing.T) {
 	invoker := mock.NewMockInvoker(ctrl)
 	clusterInvoker := register_failsafe(t, invoker)
 
-	invoker.EXPECT().GetUrl().Return(failsafeUrl)
+	invoker.EXPECT().GetUrl().Return(failsafeUrl).AnyTimes()
 
 	mockResult := &protocol.RPCResult{Err: perrors.New("error")}
 
diff --git a/cluster/loadbalance/consistent_hash.go b/cluster/loadbalance/consistent_hash.go
new file mode 100644
index 0000000000000000000000000000000000000000..365e6a66242e4a4618ab922f80b4b4247076484d
--- /dev/null
+++ b/cluster/loadbalance/consistent_hash.go
@@ -0,0 +1,165 @@
+/*
+ * 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 loadbalance
+
+import (
+	"crypto/md5"
+	"encoding/json"
+	"fmt"
+	"hash/crc32"
+	"regexp"
+	"sort"
+	"strconv"
+	"strings"
+)
+
+import (
+	"github.com/apache/dubbo-go/cluster"
+	"github.com/apache/dubbo-go/common/constant"
+	"github.com/apache/dubbo-go/common/extension"
+	"github.com/apache/dubbo-go/protocol"
+)
+
+const (
+	ConsistentHash = "consistenthash"
+	HashNodes      = "hash.nodes"
+	HashArguments  = "hash.arguments"
+)
+
+var (
+	selectors = make(map[string]*ConsistentHashSelector)
+	re        = regexp.MustCompile(constant.COMMA_SPLIT_PATTERN)
+)
+
+func init() {
+	extension.SetLoadbalance(ConsistentHash, NewConsistentHashLoadBalance)
+}
+
+type ConsistentHashLoadBalance struct {
+}
+
+func NewConsistentHashLoadBalance() cluster.LoadBalance {
+	return &ConsistentHashLoadBalance{}
+}
+
+func (lb *ConsistentHashLoadBalance) Select(invokers []protocol.Invoker, invocation protocol.Invocation) protocol.Invoker {
+	methodName := invocation.MethodName()
+	key := invokers[0].GetUrl().ServiceKey() + "." + methodName
+
+	// hash the invokers
+	bs := make([]byte, 0)
+	for _, invoker := range invokers {
+		b, err := json.Marshal(invoker)
+		if err != nil {
+			return nil
+		}
+		bs = append(bs, b...)
+	}
+	hashCode := crc32.ChecksumIEEE(bs)
+	selector, ok := selectors[key]
+	if !ok || selector.hashCode != hashCode {
+		selectors[key] = newConsistentHashSelector(invokers, methodName, hashCode)
+		selector = selectors[key]
+	}
+	return selector.Select(invocation)
+}
+
+type Uint32Slice []uint32
+
+func (s Uint32Slice) Len() int {
+	return len(s)
+}
+
+func (s Uint32Slice) Less(i, j int) bool {
+	return s[i] < s[j]
+}
+
+func (s Uint32Slice) Swap(i, j int) {
+	s[i], s[j] = s[j], s[i]
+}
+
+type ConsistentHashSelector struct {
+	hashCode        uint32
+	replicaNum      int
+	virtualInvokers map[uint32]protocol.Invoker
+	keys            Uint32Slice
+	argumentIndex   []int
+}
+
+func newConsistentHashSelector(invokers []protocol.Invoker, methodName string,
+	hashCode uint32) *ConsistentHashSelector {
+
+	selector := &ConsistentHashSelector{}
+	selector.virtualInvokers = make(map[uint32]protocol.Invoker)
+	selector.hashCode = hashCode
+	url := invokers[0].GetUrl()
+	selector.replicaNum = int(url.GetMethodParamInt(methodName, HashNodes, 160))
+	indices := re.Split(url.GetMethodParam(methodName, HashArguments, "0"), -1)
+	for _, index := range indices {
+		i, err := strconv.Atoi(index)
+		if err != nil {
+			return nil
+		}
+		selector.argumentIndex = append(selector.argumentIndex, i)
+	}
+	for _, invoker := range invokers {
+		u := invoker.GetUrl()
+		address := u.Ip + ":" + u.Port
+		for i := 0; i < selector.replicaNum/4; i++ {
+			digest := md5.Sum([]byte(address + strconv.Itoa(i)))
+			for j := 0; j < 4; j++ {
+				key := selector.hash(digest, j)
+				selector.keys = append(selector.keys, key)
+				selector.virtualInvokers[key] = invoker
+			}
+		}
+	}
+	sort.Sort(selector.keys)
+	return selector
+}
+
+func (c *ConsistentHashSelector) Select(invocation protocol.Invocation) protocol.Invoker {
+	key := c.toKey(invocation.Arguments())
+	digest := md5.Sum([]byte(key))
+	return c.selectForKey(c.hash(digest, 0))
+}
+
+func (c *ConsistentHashSelector) toKey(args []interface{}) string {
+	var sb strings.Builder
+	for i := range c.argumentIndex {
+		if i >= 0 && i < len(args) {
+			fmt.Fprint(&sb, args[i].(string))
+		}
+	}
+	return sb.String()
+}
+
+func (c *ConsistentHashSelector) selectForKey(hash uint32) protocol.Invoker {
+	idx := sort.Search(len(c.keys), func(i int) bool {
+		return c.keys[i] >= hash
+	})
+	if idx == len(c.keys) {
+		idx = 0
+	}
+	return c.virtualInvokers[c.keys[idx]]
+}
+
+func (c *ConsistentHashSelector) hash(digest [16]byte, i int) uint32 {
+	return uint32((digest[3+i*4]&0xFF)<<24) | uint32((digest[2+i*4]&0xFF)<<16) |
+		uint32((digest[1+i*4]&0xFF)<<8) | uint32(digest[i*4]&0xFF)&0xFFFFFFF
+}
diff --git a/cluster/loadbalance/consistent_hash_test.go b/cluster/loadbalance/consistent_hash_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..174d5715dd1258d329f40251e76ca47d98791ea9
--- /dev/null
+++ b/cluster/loadbalance/consistent_hash_test.go
@@ -0,0 +1,110 @@
+/*
+ * 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 loadbalance
+
+import (
+	"context"
+	"testing"
+)
+
+import (
+	"github.com/stretchr/testify/suite"
+)
+
+import (
+	"github.com/apache/dubbo-go/cluster"
+	"github.com/apache/dubbo-go/common"
+	"github.com/apache/dubbo-go/protocol"
+	"github.com/apache/dubbo-go/protocol/invocation"
+)
+
+func TestConsistentHashSelectorSuite(t *testing.T) {
+	suite.Run(t, new(consistentHashSelectorSuite))
+}
+
+type consistentHashSelectorSuite struct {
+	suite.Suite
+	selector *ConsistentHashSelector
+}
+
+func (s *consistentHashSelectorSuite) SetupTest() {
+	var invokers []protocol.Invoker
+	url, _ := common.NewURL(context.TODO(),
+		"dubbo://192.168.1.0:20000/org.apache.demo.HelloService?methods.echo.hash.arguments=0,1")
+	invokers = append(invokers, protocol.NewBaseInvoker(url))
+	s.selector = newConsistentHashSelector(invokers, "echo", 999944)
+}
+
+func (s *consistentHashSelectorSuite) TestToKey() {
+	result := s.selector.toKey([]interface{}{"username", "age"})
+	s.Equal(result, "usernameage")
+}
+
+func (s *consistentHashSelectorSuite) TestSelectForKey() {
+	url1, _ := common.NewURL(context.TODO(), "dubbo://192.168.1.0:8080")
+	url2, _ := common.NewURL(context.TODO(), "dubbo://192.168.1.0:8081")
+	s.selector.virtualInvokers = make(map[uint32]protocol.Invoker)
+	s.selector.virtualInvokers[99874] = protocol.NewBaseInvoker(url1)
+	s.selector.virtualInvokers[9999945] = protocol.NewBaseInvoker(url2)
+	s.selector.keys = []uint32{99874, 9999945}
+	result := s.selector.selectForKey(9999944)
+	s.Equal(result.GetUrl().String(), "dubbo://192.168.1.0:8081?")
+}
+
+func TestConsistentHashLoadBalanceSuite(t *testing.T) {
+	suite.Run(t, new(consistentHashLoadBalanceSuite))
+}
+
+type consistentHashLoadBalanceSuite struct {
+	suite.Suite
+	url1     common.URL
+	url2     common.URL
+	url3     common.URL
+	invokers []protocol.Invoker
+	invoker1 protocol.Invoker
+	invoker2 protocol.Invoker
+	invoker3 protocol.Invoker
+	lb       cluster.LoadBalance
+}
+
+func (s *consistentHashLoadBalanceSuite) SetupTest() {
+	var err error
+	s.url1, err = common.NewURL(context.TODO(), "dubbo://192.168.1.0:8080/org.apache.demo.HelloService?methods.echo.hash.arguments=0,1")
+	s.NoError(err)
+	s.url2, err = common.NewURL(context.TODO(), "dubbo://192.168.1.0:8081/org.apache.demo.HelloService?methods.echo.hash.arguments=0,1")
+	s.NoError(err)
+	s.url3, err = common.NewURL(context.TODO(), "dubbo://192.168.1.0:8082/org.apache.demo.HelloService?methods.echo.hash.arguments=0,1")
+	s.NoError(err)
+
+	s.invoker1 = protocol.NewBaseInvoker(s.url1)
+	s.invoker2 = protocol.NewBaseInvoker(s.url2)
+	s.invoker3 = protocol.NewBaseInvoker(s.url3)
+
+	s.invokers = append(s.invokers, s.invoker1, s.invoker2, s.invoker3)
+	s.lb = NewConsistentHashLoadBalance()
+}
+
+func (s *consistentHashLoadBalanceSuite) TestSelect() {
+	args := []interface{}{"name", "password", "age"}
+	invoker := s.lb.Select(s.invokers, invocation.NewRPCInvocation("echo", args, nil))
+	s.Equal(invoker.GetUrl().Location, "192.168.1.0:8080")
+
+	args = []interface{}{"ok", "abc"}
+	invoker = s.lb.Select(s.invokers, invocation.NewRPCInvocation("echo", args, nil))
+	s.Equal(invoker.GetUrl().Location, "192.168.1.0:8082")
+}
diff --git a/cluster/router/condition_router.go b/cluster/router/condition_router.go
index a196ceb5771422f06a820986a02499f9fe3523dc..efae65ccb34eb8a78e281cfaf7b1fcec79b3d163 100644
--- a/cluster/router/condition_router.go
+++ b/cluster/router/condition_router.go
@@ -156,10 +156,13 @@ func parseRule(rule string) (map[string]MatchPair, error) {
 	if len(rule) == 0 {
 		return condition, nil
 	}
-	var pair MatchPair
+
+	var (
+		pair       MatchPair
+		startIndex int
+	)
 	values := gxset.NewSet()
 	reg := regexp.MustCompile(`([&!=,]*)\s*([^&!=,\s]+)`)
-	var startIndex = 0
 	if indexTuple := reg.FindIndex([]byte(rule)); len(indexTuple) > 0 {
 		startIndex = indexTuple[0]
 	}
@@ -227,7 +230,7 @@ func MatchCondition(pairs map[string]MatchPair, url *common.URL, param *common.U
 	if sample == nil {
 		return true, perrors.Errorf("url is not allowed be nil")
 	}
-	result := false
+	var result bool
 	for key, matchPair := range pairs {
 		var sampleValue string
 
diff --git a/common/constant/default.go b/common/constant/default.go
index 4363e3efd55f5960b1ee55b5bef23e6b10c2c1c2..6e0f8488783ebe66939436ca14670395e2719be7 100644
--- a/common/constant/default.go
+++ b/common/constant/default.go
@@ -46,8 +46,8 @@ const (
 const (
 	DEFAULT_KEY               = "default"
 	PREFIX_DEFAULT_KEY        = "default."
-	DEFAULT_SERVICE_FILTERS   = "echo,token,accesslog"
-	DEFAULT_REFERENCE_FILTERS = ""
+	DEFAULT_SERVICE_FILTERS   = "echo,token,accesslog,tps,execute,pshutdown"
+	DEFAULT_REFERENCE_FILTERS = "cshutdown"
 	GENERIC_REFERENCE_FILTERS = "generic"
 	GENERIC                   = "$invoke"
 	ECHO                      = "$echo"
@@ -67,3 +67,7 @@ const (
 	APP_DYNAMIC_CONFIGURATORS_CATEGORY = "appdynamicconfigurators"
 	PROVIDER_CATEGORY                  = "providers"
 )
+
+const (
+	COMMA_SPLIT_PATTERN = "\\s*[,]+\\s*"
+)
diff --git a/common/constant/key.go b/common/constant/key.go
index 3006f44732626bfcfd843466f91efd5a88a56f09..7538a2995a89b0951c29f532b9ce9e475198f54e 100644
--- a/common/constant/key.go
+++ b/common/constant/key.go
@@ -48,19 +48,32 @@ const (
 )
 
 const (
-	TIMESTAMP_KEY        = "timestamp"
-	REMOTE_TIMESTAMP_KEY = "remote.timestamp"
-	CLUSTER_KEY          = "cluster"
-	LOADBALANCE_KEY      = "loadbalance"
-	WEIGHT_KEY           = "weight"
-	WARMUP_KEY           = "warmup"
-	RETRIES_KEY          = "retries"
-	BEAN_NAME            = "bean.name"
-	FAIL_BACK_TASKS_KEY  = "failbacktasks"
-	FORKS_KEY            = "forks"
-	DEFAULT_FORKS        = 2
-	DEFAULT_TIMEOUT      = 1000
-	ACCESS_LOG_KEY       = "accesslog"
+	TIMESTAMP_KEY                          = "timestamp"
+	REMOTE_TIMESTAMP_KEY                   = "remote.timestamp"
+	CLUSTER_KEY                            = "cluster"
+	LOADBALANCE_KEY                        = "loadbalance"
+	WEIGHT_KEY                             = "weight"
+	WARMUP_KEY                             = "warmup"
+	RETRIES_KEY                            = "retries"
+	STICKY_KEY                             = "sticky"
+	BEAN_NAME                              = "bean.name"
+	FAIL_BACK_TASKS_KEY                    = "failbacktasks"
+	FORKS_KEY                              = "forks"
+	DEFAULT_FORKS                          = 2
+	DEFAULT_TIMEOUT                        = 1000
+	ACCESS_LOG_KEY                         = "accesslog"
+	TPS_LIMITER_KEY                        = "tps.limiter"
+	TPS_REJECTED_EXECUTION_HANDLER_KEY     = "tps.limit.rejected.handler"
+	TPS_LIMIT_RATE_KEY                     = "tps.limit.rate"
+	DEFAULT_TPS_LIMIT_RATE                 = "-1"
+	TPS_LIMIT_INTERVAL_KEY                 = "tps.limit.interval"
+	DEFAULT_TPS_LIMIT_INTERVAL             = "60000"
+	TPS_LIMIT_STRATEGY_KEY                 = "tps.limit.strategy"
+	EXECUTE_LIMIT_KEY                      = "execute.limit"
+	DEFAULT_EXECUTE_LIMIT                  = "-1"
+	EXECUTE_REJECTED_EXECUTION_HANDLER_KEY = "execute.limit.rejected.handler"
+	PROVIDER_SHUTDOWN_FILTER               = "pshutdown"
+	CONSUMER_SHUTDOWN_FILTER               = "cshutdown"
 )
 
 const (
@@ -90,6 +103,10 @@ const (
 
 const (
 	CONFIG_NAMESPACE_KEY  = "config.namespace"
+	CONFIG_GROUP_KEY      = "config.group"
+	CONFIG_APP_ID_KEY     = "config.appId"
+	CONFIG_CLUSTER_KEY    = "config.cluster"
+	CONFIG_CHECK_KEY      = "config.check"
 	CONFIG_TIMEOUT_KET    = "config.timeout"
 	CONFIG_VERSION_KEY    = "configVersion"
 	COMPATIBLE_CONFIG_KEY = "compatible_config"
@@ -102,6 +119,7 @@ const (
 	ProtocolConfigPrefix       = "dubbo.protocols."
 	ProviderConfigPrefix       = "dubbo.provider."
 	ConsumerConfigPrefix       = "dubbo.consumer."
+	ShutdownConfigPrefix       = "dubbo.shutdown."
 )
 
 const (
diff --git a/common/extension/filter.go b/common/extension/filter.go
index d6c7f6f694cc9888bd63c1d123bc57ee86f15e1f..93f7f8cf7ccc4108fe1120b685fad36a2f9f83df 100644
--- a/common/extension/filter.go
+++ b/common/extension/filter.go
@@ -19,10 +19,12 @@ package extension
 
 import (
 	"github.com/apache/dubbo-go/filter"
+	"github.com/apache/dubbo-go/filter/common"
 )
 
 var (
-	filters = make(map[string]func() filter.Filter)
+	filters                  = make(map[string]func() filter.Filter)
+	rejectedExecutionHandler = make(map[string]func() common.RejectedExecutionHandler)
 )
 
 func SetFilter(name string, v func() filter.Filter) {
@@ -31,7 +33,20 @@ func SetFilter(name string, v func() filter.Filter) {
 
 func GetFilter(name string) filter.Filter {
 	if filters[name] == nil {
-		panic("filter for " + name + " is not existing, make sure you have import the package.")
+		panic("filter for " + name + " is not existing, make sure you have imported the package.")
 	}
 	return filters[name]()
 }
+
+func SetRejectedExecutionHandler(name string, creator func() common.RejectedExecutionHandler) {
+	rejectedExecutionHandler[name] = creator
+}
+
+func GetRejectedExecutionHandler(name string) common.RejectedExecutionHandler {
+	creator, ok := rejectedExecutionHandler[name]
+	if !ok {
+		panic("RejectedExecutionHandler for " + name + " is not existing, make sure you have import the package " +
+			"and you have register it by invoking extension.SetRejectedExecutionHandler.")
+	}
+	return creator()
+}
diff --git a/common/extension/graceful_shutdown.go b/common/extension/graceful_shutdown.go
new file mode 100644
index 0000000000000000000000000000000000000000..c8807fcc28c18c1a6fddb4e97708e9b0d5cda243
--- /dev/null
+++ b/common/extension/graceful_shutdown.go
@@ -0,0 +1,53 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package extension
+
+import (
+	"container/list"
+)
+
+var (
+	customShutdownCallbacks = list.New()
+)
+
+/**
+ * you should not make any assumption about the order.
+ * For example, if you have more than one callbacks, and you wish the order is:
+ * callback1()
+ * callback2()
+ * ...
+ * callbackN()
+ * Then you should put then together:
+ * func callback() {
+ *     callback1()
+ *     callback2()
+ *     ...
+ *     callbackN()
+ * }
+ * I think the order of custom callbacks should be decided by the users.
+ * Even though I can design a mechanism to support the ordered custom callbacks,
+ * the benefit of that mechanism is low.
+ * And it may introduce much complication for another users.
+ */
+func AddCustomShutdownCallback(callback func()) {
+	customShutdownCallbacks.PushBack(callback)
+}
+
+func GetAllCustomShutdownCallbacks() *list.List {
+	return customShutdownCallbacks
+}
diff --git a/common/extension/tps_limit.go b/common/extension/tps_limit.go
new file mode 100644
index 0000000000000000000000000000000000000000..151c33ad5e64ffa4059489e2cbcfae6f2e823328
--- /dev/null
+++ b/common/extension/tps_limit.go
@@ -0,0 +1,53 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package extension
+
+import (
+	"github.com/apache/dubbo-go/filter/impl/tps"
+)
+
+var (
+	tpsLimitStrategy = make(map[string]tps.TpsLimitStrategyCreator)
+	tpsLimiter       = make(map[string]func() tps.TpsLimiter)
+)
+
+func SetTpsLimiter(name string, creator func() tps.TpsLimiter) {
+	tpsLimiter[name] = creator
+}
+
+func GetTpsLimiter(name string) tps.TpsLimiter {
+	creator, ok := tpsLimiter[name]
+	if !ok {
+		panic("TpsLimiter for " + name + " is not existing, make sure you have import the package " +
+			"and you have register it by invoking extension.SetTpsLimiter.")
+	}
+	return creator()
+}
+
+func SetTpsLimitStrategy(name string, creator tps.TpsLimitStrategyCreator) {
+	tpsLimitStrategy[name] = creator
+}
+
+func GetTpsLimitStrategyCreator(name string) tps.TpsLimitStrategyCreator {
+	creator, ok := tpsLimitStrategy[name]
+	if !ok {
+		panic("TpsLimitStrategy for " + name + " is not existing, make sure you have import the package " +
+			"and you have register it by invoking extension.SetTpsLimitStrategy.")
+	}
+	return creator
+}
diff --git a/common/logger/logger.go b/common/logger/logger.go
index f41e95744f954da69b0e3695c97ba3389c69160a..db91d2e7c1e5f7a647eefbfa5aec14073c2b14a7 100644
--- a/common/logger/logger.go
+++ b/common/logger/logger.go
@@ -40,6 +40,11 @@ var (
 	logger Logger
 )
 
+type DubboLogger struct {
+	Logger
+	dynamicLevel zap.AtomicLevel
+}
+
 type Logger interface {
 	Info(args ...interface{})
 	Warn(args ...interface{})
@@ -109,7 +114,8 @@ func InitLogger(conf *zap.Config) {
 		zapLoggerConfig = *conf
 	}
 	zapLogger, _ := zapLoggerConfig.Build(zap.AddCallerSkip(1))
-	logger = zapLogger.Sugar()
+	//logger = zapLogger.Sugar()
+	logger = &DubboLogger{Logger: zapLogger.Sugar(), dynamicLevel: zapLoggerConfig.Level}
 
 	// set getty log
 	getty.SetLogger(logger)
@@ -123,3 +129,22 @@ func SetLogger(log Logger) {
 func GetLogger() Logger {
 	return logger
 }
+
+func SetLoggerLevel(level string) bool {
+	if l, ok := logger.(OpsLogger); ok {
+		l.SetLoggerLevel(level)
+		return true
+	}
+	return false
+}
+
+type OpsLogger interface {
+	Logger
+	SetLoggerLevel(level string)
+}
+
+func (dl *DubboLogger) SetLoggerLevel(level string) {
+	l := new(zapcore.Level)
+	l.Set(level)
+	dl.dynamicLevel.SetLevel(*l)
+}
diff --git a/common/logger/logger_test.go b/common/logger/logger_test.go
index e29b7cbc8e9bbd67df41df5ac687a079621c3360..6081f71aecccbfab5fd574335effe7788b6ce799 100644
--- a/common/logger/logger_test.go
+++ b/common/logger/logger_test.go
@@ -65,3 +65,19 @@ func TestInitLog(t *testing.T) {
 	Warnf("%s", "warn")
 	Errorf("%s", "error")
 }
+
+func TestSetLevel(t *testing.T) {
+	err := InitLog("./log.yml")
+	assert.NoError(t, err)
+	Debug("debug")
+	Info("info")
+
+	assert.True(t, SetLoggerLevel("info"))
+	Debug("debug")
+	Info("info")
+
+	SetLogger(GetLogger().(*DubboLogger).Logger)
+	assert.False(t, SetLoggerLevel("debug"))
+	Debug("debug")
+	Info("info")
+}
diff --git a/common/proxy/proxy.go b/common/proxy/proxy.go
index 1c079f6bca52bf8f6e8c5ebb168da82ab8ccb5f2..d13646dba86eea04adb3726d33ee9d20457276b6 100644
--- a/common/proxy/proxy.go
+++ b/common/proxy/proxy.go
@@ -181,3 +181,7 @@ func (p *Proxy) Implement(v common.RPCService) {
 func (p *Proxy) Get() common.RPCService {
 	return p.rpc
 }
+
+func (p *Proxy) GetCallback() interface{} {
+	return p.callBack
+}
diff --git a/common/proxy/proxy_factory.go b/common/proxy/proxy_factory.go
index 2567e0ee09cf7fa5aef7fde46872eb88205d8e45..116cfe06693b6923ca10e0df6964317dabd91d0e 100644
--- a/common/proxy/proxy_factory.go
+++ b/common/proxy/proxy_factory.go
@@ -24,6 +24,7 @@ import (
 
 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
 }
 
diff --git a/common/proxy/proxy_factory/default.go b/common/proxy/proxy_factory/default.go
index bafba60b400ec59d99e2d68ecf4d067c906ba6fb..06824fdc1e27cde5e1905be3277451dd4395049c 100644
--- a/common/proxy/proxy_factory/default.go
+++ b/common/proxy/proxy_factory/default.go
@@ -55,11 +55,16 @@ func NewDefaultProxyFactory(options ...proxy.Option) proxy.ProxyFactory {
 	return &DefaultProxyFactory{}
 }
 func (factory *DefaultProxyFactory) GetProxy(invoker protocol.Invoker, url *common.URL) *proxy.Proxy {
+	return factory.GetAsyncProxy(invoker, nil, url)
+}
+
+func (factory *DefaultProxyFactory) GetAsyncProxy(invoker protocol.Invoker, callBack interface{}, url *common.URL) *proxy.Proxy {
 	//create proxy
 	attachments := map[string]string{}
 	attachments[constant.ASYNC_KEY] = url.GetParam(constant.ASYNC_KEY, "false")
-	return proxy.NewProxy(invoker, nil, attachments)
+	return proxy.NewProxy(invoker, callBack, attachments)
 }
+
 func (factory *DefaultProxyFactory) GetInvoker(url common.URL) protocol.Invoker {
 	return &ProxyInvoker{
 		BaseInvoker: *protocol.NewBaseInvoker(url),
diff --git a/common/proxy/proxy_factory/default_test.go b/common/proxy/proxy_factory/default_test.go
index b6a6b675baf992b2d64ffd19291ee2dc009bd1e3..7159b4b00eb2fcddb0f20f701f56b3179e57c4a0 100644
--- a/common/proxy/proxy_factory/default_test.go
+++ b/common/proxy/proxy_factory/default_test.go
@@ -18,6 +18,7 @@
 package proxy_factory
 
 import (
+	"fmt"
 	"testing"
 )
 
@@ -37,6 +38,21 @@ func Test_GetProxy(t *testing.T) {
 	assert.NotNil(t, proxy)
 }
 
+type TestAsync struct {
+}
+
+func (u *TestAsync) CallBack(res common.CallbackResponse) {
+	fmt.Println("CallBack res:", res)
+}
+
+func Test_GetAsyncProxy(t *testing.T) {
+	proxyFactory := NewDefaultProxyFactory()
+	url := common.NewURLWithOptions()
+	async := &TestAsync{}
+	proxy := proxyFactory.GetAsyncProxy(protocol.NewBaseInvoker(*url), async.CallBack, url)
+	assert.NotNil(t, proxy)
+}
+
 func Test_GetInvoker(t *testing.T) {
 	proxyFactory := NewDefaultProxyFactory()
 	url := common.NewURLWithOptions()
diff --git a/common/rpc_service.go b/common/rpc_service.go
index 4741a6fa3c0daef97f044f639a5e64a38fe4a187..4c9f083dd0850c3f110491ef820c7b677c8009aa 100644
--- a/common/rpc_service.go
+++ b/common/rpc_service.go
@@ -39,6 +39,18 @@ type RPCService interface {
 	Reference() string // rpc service id or reference id
 }
 
+//AsyncCallbackService callback interface for async
+type AsyncCallbackService interface {
+	CallBack(response CallbackResponse) // callback
+}
+
+//CallbackResponse for different protocol
+type CallbackResponse interface {
+}
+
+//AsyncCallback async callback method
+type AsyncCallback func(response CallbackResponse)
+
 // for lowercase func
 // func MethodMapper() map[string][string] {
 //     return map[string][string]{}
diff --git a/common/url.go b/common/url.go
index 6e7a843c8f4d2d3b24caf50983baf041e2dd036d..c010298bf58d65b6c2fcfc7859e03b0131bf7f54 100644
--- a/common/url.go
+++ b/common/url.go
@@ -447,6 +447,11 @@ func (c URL) GetMethodParam(method string, key string, d string) string {
 	return r
 }
 
+func (c URL) GetMethodParamBool(method string, key string, d bool) bool {
+	r := c.GetParamBool("methods."+method+"."+key, d)
+	return r
+}
+
 func (c *URL) RemoveParams(set *gxset.HashSet) {
 	c.paramsLock.Lock()
 	defer c.paramsLock.Unlock()
diff --git a/common/url_test.go b/common/url_test.go
index 41fd374a4d8a4ad3e15de1080fe46d426620909f..4d60d7f13f5d139e964b0837380f1054871c5d15 100644
--- a/common/url_test.go
+++ b/common/url_test.go
@@ -217,6 +217,18 @@ func TestURL_GetMethodParam(t *testing.T) {
 	assert.Equal(t, "1s", v)
 }
 
+func TestURL_GetMethodParamBool(t *testing.T) {
+	params := url.Values{}
+	params.Set("methods.GetValue.async", "true")
+	u := URL{baseUrl: baseUrl{params: params}}
+	v := u.GetMethodParamBool("GetValue", "async", false)
+	assert.Equal(t, true, v)
+
+	u = URL{}
+	v = u.GetMethodParamBool("GetValue2", "async", false)
+	assert.Equal(t, false, v)
+}
+
 func TestMergeUrl(t *testing.T) {
 	referenceUrlParams := url.Values{}
 	referenceUrlParams.Set(constant.CLUSTER_KEY, "random")
diff --git a/config/base_config.go b/config/base_config.go
index 264eeda3cc20da1b097a24dc35cf4f9b2291eeeb..64418f0a6d4c09270d48e6e9e6366a02783508d3 100644
--- a/config/base_config.go
+++ b/config/base_config.go
@@ -47,7 +47,7 @@ type BaseConfig struct {
 }
 
 func (c *BaseConfig) startConfigCenter(ctx context.Context) error {
-	url, err := common.NewURL(ctx, c.ConfigCenterConfig.Address, common.WithProtocol(c.ConfigCenterConfig.Protocol))
+	url, err := common.NewURL(ctx, c.ConfigCenterConfig.Address, common.WithProtocol(c.ConfigCenterConfig.Protocol), common.WithParams(c.ConfigCenterConfig.GetUrlMap()))
 	if err != nil {
 		return err
 	}
@@ -68,7 +68,7 @@ func (c *BaseConfig) prepareEnvironment() error {
 		logger.Errorf("Get dynamic configuration error , error message is %v", err)
 		return perrors.WithStack(err)
 	}
-	content, err := dynamicConfig.GetConfig(c.ConfigCenterConfig.ConfigFile, config_center.WithGroup(c.ConfigCenterConfig.Group))
+	content, err := dynamicConfig.GetProperties(c.ConfigCenterConfig.ConfigFile, config_center.WithGroup(c.ConfigCenterConfig.Group))
 	if err != nil {
 		logger.Errorf("Get config content in dynamic configuration error , error message is %v", err)
 		return perrors.WithStack(err)
@@ -88,7 +88,7 @@ func (c *BaseConfig) prepareEnvironment() error {
 		if len(configFile) == 0 {
 			configFile = c.ConfigCenterConfig.ConfigFile
 		}
-		appContent, err = dynamicConfig.GetConfig(configFile, config_center.WithGroup(appGroup))
+		appContent, err = dynamicConfig.GetProperties(configFile, config_center.WithGroup(appGroup))
 	}
 	//global config file
 	mapContent, err := dynamicConfig.Parser().Parse(content)
diff --git a/config/base_config_test.go b/config/base_config_test.go
index 6dc3749e55f7efbfb1177079f613360cd0d4cc33..ab2769578072387e4686593f3c2c10fb8e49731d 100644
--- a/config/base_config_test.go
+++ b/config/base_config_test.go
@@ -29,6 +29,7 @@ import (
 	"github.com/apache/dubbo-go/common/config"
 	"github.com/apache/dubbo-go/common/extension"
 	"github.com/apache/dubbo-go/config_center"
+	_ "github.com/apache/dubbo-go/config_center/apollo"
 )
 
 func Test_refresh(t *testing.T) {
@@ -39,6 +40,7 @@ func Test_refresh(t *testing.T) {
 	mockMap["dubbo.com.MockService.MockService.GetUser.retries"] = "10"
 	mockMap["dubbo.consumer.check"] = "false"
 	mockMap["dubbo.application.name"] = "dubbo"
+	mockMap["dubbo.shutdown.timeout"] = "12s"
 
 	config.GetEnvInstance().UpdateExternalConfigMap(mockMap)
 
@@ -113,6 +115,13 @@ func Test_refresh(t *testing.T) {
 				},
 			},
 		},
+		ShutdownConfig: &ShutdownConfig{
+			Timeout:              "12s",
+			StepTimeout:          "2s",
+			RejectRequestHandler: "mock",
+			RejectRequest:        false,
+			RequestsFinished:     false,
+		},
 	}
 
 	c.SetFatherConfig(father)
diff --git a/config/config_center_config.go b/config/config_center_config.go
index ed43558956a181e669a1a8936182b65a2fb2766c..013d23946a042906021d3b1d37b38f326f67f50a 100644
--- a/config/config_center_config.go
+++ b/config/config_center_config.go
@@ -19,6 +19,7 @@ package config
 
 import (
 	"context"
+	"net/url"
 	"time"
 )
 
@@ -26,6 +27,10 @@ import (
 	"github.com/creasty/defaults"
 )
 
+import (
+	"github.com/apache/dubbo-go/common/constant"
+)
+
 type ConfigCenterConfig struct {
 	context       context.Context
 	Protocol      string `required:"true"  yaml:"protocol"  json:"protocol,omitempty"`
@@ -35,7 +40,9 @@ type ConfigCenterConfig struct {
 	Username      string `yaml:"username" json:"username,omitempty"`
 	Password      string `yaml:"password" json:"password,omitempty"`
 	ConfigFile    string `default:"dubbo.properties" yaml:"config_file"  json:"config_file,omitempty"`
+	Namespace     string `default:"dubbo.properties" yaml:"namespace"  json:"namespace,omitempty"`
 	AppConfigFile string `default:"dubbo.properties" yaml:"app_config_file"  json:"app_config_file,omitempty"`
+	AppId         string `default:"dubbo" yaml:"app_id"  json:"app_id,omitempty"`
 	TimeoutStr    string `yaml:"timeout"  json:"timeout,omitempty"`
 	timeout       time.Duration
 }
@@ -50,3 +57,12 @@ func (c *ConfigCenterConfig) UnmarshalYAML(unmarshal func(interface{}) error) er
 	}
 	return nil
 }
+
+func (c *ConfigCenterConfig) GetUrlMap() url.Values {
+	urlMap := url.Values{}
+	urlMap.Set(constant.CONFIG_NAMESPACE_KEY, c.Namespace)
+	urlMap.Set(constant.CONFIG_GROUP_KEY, c.Group)
+	urlMap.Set(constant.CONFIG_CLUSTER_KEY, c.Cluster)
+	urlMap.Set(constant.CONFIG_APP_ID_KEY, c.AppId)
+	return urlMap
+}
diff --git a/config/config_loader.go b/config/config_loader.go
index b737d3f233700f596469cfd678aa7ae7f9a82b85..414bb479025c5d6111a6373fa2626f21ffa73ef0 100644
--- a/config/config_loader.go
+++ b/config/config_loader.go
@@ -149,6 +149,8 @@ func Load() {
 			}
 		}
 	}
+	// init the shutdown callback
+	GracefulShutdownInit()
 }
 
 // get rpc service for consumer
diff --git a/config/consumer_config.go b/config/consumer_config.go
index b1ebdd5d8e082bf836071460e2a330632e07335c..72f60b5f77b9b9cc633d8939713c0eb93563deac 100644
--- a/config/consumer_config.go
+++ b/config/consumer_config.go
@@ -52,11 +52,12 @@ type ConsumerConfig struct {
 	ProxyFactory    string `yaml:"proxy_factory" default:"default" json:"proxy_factory,omitempty" property:"proxy_factory"`
 	Check           *bool  `yaml:"check"  json:"check,omitempty" property:"check"`
 
-	Registry     *RegistryConfig             `yaml:"registry" json:"registry,omitempty" property:"registry"`
-	Registries   map[string]*RegistryConfig  `yaml:"registries" json:"registries,omitempty" property:"registries"`
-	References   map[string]*ReferenceConfig `yaml:"references" json:"references,omitempty" property:"references"`
-	ProtocolConf interface{}                 `yaml:"protocol_conf" json:"protocol_conf,omitempty" property:"protocol_conf"`
-	FilterConf   interface{}                 `yaml:"filter_conf" json:"filter_conf,omitempty" property:"filter_conf" `
+	Registry       *RegistryConfig             `yaml:"registry" json:"registry,omitempty" property:"registry"`
+	Registries     map[string]*RegistryConfig  `yaml:"registries" json:"registries,omitempty" property:"registries"`
+	References     map[string]*ReferenceConfig `yaml:"references" json:"references,omitempty" property:"references"`
+	ProtocolConf   interface{}                 `yaml:"protocol_conf" json:"protocol_conf,omitempty" property:"protocol_conf"`
+	FilterConf     interface{}                 `yaml:"filter_conf" json:"filter_conf,omitempty" property:"filter_conf" `
+	ShutdownConfig *ShutdownConfig             `yaml:"shutdown_conf" json:"shutdown_conf,omitempty" property:"shutdown_conf" `
 }
 
 func (c *ConsumerConfig) UnmarshalYAML(unmarshal func(interface{}) error) error {
diff --git a/config/graceful_shutdown.go b/config/graceful_shutdown.go
new file mode 100644
index 0000000000000000000000000000000000000000..fedb2c15ecdab62d17f0a4e83c45522f1c18acb0
--- /dev/null
+++ b/config/graceful_shutdown.go
@@ -0,0 +1,229 @@
+/*
+ * 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 config
+
+import (
+	"os"
+	"os/signal"
+	"runtime/debug"
+	"time"
+)
+
+import (
+	"github.com/dubbogo/gost/container/gxset"
+)
+
+import (
+	"github.com/apache/dubbo-go/common/constant"
+	"github.com/apache/dubbo-go/common/extension"
+	"github.com/apache/dubbo-go/common/logger"
+)
+
+/*
+ * The key point is that find out the signals to handle.
+ * The most important documentation is https://golang.org/pkg/os/signal/
+ * From this documentation, we can know that:
+ * 1. The signals SIGKILL and SIGSTOP may not be caught by signal package;
+ * 2. SIGHUP, SIGINT, or SIGTERM signal causes the program to exit
+ * 3. SIGQUIT, SIGILL, SIGTRAP, SIGABRT, SIGSTKFLT, SIGEMT, or SIGSYS signal causes the program to exit with a stack dump
+ * 4. The invocation of Notify(signal...) will disable the default behavior of those signals.
+ *
+ * So the signals SIGKILL, SIGSTOP, SIGHUP, SIGINT, SIGTERM, SIGQUIT, SIGILL, SIGTRAP, SIGABRT, SIGSTKFLT, SIGEMT, SIGSYS
+ * should be processed.
+ * syscall.SIGEMT cannot be found in CI
+ * It's seems that the Unix/Linux does not have the signal SIGSTKFLT. https://github.com/golang/go/issues/33381
+ * So this signal will be ignored.
+ * The signals are different on different platforms.
+ * We define them by using 'package build' feature https://golang.org/pkg/go/build/
+ */
+
+func GracefulShutdownInit() {
+
+	signals := make(chan os.Signal, 1)
+
+	signal.Notify(signals, ShutdownSignals...)
+
+	go func() {
+		select {
+		case sig := <-signals:
+			logger.Infof("get signal %s, application will shutdown.", sig)
+			// gracefulShutdownOnce.Do(func() {
+			BeforeShutdown()
+
+			// those signals' original behavior is exit with dump ths stack, so we try to keep the behavior
+			for _, dumpSignal := range DumpHeapShutdownSignals {
+				if sig == dumpSignal {
+					debug.WriteHeapDump(os.Stdout.Fd())
+				}
+			}
+
+			time.AfterFunc(totalTimeout(), func() {
+				logger.Warn("Shutdown gracefully timeout, application will shutdown immediately. ")
+				os.Exit(0)
+			})
+
+			os.Exit(0)
+		}
+	}()
+}
+
+func BeforeShutdown() {
+
+	destroyAllRegistries()
+	// waiting for a short time so that the clients have enough time to get the notification that server shutdowns
+	// The value of configuration depends on how long the clients will get notification.
+	waitAndAcceptNewRequests()
+
+	// reject the new request, but keeping waiting for accepting requests
+	waitForReceivingRequests()
+
+	// we fetch the protocols from Consumer.References. Consumer.ProtocolConfig doesn't contains all protocol, like jsonrpc
+	consumerProtocols := getConsumerProtocols()
+
+	// If this application is not the provider, it will do nothing
+	destroyProviderProtocols(consumerProtocols)
+
+	// reject sending the new request, and waiting for response of sending requests
+	waitForSendingRequests()
+
+	// If this application is not the consumer, it will do nothing
+	destroyConsumerProtocols(consumerProtocols)
+
+	logger.Info("Graceful shutdown --- Execute the custom callbacks.")
+	customCallbacks := extension.GetAllCustomShutdownCallbacks()
+	for callback := customCallbacks.Front(); callback != nil; callback = callback.Next() {
+		callback.Value.(func())()
+	}
+}
+
+func destroyAllRegistries() {
+	logger.Info("Graceful shutdown --- Destroy all registries. ")
+	registryProtocol := extension.GetProtocol(constant.REGISTRY_KEY)
+	registryProtocol.Destroy()
+}
+
+func destroyConsumerProtocols(consumerProtocols *gxset.HashSet) {
+	logger.Info("Graceful shutdown --- Destroy consumer's protocols. ")
+	for name := range consumerProtocols.Items {
+		extension.GetProtocol(name.(string)).Destroy()
+	}
+}
+
+/**
+ * destroy the provider's protocol.
+ * if the protocol is consumer's protocol too, we will keep it.
+ */
+func destroyProviderProtocols(consumerProtocols *gxset.HashSet) {
+
+	logger.Info("Graceful shutdown --- Destroy provider's protocols. ")
+
+	if providerConfig == nil || providerConfig.Protocols == nil {
+		return
+	}
+
+	for _, protocol := range providerConfig.Protocols {
+
+		// the protocol is the consumer's protocol too, we can not destroy it.
+		if consumerProtocols.Contains(protocol.Name) {
+			continue
+		}
+		extension.GetProtocol(protocol.Name).Destroy()
+	}
+}
+
+func waitAndAcceptNewRequests() {
+
+	logger.Info("Graceful shutdown --- Keep waiting and accept new requests for a short time. ")
+	if providerConfig == nil || providerConfig.ShutdownConfig == nil {
+		return
+	}
+
+	timeout := providerConfig.ShutdownConfig.GetStepTimeout()
+
+	// ignore this step
+	if timeout < 0 {
+		return
+	}
+	time.Sleep(timeout)
+}
+
+// for provider. It will wait for processing receiving requests
+func waitForReceivingRequests() {
+	logger.Info("Graceful shutdown --- Keep waiting until accepting requests finish or timeout. ")
+	if providerConfig == nil || providerConfig.ShutdownConfig == nil {
+		// ignore this step
+		return
+	}
+	waitingProcessedTimeout(providerConfig.ShutdownConfig)
+}
+
+// for consumer. It will wait for the response of sending requests
+func waitForSendingRequests() {
+	logger.Info("Graceful shutdown --- Keep waiting until sending requests getting response or timeout ")
+	if consumerConfig == nil || consumerConfig.ShutdownConfig == nil {
+		// ignore this step
+		return
+	}
+	waitingProcessedTimeout(consumerConfig.ShutdownConfig)
+}
+
+func waitingProcessedTimeout(shutdownConfig *ShutdownConfig) {
+	timeout := shutdownConfig.GetStepTimeout()
+	if timeout <= 0 {
+		return
+	}
+	start := time.Now()
+
+	for time.Now().After(start.Add(timeout)) && !shutdownConfig.RequestsFinished {
+		// sleep 10 ms and then we check it again
+		time.Sleep(10 * time.Millisecond)
+	}
+}
+
+func totalTimeout() time.Duration {
+	var providerShutdown time.Duration
+	if providerConfig != nil && providerConfig.ShutdownConfig != nil {
+		providerShutdown = providerConfig.ShutdownConfig.GetTimeout()
+	}
+
+	var consumerShutdown time.Duration
+	if consumerConfig != nil && consumerConfig.ShutdownConfig != nil {
+		consumerShutdown = consumerConfig.ShutdownConfig.GetTimeout()
+	}
+
+	var timeout = providerShutdown
+	if consumerShutdown > providerShutdown {
+		timeout = consumerShutdown
+	}
+	return timeout
+}
+
+/*
+ * we can not get the protocols from consumerConfig because some protocol don't have configuration, like jsonrpc.
+ */
+func getConsumerProtocols() *gxset.HashSet {
+	result := gxset.NewSet()
+	if consumerConfig == nil || consumerConfig.References == nil {
+		return result
+	}
+
+	for _, reference := range consumerConfig.References {
+		result.Add(reference.Protocol)
+	}
+	return result
+}
diff --git a/config/graceful_shutdown_config.go b/config/graceful_shutdown_config.go
new file mode 100644
index 0000000000000000000000000000000000000000..df55728565f6cf14ce4357f8c9c7927c30d80e40
--- /dev/null
+++ b/config/graceful_shutdown_config.go
@@ -0,0 +1,82 @@
+/*
+ * 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 config
+
+import (
+	"time"
+)
+
+import (
+	"github.com/apache/dubbo-go/common/constant"
+	"github.com/apache/dubbo-go/common/logger"
+)
+
+const (
+	defaultTimeout     = 60 * time.Second
+	defaultStepTimeout = 10 * time.Second
+)
+
+type ShutdownConfig struct {
+	/*
+	 * Total timeout. Even though we don't release all resources,
+	 * the application will shutdown if the costing time is over this configuration. The unit is ms.
+	 * default value is 60 * 1000 ms = 1 minutes
+	 * In general, it should be bigger than 3 * StepTimeout.
+	 */
+	Timeout string `default:"60s" yaml:"timeout" json:"timeout,omitempty" property:"timeout"`
+	/*
+	 * the timeout on each step. You should evaluate the response time of request
+	 * and the time that client noticed that server shutdown.
+	 * For example, if your client will received the notification within 10s when you start to close server,
+	 * and the 99.9% requests will return response in 2s, so the StepTimeout will be bigger than(10+2) * 1000ms,
+	 * maybe (10 + 2*3) * 1000ms is a good choice.
+	 */
+	StepTimeout string `default:"10s" yaml:"step_timeout" json:"step.timeout,omitempty" property:"step.timeout"`
+	// when we try to shutdown the application, we will reject the new requests. In most cases, you don't need to configure this.
+	RejectRequestHandler string `yaml:"reject_handler" json:"reject_handler,omitempty" property:"reject_handler"`
+	// true -> new request will be rejected.
+	RejectRequest bool
+
+	// true -> all requests had been processed. In provider side it means that all requests are returned response to clients
+	// In consumer side, it means that all requests getting response from servers
+	RequestsFinished bool
+}
+
+func (config *ShutdownConfig) Prefix() string {
+	return constant.ShutdownConfigPrefix
+}
+
+func (config *ShutdownConfig) GetTimeout() time.Duration {
+	result, err := time.ParseDuration(config.Timeout)
+	if err != nil {
+		logger.Errorf("The Timeout configuration is invalid: %s, and we will use the default value: %s, err: %v",
+			config.Timeout, defaultTimeout.String(), err)
+		return defaultTimeout
+	}
+	return result
+}
+
+func (config *ShutdownConfig) GetStepTimeout() time.Duration {
+	result, err := time.ParseDuration(config.StepTimeout)
+	if err != nil {
+		logger.Errorf("The StepTimeout configuration is invalid: %s, and we will use the default value: %s, err: %v",
+			config.StepTimeout, defaultStepTimeout.String(), err)
+		return defaultStepTimeout
+	}
+	return result
+}
diff --git a/config/graceful_shutdown_config_test.go b/config/graceful_shutdown_config_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..583ed70b838a8271a47e180ee3c6eb32cbb46984
--- /dev/null
+++ b/config/graceful_shutdown_config_test.go
@@ -0,0 +1,49 @@
+/*
+ * 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 config
+
+import (
+	"testing"
+	"time"
+)
+
+import (
+	"github.com/stretchr/testify/assert"
+)
+
+func TestShutdownConfig_GetTimeout(t *testing.T) {
+	config := ShutdownConfig{}
+	assert.False(t, config.RejectRequest)
+	assert.False(t, config.RequestsFinished)
+
+	config = ShutdownConfig{
+		Timeout:     "12x",
+		StepTimeout: "34a",
+	}
+
+	assert.Equal(t, 60*time.Second, config.GetTimeout())
+	assert.Equal(t, 10*time.Second, config.GetStepTimeout())
+
+	config = ShutdownConfig{
+		Timeout:     "34ms",
+		StepTimeout: "79ms",
+	}
+
+	assert.Equal(t, 34*time.Millisecond, config.GetTimeout())
+	assert.Equal(t, 79*time.Millisecond, config.GetStepTimeout())
+}
diff --git a/config/graceful_shutdown_signal_darwin.go b/config/graceful_shutdown_signal_darwin.go
new file mode 100644
index 0000000000000000000000000000000000000000..59c1a5d149c2e9db8e9ac981adec107cafc863ad
--- /dev/null
+++ b/config/graceful_shutdown_signal_darwin.go
@@ -0,0 +1,30 @@
+/*
+ * 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 config
+
+import (
+	"os"
+	"syscall"
+)
+
+var ShutdownSignals = []os.Signal{os.Interrupt, os.Kill, syscall.SIGKILL, syscall.SIGSTOP,
+	syscall.SIGHUP, syscall.SIGINT, syscall.SIGQUIT, syscall.SIGILL, syscall.SIGTRAP,
+	syscall.SIGABRT, syscall.SIGSYS}
+
+var DumpHeapShutdownSignals = []os.Signal{syscall.SIGQUIT, syscall.SIGILL,
+	syscall.SIGTRAP, syscall.SIGABRT, syscall.SIGSYS}
diff --git a/config/graceful_shutdown_signal_linux.go b/config/graceful_shutdown_signal_linux.go
new file mode 100644
index 0000000000000000000000000000000000000000..59c1a5d149c2e9db8e9ac981adec107cafc863ad
--- /dev/null
+++ b/config/graceful_shutdown_signal_linux.go
@@ -0,0 +1,30 @@
+/*
+ * 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 config
+
+import (
+	"os"
+	"syscall"
+)
+
+var ShutdownSignals = []os.Signal{os.Interrupt, os.Kill, syscall.SIGKILL, syscall.SIGSTOP,
+	syscall.SIGHUP, syscall.SIGINT, syscall.SIGQUIT, syscall.SIGILL, syscall.SIGTRAP,
+	syscall.SIGABRT, syscall.SIGSYS}
+
+var DumpHeapShutdownSignals = []os.Signal{syscall.SIGQUIT, syscall.SIGILL,
+	syscall.SIGTRAP, syscall.SIGABRT, syscall.SIGSYS}
diff --git a/config/graceful_shutdown_signal_windows.go b/config/graceful_shutdown_signal_windows.go
new file mode 100644
index 0000000000000000000000000000000000000000..91b2bce7c2311ecbe9a1255be3e7b7b357a9b403
--- /dev/null
+++ b/config/graceful_shutdown_signal_windows.go
@@ -0,0 +1,29 @@
+/*
+ * 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 config
+
+import (
+	"os"
+	"syscall"
+)
+
+var ShutdownSignals = []os.Signal{os.Interrupt, os.Kill, syscall.SIGKILL,
+	syscall.SIGHUP, syscall.SIGINT, syscall.SIGQUIT, syscall.SIGILL, syscall.SIGTRAP,
+	syscall.SIGABRT}
+
+var DumpHeapShutdownSignals = []os.Signal{syscall.SIGQUIT, syscall.SIGILL, syscall.SIGTRAP, syscall.SIGABRT}
diff --git a/config/graceful_shutdown_test.go b/config/graceful_shutdown_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..de203572c76281d221181dea90b0f31b43038de6
--- /dev/null
+++ b/config/graceful_shutdown_test.go
@@ -0,0 +1,99 @@
+/*
+ * 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 config
+
+import (
+	"testing"
+)
+
+import (
+	"github.com/apache/dubbo-go/common/constant"
+	"github.com/apache/dubbo-go/common/extension"
+	"github.com/apache/dubbo-go/protocol"
+)
+
+func TestGracefulShutdownInit(t *testing.T) {
+	GracefulShutdownInit()
+}
+
+func TestBeforeShutdown(t *testing.T) {
+	extension.SetProtocol("registry", func() protocol.Protocol {
+		return &mockRegistryProtocol{}
+	})
+	extension.SetProtocol(constant.DUBBO, func() protocol.Protocol {
+		return &mockRegistryProtocol{}
+	})
+
+	extension.SetProtocol("mock", func() protocol.Protocol {
+		return &mockRegistryProtocol{}
+	})
+
+	// protocolConfigs := make(map[interface{}]interface{}, 16)
+	consumerReferences := map[string]*ReferenceConfig{}
+	consumerReferences[constant.DUBBO] = &ReferenceConfig{
+		Protocol: constant.DUBBO,
+	}
+
+	// without configuration
+	BeforeShutdown()
+
+	consumerConfig = &ConsumerConfig{
+		References: consumerReferences,
+		ShutdownConfig: &ShutdownConfig{
+			Timeout:     "1",
+			StepTimeout: "1s",
+		}}
+
+	providerProtocols := map[string]*ProtocolConfig{}
+	providerProtocols[constant.DUBBO] = &ProtocolConfig{
+		Name: constant.DUBBO,
+	}
+
+	providerProtocols["mock"] = &ProtocolConfig{
+		Name: "mock",
+	}
+
+	providerConfig = &ProviderConfig{
+		ShutdownConfig: &ShutdownConfig{
+			Timeout:     "1",
+			StepTimeout: "1s",
+		},
+		Protocols: providerProtocols,
+	}
+	// test destroy protocol
+	BeforeShutdown()
+
+	providerConfig = &ProviderConfig{
+		ShutdownConfig: &ShutdownConfig{
+			Timeout:     "1",
+			StepTimeout: "-1s",
+		},
+		Protocols: providerProtocols,
+	}
+
+	consumerConfig = &ConsumerConfig{
+		References: consumerReferences,
+		ShutdownConfig: &ShutdownConfig{
+			Timeout:     "1",
+			StepTimeout: "-1s",
+		},
+	}
+
+	// test ignore steps
+	BeforeShutdown()
+}
diff --git a/config/method_config.go b/config/method_config.go
index ac9242a230816711ab84a074473890b6f96c2b11..876abeeae0c7d37070c5938107d1bb1dd5dbbaa9 100644
--- a/config/method_config.go
+++ b/config/method_config.go
@@ -25,12 +25,18 @@ import (
 )
 
 type MethodConfig struct {
-	InterfaceId   string
-	InterfaceName string
-	Name          string `yaml:"name"  json:"name,omitempty" property:"name"`
-	Retries       string `yaml:"retries"  json:"retries,omitempty" property:"retries"`
-	Loadbalance   string `yaml:"loadbalance"  json:"loadbalance,omitempty" property:"loadbalance"`
-	Weight        int64  `yaml:"weight"  json:"weight,omitempty" property:"weight"`
+	InterfaceId                 string
+	InterfaceName               string
+	Name                        string `yaml:"name"  json:"name,omitempty" property:"name"`
+	Retries                     string `yaml:"retries"  json:"retries,omitempty" property:"retries"`
+	Loadbalance                 string `yaml:"loadbalance"  json:"loadbalance,omitempty" property:"loadbalance"`
+	Weight                      int64  `yaml:"weight"  json:"weight,omitempty" property:"weight"`
+	TpsLimitInterval            string `yaml:"tps.limit.interval" json:"tps.limit.interval,omitempty" property:"tps.limit.interval"`
+	TpsLimitRate                string `yaml:"tps.limit.rate" json:"tps.limit.rate,omitempty" property:"tps.limit.rate"`
+	TpsLimitStrategy            string `yaml:"tps.limit.strategy" json:"tps.limit.strategy,omitempty" property:"tps.limit.strategy"`
+	ExecuteLimit                string `yaml:"execute.limit" json:"execute.limit,omitempty" property:"execute.limit"`
+	ExecuteLimitRejectedHandler string `yaml:"execute.limit.rejected.handler" json:"execute.limit.rejected.handler,omitempty" property:"execute.limit.rejected.handler"`
+	Sticky                      bool   `yaml:"sticky"   json:"sticky,omitempty" property:"sticky"`
 }
 
 func (c *MethodConfig) Prefix() string {
diff --git a/config/provider_config.go b/config/provider_config.go
index 00faa1d0ab1b65a7a39d7d3548e5b89b0f250aba..0fed44c81b124cd40825695981a5394c273203fa 100644
--- a/config/provider_config.go
+++ b/config/provider_config.go
@@ -49,6 +49,7 @@ type ProviderConfig struct {
 	Protocols         map[string]*ProtocolConfig `yaml:"protocols" json:"protocols,omitempty" property:"protocols"`
 	ProtocolConf      interface{}                `yaml:"protocol_conf" json:"protocol_conf,omitempty" property:"protocol_conf" `
 	FilterConf        interface{}                `yaml:"filter_conf" json:"filter_conf,omitempty" property:"filter_conf" `
+	ShutdownConfig    *ShutdownConfig            `yaml:"shutdown_conf" json:"shutdown_conf,omitempty" property:"shutdown_conf" `
 }
 
 func (c *ProviderConfig) UnmarshalYAML(unmarshal func(interface{}) error) error {
@@ -106,6 +107,7 @@ func ProviderInit(confProFile string) error {
 	}
 
 	logger.Debugf("provider config{%#v}\n", providerConfig)
+
 	return nil
 }
 
diff --git a/config/provider_config_test.go b/config/provider_config_test.go
index db4b5f9906efb25cdb0ad8bf91f412f4510f5af5..e8a9c1f7a730f79e5bf92e1d7dd2e42b969cb0f3 100644
--- a/config/provider_config_test.go
+++ b/config/provider_config_test.go
@@ -1,3 +1,20 @@
+/*
+ * 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 config
 
 import (
diff --git a/config/reference_config.go b/config/reference_config.go
index c63ac2ef28ff85d07b76ad0f5fef669d83bca3a5..4e0c56c0bc25e3b71b8edf015580cbe5ac5f0d9c 100644
--- a/config/reference_config.go
+++ b/config/reference_config.go
@@ -55,11 +55,12 @@ type ReferenceConfig struct {
 	Group         string            `yaml:"group"  json:"group,omitempty" property:"group"`
 	Version       string            `yaml:"version"  json:"version,omitempty" property:"version"`
 	Methods       []*MethodConfig   `yaml:"methods"  json:"methods,omitempty" property:"methods"`
-	async         bool              `yaml:"async"  json:"async,omitempty" property:"async"`
+	Async         bool              `yaml:"async"  json:"async,omitempty" property:"async"`
 	Params        map[string]string `yaml:"params"  json:"params,omitempty" property:"params"`
 	invoker       protocol.Invoker
 	urls          []*common.URL
 	Generic       bool `yaml:"generic"  json:"generic,omitempty" property:"generic"`
+	Sticky        bool `yaml:"sticky"   json:"sticky,omitempty" property:"sticky"`
 }
 
 func (c *ReferenceConfig) Prefix() string {
@@ -141,7 +142,12 @@ func (refconfig *ReferenceConfig) Refer() {
 	}
 
 	//create proxy
-	refconfig.pxy = extension.GetProxyFactory(consumerConfig.ProxyFactory).GetProxy(refconfig.invoker, url)
+	if refconfig.Async {
+		callback := GetCallback(refconfig.id)
+		refconfig.pxy = extension.GetProxyFactory(consumerConfig.ProxyFactory).GetAsyncProxy(refconfig.invoker, callback, url)
+	} else {
+		refconfig.pxy = extension.GetProxyFactory(consumerConfig.ProxyFactory).GetProxy(refconfig.invoker, url)
+	}
 }
 
 // @v is service provider implemented RPCService
@@ -169,7 +175,8 @@ func (refconfig *ReferenceConfig) getUrlMap() url.Values {
 	urlMap.Set(constant.GENERIC_KEY, strconv.FormatBool(refconfig.Generic))
 	urlMap.Set(constant.ROLE_KEY, strconv.Itoa(common.CONSUMER))
 	//getty invoke async or sync
-	urlMap.Set(constant.ASYNC_KEY, strconv.FormatBool(refconfig.async))
+	urlMap.Set(constant.ASYNC_KEY, strconv.FormatBool(refconfig.Async))
+	urlMap.Set(constant.STICKY_KEY, strconv.FormatBool(refconfig.Sticky))
 
 	//application info
 	urlMap.Set(constant.APPLICATION_KEY, consumerConfig.ApplicationConfig.Name)
@@ -183,13 +190,14 @@ func (refconfig *ReferenceConfig) getUrlMap() url.Values {
 	//filter
 	var defaultReferenceFilter = constant.DEFAULT_REFERENCE_FILTERS
 	if refconfig.Generic {
-		defaultReferenceFilter = constant.GENERIC_REFERENCE_FILTERS + defaultReferenceFilter
+		defaultReferenceFilter = constant.GENERIC_REFERENCE_FILTERS + "," + defaultReferenceFilter
 	}
 	urlMap.Set(constant.REFERENCE_FILTER_KEY, mergeValue(consumerConfig.Filter, refconfig.Filter, defaultReferenceFilter))
 
 	for _, v := range refconfig.Methods {
 		urlMap.Set("methods."+v.Name+"."+constant.LOADBALANCE_KEY, v.Loadbalance)
 		urlMap.Set("methods."+v.Name+"."+constant.RETRIES_KEY, v.Retries)
+		urlMap.Set("methods."+v.Name+"."+constant.STICKY_KEY, strconv.FormatBool(v.Sticky))
 	}
 
 	return urlMap
diff --git a/config/reference_config_test.go b/config/reference_config_test.go
index a81dbf06cef7d275cf6af4a7f651ff8d1600a3c9..e689c471ed12b58a40d4416efaa16abfe107e09b 100644
--- a/config/reference_config_test.go
+++ b/config/reference_config_test.go
@@ -81,10 +81,12 @@ func doInitConsumer() {
 		},
 		References: map[string]*ReferenceConfig{
 			"MockService": {
+				id: "MockProvider",
 				Params: map[string]string{
 					"serviceid": "soa.mock",
 					"forks":     "5",
 				},
+				Sticky:        false,
 				Registry:      "shanghai_reg1,shanghai_reg2,hangzhou_reg1,hangzhou_reg2",
 				InterfaceName: "com.MockService",
 				Protocol:      "mock",
@@ -103,6 +105,7 @@ func doInitConsumer() {
 						Name:        "GetUser1",
 						Retries:     "2",
 						Loadbalance: "random",
+						Sticky:      true,
 					},
 				},
 			},
@@ -110,6 +113,26 @@ func doInitConsumer() {
 	}
 }
 
+var mockProvider = new(MockProvider)
+
+type MockProvider struct {
+}
+
+func (m *MockProvider) Reference() string {
+	return "MockProvider"
+}
+
+func (m *MockProvider) CallBack(res common.CallbackResponse) {
+}
+
+func doInitConsumerAsync() {
+	doInitConsumer()
+	SetConsumerService(mockProvider)
+	for _, v := range consumerConfig.References {
+		v.Async = true
+	}
+}
+
 func doInitConsumerWithSingleRegistry() {
 	consumerConfig = &ConsumerConfig{
 		ApplicationConfig: &ApplicationConfig{
@@ -181,6 +204,22 @@ func Test_Refer(t *testing.T) {
 	}
 	consumerConfig = nil
 }
+
+func Test_ReferAsync(t *testing.T) {
+	doInitConsumerAsync()
+	extension.SetProtocol("registry", GetProtocol)
+	extension.SetCluster("registryAware", cluster_impl.NewRegistryAwareCluster)
+
+	for _, reference := range consumerConfig.References {
+		reference.Refer()
+		assert.Equal(t, "soa.mock", reference.Params["serviceid"])
+		assert.NotNil(t, reference.invoker)
+		assert.NotNil(t, reference.pxy)
+		assert.NotNil(t, reference.pxy.GetCallback())
+	}
+	consumerConfig = nil
+}
+
 func Test_ReferP2P(t *testing.T) {
 	doInitConsumer()
 	extension.SetProtocol("dubbo", GetProtocol)
@@ -254,6 +293,24 @@ func Test_Forking(t *testing.T) {
 	consumerConfig = nil
 }
 
+func Test_Sticky(t *testing.T) {
+	doInitConsumer()
+	extension.SetProtocol("dubbo", GetProtocol)
+	extension.SetProtocol("registry", GetProtocol)
+	m := consumerConfig.References["MockService"]
+	m.Url = "dubbo://127.0.0.1:20000;registry://127.0.0.2:20000"
+
+	reference := consumerConfig.References["MockService"]
+	reference.Refer()
+	referenceSticky := reference.invoker.GetUrl().GetParam(constant.STICKY_KEY, "false")
+	assert.Equal(t, "false", referenceSticky)
+
+	method0StickKey := reference.invoker.GetUrl().GetMethodParam(reference.Methods[0].Name, constant.STICKY_KEY, "false")
+	assert.Equal(t, "false", method0StickKey)
+	method1StickKey := reference.invoker.GetUrl().GetMethodParam(reference.Methods[1].Name, constant.STICKY_KEY, "false")
+	assert.Equal(t, "true", method1StickKey)
+}
+
 func GetProtocol() protocol.Protocol {
 	if regProtocol != nil {
 		return regProtocol
diff --git a/config/service.go b/config/service.go
index 2bceac4a8c20bb598dc2607c90c8206e4a448808..f1b51790ca13df0534882837397181e45e56ffa3 100644
--- a/config/service.go
+++ b/config/service.go
@@ -43,3 +43,11 @@ func GetConsumerService(name string) common.RPCService {
 func GetProviderService(name string) common.RPCService {
 	return proServices[name]
 }
+
+func GetCallback(name string) func(response common.CallbackResponse) {
+	service := GetConsumerService(name)
+	if sv, ok := service.(common.AsyncCallbackService); ok {
+		return sv.CallBack
+	}
+	return nil
+}
diff --git a/config/service_config.go b/config/service_config.go
index ee0457937e0c7bfaf6e5928e6333fe1c8db5a8b3..c17846322e20120bfdf00f1afe24bd20efe7510b 100644
--- a/config/service_config.go
+++ b/config/service_config.go
@@ -43,22 +43,30 @@ import (
 )
 
 type ServiceConfig struct {
-	context       context.Context
-	id            string
-	Filter        string            `yaml:"filter" json:"filter,omitempty" property:"filter"`
-	Protocol      string            `default:"dubbo"  required:"true"  yaml:"protocol"  json:"protocol,omitempty" property:"protocol"` //multi protocol support, split by ','
-	InterfaceName string            `required:"true"  yaml:"interface"  json:"interface,omitempty" property:"interface"`
-	Registry      string            `yaml:"registry"  json:"registry,omitempty"  property:"registry"`
-	Cluster       string            `default:"failover" yaml:"cluster"  json:"cluster,omitempty" property:"cluster"`
-	Loadbalance   string            `default:"random" yaml:"loadbalance"  json:"loadbalance,omitempty"  property:"loadbalance"`
-	Group         string            `yaml:"group"  json:"group,omitempty" property:"group"`
-	Version       string            `yaml:"version"  json:"version,omitempty" property:"version" `
-	Methods       []*MethodConfig   `yaml:"methods"  json:"methods,omitempty" property:"methods"`
-	Warmup        string            `yaml:"warmup"  json:"warmup,omitempty"  property:"warmup"`
-	Retries       string            `yaml:"retries"  json:"retries,omitempty" property:"retries"`
-	Params        map[string]string `yaml:"params"  json:"params,omitempty" property:"params"`
-	Token         string            `yaml:"token" json:"token,omitempty" property:"token"`
-	AccessLog     string            `yaml:"accesslog" json:"accesslog,omitempty" property:"accesslog"`
+	context                     context.Context
+	id                          string
+	Filter                      string            `yaml:"filter" json:"filter,omitempty" property:"filter"`
+	Protocol                    string            `default:"dubbo"  required:"true"  yaml:"protocol"  json:"protocol,omitempty" property:"protocol"` // multi protocol support, split by ','
+	InterfaceName               string            `required:"true"  yaml:"interface"  json:"interface,omitempty" property:"interface"`
+	Registry                    string            `yaml:"registry"  json:"registry,omitempty"  property:"registry"`
+	Cluster                     string            `default:"failover" yaml:"cluster"  json:"cluster,omitempty" property:"cluster"`
+	Loadbalance                 string            `default:"random" yaml:"loadbalance"  json:"loadbalance,omitempty"  property:"loadbalance"`
+	Group                       string            `yaml:"group"  json:"group,omitempty" property:"group"`
+	Version                     string            `yaml:"version"  json:"version,omitempty" property:"version" `
+	Methods                     []*MethodConfig   `yaml:"methods"  json:"methods,omitempty" property:"methods"`
+	Warmup                      string            `yaml:"warmup"  json:"warmup,omitempty"  property:"warmup"`
+	Retries                     string            `yaml:"retries"  json:"retries,omitempty" property:"retries"`
+	Params                      map[string]string `yaml:"params"  json:"params,omitempty" property:"params"`
+	Token                       string            `yaml:"token" json:"token,omitempty" property:"token"`
+	AccessLog                   string            `yaml:"accesslog" json:"accesslog,omitempty" property:"accesslog"`
+	TpsLimiter                  string            `yaml:"tps.limiter" json:"tps.limiter,omitempty" property:"tps.limiter"`
+	TpsLimitInterval            string            `yaml:"tps.limit.interval" json:"tps.limit.interval,omitempty" property:"tps.limit.interval"`
+	TpsLimitRate                string            `yaml:"tps.limit.rate" json:"tps.limit.rate,omitempty" property:"tps.limit.rate"`
+	TpsLimitStrategy            string            `yaml:"tps.limit.strategy" json:"tps.limit.strategy,omitempty" property:"tps.limit.strategy"`
+	TpsLimitRejectedHandler     string            `yaml:"tps.limit.rejected.handler" json:"tps.limit.rejected.handler,omitempty" property:"tps.limit.rejected.handler"`
+	ExecuteLimit                string            `yaml:"execute.limit" json:"execute.limit,omitempty" property:"execute.limit"`
+	ExecuteLimitRejectedHandler string            `yaml:"execute.limit.rejected.handler" json:"execute.limit.rejected.handler,omitempty" property:"execute.limit.rejected.handler"`
+
 	unexported    *atomic.Bool
 	exported      *atomic.Bool
 	rpcService    common.RPCService
@@ -94,9 +102,9 @@ func NewServiceConfig(id string, context context.Context) *ServiceConfig {
 }
 
 func (srvconfig *ServiceConfig) Export() error {
-	//TODO: config center start here
+	// TODO: config center start here
 
-	//TODO:delay export
+	// TODO:delay export
 	if srvconfig.unexported != nil && srvconfig.unexported.Load() {
 		err := perrors.Errorf("The service %v has already unexported! ", srvconfig.InterfaceName)
 		logger.Errorf(err.Error())
@@ -111,7 +119,7 @@ func (srvconfig *ServiceConfig) Export() error {
 	urlMap := srvconfig.getUrlMap()
 
 	for _, proto := range loadProtocol(srvconfig.Protocol, providerConfig.Protocols) {
-		//registry the service reflect
+		// registry the service reflect
 		methods, err := common.ServiceMap.Register(proto.Name, srvconfig.rpcService)
 		if err != nil {
 			err := perrors.Errorf("The service %v  export the protocol %v error! Error message is %v .", srvconfig.InterfaceName, proto.Name, err.Error())
@@ -164,7 +172,7 @@ func (srvconfig *ServiceConfig) Implement(s common.RPCService) {
 
 func (srvconfig *ServiceConfig) getUrlMap() url.Values {
 	urlMap := url.Values{}
-	//first set user params
+	// first set user params
 	for k, v := range srvconfig.Params {
 		urlMap.Set(k, v)
 	}
@@ -177,7 +185,7 @@ func (srvconfig *ServiceConfig) getUrlMap() url.Values {
 	urlMap.Set(constant.GROUP_KEY, srvconfig.Group)
 	urlMap.Set(constant.VERSION_KEY, srvconfig.Version)
 	urlMap.Set(constant.ROLE_KEY, strconv.Itoa(common.PROVIDER))
-	//application info
+	// application info
 	urlMap.Set(constant.APPLICATION_KEY, providerConfig.ApplicationConfig.Name)
 	urlMap.Set(constant.ORGANIZATION_KEY, providerConfig.ApplicationConfig.Organization)
 	urlMap.Set(constant.NAME_KEY, providerConfig.ApplicationConfig.Name)
@@ -186,16 +194,35 @@ func (srvconfig *ServiceConfig) getUrlMap() url.Values {
 	urlMap.Set(constant.OWNER_KEY, providerConfig.ApplicationConfig.Owner)
 	urlMap.Set(constant.ENVIRONMENT_KEY, providerConfig.ApplicationConfig.Environment)
 
-	//filter
+	// filter
 	urlMap.Set(constant.SERVICE_FILTER_KEY, mergeValue(providerConfig.Filter, srvconfig.Filter, constant.DEFAULT_SERVICE_FILTERS))
 
-	//filter special config
+	// filter special config
 	urlMap.Set(constant.ACCESS_LOG_KEY, srvconfig.AccessLog)
+	// tps limiter
+	urlMap.Set(constant.TPS_LIMIT_STRATEGY_KEY, srvconfig.TpsLimitStrategy)
+	urlMap.Set(constant.TPS_LIMIT_INTERVAL_KEY, srvconfig.TpsLimitInterval)
+	urlMap.Set(constant.TPS_LIMIT_RATE_KEY, srvconfig.TpsLimitRate)
+	urlMap.Set(constant.TPS_LIMITER_KEY, srvconfig.TpsLimiter)
+	urlMap.Set(constant.TPS_REJECTED_EXECUTION_HANDLER_KEY, srvconfig.TpsLimitRejectedHandler)
+
+	// execute limit filter
+	urlMap.Set(constant.EXECUTE_LIMIT_KEY, srvconfig.ExecuteLimit)
+	urlMap.Set(constant.EXECUTE_REJECTED_EXECUTION_HANDLER_KEY, srvconfig.ExecuteLimitRejectedHandler)
 
 	for _, v := range srvconfig.Methods {
-		urlMap.Set("methods."+v.Name+"."+constant.LOADBALANCE_KEY, v.Loadbalance)
-		urlMap.Set("methods."+v.Name+"."+constant.RETRIES_KEY, v.Retries)
-		urlMap.Set("methods."+v.Name+"."+constant.WEIGHT_KEY, strconv.FormatInt(v.Weight, 10))
+		prefix := "methods." + v.Name + "."
+		urlMap.Set(prefix+constant.LOADBALANCE_KEY, v.Loadbalance)
+		urlMap.Set(prefix+constant.RETRIES_KEY, v.Retries)
+		urlMap.Set(prefix+constant.WEIGHT_KEY, strconv.FormatInt(v.Weight, 10))
+
+		urlMap.Set(prefix+constant.TPS_LIMIT_STRATEGY_KEY, v.TpsLimitStrategy)
+		urlMap.Set(prefix+constant.TPS_LIMIT_INTERVAL_KEY, v.TpsLimitInterval)
+		urlMap.Set(prefix+constant.TPS_LIMIT_RATE_KEY, v.TpsLimitRate)
+
+		urlMap.Set(constant.EXECUTE_LIMIT_KEY, v.ExecuteLimit)
+		urlMap.Set(constant.EXECUTE_REJECTED_EXECUTION_HANDLER_KEY, v.ExecuteLimitRejectedHandler)
+
 	}
 
 	return urlMap
diff --git a/config/testdata/consumer_config.properties b/config/testdata/consumer_config.properties
new file mode 100644
index 0000000000000000000000000000000000000000..da9fe4f3b3f2ae47dafc8252e388678e7cd5d03b
--- /dev/null
+++ b/config/testdata/consumer_config.properties
@@ -0,0 +1,52 @@
+filter=
+request_timeout=100ms
+connect_timeout=100ms
+check=true
+application.organization=ikurento.com
+application.name=BDTService
+application.module=dubbogo user-info client
+application.version=0.0.1
+application.owner=ZX
+application.environment=dev
+registries.hangzhouzk.protocol=zookeeper
+registries.hangzhouzk.timeout=3s
+registries.hangzhouzk.address=127.0.0.1:2181
+registries.hangzhouzk.username=
+registries.hangzhouzk.password=
+registries.shanghaizk.protocol=zookeeper
+registries.shanghaizk.timeout=3s
+registries.shanghaizk.address=127.0.0.1:2182
+registries.shanghaizk.username=
+registries.shanghaizk.password=
+references.UserProvider.registry=hangzhouzk,shanghaizk
+references.UserProvider.filter=
+references.UserProvider.version=1.0
+references.UserProvider.group=as
+references.UserProvider.interface=com.ikurento.user.UserProvider
+references.UserProvider.url=dubbo://127.0.0.1:20000/UserProvider
+references.UserProvider.cluster=failover
+references.UserProvider.methods[0].name=GetUser
+references.UserProvider.methods[0].retries=3
+references.UserProvider.params.serviceid=soa.com.ikurento.user.UserProvider
+references.UserProvider.params.forks=5
+protocol_conf.dubbo.reconnect_interval=0
+protocol_conf.dubbo.connection_number=2
+protocol_conf.dubbo.heartbeat_period=5s
+protocol_conf.dubbo.session_timeout=20s
+protocol_conf.dubbo.pool_size=64
+protocol_conf.dubbo.pool_ttl=600
+protocol_conf.dubbo.gr_pool_size=1200
+protocol_conf.dubbo.queue_len=64
+protocol_conf.dubbo.queue_number=60
+protocol_conf.dubbo.getty_session_param.compress_encoding=false
+protocol_conf.dubbo.getty_session_param.tcp_no_delay=true
+protocol_conf.dubbo.getty_session_param.tcp_keep_alive=true
+protocol_conf.dubbo.getty_session_param.keep_alive_period=120s
+protocol_conf.dubbo.getty_session_param.tcp_r_buf_size=262144
+protocol_conf.dubbo.getty_session_param.tcp_w_buf_size=65536
+protocol_conf.dubbo.getty_session_param.pkg_wq_size=512
+protocol_conf.dubbo.getty_session_param.tcp_read_timeout=1s
+protocol_conf.dubbo.getty_session_param.tcp_write_timeout=5s
+protocol_conf.dubbo.getty_session_param.wait_timeout=1s
+protocol_conf.dubbo.getty_session_param.max_msg_len=1024
+protocol_conf.dubbo.getty_session_param.session_name=client
\ No newline at end of file
diff --git a/config/testdata/consumer_config.yml b/config/testdata/consumer_config.yml
index 9fd50bb4d35a40d8532c9a644a86ad6834f8e89b..f44ea449fd16235050f6a7ba7823a87e24791780 100644
--- a/config/testdata/consumer_config.yml
+++ b/config/testdata/consumer_config.yml
@@ -49,6 +49,10 @@ references:
         "soa.com.ikurento.user.UserProvider"
       "forks": 5
 
+shutdown_conf:
+  timeout: 60s
+  step_timeout: 10s
+
 protocol_conf:
   dubbo:
     reconnect_interval: 0
diff --git a/config/testdata/consumer_config_with_configcenter.yml b/config/testdata/consumer_config_with_configcenter.yml
index 0550cc89741b6a490aaba9ff8906d7dda1b3ed49..ebe56fa93f9f5728aa365ee5b7a99b6bb5857a8e 100644
--- a/config/testdata/consumer_config_with_configcenter.yml
+++ b/config/testdata/consumer_config_with_configcenter.yml
@@ -17,6 +17,10 @@ references:
       - name: "GetUser"
         retries: "3"
 
+shutdown_conf:
+  timeout: 60s
+  step_timeout: 10s
+
 protocol_conf:
   dubbo:
     reconnect_interval: 0
diff --git a/config/testdata/consumer_config_with_configcenter_apollo.yml b/config/testdata/consumer_config_with_configcenter_apollo.yml
new file mode 100644
index 0000000000000000000000000000000000000000..49b8fff59541766729433138574d909ae4b9566e
--- /dev/null
+++ b/config/testdata/consumer_config_with_configcenter_apollo.yml
@@ -0,0 +1,24 @@
+# use apollo config center for fetch config file
+# default config file namespace is dubbo.properties
+# consumer config file Ref:consumer_config.properties
+# provider config file Ref:provider_config.properties
+config_center:
+  protocol: apollo
+  address: 106.12.25.204:8080
+  group: testApplication_yang
+  cluster: dev
+  # 'namespace' can be used for router rule , default value is dubbo.properties
+  # but if you want to change router rule config file ,just open this item
+#  namespace: governance.properties
+  # 'config_file' is not necessary ,default : dubbo.properties
+  # but if you want to change config file ,just open this item
+#  config_file: mockDubbog.properties
+
+# application config required
+application:
+  organization: "ikurento.com"
+  name: "BDTService"
+  module: "dubbogo user-info server"
+  version: "0.0.1"
+  owner: "ZX"
+  environment: "dev"
\ No newline at end of file
diff --git a/config/testdata/consumer_config_withoutProtocol.yml b/config/testdata/consumer_config_withoutProtocol.yml
index 5e57c7ddf6e82152e4f207b2d06df1443766717c..32bad8b91db3fac9c026fca36c5dc3b84f4c3fc9 100644
--- a/config/testdata/consumer_config_withoutProtocol.yml
+++ b/config/testdata/consumer_config_withoutProtocol.yml
@@ -48,6 +48,10 @@ references:
         "soa.com.ikurento.user.UserProvider"
       "forks": 5
 
+shutdown_conf:
+  timeout: 60s
+  step_timeout: 10s
+
 protocol_conf:
   dubbo:
     reconnect_interval: 0
diff --git a/config/testdata/provider_config.properties b/config/testdata/provider_config.properties
new file mode 100644
index 0000000000000000000000000000000000000000..f7d70f5cd635cae0b14d79890c1bab976978d1c6
--- /dev/null
+++ b/config/testdata/provider_config.properties
@@ -0,0 +1,58 @@
+filter=
+application.organization=ikurento.com
+application.name=BDTService
+application.module=dubbogo user-info server
+application.version=0.0.1
+application.owner=ZX
+application.environment=dev
+registries.hangzhouzk.protocol=zookeeper
+registries.hangzhouzk.timeout=3s
+registries.hangzhouzk.address=127.0.0.1:2181
+registries.hangzhouzk.username=
+registries.hangzhouzk.password=
+registries.shanghaizk.protocol=zookeeper
+registries.shanghaizk.timeout=3s
+registries.shanghaizk.address=127.0.0.1:2182
+registries.shanghaizk.username=
+registries.shanghaizk.password=
+services.UserProvider.registry=hangzhouzk,shanghaizk
+services.UserProvider.filter=
+services.UserProvider.tps.limiter=default
+services.UserProvider.tps.limit.interval=60000
+services.UserProvider.tps.limit.rate=200
+services.UserProvider.tps.limit.strategy=slidingWindow
+services.UserProvider.tps.limit.rejected.handler=default
+services.UserProvider.execute.limit=200
+services.UserProvider.execute.limit.rejected.handler=default
+services.UserProvider.protocol=dubbo
+services.UserProvider.interface=com.ikurento.user.UserProvider
+services.UserProvider.loadbalance=random
+services.UserProvider.version=1.0
+services.UserProvider.group=as
+services.UserProvider.warmup=100
+services.UserProvider.cluster=failover
+services.UserProvider.methods[0].name=GetUser
+services.UserProvider.methods[0].retries=1
+services.UserProvider.methods[0].loadbalance=random
+services.UserProvider.methods[0].execute.limit=200
+services.UserProvider.methods[0].execute.limit.rejected.handler=default
+protocols.dubbo.name=dubbo
+protocols.dubbo.ip=127.0.0.1
+protocols.dubbo.port=20000
+protocol_conf.dubbo.session_number=700
+protocol_conf.dubbo.session_timeout=20s
+protocol_conf.dubbo.gr_pool_size=120
+protocol_conf.dubbo.queue_len=64
+protocol_conf.dubbo.queue_number=6
+protocol_conf.dubbo.getty_session_param.compress_encoding=false
+protocol_conf.dubbo.getty_session_param.tcp_no_delay=true
+protocol_conf.dubbo.getty_session_param.tcp_keep_alive=true
+protocol_conf.dubbo.getty_session_param.keep_alive_period=120s
+protocol_conf.dubbo.getty_session_param.tcp_r_buf_size=262144
+protocol_conf.dubbo.getty_session_param.tcp_w_buf_size=65536
+protocol_conf.dubbo.getty_session_param.pkg_wq_size=512
+protocol_conf.dubbo.getty_session_param.tcp_read_timeout=1s
+protocol_conf.dubbo.getty_session_param.tcp_write_timeout=5s
+protocol_conf.dubbo.getty_session_param.wait_timeout=1s
+protocol_conf.dubbo.getty_session_param.max_msg_len=1024
+protocol_conf.dubbo.getty_session_param.session_name=server
\ No newline at end of file
diff --git a/config/testdata/provider_config.yml b/config/testdata/provider_config.yml
index 5cbefe08111a048cec1902fbf9563cf78552a730..7c46f9101aa9a6ecb88a92953dfcec28dda4e0ff 100644
--- a/config/testdata/provider_config.yml
+++ b/config/testdata/provider_config.yml
@@ -29,6 +29,20 @@ services:
   "UserProvider":
     registry: "hangzhouzk,shanghaizk"
     filter: ""
+    # the name of limiter
+    tps.limiter: "default"
+    # the time unit of interval is ms
+    tps.limit.interval: 60000
+    tps.limit.rate: 200
+    # the name of strategy
+    tps.limit.strategy: "slidingWindow"
+    # the name of RejectedExecutionHandler
+    tps.limit.rejected.handler: "default"
+    # the concurrent request limitation of this service
+    # if the value < 0, it will not be limited.
+    execute.limit: "200"
+    # the name of RejectedExecutionHandler
+    execute.limit.rejected.handler: "default"
     protocol : "dubbo"
     # equivalent to interface of dubbo.xml
     interface : "com.ikurento.user.UserProvider"
@@ -41,6 +55,11 @@ services:
       - name: "GetUser"
         retries: 1
         loadbalance: "random"
+        # the concurrent request limitation of this method
+        # if the value < 0, it will not be limited.
+        execute.limit: "200"
+        # the name of RejectedExecutionHandler
+        execute.limit.rejected.handler: "default"
 
 protocols:
     "dubbo":
@@ -52,6 +71,10 @@ protocols:
   #    ip: "127.0.0.1"
   #    port: 20001
 
+shutdown_conf:
+  timeout: 60s
+  step_timeout: 10s
+
 protocol_conf:
   dubbo:
     session_number: 700
diff --git a/config/testdata/provider_config_withoutProtocol.yml b/config/testdata/provider_config_withoutProtocol.yml
index 2f65868d4948db9a8b99c500014ea1307569d86f..532d3005aa351820bd540b31e2721dc2a0b5c6ed 100644
--- a/config/testdata/provider_config_withoutProtocol.yml
+++ b/config/testdata/provider_config_withoutProtocol.yml
@@ -51,6 +51,10 @@ protocols:
   #    ip: "127.0.0.1"
   #    port: 20001
 
+shutdown_conf:
+  timeout: 60s
+  step_timeout: 10s
+
 protocol_conf:
   dubbo:
     session_number: 700
diff --git a/config_center/apollo/factory.go b/config_center/apollo/factory.go
new file mode 100644
index 0000000000000000000000000000000000000000..47011be4a3e0e421ca7a314620a3547d665111c8
--- /dev/null
+++ b/config_center/apollo/factory.go
@@ -0,0 +1,45 @@
+/*
+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 apollo
+
+import (
+	"github.com/apache/dubbo-go/common"
+	"github.com/apache/dubbo-go/common/extension"
+	. "github.com/apache/dubbo-go/config_center"
+	"github.com/apache/dubbo-go/config_center/parser"
+)
+
+func init() {
+	extension.SetConfigCenterFactory("apollo", createDynamicConfigurationFactory)
+}
+
+func createDynamicConfigurationFactory() DynamicConfigurationFactory {
+	return &apolloConfigurationFactory{}
+}
+
+type apolloConfigurationFactory struct{}
+
+func (f *apolloConfigurationFactory) GetDynamicConfiguration(url *common.URL) (DynamicConfiguration, error) {
+	dynamicConfiguration, err := newApolloConfiguration(url)
+	if err != nil {
+		return nil, err
+	}
+	dynamicConfiguration.SetParser(&parser.DefaultConfigurationParser{})
+	return dynamicConfiguration, err
+
+}
diff --git a/config_center/apollo/impl.go b/config_center/apollo/impl.go
new file mode 100644
index 0000000000000000000000000000000000000000..ed46d4f9635d4d480a21d09fce0ec4ec84d47a66
--- /dev/null
+++ b/config_center/apollo/impl.go
@@ -0,0 +1,168 @@
+/*
+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 apollo
+
+import (
+	"fmt"
+	"regexp"
+	"strings"
+	"sync"
+)
+
+import (
+	"github.com/pkg/errors"
+	"github.com/zouyx/agollo"
+)
+
+import (
+	"github.com/apache/dubbo-go/common"
+	"github.com/apache/dubbo-go/common/constant"
+	. "github.com/apache/dubbo-go/config_center"
+	"github.com/apache/dubbo-go/config_center/parser"
+	"github.com/apache/dubbo-go/remoting"
+)
+
+const (
+	apolloProtocolPrefix = "http://"
+	apolloConfigFormat   = "%s.%s"
+)
+
+type apolloConfiguration struct {
+	url *common.URL
+
+	listeners sync.Map
+	appConf   *agollo.AppConfig
+	parser    parser.ConfigurationParser
+}
+
+func newApolloConfiguration(url *common.URL) (*apolloConfiguration, error) {
+	c := &apolloConfiguration{
+		url: url,
+	}
+	configAddr := c.getAddressWithProtocolPrefix(url)
+	configCluster := url.GetParam(constant.CONFIG_CLUSTER_KEY, "")
+
+	appId := url.GetParam(constant.CONFIG_APP_ID_KEY, "")
+	namespaces := url.GetParam(constant.CONFIG_NAMESPACE_KEY, getProperties(DEFAULT_GROUP))
+	c.appConf = &agollo.AppConfig{
+		AppId:         appId,
+		Cluster:       configCluster,
+		NamespaceName: namespaces,
+		Ip:            configAddr,
+	}
+
+	agollo.InitCustomConfig(func() (*agollo.AppConfig, error) {
+		return c.appConf, nil
+	})
+
+	return c, agollo.Start()
+}
+
+func getChangeType(change agollo.ConfigChangeType) remoting.EventType {
+	switch change {
+	case agollo.ADDED:
+		return remoting.EventTypeAdd
+	case agollo.DELETED:
+		return remoting.EventTypeDel
+	default:
+		return remoting.EventTypeUpdate
+	}
+}
+
+func (c *apolloConfiguration) AddListener(key string, listener ConfigurationListener, opts ...Option) {
+	k := &Options{}
+	for _, opt := range opts {
+		opt(k)
+	}
+
+	key = k.Group + key
+	l, _ := c.listeners.LoadOrStore(key, NewApolloListener())
+	l.(*apolloListener).AddListener(listener)
+}
+
+func (c *apolloConfiguration) RemoveListener(key string, listener ConfigurationListener, opts ...Option) {
+	k := &Options{}
+	for _, opt := range opts {
+		opt(k)
+	}
+
+	key = k.Group + key
+	l, ok := c.listeners.Load(key)
+	if ok {
+		l.(*apolloListener).RemoveListener(listener)
+	}
+}
+
+func getProperties(namespace string) string {
+	return getNamespaceName(namespace, agollo.Properties)
+}
+
+func getNamespaceName(namespace string, configFileFormat agollo.ConfigFileFormat) string {
+	return fmt.Sprintf(apolloConfigFormat, namespace, configFileFormat)
+}
+
+func (c *apolloConfiguration) GetInternalProperty(key string, opts ...Option) (string, error) {
+	config := agollo.GetConfig(c.appConf.NamespaceName)
+	if config == nil {
+		return "", errors.New(fmt.Sprintf("nothing in namespace:%s ", key))
+	}
+	return config.GetStringValue(key, ""), nil
+}
+
+func (c *apolloConfiguration) GetRule(key string, opts ...Option) (string, error) {
+	return c.GetInternalProperty(key, opts...)
+}
+
+func (c *apolloConfiguration) GetProperties(key string, opts ...Option) (string, error) {
+	/**
+	 * 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 {
+		return "", errors.New(fmt.Sprintf("nothing in namespace:%s ", key))
+	}
+	return config.GetContent(agollo.Properties), nil
+}
+
+func (c *apolloConfiguration) getAddressWithProtocolPrefix(url *common.URL) string {
+	address := url.Location
+	converted := address
+	if len(address) != 0 {
+		reg := regexp.MustCompile("\\s+")
+		address = reg.ReplaceAllString(address, "")
+		parts := strings.Split(address, ",")
+		addrs := make([]string, 0)
+		for _, part := range parts {
+			addr := part
+			if !strings.HasPrefix(part, apolloProtocolPrefix) {
+				addr = apolloProtocolPrefix + part
+			}
+			addrs = append(addrs, addr)
+		}
+		converted = strings.Join(addrs, ",")
+	}
+	return converted
+}
+
+func (c *apolloConfiguration) Parser() parser.ConfigurationParser {
+	return c.parser
+}
+func (c *apolloConfiguration) SetParser(p parser.ConfigurationParser) {
+	c.parser = p
+}
diff --git a/config_center/apollo/impl_test.go b/config_center/apollo/impl_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..e898be91ee356180f5967f9dd5a02df0dbcfb311
--- /dev/null
+++ b/config_center/apollo/impl_test.go
@@ -0,0 +1,262 @@
+/*
+ * 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 apollo
+
+import (
+	"context"
+	"fmt"
+	"net/http"
+	"net/http/httptest"
+	"strings"
+	"sync"
+	"testing"
+)
+
+import (
+	"github.com/stretchr/testify/assert"
+)
+
+import (
+	"github.com/apache/dubbo-go/common"
+	"github.com/apache/dubbo-go/config"
+	"github.com/apache/dubbo-go/config_center"
+	"github.com/apache/dubbo-go/config_center/parser"
+	"github.com/apache/dubbo-go/remoting"
+)
+
+const (
+	mockAppId     = "testApplication_yang"
+	mockCluster   = "dev"
+	mockNamespace = "mockDubbog.properties"
+	mockNotifyRes = `[{
+	"namespaceName": "mockDubbog.properties",
+	"notificationId": 53050,
+	"messages": {
+		"details": {
+			"testApplication_yang+default+mockDubbog": 53050
+		}
+	}
+}]`
+	mockServiceConfigRes = `[{
+	"appName": "APOLLO-CONFIGSERVICE",
+	"instanceId": "instance-300408ep:apollo-configservice:8080",
+	"homepageUrl": "http://localhost:8080"
+}]`
+)
+
+var (
+	mockConfigRes = `{
+	"appId": "testApplication_yang",
+	"cluster": "default",
+	"namespaceName": "mockDubbog.properties",
+	"configurations": {
+		"registries.hangzhouzk.username": "",
+		"application.owner": "ZX",
+		"registries.shanghaizk.username": "",
+		"protocols.dubbo.ip": "127.0.0.1",
+		"protocol_conf.dubbo.getty_session_param.tcp_write_timeout": "5s",
+		"services.UserProvider.cluster": "failover",
+		"application.module": "dubbogo user-info server",
+		"services.UserProvider.interface": "com.ikurento.user.UserProvider",
+		"protocol_conf.dubbo.getty_session_param.compress_encoding": "false",
+		"registries.shanghaizk.address": "127.0.0.1:2182",
+		"protocol_conf.dubbo.session_timeout": "20s",
+		"registries.shanghaizk.timeout": "3s",
+		"protocol_conf.dubbo.getty_session_param.keep_alive_period": "120s",
+		"services.UserProvider.warmup": "100",
+		"application.version": "0.0.1",
+		"registries.hangzhouzk.protocol": "zookeeper",
+		"registries.hangzhouzk.password": "",
+		"protocols.dubbo.name": "dubbo",
+		"protocol_conf.dubbo.getty_session_param.wait_timeout": "1s",
+		"protocols.dubbo.port": "20000",
+		"application_config.owner": "demo",
+		"application_config.name": "demo",
+		"application_config.version": "0.0.1",
+		"application_config.environment": "dev",
+		"protocol_conf.dubbo.getty_session_param.session_name": "server",
+		"application.name": "BDTService",
+		"registries.hangzhouzk.timeout": "3s",
+		"protocol_conf.dubbo.getty_session_param.tcp_read_timeout": "1s",
+		"services.UserProvider.loadbalance": "random",
+		"protocol_conf.dubbo.session_number": "700",
+		"protocol_conf.dubbo.getty_session_param.max_msg_len": "1024",
+		"services.UserProvider.registry": "hangzhouzk",
+		"application_config.module": "demo",
+		"services.UserProvider.methods[0].name": "GetUser",
+		"protocol_conf.dubbo.getty_session_param.tcp_no_delay": "true",
+		"services.UserProvider.methods[0].retries": "1",
+		"protocol_conf.dubbo.getty_session_param.tcp_w_buf_size": "65536",
+		"protocol_conf.dubbo.getty_session_param.tcp_r_buf_size": "262144",
+		"registries.shanghaizk.password": "",
+		"application_config.organization": "demo",
+		"registries.shanghaizk.protocol": "zookeeper",
+		"protocol_conf.dubbo.getty_session_param.tcp_keep_alive": "true",
+		"registries.hangzhouzk.address": "127.0.0.1:2181",
+		"application.environment": "dev",
+		"services.UserProvider.protocol": "dubbo",
+		"application.organization": "ikurento.com",
+		"protocol_conf.dubbo.getty_session_param.pkg_wq_size": "512",
+		"services.UserProvider.methods[0].loadbalance": "random"
+	},
+	"releaseKey": "20191104105242-0f13805d89f834a4"
+}`
+)
+
+func initApollo() *httptest.Server {
+	handlerMap := make(map[string]func(http.ResponseWriter, *http.Request), 1)
+	handlerMap[mockNamespace] = configResponse
+
+	return runMockConfigServer(handlerMap, notifyResponse)
+}
+
+func configResponse(rw http.ResponseWriter, req *http.Request) {
+	result := fmt.Sprintf(mockConfigRes)
+	fmt.Fprintf(rw, "%s", result)
+}
+
+func notifyResponse(rw http.ResponseWriter, req *http.Request) {
+	result := fmt.Sprintf(mockNotifyRes)
+	fmt.Fprintf(rw, "%s", result)
+}
+
+func serviceConfigResponse(rw http.ResponseWriter, req *http.Request) {
+	result := fmt.Sprintf(mockServiceConfigRes)
+	fmt.Fprintf(rw, "%s", result)
+}
+
+//run mock config server
+func runMockConfigServer(handlerMap map[string]func(http.ResponseWriter, *http.Request),
+	notifyHandler func(http.ResponseWriter, *http.Request)) *httptest.Server {
+	uriHandlerMap := make(map[string]func(http.ResponseWriter, *http.Request), 0)
+	for namespace, handler := range handlerMap {
+		uri := fmt.Sprintf("/configs/%s/%s/%s", mockAppId, mockCluster, namespace)
+		uriHandlerMap[uri] = handler
+	}
+	uriHandlerMap["/notifications/v2"] = notifyHandler
+	uriHandlerMap["/services/config"] = serviceConfigResponse
+
+	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+		uri := r.RequestURI
+		for path, handler := range uriHandlerMap {
+			if strings.HasPrefix(uri, path) {
+				handler(w, r)
+				break
+			}
+		}
+	}))
+
+	return ts
+}
+
+func Test_GetConfig(t *testing.T) {
+	configuration := initMockApollo(t)
+	configs, err := configuration.GetProperties(mockNamespace, config_center.WithGroup("dubbo"))
+	assert.NoError(t, err)
+	configuration.SetParser(&parser.DefaultConfigurationParser{})
+	mapContent, err := configuration.Parser().Parse(configs)
+	assert.NoError(t, err)
+	assert.Equal(t, "ikurento.com", mapContent["application.organization"])
+}
+
+func Test_GetConfigItem(t *testing.T) {
+	configuration := initMockApollo(t)
+	configs, err := configuration.GetInternalProperty("application.organization")
+	assert.NoError(t, err)
+	configuration.SetParser(&parser.DefaultConfigurationParser{})
+	assert.NoError(t, err)
+	assert.Equal(t, "ikurento.com", configs)
+}
+
+func initMockApollo(t *testing.T) *apolloConfiguration {
+	c := &config.BaseConfig{ConfigCenterConfig: &config.ConfigCenterConfig{
+		Protocol:  "apollo",
+		Address:   "106.12.25.204:8080",
+		AppId:     "testApplication_yang",
+		Cluster:   "dev",
+		Namespace: "mockDubbog.properties",
+	}}
+	apollo := initApollo()
+	apolloUrl := strings.ReplaceAll(apollo.URL, "http", "apollo")
+	url, err := common.NewURL(context.TODO(), apolloUrl, common.WithParams(c.ConfigCenterConfig.GetUrlMap()))
+	assert.NoError(t, err)
+	configuration, err := newApolloConfiguration(&url)
+	assert.NoError(t, err)
+	return configuration
+}
+
+func TestAddListener(t *testing.T) {
+	listener := &apolloDataListener{}
+	listener.wg.Add(1)
+	apollo := initMockApollo(t)
+	mockConfigRes = `{
+	"appId": "testApplication_yang",
+	"cluster": "default",
+	"namespaceName": "mockDubbog.properties",
+	"configurations": {
+		"registries.hangzhouzk.username": "11111"
+	},
+	"releaseKey": "20191104105242-0f13805d89f834a4"
+}`
+	apollo.AddListener(mockNamespace, listener)
+	listener.wg.Wait()
+	assert.Equal(t, "registries.hangzhouzk.username", listener.event)
+	assert.Greater(t, listener.count, 0)
+}
+
+func TestRemoveListener(t *testing.T) {
+	listener := &apolloDataListener{}
+	apollo := initMockApollo(t)
+	mockConfigRes = `{
+	"appId": "testApplication_yang",
+	"cluster": "default",
+	"namespaceName": "mockDubbog.properties",
+	"configurations": {
+		"registries.hangzhouzk.username": "11111"
+	},
+	"releaseKey": "20191104105242-0f13805d89f834a4"
+}`
+	apollo.AddListener(mockNamespace, listener)
+	apollo.RemoveListener(mockNamespace, listener)
+	assert.Equal(t, "", listener.event)
+	listenerCount := 0
+	apollo.listeners.Range(func(key, value interface{}) bool {
+		apolloListener := value.(*apolloListener)
+		for e := range apolloListener.listeners {
+			fmt.Println(e)
+			listenerCount++
+		}
+		return true
+	})
+	assert.Equal(t, listenerCount, 0)
+	assert.Equal(t, listener.count, 0)
+}
+
+type apolloDataListener struct {
+	wg    sync.WaitGroup
+	count int
+	event string
+}
+
+func (l *apolloDataListener) Process(configType *config_center.ConfigChangeEvent) {
+	if configType.ConfigType != remoting.EventTypeUpdate {
+		return
+	}
+	l.wg.Done()
+	l.count++
+	l.event = configType.Key
+}
diff --git a/config_center/apollo/listener.go b/config_center/apollo/listener.go
new file mode 100644
index 0000000000000000000000000000000000000000..d81e1cbf34e405f7d2974e29558414029308b36b
--- /dev/null
+++ b/config_center/apollo/listener.go
@@ -0,0 +1,59 @@
+/*
+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 apollo
+
+import (
+	"github.com/zouyx/agollo"
+)
+
+import (
+	"github.com/apache/dubbo-go/config_center"
+)
+
+type apolloListener struct {
+	listeners map[config_center.ConfigurationListener]struct{}
+}
+
+func (a *apolloListener) OnChange(changeEvent *agollo.ChangeEvent) {
+	for key, change := range changeEvent.Changes {
+		for listener := range a.listeners {
+			listener.Process(&config_center.ConfigChangeEvent{
+				ConfigType: getChangeType(change.ChangeType),
+				Key:        key,
+				Value:      change.NewValue,
+			})
+		}
+	}
+}
+
+func NewApolloListener() *apolloListener {
+	return &apolloListener{
+		listeners: make(map[config_center.ConfigurationListener]struct{}, 0),
+	}
+}
+
+func (al *apolloListener) AddListener(l config_center.ConfigurationListener) {
+	if _, ok := al.listeners[l]; !ok {
+		al.listeners[l] = struct{}{}
+		agollo.AddChangeListener(al)
+	}
+}
+
+func (al *apolloListener) RemoveListener(l config_center.ConfigurationListener) {
+	delete(al.listeners, l)
+}
diff --git a/config_center/dynamic_configuration.go b/config_center/dynamic_configuration.go
index 1028b26d963cfcb02636113abc3e482bb22192a0..0546d39732deaa83ace948275a0d4448b1b24cf8 100644
--- a/config_center/dynamic_configuration.go
+++ b/config_center/dynamic_configuration.go
@@ -36,8 +36,14 @@ type DynamicConfiguration interface {
 	SetParser(parser.ConfigurationParser)
 	AddListener(string, ConfigurationListener, ...Option)
 	RemoveListener(string, ConfigurationListener, ...Option)
-	GetConfig(string, ...Option) (string, error)
-	GetConfigs(string, ...Option) (string, error)
+	//GetProperties get properties file
+	GetProperties(string, ...Option) (string, error)
+
+	//GetRule get Router rule properties file
+	GetRule(string, ...Option) (string, error)
+
+	//GetInternalProperty get value by key in Default properties file(dubbo.properties)
+	GetInternalProperty(string, ...Option) (string, error)
 }
 
 type Options struct {
diff --git a/config_center/mock_dynamic_config.go b/config_center/mock_dynamic_config.go
index 47b509231d225491e6791e295a707756256f61d5..79c7c171945400a52563e0b66ef29c2896db0b99 100644
--- a/config_center/mock_dynamic_config.go
+++ b/config_center/mock_dynamic_config.go
@@ -108,6 +108,18 @@ func (c *MockDynamicConfiguration) Parser() parser.ConfigurationParser {
 func (c *MockDynamicConfiguration) SetParser(p parser.ConfigurationParser) {
 	c.parser = p
 }
+func (c *MockDynamicConfiguration) GetProperties(key string, opts ...Option) (string, error) {
+	return c.content, nil
+}
+
+//For zookeeper, getConfig and getConfigs have the same meaning.
+func (c *MockDynamicConfiguration) GetInternalProperty(key string, opts ...Option) (string, error) {
+	return c.GetProperties(key, opts...)
+}
+
+func (c *MockDynamicConfiguration) GetRule(key string, opts ...Option) (string, error) {
+	return c.GetProperties(key, opts...)
+}
 
 func (c *MockDynamicConfiguration) MockServiceConfigEvent() {
 	config := &parser.ConfiguratorConfig{
diff --git a/config_center/parser/configuration_parser.go b/config_center/parser/configuration_parser.go
index 1ce6594017ddc3cf76ba01c985b01a97e5ec91f3..85033ce97f3e9038d57b6156e6dc68139363e8c3 100644
--- a/config_center/parser/configuration_parser.go
+++ b/config_center/parser/configuration_parser.go
@@ -134,14 +134,14 @@ func serviceItemToUrls(item ConfigItem, config ConfiguratorConfig) ([]*common.UR
 				newUrlStr = newUrlStr + v
 				url, err := common.NewURL(context.Background(), newUrlStr)
 				if err != nil {
-					perrors.WithStack(err)
+					return nil, perrors.WithStack(err)
 				}
 				urls = append(urls, &url)
 			}
 		} else {
 			url, err := common.NewURL(context.Background(), urlStr)
 			if err != nil {
-				perrors.WithStack(err)
+				return nil, perrors.WithStack(err)
 			}
 			urls = append(urls, &url)
 		}
diff --git a/config_center/zookeeper/factory.go b/config_center/zookeeper/factory.go
index 611f4b9785c38eac4181750eefcabfb39607135d..3f4690d4e0edb4a859d76bf0fd692ca54e1a7a6a 100644
--- a/config_center/zookeeper/factory.go
+++ b/config_center/zookeeper/factory.go
@@ -17,10 +17,6 @@
 
 package zookeeper
 
-import (
-	"sync"
-)
-
 import (
 	"github.com/apache/dubbo-go/common"
 	"github.com/apache/dubbo-go/common/extension"
@@ -35,14 +31,8 @@ func init() {
 type zookeeperDynamicConfigurationFactory struct {
 }
 
-var once sync.Once
-var dynamicConfiguration *zookeeperDynamicConfiguration
-
 func (f *zookeeperDynamicConfigurationFactory) GetDynamicConfiguration(url *common.URL) (config_center.DynamicConfiguration, error) {
-	var err error
-	once.Do(func() {
-		dynamicConfiguration, err = newZookeeperDynamicConfiguration(url)
-	})
+	dynamicConfiguration, err := newZookeeperDynamicConfiguration(url)
 	if err != nil {
 		return nil, err
 	}
diff --git a/config_center/zookeeper/impl.go b/config_center/zookeeper/impl.go
index 84e4b54e237fabb5775bfd0dfeb7043f1794a7ae..504d4910581aff52afa74b13fdfce61c9170ca48 100644
--- a/config_center/zookeeper/impl.go
+++ b/config_center/zookeeper/impl.go
@@ -109,7 +109,7 @@ func (c *zookeeperDynamicConfiguration) RemoveListener(key string, listener conf
 	c.cacheListener.RemoveListener(key, listener)
 }
 
-func (c *zookeeperDynamicConfiguration) GetConfig(key string, opts ...config_center.Option) (string, error) {
+func (c *zookeeperDynamicConfiguration) GetProperties(key string, opts ...config_center.Option) (string, error) {
 
 	tmpOpts := &config_center.Options{}
 	for _, opt := range opts {
@@ -141,8 +141,12 @@ func (c *zookeeperDynamicConfiguration) GetConfig(key string, opts ...config_cen
 }
 
 //For zookeeper, getConfig and getConfigs have the same meaning.
-func (c *zookeeperDynamicConfiguration) GetConfigs(key string, opts ...config_center.Option) (string, error) {
-	return c.GetConfig(key, opts...)
+func (c *zookeeperDynamicConfiguration) GetInternalProperty(key string, opts ...config_center.Option) (string, error) {
+	return c.GetProperties(key, opts...)
+}
+
+func (c *zookeeperDynamicConfiguration) GetRule(key string, opts ...config_center.Option) (string, error) {
+	return c.GetProperties(key, opts...)
 }
 
 func (c *zookeeperDynamicConfiguration) Parser() parser.ConfigurationParser {
diff --git a/config_center/zookeeper/impl_test.go b/config_center/zookeeper/impl_test.go
index 2f620457f75b7e35f713423e3841d0272cbd0730..e614009faa5b32873c6245dea5c85cc2747e19ea 100644
--- a/config_center/zookeeper/impl_test.go
+++ b/config_center/zookeeper/impl_test.go
@@ -81,7 +81,7 @@ func initZkData(group string, t *testing.T) (*zk.TestCluster, *zookeeperDynamicC
 func Test_GetConfig(t *testing.T) {
 	ts, reg := initZkData("dubbo", t)
 	defer ts.Stop()
-	configs, err := reg.GetConfig("dubbo.properties", config_center.WithGroup("dubbo"))
+	configs, err := reg.GetProperties("dubbo.properties", config_center.WithGroup("dubbo"))
 	assert.NoError(t, err)
 	m, err := reg.Parser().Parse(configs)
 	assert.NoError(t, err)
diff --git a/dubbogo.png b/dubbogo.png
deleted file mode 100644
index 2cac434091276df102c3ae405c09621b8d8926ef..0000000000000000000000000000000000000000
Binary files a/dubbogo.png and /dev/null differ
diff --git a/filter/common/impl/rejected_execution_handler_mock.go b/filter/common/impl/rejected_execution_handler_mock.go
new file mode 100644
index 0000000000000000000000000000000000000000..dace1894668d3a4a154a87bfbdbcc860a97a11ec
--- /dev/null
+++ b/filter/common/impl/rejected_execution_handler_mock.go
@@ -0,0 +1,71 @@
+//  Licensed to the Apache Software Foundation (ASF) under one or more
+//  contributor license agreements.  See the NOTICE file distributed with
+//  this work for additional information regarding copyright ownership.
+//  The ASF licenses this file to You under the Apache License, Version 2.0
+//  (the "License"); you may not use this file except in compliance with
+//  the License.  You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//  See the License for the specific language governing permissions and
+//  limitations under the License.
+//
+
+// Code generated by MockGen. DO NOT EDIT.
+// Source: rejected_execution_handler.go
+
+// Package filter is a generated GoMock package.
+package impl
+
+import (
+	reflect "reflect"
+)
+
+import (
+	gomock "github.com/golang/mock/gomock"
+)
+
+import (
+	common "github.com/apache/dubbo-go/common"
+	protocol "github.com/apache/dubbo-go/protocol"
+)
+
+// MockRejectedExecutionHandler is a mock of RejectedExecutionHandler interface
+type MockRejectedExecutionHandler struct {
+	ctrl     *gomock.Controller
+	recorder *MockRejectedExecutionHandlerMockRecorder
+}
+
+// MockRejectedExecutionHandlerMockRecorder is the mock recorder for MockRejectedExecutionHandler
+type MockRejectedExecutionHandlerMockRecorder struct {
+	mock *MockRejectedExecutionHandler
+}
+
+// NewMockRejectedExecutionHandler creates a new mock instance
+func NewMockRejectedExecutionHandler(ctrl *gomock.Controller) *MockRejectedExecutionHandler {
+	mock := &MockRejectedExecutionHandler{ctrl: ctrl}
+	mock.recorder = &MockRejectedExecutionHandlerMockRecorder{mock}
+	return mock
+}
+
+// EXPECT returns an object that allows the caller to indicate expected use
+func (m *MockRejectedExecutionHandler) EXPECT() *MockRejectedExecutionHandlerMockRecorder {
+	return m.recorder
+}
+
+// RejectedExecution mocks base method
+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)
+	return ret0
+}
+
+// RejectedExecution indicates an expected call of RejectedExecution
+func (mr *MockRejectedExecutionHandlerMockRecorder) RejectedExecution(url, invocation interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RejectedExecution", reflect.TypeOf((*MockRejectedExecutionHandler)(nil).RejectedExecution), url, invocation)
+}
diff --git a/filter/common/impl/rejected_execution_handler_only_log.go b/filter/common/impl/rejected_execution_handler_only_log.go
new file mode 100644
index 0000000000000000000000000000000000000000..8943433af1ba908fc834740163df78e3b2b6443a
--- /dev/null
+++ b/filter/common/impl/rejected_execution_handler_only_log.go
@@ -0,0 +1,69 @@
+/*
+ * 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 impl
+
+import (
+	"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"
+	filterCommon "github.com/apache/dubbo-go/filter/common"
+	"github.com/apache/dubbo-go/protocol"
+)
+
+const HandlerName = "log"
+
+func init() {
+	extension.SetRejectedExecutionHandler(HandlerName, GetOnlyLogRejectedExecutionHandler)
+	extension.SetRejectedExecutionHandler(constant.DEFAULT_KEY, GetOnlyLogRejectedExecutionHandler)
+}
+
+var onlyLogHandlerInstance *OnlyLogRejectedExecutionHandler
+var onlyLogHandlerOnce sync.Once
+
+/**
+ * This implementation only logs the invocation info.
+ * it always return en error inside the result.
+ * "UserProvider":
+ *   registry: "hangzhouzk"
+ *   protocol : "dubbo"
+ *   interface : "com.ikurento.user.UserProvider"
+ *   ... # other configuration
+ *   tps.limiter: "method-service" # the name of limiter
+ *   tps.limit.rejected.handler: "default" or "log"
+ *   methods:
+ *    - name: "GetUser"
+ */
+type OnlyLogRejectedExecutionHandler struct {
+}
+
+func (handler *OnlyLogRejectedExecutionHandler) RejectedExecution(url common.URL, invocation protocol.Invocation) protocol.Result {
+	logger.Errorf("The invocation was rejected. url: %s", url.String())
+	return &protocol.RPCResult{}
+}
+
+func GetOnlyLogRejectedExecutionHandler() filterCommon.RejectedExecutionHandler {
+	onlyLogHandlerOnce.Do(func() {
+		onlyLogHandlerInstance = &OnlyLogRejectedExecutionHandler{}
+	})
+	return onlyLogHandlerInstance
+}
diff --git a/filter/common/impl/rejected_execution_handler_only_log_test.go b/filter/common/impl/rejected_execution_handler_only_log_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..da54d8a106338dd4f21f9b01e66b031e3c311e01
--- /dev/null
+++ b/filter/common/impl/rejected_execution_handler_only_log_test.go
@@ -0,0 +1,35 @@
+/*
+ * 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 impl
+
+import (
+	"net/url"
+	"testing"
+)
+import (
+	"github.com/apache/dubbo-go/common"
+	"github.com/apache/dubbo-go/common/constant"
+)
+
+func TestOnlyLogRejectedExecutionHandler_RejectedExecution(t *testing.T) {
+	handler := GetOnlyLogRejectedExecutionHandler()
+	invokeUrl := common.NewURLWithOptions(
+		common.WithParams(url.Values{}),
+		common.WithParamsValue(constant.INTERFACE_KEY, "methodName"))
+	handler.RejectedExecution(*invokeUrl, nil)
+}
diff --git a/filter/common/rejected_execution_handler.go b/filter/common/rejected_execution_handler.go
new file mode 100644
index 0000000000000000000000000000000000000000..b993b8444c14c13ce9a8861c113dc02ca5fd335a
--- /dev/null
+++ b/filter/common/rejected_execution_handler.go
@@ -0,0 +1,33 @@
+/*
+ * 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 common
+
+import (
+	"github.com/apache/dubbo-go/common"
+	"github.com/apache/dubbo-go/protocol"
+)
+
+/**
+ * If the invocation cannot pass any validation in filter, like ExecuteLimitFilter and TpsLimitFilter,
+ * the implementation will be used.
+ * The common case is that sometimes you want to return the default value when the request was rejected.
+ * Or you want to be warned if any request was rejected.
+ * In such situation, implement this interface and register it by invoking extension.SetRejectedExecutionHandler.
+ */
+type RejectedExecutionHandler interface {
+	RejectedExecution(url common.URL, invocation protocol.Invocation) protocol.Result
+}
diff --git a/filter/impl/access_log_filter.go b/filter/impl/access_log_filter.go
index 75c0582937c69b1c3368cd38fd015cd5b0d68315..89fa34952f99057f1d8bb35794a57f9905f5f169 100644
--- a/filter/impl/access_log_filter.go
+++ b/filter/impl/access_log_filter.go
@@ -132,7 +132,7 @@ func (ef *AccessLogFilter) writeLogToFile(data AccessLogData) {
 
 	logFile, err := ef.openLogFile(accessLog)
 	if err != nil {
-		logger.Warnf("Can not open 	the access log file: %s, %v", accessLog, err)
+		logger.Warnf("Can not open the access log file: %s, %v", accessLog, err)
 		return
 	}
 	logger.Debugf("Append log to %s", accessLog)
diff --git a/filter/impl/execute_limit_filter.go b/filter/impl/execute_limit_filter.go
new file mode 100644
index 0000000000000000000000000000000000000000..156af1b140283dd76c4867ca26e9b42ce8eb25c0
--- /dev/null
+++ b/filter/impl/execute_limit_filter.go
@@ -0,0 +1,141 @@
+/*
+ * 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 impl
+
+import (
+	"strconv"
+	"sync"
+	"sync/atomic"
+)
+
+import (
+	"github.com/modern-go/concurrent"
+)
+
+import (
+	"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/filter"
+	_ "github.com/apache/dubbo-go/filter/common/impl"
+	"github.com/apache/dubbo-go/protocol"
+)
+
+const name = "execute"
+
+func init() {
+	extension.SetFilter(name, GetExecuteLimitFilter)
+}
+
+/**
+ * The filter will limit the number of in-progress request and it's thread-safe.
+ * example:
+ * "UserProvider":
+ *   registry: "hangzhouzk"
+ *   protocol : "dubbo"
+ *   interface : "com.ikurento.user.UserProvider"
+ *   ... # other configuration
+ *   execute.limit: 200 # the name of MethodServiceTpsLimiterImpl. if the value < 0, invocation will be ignored.
+ *   execute.limit.rejected.handle: "default" # the name of rejected handler
+ *   methods:
+ *    - name: "GetUser"
+ *      execute.limit: 20, # in this case, this configuration in service-level will be ignored.
+ *    - name: "UpdateUser"
+ *      execute.limit: -1, # If the rate<0, the method will be ignored
+ *    - name: "DeleteUser"
+ *      execute.limit.rejected.handle: "customHandler" # Using the custom handler to do something when the request was rejected.
+ *    - name: "AddUser"
+ * From the example, the configuration in service-level is 200, and the configuration of method GetUser is 20.
+ * it means that, the GetUser will be counted separately.
+ * The configuration of method UpdateUser is -1, so the invocation for it will not be counted.
+ * So the method DeleteUser and method AddUser will be limited by service-level configuration.
+ * Sometimes we want to do something, like log the request or return default value when the request is over limitation.
+ * Then you can implement the RejectedExecutionHandler interface and register it by invoking SetRejectedExecutionHandler.
+ */
+type ExecuteLimitFilter struct {
+	executeState *concurrent.Map
+}
+
+type ExecuteState struct {
+	concurrentCount int64
+}
+
+func (ef *ExecuteLimitFilter) Invoke(invoker protocol.Invoker, invocation protocol.Invocation) protocol.Result {
+	methodConfigPrefix := "methods." + invocation.MethodName() + "."
+	url := invoker.GetUrl()
+	limitTarget := url.ServiceKey()
+	limitRateConfig := constant.DEFAULT_EXECUTE_LIMIT
+
+	methodLevelConfig := url.GetParam(methodConfigPrefix+constant.EXECUTE_LIMIT_KEY, "")
+	if len(methodLevelConfig) > 0 {
+		// we have the method-level configuration
+		limitTarget = limitTarget + "#" + invocation.MethodName()
+		limitRateConfig = methodLevelConfig
+	} else {
+		limitRateConfig = url.GetParam(constant.EXECUTE_LIMIT_KEY, constant.DEFAULT_EXECUTE_LIMIT)
+	}
+
+	limitRate, err := strconv.ParseInt(limitRateConfig, 0, 0)
+	if err != nil {
+		logger.Errorf("The configuration of execute.limit is invalid: %s", limitRateConfig)
+		return &protocol.RPCResult{}
+	}
+
+	if limitRate < 0 {
+		return invoker.Invoke(invocation)
+	}
+
+	state, _ := ef.executeState.LoadOrStore(limitTarget, &ExecuteState{
+		concurrentCount: 0,
+	})
+
+	concurrentCount := state.(*ExecuteState).increase()
+	defer state.(*ExecuteState).decrease()
+	if concurrentCount > limitRate {
+		logger.Errorf("The invocation was rejected due to over the execute limitation, url: %s ", url.String())
+		rejectedHandlerConfig := url.GetParam(methodConfigPrefix+constant.EXECUTE_REJECTED_EXECUTION_HANDLER_KEY,
+			url.GetParam(constant.EXECUTE_REJECTED_EXECUTION_HANDLER_KEY, constant.DEFAULT_KEY))
+		return extension.GetRejectedExecutionHandler(rejectedHandlerConfig).RejectedExecution(url, invocation)
+	}
+
+	return invoker.Invoke(invocation)
+}
+
+func (ef *ExecuteLimitFilter) OnResponse(result protocol.Result, invoker protocol.Invoker, invocation protocol.Invocation) protocol.Result {
+	return result
+}
+
+func (state *ExecuteState) increase() int64 {
+	return atomic.AddInt64(&state.concurrentCount, 1)
+}
+
+func (state *ExecuteState) decrease() {
+	atomic.AddInt64(&state.concurrentCount, -1)
+}
+
+var executeLimitOnce sync.Once
+var executeLimitFilter *ExecuteLimitFilter
+
+func GetExecuteLimitFilter() filter.Filter {
+	executeLimitOnce.Do(func() {
+		executeLimitFilter = &ExecuteLimitFilter{
+			executeState: concurrent.NewMap(),
+		}
+	})
+	return executeLimitFilter
+}
diff --git a/filter/impl/execute_limit_filter_test.go b/filter/impl/execute_limit_filter_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..5d729c0e6a1205902856eccfa6aa96b0bee0e790
--- /dev/null
+++ b/filter/impl/execute_limit_filter_test.go
@@ -0,0 +1,83 @@
+/*
+ * 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 impl
+
+import (
+	"net/url"
+	"testing"
+)
+
+import (
+	"github.com/stretchr/testify/assert"
+)
+
+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"
+)
+
+func TestExecuteLimitFilter_Invoke_Ignored(t *testing.T) {
+	methodName := "hello"
+	invoc := invocation.NewRPCInvocation(methodName, []interface{}{"OK"}, make(map[string]string, 0))
+
+	invokeUrl := common.NewURLWithOptions(
+		common.WithParams(url.Values{}),
+		common.WithParamsValue(constant.INTERFACE_KEY, methodName))
+
+	limitFilter := GetExecuteLimitFilter()
+
+	result := limitFilter.Invoke(protocol.NewBaseInvoker(*invokeUrl), invoc)
+	assert.NotNil(t, result)
+	assert.Nil(t, result.Error())
+}
+
+func TestExecuteLimitFilter_Invoke_Configure_Error(t *testing.T) {
+	methodName := "hello1"
+	invoc := invocation.NewRPCInvocation(methodName, []interface{}{"OK"}, make(map[string]string, 0))
+
+	invokeUrl := common.NewURLWithOptions(
+		common.WithParams(url.Values{}),
+		common.WithParamsValue(constant.INTERFACE_KEY, methodName),
+		common.WithParamsValue(constant.EXECUTE_LIMIT_KEY, "13a"),
+	)
+
+	limitFilter := GetExecuteLimitFilter()
+
+	result := limitFilter.Invoke(protocol.NewBaseInvoker(*invokeUrl), invoc)
+	assert.NotNil(t, result)
+	assert.Nil(t, result.Error())
+}
+
+func TestExecuteLimitFilter_Invoke(t *testing.T) {
+	methodName := "hello1"
+	invoc := invocation.NewRPCInvocation(methodName, []interface{}{"OK"}, make(map[string]string, 0))
+
+	invokeUrl := common.NewURLWithOptions(
+		common.WithParams(url.Values{}),
+		common.WithParamsValue(constant.INTERFACE_KEY, methodName),
+		common.WithParamsValue(constant.EXECUTE_LIMIT_KEY, "20"),
+	)
+
+	limitFilter := GetExecuteLimitFilter()
+
+	result := limitFilter.Invoke(protocol.NewBaseInvoker(*invokeUrl), invoc)
+	assert.NotNil(t, result)
+	assert.Nil(t, result.Error())
+}
diff --git a/filter/impl/generic_filter.go b/filter/impl/generic_filter.go
index 35aadb11a444bda56109e238b17267f71ec2606b..067939a34b889198a25b08af23892ad4037e642e 100644
--- a/filter/impl/generic_filter.go
+++ b/filter/impl/generic_filter.go
@@ -47,22 +47,21 @@ type GenericFilter struct{}
 func (ef *GenericFilter) Invoke(invoker protocol.Invoker, invocation protocol.Invocation) protocol.Result {
 	if invocation.MethodName() == constant.GENERIC && len(invocation.Arguments()) == 3 {
 		oldArguments := invocation.Arguments()
-		var newParams []hessian.Object
+
 		if oldParams, ok := oldArguments[2].([]interface{}); ok {
+			newParams := make([]hessian.Object, 0, len(oldParams))
 			for i := range oldParams {
 				newParams = append(newParams, hessian.Object(struct2MapAll(oldParams[i])))
 			}
-		} else {
-			return invoker.Invoke(invocation)
-		}
-		newArguments := []interface{}{
-			oldArguments[0],
-			oldArguments[1],
-			newParams,
+			newArguments := []interface{}{
+				oldArguments[0],
+				oldArguments[1],
+				newParams,
+			}
+			newInvocation := invocation2.NewRPCInvocation(invocation.MethodName(), newArguments, invocation.Attachments())
+			newInvocation.SetReply(invocation.Reply())
+			return invoker.Invoke(newInvocation)
 		}
-		newInvocation := invocation2.NewRPCInvocation(invocation.MethodName(), newArguments, invocation.Attachments())
-		newInvocation.SetReply(invocation.Reply())
-		return invoker.Invoke(newInvocation)
 	}
 	return invoker.Invoke(invocation)
 }
diff --git a/filter/impl/graceful_shutdown_filter.go b/filter/impl/graceful_shutdown_filter.go
new file mode 100644
index 0000000000000000000000000000000000000000..b912ea88e4ba4741b7d7fe36b8bbd3ba158abe63
--- /dev/null
+++ b/filter/impl/graceful_shutdown_filter.go
@@ -0,0 +1,87 @@
+/*
+ * 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 impl
+
+import (
+	"sync/atomic"
+)
+
+import (
+	"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/config"
+	"github.com/apache/dubbo-go/filter"
+	"github.com/apache/dubbo-go/filter/common"
+	"github.com/apache/dubbo-go/protocol"
+)
+
+func init() {
+	var consumerFiler = &gracefulShutdownFilter{
+		shutdownConfig: config.GetConsumerConfig().ShutdownConfig,
+	}
+	var providerFilter = &gracefulShutdownFilter{
+		shutdownConfig: config.GetProviderConfig().ShutdownConfig,
+	}
+
+	extension.SetFilter(constant.CONSUMER_SHUTDOWN_FILTER, func() filter.Filter {
+		return consumerFiler
+	})
+
+	extension.SetFilter(constant.PROVIDER_SHUTDOWN_FILTER, func() filter.Filter {
+		return providerFilter
+	})
+}
+
+type gracefulShutdownFilter struct {
+	activeCount    int32
+	shutdownConfig *config.ShutdownConfig
+}
+
+func (gf *gracefulShutdownFilter) Invoke(invoker protocol.Invoker, invocation protocol.Invocation) protocol.Result {
+	if gf.rejectNewRequest() {
+		logger.Info("The application is closing, new request will be rejected.")
+		return gf.getRejectHandler().RejectedExecution(invoker.GetUrl(), invocation)
+	}
+	atomic.AddInt32(&gf.activeCount, 1)
+	return invoker.Invoke(invocation)
+}
+
+func (gf *gracefulShutdownFilter) OnResponse(result protocol.Result, invoker protocol.Invoker, invocation protocol.Invocation) protocol.Result {
+	atomic.AddInt32(&gf.activeCount, -1)
+	// although this isn't thread safe, it won't be a problem if the gf.rejectNewRequest() is true.
+	if gf.shutdownConfig != nil && gf.activeCount <= 0 {
+		gf.shutdownConfig.RequestsFinished = true
+	}
+	return result
+}
+
+func (gf *gracefulShutdownFilter) rejectNewRequest() bool {
+	if gf.shutdownConfig == nil {
+		return false
+	}
+	return gf.shutdownConfig.RejectRequest
+}
+
+func (gf *gracefulShutdownFilter) getRejectHandler() common.RejectedExecutionHandler {
+	handler := constant.DEFAULT_KEY
+	if gf.shutdownConfig != nil && len(gf.shutdownConfig.RejectRequestHandler) > 0 {
+		handler = gf.shutdownConfig.RejectRequestHandler
+	}
+	return extension.GetRejectedExecutionHandler(handler)
+}
diff --git a/filter/impl/graceful_shutdown_filter_test.go b/filter/impl/graceful_shutdown_filter_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..21da167ea0f201ea357c51cab0ecb4f8ebec0957
--- /dev/null
+++ b/filter/impl/graceful_shutdown_filter_test.go
@@ -0,0 +1,76 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package impl
+
+import (
+	"net/url"
+	"testing"
+)
+
+import (
+	"github.com/stretchr/testify/assert"
+)
+
+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/config"
+	filterCommon "github.com/apache/dubbo-go/filter/common"
+	"github.com/apache/dubbo-go/filter/common/impl"
+	"github.com/apache/dubbo-go/protocol"
+	"github.com/apache/dubbo-go/protocol/invocation"
+)
+
+func TestGenericFilter_Invoke(t *testing.T) {
+	invoc := invocation.NewRPCInvocation("GetUser", []interface{}{"OK"}, make(map[string]string, 0))
+
+	invokeUrl := common.NewURLWithOptions(
+		common.WithParams(url.Values{}))
+
+	shutdownFilter := extension.GetFilter(constant.PROVIDER_SHUTDOWN_FILTER).(*gracefulShutdownFilter)
+
+	providerConfig := config.GetProviderConfig()
+
+	assert.False(t, shutdownFilter.rejectNewRequest())
+	assert.Nil(t, providerConfig.ShutdownConfig)
+
+	assert.Equal(t, extension.GetRejectedExecutionHandler(constant.DEFAULT_KEY),
+		shutdownFilter.getRejectHandler())
+
+	result := shutdownFilter.Invoke(protocol.NewBaseInvoker(*invokeUrl), invoc)
+	assert.NotNil(t, result)
+	assert.Nil(t, result.Error())
+
+	providerConfig.ShutdownConfig = &config.ShutdownConfig{
+		RejectRequest:        true,
+		RejectRequestHandler: "mock",
+	}
+	shutdownFilter.shutdownConfig = providerConfig.ShutdownConfig
+
+	assert.True(t, shutdownFilter.rejectNewRequest())
+	result = shutdownFilter.OnResponse(nil, protocol.NewBaseInvoker(*invokeUrl), invoc)
+
+	rejectHandler := &impl.OnlyLogRejectedExecutionHandler{}
+	extension.SetRejectedExecutionHandler("mock", func() filterCommon.RejectedExecutionHandler {
+		return rejectHandler
+	})
+	assert.True(t, providerConfig.ShutdownConfig.RequestsFinished)
+	assert.Equal(t, rejectHandler, shutdownFilter.getRejectHandler())
+
+}
diff --git a/filter/impl/tps/impl/tps_limit_fix_window_strategy.go b/filter/impl/tps/impl/tps_limit_fix_window_strategy.go
new file mode 100644
index 0000000000000000000000000000000000000000..285ecfa658cf838cc1140ba716bd72e1976b86fe
--- /dev/null
+++ b/filter/impl/tps/impl/tps_limit_fix_window_strategy.go
@@ -0,0 +1,89 @@
+/*
+ * 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 impl
+
+import (
+	"sync/atomic"
+	"time"
+)
+
+import (
+	"github.com/apache/dubbo-go/common/constant"
+	"github.com/apache/dubbo-go/common/extension"
+	"github.com/apache/dubbo-go/filter/impl/tps"
+)
+
+const (
+	FixedWindowKey = "fixedWindow"
+)
+
+func init() {
+	creator := &fixedWindowStrategyCreator{}
+	extension.SetTpsLimitStrategy(FixedWindowKey, creator)
+	extension.SetTpsLimitStrategy(constant.DEFAULT_KEY, creator)
+}
+
+/**
+ * It's the same as default implementation in Java
+ * It's not a thread-safe implementation.
+ * It you want to use the thread-safe implementation, please use ThreadSafeFixedWindowTpsLimitStrategyImpl
+ * This is the default implementation.
+ *
+ * "UserProvider":
+ *   registry: "hangzhouzk"
+ *   protocol : "dubbo"
+ *   interface : "com.ikurento.user.UserProvider"
+ *   ... # other configuration
+ *   tps.limiter: "method-service" # the name of limiter
+ *   tps.limit.strategy: "default" or "fixedWindow" # service-level
+ *   methods:
+ *    - name: "GetUser"
+ *      tps.interval: 3000
+ *      tps.limit.strategy: "default" or "fixedWindow" # method-level
+ */
+type FixedWindowTpsLimitStrategyImpl struct {
+	rate      int32
+	interval  int64
+	count     int32
+	timestamp int64
+}
+
+func (impl *FixedWindowTpsLimitStrategyImpl) IsAllowable() bool {
+
+	current := time.Now().UnixNano()
+	if impl.timestamp+impl.interval < current {
+		// it's a new window
+		// if a lot of threads come here, the count will be set to 0 several times.
+		// so the return statement will be wrong.
+		impl.timestamp = current
+		impl.count = 0
+	}
+	// this operation is thread-safe, but count + 1 may be overflow
+	return atomic.AddInt32(&impl.count, 1) <= impl.rate
+}
+
+type fixedWindowStrategyCreator struct{}
+
+func (creator *fixedWindowStrategyCreator) Create(rate int, interval int) tps.TpsLimitStrategy {
+	return &FixedWindowTpsLimitStrategyImpl{
+		rate:      int32(rate),
+		interval:  int64(interval) * int64(time.Millisecond), // convert to ns
+		count:     0,
+		timestamp: time.Now().UnixNano(),
+	}
+}
diff --git a/filter/impl/tps/impl/tps_limit_fix_window_strategy_test.go b/filter/impl/tps/impl/tps_limit_fix_window_strategy_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..7ef539ed3b2b93da5c56a05f606e75282226d1ef
--- /dev/null
+++ b/filter/impl/tps/impl/tps_limit_fix_window_strategy_test.go
@@ -0,0 +1,44 @@
+/*
+ * 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 impl
+
+import (
+	"testing"
+	"time"
+)
+
+import (
+	"github.com/stretchr/testify/assert"
+)
+
+func TestFixedWindowTpsLimitStrategyImpl_IsAllowable(t *testing.T) {
+	creator := &fixedWindowStrategyCreator{}
+	strategy := creator.Create(2, 60000)
+	assert.True(t, strategy.IsAllowable())
+	assert.True(t, strategy.IsAllowable())
+	assert.False(t, strategy.IsAllowable())
+
+	strategy = creator.Create(2, 2000)
+	assert.True(t, strategy.IsAllowable())
+	assert.True(t, strategy.IsAllowable())
+	assert.False(t, strategy.IsAllowable())
+	time.Sleep(2100 * time.Millisecond)
+	assert.True(t, strategy.IsAllowable())
+	assert.True(t, strategy.IsAllowable())
+	assert.False(t, strategy.IsAllowable())
+}
diff --git a/filter/impl/tps/impl/tps_limit_sliding_window_strategy.go b/filter/impl/tps/impl/tps_limit_sliding_window_strategy.go
new file mode 100644
index 0000000000000000000000000000000000000000..d1a5db6e259ffa63282065f881f6cc8360c8d25b
--- /dev/null
+++ b/filter/impl/tps/impl/tps_limit_sliding_window_strategy.go
@@ -0,0 +1,92 @@
+/*
+ * 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 impl
+
+import (
+	"container/list"
+	"sync"
+	"time"
+)
+
+import (
+	"github.com/apache/dubbo-go/common/extension"
+	"github.com/apache/dubbo-go/filter/impl/tps"
+)
+
+func init() {
+	extension.SetTpsLimitStrategy("slidingWindow", &slidingWindowStrategyCreator{})
+}
+
+/**
+ * it's thread-safe.
+ * "UserProvider":
+ *   registry: "hangzhouzk"
+ *   protocol : "dubbo"
+ *   interface : "com.ikurento.user.UserProvider"
+ *   ... # other configuration
+ *   tps.limiter: "method-service" # the name of limiter
+ *   tps.limit.strategy: "slidingWindow" # service-level
+ *   methods:
+ *    - name: "GetUser"
+ *      tps.interval: 3000
+ *      tps.limit.strategy: "slidingWindow" # method-level
+ */
+type SlidingWindowTpsLimitStrategyImpl struct {
+	rate     int
+	interval int64
+	mutex    *sync.Mutex
+	queue    *list.List
+}
+
+func (impl *SlidingWindowTpsLimitStrategyImpl) IsAllowable() bool {
+	impl.mutex.Lock()
+	defer impl.mutex.Unlock()
+	// quick path
+	size := impl.queue.Len()
+	current := time.Now().UnixNano()
+	if size < impl.rate {
+		impl.queue.PushBack(current)
+		return true
+	}
+
+	// slow path
+	boundary := current - impl.interval
+
+	timestamp := impl.queue.Front()
+	// remove the element that out of the window
+	for timestamp != nil && timestamp.Value.(int64) < boundary {
+		impl.queue.Remove(timestamp)
+		timestamp = impl.queue.Front()
+	}
+	if impl.queue.Len() < impl.rate {
+		impl.queue.PushBack(current)
+		return true
+	}
+	return false
+}
+
+type slidingWindowStrategyCreator struct{}
+
+func (creator *slidingWindowStrategyCreator) Create(rate int, interval int) tps.TpsLimitStrategy {
+	return &SlidingWindowTpsLimitStrategyImpl{
+		rate:     rate,
+		interval: int64(interval) * int64(time.Millisecond),
+		mutex:    &sync.Mutex{},
+		queue:    list.New(),
+	}
+}
diff --git a/filter/impl/tps/impl/tps_limit_sliding_window_strategy_test.go b/filter/impl/tps/impl/tps_limit_sliding_window_strategy_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..075f1d9d2be2d18edfee7dc8691b71da65f5da45
--- /dev/null
+++ b/filter/impl/tps/impl/tps_limit_sliding_window_strategy_test.go
@@ -0,0 +1,46 @@
+/*
+ * 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 impl
+
+import (
+	"testing"
+	"time"
+)
+
+import (
+	"github.com/stretchr/testify/assert"
+)
+
+func TestSlidingWindowTpsLimitStrategyImpl_IsAllowable(t *testing.T) {
+	creator := &slidingWindowStrategyCreator{}
+	strategy := creator.Create(2, 60000)
+	assert.True(t, strategy.IsAllowable())
+	assert.True(t, strategy.IsAllowable())
+	assert.False(t, strategy.IsAllowable())
+	time.Sleep(2100 * time.Millisecond)
+	assert.False(t, strategy.IsAllowable())
+
+	strategy = creator.Create(2, 2000)
+	assert.True(t, strategy.IsAllowable())
+	assert.True(t, strategy.IsAllowable())
+	assert.False(t, strategy.IsAllowable())
+	time.Sleep(2100 * time.Millisecond)
+	assert.True(t, strategy.IsAllowable())
+	assert.True(t, strategy.IsAllowable())
+	assert.False(t, strategy.IsAllowable())
+}
diff --git a/filter/impl/tps/impl/tps_limit_strategy_mock.go b/filter/impl/tps/impl/tps_limit_strategy_mock.go
new file mode 100644
index 0000000000000000000000000000000000000000..a653fb287a2d89d8c6151889ca14b4b7b4832505
--- /dev/null
+++ b/filter/impl/tps/impl/tps_limit_strategy_mock.go
@@ -0,0 +1,63 @@
+//  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.
+//
+
+// Code generated by MockGen. DO NOT EDIT.
+// Source: tps_limit_strategy.go
+
+// Package filter is a generated GoMock package.
+package impl
+
+import (
+	gomock "github.com/golang/mock/gomock"
+	reflect "reflect"
+)
+
+// MockTpsLimitStrategy is a mock of TpsLimitStrategy interface
+type MockTpsLimitStrategy struct {
+	ctrl     *gomock.Controller
+	recorder *MockTpsLimitStrategyMockRecorder
+}
+
+// MockTpsLimitStrategyMockRecorder is the mock recorder for MockTpsLimitStrategy
+type MockTpsLimitStrategyMockRecorder struct {
+	mock *MockTpsLimitStrategy
+}
+
+// NewMockTpsLimitStrategy creates a new mock instance
+func NewMockTpsLimitStrategy(ctrl *gomock.Controller) *MockTpsLimitStrategy {
+	mock := &MockTpsLimitStrategy{ctrl: ctrl}
+	mock.recorder = &MockTpsLimitStrategyMockRecorder{mock}
+	return mock
+}
+
+// EXPECT returns an object that allows the caller to indicate expected use
+func (m *MockTpsLimitStrategy) EXPECT() *MockTpsLimitStrategyMockRecorder {
+	return m.recorder
+}
+
+// IsAllowable mocks base method
+func (m *MockTpsLimitStrategy) IsAllowable() bool {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "IsAllowable")
+	ret0, _ := ret[0].(bool)
+	return ret0
+}
+
+// IsAllowable indicates an expected call of IsAllowable
+func (mr *MockTpsLimitStrategyMockRecorder) IsAllowable() *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsAllowable", reflect.TypeOf((*MockTpsLimitStrategy)(nil).IsAllowable))
+}
diff --git a/filter/impl/tps/impl/tps_limit_thread_safe_fix_window_strategy.go b/filter/impl/tps/impl/tps_limit_thread_safe_fix_window_strategy.go
new file mode 100644
index 0000000000000000000000000000000000000000..9a1b21a3349845e32cb0fe38b07a7f932ec4f454
--- /dev/null
+++ b/filter/impl/tps/impl/tps_limit_thread_safe_fix_window_strategy.go
@@ -0,0 +1,71 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package impl
+
+import (
+	"sync"
+)
+
+import (
+	"github.com/apache/dubbo-go/common/extension"
+	"github.com/apache/dubbo-go/filter/impl/tps"
+)
+
+func init() {
+	extension.SetTpsLimitStrategy("threadSafeFixedWindow", &threadSafeFixedWindowStrategyCreator{
+		fixedWindowStrategyCreator: &fixedWindowStrategyCreator{},
+	})
+}
+
+/**
+ * it's the thread-safe implementation.
+ * Also, it's a thread-safe decorator of FixedWindowTpsLimitStrategyImpl
+ * "UserProvider":
+ *   registry: "hangzhouzk"
+ *   protocol : "dubbo"
+ *   interface : "com.ikurento.user.UserProvider"
+ *   ... # other configuration
+ *   tps.limiter: "method-service" # the name of limiter
+ *   tps.limit.strategy: "threadSafeFixedWindow" # service-level
+ *   methods:
+ *    - name: "GetUser"
+ *      tps.interval: 3000
+ *      tps.limit.strategy: "threadSafeFixedWindow" # method-level
+ */
+type ThreadSafeFixedWindowTpsLimitStrategyImpl struct {
+	mutex       *sync.Mutex
+	fixedWindow *FixedWindowTpsLimitStrategyImpl
+}
+
+func (impl *ThreadSafeFixedWindowTpsLimitStrategyImpl) IsAllowable() bool {
+	impl.mutex.Lock()
+	defer impl.mutex.Unlock()
+	return impl.fixedWindow.IsAllowable()
+}
+
+type threadSafeFixedWindowStrategyCreator struct {
+	fixedWindowStrategyCreator *fixedWindowStrategyCreator
+}
+
+func (creator *threadSafeFixedWindowStrategyCreator) Create(rate int, interval int) tps.TpsLimitStrategy {
+	fixedWindowStrategy := creator.fixedWindowStrategyCreator.Create(rate, interval).(*FixedWindowTpsLimitStrategyImpl)
+	return &ThreadSafeFixedWindowTpsLimitStrategyImpl{
+		fixedWindow: fixedWindowStrategy,
+		mutex:       &sync.Mutex{},
+	}
+}
diff --git a/filter/impl/tps/impl/tps_limit_thread_safe_fix_window_strategy_test.go b/filter/impl/tps/impl/tps_limit_thread_safe_fix_window_strategy_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..129493962403e0028b09f9646054fda236c99ff7
--- /dev/null
+++ b/filter/impl/tps/impl/tps_limit_thread_safe_fix_window_strategy_test.go
@@ -0,0 +1,44 @@
+/*
+ * 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 impl
+
+import (
+	"testing"
+	"time"
+)
+
+import (
+	"github.com/stretchr/testify/assert"
+)
+
+func TestThreadSafeFixedWindowTpsLimitStrategyImpl_IsAllowable(t *testing.T) {
+	creator := &threadSafeFixedWindowStrategyCreator{}
+	strategy := creator.Create(2, 60000)
+	assert.True(t, strategy.IsAllowable())
+	assert.True(t, strategy.IsAllowable())
+	assert.False(t, strategy.IsAllowable())
+
+	strategy = creator.Create(2, 2000)
+	assert.True(t, strategy.IsAllowable())
+	assert.True(t, strategy.IsAllowable())
+	assert.False(t, strategy.IsAllowable())
+	time.Sleep(2100 * time.Millisecond)
+	assert.True(t, strategy.IsAllowable())
+	assert.True(t, strategy.IsAllowable())
+	assert.False(t, strategy.IsAllowable())
+}
diff --git a/filter/impl/tps/impl/tps_limiter_method_service.go b/filter/impl/tps/impl/tps_limiter_method_service.go
new file mode 100644
index 0000000000000000000000000000000000000000..426ae5994867c5a09653641870ebcef531c0d43c
--- /dev/null
+++ b/filter/impl/tps/impl/tps_limiter_method_service.go
@@ -0,0 +1,188 @@
+/*
+ * 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 impl
+
+import (
+	"fmt"
+	"strconv"
+	"sync"
+)
+
+import (
+	"github.com/modern-go/concurrent"
+)
+
+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/filter/impl/tps"
+	"github.com/apache/dubbo-go/protocol"
+)
+
+const name = "method-service"
+
+func init() {
+	extension.SetTpsLimiter(constant.DEFAULT_KEY, GetMethodServiceTpsLimiter)
+	extension.SetTpsLimiter(name, GetMethodServiceTpsLimiter)
+}
+
+/**
+ * This implementation allows developer to config both method-level and service-level tps limiter.
+ * for example:
+ * "UserProvider":
+ *   registry: "hangzhouzk"
+ *   protocol : "dubbo"
+ *   interface : "com.ikurento.user.UserProvider"
+ *   ... # other configuration
+ *   tps.limiter: "method-service" or "default" # the name of MethodServiceTpsLimiterImpl. It's the default limiter too.
+ *   tps.limit.interval: 5000 # interval, the time unit is ms
+ *   tps.limit.rate: 300 # the max value in the interval. <0 means that the service will not be limited.
+ *   methods:
+ *    - name: "GetUser"
+ *      tps.interval: 3000
+ *      tps.limit.rate: 20, # in this case, this configuration in service-level will be ignored.
+ *    - name: "UpdateUser"
+ *      tps.limit.rate: -1, # If the rate<0, the method will be ignored
+ *
+ *
+ * More examples:
+ * case1:
+ * "UserProvider":
+ *   registry: "hangzhouzk"
+ *   protocol : "dubbo"
+ *   interface : "com.ikurento.user.UserProvider"
+ *   ... # other configuration
+ *   tps.limiter: "method-service" or "default" # the name of MethodServiceTpsLimiterImpl. It's the default limiter too.
+ *   tps.limit.interval: 5000 # interval, the time unit is ms
+ *   tps.limit.rate: 300 # the max value in the interval. <0 means that the service will not be limited.
+ *   methods:
+ *    - name: "GetUser"
+ *    - name: "UpdateUser"
+ *      tps.limit.rate: -1,
+ * in this case, the method UpdateUser will be ignored,
+ * which means that only GetUser will be limited by service-level configuration.
+ *
+ * case2:
+ * "UserProvider":
+ *   registry: "hangzhouzk"
+ *   protocol : "dubbo"
+ *   interface : "com.ikurento.user.UserProvider"
+ *   ... # other configuration
+ *   tps.limiter: "method-service" or "default" # the name of MethodServiceTpsLimiterImpl. It's the default limiter too.
+ *   tps.limit.interval: 5000 # interval, the time unit is ms
+ *   tps.limit.rate: 300 # the max value in the interval. <0 means that the service will not be limited.
+ *   methods:
+ *    - name: "GetUser"
+ *    - name: "UpdateUser"
+ *      tps.limit.rate: 30,
+ * In this case, the GetUser will be limited by service-level configuration(300 times in 5000ms),
+ * but UpdateUser will be limited by its configuration (30 times in 60000ms)
+ *
+ * case3:
+ * "UserProvider":
+ *   registry: "hangzhouzk"
+ *   protocol : "dubbo"
+ *   interface : "com.ikurento.user.UserProvider"
+ *   ... # other configuration
+ *   tps.limiter: "method-service" or "default" # the name of MethodServiceTpsLimiterImpl. It's the default limiter too.
+ *   methods:
+ *    - name: "GetUser"
+ *    - name: "UpdateUser"
+ *      tps.limit.rate: 70,
+ *      tps.limit.interval: 40000
+ * In this case, only UpdateUser will be limited by its configuration (70 times in 40000ms)
+ */
+type MethodServiceTpsLimiterImpl struct {
+	tpsState *concurrent.Map
+}
+
+func (limiter MethodServiceTpsLimiterImpl) IsAllowable(url common.URL, invocation protocol.Invocation) bool {
+
+	methodConfigPrefix := "methods." + invocation.MethodName() + "."
+
+	methodLimitRateConfig := url.GetParam(methodConfigPrefix+constant.TPS_LIMIT_RATE_KEY, "")
+	methodIntervalConfig := url.GetParam(methodConfigPrefix+constant.TPS_LIMIT_INTERVAL_KEY, "")
+
+	limitTarget := url.ServiceKey()
+
+	// method-level tps limit
+	if len(methodIntervalConfig) > 0 || len(methodLimitRateConfig) > 0 {
+		limitTarget = limitTarget + "#" + invocation.MethodName()
+	}
+
+	limitState, found := limiter.tpsState.Load(limitTarget)
+	if found {
+		return limitState.(tps.TpsLimitStrategy).IsAllowable()
+	}
+
+	limitRate := getLimitConfig(methodLimitRateConfig, url, invocation,
+		constant.TPS_LIMIT_RATE_KEY,
+		constant.DEFAULT_TPS_LIMIT_RATE)
+
+	if limitRate < 0 {
+		return true
+	}
+
+	limitInterval := getLimitConfig(methodIntervalConfig, url, invocation,
+		constant.TPS_LIMIT_INTERVAL_KEY,
+		constant.DEFAULT_TPS_LIMIT_INTERVAL)
+	if limitInterval <= 0 {
+		panic(fmt.Sprintf("The interval must be positive, please check your configuration! url: %s", url.String()))
+	}
+
+	limitStrategyConfig := url.GetParam(methodConfigPrefix+constant.TPS_LIMIT_STRATEGY_KEY,
+		url.GetParam(constant.TPS_LIMIT_STRATEGY_KEY, constant.DEFAULT_KEY))
+	limitStateCreator := extension.GetTpsLimitStrategyCreator(limitStrategyConfig)
+	limitState, _ = limiter.tpsState.LoadOrStore(limitTarget, limitStateCreator.Create(int(limitRate), int(limitInterval)))
+	return limitState.(tps.TpsLimitStrategy).IsAllowable()
+}
+
+func getLimitConfig(methodLevelConfig string,
+	url common.URL,
+	invocation protocol.Invocation,
+	configKey string,
+	defaultVal string) int64 {
+
+	if len(methodLevelConfig) > 0 {
+		result, err := strconv.ParseInt(methodLevelConfig, 0, 0)
+		if err != nil {
+			panic(fmt.Sprintf("The %s for invocation %s # %s must be positive, please check your configuration!",
+				configKey, url.ServiceKey(), invocation.MethodName()))
+		}
+		return result
+	}
+
+	result, err := strconv.ParseInt(url.GetParam(configKey, defaultVal), 0, 0)
+
+	if err != nil {
+		panic(fmt.Sprintf("Cannot parse the configuration %s, please check your configuration!", configKey))
+	}
+	return result
+}
+
+var methodServiceTpsLimiterInstance *MethodServiceTpsLimiterImpl
+var methodServiceTpsLimiterOnce sync.Once
+
+func GetMethodServiceTpsLimiter() tps.TpsLimiter {
+	methodServiceTpsLimiterOnce.Do(func() {
+		methodServiceTpsLimiterInstance = &MethodServiceTpsLimiterImpl{
+			tpsState: concurrent.NewMap(),
+		}
+	})
+	return methodServiceTpsLimiterInstance
+}
diff --git a/filter/impl/tps/impl/tps_limiter_method_service_test.go b/filter/impl/tps/impl/tps_limiter_method_service_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..e747d4682d0a8bdee03da6f012fb76b7bd1e02af
--- /dev/null
+++ b/filter/impl/tps/impl/tps_limiter_method_service_test.go
@@ -0,0 +1,154 @@
+/*
+ * 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 impl
+
+import (
+	"net/url"
+	"testing"
+)
+import (
+	"github.com/golang/mock/gomock"
+	"github.com/stretchr/testify/assert"
+)
+
+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/filter/impl/tps"
+	"github.com/apache/dubbo-go/protocol/invocation"
+)
+
+func TestMethodServiceTpsLimiterImpl_IsAllowable_Only_Service_Level(t *testing.T) {
+	methodName := "hello"
+	invoc := invocation.NewRPCInvocation(methodName, []interface{}{"OK"}, make(map[string]string, 0))
+
+	ctrl := gomock.NewController(t)
+	defer ctrl.Finish()
+
+	invokeUrl := common.NewURLWithOptions(
+		common.WithParams(url.Values{}),
+		common.WithParamsValue(constant.INTERFACE_KEY, methodName),
+		common.WithParamsValue(constant.TPS_LIMIT_RATE_KEY, "20"))
+
+	mockStrategyImpl := NewMockTpsLimitStrategy(ctrl)
+	mockStrategyImpl.EXPECT().IsAllowable().Return(true).Times(1)
+
+	extension.SetTpsLimitStrategy(constant.DEFAULT_KEY, &mockStrategyCreator{
+		rate:     20,
+		interval: 60000,
+		t:        t,
+		strategy: mockStrategyImpl,
+	})
+
+	limiter := GetMethodServiceTpsLimiter()
+	result := limiter.IsAllowable(*invokeUrl, invoc)
+	assert.True(t, result)
+}
+
+func TestMethodServiceTpsLimiterImpl_IsAllowable_No_Config(t *testing.T) {
+	methodName := "hello1"
+	invoc := invocation.NewRPCInvocation(methodName, []interface{}{"OK"}, make(map[string]string, 0))
+	// ctrl := gomock.NewController(t)
+	// defer ctrl.Finish()
+
+	invokeUrl := common.NewURLWithOptions(
+		common.WithParams(url.Values{}),
+		common.WithParamsValue(constant.INTERFACE_KEY, methodName),
+		common.WithParamsValue(constant.TPS_LIMIT_RATE_KEY, ""))
+
+	limiter := GetMethodServiceTpsLimiter()
+	result := limiter.IsAllowable(*invokeUrl, invoc)
+	assert.True(t, result)
+}
+
+func TestMethodServiceTpsLimiterImpl_IsAllowable_Method_Level_Override(t *testing.T) {
+	methodName := "hello2"
+	methodConfigPrefix := "methods." + methodName + "."
+	invoc := invocation.NewRPCInvocation(methodName, []interface{}{"OK"}, make(map[string]string, 0))
+	ctrl := gomock.NewController(t)
+	defer ctrl.Finish()
+
+	invokeUrl := common.NewURLWithOptions(
+		common.WithParams(url.Values{}),
+		common.WithParamsValue(constant.INTERFACE_KEY, methodName),
+		common.WithParamsValue(constant.TPS_LIMIT_RATE_KEY, "20"),
+		common.WithParamsValue(constant.TPS_LIMIT_INTERVAL_KEY, "3000"),
+		common.WithParamsValue(constant.TPS_LIMIT_STRATEGY_KEY, "invalid"),
+		common.WithParamsValue(methodConfigPrefix+constant.TPS_LIMIT_RATE_KEY, "40"),
+		common.WithParamsValue(methodConfigPrefix+constant.TPS_LIMIT_INTERVAL_KEY, "7000"),
+		common.WithParamsValue(methodConfigPrefix+constant.TPS_LIMIT_STRATEGY_KEY, "default"),
+	)
+
+	mockStrategyImpl := NewMockTpsLimitStrategy(ctrl)
+	mockStrategyImpl.EXPECT().IsAllowable().Return(true).Times(1)
+
+	extension.SetTpsLimitStrategy(constant.DEFAULT_KEY, &mockStrategyCreator{
+		rate:     40,
+		interval: 7000,
+		t:        t,
+		strategy: mockStrategyImpl,
+	})
+
+	limiter := GetMethodServiceTpsLimiter()
+	result := limiter.IsAllowable(*invokeUrl, invoc)
+	assert.True(t, result)
+}
+
+func TestMethodServiceTpsLimiterImpl_IsAllowable_Both_Method_And_Service(t *testing.T) {
+	methodName := "hello3"
+	methodConfigPrefix := "methods." + methodName + "."
+	invoc := invocation.NewRPCInvocation(methodName, []interface{}{"OK"}, make(map[string]string, 0))
+	ctrl := gomock.NewController(t)
+	defer ctrl.Finish()
+
+	invokeUrl := common.NewURLWithOptions(
+		common.WithParams(url.Values{}),
+		common.WithParamsValue(constant.INTERFACE_KEY, methodName),
+		common.WithParamsValue(constant.TPS_LIMIT_RATE_KEY, "20"),
+		common.WithParamsValue(constant.TPS_LIMIT_INTERVAL_KEY, "3000"),
+		common.WithParamsValue(methodConfigPrefix+constant.TPS_LIMIT_RATE_KEY, "40"),
+	)
+
+	mockStrategyImpl := NewMockTpsLimitStrategy(ctrl)
+	mockStrategyImpl.EXPECT().IsAllowable().Return(true).Times(1)
+
+	extension.SetTpsLimitStrategy(constant.DEFAULT_KEY, &mockStrategyCreator{
+		rate:     40,
+		interval: 3000,
+		t:        t,
+		strategy: mockStrategyImpl,
+	})
+
+	limiter := GetMethodServiceTpsLimiter()
+	result := limiter.IsAllowable(*invokeUrl, invoc)
+	assert.True(t, result)
+}
+
+type mockStrategyCreator struct {
+	rate     int
+	interval int
+	t        *testing.T
+	strategy tps.TpsLimitStrategy
+}
+
+func (creator *mockStrategyCreator) Create(rate int, interval int) tps.TpsLimitStrategy {
+	assert.Equal(creator.t, creator.rate, rate)
+	assert.Equal(creator.t, creator.interval, interval)
+	return creator.strategy
+}
diff --git a/filter/impl/tps/impl/tps_limiter_mock.go b/filter/impl/tps/impl/tps_limiter_mock.go
new file mode 100644
index 0000000000000000000000000000000000000000..acd3a15d18baf10838faf57e141afe1711f0aebb
--- /dev/null
+++ b/filter/impl/tps/impl/tps_limiter_mock.go
@@ -0,0 +1,71 @@
+//  Licensed to the Apache Software Foundation (ASF) under one or more
+//  contributor license agreements.  See the NOTICE file distributed with
+//  this work for additional information regarding copyright ownership.
+//  The ASF licenses this file to You under the Apache License, Version 2.0
+//  (the "License"); you may not use this file except in compliance with
+//  the License.  You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//  See the License for the specific language governing permissions and
+//  limitations under the License.
+//
+
+// Code generated by MockGen. DO NOT EDIT.
+// Source: tps_limiter.go
+
+// Package filter is a generated GoMock package.
+package impl
+
+import (
+	reflect "reflect"
+)
+
+import (
+	gomock "github.com/golang/mock/gomock"
+)
+
+import (
+	common "github.com/apache/dubbo-go/common"
+	protocol "github.com/apache/dubbo-go/protocol"
+)
+
+// MockTpsLimiter is a mock of TpsLimiter interface
+type MockTpsLimiter struct {
+	ctrl     *gomock.Controller
+	recorder *MockTpsLimiterMockRecorder
+}
+
+// MockTpsLimiterMockRecorder is the mock recorder for MockTpsLimiter
+type MockTpsLimiterMockRecorder struct {
+	mock *MockTpsLimiter
+}
+
+// NewMockTpsLimiter creates a new mock instance
+func NewMockTpsLimiter(ctrl *gomock.Controller) *MockTpsLimiter {
+	mock := &MockTpsLimiter{ctrl: ctrl}
+	mock.recorder = &MockTpsLimiterMockRecorder{mock}
+	return mock
+}
+
+// EXPECT returns an object that allows the caller to indicate expected use
+func (m *MockTpsLimiter) EXPECT() *MockTpsLimiterMockRecorder {
+	return m.recorder
+}
+
+// IsAllowable mocks base method
+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)
+	return ret0
+}
+
+// IsAllowable indicates an expected call of IsAllowable
+func (mr *MockTpsLimiterMockRecorder) IsAllowable(arg0, arg1 interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsAllowable", reflect.TypeOf((*MockTpsLimiter)(nil).IsAllowable), arg0, arg1)
+}
diff --git a/filter/impl/tps/tps_limit_strategy.go b/filter/impl/tps/tps_limit_strategy.go
new file mode 100644
index 0000000000000000000000000000000000000000..c55f008a09b3743f728ab0506c6b0095cbfd181c
--- /dev/null
+++ b/filter/impl/tps/tps_limit_strategy.go
@@ -0,0 +1,40 @@
+/*
+ * 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 tps
+
+/*
+ * please register your implementation by invoking SetTpsLimitStrategy
+ * "UserProvider":
+ *   registry: "hangzhouzk"
+ *   protocol : "dubbo"
+ *   interface : "com.ikurento.user.UserProvider"
+ *   ... # other configuration
+ *   tps.limiter: "method-service" # the name of limiter
+ *   tps.limit.strategy: "name of implementation" # service-level
+ *   methods:
+ *    - name: "GetUser"
+ *      tps.interval: 3000
+ *      tps.limit.strategy: "name of implementation" # method-level
+ */
+type TpsLimitStrategy interface {
+	IsAllowable() bool
+}
+
+type TpsLimitStrategyCreator interface {
+	Create(rate int, interval int) TpsLimitStrategy
+}
diff --git a/filter/impl/tps/tps_limiter.go b/filter/impl/tps/tps_limiter.go
new file mode 100644
index 0000000000000000000000000000000000000000..0622a957a8ba14fdebb52ff44ecf72da17703163
--- /dev/null
+++ b/filter/impl/tps/tps_limiter.go
@@ -0,0 +1,37 @@
+/*
+ * 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 tps
+
+import (
+	"github.com/apache/dubbo-go/common"
+	"github.com/apache/dubbo-go/protocol"
+)
+
+/*
+ * please register your implementation by invoking SetTpsLimiter
+ * The usage, for example:
+ * "UserProvider":
+ *   registry: "hangzhouzk"
+ *   protocol : "dubbo"
+ *   interface : "com.ikurento.user.UserProvider"
+ *   ... # other configuration
+ *   tps.limiter: "the name of limiter",
+ */
+type TpsLimiter interface {
+	IsAllowable(common.URL, protocol.Invocation) bool
+}
diff --git a/filter/impl/tps_limit_filter.go b/filter/impl/tps_limit_filter.go
new file mode 100644
index 0000000000000000000000000000000000000000..3cb7381c8616abd61fe2ac306b59694a92715dda
--- /dev/null
+++ b/filter/impl/tps_limit_filter.go
@@ -0,0 +1,75 @@
+/*
+ * 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 impl
+
+import (
+	"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/filter"
+	_ "github.com/apache/dubbo-go/filter/common/impl"
+	_ "github.com/apache/dubbo-go/filter/impl/tps/impl"
+	"github.com/apache/dubbo-go/protocol"
+)
+
+const (
+	TpsLimitFilterKey = "tps"
+)
+
+func init() {
+	extension.SetFilter(TpsLimitFilterKey, GetTpsLimitFilter)
+}
+
+/**
+ * if you wish to use the TpsLimiter, please add the configuration into your service provider configuration:
+ * for example:
+ * "UserProvider":
+ *   registry: "hangzhouzk"
+ *   protocol : "dubbo"
+ *   interface : "com.ikurento.user.UserProvider"
+ *   ... # other configuration
+ *   tps.limiter: "method-service", # it should be the name of limiter. if the value is 'default',
+ *                                  # the MethodServiceTpsLimiterImpl will be used.
+ *   tps.limit.rejected.handler: "default", # optional, or the name of the implementation
+ *   if the value of 'tps.limiter' is nil or empty string, the tps filter will do nothing
+ */
+type TpsLimitFilter struct {
+}
+
+func (t TpsLimitFilter) Invoke(invoker protocol.Invoker, invocation protocol.Invocation) protocol.Result {
+	url := invoker.GetUrl()
+	tpsLimiter := url.GetParam(constant.TPS_LIMITER_KEY, "")
+	rejectedExeHandler := url.GetParam(constant.TPS_REJECTED_EXECUTION_HANDLER_KEY, constant.DEFAULT_KEY)
+	if len(tpsLimiter) > 0 {
+		allow := extension.GetTpsLimiter(tpsLimiter).IsAllowable(invoker.GetUrl(), invocation)
+		if allow {
+			return invoker.Invoke(invocation)
+		}
+		logger.Errorf("The invocation was rejected due to over the tps limitation, url: %s ", url.String())
+		return extension.GetRejectedExecutionHandler(rejectedExeHandler).RejectedExecution(url, invocation)
+	}
+	return invoker.Invoke(invocation)
+}
+
+func (t TpsLimitFilter) OnResponse(result protocol.Result, invoker protocol.Invoker, invocation protocol.Invocation) protocol.Result {
+	return result
+}
+
+func GetTpsLimitFilter() filter.Filter {
+	return &TpsLimitFilter{}
+}
diff --git a/filter/impl/tps_limit_filter_test.go b/filter/impl/tps_limit_filter_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..debdbd00dec97ed67d789bfc45103993c014ab4a
--- /dev/null
+++ b/filter/impl/tps_limit_filter_test.go
@@ -0,0 +1,104 @@
+/*
+ * 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 impl
+
+import (
+	"net/url"
+	"testing"
+)
+
+import (
+	"github.com/golang/mock/gomock"
+	"github.com/stretchr/testify/assert"
+)
+
+import (
+	"github.com/apache/dubbo-go/common"
+	"github.com/apache/dubbo-go/common/constant"
+	"github.com/apache/dubbo-go/common/extension"
+	filterCommon "github.com/apache/dubbo-go/filter/common"
+	filterCommonImpl "github.com/apache/dubbo-go/filter/common/impl"
+	"github.com/apache/dubbo-go/filter/impl/tps"
+	"github.com/apache/dubbo-go/filter/impl/tps/impl"
+	"github.com/apache/dubbo-go/protocol"
+	"github.com/apache/dubbo-go/protocol/invocation"
+)
+
+func TestTpsLimitFilter_Invoke_With_No_TpsLimiter(t *testing.T) {
+	tpsFilter := GetTpsLimitFilter()
+	invokeUrl := common.NewURLWithOptions(
+		common.WithParams(url.Values{}),
+		common.WithParamsValue(constant.TPS_LIMITER_KEY, ""))
+	attch := make(map[string]string, 0)
+
+	result := tpsFilter.Invoke(protocol.NewBaseInvoker(*invokeUrl),
+		invocation.NewRPCInvocation("MethodName", []interface{}{"OK"}, attch))
+	assert.Nil(t, result.Error())
+	assert.Nil(t, result.Result())
+
+}
+
+func TestGenericFilter_Invoke_With_Default_TpsLimiter(t *testing.T) {
+	ctrl := gomock.NewController(t)
+	defer ctrl.Finish()
+	mockLimiter := impl.NewMockTpsLimiter(ctrl)
+	mockLimiter.EXPECT().IsAllowable(gomock.Any(), gomock.Any()).Return(true).Times(1)
+	extension.SetTpsLimiter(constant.DEFAULT_KEY, func() tps.TpsLimiter {
+		return mockLimiter
+	})
+
+	tpsFilter := GetTpsLimitFilter()
+	invokeUrl := common.NewURLWithOptions(
+		common.WithParams(url.Values{}),
+		common.WithParamsValue(constant.TPS_LIMITER_KEY, constant.DEFAULT_KEY))
+	attch := make(map[string]string, 0)
+
+	result := tpsFilter.Invoke(protocol.NewBaseInvoker(*invokeUrl),
+		invocation.NewRPCInvocation("MethodName", []interface{}{"OK"}, attch))
+	assert.Nil(t, result.Error())
+	assert.Nil(t, result.Result())
+}
+
+func TestGenericFilter_Invoke_With_Default_TpsLimiter_Not_Allow(t *testing.T) {
+	ctrl := gomock.NewController(t)
+	defer ctrl.Finish()
+	mockLimiter := impl.NewMockTpsLimiter(ctrl)
+	mockLimiter.EXPECT().IsAllowable(gomock.Any(), gomock.Any()).Return(false).Times(1)
+	extension.SetTpsLimiter(constant.DEFAULT_KEY, func() tps.TpsLimiter {
+		return mockLimiter
+	})
+
+	mockResult := &protocol.RPCResult{}
+	mockRejectedHandler := filterCommonImpl.NewMockRejectedExecutionHandler(ctrl)
+	mockRejectedHandler.EXPECT().RejectedExecution(gomock.Any(), gomock.Any()).Return(mockResult).Times(1)
+
+	extension.SetRejectedExecutionHandler(constant.DEFAULT_KEY, func() filterCommon.RejectedExecutionHandler {
+		return mockRejectedHandler
+	})
+
+	tpsFilter := GetTpsLimitFilter()
+	invokeUrl := common.NewURLWithOptions(
+		common.WithParams(url.Values{}),
+		common.WithParamsValue(constant.TPS_LIMITER_KEY, constant.DEFAULT_KEY))
+	attch := make(map[string]string, 0)
+
+	result := tpsFilter.Invoke(protocol.NewBaseInvoker(*invokeUrl),
+		invocation.NewRPCInvocation("MethodName", []interface{}{"OK"}, attch))
+	assert.Nil(t, result.Error())
+	assert.Nil(t, result.Result())
+}
diff --git a/go.mod b/go.mod
index be1c80bd170fe15a05eef55e013607265c282b2a..c2a61f2db1484338bba7dd1bf00a9ff9de2125df 100644
--- a/go.mod
+++ b/go.mod
@@ -4,7 +4,7 @@ require (
 	github.com/Workiva/go-datastructures v1.0.50
 	github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5
 	github.com/aliyun/alibaba-cloud-sdk-go v0.0.0-20190802083043-4cd0c391755e // indirect
-	github.com/apache/dubbo-go-hessian2 v1.2.5-0.20190923055845-e3dd5d131df5
+	github.com/apache/dubbo-go-hessian2 v1.2.5-0.20191029001541-894e45c9aaaa
 	github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23 // indirect
 	github.com/coreos/bbolt v1.3.3 // indirect
 	github.com/coreos/etcd v3.3.13+incompatible
@@ -12,7 +12,7 @@ require (
 	github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f // indirect
 	github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f // indirect
 	github.com/creasty/defaults v1.3.0
-	github.com/dubbogo/getty v1.3.0
+	github.com/dubbogo/getty v1.3.1
 	github.com/dubbogo/gost v1.3.0
 	github.com/fastly/go-utils v0.0.0-20180712184237-d95a45783239 // indirect
 	github.com/go-errors/errors v1.0.1 // indirect
@@ -31,6 +31,7 @@ require (
 	github.com/lestrrat/go-file-rotatelogs v0.0.0-20180223000712-d3151e2a480f // indirect
 	github.com/lestrrat/go-strftime v0.0.0-20180220042222-ba3bf9c1d042 // indirect
 	github.com/magiconair/properties v1.8.1
+	github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd
 	github.com/nacos-group/nacos-sdk-go v0.0.0-20190723125407-0242d42e3dbb
 	github.com/pkg/errors v0.8.1
 	github.com/prometheus/client_golang v1.1.0 // indirect
@@ -38,11 +39,12 @@ require (
 	github.com/satori/go.uuid v1.2.0
 	github.com/smartystreets/goconvey v0.0.0-20190710185942-9d28bd7c0945 // indirect
 	github.com/soheilhy/cmux v0.1.4 // indirect
-	github.com/stretchr/testify v1.3.0
+	github.com/stretchr/testify v1.4.0
 	github.com/tebeka/strftime v0.1.3 // indirect
 	github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5 // indirect
 	github.com/toolkits/concurrent v0.0.0-20150624120057-a4371d70e3e3 // indirect
 	github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 // indirect
+	github.com/zouyx/agollo v0.0.0-20191114083447-dde9fc9f35b8
 	go.etcd.io/bbolt v1.3.3 // indirect
 	go.etcd.io/etcd v3.3.13+incompatible
 	go.uber.org/atomic v1.4.0
@@ -50,3 +52,5 @@ require (
 	google.golang.org/grpc v1.22.1
 	gopkg.in/yaml.v2 v2.2.2
 )
+
+go 1.13
diff --git a/go.sum b/go.sum
index 19b148133b736a6891ad2774db2f010a0b5691ca..9855250a90f72eca314bf54cd9bea03a619b6a5e 100644
--- a/go.sum
+++ b/go.sum
@@ -35,10 +35,8 @@ github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRF
 github.com/aliyun/alibaba-cloud-sdk-go v0.0.0-20190802083043-4cd0c391755e h1:MSuLXx/mveDbpDNhVrcWTMeV4lbYWKcyO4rH+jAxmX0=
 github.com/aliyun/alibaba-cloud-sdk-go v0.0.0-20190802083043-4cd0c391755e/go.mod h1:myCDvQSzCW+wB1WAlocEru4wMGJxy+vlxHdhegi1CDQ=
 github.com/aliyun/aliyun-oss-go-sdk v0.0.0-20190307165228-86c17b95fcd5/go.mod h1:T/Aws4fEfogEE9v+HPhhw+CntffsBHJ8nXQCwKr0/g8=
-github.com/apache/dubbo-go-hessian2 v1.2.5-0.20190921023740-335b8c601359 h1:ti5HOgxW/aKonsBe4Sj/W3+RMq4Jxl/EAAblROneggg=
-github.com/apache/dubbo-go-hessian2 v1.2.5-0.20190921023740-335b8c601359/go.mod h1:LWnndnrFXZmJLAzoyNAPNHSIJ1KOHVkTSsHgC3YYWlo=
-github.com/apache/dubbo-go-hessian2 v1.2.5-0.20190923055845-e3dd5d131df5 h1:p85EqnwOfcqqayW7OPREn0YJxIPIuEmuBJPezzhtO/M=
-github.com/apache/dubbo-go-hessian2 v1.2.5-0.20190923055845-e3dd5d131df5/go.mod h1:LWnndnrFXZmJLAzoyNAPNHSIJ1KOHVkTSsHgC3YYWlo=
+github.com/apache/dubbo-go-hessian2 v1.2.5-0.20191029001541-894e45c9aaaa h1:11TO1wiM5bvGAVrmfN5atD8gZqUSPE1TBoIs8sI6Abk=
+github.com/apache/dubbo-go-hessian2 v1.2.5-0.20191029001541-894e45c9aaaa/go.mod h1:LWnndnrFXZmJLAzoyNAPNHSIJ1KOHVkTSsHgC3YYWlo=
 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/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
@@ -104,8 +102,8 @@ github.com/docker/go-connections v0.3.0 h1:3lOnM9cSzgGwx8VfK/NGOW5fLQ0GjIlCkaktF
 github.com/docker/go-connections v0.3.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
 github.com/docker/go-units v0.3.3 h1:Xk8S3Xj5sLGlG5g67hJmYMmUgXv5N4PhkjJHHqrwnTk=
 github.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
-github.com/dubbogo/getty v1.3.0 h1:GImOCANdts7dlRqi9GMVsZJnfst9EPyjTVTR1AesOD8=
-github.com/dubbogo/getty v1.3.0/go.mod h1:K4b3MkGLf7T+lMgQNFgpg0dI1Wvv1PTisFs1Psf86kU=
+github.com/dubbogo/getty v1.3.1 h1:9fehwTo/D6+z6/+kADMbhbKeMkP80o/3g+XwV5lFLTY=
+github.com/dubbogo/getty v1.3.1/go.mod h1:dtLOEb1v6EMHsQNYRWEACiRLmTWB2kJGUAj1aXayPOg=
 github.com/dubbogo/gost v1.1.1 h1:JCM7vx5edPIjDA5ovJTuzEEXuw2t7xLyrlgi2mi5jHI=
 github.com/dubbogo/gost v1.1.1/go.mod h1:R7wZm1DrmrKGr50mBZVcg6C9ekG8aL5hP+sgWcIDwQg=
 github.com/dubbogo/gost v1.3.0 h1:n90mIUWCPD69BqW8wJ43NDy0RgNxx02aAG4QJcJ785U=
@@ -446,9 +444,12 @@ github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+
 github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
 github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
 github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
+github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
+github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
 github.com/tebeka/strftime v0.1.3 h1:5HQXOqWKYRFfNyBMNVc9z5+QzuBtIXy03psIhtdJYto=
 github.com/tebeka/strftime v0.1.3/go.mod h1:7wJm3dZlpr4l/oVK0t1HYIc4rMzQ2XJlOMIUJUJH6XQ=
 github.com/tent/http-link-go v0.0.0-20130702225549-ac974c61c2f9/go.mod h1:RHkNRtSLfOK7qBTHaeSX1D6BNpI3qw7NTxsmNr4RvN8=
+github.com/tevid/gohamcrest v1.1.1/go.mod h1:3UvtWlqm8j5JbwYZh80D/PVBt0mJ1eJiYgZMibh0H/k=
 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/toolkits/concurrent v0.0.0-20150624120057-a4371d70e3e3 h1:kF/7m/ZU+0D4Jj5eZ41Zm3IH/J8OElK1Qtd7tVKAwLk=
@@ -459,6 +460,8 @@ github.com/vmware/govmomi v0.18.0 h1:f7QxSmP7meCtoAmiKZogvVbLInT+CZx6Px6K5rYsJZo
 github.com/vmware/govmomi v0.18.0/go.mod h1:URlwyTFZX72RmxtxuaFL2Uj3fD1JTvZdx59bHWk6aFU=
 github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 h1:eY9dn8+vbi4tKz5Qo6v2eYzo7kUS51QINcR5jNpbZS8=
 github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
+github.com/zouyx/agollo v0.0.0-20191114083447-dde9fc9f35b8 h1:k8TV7Gz7cpWpOw/dz71fx8cCZdWoPuckHJ/wkJl+meg=
+github.com/zouyx/agollo v0.0.0-20191114083447-dde9fc9f35b8/go.mod h1:S1cAa98KMFv4Sa8SbJ6ZtvOmf0VlgH0QJ1gXI0lBfBY=
 go.etcd.io/bbolt v1.3.3 h1:MUGmc65QhB3pIlaQ5bB4LwqSj6GIonVJXpZiaKNyaKk=
 go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
 go.etcd.io/etcd v3.3.13+incompatible h1:jCejD5EMnlGxFvcGRyEV4VGlENZc7oPQX6o0t7n3xbw=
@@ -534,6 +537,7 @@ google.golang.org/grpc v1.19.1/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZi
 google.golang.org/grpc v1.22.1 h1:/7cs52RnTJmD43s3uxzlq2U7nqVTd/37viQwMrMNlOM=
 google.golang.org/grpc v1.22.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
 gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U=
+gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc=
 gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
 gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d h1:TxyelI5cVkbREznMhfzycHdkp5cLA7DpE+GKjSslYhM=
 gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d/go.mod h1:cuepJuh7vyXfUyUwEgHQXw849cJrilpS5NeIjOWESAw=
diff --git a/protocol/dubbo/client.go b/protocol/dubbo/client.go
index 03ab70467680e6b4c02da52071729e02200f65fc..81f392565f701d990dc1783d5d467814a0fba5bf 100644
--- a/protocol/dubbo/client.go
+++ b/protocol/dubbo/client.go
@@ -113,7 +113,9 @@ type Options struct {
 	RequestTimeout time.Duration
 }
 
-type CallResponse struct {
+//AsyncCallbackResponse async response for dubbo
+type AsyncCallbackResponse struct {
+	common.CallbackResponse
 	Opts      Options
 	Cause     error
 	Start     time.Time // invoke(call) start time == write start time
@@ -121,8 +123,6 @@ type CallResponse struct {
 	Reply     interface{}
 }
 
-type AsyncCallback func(response CallResponse)
-
 type Client struct {
 	opts     Options
 	conf     ClientConfig
@@ -136,10 +136,10 @@ func NewClient(opt Options) *Client {
 
 	switch {
 	case opt.ConnectTimeout == 0:
-		opt.ConnectTimeout = 3e9
+		opt.ConnectTimeout = 3 * time.Second
 		fallthrough
 	case opt.RequestTimeout == 0:
-		opt.RequestTimeout = 3e9
+		opt.RequestTimeout = 3 * time.Second
 	}
 
 	c := &Client{
@@ -199,17 +199,18 @@ func (c *Client) Call(request *Request, response *Response) error {
 	return perrors.WithStack(c.call(ct, request, response, nil))
 }
 
-func (c *Client) AsyncCall(request *Request, callback AsyncCallback, response *Response) error {
+func (c *Client) AsyncCall(request *Request, callback common.AsyncCallback, response *Response) error {
 
 	return perrors.WithStack(c.call(CT_TwoWay, request, response, callback))
 }
 
-func (c *Client) call(ct CallType, request *Request, response *Response, callback AsyncCallback) error {
+func (c *Client) call(ct CallType, request *Request, response *Response, callback common.AsyncCallback) error {
 
 	p := &DubboPackage{}
 	p.Service.Path = strings.TrimPrefix(request.svcUrl.Path, "/")
 	p.Service.Interface = request.svcUrl.GetParam(constant.INTERFACE_KEY, "")
 	p.Service.Version = request.svcUrl.GetParam(constant.VERSION_KEY, "")
+	p.Service.Group = request.svcUrl.GetParam(constant.GROUP_KEY, "")
 	p.Service.Method = request.method
 	p.Service.Timeout = c.opts.RequestTimeout
 	p.Header.SerialID = byte(S_Dubbo)
diff --git a/protocol/dubbo/client_test.go b/protocol/dubbo/client_test.go
index eb1f15c862a910120e118c06bf9b572e93f58832..3f8a8ee98c3b2d8b87e2d5469a18d1792578d1d6 100644
--- a/protocol/dubbo/client_test.go
+++ b/protocol/dubbo/client_test.go
@@ -144,8 +144,9 @@ func TestClient_AsyncCall(t *testing.T) {
 	user := &User{}
 	lock := sync.Mutex{}
 	lock.Lock()
-	err := c.AsyncCall(NewRequest("127.0.0.1:20000", url, "GetUser", []interface{}{"1", "username"}, nil), func(response CallResponse) {
-		assert.Equal(t, User{Id: "1", Name: "username"}, *response.Reply.(*Response).reply.(*User))
+	err := c.AsyncCall(NewRequest("127.0.0.1:20000", url, "GetUser", []interface{}{"1", "username"}, nil), func(response common.CallbackResponse) {
+		r := response.(AsyncCallbackResponse)
+		assert.Equal(t, User{Id: "1", Name: "username"}, *r.Reply.(*Response).reply.(*User))
 		lock.Unlock()
 	}, NewResponse(user, nil))
 	assert.NoError(t, err)
diff --git a/protocol/dubbo/codec.go b/protocol/dubbo/codec.go
index 0b4684487b3c16f4548d6413cedfd81dbe8f32dd..4e7e5ec0a0ecf341c16643c3d745e78398a9f28a 100644
--- a/protocol/dubbo/codec.go
+++ b/protocol/dubbo/codec.go
@@ -26,6 +26,7 @@ import (
 
 import (
 	"github.com/apache/dubbo-go-hessian2"
+	"github.com/apache/dubbo-go/common"
 	perrors "github.com/pkg/errors"
 )
 
@@ -113,7 +114,7 @@ type PendingResponse struct {
 	err       error
 	start     time.Time
 	readStart time.Time
-	callback  AsyncCallback
+	callback  common.AsyncCallback
 	response  *Response
 	done      chan struct{}
 }
@@ -126,8 +127,8 @@ func NewPendingResponse() *PendingResponse {
 	}
 }
 
-func (r PendingResponse) GetCallResponse() CallResponse {
-	return CallResponse{
+func (r PendingResponse) GetCallResponse() common.CallbackResponse {
+	return AsyncCallbackResponse{
 		Cause:     r.err,
 		Start:     r.start,
 		ReadStart: r.readStart,
diff --git a/protocol/dubbo/codec_test.go b/protocol/dubbo/codec_test.go
index c192c2294db5597517ace011224e34f8affefb1f..149644a6eadc23a72b672ae9fa653a1991802dc0 100644
--- a/protocol/dubbo/codec_test.go
+++ b/protocol/dubbo/codec_test.go
@@ -70,5 +70,5 @@ func TestDubboPackage_MarshalAndUnmarshal(t *testing.T) {
 	assert.Equal(t, "Method", pkgres.Body.([]interface{})[3])
 	assert.Equal(t, "Ljava/lang/String;", pkgres.Body.([]interface{})[4])
 	assert.Equal(t, []interface{}{"a"}, pkgres.Body.([]interface{})[5])
-	assert.Equal(t, map[string]string{"dubbo": "2.0.2", "group": "", "interface": "Service", "path": "path", "timeout": "1000", "version": "2.6"}, pkgres.Body.([]interface{})[6])
+	assert.Equal(t, map[string]string{"dubbo": "2.0.2", "interface": "Service", "path": "path", "timeout": "1000", "version": "2.6"}, pkgres.Body.([]interface{})[6])
 }
diff --git a/protocol/dubbo/dubbo_invoker.go b/protocol/dubbo/dubbo_invoker.go
index bc321a97a4271c147d9317145d9f1aa76ca27902..6dcf2568fa8c88a864c567486a501c2ad7feb3f7 100644
--- a/protocol/dubbo/dubbo_invoker.go
+++ b/protocol/dubbo/dubbo_invoker.go
@@ -42,8 +42,8 @@ var (
 
 type DubboInvoker struct {
 	protocol.BaseInvoker
-	client      *Client
-	destroyLock sync.Mutex
+	client   *Client
+	quitOnce sync.Once
 }
 
 func NewDubboInvoker(url common.URL, client *Client) *DubboInvoker {
@@ -75,7 +75,7 @@ func (di *DubboInvoker) Invoke(invocation protocol.Invocation) protocol.Result {
 	}
 	response := NewResponse(inv.Reply(), nil)
 	if async {
-		if callBack, ok := inv.CallBack().(func(response CallResponse)); ok {
+		if callBack, ok := inv.CallBack().(func(response common.CallbackResponse)); ok {
 			result.Err = di.client.AsyncCall(NewRequest(url.Location, url, inv.MethodName(), inv.Arguments(), inv.Attachments()), callBack, response)
 		} else {
 			result.Err = di.client.CallOneway(NewRequest(url.Location, url, inv.MethodName(), inv.Arguments(), inv.Attachments()))
@@ -97,19 +97,11 @@ func (di *DubboInvoker) Invoke(invocation protocol.Invocation) protocol.Result {
 }
 
 func (di *DubboInvoker) Destroy() {
-	if di.IsDestroyed() {
-		return
-	}
-	di.destroyLock.Lock()
-	defer di.destroyLock.Unlock()
-
-	if di.IsDestroyed() {
-		return
-	}
+	di.quitOnce.Do(func() {
+		di.BaseInvoker.Destroy()
 
-	di.BaseInvoker.Destroy()
-
-	if di.client != nil {
-		di.client.Close() // close client
-	}
+		if di.client != nil {
+			di.client.Close()
+		}
+	})
 }
diff --git a/protocol/dubbo/dubbo_invoker_test.go b/protocol/dubbo/dubbo_invoker_test.go
index 0a765356f7353829c8486fddba986e3a444441a1..7d60090e2d81bcb750d1e6d79a08059687c7937d 100644
--- a/protocol/dubbo/dubbo_invoker_test.go
+++ b/protocol/dubbo/dubbo_invoker_test.go
@@ -28,6 +28,7 @@ import (
 )
 
 import (
+	"github.com/apache/dubbo-go/common"
 	"github.com/apache/dubbo-go/common/constant"
 	"github.com/apache/dubbo-go/protocol/invocation"
 )
@@ -65,8 +66,9 @@ func TestDubboInvoker_Invoke(t *testing.T) {
 	// AsyncCall
 	lock := sync.Mutex{}
 	lock.Lock()
-	inv.SetCallBack(func(response CallResponse) {
-		assert.Equal(t, User{Id: "1", Name: "username"}, *response.Reply.(*Response).reply.(*User))
+	inv.SetCallBack(func(response common.CallbackResponse) {
+		r := response.(AsyncCallbackResponse)
+		assert.Equal(t, User{Id: "1", Name: "username"}, *r.Reply.(*Response).reply.(*User))
 		lock.Unlock()
 	})
 	res = invoker.Invoke(inv)
diff --git a/protocol/dubbo/pool.go b/protocol/dubbo/pool.go
index d619a2f8fe78524b3d704cb9de280ebbf534eb12..b5bf040c67c2e0071222466e59db4de67d9e1ca2 100644
--- a/protocol/dubbo/pool.go
+++ b/protocol/dubbo/pool.go
@@ -289,7 +289,17 @@ func (p *gettyRPCClientPool) close() {
 }
 
 func (p *gettyRPCClientPool) getGettyRpcClient(protocol, addr string) (*gettyRPCClient, error) {
-
+	var (
+		conn *gettyRPCClient
+		err  error
+	)
+	if conn, err = p.selectGettyRpcClient(protocol, addr); err == nil && conn == nil {
+		// create new conn
+		return newGettyRPCClientConn(p, protocol, addr)
+	}
+	return conn, err
+}
+func (p *gettyRPCClientPool) selectGettyRpcClient(protocol, addr string) (*gettyRPCClient, error) {
 	p.Lock()
 	defer p.Unlock()
 	if p.conns == nil {
@@ -308,13 +318,10 @@ func (p *gettyRPCClientPool) getGettyRpcClient(protocol, addr string) (*gettyRPC
 			continue
 		}
 		conn.updateActive(now) //update active time
-
 		return conn, nil
 	}
-	// create new conn
-	return newGettyRPCClientConn(p, protocol, addr)
+	return nil, nil
 }
-
 func (p *gettyRPCClientPool) release(conn *gettyRPCClient, err error) {
 	if conn == nil || conn.getActive() == 0 {
 		return
diff --git a/protocol/invocation/rpcinvocation.go b/protocol/invocation/rpcinvocation.go
index 2124a22f1611b24d7f4370de64b117c58c4f7e7b..bddd83b5db60cc3ccaa1ab0c43aaeec28e77855d 100644
--- a/protocol/invocation/rpcinvocation.go
+++ b/protocol/invocation/rpcinvocation.go
@@ -19,6 +19,7 @@ package invocation
 
 import (
 	"reflect"
+	"sync"
 )
 
 import (
@@ -37,6 +38,7 @@ type RPCInvocation struct {
 	callBack       interface{}
 	attachments    map[string]string
 	invoker        protocol.Invoker
+	lock           sync.RWMutex
 }
 
 func NewRPCInvocation(methodName string, arguments []interface{}, attachments map[string]string) *RPCInvocation {
@@ -80,6 +82,8 @@ func (r *RPCInvocation) Attachments() map[string]string {
 }
 
 func (r *RPCInvocation) AttachmentsByKey(key string, defaultValue string) string {
+	r.lock.RLock()
+	defer r.lock.RUnlock()
 	if r.attachments == nil {
 		return defaultValue
 	}
@@ -91,6 +95,8 @@ func (r *RPCInvocation) AttachmentsByKey(key string, defaultValue string) string
 }
 
 func (r *RPCInvocation) SetAttachments(key string, value string) {
+	r.lock.Lock()
+	defer r.lock.Unlock()
 	if r.attachments == nil {
 		r.attachments = make(map[string]string)
 	}
diff --git a/protocol/jsonrpc/http.go b/protocol/jsonrpc/http.go
index b64a3a344e95164b8f49556cdc155bf34642a83b..3d99786624c71818cc5f787c8695d1c116c35707 100644
--- a/protocol/jsonrpc/http.go
+++ b/protocol/jsonrpc/http.go
@@ -66,8 +66,8 @@ type HTTPOptions struct {
 }
 
 var defaultHTTPOptions = HTTPOptions{
-	HandshakeTimeout: 3e9,
-	HTTPTimeout:      3e9,
+	HandshakeTimeout: 3 * time.Second,
+	HTTPTimeout:      3 * time.Second,
 }
 
 type HTTPClient struct {
@@ -115,7 +115,7 @@ func (c *HTTPClient) Call(ctx context.Context, service common.URL, req *Request,
 
 	reqTimeout := c.options.HTTPTimeout
 	if reqTimeout <= 0 {
-		reqTimeout = 1e8
+		reqTimeout = 100 * time.Millisecond
 	}
 	httpHeader.Set("Timeout", reqTimeout.String())
 	if md, ok := ctx.Value(constant.DUBBOGO_CTX_KEY).(map[string]string); ok {
diff --git a/protocol/mock/mock_invoker.go b/protocol/mock/mock_invoker.go
index 557dafa277e95c39d0b960436ac10ba8842c9186..c509cef054f5a23fe504486e01d7cc0e8772711d 100644
--- a/protocol/mock/mock_invoker.go
+++ b/protocol/mock/mock_invoker.go
@@ -1,3 +1,19 @@
+//  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.
+//
+
 // Code generated by MockGen. DO NOT EDIT.
 // Source: invoker.go
 
diff --git a/registry/base_configuration_listener.go b/registry/base_configuration_listener.go
index 925baa2198d9917824c1be78b7cd0c2f93bfb894..056a93aaff1ec657db89f21b4a6b28efc354b49b 100644
--- a/registry/base_configuration_listener.go
+++ b/registry/base_configuration_listener.go
@@ -47,7 +47,7 @@ func (bcl *BaseConfigurationListener) InitWith(key string, listener config_cente
 	}
 	bcl.defaultConfiguratorFunc = f
 	bcl.dynamicConfiguration.AddListener(key, listener)
-	if rawConfig, err := bcl.dynamicConfiguration.GetConfig(key, config_center.WithGroup(constant.DUBBO)); err != nil {
+	if rawConfig, err := bcl.dynamicConfiguration.GetInternalProperty(key, config_center.WithGroup(constant.DUBBO)); err != nil {
 		//set configurators to empty
 		bcl.configurators = []config_center.Configurator{}
 		return
diff --git a/registry/directory/directory.go b/registry/directory/directory.go
index b6794e2ebf212ec024d73335ddb19441afa5b96e..e88c611f6f20bc182c3630e328caab848affc08b 100644
--- a/registry/directory/directory.go
+++ b/registry/directory/directory.go
@@ -38,6 +38,7 @@ import (
 	"github.com/apache/dubbo-go/protocol"
 	"github.com/apache/dubbo-go/protocol/protocolwrapper"
 	"github.com/apache/dubbo-go/registry"
+	"github.com/apache/dubbo-go/remoting"
 )
 
 type Options struct {
@@ -119,20 +120,19 @@ func (dir *registryDirectory) refreshInvokers(res *registry.ServiceEvent) {
 			url = nil
 			//TODO: router
 		}
+		switch res.Action {
+		case remoting.EventTypeAdd, remoting.EventTypeUpdate:
+			//dir.cacheService.EventTypeAdd(res.Path, dir.serviceTTL)
+			dir.cacheInvoker(url)
+		case remoting.EventTypeDel:
+			//dir.cacheService.EventTypeDel(res.Path, dir.serviceTTL)
+			dir.uncacheInvoker(url)
+			logger.Infof("selector delete service url{%s}", res.Service)
+		default:
+			return
+		}
 	}
-	//
-	//switch res.Action {
-	//case remoting.EventTypeAdd:
-	//	//dir.cacheService.EventTypeAdd(res.Path, dir.serviceTTL)
-	//	dir.cacheInvoker(&res.Service)
-	//case remoting.EventTypeDel:
-	//	//dir.cacheService.EventTypeDel(res.Path, dir.serviceTTL)
-	//	dir.uncacheInvoker(&res.Service)
-	//	logger.Infof("selector delete service url{%s}", res.Service)
-	//default:
-	//	return
-	//}
-	dir.cacheInvoker(url)
+
 	newInvokers := dir.toGroupInvokers()
 	dir.listenerLock.Lock()
 	defer dir.listenerLock.Unlock()
diff --git a/registry/etcdv3/listener.go b/registry/etcdv3/listener.go
index e0dc09908567ffcd8b8f77a9627c83876906e792..31d62fa916e5659cf424839cedf8f063fabedaa0 100644
--- a/registry/etcdv3/listener.go
+++ b/registry/etcdv3/listener.go
@@ -1,3 +1,20 @@
+/*
+ * 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 etcdv3
 
 import (
diff --git a/registry/etcdv3/listener_test.go b/registry/etcdv3/listener_test.go
index 00024d28949f8b517d49f45ce6f16422d67b0a6b..c064f99c6c4b447a6c81093b87d99e1d1ba6d17a 100644
--- a/registry/etcdv3/listener_test.go
+++ b/registry/etcdv3/listener_test.go
@@ -1,3 +1,20 @@
+/*
+ * 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 etcdv3
 
 import (
diff --git a/registry/etcdv3/registry.go b/registry/etcdv3/registry.go
index 4ee90969e57fc50344c914f5332134e6f7f01b89..b058113c69b8007803a8a18c1b5e0c3af8c184f4 100644
--- a/registry/etcdv3/registry.go
+++ b/registry/etcdv3/registry.go
@@ -1,3 +1,20 @@
+/*
+ * 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 etcdv3
 
 import (
diff --git a/registry/etcdv3/registry_test.go b/registry/etcdv3/registry_test.go
index 6da9ad9d7d13bb0b6f8d1dab9b582669735ceec8..3f8c0f4cfccc2bcc68fc1e55fa69d74e9f0f8c0f 100644
--- a/registry/etcdv3/registry_test.go
+++ b/registry/etcdv3/registry_test.go
@@ -1,3 +1,20 @@
+/*
+ * 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 etcdv3
 
 import (
diff --git a/registry/nacos/listener.go b/registry/nacos/listener.go
index 1f264ec9e4ba9b8e970eba7da3b46d8792831dea..25cd3d09b5711e4e7db56cd8e40f3283f3252e10 100644
--- a/registry/nacos/listener.go
+++ b/registry/nacos/listener.go
@@ -1,3 +1,20 @@
+/*
+ * 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 nacos
 
 import (
diff --git a/registry/nacos/registry.go b/registry/nacos/registry.go
index 810a1cb05fec780868cf7767a9fcf8a7ccbd2b41..a8b9fa83fa73858064e570722341c14f974f5c9e 100644
--- a/registry/nacos/registry.go
+++ b/registry/nacos/registry.go
@@ -1,3 +1,20 @@
+/*
+ * 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 nacos
 
 import (
diff --git a/registry/nacos/registry_test.go b/registry/nacos/registry_test.go
index 023ff788091c0c0f7c83ab213d8ab52006cfdc81..e6ab693cd3f5432fe30c2b83011cd56e44ac509f 100644
--- a/registry/nacos/registry_test.go
+++ b/registry/nacos/registry_test.go
@@ -1,3 +1,20 @@
+/*
+ * 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 nacos
 
 import (
diff --git a/registry/zookeeper/listener.go b/registry/zookeeper/listener.go
index 857421f07706d6bdfec5a3ec21ba674627633458..53a592609153003d7d6c24881bccde0dfe6cdde6 100644
--- a/registry/zookeeper/listener.go
+++ b/registry/zookeeper/listener.go
@@ -20,6 +20,7 @@ package zookeeper
 import (
 	"context"
 	"strings"
+	"sync"
 )
 
 import (
@@ -71,14 +72,16 @@ func (l *RegistryDataListener) DataChange(eventType remoting.Event) bool {
 }
 
 type RegistryConfigurationListener struct {
-	client   *zk.ZookeeperClient
-	registry *zkRegistry
-	events   chan *config_center.ConfigChangeEvent
+	client    *zk.ZookeeperClient
+	registry  *zkRegistry
+	events    chan *config_center.ConfigChangeEvent
+	isClosed  bool
+	closeOnce sync.Once
 }
 
 func NewRegistryConfigurationListener(client *zk.ZookeeperClient, reg *zkRegistry) *RegistryConfigurationListener {
 	reg.wg.Add(1)
-	return &RegistryConfigurationListener{client: client, registry: reg, events: make(chan *config_center.ConfigChangeEvent, 32)}
+	return &RegistryConfigurationListener{client: client, registry: reg, events: make(chan *config_center.ConfigChangeEvent, 32), isClosed: false}
 }
 func (l *RegistryConfigurationListener) Process(configType *config_center.ConfigChangeEvent) {
 	l.events <- configType
@@ -92,7 +95,7 @@ func (l *RegistryConfigurationListener) Next() (*registry.ServiceEvent, error) {
 			return nil, perrors.New("listener stopped")
 
 		case <-l.registry.done:
-			logger.Warnf("zk consumer register has quit, so zk event listener exit asap now.")
+			logger.Warnf("zk consumer register has quit, so zk event listener exit now.")
 			return nil, perrors.New("listener stopped")
 
 		case e := <-l.events:
@@ -109,7 +112,11 @@ func (l *RegistryConfigurationListener) Next() (*registry.ServiceEvent, error) {
 	}
 }
 func (l *RegistryConfigurationListener) Close() {
-	l.registry.wg.Done()
+	// ensure that the listener will be closed at most once.
+	l.closeOnce.Do(func() {
+		l.isClosed = true
+		l.registry.wg.Done()
+	})
 }
 
 func (l *RegistryConfigurationListener) valid() bool {
diff --git a/registry/zookeeper/registry.go b/registry/zookeeper/registry.go
index 29ae51d44f3691807cbc74912290ba141d1f5d47..1defedc28a2d42183be8c2e5d77441d8831c1d30 100644
--- a/registry/zookeeper/registry.go
+++ b/registry/zookeeper/registry.go
@@ -46,6 +46,7 @@ import (
 const (
 	RegistryZkClient  = "zk registry"
 	RegistryConnDelay = 3
+	MaxWaitInterval   = time.Duration(3e9)
 )
 
 var (
@@ -200,6 +201,10 @@ func (r *zkRegistry) RestartCallBack() bool {
 		}
 		logger.Infof("success to re-register service :%v", confIf.Key())
 	}
+	r.listener = zookeeper.NewZkEventListener(r.client)
+	r.configListener = NewRegistryConfigurationListener(r.client, r)
+	r.dataListener = NewRegistryDataListener(r.configListener)
+
 	return flag
 }
 
@@ -256,6 +261,10 @@ func (r *zkRegistry) Register(conf common.URL) error {
 	return nil
 }
 
+func (r *zkRegistry) service(c common.URL) string {
+	return url.QueryEscape(c.Service())
+}
+
 func (r *zkRegistry) register(c common.URL) error {
 	var (
 		err error
@@ -291,7 +300,7 @@ func (r *zkRegistry) register(c common.URL) error {
 			return perrors.Errorf("conf{Path:%s, Methods:%s}", c.Path, c.Methods)
 		}
 		// 鍏堝垱寤烘湇鍔′笅闈㈢殑provider node
-		dubboPath = fmt.Sprintf("/dubbo/%s/%s", c.Service(), common.DubboNodes[common.PROVIDER])
+		dubboPath = fmt.Sprintf("/dubbo/%s/%s", r.service(c), common.DubboNodes[common.PROVIDER])
 		r.cltLock.Lock()
 		err = r.client.Create(dubboPath)
 		r.cltLock.Unlock()
@@ -325,11 +334,11 @@ func (r *zkRegistry) register(c common.URL) error {
 		encodedURL = url.QueryEscape(rawURL)
 
 		// Print your own registration service providers.
-		dubboPath = fmt.Sprintf("/dubbo/%s/%s", c.Service(), (common.RoleType(common.PROVIDER)).String())
+		dubboPath = fmt.Sprintf("/dubbo/%s/%s", r.service(c), (common.RoleType(common.PROVIDER)).String())
 		logger.Debugf("provider path:%s, url:%s", dubboPath, rawURL)
 
 	case common.CONSUMER:
-		dubboPath = fmt.Sprintf("/dubbo/%s/%s", c.Service(), common.DubboNodes[common.CONSUMER])
+		dubboPath = fmt.Sprintf("/dubbo/%s/%s", r.service(c), common.DubboNodes[common.CONSUMER])
 		r.cltLock.Lock()
 		err = r.client.Create(dubboPath)
 		r.cltLock.Unlock()
@@ -337,7 +346,7 @@ func (r *zkRegistry) register(c common.URL) error {
 			logger.Errorf("zkClient.create(path{%s}) = error{%v}", dubboPath, perrors.WithStack(err))
 			return perrors.WithStack(err)
 		}
-		dubboPath = fmt.Sprintf("/dubbo/%s/%s", c.Service(), common.DubboNodes[common.PROVIDER])
+		dubboPath = fmt.Sprintf("/dubbo/%s/%s", r.service(c), common.DubboNodes[common.PROVIDER])
 		r.cltLock.Lock()
 		err = r.client.Create(dubboPath)
 		r.cltLock.Unlock()
@@ -354,7 +363,7 @@ func (r *zkRegistry) register(c common.URL) error {
 		rawURL = fmt.Sprintf("consumer://%s%s?%s", localIP, c.Path, params.Encode())
 		encodedURL = url.QueryEscape(rawURL)
 
-		dubboPath = fmt.Sprintf("/dubbo/%s/%s", c.Service(), (common.RoleType(common.CONSUMER)).String())
+		dubboPath = fmt.Sprintf("/dubbo/%s/%s", r.service(c), (common.RoleType(common.CONSUMER)).String())
 		logger.Debugf("consumer path:%s, url:%s", dubboPath, rawURL)
 
 	default:
@@ -399,10 +408,19 @@ func (r *zkRegistry) registerTempZookeeperNode(root string, node string) error {
 func (r *zkRegistry) subscribe(conf *common.URL) (registry.Listener, error) {
 	return r.getListener(conf)
 }
+func sleepWait(n int) {
+	wait := time.Duration((n + 1) * 2e8)
+	if wait > MaxWaitInterval {
+		wait = MaxWaitInterval
+	}
+	time.Sleep(wait)
+}
 
 //subscribe from registry
 func (r *zkRegistry) Subscribe(url *common.URL, notifyListener registry.NotifyListener) {
+	n := 0
 	for {
+		n++
 		if !r.IsAvailable() {
 			logger.Warnf("event listener game over.")
 			return
@@ -423,14 +441,14 @@ func (r *zkRegistry) Subscribe(url *common.URL, notifyListener registry.NotifyLi
 			if serviceEvent, err := listener.Next(); err != nil {
 				logger.Warnf("Selector.watch() = error{%v}", perrors.WithStack(err))
 				listener.Close()
-				return
+				break
 			} else {
 				logger.Infof("update begin, service event: %v", serviceEvent.String())
 				notifyListener.Notify(serviceEvent)
 			}
 
 		}
-
+		sleepWait(n)
 	}
 }
 
@@ -440,6 +458,10 @@ func (r *zkRegistry) getListener(conf *common.URL) (*RegistryConfigurationListen
 	)
 
 	r.listenerLock.Lock()
+	if r.configListener.isClosed {
+		r.listenerLock.Unlock()
+		return nil, perrors.New("configListener already been closed")
+	}
 	zkListener = r.configListener
 	r.listenerLock.Unlock()
 	if r.listener == nil {
@@ -461,7 +483,7 @@ func (r *zkRegistry) getListener(conf *common.URL) (*RegistryConfigurationListen
 	//Interested register to dataconfig.
 	r.dataListener.AddInterestedURL(conf)
 	for _, v := range strings.Split(conf.GetParam(constant.CATEGORY_KEY, constant.DEFAULT_CATEGORY), ",") {
-		go r.listener.ListenServiceEvent(fmt.Sprintf("/dubbo/%s/"+v, conf.Service()), r.dataListener)
+		go r.listener.ListenServiceEvent(fmt.Sprintf("/dubbo/%s/"+v, url.QueryEscape(conf.Service())), r.dataListener)
 	}
 
 	return zkListener, nil
diff --git a/remoting/etcdv3/client.go b/remoting/etcdv3/client.go
index 57d1211fe30e00dcb1ad16733f36b7969ebaf505..050968565387fd31871b0aa8e9969496d39f6534 100644
--- a/remoting/etcdv3/client.go
+++ b/remoting/etcdv3/client.go
@@ -1,3 +1,20 @@
+/*
+ * 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 etcdv3
 
 import (
diff --git a/remoting/etcdv3/client_test.go b/remoting/etcdv3/client_test.go
index 187789e0abfac6a0e195bebd68ce4b91e0f9bdec..8f9b80cd30a9791709a0b2e83b9e59e0046f4c6c 100644
--- a/remoting/etcdv3/client_test.go
+++ b/remoting/etcdv3/client_test.go
@@ -1,3 +1,20 @@
+/*
+ * 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 etcdv3
 
 import (
diff --git a/remoting/etcdv3/facade.go b/remoting/etcdv3/facade.go
index e75b39d6bcd7f67f7606c6b212f59e7a42178fd8..499044b8d77d3dcd8d32b0cb70cb78f84fae8ec4 100644
--- a/remoting/etcdv3/facade.go
+++ b/remoting/etcdv3/facade.go
@@ -1,3 +1,20 @@
+/*
+ * 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 etcdv3
 
 import (
diff --git a/remoting/etcdv3/listener.go b/remoting/etcdv3/listener.go
index f5401917e208f41d3ea84e47c46f535b344e2784..a4d5805a6dbf3c76f43cb6085653c791b33ab119 100644
--- a/remoting/etcdv3/listener.go
+++ b/remoting/etcdv3/listener.go
@@ -1,3 +1,20 @@
+/*
+ * 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 etcdv3
 
 import (
diff --git a/remoting/etcdv3/listener_test.go b/remoting/etcdv3/listener_test.go
index 33904a21345ec0ac7ee1adbb239a0a7a44852387..7da85819730eaeb1c6931b0e13de26e2e171bec2 100644
--- a/remoting/etcdv3/listener_test.go
+++ b/remoting/etcdv3/listener_test.go
@@ -1,3 +1,20 @@
+/*
+ * 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 etcdv3
 
 import (
diff --git a/remoting/zookeeper/listener_test.go b/remoting/zookeeper/listener_test.go
index a90fbad05ae787f36d38607b0a73374d874e6994..aa627c7e8a53ef87fb39446b05d4001bcf18cf3f 100644
--- a/remoting/zookeeper/listener_test.go
+++ b/remoting/zookeeper/listener_test.go
@@ -18,6 +18,7 @@
 package zookeeper
 
 import (
+	"net/url"
 	"sync"
 	"testing"
 	"time"
@@ -122,3 +123,9 @@ func (m *mockDataListener) DataChange(eventType remoting.Event) bool {
 	}
 	return true
 }
+
+func TestZkPath(t *testing.T) {
+	zkPath := "io.grpc.examples.helloworld.GreeterGrpc$IGreeter"
+	zkPath = url.QueryEscape(zkPath)
+	assert.Equal(t, zkPath, "io.grpc.examples.helloworld.GreeterGrpc%24IGreeter")
+}