diff --git a/cluster/cluster_impl/base_cluster_invoker.go b/cluster/cluster_impl/base_cluster_invoker.go
index 2426258b95e8a2ecf5067b2ed469eeb9a5617f18..d42a099bbf71608753e463084c6a403ae9627e01 100644
--- a/cluster/cluster_impl/base_cluster_invoker.go
+++ b/cluster/cluster_impl/base_cluster_invoker.go
@@ -84,7 +84,7 @@ func (invoker *baseClusterInvoker) checkWhetherDestroyed() error {
 }
 
 func (invoker *baseClusterInvoker) doSelect(lb cluster.LoadBalance, invocation protocol.Invocation, invokers []protocol.Invoker, invoked []protocol.Invoker) protocol.Invoker {
-	//todo:ticky connect 绮樼焊杩炴帴
+	//todo:sticky connect
 	if len(invokers) == 1 {
 		return invokers[0]
 	}
diff --git a/common/constant/key.go b/common/constant/key.go
index 4d2664baf9b311f6ed8aa8e295599d7e8e5846c4..3441b341d038e505e8e1f4444adb4cecc2d8b847 100644
--- a/common/constant/key.go
+++ b/common/constant/key.go
@@ -87,3 +87,15 @@ const (
 	ProviderConfigPrefix  = "dubbo.provider."
 	ConsumerConfigPrefix  = "dubbo.consumer."
 )
+
+const (
+	NACOS_KEY                    = "nacos"
+	NACOS_DEFAULT_ROLETYPE       = 3
+	NACOS_CACHE_DIR_KEY          = "cacheDir"
+	NACOS_LOG_DIR_KEY            = "logDir"
+	NACOS_ENDPOINT               = "endpoint"
+	NACOS_SERVICE_NAME_SEPARATOR = ":"
+	NACOS_CATEGORY_KEY           = "category"
+	NACOS_PROTOCOL_KEY           = "protocol"
+	NACOS_PATH_KEY               = "path"
+)
diff --git a/config/reference_config.go b/config/reference_config.go
index 67a4a3d816060475fa49182f7141aba9807849e1..f90e3aabd3a68b8dc7a7509331d301ea3a252f92 100644
--- a/config/reference_config.go
+++ b/config/reference_config.go
@@ -158,6 +158,7 @@ func (refconfig *ReferenceConfig) getUrlMap() url.Values {
 	urlMap.Set(constant.GROUP_KEY, refconfig.Group)
 	urlMap.Set(constant.VERSION_KEY, refconfig.Version)
 	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))
 
diff --git a/config/registry_config.go b/config/registry_config.go
index 3d54c348aadd2a2f836849d12e50887c36909d31..0abdab810f3cfa835f7d1f21e395cd2a2812a051 100644
--- a/config/registry_config.go
+++ b/config/registry_config.go
@@ -36,9 +36,10 @@ type RegistryConfig struct {
 	TimeoutStr string `yaml:"timeout" default:"5s" json:"timeout,omitempty" property:"timeout"` // unit: second
 	Group      string `yaml:"group" json:"group,omitempty" property:"group"`
 	//for registry
-	Address  string `yaml:"address" json:"address,omitempty" property:"address"`
-	Username string `yaml:"username" json:"username,omitempty" property:"username"`
-	Password string `yaml:"password" json:"password,omitempty"  property:"password"`
+	Address  string            `yaml:"address" json:"address,omitempty" property:"address"`
+	Username string            `yaml:"username" json:"username,omitempty" property:"username"`
+	Password string            `yaml:"password" json:"password,omitempty"  property:"password"`
+	Params   map[string]string `yaml:"params" json:"params,omitempty" property:"params"`
 }
 
 func (*RegistryConfig) Prefix() string {
@@ -109,6 +110,8 @@ func (regconfig *RegistryConfig) getUrlMap(roleType common.RoleType) url.Values
 	urlMap.Set(constant.ROLE_KEY, strconv.Itoa(int(roleType)))
 	urlMap.Set(constant.REGISTRY_KEY, regconfig.Protocol)
 	urlMap.Set(constant.REGISTRY_TIMEOUT_KEY, regconfig.TimeoutStr)
-
+	for k, v := range regconfig.Params {
+		urlMap.Set(k, v)
+	}
 	return urlMap
 }
diff --git a/config/service_config.go b/config/service_config.go
index 76913319f6f0ac27ec36ebaa2d89db09bbd79c7c..8b4a7d1b2251be206085a54a8676944aa3158609 100644
--- a/config/service_config.go
+++ b/config/service_config.go
@@ -163,6 +163,7 @@ func (srvconfig *ServiceConfig) getUrlMap() url.Values {
 	urlMap.Set(constant.RETRIES_KEY, strconv.FormatInt(srvconfig.Retries, 10))
 	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
 	urlMap.Set(constant.APPLICATION_KEY, providerConfig.ApplicationConfig.Name)
 	urlMap.Set(constant.ORGANIZATION_KEY, providerConfig.ApplicationConfig.Organization)
diff --git a/config_center/zookeeper/impl.go b/config_center/zookeeper/impl.go
index ef0761efcd0d2cee47425dd5e1099200d3be6a70..f2827b2bb693fc1943116686f8056c0edaeadc99 100644
--- a/config_center/zookeeper/impl.go
+++ b/config_center/zookeeper/impl.go
@@ -196,7 +196,7 @@ func (r *zookeeperDynamicConfiguration) closeConfigs() {
 	r.cltLock.Lock()
 	defer r.cltLock.Unlock()
 	logger.Infof("begin to close provider zk client")
-	// 鍏堝叧闂棫client锛屼互鍏抽棴tmp node
+	// Close the old client first to close the tmp node
 	r.client.Close()
 	r.client = nil
 }
diff --git a/examples/configcenter/zookeeper/dubbo/with-configcenter-go-client/app/client.go b/examples/configcenter/zookeeper/dubbo/with-configcenter-go-client/app/client.go
index fb2e0ef7ec4cc82e681ff8d352a8f45276ccfd99..5da8506d5d0a3f16388446fe29799ffb28023c7f 100644
--- a/examples/configcenter/zookeeper/dubbo/with-configcenter-go-client/app/client.go
+++ b/examples/configcenter/zookeeper/dubbo/with-configcenter-go-client/app/client.go
@@ -27,7 +27,7 @@ import (
 )
 
 import (
-	"github.com/apache/dubbo-go-hessian2"
+	hessian "github.com/apache/dubbo-go-hessian2"
 )
 
 import (
@@ -140,7 +140,7 @@ func initSignal() {
 				os.Exit(1)
 			})
 
-			// 瑕佷箞fastFailTimeout鏃堕棿鍐呮墽琛屽畬姣曚笅闈㈢殑閫昏緫鐒跺悗绋嬪簭閫€鍑猴紝瑕佷箞鎵ц涓婇潰鐨勮秴鏃跺嚱鏁扮▼搴忓己琛岄€€鍑�
+			// The program exits normally or timeout forcibly exits.//
 			fmt.Println("app exit now...")
 			return
 		}
diff --git a/examples/configcenter/zookeeper/dubbo/with-configcenter-go-client/app/user.go b/examples/configcenter/zookeeper/dubbo/with-configcenter-go-client/app/user.go
index 8140acaef621f361e5b35fa90318d73546902913..5bddf1e19f59be1b7fae917cffddfde4d362f44e 100644
--- a/examples/configcenter/zookeeper/dubbo/with-configcenter-go-client/app/user.go
+++ b/examples/configcenter/zookeeper/dubbo/with-configcenter-go-client/app/user.go
@@ -83,7 +83,7 @@ type User struct {
 	Name string
 	Age  int32
 	Time time.Time
-	Sex  Gender // 娉ㄦ剰姝ゅ锛宩ava enum Object <--> go string
+	Sex  Gender // notice: java enum Object <--> go string
 }
 
 func (u User) String() string {
diff --git a/examples/configcenter/zookeeper/dubbo/with-configcenter-go-server/app/server.go b/examples/configcenter/zookeeper/dubbo/with-configcenter-go-server/app/server.go
index 814978566774c449e058c7f0d4e73176f5a1f57b..cd982992171fdf674e560bfb4ed280c1951cccde 100644
--- a/examples/configcenter/zookeeper/dubbo/with-configcenter-go-server/app/server.go
+++ b/examples/configcenter/zookeeper/dubbo/with-configcenter-go-server/app/server.go
@@ -78,7 +78,7 @@ func initSignal() {
 				os.Exit(1)
 			})
 
-			// 瑕佷箞fastFailTimeout鏃堕棿鍐呮墽琛屽畬姣曚笅闈㈢殑閫昏緫鐒跺悗绋嬪簭閫€鍑猴紝瑕佷箞鎵ц涓婇潰鐨勮秴鏃跺嚱鏁扮▼搴忓己琛岄€€鍑�
+			// The program exits normally or timeout forcibly exits.
 			fmt.Println("provider app exit now...")
 			return
 		}
diff --git a/examples/configcenter/zookeeper/dubbo/with-configcenter-go-server/app/user.go b/examples/configcenter/zookeeper/dubbo/with-configcenter-go-server/app/user.go
index d0ac61e4c41e805dbcadc30238993e3946da7cd0..0e4d05766887ae41440313b49ba4dc859a09ed35 100644
--- a/examples/configcenter/zookeeper/dubbo/with-configcenter-go-server/app/user.go
+++ b/examples/configcenter/zookeeper/dubbo/with-configcenter-go-server/app/user.go
@@ -84,7 +84,7 @@ type (
 		Name string
 		Age  int32
 		Time time.Time
-		Sex  Gender // 娉ㄦ剰姝ゅ锛宩ava enum Object <--> go string
+		Sex  Gender // notice: java enum Object <--> go string
 	}
 
 	UserProvider struct {
diff --git a/examples/configcenter/zookeeper/jsonrpc/with-configcenter-go-client/app/client.go b/examples/configcenter/zookeeper/jsonrpc/with-configcenter-go-client/app/client.go
index 642b45a9343477086300ccb78d56756fbf51a817..5b1634788c455f6b8f0fb964f25a07b525492cf0 100644
--- a/examples/configcenter/zookeeper/jsonrpc/with-configcenter-go-client/app/client.go
+++ b/examples/configcenter/zookeeper/jsonrpc/with-configcenter-go-client/app/client.go
@@ -125,7 +125,7 @@ func initSignal() {
 				os.Exit(1)
 			})
 
-			// 瑕佷箞fastFailTimeout鏃堕棿鍐呮墽琛屽畬姣曚笅闈㈢殑閫昏緫鐒跺悗绋嬪簭閫€鍑猴紝瑕佷箞鎵ц涓婇潰鐨勮秴鏃跺嚱鏁扮▼搴忓己琛岄€€鍑�
+			// The program exits normally or timeout forcibly exits.
 			fmt.Println("app exit now...")
 			return
 		}
diff --git a/examples/configcenter/zookeeper/jsonrpc/with-configcenter-go-server/app/server.go b/examples/configcenter/zookeeper/jsonrpc/with-configcenter-go-server/app/server.go
index 851a97c15543961ad29784de449fe1ee56adc9c9..0a0e72915fef0ca4613f78a87fa1057152c1cc9a 100644
--- a/examples/configcenter/zookeeper/jsonrpc/with-configcenter-go-server/app/server.go
+++ b/examples/configcenter/zookeeper/jsonrpc/with-configcenter-go-server/app/server.go
@@ -67,7 +67,7 @@ func initSignal() {
 				os.Exit(1)
 			})
 
-			// 瑕佷箞fastFailTimeout鏃堕棿鍐呮墽琛屽畬姣曚笅闈㈢殑閫昏緫鐒跺悗绋嬪簭閫€鍑猴紝瑕佷箞鎵ц涓婇潰鐨勮秴鏃跺嚱鏁扮▼搴忓己琛岄€€鍑�
+			// The program exits normally or timeout forcibly exits.
 			fmt.Println("provider app exit now...")
 			return
 		}
diff --git a/examples/general/dubbo/go-client/app/client.go b/examples/general/dubbo/go-client/app/client.go
index b7ee0e662a26251a79af13d36215cc2cb44fd794..47f453c3a451a4c6d98f40e1ec7e7618440fe4f9 100644
--- a/examples/general/dubbo/go-client/app/client.go
+++ b/examples/general/dubbo/go-client/app/client.go
@@ -86,7 +86,7 @@ func initSignal() {
 				os.Exit(1)
 			})
 
-			// 瑕佷箞fastFailTimeout鏃堕棿鍐呮墽琛屽畬姣曚笅闈㈢殑閫昏緫鐒跺悗绋嬪簭閫€鍑猴紝瑕佷箞鎵ц涓婇潰鐨勮秴鏃跺嚱鏁扮▼搴忓己琛岄€€鍑�
+			// The program exits normally or timeout forcibly exits.
 			fmt.Println("app exit now...")
 			return
 		}
diff --git a/examples/general/dubbo/go-client/app/user.go b/examples/general/dubbo/go-client/app/user.go
index affa5418a701842e890f9e2498c2ef7a769532bd..104d325d052940439da1c89c565a47520c73dd88 100644
--- a/examples/general/dubbo/go-client/app/user.go
+++ b/examples/general/dubbo/go-client/app/user.go
@@ -89,7 +89,7 @@ type User struct {
 	Name string
 	Age  int32
 	Time time.Time
-	Sex  Gender // 娉ㄦ剰姝ゅ锛宩ava enum Object <--> go string
+	Sex  Gender // notice: java enum Object <--> go string
 }
 
 func (u User) String() string {
diff --git a/examples/general/dubbo/go-server/app/server.go b/examples/general/dubbo/go-server/app/server.go
index de9c28737b43cee780494c6f0824cabac84b6595..ac92b879b15cb88ebc71fc5df90675b01760c899 100644
--- a/examples/general/dubbo/go-server/app/server.go
+++ b/examples/general/dubbo/go-server/app/server.go
@@ -79,7 +79,7 @@ func initSignal() {
 				os.Exit(1)
 			})
 
-			// 瑕佷箞fastFailTimeout鏃堕棿鍐呮墽琛屽畬姣曚笅闈㈢殑閫昏緫鐒跺悗绋嬪簭閫€鍑猴紝瑕佷箞鎵ц涓婇潰鐨勮秴鏃跺嚱鏁扮▼搴忓己琛岄€€鍑�
+			// The program exits normally or timeout forcibly exits.
 			fmt.Println("provider app exit now...")
 			return
 		}
diff --git a/examples/general/dubbo/go-server/app/user.go b/examples/general/dubbo/go-server/app/user.go
index ce53bca080e388c2ef8bb852a4ddc7f95a232d96..e07a02e772de589bd9df85ef6e1e69fb2468d347 100644
--- a/examples/general/dubbo/go-server/app/user.go
+++ b/examples/general/dubbo/go-server/app/user.go
@@ -24,7 +24,7 @@ import (
 )
 
 import (
-	"github.com/apache/dubbo-go-hessian2"
+	hessian "github.com/apache/dubbo-go-hessian2"
 )
 
 type Gender hessian.JavaEnum
@@ -73,7 +73,7 @@ type (
 		Name string
 		Age  int32
 		Time time.Time
-		Sex  Gender // 娉ㄦ剰姝ゅ锛宩ava enum Object <--> go string
+		Sex  Gender // notice: java enum Object <--> go string
 	}
 )
 
diff --git a/examples/general/dubbo/java-client/src/main/java/com/ikurento/user/Consumer.java b/examples/general/dubbo/java-client/src/main/java/com/ikurento/user/Consumer.java
index 9122a629f49cb1e5eeee1641e89fa0c91091e960..5c9870eecacb51115b266e8e13d81e02323d5a74 100644
--- a/examples/general/dubbo/java-client/src/main/java/com/ikurento/user/Consumer.java
+++ b/examples/general/dubbo/java-client/src/main/java/com/ikurento/user/Consumer.java
@@ -17,12 +17,12 @@ import com.alibaba.dubbo.rpc.service.EchoService;
 import java.util.List;
 
 public class Consumer {
-    //瀹氫箟涓€涓鏈夊彉閲� 锛圫pring涓姹傦級
+    // Define a private variable (Required in Spring)
     private UserProvider userProvider;
     private UserProvider userProvider1;
     private UserProvider userProvider2;
 
-    //Spring娉ㄥ叆锛圫pring涓姹傦級
+    // Spring DI (Required in Spring)
     public void setUserProvider(UserProvider u) {
         this.userProvider = u;
     }
@@ -33,7 +33,7 @@ public class Consumer {
         this.userProvider2 = u;
     }
 
-    //鍚姩consumer鐨勫叆鍙e嚱鏁�(鍦ㄩ厤缃枃浠朵腑鎸囧畾)
+    // Start the entry function for consumer (Specified in the configuration file)
     public void start() throws Exception {
         System.out.println("\n\ntest");
         testGetUser();
diff --git a/examples/general/dubbo/java-server/src/main/java/com/ikurento/user/UserProviderAnotherImpl.java b/examples/general/dubbo/java-server/src/main/java/com/ikurento/user/UserProviderAnotherImpl.java
index d600545c5084a40f1318e47a6a1c20bfcd6d36bc..04729fb7a33abe9738ccfdd48a7b2b19028587da 100644
--- a/examples/general/dubbo/java-server/src/main/java/com/ikurento/user/UserProviderAnotherImpl.java
+++ b/examples/general/dubbo/java-server/src/main/java/com/ikurento/user/UserProviderAnotherImpl.java
@@ -9,8 +9,8 @@ import org.slf4j.LoggerFactory;
 import java.util.*;
 
 public class UserProviderAnotherImpl implements UserProvider {
-    // private static final Logger logger = LoggerFactory.getLogger(getClass()); // 鍙緭鍑哄埌dubbo鐨刲og(logs/server.log)
-    private static final Logger logger = LoggerFactory.getLogger("userLogger"); // 杈撳嚭鍒皍ser-server.log
+    // private static final Logger logger = LoggerFactory.getLogger(getClass()); // Only output to dubbo's log(logs/server.log)
+    private static final Logger logger = LoggerFactory.getLogger("userLogger"); // Output to user-server.log
 
     private Map<String, User> userMap = new HashMap<String, User>();
 
diff --git a/examples/general/dubbo/java-server/src/main/java/com/ikurento/user/UserProviderImpl.java b/examples/general/dubbo/java-server/src/main/java/com/ikurento/user/UserProviderImpl.java
index 47a4e2d9732aa8d8d9279d47af5bb4fb3db37195..1efbf823740f5e3e4e82931a48bfc02ee9e78029 100644
--- a/examples/general/dubbo/java-server/src/main/java/com/ikurento/user/UserProviderImpl.java
+++ b/examples/general/dubbo/java-server/src/main/java/com/ikurento/user/UserProviderImpl.java
@@ -14,8 +14,8 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 public class UserProviderImpl implements UserProvider {
-    // private static final Logger logger = LoggerFactory.getLogger(getClass()); // 鍙緭鍑哄埌dubbo鐨刲og(logs/server.log)
-    private static final Logger LOG = LoggerFactory.getLogger("UserLogger"); // 杈撳嚭鍒皍ser-server.log
+    // private static final Logger logger = LoggerFactory.getLogger(getClass()); // Only output to dubbo's log(logs/server.log)
+    private static final Logger LOG = LoggerFactory.getLogger("UserLogger"); // Output to user-server.log
     Map<String, User> userMap = new HashMap<String, User>();
 
     public UserProviderImpl() {
diff --git a/examples/general/jsonrpc/go-client/app/client.go b/examples/general/jsonrpc/go-client/app/client.go
index b781f860bc41cdc616f8836499d584056c29af43..abbe586de94a26c9d1a71892b38844662ae4863a 100644
--- a/examples/general/jsonrpc/go-client/app/client.go
+++ b/examples/general/jsonrpc/go-client/app/client.go
@@ -78,7 +78,7 @@ func initSignal() {
 				os.Exit(1)
 			})
 
-			// 瑕佷箞fastFailTimeout鏃堕棿鍐呮墽琛屽畬姣曚笅闈㈢殑閫昏緫鐒跺悗绋嬪簭閫€鍑猴紝瑕佷箞鎵ц涓婇潰鐨勮秴鏃跺嚱鏁扮▼搴忓己琛岄€€鍑�
+			// The program exits normally or timeout forcibly exits.
 			fmt.Println("app exit now...")
 			return
 		}
diff --git a/examples/general/jsonrpc/go-server/app/server.go b/examples/general/jsonrpc/go-server/app/server.go
index 231082b5b4accbbb9aa78b2241416f0c8014c5ef..e36b6efe9d115d8352f09f1f5011ea00d92f0d13 100644
--- a/examples/general/jsonrpc/go-server/app/server.go
+++ b/examples/general/jsonrpc/go-server/app/server.go
@@ -69,7 +69,7 @@ func initSignal() {
 				os.Exit(1)
 			})
 
-			// 瑕佷箞fastFailTimeout鏃堕棿鍐呮墽琛屽畬姣曚笅闈㈢殑閫昏緫鐒跺悗绋嬪簭閫€鍑猴紝瑕佷箞鎵ц涓婇潰鐨勮秴鏃跺嚱鏁扮▼搴忓己琛岄€€鍑�
+			// The program exits normally or timeout forcibly exits.
 			fmt.Println("provider app exit now...")
 			return
 		}
diff --git a/examples/general/jsonrpc/java-client/src/main/java/com/ikurento/user/Consumer.java b/examples/general/jsonrpc/java-client/src/main/java/com/ikurento/user/Consumer.java
index 2c7b27b5e6a494420a57d6614a8f76017fccbea7..1a38dbfba906a951fcf8bd481650608bd5d35c9f 100644
--- a/examples/general/jsonrpc/java-client/src/main/java/com/ikurento/user/Consumer.java
+++ b/examples/general/jsonrpc/java-client/src/main/java/com/ikurento/user/Consumer.java
@@ -17,12 +17,12 @@ import com.alibaba.dubbo.rpc.service.EchoService;
 import java.util.List;
 
 public class Consumer {
-    //瀹氫箟涓€涓鏈夊彉閲� 锛圫pring涓姹傦級
+    // Define a private variable (Required in Spring)
     private UserProvider userProvider;
     private UserProvider userProvider1;
     private UserProvider userProvider2;
 
-    //Spring娉ㄥ叆锛圫pring涓姹傦級
+    // Spring DI (Required in Spring)
     public void setUserProvider(UserProvider u) {
         this.userProvider = u;
     }
@@ -33,7 +33,7 @@ public class Consumer {
         this.userProvider2 = u;
     }
 
-    //鍚姩consumer鐨勫叆鍙e嚱鏁�(鍦ㄩ厤缃枃浠朵腑鎸囧畾)
+    // Start the entry function for consumer (Specified in the configuration file)
     public void start() throws Exception {
         System.out.println("\n\ntest");
         testGetUser();
diff --git a/examples/general/jsonrpc/java-server/src/main/java/com/ikurento/user/UserProviderAnotherImpl.java b/examples/general/jsonrpc/java-server/src/main/java/com/ikurento/user/UserProviderAnotherImpl.java
index 753a6f89a5f60e0f4884711d4c3b79e52ed2f094..9e22b78b3de2412c8aefbfdbb37d2886d016a0f4 100644
--- a/examples/general/jsonrpc/java-server/src/main/java/com/ikurento/user/UserProviderAnotherImpl.java
+++ b/examples/general/jsonrpc/java-server/src/main/java/com/ikurento/user/UserProviderAnotherImpl.java
@@ -9,8 +9,8 @@ import org.slf4j.LoggerFactory;
 import java.util.*;
 
 public class UserProviderAnotherImpl implements UserProvider {
-    // private static final Logger logger = LoggerFactory.getLogger(getClass()); // 鍙緭鍑哄埌dubbo鐨刲og(logs/server.log)
-    private static final Logger logger = LoggerFactory.getLogger("userLogger"); // 杈撳嚭鍒皍ser-server.log
+    // private static final Logger logger = LoggerFactory.getLogger(getClass()); // Only output to dubbo's log(logs/server.log)
+    private static final Logger logger = LoggerFactory.getLogger("userLogger"); // Output to user-server.log
 
     private Map<String, User> userMap = new HashMap<String, User>();
 
diff --git a/examples/general/jsonrpc/java-server/src/main/java/com/ikurento/user/UserProviderImpl.java b/examples/general/jsonrpc/java-server/src/main/java/com/ikurento/user/UserProviderImpl.java
index 960c678cf76cf4bafb3de9d5ce2a587b61aa1bac..1ff8afa62220463932872df2172b35e4e16a4591 100644
--- a/examples/general/jsonrpc/java-server/src/main/java/com/ikurento/user/UserProviderImpl.java
+++ b/examples/general/jsonrpc/java-server/src/main/java/com/ikurento/user/UserProviderImpl.java
@@ -14,8 +14,8 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 public class UserProviderImpl implements UserProvider {
-    // private static final Logger logger = LoggerFactory.getLogger(getClass()); // 鍙緭鍑哄埌dubbo鐨刲og(logs/server.log)
-    private static final Logger LOG = LoggerFactory.getLogger("UserLogger"); // 杈撳嚭鍒皍ser-server.log
+    // private static final Logger logger = LoggerFactory.getLogger(getClass()); // Only output to dubbo's log(logs/server.log)
+    private static final Logger LOG = LoggerFactory.getLogger("UserLogger"); // Output to user-server.log
     Map<String, User> userMap = new HashMap<String, User>();
 
     public UserProviderImpl() {
diff --git a/examples/helloworld/dubbo/go-server/app/server.go b/examples/helloworld/dubbo/go-server/app/server.go
index 29f2ad57ead58c09614ccf5f7098c77612085449..f02a6ba05e8723410c985823caafe88192f5af7e 100644
--- a/examples/helloworld/dubbo/go-server/app/server.go
+++ b/examples/helloworld/dubbo/go-server/app/server.go
@@ -69,7 +69,7 @@ func initSignal() {
 				os.Exit(1)
 			})
 
-			// 瑕佷箞fastFailTimeout鏃堕棿鍐呮墽琛屽畬姣曚笅闈㈢殑閫昏緫鐒跺悗绋嬪簭閫€鍑猴紝瑕佷箞鎵ц涓婇潰鐨勮秴鏃跺嚱鏁扮▼搴忓己琛岄€€鍑�
+			// The program exits normally or timeout forcibly exits.
 			fmt.Println("provider app exit now...")
 			return
 		}
diff --git a/examples/helloworld/dubbo/java-server/src/main/java/com/ikurento/user/UserProviderImpl.java b/examples/helloworld/dubbo/java-server/src/main/java/com/ikurento/user/UserProviderImpl.java
index ddbccab37bbe2cc59b584e59ef317d5bdaeae32d..d57ae54e386c981656ab68c1133dd37a9cc6711a 100644
--- a/examples/helloworld/dubbo/java-server/src/main/java/com/ikurento/user/UserProviderImpl.java
+++ b/examples/helloworld/dubbo/java-server/src/main/java/com/ikurento/user/UserProviderImpl.java
@@ -6,7 +6,7 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 public class UserProviderImpl implements UserProvider {
-    private static final Logger LOG = LoggerFactory.getLogger("UserLogger"); // 杈撳嚭鍒皍ser-server.log
+    private static final Logger LOG = LoggerFactory.getLogger("UserLogger"); // Output to user埌user-server.log
 
     public User GetUser(String userId) {
         return new User(userId, "zhangsan", 18);
diff --git a/go.mod b/go.mod
index 0cb5727894496a4253c459685f209327406f7bcc..94be8ac01b3e448652e24f0e4540fd67f57d3bf8 100644
--- a/go.mod
+++ b/go.mod
@@ -2,17 +2,48 @@ module github.com/apache/dubbo-go
 
 require (
 	github.com/Workiva/go-datastructures v1.0.50
+	github.com/aliyun/alibaba-cloud-sdk-go v0.0.0-20190802083043-4cd0c391755e // indirect
 	github.com/apache/dubbo-go-hessian2 v1.2.5-0.20190731020727-1697039810c8
+	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
+	github.com/coreos/go-semver v0.3.0 // indirect
+	github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f // indirect
+	github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f // indirect
+	github.com/dgrijalva/jwt-go v3.2.0+incompatible // indirect
 	github.com/dubbogo/getty v1.2.2
 	github.com/dubbogo/gost v1.1.1
+	github.com/fastly/go-utils v0.0.0-20180712184237-d95a45783239 // indirect
+	github.com/go-errors/errors v1.0.1 // indirect
+	github.com/gogo/protobuf v1.2.1 // indirect
+	github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6 // indirect
 	github.com/golang/mock v1.3.1
+	github.com/google/btree v1.0.0 // indirect
+	github.com/grpc-ecosystem/go-grpc-middleware v1.0.0 // indirect
+	github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 // indirect
+	github.com/grpc-ecosystem/grpc-gateway v1.9.5 // indirect
 	github.com/hashicorp/consul/api v1.1.0
-	github.com/hashicorp/consul/sdk v0.1.1
+	github.com/jehiah/go-strftime v0.0.0-20171201141054-1d33003b3869 // indirect
+	github.com/jonboulle/clockwork v0.1.0 // indirect
+	github.com/lestrrat/go-envload v0.0.0-20180220120943-6ed08b54a570 // indirect
+	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/reflect2 v1.0.1 // indirect
+	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
 	github.com/samuel/go-zookeeper v0.0.0-20180130194729-c4fab1ac1bec
+	github.com/soheilhy/cmux v0.1.4 // indirect
 	github.com/stretchr/testify v1.3.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
+	go.etcd.io/bbolt v1.3.3 // indirect
+	go.etcd.io/etcd v3.3.13+incompatible
 	go.uber.org/atomic v1.4.0
 	go.uber.org/zap v1.10.0
+	google.golang.org/grpc v1.22.1
 	gopkg.in/yaml.v2 v2.2.2
 )
diff --git a/go.sum b/go.sum
index 9bdb8678e09afd06cce87f24d3b10def690ec834..1273e25b48d0e18251e54e9c80dcc30102c8b71f 100644
--- a/go.sum
+++ b/go.sum
@@ -1,28 +1,90 @@
+cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
+github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
 github.com/Workiva/go-datastructures v1.0.50 h1:slDmfW6KCHcC7U+LP3DDBbm4fqTwZGn1beOFPfGaLvo=
 github.com/Workiva/go-datastructures v1.0.50/go.mod h1:Z+F2Rca0qCsVYDS8z7bAGm8f3UkzuWYS/oBZz5a7VVA=
+github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
+github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
+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.20190731020727-1697039810c8 h1:7zJlM+8bpCAUhv03TZnXkT4MLlLWng1s7An8CLuN73E=
 github.com/apache/dubbo-go-hessian2 v1.2.5-0.20190731020727-1697039810c8/go.mod h1:LWnndnrFXZmJLAzoyNAPNHSIJ1KOHVkTSsHgC3YYWlo=
 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 h1:8GUt8eRujhVEGZFFEjBj46YV4rDjvGrNxb0KMWYkL2I=
 github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
 github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
+github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f/go.mod h1:AuiFmCCPBSrqvVMvuqFuk0qogytodnVFVSN5CeJB8Gc=
+github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
+github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
+github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
+github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
 github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
+github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23 h1:D21IyuvjDCshj1/qq+pCNd3VZOAEI9jy6Bi131YlXgI=
+github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s=
+github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
+github.com/coreos/bbolt v1.3.3 h1:n6AiVyVRKQFNb6mJlwESEvvLoDyiTzXX7ORAUlkeBdY=
+github.com/coreos/bbolt v1.3.3/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
+github.com/coreos/etcd v3.3.13+incompatible h1:8F3hqu9fGYLBifCmRCJsicFqDx/D68Rt3q1JMazcgBQ=
+github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
+github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM=
+github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
+github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f h1:JOrtw2xFKzlg+cbHpyrpLDmnN1HqhBfnX7WDiW7eG2c=
+github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
+github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f h1:lBNOc5arjvs8E5mO2tbpBpLoyyu8B6e44T7hJy6potg=
+github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
 github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
+github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
 github.com/dubbogo/getty v1.2.2 h1:qDC9WXjxcs5NPvWZz2ruVKBKr2r1Jjm6i0Sq//CQwbE=
 github.com/dubbogo/getty v1.2.2/go.mod h1:K4b3MkGLf7T+lMgQNFgpg0dI1Wvv1PTisFs1Psf86kU=
 github.com/dubbogo/gost v1.1.1 h1:JCM7vx5edPIjDA5ovJTuzEEXuw2t7xLyrlgi2mi5jHI=
 github.com/dubbogo/gost v1.1.1/go.mod h1:R7wZm1DrmrKGr50mBZVcg6C9ekG8aL5hP+sgWcIDwQg=
+github.com/fastly/go-utils v0.0.0-20180712184237-d95a45783239 h1:Ghm4eQYC0nEPnSJdVkTrXpu9KtoVCSo1hg7mtI7G9KU=
+github.com/fastly/go-utils v0.0.0-20180712184237-d95a45783239/go.mod h1:Gdwt2ce0yfBxPvZrHkprdPPTTS3N5rwmLE8T22KBXlw=
 github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
+github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
+github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
+github.com/go-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w=
+github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
+github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
+github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
+github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
+github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
+github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
+github.com/gogo/protobuf v1.2.1 h1:/s5zKNz0uPFCZ5hddgPdo2TK2TVrUNMn0OOX8/aZMTE=
+github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
+github.com/goji/httpauth v0.0.0-20160601135302-2da839ab0f4d/go.mod h1:nnjvkQ9ptGaCkuDUx6wNykzzlUixGxvkme+H/lnzb+A=
+github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58=
+github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
+github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6 h1:ZgQEtGgCBiWRM39fZuwSd1LwSqqSW0hOdXCYYDX0R3I=
+github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
+github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
 github.com/golang/mock v1.3.1 h1:qGJ6qTW+x6xX/my+8YUVl4WNpX9B7+/l2tRsHGZ7f2s=
 github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
+github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs=
+github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
 github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4=
 github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
-github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c h1:964Od4U6p2jUkFxvCydnIczKteheJEzHRToSGK3Bnlw=
 github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
+github.com/google/btree v1.0.0 h1:0udJVsspx3VBr5FwtLhQQtuAsVc79tTq0ocGIPAU6qo=
+github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
+github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
+github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
+github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
+github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
+github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
 github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q=
 github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
+github.com/grpc-ecosystem/go-grpc-middleware v1.0.0 h1:Iju5GlWwrvL6UBg4zJJt3btmonfrMlCDdsejg4CZE7c=
+github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
+github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho=
+github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
+github.com/grpc-ecosystem/grpc-gateway v1.9.5 h1:UImYN5qQ8tuGpGE16ZmjvcTtTw24zw1QAp/SlnNrZhI=
+github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
 github.com/hashicorp/consul/api v1.1.0 h1:BNQPM9ytxj6jbjjdRPioQ94T6YXriSopn0i8COv6SRA=
 github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q=
 github.com/hashicorp/consul/sdk v0.1.1 h1:LnuDWGNsoajlhGyHJvuWW6FVqRl8JOTPqS6CPTsYjhY=
@@ -54,10 +116,41 @@ github.com/hashicorp/memberlist v0.1.3 h1:EmmoJme1matNzb+hMpDuR/0sbJSUisxyqBGG67
 github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
 github.com/hashicorp/serf v0.8.2 h1:YZ7UKsJv+hKjqGVUUbtE3HNj79Eln2oQ75tniF6iPt0=
 github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
+github.com/jehiah/go-strftime v0.0.0-20171201141054-1d33003b3869 h1:IPJ3dvxmJ4uczJe5YQdrYB16oTJlGSC/OyZDqUk9xX4=
+github.com/jehiah/go-strftime v0.0.0-20171201141054-1d33003b3869/go.mod h1:cJ6Cj7dQo+O6GJNiMx+Pa94qKj+TG8ONdKHgMNIyyag=
+github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af h1:pmfjZENx5imkbgOkpRUYLnmbU7UEFbjtDA2hxJ1ichM=
+github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
+github.com/jonboulle/clockwork v0.1.0 h1:VKV+ZcuP6l3yW9doeqz6ziZGgcynBVQO+obU0+0hcPo=
+github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
+github.com/json-iterator/go v1.1.5/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
+github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
+github.com/json-iterator/go v1.1.7 h1:KfgG9LzI+pYjr4xvmz/5H4FXjokeP+rlHLhv3iH62Fo=
+github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
+github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
+github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
+github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
+github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
+github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
+github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk=
+github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
+github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
+github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
+github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
+github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
+github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
+github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
+github.com/lestrrat/go-envload v0.0.0-20180220120943-6ed08b54a570 h1:0iQektZGS248WXmGIYOwRXSQhD4qn3icjMpuxwO7qlo=
+github.com/lestrrat/go-envload v0.0.0-20180220120943-6ed08b54a570/go.mod h1:BLt8L9ld7wVsvEWQbuLrUZnCMnUmLZ+CGDzKtclrTlE=
+github.com/lestrrat/go-file-rotatelogs v0.0.0-20180223000712-d3151e2a480f h1:sgUSP4zdTUZYZgAGGtN5Lxk92rK+JUFOwf+FT99EEI4=
+github.com/lestrrat/go-file-rotatelogs v0.0.0-20180223000712-d3151e2a480f/go.mod h1:UGmTpUd3rjbtfIpwAPrcfmGf/Z1HS95TATB+m57TPB8=
+github.com/lestrrat/go-strftime v0.0.0-20180220042222-ba3bf9c1d042 h1:Bvq8AziQ5jFF4BHGAEDSqwPW1NJS3XshxbRCxtjFAZc=
+github.com/lestrrat/go-strftime v0.0.0-20180220042222-ba3bf9c1d042/go.mod h1:TPpsiPUEh0zFL1Snz4crhMlBe60PYxRHr5oFF3rRYg0=
 github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4=
 github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
 github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
 github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
+github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
+github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
 github.com/miekg/dns v1.0.14 h1:9jZdLNd/P4+SfEJ0TNyxYpsK8N4GtfylBLqtbYN1sbA=
 github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
 github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
@@ -70,46 +163,132 @@ github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0Qu
 github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
 github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
 github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
+github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
+github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
+github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
+github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
+github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
+github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
+github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
+github.com/nacos-group/nacos-sdk-go v0.0.0-20190723125407-0242d42e3dbb h1:lbmvw8r9W55w+aQgWn35W1nuleRIECMoqUrmwAOAvoI=
+github.com/nacos-group/nacos-sdk-go v0.0.0-20190723125407-0242d42e3dbb/go.mod h1:CEkSvEpoveoYjA81m4HNeYQ0sge0LFGKSEqO3JKHllo=
 github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c h1:Lgl0gzECD8GnQ5QCWA8o6BtfL6mDH5rQgM4/fX3avOs=
 github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
+github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
 github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
 github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
 github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
 github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
+github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
+github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
+github.com/prometheus/client_golang v1.1.0 h1:BQ53HtBmfOitExawJ6LokA4x8ov/z0SYYb0+HxJfRI8=
+github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g=
+github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
+github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90 h1:S/YWwWx/RA8rT8tKFRuGUZhuA90OyIBpPCXkcbwU8DE=
+github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
+github.com/prometheus/common v0.6.0 h1:kRhiuYSXR3+uv2IbVbZhUxK5zVD/2pp3Gd2PpvPkpEo=
+github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc=
+github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
+github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
+github.com/prometheus/procfs v0.0.3 h1:CTwfnzjQ+8dS6MhHHu4YswVAD99sL2wjPqP+VkURmKE=
+github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ=
+github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
 github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
 github.com/samuel/go-zookeeper v0.0.0-20180130194729-c4fab1ac1bec h1:6ncX5ko6B9LntYM0YBRXkiSaZMmLYeZ/NWcmeB43mMY=
 github.com/samuel/go-zookeeper v0.0.0-20180130194729-c4fab1ac1bec/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E=
+github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww=
+github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
 github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 h1:nn5Wsu0esKSJiIVhscUtVbo7ada43DJhG55ua/hjS5I=
 github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
+github.com/sirupsen/logrus v1.2.0 h1:juTguoYk5qI21pwyTXY3B3Y5cOTH3ZUyZCg1v/mihuo=
+github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
+github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=
+github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
+github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a h1:pa8hGb/2YqsZKovtsgrwcDH1RZhVbTKCjLp47XpqCDs=
+github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
+github.com/soheilhy/cmux v0.1.4 h1:0HKaf1o97UwFjHH9o5XsHUOF+tqmdA7KEzXLpiyaw0E=
+github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
 github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
 github.com/stretchr/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/tebeka/strftime v0.1.3 h1:5HQXOqWKYRFfNyBMNVc9z5+QzuBtIXy03psIhtdJYto=
+github.com/tebeka/strftime v0.1.3/go.mod h1:7wJm3dZlpr4l/oVK0t1HYIc4rMzQ2XJlOMIUJUJH6XQ=
+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=
+github.com/toolkits/concurrent v0.0.0-20150624120057-a4371d70e3e3/go.mod h1:QDlpd3qS71vYtakd2hmdpqhJ9nwv6mD6A30bQ1BPBFE=
+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=
+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=
+go.etcd.io/etcd v3.3.13+incompatible/go.mod h1:yaeTdrJi5lOmYerz05bd8+V7KubZs8YSFZfzsF9A6aI=
 go.uber.org/atomic v1.4.0 h1:cxzIVoETapQEqDhQu3QfnvXAV4AlzcvUCxkVUFw3+EU=
 go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
 go.uber.org/multierr v1.1.0 h1:HoEmRHQPVSqub6w2z2d2EOVs2fjyFRGyofhKuyDq0QI=
 go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
 go.uber.org/zap v1.10.0 h1:ORx85nbTijNz8ljznvCMR1ZBIPKFn3jQrag10X2AsuM=
 go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
+golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
 golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M=
 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
+golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
-golang.org/x/net v0.0.0-20190320064053-1272bf9dcd53 h1:kcXqo9vE6fsZY5X5Rd7R1l7fTgnWaDCVmln65REefiE=
 golang.org/x/net v0.0.0-20190320064053-1272bf9dcd53/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190613194153-d28f0bde5980 h1:dfGZHvZk057jK2MCeWus/TowKpJ8y4AmooUzdBSR9GU=
+golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
+golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEhagSSnXWGV915qUMm9mrU=
 golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a h1:1BGLXjeY4akVXGgbC9HugT3Jv3hCI0z56oJR5vAMgBU=
+golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3 h1:4y9KwBHBgBNwDbtu44R5o1fdOCQUEXhbk/P4A9WmJq0=
+golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/time v0.0.0-20190308202827-9d24e82272b4 h1:SvFZT6jyqRaOeXpc5h/JSfZenJ2O330aBsf7JfSUXmQ=
+golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
 golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
-gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
+golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
+google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8 h1:Nw54tB0rB7hY/N0NQvRW8DG4Yk3Q6T9cu9RcFQDu1tc=
+google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
+google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
+google.golang.org/grpc v1.22.1 h1:/7cs52RnTJmD43s3uxzlq2U7nqVTd/37viQwMrMNlOM=
+google.golang.org/grpc v1.22.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
+gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
+gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/ini.v1 v1.42.0 h1:7N3gPTt50s8GuLortA00n8AqRTk75qOP98+mTPpgzRk=
+gopkg.in/ini.v1 v1.42.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
+gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
+gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
+gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
 gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
diff --git a/protocol/dubbo/listener.go b/protocol/dubbo/listener.go
index c0d5fe29169606c0655ac60e571ba9f59912ffa0..aa208284825665dae4c23f871117a7f34c548d16 100644
--- a/protocol/dubbo/listener.go
+++ b/protocol/dubbo/listener.go
@@ -91,6 +91,7 @@ func (h *RpcClientHandler) OnMessage(session getty.Session, pkg interface{}) {
 		if p.Err != nil {
 			logger.Errorf("rpc heartbeat response{error: %#v}", p.Err)
 		}
+		h.conn.pool.rpcClient.removePendingResponse(SequenceType(p.Header.ID))
 		return
 	}
 	logger.Debugf("get rpc response{header: %#v, body: %#v}", p.Header, p.Body)
diff --git a/registry/etcdv3/listener.go b/registry/etcdv3/listener.go
new file mode 100644
index 0000000000000000000000000000000000000000..a8f2facc1aa43db4daea77c03f332df16f302431
--- /dev/null
+++ b/registry/etcdv3/listener.go
@@ -0,0 +1,88 @@
+package etcdv3
+
+import (
+	"context"
+	"strings"
+)
+
+import (
+	perrors "github.com/pkg/errors"
+)
+
+import (
+	"github.com/apache/dubbo-go/common"
+	"github.com/apache/dubbo-go/common/logger"
+	"github.com/apache/dubbo-go/registry"
+	"github.com/apache/dubbo-go/remoting"
+)
+
+type dataListener struct {
+	interestedURL []*common.URL
+	listener      remoting.ConfigurationListener
+}
+
+func NewRegistryDataListener(listener remoting.ConfigurationListener) *dataListener {
+	return &dataListener{listener: listener, interestedURL: []*common.URL{}}
+}
+
+func (l *dataListener) AddInterestedURL(url *common.URL) {
+	l.interestedURL = append(l.interestedURL, url)
+}
+
+func (l *dataListener) DataChange(eventType remoting.Event) bool {
+
+	url := eventType.Path[strings.Index(eventType.Path, "/providers/")+len("/providers/"):]
+	serviceURL, err := common.NewURL(context.Background(), url)
+	if err != nil {
+		logger.Warnf("Listen NewURL(r{%s}) = error{%v}", eventType.Path, err)
+		return false
+	}
+
+	for _, v := range l.interestedURL {
+		if serviceURL.URLEqual(*v) {
+			l.listener.Process(&remoting.ConfigChangeEvent{Key: eventType.Path, Value: serviceURL, ConfigType: eventType.Action})
+			return true
+		}
+	}
+
+	return false
+}
+
+type configurationListener struct {
+	registry *etcdV3Registry
+	events   chan *remoting.ConfigChangeEvent
+}
+
+func NewConfigurationListener(reg *etcdV3Registry) *configurationListener {
+	// add a new waiter
+	reg.wg.Add(1)
+	return &configurationListener{registry: reg, events: make(chan *remoting.ConfigChangeEvent, 32)}
+}
+func (l *configurationListener) Process(configType *remoting.ConfigChangeEvent) {
+	l.events <- configType
+}
+
+func (l *configurationListener) Next() (*registry.ServiceEvent, error) {
+	for {
+		select {
+		case <-l.registry.done:
+			logger.Warnf("listener's etcd client connection is broken, so etcd event listener exit now.")
+			return nil, perrors.New("listener stopped")
+
+		case e := <-l.events:
+			logger.Infof("got etcd event %#v", e)
+			if e.ConfigType == remoting.EventTypeDel {
+				select {
+				case <-l.registry.done:
+					logger.Warnf("update @result{%s}. But its connection to registry is invalid", e.Value)
+				default:
+				}
+				continue
+			}
+			return &registry.ServiceEvent{Action: e.ConfigType, Service: e.Value.(common.URL)}, nil
+		}
+	}
+}
+func (l *configurationListener) Close() {
+	l.registry.wg.Done()
+}
diff --git a/registry/etcdv3/listener_test.go b/registry/etcdv3/listener_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..0ac8fc475e454e737e0ea03301709457561e961c
--- /dev/null
+++ b/registry/etcdv3/listener_test.go
@@ -0,0 +1,71 @@
+package etcdv3
+
+import (
+	"context"
+	"testing"
+	"time"
+)
+
+import (
+	"github.com/dubbogo/getty"
+	"github.com/stretchr/testify/suite"
+	"go.etcd.io/etcd/embed"
+)
+
+import (
+	"github.com/apache/dubbo-go/common"
+	"github.com/apache/dubbo-go/remoting"
+)
+
+type RegistryTestSuite struct {
+	suite.Suite
+	etcd *embed.Etcd
+}
+
+// start etcd server
+func (suite *RegistryTestSuite) SetupSuite() {
+
+	t := suite.T()
+
+	cfg := embed.NewConfig()
+	cfg.Dir = "/tmp/default.etcd"
+	e, err := embed.StartEtcd(cfg)
+	if err != nil {
+		t.Fatal(err)
+	}
+	select {
+	case <-e.Server.ReadyNotify():
+		t.Log("Server is ready!")
+	case <-getty.GetTimeWheel().After(60 * time.Second):
+		e.Server.Stop() // trigger a shutdown
+		t.Logf("Server took too long to start!")
+	}
+
+	suite.etcd = e
+	return
+}
+
+// stop etcd server
+func (suite *RegistryTestSuite) TearDownSuite() {
+	suite.etcd.Close()
+}
+
+func (suite *RegistryTestSuite) TestDataChange() {
+
+	t := suite.T()
+
+	listener := NewRegistryDataListener(&MockDataListener{})
+	url, _ := common.NewURL(context.Background(), "jsonrpc%3A%2F%2F127.0.0.1%3A20001%2Fcom.ikurento.user.UserProvider%3Fanyhost%3Dtrue%26app.version%3D0.0.1%26application%3DBDTService%26category%3Dproviders%26cluster%3Dfailover%26dubbo%3Ddubbo-provider-golang-2.6.0%26environment%3Ddev%26group%3D%26interface%3Dcom.ikurento.user.UserProvider%26ip%3D10.32.20.124%26loadbalance%3Drandom%26methods.GetUser.loadbalance%3Drandom%26methods.GetUser.retries%3D1%26methods.GetUser.weight%3D0%26module%3Ddubbogo%2Buser-info%2Bserver%26name%3DBDTService%26organization%3Dikurento.com%26owner%3DZX%26pid%3D74500%26retries%3D0%26service.filter%3Decho%26side%3Dprovider%26timestamp%3D1560155407%26version%3D%26warmup%3D100")
+	listener.AddInterestedURL(&url)
+	if !listener.DataChange(remoting.Event{Path: "/dubbo/com.ikurento.user.UserProvider/providers/jsonrpc%3A%2F%2F127.0.0.1%3A20001%2Fcom.ikurento.user.UserProvider%3Fanyhost%3Dtrue%26app.version%3D0.0.1%26application%3DBDTService%26category%3Dproviders%26cluster%3Dfailover%26dubbo%3Ddubbo-provider-golang-2.6.0%26environment%3Ddev%26group%3D%26interface%3Dcom.ikurento.user.UserProvider%26ip%3D10.32.20.124%26loadbalance%3Drandom%26methods.GetUser.loadbalance%3Drandom%26methods.GetUser.retries%3D1%26methods.GetUser.weight%3D0%26module%3Ddubbogo%2Buser-info%2Bserver%26name%3DBDTService%26organization%3Dikurento.com%26owner%3DZX%26pid%3D74500%26retries%3D0%26service.filter%3Decho%26side%3Dprovider%26timestamp%3D1560155407%26version%3D%26warmup%3D100"}) {
+		t.Fatal("data change not ok")
+	}
+}
+
+func TestRegistrySuite(t *testing.T) {
+	suite.Run(t, &RegistryTestSuite{})
+}
+
+type MockDataListener struct{}
+
+func (*MockDataListener) Process(configType *remoting.ConfigChangeEvent) {}
diff --git a/registry/etcdv3/registry.go b/registry/etcdv3/registry.go
new file mode 100644
index 0000000000000000000000000000000000000000..c716653cf9220256f28468f8e322a499eea61299
--- /dev/null
+++ b/registry/etcdv3/registry.go
@@ -0,0 +1,326 @@
+package etcdv3
+
+import (
+	"fmt"
+	"net/url"
+	"os"
+	"path"
+	"strconv"
+	"strings"
+	"sync"
+	"time"
+)
+
+import (
+	perrors "github.com/pkg/errors"
+)
+
+import (
+	"github.com/apache/dubbo-go/common"
+	"github.com/apache/dubbo-go/common/constant"
+	"github.com/apache/dubbo-go/common/extension"
+	"github.com/apache/dubbo-go/common/logger"
+	"github.com/apache/dubbo-go/common/utils"
+	"github.com/apache/dubbo-go/registry"
+	"github.com/apache/dubbo-go/remoting/etcdv3"
+	"github.com/apache/dubbo-go/version"
+)
+
+var (
+	processID = ""
+	localIP   = ""
+)
+
+const Name = "etcdv3"
+
+func init() {
+	processID = fmt.Sprintf("%d", os.Getpid())
+	localIP, _ = utils.GetLocalIP()
+	extension.SetRegistry(Name, newETCDV3Registry)
+}
+
+type etcdV3Registry struct {
+	*common.URL
+	birth int64 // time of file birth, seconds since Epoch; 0 if unknown
+
+	cltLock  sync.Mutex
+	client   *etcdv3.Client
+	services map[string]common.URL // service name + protocol -> service config
+
+	listenerLock   sync.Mutex
+	listener       *etcdv3.EventListener
+	dataListener   *dataListener
+	configListener *configurationListener
+
+	wg   sync.WaitGroup // wg+done for etcd client restart
+	done chan struct{}
+}
+
+func (r *etcdV3Registry) Client() *etcdv3.Client {
+	return r.client
+}
+func (r *etcdV3Registry) SetClient(client *etcdv3.Client) {
+	r.client = client
+}
+func (r *etcdV3Registry) ClientLock() *sync.Mutex {
+	return &r.cltLock
+}
+func (r *etcdV3Registry) WaitGroup() *sync.WaitGroup {
+	return &r.wg
+}
+func (r *etcdV3Registry) GetDone() chan struct{} {
+	return r.done
+}
+func (r *etcdV3Registry) RestartCallBack() bool {
+
+	services := []common.URL{}
+	for _, confIf := range r.services {
+		services = append(services, confIf)
+	}
+
+	flag := true
+	for _, confIf := range services {
+		err := r.Register(confIf)
+		if err != nil {
+			logger.Errorf("(etcdV3ProviderRegistry)register(conf{%#v}) = error{%#v}",
+				confIf, perrors.WithStack(err))
+			flag = false
+			break
+		}
+		logger.Infof("success to re-register service :%v", confIf.Key())
+	}
+	return flag
+}
+
+func newETCDV3Registry(url *common.URL) (registry.Registry, error) {
+
+	timeout, err := time.ParseDuration(url.GetParam(constant.REGISTRY_TIMEOUT_KEY, constant.DEFAULT_REG_TIMEOUT))
+	if err != nil {
+		logger.Errorf("timeout config %v is invalid ,err is %v",
+			url.GetParam(constant.REGISTRY_TIMEOUT_KEY, constant.DEFAULT_REG_TIMEOUT), err.Error())
+		return nil, perrors.WithMessagef(err, "new etcd registry(address:%+v)", url.Location)
+	}
+
+	logger.Infof("etcd address is: %v, timeout is: %s", url.Location, timeout.String())
+
+	r := &etcdV3Registry{
+		URL:      url,
+		birth:    time.Now().UnixNano(),
+		done:     make(chan struct{}),
+		services: make(map[string]common.URL),
+	}
+
+	if err := etcdv3.ValidateClient(
+		r,
+		etcdv3.WithName(etcdv3.RegistryETCDV3Client),
+		etcdv3.WithTimeout(timeout),
+		etcdv3.WithEndpoints(url.Location),
+	); err != nil {
+		return nil, err
+	}
+
+	r.wg.Add(1)
+	go etcdv3.HandleClientRestart(r)
+
+	r.listener = etcdv3.NewEventListener(r.client)
+	r.configListener = NewConfigurationListener(r)
+	r.dataListener = NewRegistryDataListener(r.configListener)
+
+	return r, nil
+}
+
+func (r *etcdV3Registry) GetUrl() common.URL {
+	return *r.URL
+}
+
+func (r *etcdV3Registry) IsAvailable() bool {
+
+	select {
+	case <-r.done:
+		return false
+	default:
+		return true
+	}
+}
+
+func (r *etcdV3Registry) Destroy() {
+
+	if r.configListener != nil {
+		r.configListener.Close()
+	}
+	r.stop()
+}
+
+func (r *etcdV3Registry) stop() {
+
+	close(r.done)
+
+	// close current client
+	r.client.Close()
+
+	r.cltLock.Lock()
+	r.client = nil
+	r.services = nil
+	r.cltLock.Unlock()
+}
+
+func (r *etcdV3Registry) Register(svc common.URL) error {
+
+	role, err := strconv.Atoi(r.URL.GetParam(constant.ROLE_KEY, ""))
+	if err != nil {
+		return perrors.WithMessage(err, "get registry role")
+	}
+
+	r.cltLock.Lock()
+	if _, ok := r.services[svc.Key()]; ok {
+		r.cltLock.Unlock()
+		return perrors.New(fmt.Sprintf("Path{%s} has been registered", svc.Path))
+	}
+	r.cltLock.Unlock()
+
+	switch role {
+	case common.PROVIDER:
+		logger.Debugf("(provider register )Register(conf{%#v})", svc)
+		if err := r.registerProvider(svc); err != nil {
+			return perrors.WithMessage(err, "register provider")
+		}
+	case common.CONSUMER:
+		logger.Debugf("(consumer register )Register(conf{%#v})", svc)
+		if err := r.registerConsumer(svc); err != nil {
+			return perrors.WithMessage(err, "register consumer")
+		}
+	default:
+		return perrors.New(fmt.Sprintf("unknown role %d", role))
+	}
+
+	r.cltLock.Lock()
+	r.services[svc.Key()] = svc
+	r.cltLock.Unlock()
+	return nil
+}
+
+func (r *etcdV3Registry) createDirIfNotExist(k string) error {
+
+	var tmpPath string
+	for _, str := range strings.Split(k, "/")[1:] {
+		tmpPath = path.Join(tmpPath, "/", str)
+		if err := r.client.Create(tmpPath, ""); err != nil {
+			return perrors.WithMessagef(err, "create path %s in etcd", tmpPath)
+		}
+	}
+
+	return nil
+}
+
+func (r *etcdV3Registry) registerConsumer(svc common.URL) error {
+
+	consumersNode := fmt.Sprintf("/dubbo/%s/%s", svc.Service(), common.DubboNodes[common.CONSUMER])
+	if err := r.createDirIfNotExist(consumersNode); err != nil {
+		logger.Errorf("etcd client create path %s: %v", consumersNode, err)
+		return perrors.WithMessage(err, "etcd create consumer nodes")
+	}
+	providersNode := fmt.Sprintf("/dubbo/%s/%s", svc.Service(), common.DubboNodes[common.PROVIDER])
+	if err := r.createDirIfNotExist(providersNode); err != nil {
+		return perrors.WithMessage(err, "create provider node")
+	}
+
+	params := url.Values{}
+
+	params.Add("protocol", svc.Protocol)
+
+	params.Add("category", (common.RoleType(common.CONSUMER)).String())
+	params.Add("dubbo", "dubbogo-consumer-"+version.Version)
+
+	encodedURL := url.QueryEscape(fmt.Sprintf("consumer://%s%s?%s", localIP, svc.Path, params.Encode()))
+	dubboPath := fmt.Sprintf("/dubbo/%s/%s", svc.Service(), (common.RoleType(common.CONSUMER)).String())
+	if err := r.client.Create(path.Join(dubboPath, encodedURL), ""); err != nil {
+		return perrors.WithMessagef(err, "create k/v in etcd (path:%s, url:%s)", dubboPath, encodedURL)
+	}
+
+	return nil
+}
+
+func (r *etcdV3Registry) registerProvider(svc common.URL) error {
+
+	if len(svc.Path) == 0 || len(svc.Methods) == 0 {
+		return perrors.New(fmt.Sprintf("service path %s or service method %s", svc.Path, svc.Methods))
+	}
+
+	var (
+		urlPath    string
+		encodedURL string
+		dubboPath  string
+	)
+
+	providersNode := fmt.Sprintf("/dubbo/%s/%s", svc.Service(), common.DubboNodes[common.PROVIDER])
+	if err := r.createDirIfNotExist(providersNode); err != nil {
+		return perrors.WithMessage(err, "create provider node")
+	}
+
+	params := url.Values{}
+	for k, v := range svc.Params {
+		params[k] = v
+	}
+
+	params.Add("pid", processID)
+	params.Add("ip", localIP)
+	params.Add("anyhost", "true")
+	params.Add("category", (common.RoleType(common.PROVIDER)).String())
+	params.Add("dubbo", "dubbo-provider-golang-"+version.Version)
+	params.Add("side", (common.RoleType(common.PROVIDER)).Role())
+
+	if len(svc.Methods) == 0 {
+		params.Add("methods", strings.Join(svc.Methods, ","))
+	}
+
+	logger.Debugf("provider url params:%#v", params)
+	var host string
+	if len(svc.Ip) == 0 {
+		host = localIP + ":" + svc.Port
+	} else {
+		host = svc.Ip + ":" + svc.Port
+	}
+
+	urlPath = svc.Path
+
+	encodedURL = url.QueryEscape(fmt.Sprintf("%s://%s%s?%s", svc.Protocol, host, urlPath, params.Encode()))
+	dubboPath = fmt.Sprintf("/dubbo/%s/%s", svc.Service(), (common.RoleType(common.PROVIDER)).String())
+
+	if err := r.client.Create(path.Join(dubboPath, encodedURL), ""); err != nil {
+		return perrors.WithMessagef(err, "create k/v in etcd (path:%s, url:%s)", dubboPath, encodedURL)
+	}
+
+	return nil
+}
+
+func (r *etcdV3Registry) Subscribe(svc common.URL) (registry.Listener, error) {
+
+	var (
+		configListener *configurationListener
+	)
+
+	r.listenerLock.Lock()
+	configListener = r.configListener
+	r.listenerLock.Unlock()
+	if r.listener == nil {
+		r.cltLock.Lock()
+		client := r.client
+		r.cltLock.Unlock()
+		if client == nil {
+			return nil, perrors.New("etcd client broken")
+		}
+
+		// new client & listener
+		listener := etcdv3.NewEventListener(r.client)
+
+		r.listenerLock.Lock()
+		r.listener = listener
+		r.listenerLock.Unlock()
+	}
+
+	//register the svc to dataListener
+	r.dataListener.AddInterestedURL(&svc)
+	go r.listener.ListenServiceEvent(fmt.Sprintf("/dubbo/%s/providers", svc.Service()), r.dataListener)
+
+	return configListener, nil
+}
diff --git a/registry/etcdv3/registry_test.go b/registry/etcdv3/registry_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..26204c74ad4305278e33d9c8b50199cfa578bf8a
--- /dev/null
+++ b/registry/etcdv3/registry_test.go
@@ -0,0 +1,112 @@
+package etcdv3
+
+import (
+	"context"
+	"strconv"
+	"testing"
+	"time"
+)
+
+import (
+	"github.com/stretchr/testify/assert"
+)
+
+import (
+	"github.com/apache/dubbo-go/common"
+	"github.com/apache/dubbo-go/common/constant"
+)
+
+func initRegistry(t *testing.T) *etcdV3Registry {
+
+	regurl, err := common.NewURL(context.Background(), "registry://127.0.0.1:2379", common.WithParamsValue(constant.ROLE_KEY, strconv.Itoa(common.PROVIDER)))
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	reg, err := newETCDV3Registry(&regurl)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	out := reg.(*etcdV3Registry)
+	out.client.CleanKV()
+	return out
+}
+
+func (suite *RegistryTestSuite) TestRegister() {
+
+	t := suite.T()
+
+	url, _ := common.NewURL(context.Background(), "dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider", common.WithParamsValue(constant.CLUSTER_KEY, "mock"), common.WithMethods([]string{"GetUser", "AddUser"}))
+
+	reg := initRegistry(t)
+	err := reg.Register(url)
+	children, _, err := reg.client.GetChildrenKVList("/dubbo/com.ikurento.user.UserProvider/providers")
+	if err != nil {
+		t.Fatal(err)
+	}
+	assert.Regexp(t, ".*dubbo%3A%2F%2F127.0.0.1%3A20000%2Fcom.ikurento.user.UserProvider%3Fanyhost%3Dtrue%26category%3Dproviders%26cluster%3Dmock%26dubbo%3Ddubbo-provider-golang-2.6.0%26.*provider", children)
+	assert.NoError(t, err)
+}
+
+func (suite *RegistryTestSuite) TestSubscribe() {
+
+	t := suite.T()
+	regurl, _ := common.NewURL(context.Background(), "registry://127.0.0.1:1111", common.WithParamsValue(constant.ROLE_KEY, strconv.Itoa(common.PROVIDER)))
+	url, _ := common.NewURL(context.Background(), "dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider", common.WithParamsValue(constant.CLUSTER_KEY, "mock"), common.WithMethods([]string{"GetUser", "AddUser"}))
+
+	reg := initRegistry(t)
+	//provider register
+	err := reg.Register(url)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	//consumer register
+	regurl.Params.Set(constant.ROLE_KEY, strconv.Itoa(common.CONSUMER))
+	reg2 := initRegistry(t)
+
+	reg2.Register(url)
+	listener, err := reg2.Subscribe(url)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	serviceEvent, err := listener.Next()
+	if err != nil {
+		t.Fatal(err)
+	}
+	assert.Regexp(t, ".*ServiceEvent{Action{add}.*", serviceEvent.String())
+}
+
+func (suite *RegistryTestSuite) TestConsumerDestory() {
+
+	t := suite.T()
+	url, _ := common.NewURL(context.Background(), "dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider", common.WithParamsValue(constant.CLUSTER_KEY, "mock"), common.WithMethods([]string{"GetUser", "AddUser"}))
+
+	reg := initRegistry(t)
+	_, err := reg.Subscribe(url)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	//listener.Close()
+	time.Sleep(1e9)
+	reg.Destroy()
+
+	assert.Equal(t, false, reg.IsAvailable())
+
+}
+
+func (suite *RegistryTestSuite) TestProviderDestory() {
+
+	t := suite.T()
+	reg := initRegistry(t)
+	url, _ := common.NewURL(context.Background(), "dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider", common.WithParamsValue(constant.CLUSTER_KEY, "mock"), common.WithMethods([]string{"GetUser", "AddUser"}))
+	reg.Register(url)
+
+	//listener.Close()
+	time.Sleep(1e9)
+	reg.Destroy()
+	assert.Equal(t, false, reg.IsAvailable())
+}
diff --git a/registry/nacos/listener.go b/registry/nacos/listener.go
new file mode 100644
index 0000000000000000000000000000000000000000..c42abd0bb16573da33c20c150896f85b3a7edfd0
--- /dev/null
+++ b/registry/nacos/listener.go
@@ -0,0 +1,199 @@
+package nacos
+
+import (
+	"bytes"
+	"net/url"
+	"reflect"
+	"strconv"
+	"sync"
+)
+
+import (
+	"github.com/nacos-group/nacos-sdk-go/clients/naming_client"
+	"github.com/nacos-group/nacos-sdk-go/model"
+	"github.com/nacos-group/nacos-sdk-go/vo"
+	perrors "github.com/pkg/errors"
+)
+
+import (
+	"github.com/apache/dubbo-go/common"
+	"github.com/apache/dubbo-go/common/constant"
+	"github.com/apache/dubbo-go/common/logger"
+	"github.com/apache/dubbo-go/registry"
+	"github.com/apache/dubbo-go/remoting"
+)
+
+type nacosListener struct {
+	namingClient   naming_client.INamingClient
+	listenUrl      common.URL
+	events         chan *remoting.ConfigChangeEvent
+	instanceMap    map[string]model.Instance
+	cacheLock      sync.Mutex
+	done           chan struct{}
+	subscribeParam *vo.SubscribeParam
+}
+
+func NewNacosListener(url common.URL, namingClient naming_client.INamingClient) (*nacosListener, error) {
+	listener := &nacosListener{
+		namingClient: namingClient,
+		listenUrl:    url, events: make(chan *remoting.ConfigChangeEvent, 32),
+		instanceMap: map[string]model.Instance{},
+		done:        make(chan struct{}),
+	}
+	err := listener.startListen()
+	return listener, err
+}
+
+func generateInstance(ss model.SubscribeService) model.Instance {
+	return model.Instance{
+		InstanceId:  ss.InstanceId,
+		Ip:          ss.Ip,
+		Port:        ss.Port,
+		ServiceName: ss.ServiceName,
+		Valid:       ss.Valid,
+		Enable:      ss.Enable,
+		Weight:      ss.Weight,
+		Metadata:    ss.Metadata,
+		ClusterName: ss.ClusterName,
+	}
+}
+
+func generateUrl(instance model.Instance) *common.URL {
+	if instance.Metadata == nil {
+		logger.Errorf("nacos instance metadata is empty,instance:%+v", instance)
+		return nil
+	}
+	path := instance.Metadata["path"]
+	myInterface := instance.Metadata["interface"]
+	if len(path) == 0 && len(myInterface) == 0 {
+		logger.Errorf("nacos instance metadata does not have  both path key and interface key,instance:%+v", instance)
+		return nil
+	}
+	if len(path) == 0 && len(myInterface) != 0 {
+		path = "/" + myInterface
+	}
+	protocol := instance.Metadata["protocol"]
+	if len(protocol) == 0 {
+		logger.Errorf("nacos instance metadata does not have protocol key,instance:%+v", instance)
+		return nil
+	}
+	urlMap := url.Values{}
+	for k, v := range instance.Metadata {
+		urlMap.Set(k, v)
+	}
+	return common.NewURLWithOptions(
+		common.WithIp(instance.Ip),
+		common.WithPort(strconv.Itoa(int(instance.Port))),
+		common.WithProtocol(protocol),
+		common.WithParams(urlMap),
+		common.WithPath(path),
+	)
+}
+
+func (nl *nacosListener) Callback(services []model.SubscribeService, err error) {
+	if err != nil {
+		logger.Errorf("nacos subscribe callback error:%s , subscribe:%+v ", err.Error(), nl.subscribeParam)
+		return
+	}
+	nl.cacheLock.Lock()
+	defer nl.cacheLock.Unlock()
+	addInstances := make([]model.Instance, 0, len(services))
+	delInstances := make([]model.Instance, 0, len(services))
+	updateInstances := make([]model.Instance, 0, len(services))
+
+	newInstanceMap := make(map[string]model.Instance, len(services))
+
+	for i := range services {
+		if !services[i].Enable || !services[i].Valid {
+			// instance is not available,so ignore it
+			continue
+		}
+		host := services[i].Ip + ":" + strconv.Itoa(int(services[i].Port))
+		instance := generateInstance(services[i])
+		newInstanceMap[host] = instance
+		if old, ok := nl.instanceMap[host]; !ok {
+			//instance is not exsit in cache,add it to cache
+			addInstances = append(addInstances, instance)
+		} else {
+			//instance is not different from cache,update it to cache
+			if !reflect.DeepEqual(old, instance) {
+				updateInstances = append(updateInstances, instance)
+			}
+		}
+	}
+
+	for host, inst := range nl.instanceMap {
+		if _, ok := newInstanceMap[host]; !ok {
+			//cache  instance is not exsit in  new instance list, remove it from  cache
+			delInstances = append(delInstances, inst)
+		}
+	}
+
+	nl.instanceMap = newInstanceMap
+
+	for i := range addInstances {
+		newUrl := generateUrl(addInstances[i])
+		if newUrl != nil {
+			nl.process(&remoting.ConfigChangeEvent{Value: *newUrl, ConfigType: remoting.EventTypeAdd})
+		}
+	}
+	for i := range delInstances {
+		newUrl := generateUrl(delInstances[i])
+		if newUrl != nil {
+			nl.process(&remoting.ConfigChangeEvent{Value: *newUrl, ConfigType: remoting.EventTypeDel})
+		}
+	}
+
+	for i := range updateInstances {
+		newUrl := generateUrl(updateInstances[i])
+		if newUrl != nil {
+			nl.process(&remoting.ConfigChangeEvent{Value: *newUrl, ConfigType: remoting.EvnetTypeUpdate})
+		}
+	}
+}
+
+func getSubscribeName(url common.URL) string {
+	var buffer bytes.Buffer
+
+	buffer.Write([]byte(common.DubboNodes[common.PROVIDER]))
+	appendParam(&buffer, url, constant.INTERFACE_KEY)
+	appendParam(&buffer, url, constant.VERSION_KEY)
+	appendParam(&buffer, url, constant.GROUP_KEY)
+	return buffer.String()
+}
+
+func (nl *nacosListener) startListen() error {
+	if nl.namingClient == nil {
+		return perrors.New("nacos naming client stopped")
+	}
+	serviceName := getSubscribeName(nl.listenUrl)
+	nl.subscribeParam = &vo.SubscribeParam{ServiceName: serviceName, SubscribeCallback: nl.Callback}
+	return nl.namingClient.Subscribe(nl.subscribeParam)
+}
+
+func (nl *nacosListener) stopListen() error {
+	return nl.namingClient.Unsubscribe(nl.subscribeParam)
+}
+
+func (nl *nacosListener) process(configType *remoting.ConfigChangeEvent) {
+	nl.events <- configType
+}
+
+func (nl *nacosListener) Next() (*registry.ServiceEvent, error) {
+	for {
+		select {
+		case <-nl.done:
+			logger.Warnf("nacos listener is close!listenUrl:%+v", nl.listenUrl)
+			return nil, perrors.New("listener stopped")
+
+		case e := <-nl.events:
+			logger.Debugf("got nacos event %s", e)
+			return &registry.ServiceEvent{Action: e.ConfigType, Service: e.Value.(common.URL)}, nil
+		}
+	}
+}
+
+func (nl *nacosListener) Close() {
+	nl.stopListen()
+	close(nl.done)
+}
diff --git a/registry/nacos/registry.go b/registry/nacos/registry.go
new file mode 100644
index 0000000000000000000000000000000000000000..f10e230bc44dba8f8007ea659db3747a237c9de1
--- /dev/null
+++ b/registry/nacos/registry.go
@@ -0,0 +1,176 @@
+package nacos
+
+import (
+	"bytes"
+	"net"
+	"strconv"
+	"strings"
+	"time"
+)
+import (
+	"github.com/nacos-group/nacos-sdk-go/clients"
+	"github.com/nacos-group/nacos-sdk-go/clients/naming_client"
+	nacosConstant "github.com/nacos-group/nacos-sdk-go/common/constant"
+	"github.com/nacos-group/nacos-sdk-go/vo"
+	perrors "github.com/pkg/errors"
+)
+
+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/utils"
+	"github.com/apache/dubbo-go/registry"
+)
+
+var (
+	localIP = ""
+)
+
+func init() {
+	localIP, _ = utils.GetLocalIP()
+	extension.SetRegistry(constant.NACOS_KEY, newNacosRegistry)
+}
+
+type nacosRegistry struct {
+	*common.URL
+	namingClient naming_client.INamingClient
+}
+
+func getNacosConfig(url *common.URL) (map[string]interface{}, error) {
+	if url == nil {
+		return nil, perrors.New("url is empty!")
+	}
+	if len(url.Location) == 0 {
+		return nil, perrors.New("url.location is empty!")
+	}
+	configMap := make(map[string]interface{}, 2)
+
+	addresses := strings.Split(url.Location, ",")
+	serverConfigs := make([]nacosConstant.ServerConfig, 0, len(addresses))
+	for _, addr := range addresses {
+		ip, portStr, err := net.SplitHostPort(addr)
+		if err != nil {
+			return nil, perrors.WithMessagef(err, "split [%s] ", addr)
+		}
+		port, _ := strconv.Atoi(portStr)
+		serverConfigs = append(serverConfigs, nacosConstant.ServerConfig{
+			IpAddr: ip,
+			Port:   uint64(port),
+		})
+	}
+	configMap["serverConfigs"] = serverConfigs
+
+	var clientConfig nacosConstant.ClientConfig
+	timeout, err := time.ParseDuration(url.GetParam(constant.REGISTRY_TIMEOUT_KEY, constant.DEFAULT_REG_TIMEOUT))
+	if err != nil {
+		return nil, err
+	}
+	clientConfig.TimeoutMs = uint64(timeout.Seconds() * 1000)
+	clientConfig.ListenInterval = 2 * clientConfig.TimeoutMs
+	clientConfig.CacheDir = url.GetParam(constant.NACOS_CACHE_DIR_KEY, "")
+	clientConfig.LogDir = url.GetParam(constant.NACOS_LOG_DIR_KEY, "")
+	clientConfig.Endpoint = url.GetParam(constant.NACOS_ENDPOINT, "")
+	clientConfig.NotLoadCacheAtStart = true
+	configMap["clientConfig"] = clientConfig
+
+	return configMap, nil
+}
+
+func newNacosRegistry(url *common.URL) (registry.Registry, error) {
+	nacosConfig, err := getNacosConfig(url)
+	if err != nil {
+		return nil, err
+	}
+	client, err := clients.CreateNamingClient(nacosConfig)
+	if err != nil {
+		return nil, err
+	}
+	registry := nacosRegistry{
+		URL:          url,
+		namingClient: client,
+	}
+	return &registry, nil
+}
+
+func getCategory(url common.URL) string {
+	role, _ := strconv.Atoi(url.GetParam(constant.ROLE_KEY, strconv.Itoa(constant.NACOS_DEFAULT_ROLETYPE)))
+	category := common.DubboNodes[role]
+	return category
+}
+
+func getServiceName(url common.URL) string {
+	var buffer bytes.Buffer
+
+	buffer.Write([]byte(getCategory(url)))
+	appendParam(&buffer, url, constant.INTERFACE_KEY)
+	appendParam(&buffer, url, constant.VERSION_KEY)
+	appendParam(&buffer, url, constant.GROUP_KEY)
+	return buffer.String()
+}
+
+func appendParam(target *bytes.Buffer, url common.URL, key string) {
+	value := url.GetParam(key, "")
+	if strings.TrimSpace(value) != "" {
+		target.Write([]byte(constant.NACOS_SERVICE_NAME_SEPARATOR))
+		target.Write([]byte(value))
+	}
+}
+
+func createRegisterParam(url common.URL, serviceName string) vo.RegisterInstanceParam {
+	category := getCategory(url)
+	params := make(map[string]string, len(url.Params)+3)
+	for k, _ := range url.Params {
+		params[k] = url.Params.Get(k)
+	}
+	params[constant.NACOS_CATEGORY_KEY] = category
+	params[constant.NACOS_PROTOCOL_KEY] = url.Protocol
+	params[constant.NACOS_PATH_KEY] = url.Path
+	if len(url.Ip) == 0 {
+		url.Ip = localIP
+	}
+	if len(url.Port) == 0 || url.Port == "0" {
+		url.Port = "80"
+	}
+	port, _ := strconv.Atoi(url.Port)
+	instance := vo.RegisterInstanceParam{
+		Ip:          url.Ip,
+		Port:        uint64(port),
+		Metadata:    params,
+		Weight:      1,
+		Enable:      true,
+		Healthy:     true,
+		Ephemeral:   true,
+		ServiceName: serviceName,
+	}
+	return instance
+}
+
+func (nr *nacosRegistry) Register(url common.URL) error {
+	serviceName := getServiceName(url)
+	param := createRegisterParam(url, serviceName)
+	isRegistry, err := nr.namingClient.RegisterInstance(param)
+	if err != nil {
+		return err
+	}
+	if !isRegistry {
+		return perrors.New("registry [" + serviceName + "] to  nacos failed")
+	}
+	return nil
+}
+
+func (nr *nacosRegistry) Subscribe(conf common.URL) (registry.Listener, error) {
+	return NewNacosListener(conf, nr.namingClient)
+}
+
+func (nr *nacosRegistry) GetUrl() common.URL {
+	return *nr.URL
+}
+
+func (nr *nacosRegistry) IsAvailable() bool {
+	return true
+}
+
+func (nr *nacosRegistry) Destroy() {
+	return
+}
diff --git a/registry/nacos/registry_test.go b/registry/nacos/registry_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..97dea0d2b016c8f84ee7cf6f4856ba545b720a48
--- /dev/null
+++ b/registry/nacos/registry_test.go
@@ -0,0 +1,174 @@
+package nacos
+
+import (
+	"context"
+	"encoding/json"
+	"net/url"
+	"strconv"
+	"testing"
+)
+
+import (
+	"github.com/nacos-group/nacos-sdk-go/vo"
+	"github.com/stretchr/testify/assert"
+)
+
+import (
+	"github.com/apache/dubbo-go/common"
+	"github.com/apache/dubbo-go/common/constant"
+)
+
+func Test_Register(t *testing.T) {
+	regurl, _ := common.NewURL(context.TODO(), "registry://console.nacos.io:80", common.WithParamsValue(constant.ROLE_KEY, strconv.Itoa(common.PROVIDER)))
+	urlMap := url.Values{}
+	urlMap.Set(constant.GROUP_KEY, "guangzhou-idc")
+	urlMap.Set(constant.ROLE_KEY, strconv.Itoa(common.PROVIDER))
+	urlMap.Set(constant.INTERFACE_KEY, "com.ikurento.user.UserProvider")
+	urlMap.Set(constant.VERSION_KEY, "1.0.0")
+	urlMap.Set(constant.CLUSTER_KEY, "mock")
+	url, _ := common.NewURL(context.TODO(), "dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider", common.WithParams(urlMap), common.WithMethods([]string{"GetUser", "AddUser"}))
+
+	reg, err := newNacosRegistry(&regurl)
+	assert.Nil(t, err)
+	if err != nil {
+		t.Errorf("new nacos registry error:%s \n", err.Error())
+		return
+	}
+	err = reg.Register(url)
+	assert.Nil(t, err)
+	if err != nil {
+		t.Errorf("register error:%s \n", err.Error())
+		return
+	}
+	nacosReg := reg.(*nacosRegistry)
+	service, _ := nacosReg.namingClient.GetService(vo.GetServiceParam{ServiceName: "providers:com.ikurento.user.UserProvider:1.0.0:guangzhou-idc"})
+	data, _ := json.Marshal(service)
+	t.Logf(string(data))
+	assert.Equal(t, 1, len(service.Hosts))
+}
+
+func TestNacosRegistry_Subscribe(t *testing.T) {
+	regurl, _ := common.NewURL(context.TODO(), "registry://console.nacos.io:80", common.WithParamsValue(constant.ROLE_KEY, strconv.Itoa(common.PROVIDER)))
+	urlMap := url.Values{}
+	urlMap.Set(constant.GROUP_KEY, "guangzhou-idc")
+	urlMap.Set(constant.ROLE_KEY, strconv.Itoa(common.PROVIDER))
+	urlMap.Set(constant.INTERFACE_KEY, "com.ikurento.user.UserProvider")
+	urlMap.Set(constant.VERSION_KEY, "1.0.0")
+	urlMap.Set(constant.CLUSTER_KEY, "mock")
+	urlMap.Set(constant.NACOS_PATH_KEY, "")
+	url, _ := common.NewURL(context.TODO(), "dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider", common.WithParams(urlMap), common.WithMethods([]string{"GetUser", "AddUser"}))
+
+	reg, _ := newNacosRegistry(&regurl)
+	err := reg.Register(url)
+	assert.Nil(t, err)
+	if err != nil {
+		t.Errorf("new nacos registry error:%s \n", err.Error())
+		return
+	}
+
+	regurl.Params.Set(constant.ROLE_KEY, strconv.Itoa(common.CONSUMER))
+	reg2, _ := newNacosRegistry(&regurl)
+	listener, err := reg2.Subscribe(url)
+	assert.Nil(t, err)
+	if err != nil {
+		t.Errorf("subscribe error:%s \n", err.Error())
+		return
+	}
+	serviceEvent, _ := listener.Next()
+	assert.NoError(t, err)
+	if err != nil {
+		t.Errorf("listener error:%s \n", err.Error())
+		return
+	}
+	t.Logf("serviceEvent:%+v \n", serviceEvent)
+	assert.Regexp(t, ".*ServiceEvent{Action{add}.*", serviceEvent.String())
+
+}
+
+func TestNacosRegistry_Subscribe_del(t *testing.T) {
+	regurl, _ := common.NewURL(context.TODO(), "registry://console.nacos.io:80", common.WithParamsValue(constant.ROLE_KEY, strconv.Itoa(common.PROVIDER)))
+	urlMap := url.Values{}
+	urlMap.Set(constant.GROUP_KEY, "guangzhou-idc")
+	urlMap.Set(constant.ROLE_KEY, strconv.Itoa(common.PROVIDER))
+	urlMap.Set(constant.INTERFACE_KEY, "com.ikurento.user.UserProvider")
+	urlMap.Set(constant.VERSION_KEY, "1.0.0")
+	urlMap.Set(constant.CLUSTER_KEY, "mock")
+	urlMap.Set(constant.NACOS_PATH_KEY, "")
+	url1, _ := common.NewURL(context.TODO(), "dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider", common.WithParams(urlMap), common.WithMethods([]string{"GetUser", "AddUser"}))
+	url2, _ := common.NewURL(context.TODO(), "dubbo://127.0.0.2:20000/com.ikurento.user.UserProvider", common.WithParams(urlMap), common.WithMethods([]string{"GetUser", "AddUser"}))
+
+	reg, _ := newNacosRegistry(&regurl)
+	err := reg.Register(url1)
+	assert.Nil(t, err)
+	if err != nil {
+		t.Errorf("register1 error:%s \n", err.Error())
+		return
+	}
+	err = reg.Register(url2)
+	assert.Nil(t, err)
+	if err != nil {
+		t.Errorf("register2 error:%s \n", err.Error())
+		return
+	}
+
+	regurl.Params.Set(constant.ROLE_KEY, strconv.Itoa(common.CONSUMER))
+	reg2, _ := newNacosRegistry(&regurl)
+	listener, err := reg2.Subscribe(url1)
+	assert.Nil(t, err)
+	if err != nil {
+		t.Errorf("subscribe error:%s \n", err.Error())
+		return
+	}
+
+	serviceEvent1, _ := listener.Next()
+	assert.NoError(t, err)
+	if err != nil {
+		t.Errorf("listener1 error:%s \n", err.Error())
+		return
+	}
+	t.Logf("serviceEvent1:%+v \n", serviceEvent1)
+	assert.Regexp(t, ".*ServiceEvent{Action{add}.*", serviceEvent1.String())
+
+	serviceEvent2, _ := listener.Next()
+	assert.NoError(t, err)
+	if err != nil {
+		t.Errorf("listener2 error:%s \n", err.Error())
+		return
+	}
+	t.Logf("serviceEvent2:%+v \n", serviceEvent2)
+	assert.Regexp(t, ".*ServiceEvent{Action{add}.*", serviceEvent2.String())
+
+	nacosReg := reg.(*nacosRegistry)
+	//deregister  instance to mock instance offline
+	nacosReg.namingClient.DeregisterInstance(vo.DeregisterInstanceParam{Ip: "127.0.0.2", Port: 20000, ServiceName: "providers:com.ikurento.user.UserProvider:1.0.0:guangzhou-idc"})
+
+	serviceEvent3, _ := listener.Next()
+	assert.NoError(t, err)
+	if err != nil {
+		return
+	}
+	t.Logf("serviceEvent3:%+v \n", serviceEvent3)
+	assert.Regexp(t, ".*ServiceEvent{Action{delete}.*", serviceEvent3.String())
+}
+
+func TestNacosListener_Close(t *testing.T) {
+	regurl, _ := common.NewURL(context.TODO(), "registry://console.nacos.io:80", common.WithParamsValue(constant.ROLE_KEY, strconv.Itoa(common.PROVIDER)))
+	urlMap := url.Values{}
+	urlMap.Set(constant.GROUP_KEY, "guangzhou-idc")
+	urlMap.Set(constant.ROLE_KEY, strconv.Itoa(common.PROVIDER))
+	urlMap.Set(constant.INTERFACE_KEY, "com.ikurento.user.UserProvider2")
+	urlMap.Set(constant.VERSION_KEY, "1.0.0")
+	urlMap.Set(constant.CLUSTER_KEY, "mock")
+	urlMap.Set(constant.NACOS_PATH_KEY, "")
+	url1, _ := common.NewURL(context.TODO(), "dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider2", common.WithParams(urlMap), common.WithMethods([]string{"GetUser", "AddUser"}))
+	reg, _ := newNacosRegistry(&regurl)
+	listener, err := reg.Subscribe(url1)
+	assert.Nil(t, err)
+	if err != nil {
+		t.Errorf("subscribe error:%s \n", err.Error())
+		return
+	}
+	listener.Close()
+	_, err = listener.Next()
+	assert.NotNil(t, err)
+}
diff --git a/registry/zookeeper/listener.go b/registry/zookeeper/listener.go
index 67f20370602a0a9c5c3d87ef93b1bafed3449d36..19f25693c82b6390c7c54e47d13a4e9e36fa85ce 100644
--- a/registry/zookeeper/listener.go
+++ b/registry/zookeeper/listener.go
@@ -45,7 +45,7 @@ func (l *RegistryDataListener) AddInterestedURL(url *common.URL) {
 }
 
 func (l *RegistryDataListener) DataChange(eventType remoting.Event) bool {
-	//鎴彇鏈€鍚庝竴浣�
+	// Intercept the last bit
 	url := eventType.Path[strings.Index(eventType.Path, "/providers/")+len("/providers/"):]
 	serviceURL, err := common.NewURL(context.TODO(), url)
 	if err != nil {
diff --git a/registry/zookeeper/registry.go b/registry/zookeeper/registry.go
index c272c5bba615c68c452f36819edef0f2a821a5dc..003ee2940d43005b06457d9dbbaa2e2065d03693 100644
--- a/registry/zookeeper/registry.go
+++ b/registry/zookeeper/registry.go
@@ -230,10 +230,11 @@ func (r *zkRegistry) Register(conf common.URL) error {
 
 	case common.PROVIDER:
 
-		// 妫€楠屾湇鍔℃槸鍚﹀凡缁忔敞鍐岃繃
+		// Check if the service has been registered
 		r.cltLock.Lock()
-		// 娉ㄦ剰姝ゅ涓巆onsumerZookeeperRegistry鐨勫樊寮傦紝consumer鐢ㄧ殑鏄痗onf.Path锛�
-		// 鍥犱负consumer瑕佹彁渚泈atch鍔熻兘缁檚elector浣跨敤, provider鍏佽娉ㄥ唽鍚屼竴涓猻ervice鐨勫涓猤roup or version
+		// Note the difference between consumer and consumerZookeeperRegistry (consumer use conf.Path).
+		// Because the consumer wants to provide monitoring functions for the selector,
+		// the provider allows multiple groups or versions of the same service to be registered.
 		_, ok = r.services[conf.Key()]
 		r.cltLock.Unlock()
 		if ok {
@@ -298,7 +299,8 @@ func (r *zkRegistry) register(c common.URL) error {
 		}
 		params.Add("anyhost", "true")
 
-		// dubbo java consumer鏉ュ惎鍔ㄦ壘provider url鏃讹紝鍥犱负category涓嶅尮閰嶏紝浼氭壘涓嶅埌provider锛屽鑷碿onsumer鍚姩涓嶄簡,鎵€浠ヤ娇鐢╟onsumers&providers
+		// Dubbo java consumer to start looking for the provider url,because the category does not match,
+		// the provider will not find, causing the consumer can not start, so we use consumers.
 		// DubboRole               = [...]string{"consumer", "", "", "provider"}
 		// params.Add("category", (RoleType(PROVIDER)).Role())
 		params.Add("category", (common.RoleType(common.PROVIDER)).String())
@@ -320,7 +322,7 @@ func (r *zkRegistry) register(c common.URL) error {
 		rawURL = fmt.Sprintf("%s://%s%s?%s", c.Protocol, host, c.Path, params.Encode())
 		encodedURL = url.QueryEscape(rawURL)
 
-		// 鎶婅嚜宸辨敞鍐宻ervice providers
+		// Print your own registration service providers.
 		dubboPath = fmt.Sprintf("/dubbo/%s/%s", c.Service(), (common.RoleType(common.PROVIDER)).String())
 		logger.Debugf("provider path:%s, url:%s", dubboPath, rawURL)
 
@@ -416,7 +418,7 @@ func (r *zkRegistry) getListener(conf common.URL) (*RegistryConfigurationListene
 		r.listenerLock.Unlock()
 	}
 
-	//娉ㄥ唽鍒癲ataconfig鐨刬nterested
+	//Interested register to dataconfig.
 	r.dataListener.AddInterestedURL(&conf)
 
 	go r.listener.ListenServiceEvent(fmt.Sprintf("/dubbo/%s/providers", conf.Service()), r.dataListener)
@@ -428,7 +430,7 @@ func (r *zkRegistry) closeRegisters() {
 	r.cltLock.Lock()
 	defer r.cltLock.Unlock()
 	logger.Infof("begin to close provider zk client")
-	// 鍏堝叧闂棫client锛屼互鍏抽棴tmp node
+	// Close the old client first to close the tmp node.
 	r.client.Close()
 	r.client = nil
 	r.services = nil
diff --git a/remoting/etcdv3/client.go b/remoting/etcdv3/client.go
new file mode 100644
index 0000000000000000000000000000000000000000..57d1211fe30e00dcb1ad16733f36b7969ebaf505
--- /dev/null
+++ b/remoting/etcdv3/client.go
@@ -0,0 +1,480 @@
+package etcdv3
+
+import (
+	"context"
+	"path"
+	"sync"
+	"time"
+)
+
+import (
+	"github.com/coreos/etcd/clientv3"
+	"github.com/coreos/etcd/clientv3/concurrency"
+	perrors "github.com/pkg/errors"
+	"google.golang.org/grpc"
+)
+
+import (
+	"github.com/apache/dubbo-go/common/logger"
+)
+
+const (
+	ConnDelay            = 3
+	MaxFailTimes         = 15
+	RegistryETCDV3Client = "etcd registry"
+)
+
+var (
+	ErrNilETCDV3Client = perrors.New("etcd raw client is nil") // full describe the ERR
+	ErrKVPairNotFound  = perrors.New("k/v pair not found")
+)
+
+type Options struct {
+	name      string
+	endpoints []string
+	client    *Client
+	timeout   time.Duration
+	heartbeat int // heartbeat second
+}
+
+type Option func(*Options)
+
+func WithEndpoints(endpoints ...string) Option {
+	return func(opt *Options) {
+		opt.endpoints = endpoints
+	}
+}
+func WithName(name string) Option {
+	return func(opt *Options) {
+		opt.name = name
+	}
+}
+func WithTimeout(timeout time.Duration) Option {
+	return func(opt *Options) {
+		opt.timeout = timeout
+	}
+}
+
+func WithHeartbeat(heartbeat int) Option {
+	return func(opt *Options) {
+		opt.heartbeat = heartbeat
+	}
+}
+
+func ValidateClient(container clientFacade, opts ...Option) error {
+
+	options := &Options{
+		heartbeat: 1, // default heartbeat
+	}
+	for _, opt := range opts {
+		opt(options)
+	}
+
+	lock := container.ClientLock()
+	lock.Lock()
+	defer lock.Unlock()
+
+	// new Client
+	if container.Client() == nil {
+		newClient, err := newClient(options.name, options.endpoints, options.timeout, options.heartbeat)
+		if err != nil {
+			logger.Warnf("new etcd client (name{%s}, etcd addresses{%v}, timeout{%d}) = error{%v}",
+				options.name, options.endpoints, options.timeout, err)
+			return perrors.WithMessagef(err, "new client (address:%+v)", options.endpoints)
+		}
+		container.SetClient(newClient)
+	}
+
+	// Client lose connection with etcd server
+	if container.Client().rawClient == nil {
+
+		newClient, err := newClient(options.name, options.endpoints, options.timeout, options.heartbeat)
+		if err != nil {
+			logger.Warnf("new etcd client (name{%s}, etcd addresses{%v}, timeout{%d}) = error{%v}",
+				options.name, options.endpoints, options.timeout, err)
+			return perrors.WithMessagef(err, "new client (address:%+v)", options.endpoints)
+		}
+		container.SetClient(newClient)
+	}
+
+	return nil
+}
+
+type Client struct {
+	lock sync.RWMutex
+
+	// these properties are only set once when they are started.
+	name      string
+	endpoints []string
+	timeout   time.Duration
+	heartbeat int
+
+	ctx       context.Context    // if etcd server connection lose, the ctx.Done will be sent msg
+	cancel    context.CancelFunc // cancel the ctx,  all watcher will stopped
+	rawClient *clientv3.Client
+
+	exit chan struct{}
+	Wait sync.WaitGroup
+}
+
+func newClient(name string, endpoints []string, timeout time.Duration, heartbeat int) (*Client, error) {
+
+	ctx, cancel := context.WithCancel(context.Background())
+	rawClient, err := clientv3.New(clientv3.Config{
+		Context:     ctx,
+		Endpoints:   endpoints,
+		DialTimeout: timeout,
+		DialOptions: []grpc.DialOption{grpc.WithBlock()},
+	})
+	if err != nil {
+		return nil, perrors.WithMessage(err, "new raw client block connect to server")
+	}
+
+	c := &Client{
+
+		name:      name,
+		timeout:   timeout,
+		endpoints: endpoints,
+		heartbeat: heartbeat,
+
+		ctx:       ctx,
+		cancel:    cancel,
+		rawClient: rawClient,
+
+		exit: make(chan struct{}),
+	}
+
+	if err := c.maintenanceStatus(); err != nil {
+		return nil, perrors.WithMessage(err, "client maintenance status")
+	}
+	return c, nil
+}
+
+// NOTICE: need to get the lock before calling this method
+func (c *Client) clean() {
+
+	// close raw client
+	c.rawClient.Close()
+
+	// cancel ctx for raw client
+	c.cancel()
+
+	// clean raw client
+	c.rawClient = nil
+}
+
+func (c *Client) stop() bool {
+
+	select {
+	case <-c.exit:
+		return true
+	default:
+		close(c.exit)
+	}
+	return false
+}
+
+func (c *Client) Close() {
+
+	if c == nil {
+		return
+	}
+
+	// stop the client
+	c.stop()
+
+	// wait client maintenance status stop
+	c.Wait.Wait()
+
+	c.lock.Lock()
+	if c.rawClient != nil {
+		c.clean()
+	}
+	c.lock.Unlock()
+	logger.Warnf("etcd client{name:%s, endpoints:%s} exit now.", c.name, c.endpoints)
+}
+
+func (c *Client) maintenanceStatus() error {
+
+	s, err := concurrency.NewSession(c.rawClient, concurrency.WithTTL(c.heartbeat))
+	if err != nil {
+		return perrors.WithMessage(err, "new session with server")
+	}
+
+	// must add wg before go maintenance status goroutine
+	c.Wait.Add(1)
+	go c.maintenanceStatusLoop(s)
+	return nil
+}
+
+func (c *Client) maintenanceStatusLoop(s *concurrency.Session) {
+
+	defer func() {
+		c.Wait.Done()
+		logger.Infof("etcd client {endpoints:%v, name:%s} maintenance goroutine game over.", c.endpoints, c.name)
+	}()
+
+	for {
+		select {
+		case <-c.Done():
+			// Client be stopped, will clean the client hold resources
+			return
+		case <-s.Done():
+			logger.Warn("etcd server stopped")
+			c.lock.Lock()
+			// when etcd server stopped, cancel ctx, stop all watchers
+			c.clean()
+			// when connection lose, stop client, trigger reconnect to etcd
+			c.stop()
+			c.lock.Unlock()
+			return
+		}
+	}
+}
+
+// if k not exist will put k/v in etcd
+// if k is already exist in etcd, return nil
+func (c *Client) put(k string, v string, opts ...clientv3.OpOption) error {
+
+	c.lock.RLock()
+	defer c.lock.RUnlock()
+
+	if c.rawClient == nil {
+		return ErrNilETCDV3Client
+	}
+
+	_, err := c.rawClient.Txn(c.ctx).
+		If(clientv3.Compare(clientv3.Version(k), "<", 1)).
+		Then(clientv3.OpPut(k, v, opts...)).
+		Commit()
+	if err != nil {
+		return err
+
+	}
+	return nil
+}
+
+func (c *Client) delete(k string) error {
+
+	c.lock.RLock()
+	defer c.lock.RUnlock()
+
+	if c.rawClient == nil {
+		return ErrNilETCDV3Client
+	}
+
+	_, err := c.rawClient.Delete(c.ctx, k)
+	if err != nil {
+		return err
+
+	}
+	return nil
+}
+
+func (c *Client) get(k string) (string, error) {
+
+	c.lock.RLock()
+	defer c.lock.RUnlock()
+
+	if c.rawClient == nil {
+		return "", ErrNilETCDV3Client
+	}
+
+	resp, err := c.rawClient.Get(c.ctx, k)
+	if err != nil {
+		return "", err
+	}
+
+	if len(resp.Kvs) == 0 {
+		return "", ErrKVPairNotFound
+	}
+
+	return string(resp.Kvs[0].Value), nil
+}
+
+func (c *Client) CleanKV() error {
+
+	c.lock.RLock()
+	defer c.lock.RUnlock()
+
+	if c.rawClient == nil {
+		return ErrNilETCDV3Client
+	}
+
+	_, err := c.rawClient.Delete(c.ctx, "", clientv3.WithPrefix())
+	if err != nil {
+		return err
+	}
+
+	return nil
+}
+
+func (c *Client) getChildren(k string) ([]string, []string, error) {
+
+	c.lock.RLock()
+	defer c.lock.RUnlock()
+
+	if c.rawClient == nil {
+		return nil, nil, ErrNilETCDV3Client
+	}
+
+	resp, err := c.rawClient.Get(c.ctx, k, clientv3.WithPrefix())
+	if err != nil {
+		return nil, nil, err
+	}
+
+	if len(resp.Kvs) == 0 {
+		return nil, nil, ErrKVPairNotFound
+	}
+
+	var (
+		kList []string
+		vList []string
+	)
+
+	for _, kv := range resp.Kvs {
+		kList = append(kList, string(kv.Key))
+		vList = append(vList, string(kv.Value))
+	}
+
+	return kList, vList, nil
+}
+
+func (c *Client) watchWithPrefix(prefix string) (clientv3.WatchChan, error) {
+
+	c.lock.RLock()
+	defer c.lock.RUnlock()
+
+	if c.rawClient == nil {
+		return nil, ErrNilETCDV3Client
+	}
+
+	return c.rawClient.Watch(c.ctx, prefix, clientv3.WithPrefix()), nil
+}
+
+func (c *Client) watch(k string) (clientv3.WatchChan, error) {
+
+	c.lock.RLock()
+	defer c.lock.RUnlock()
+
+	if c.rawClient == nil {
+		return nil, ErrNilETCDV3Client
+	}
+
+	return c.rawClient.Watch(c.ctx, k), nil
+}
+
+func (c *Client) keepAliveKV(k string, v string) error {
+
+	c.lock.RLock()
+	defer c.lock.RUnlock()
+
+	if c.rawClient == nil {
+		return ErrNilETCDV3Client
+	}
+
+	lease, err := c.rawClient.Grant(c.ctx, int64(time.Second.Seconds()))
+	if err != nil {
+		return perrors.WithMessage(err, "grant lease")
+	}
+
+	keepAlive, err := c.rawClient.KeepAlive(c.ctx, lease.ID)
+	if err != nil || keepAlive == nil {
+		c.rawClient.Revoke(c.ctx, lease.ID)
+		return perrors.WithMessage(err, "keep alive lease")
+	}
+
+	_, err = c.rawClient.Put(c.ctx, k, v, clientv3.WithLease(lease.ID))
+	if err != nil {
+		return perrors.WithMessage(err, "put k/v with lease")
+	}
+	return nil
+}
+
+func (c *Client) Done() <-chan struct{} {
+	return c.exit
+}
+
+func (c *Client) Valid() bool {
+	select {
+	case <-c.exit:
+		return false
+	default:
+	}
+
+	c.lock.RLock()
+	if c.rawClient == nil {
+		c.lock.RUnlock()
+		return false
+	}
+	c.lock.RUnlock()
+	return true
+}
+
+func (c *Client) Create(k string, v string) error {
+
+	err := c.put(k, v)
+	if err != nil {
+		return perrors.WithMessagef(err, "put k/v (key: %s value %s)", k, v)
+	}
+	return nil
+}
+
+func (c *Client) Delete(k string) error {
+
+	err := c.delete(k)
+	if err != nil {
+		return perrors.WithMessagef(err, "delete k/v (key %s)", k)
+	}
+
+	return nil
+}
+
+func (c *Client) RegisterTemp(basePath string, node string) (string, error) {
+
+	completeKey := path.Join(basePath, node)
+
+	err := c.keepAliveKV(completeKey, "")
+	if err != nil {
+		return "", perrors.WithMessagef(err, "keepalive kv (key %s)", completeKey)
+	}
+
+	return completeKey, nil
+}
+
+func (c *Client) GetChildrenKVList(k string) ([]string, []string, error) {
+
+	kList, vList, err := c.getChildren(k)
+	if err != nil {
+		return nil, nil, perrors.WithMessagef(err, "get key children (key %s)", k)
+	}
+	return kList, vList, nil
+}
+
+func (c *Client) Get(k string) (string, error) {
+
+	v, err := c.get(k)
+	if err != nil {
+		return "", perrors.WithMessagef(err, "get key value (key %s)", k)
+	}
+
+	return v, nil
+}
+
+func (c *Client) Watch(k string) (clientv3.WatchChan, error) {
+
+	wc, err := c.watch(k)
+	if err != nil {
+		return nil, perrors.WithMessagef(err, "watch prefix (key %s)", k)
+	}
+	return wc, nil
+}
+
+func (c *Client) WatchWithPrefix(prefix string) (clientv3.WatchChan, error) {
+
+	wc, err := c.watchWithPrefix(prefix)
+	if err != nil {
+		return nil, perrors.WithMessagef(err, "watch prefix (key %s)", prefix)
+	}
+	return wc, nil
+}
diff --git a/remoting/etcdv3/client_test.go b/remoting/etcdv3/client_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..187789e0abfac6a0e195bebd68ce4b91e0f9bdec
--- /dev/null
+++ b/remoting/etcdv3/client_test.go
@@ -0,0 +1,366 @@
+package etcdv3
+
+import (
+	"fmt"
+	"net/url"
+	"path"
+	"reflect"
+	"strings"
+	"sync"
+	"testing"
+	"time"
+)
+
+import (
+	"github.com/coreos/etcd/mvcc/mvccpb"
+	perrors "github.com/pkg/errors"
+	"github.com/stretchr/testify/suite"
+	"go.etcd.io/etcd/embed"
+	"google.golang.org/grpc/connectivity"
+)
+
+// tests dataset
+var tests = []struct {
+	input struct {
+		k string
+		v string
+	}
+}{
+	{input: struct {
+		k string
+		v string
+	}{k: "name", v: "scott.wang"}},
+	{input: struct {
+		k string
+		v string
+	}{k: "namePrefix", v: "prefix.scott.wang"}},
+	{input: struct {
+		k string
+		v string
+	}{k: "namePrefix1", v: "prefix1.scott.wang"}},
+	{input: struct {
+		k string
+		v string
+	}{k: "age", v: "27"}},
+}
+
+// test dataset prefix
+const prefix = "name"
+
+type ClientTestSuite struct {
+	suite.Suite
+
+	etcdConfig struct {
+		name      string
+		endpoints []string
+		timeout   time.Duration
+		heartbeat int
+	}
+
+	etcd *embed.Etcd
+
+	client *Client
+}
+
+// start etcd server
+func (suite *ClientTestSuite) SetupSuite() {
+
+	t := suite.T()
+
+	DefaultListenPeerURLs := "http://localhost:2382"
+	DefaultListenClientURLs := "http://localhost:2381"
+	lpurl, _ := url.Parse(DefaultListenPeerURLs)
+	lcurl, _ := url.Parse(DefaultListenClientURLs)
+	cfg := embed.NewConfig()
+	cfg.LPUrls = []url.URL{*lpurl}
+	cfg.LCUrls = []url.URL{*lcurl}
+	cfg.Dir = "/tmp/default.etcd"
+	e, err := embed.StartEtcd(cfg)
+	if err != nil {
+		t.Fatal(err)
+	}
+	select {
+	case <-e.Server.ReadyNotify():
+		t.Log("Server is ready!")
+	case <-time.After(60 * time.Second):
+		e.Server.Stop() // trigger a shutdown
+		t.Logf("Server took too long to start!")
+	}
+
+	suite.etcd = e
+	return
+}
+
+// stop etcd server
+func (suite *ClientTestSuite) TearDownSuite() {
+	suite.etcd.Close()
+}
+
+func (suite *ClientTestSuite) setUpClient() *Client {
+	c, err := newClient(suite.etcdConfig.name,
+		suite.etcdConfig.endpoints,
+		suite.etcdConfig.timeout,
+		suite.etcdConfig.heartbeat)
+	if err != nil {
+		suite.T().Fatal(err)
+	}
+	return c
+}
+
+// set up a client for suite
+func (suite *ClientTestSuite) SetupTest() {
+	c := suite.setUpClient()
+	c.CleanKV()
+	suite.client = c
+	return
+}
+
+func (suite *ClientTestSuite) TestClientClose() {
+
+	fmt.Println("called client close")
+
+	c := suite.client
+	t := suite.T()
+
+	defer c.Close()
+	if c.rawClient.ActiveConnection().GetState() != connectivity.Ready {
+		t.Fatal(suite.client.rawClient.ActiveConnection().GetState())
+	}
+}
+
+func (suite *ClientTestSuite) TestClientValid() {
+
+	fmt.Println("called client valid")
+
+	c := suite.client
+	t := suite.T()
+
+	if c.Valid() != true {
+		t.Fatal("client is not valid")
+	}
+	c.Close()
+	if suite.client.Valid() != false {
+		t.Fatal("client is valid")
+	}
+}
+
+func (suite *ClientTestSuite) TestClientDone() {
+
+	c := suite.client
+
+	go func() {
+		time.Sleep(2 * time.Second)
+		c.Close()
+	}()
+
+	c.Wait.Wait()
+}
+
+func (suite *ClientTestSuite) TestClientCreateKV() {
+
+	tests := tests
+
+	c := suite.client
+	t := suite.T()
+
+	defer suite.client.Close()
+
+	for _, tc := range tests {
+
+		k := tc.input.k
+		v := tc.input.v
+		expect := tc.input.v
+
+		if err := c.Create(k, v); err != nil {
+			t.Fatal(err)
+		}
+
+		value, err := c.Get(k)
+		if err != nil {
+			t.Fatal(err)
+		}
+
+		if value != expect {
+			t.Fatalf("expect %v but get %v", expect, value)
+		}
+
+	}
+}
+
+func (suite *ClientTestSuite) TestClientDeleteKV() {
+
+	tests := tests
+	c := suite.client
+	t := suite.T()
+
+	defer c.Close()
+
+	for _, tc := range tests {
+
+		k := tc.input.k
+		v := tc.input.v
+		expect := ErrKVPairNotFound
+
+		if err := c.Create(k, v); err != nil {
+			t.Fatal(err)
+		}
+
+		if err := c.Delete(k); err != nil {
+			t.Fatal(err)
+		}
+
+		_, err := c.Get(k)
+		if perrors.Cause(err) == expect {
+			continue
+		}
+
+		if err != nil {
+			t.Fatal(err)
+		}
+	}
+
+}
+
+func (suite *ClientTestSuite) TestClientGetChildrenKVList() {
+
+	tests := tests
+
+	c := suite.client
+	t := suite.T()
+
+	var expectKList []string
+	var expectVList []string
+
+	for _, tc := range tests {
+
+		k := tc.input.k
+		v := tc.input.v
+
+		if strings.Contains(k, prefix) {
+			expectKList = append(expectKList, k)
+			expectVList = append(expectVList, v)
+		}
+
+		if err := c.Create(k, v); err != nil {
+			t.Fatal(err)
+		}
+	}
+
+	kList, vList, err := c.GetChildrenKVList(prefix)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	if reflect.DeepEqual(expectKList, kList) && reflect.DeepEqual(expectVList, vList) {
+		return
+	}
+
+	t.Fatalf("expect keylist %v but got %v expect valueList %v but got %v ", expectKList, kList, expectVList, vList)
+
+}
+
+func (suite *ClientTestSuite) TestClientWatch() {
+
+	tests := tests
+
+	c := suite.client
+	t := suite.T()
+
+	wg := sync.WaitGroup{}
+	wg.Add(1)
+
+	go func() {
+
+		defer wg.Done()
+
+		wc, err := c.watch(prefix)
+		if err != nil {
+			t.Fatal(err)
+		}
+
+		for e := range wc {
+
+			for _, event := range e.Events {
+				t.Logf("type IsCreate %v k %s v %s", event.IsCreate(), event.Kv.Key, event.Kv.Value)
+			}
+		}
+
+	}()
+
+	for _, tc := range tests {
+
+		k := tc.input.k
+		v := tc.input.v
+
+		if err := c.Create(k, v); err != nil {
+			t.Fatal(err)
+		}
+
+		if err := c.delete(k); err != nil {
+			t.Fatal(err)
+		}
+	}
+
+	c.Close()
+
+	wg.Wait()
+
+}
+
+func (suite *ClientTestSuite) TestClientRegisterTemp() {
+
+	c := suite.client
+	observeC := suite.setUpClient()
+	t := suite.T()
+
+	wg := sync.WaitGroup{}
+	wg.Add(1)
+
+	go func() {
+		completePath := path.Join("scott", "wang")
+		wc, err := observeC.watch(completePath)
+		if err != nil {
+			t.Fatal(err)
+		}
+
+		for e := range wc {
+
+			for _, event := range e.Events {
+
+				if event.Type == mvccpb.DELETE {
+					t.Logf("complete key (%s) is delete", completePath)
+					wg.Done()
+					observeC.Close()
+					return
+				}
+				t.Logf("type IsCreate %v k %s v %s", event.IsCreate(), event.Kv.Key, event.Kv.Value)
+			}
+		}
+	}()
+
+	_, err := c.RegisterTemp("scott", "wang")
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	time.Sleep(2 * time.Second)
+	c.Close()
+
+	wg.Wait()
+}
+
+func TestClientSuite(t *testing.T) {
+	suite.Run(t, &ClientTestSuite{
+		etcdConfig: struct {
+			name      string
+			endpoints []string
+			timeout   time.Duration
+			heartbeat int
+		}{
+			name:      "test",
+			endpoints: []string{"localhost:2381"},
+			timeout:   time.Second,
+			heartbeat: 1,
+		},
+	})
+}
diff --git a/remoting/etcdv3/facade.go b/remoting/etcdv3/facade.go
new file mode 100644
index 0000000000000000000000000000000000000000..e75b39d6bcd7f67f7606c6b212f59e7a42178fd8
--- /dev/null
+++ b/remoting/etcdv3/facade.go
@@ -0,0 +1,82 @@
+package etcdv3
+
+import (
+	"sync"
+	"time"
+)
+
+import (
+	"github.com/dubbogo/getty"
+	perrors "github.com/pkg/errors"
+)
+
+import (
+	"github.com/apache/dubbo-go/common"
+	"github.com/apache/dubbo-go/common/constant"
+	"github.com/apache/dubbo-go/common/logger"
+)
+
+type clientFacade interface {
+	Client() *Client
+	SetClient(*Client)
+	ClientLock() *sync.Mutex
+	WaitGroup() *sync.WaitGroup //for wait group control, etcd client listener & etcd client container
+	GetDone() chan struct{}     //for etcd client control
+	RestartCallBack() bool
+	common.Node
+}
+
+func HandleClientRestart(r clientFacade) {
+
+	var (
+		err       error
+		failTimes int
+	)
+
+	defer r.WaitGroup().Done()
+LOOP:
+	for {
+		select {
+		case <-r.GetDone():
+			logger.Warnf("(ETCDV3ProviderRegistry)reconnectETCDV3 goroutine exit now...")
+			break LOOP
+			// re-register all services
+		case <-r.Client().Done():
+			r.ClientLock().Lock()
+			clientName := RegistryETCDV3Client
+			timeout, _ := time.ParseDuration(r.GetUrl().GetParam(constant.REGISTRY_TIMEOUT_KEY, constant.DEFAULT_REG_TIMEOUT))
+			endpoint := r.GetUrl().Location
+			r.Client().Close()
+			r.SetClient(nil)
+			r.ClientLock().Unlock()
+
+			// try to connect to etcd,
+			failTimes = 0
+			for {
+				select {
+				case <-r.GetDone():
+					logger.Warnf("(ETCDV3ProviderRegistry)reconnectETCDRegistry goroutine exit now...")
+					break LOOP
+				case <-getty.GetTimeWheel().After(timeSecondDuration(failTimes * ConnDelay)): // avoid connect frequent
+				}
+				err = ValidateClient(
+					r,
+					WithName(clientName),
+					WithEndpoints(endpoint),
+					WithTimeout(timeout),
+				)
+				logger.Infof("ETCDV3ProviderRegistry.validateETCDV3Client(etcd Addr{%s}) = error{%#v}",
+					endpoint, perrors.WithStack(err))
+				if err == nil {
+					if r.RestartCallBack() {
+						break
+					}
+				}
+				failTimes++
+				if MaxFailTimes <= failTimes {
+					failTimes = MaxFailTimes
+				}
+			}
+		}
+	}
+}
diff --git a/remoting/etcdv3/listener.go b/remoting/etcdv3/listener.go
new file mode 100644
index 0000000000000000000000000000000000000000..59273af554a63e5fc907ba5a30bb1e18bb22c0f5
--- /dev/null
+++ b/remoting/etcdv3/listener.go
@@ -0,0 +1,217 @@
+package etcdv3
+
+import (
+	"sync"
+	"time"
+)
+
+import (
+	"github.com/coreos/etcd/clientv3"
+	"github.com/coreos/etcd/mvcc/mvccpb"
+	perrors "github.com/pkg/errors"
+)
+
+import (
+	"github.com/apache/dubbo-go/common/logger"
+	"github.com/apache/dubbo-go/remoting"
+)
+
+type EventListener struct {
+	client     *Client
+	keyMapLock sync.Mutex
+	keyMap     map[string]struct{}
+	wg         sync.WaitGroup
+}
+
+func NewEventListener(client *Client) *EventListener {
+	return &EventListener{
+		client: client,
+		keyMap: make(map[string]struct{}),
+	}
+}
+
+// Listen on a spec key
+// this method will return true when spec key deleted,
+// this method will return false when deep layer connection lose
+func (l *EventListener) ListenServiceNodeEvent(key string, listener ...remoting.DataListener) bool {
+	l.wg.Add(1)
+	defer l.wg.Done()
+	for {
+		wc, err := l.client.Watch(key)
+		if err != nil {
+			logger.Warnf("WatchExist{key:%s} = error{%v}", key, err)
+			return false
+		}
+
+		select {
+
+		// client stopped
+		case <-l.client.Done():
+			logger.Warnf("etcd client stopped")
+			return false
+
+		// client ctx stop
+		case <-l.client.ctx.Done():
+			logger.Warnf("etcd client ctx cancel")
+			return false
+
+		// handle etcd events
+		case e, ok := <-wc:
+			if !ok {
+				logger.Warnf("etcd watch-chan closed")
+				return false
+			}
+
+			if e.Err() != nil {
+				logger.Errorf("etcd watch ERR {err: %s}", e.Err())
+				continue
+			}
+			for _, event := range e.Events {
+				if l.handleEvents(event, listener...) {
+					// if event is delete
+					return true
+				}
+			}
+		}
+	}
+
+	return false
+}
+
+// return true mean the event type is DELETE
+// return false mean the event type is CREATE || UPDATE
+func (l *EventListener) handleEvents(event *clientv3.Event, listeners ...remoting.DataListener) bool {
+
+	logger.Infof("got a etcd event {type: %s, key: %s}", event.Type, event.Kv.Key)
+
+	switch event.Type {
+	// the etcdv3 event just include PUT && DELETE
+	case mvccpb.PUT:
+		for _, listener := range listeners {
+			switch event.IsCreate() {
+			case true:
+				logger.Infof("etcd get event (key{%s}) = event{EventNodeDataCreated}", event.Kv.Key)
+				listener.DataChange(remoting.Event{
+					Path:    string(event.Kv.Key),
+					Action:  remoting.EventTypeAdd,
+					Content: string(event.Kv.Value),
+				})
+			case false:
+				logger.Infof("etcd get event (key{%s}) = event{EventNodeDataChanged}", event.Kv.Key)
+				listener.DataChange(remoting.Event{
+					Path:    string(event.Kv.Key),
+					Action:  remoting.EvnetTypeUpdate,
+					Content: string(event.Kv.Value),
+				})
+			}
+		}
+		return false
+	case mvccpb.DELETE:
+		logger.Warnf("etcd get event (key{%s}) = event{EventNodeDeleted}", event.Kv.Key)
+		return true
+
+	default:
+		return false
+	}
+
+	panic("unreachable")
+}
+
+// Listen on a set of key with spec prefix
+func (l *EventListener) ListenServiceNodeEventWithPrefix(prefix string, listener ...remoting.DataListener) {
+
+	l.wg.Add(1)
+	defer l.wg.Done()
+	for {
+		wc, err := l.client.WatchWithPrefix(prefix)
+		if err != nil {
+			logger.Warnf("listenDirEvent(key{%s}) = error{%v}", prefix, err)
+		}
+
+		select {
+
+		// client stopped
+		case <-l.client.Done():
+			logger.Warnf("etcd client stopped")
+			return
+
+			// client ctx stop
+		case <-l.client.ctx.Done():
+			logger.Warnf("etcd client ctx cancel")
+			return
+
+			// etcd event stream
+		case e, ok := <-wc:
+
+			if !ok {
+				logger.Warnf("etcd watch-chan closed")
+				return
+			}
+
+			if e.Err() != nil {
+				logger.Errorf("etcd watch ERR {err: %s}", e.Err())
+				continue
+			}
+			for _, event := range e.Events {
+				l.handleEvents(event, listener...)
+			}
+		}
+	}
+}
+
+func timeSecondDuration(sec int) time.Duration {
+	return time.Duration(sec) * time.Second
+}
+
+// this func is invoked by etcdv3 ConsumerRegistry::Registe/ etcdv3 ConsumerRegistry::get/etcdv3 ConsumerRegistry::getListener
+// registry.go:Listen -> listenServiceEvent -> listenDirEvent -> ListenServiceNodeEvent
+//                            |
+//                            --------> ListenServiceNodeEvent
+func (l *EventListener) ListenServiceEvent(key string, listener remoting.DataListener) {
+
+	l.keyMapLock.Lock()
+	_, ok := l.keyMap[key]
+	l.keyMapLock.Unlock()
+	if ok {
+		logger.Warnf("etcdv3 key %s has already been listened.", key)
+		return
+	}
+
+	l.keyMapLock.Lock()
+	l.keyMap[key] = struct{}{}
+	l.keyMapLock.Unlock()
+
+	keyList, valueList, err := l.client.getChildren(key)
+	if err != nil {
+		logger.Errorf("Get new node path {%v} 's content error,message is  {%v}", key, perrors.WithMessage(err, "get children"))
+	}
+
+	logger.Infof("get key children list %s, keys %v values %v", key, keyList, valueList)
+
+	for i, k := range keyList {
+		logger.Infof("got children list key -> %s", k)
+		listener.DataChange(remoting.Event{
+			Path:    k,
+			Action:  remoting.EventTypeAdd,
+			Content: valueList[i],
+		})
+	}
+
+	logger.Infof("listen dubbo provider key{%s} event and wait to get all provider etcdv3 nodes", key)
+	go func(key string, listener remoting.DataListener) {
+		l.ListenServiceNodeEventWithPrefix(key, listener)
+		logger.Warnf("listenDirEvent(key{%s}) goroutine exit now", key)
+	}(key, listener)
+
+	logger.Infof("listen dubbo service key{%s}", key)
+	go func(key string) {
+		if l.ListenServiceNodeEvent(key) {
+			listener.DataChange(remoting.Event{Path: key, Action: remoting.EventTypeDel})
+		}
+		logger.Warnf("listenSelf(etcd key{%s}) goroutine exit now", key)
+	}(key)
+}
+
+func (l *EventListener) Close() {
+	l.wg.Wait()
+}
diff --git a/remoting/etcdv3/listener_test.go b/remoting/etcdv3/listener_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..33904a21345ec0ac7ee1adbb239a0a7a44852387
--- /dev/null
+++ b/remoting/etcdv3/listener_test.go
@@ -0,0 +1,87 @@
+package etcdv3
+
+import (
+	"time"
+)
+
+import (
+	"github.com/stretchr/testify/assert"
+)
+
+import (
+	"github.com/apache/dubbo-go/remoting"
+)
+
+var changedData = `
+	dubbo.consumer.request_timeout=3s
+	dubbo.consumer.connect_timeout=5s
+	dubbo.application.organization=ikurento.com
+	dubbo.application.name=BDTService
+	dubbo.application.module=dubbogo user-info server
+	dubbo.application.version=0.0.1
+	dubbo.application.owner=ZX
+	dubbo.application.environment=dev
+	dubbo.registries.hangzhouzk.protocol=zookeeper
+	dubbo.registries.hangzhouzk.timeout=3s
+	dubbo.registries.hangzhouzk.address=127.0.0.1:2181
+	dubbo.registries.shanghaizk.protocol=zookeeper
+	dubbo.registries.shanghaizk.timeout=3s
+	dubbo.registries.shanghaizk.address=127.0.0.1:2182
+	dubbo.service.com.ikurento.user.UserProvider.protocol=dubbo
+	dubbo.service.com.ikurento.user.UserProvider.interface=com.ikurento.user.UserProvider
+	dubbo.service.com.ikurento.user.UserProvider.loadbalance=random
+	dubbo.service.com.ikurento.user.UserProvider.warmup=100
+	dubbo.service.com.ikurento.user.UserProvider.cluster=failover
+`
+
+func (suite *ClientTestSuite) TestListener() {
+
+	var tests = []struct {
+		input struct {
+			k string
+			v string
+		}
+	}{
+		{input: struct {
+			k string
+			v string
+		}{k: "/dubbo", v: changedData}},
+	}
+
+	c := suite.client
+	t := suite.T()
+
+	listener := NewEventListener(c)
+	dataListener := &mockDataListener{client: c, changedData: changedData, rc: make(chan remoting.Event)}
+	listener.ListenServiceEvent("/dubbo", dataListener)
+
+	// NOTICE:  direct listen will lose create msg
+	time.Sleep(time.Second)
+	for _, tc := range tests {
+
+		k := tc.input.k
+		v := tc.input.v
+		if err := c.Create(k, v); err != nil {
+			t.Fatal(err)
+		}
+
+	}
+	msg := <-dataListener.rc
+	assert.Equal(t, changedData, msg.Content)
+}
+
+type mockDataListener struct {
+	eventList   []remoting.Event
+	client      *Client
+	changedData string
+
+	rc chan remoting.Event
+}
+
+func (m *mockDataListener) DataChange(eventType remoting.Event) bool {
+	m.eventList = append(m.eventList, eventType)
+	if eventType.Content == m.changedData {
+		m.rc <- eventType
+	}
+	return true
+}
diff --git a/remoting/listener.go b/remoting/listener.go
index da30f6989dbaae5668ad189b4fdef945d622fd9b..fd566f353857943acd620af5da21e85054dff646 100644
--- a/remoting/listener.go
+++ b/remoting/listener.go
@@ -52,6 +52,7 @@ const (
 var serviceEventTypeStrings = [...]string{
 	"add",
 	"delete",
+	"update",
 }
 
 func (t EventType) String() string {
diff --git a/remoting/zookeeper/facade.go b/remoting/zookeeper/facade.go
index 4eace5e9d540ac86ca01683963b19ae547c7c732..cdc7ead61226906a629fdb99b6b966ada5ee5253 100644
--- a/remoting/zookeeper/facade.go
+++ b/remoting/zookeeper/facade.go
@@ -63,14 +63,14 @@ LOOP:
 			r.SetZkClient(nil)
 			r.ZkClientLock().Unlock()
 
-			// 鎺k锛岀洿鑷虫垚鍔�
+			// Connect zk until success.
 			failTimes = 0
 			for {
 				select {
 				case <-r.GetDone():
 					logger.Warnf("(ZkProviderRegistry)reconnectZkRegistry goroutine exit now...")
 					break LOOP
-				case <-getty.GetTimeWheel().After(timeSecondDuration(failTimes * ConnDelay)): // 闃叉鐤媯閲嶈繛zk
+				case <-getty.GetTimeWheel().After(timeSecondDuration(failTimes * ConnDelay)): // Prevent crazy reconnection zk.
 				}
 				err = ValidateZookeeperClient(r, WithZkName(zkName))
 				logger.Infof("ZkProviderRegistry.validateZookeeperClient(zkAddr{%s}) = error{%#v}",
diff --git a/version/version.go b/version/version.go
deleted file mode 100644
index b9a076e78cbf0c9c7b5172e1b30c84f60f250ea7..0000000000000000000000000000000000000000
--- a/version/version.go
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package version
-
-const (
-	Version = "2.6.0"
-	Name    = "dubbogo"
-	DATE    = "2019/05/06"
-)