Repository: go-kratos/kratos
Pull request #1563 (2021-10-18 08:32:00)

feat(http): http client support service discovery in Do
<!--
🎉 Thanks for sending a pull request to Kratos! Here are some tips for you:

1. If this is your first time contributing to Kratos, please read our contribution guide: https://go-kratos.dev/en/docs/community/contribution/
2. Ensure you have added or ran the appropriate tests and lint for your PR, please use `make lint` and `make test` before filing your PR, use `make clean` to tidy your go mod.
3. If the PR is unfinished, you may need mark it as a WIP(Work In Progress) PR or draft PR
4. Please use a conventional commits format title: `<type>[optional scope]: <description>`
    
    Some suggestion on <type>:

    fix: A bug fix
    feat: A new feature
    test: Adding missing tests or correcting existing tests
    refactor: A code change that neither fixes a bug nor adds a feature
    break: Changes has break change

    docs: Documentation only changes
    deps: Changes external dependencies
    style: Changes that do not affect the meaning of the code (white-space, formatting, etc)
    chore Daily work, examples, etc.
    ci: Changes to our CI configuration files and scripts
-->

#### Description (what this PR does / why we need it):
<!--
* The description should include the motivation for this PR or contrast this with previous behavior
-->


#### Which issue(s) this PR fixes (resolves / be part of):
<!--
* Automatically closes linked issue when PR is merged.
* If you PR is not fully resolved issue, please use `part of #<issue number>` instead.

Usage: `fixes/resolves #<issue number>`, or `fixes/resolves (paste link of issue)`.
-->
fixes # https://github.com/go-kratos/kratos/issues/1562

#### Other special notes for reviewer:
<!--
* Somethings that need extra attention for reviewer
* Some additional notes, TODO list, etc.
-->


codecov-commenter: # [Codecov](https://codecov.io/gh/go-kratos/kratos/pull/1563?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=go-kratos) Report
> Merging [#1563](https://codecov.io/gh/go-kratos/kratos/pull/1563?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=go-kratos) (43ec3fd) into [main](https://codecov.io/gh/go-kratos/kratos/commit/2d026f1f95d40be99811aeb47651870e2fa627b0?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=go-kratos) (2d026f1) will **decrease** coverage by `0.04%`.
> The diff coverage is `0.00%`.

[![Impacted file tree graph](https://codecov.io/gh/go-kratos/kratos/pull/1563/graphs/tree.svg?width=650&height=150&src=pr&token=XwnmBTz78x&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=go-kratos)](https://codecov.io/gh/go-kratos/kratos/pull/1563?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=go-kratos)

```diff
@@            Coverage Diff             @@
##             main    #1563      +/-   ##
==========================================
- Coverage   68.75%   68.71%   -0.05%     
==========================================
  Files          68       68              
  Lines        3108     3110       +2     
==========================================
  Hits         2137     2137              
- Misses        791      793       +2     
  Partials      180      180              
```


| [Impacted Files](https://codecov.io/gh/go-kratos/kratos/pull/1563?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=go-kratos) | Coverage Δ | |
|---|---|---|
| [transport/http/client.go](https://codecov.io/gh/go-kratos/kratos/pull/1563/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=go-kratos#diff-dHJhbnNwb3J0L2h0dHAvY2xpZW50Lmdv) | `65.38% <0.00%> (-0.73%)` | :arrow_down: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/go-kratos/kratos/pull/1563?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=go-kratos).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=go-kratos)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/go-kratos/kratos/pull/1563?src=pr&el=footer&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=go-kratos). Last update [2d026f1...43ec3fd](https://codecov.io/gh/go-kratos/kratos/pull/1563?src=pr&el=lastupdated&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=go-kratos). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=go-kratos).


Patch:
diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml
index 0e5e2684..d3b84788 100644
--- a/.github/workflows/go.yml
+++ b/.github/workflows/go.yml
@@ -25,10 +25,15 @@ jobs:
         image: consul:latest
         ports:
           - 8500:8500
-
+      nacos:
+        image: nacos/nacos-server:latest
+        env:
+          MODE: standalone
+        ports:
+          - "8848:8848"
+          - "9848:9848"
     steps:
       - uses: actions/checkout@v2
-
       - name: Set up Go
         uses: actions/setup-go@v2
         with:
diff --git a/cmd/kratos/internal/base/repo.go b/cmd/kratos/internal/base/repo.go
index ec4cb09d..7bf606d3 100644
--- a/cmd/kratos/internal/base/repo.go
+++ b/cmd/kratos/internal/base/repo.go
@@ -2,6 +2,7 @@ package base
 
 import (
 	"context"
+	"fmt"
 	"os"
 	"os/exec"
 	"path"
@@ -50,17 +51,19 @@ func (r *Repo) Path() string {
 
 // Pull fetch the repository from remote url.
 func (r *Repo) Pull(ctx context.Context) error {
-	cmd := exec.Command("git", "symbolic-ref", "HEAD")
+	cmd := exec.CommandContext(ctx, "git", "symbolic-ref", "HEAD")
 	cmd.Dir = r.Path()
-	err := cmd.Run()
+	_, err := cmd.CombinedOutput()
 	if err != nil {
 		return nil
 	}
-	cmd = exec.Command("git", "pull")
+	cmd = exec.CommandContext(ctx, "git", "pull")
 	cmd.Dir = r.Path()
-	cmd.Stderr = os.Stderr
-	cmd.Stdout = os.Stdout
-	err = cmd.Run()
+	out, err := cmd.CombinedOutput()
+	if err != nil {
+		return err
+	}
+	fmt.Println(string(out))
 	return err
 }
 
@@ -71,14 +74,16 @@ func (r *Repo) Clone(ctx context.Context) error {
 	}
 	var cmd *exec.Cmd
 	if r.branch == "" {
-		cmd = exec.Command("git", "clone", r.url, r.Path())
+		cmd = exec.CommandContext(ctx, "git", "clone", r.url, r.Path())
 	} else {
-		cmd = exec.Command("git", "clone", "-b", r.branch, r.url, r.Path())
+		cmd = exec.CommandContext(ctx, "git", "clone", "-b", r.branch, r.url, r.Path())
 	}
-	cmd.Stderr = os.Stderr
-	cmd.Stdout = os.Stdout
-	err := cmd.Run()
-	return err
+	out, err := cmd.CombinedOutput()
+	if err != nil {
+		return err
+	}
+	fmt.Println(string(out))
+	return nil
 }
 
 // CopyTo copies the repository to project path.
diff --git a/cmd/kratos/internal/project/project.go b/cmd/kratos/internal/project/project.go
index 1ead3cbc..dd0a3c18 100644
--- a/cmd/kratos/internal/project/project.go
+++ b/cmd/kratos/internal/project/project.go
@@ -2,6 +2,7 @@ package project
 
 import (
 	"context"
+	"errors"
 	"fmt"
 	"os"
 	"path"
@@ -22,14 +23,17 @@ var CmdNew = &cobra.Command{
 var (
 	repoURL string
 	branch  string
+	timeout string
 )
 
 func init() {
 	if repoURL = os.Getenv("KRATOS_LAYOUT_REPO"); repoURL == "" {
 		repoURL = "https://github.com/go-kratos/kratos-layout.git"
 	}
+	timeout = "60s"
 	CmdNew.Flags().StringVarP(&repoURL, "repo-url", "r", repoURL, "layout repo")
 	CmdNew.Flags().StringVarP(&branch, "branch", "b", branch, "repo branch")
+	CmdNew.Flags().StringVarP(&timeout, "timeout", "t", timeout, "time out")
 }
 
 func run(cmd *cobra.Command, args []string) {
@@ -37,7 +41,11 @@ func run(cmd *cobra.Command, args []string) {
 	if err != nil {
 		panic(err)
 	}
-	ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
+	t, err := time.ParseDuration(timeout)
+	if err != nil {
+		panic(err)
+	}
+	ctx, cancel := context.WithTimeout(context.Background(), t)
 	defer cancel()
 	name := ""
 	if len(args) == 0 {
@@ -53,8 +61,20 @@ func run(cmd *cobra.Command, args []string) {
 		name = args[0]
 	}
 	p := &Project{Name: path.Base(name), Path: name}
-	if err := p.New(ctx, wd, repoURL, branch); err != nil {
-		fmt.Fprintf(os.Stderr, "\033[31mERROR: %s\033[m\n", err)
-		return
+	done := make(chan error, 1)
+	go func() {
+		done <- p.New(ctx, wd, repoURL, branch)
+	}()
+	select {
+	case <-ctx.Done():
+		if errors.Is(ctx.Err(), context.DeadlineExceeded) {
+			fmt.Fprint(os.Stderr, "\033[31mERROR: project creation timed out\033[m\n")
+		} else {
+			fmt.Fprintf(os.Stderr, "\033[31mERROR: failed to create project(%s)\033[m\n", ctx.Err())
+		}
+	case err = <-done:
+		if err != nil {
+			fmt.Fprintf(os.Stderr, "\033[31mERROR: Failed to create project(%s)\033[m\n", ctx.Err())
+		}
 	}
 }
diff --git a/cmd/protoc-gen-go-http/http.go b/cmd/protoc-gen-go-http/http.go
index 6742808e..4d6c80d9 100644
--- a/cmd/protoc-gen-go-http/http.go
+++ b/cmd/protoc-gen-go-http/http.go
@@ -164,6 +164,9 @@ func buildMethodDesc(g *protogen.GeneratedFile, m *protogen.Method, method, path
 			if strings.TrimSpace(field) == "" {
 				continue
 			}
+			if strings.Contains(field, ":") {
+				field = strings.Split(field, ":")[0]
+			}
 			fd := fields.ByName(protoreflect.Name(field))
 			if fd == nil {
 				fmt.Fprintf(os.Stderr, "\u001B[31mERROR\u001B[m: The corresponding field '%s' declaration in message could not be found in '%s'\n", v, path)
diff --git a/contrib/config/consul/README.md b/contrib/config/consul/README.md
new file mode 100644
index 00000000..03de8d5c
--- /dev/null
+++ b/contrib/config/consul/README.md
@@ -0,0 +1,36 @@
+# Consul Config
+
+```go
+import (
+	kconfig "github.com/go-kratos/kratos/v2/config"
+	"github.com/nacos-group/nacos-sdk-go/clients"
+	"github.com/nacos-group/nacos-sdk-go/common/constant"
+)
+
+
+sc := []constant.ServerConfig{
+	*constant.NewServerConfig("127.0.0.1", 8848),
+}
+
+cc := &constant.ClientConfig{
+	NamespaceId:         "public", //namespace id
+	TimeoutMs:           5000,
+	NotLoadCacheAtStart: true,
+	LogDir:              "/tmp/nacos/log",
+	CacheDir:            "/tmp/nacos/cache",
+	RotateTime:          "1h",
+	MaxAge:              3,
+	LogLevel:            "debug",
+}
+
+// a more graceful way to create naming client
+client, err := clients.NewNamingClient(
+	vo.NacosClientParam{
+		ClientConfig:  cc,
+		ServerConfigs: sc,
+	},
+)
+if err != nil {
+	log.Panic(err)
+}
+```
\ No newline at end of file
diff --git a/contrib/config/kubernetes/README.md b/contrib/config/kubernetes/README.md
index 0345db1c..46919537 100644
--- a/contrib/config/kubernetes/README.md
+++ b/contrib/config/kubernetes/README.md
@@ -1,14 +1,13 @@
-# kube
-Kubernetes is a service discovery.
+# Kubernetes Config
 
-### kube集群内部署
-集群内部署需要权限
-kubectl执行
-> serviceaccount 请调整为实际环境account。在未指定spec.serviceAccount情况下默认为namespace::default
+### Usage in the Kubernates Cluster
+It is required to 
+> serviceaccount should be set to the actual account of your environment, the default account will be `namespace::default` if the `spec.serviceAccount` is unset. 
+execute this command:
 ```
 kubectl create clusterrolebinding go-kratos:kube --clusterrole=view --serviceaccount=mesh:default
 ```
-或者 kubect apply -f bind-role.yaml
+or use `kubect apply -f bind-role.yaml`
 ```yaml
 apiVersion: rbac.authorization.k8s.io/v1
 kind: ClusterRoleBinding
@@ -24,8 +23,8 @@ subjects:
   namespace: mesh
 ```
 
-### 集群外运行
-> 指定 .kube 文件访问
+### Usage outside the Kubernates Cluster
+Set the path `~/.kube/config` to KubeConfig
 ```go
     config.NewSource(SourceOption{
 		Namespace:     "mesh",
diff --git a/contrib/config/nacos/README.md b/contrib/config/nacos/README.md
new file mode 100644
index 00000000..1bb7b53b
--- /dev/null
+++ b/contrib/config/nacos/README.md
@@ -0,0 +1,36 @@
+# Nacos Config
+
+```go
+import (
+	kconfig "github.com/go-kratos/kratos/v2/config"
+	"github.com/nacos-group/nacos-sdk-go/clients"
+	"github.com/nacos-group/nacos-sdk-go/common/constant"
+)
+
+
+sc := []constant.ServerConfig{
+	*constant.NewServerConfig("127.0.0.1", 8848),
+}
+
+cc := &constant.ClientConfig{
+	NamespaceId:         "public", //namespace id
+	TimeoutMs:           5000,
+	NotLoadCacheAtStart: true,
+	LogDir:              "/tmp/nacos/log",
+	CacheDir:            "/tmp/nacos/cache",
+	RotateTime:          "1h",
+	MaxAge:              3,
+	LogLevel:            "debug",
+}
+
+// a more graceful way to create naming client
+client, err := clients.NewNamingClient(
+	vo.NacosClientParam{
+		ClientConfig:  cc,
+		ServerConfigs: sc,
+	},
+)
+if err != nil {
+	log.Panic(err)
+}
+```
\ No newline at end of file
diff --git a/contrib/config/nacos/go.mod b/contrib/config/nacos/go.mod
index 42131209..f5276895 100644
--- a/contrib/config/nacos/go.mod
+++ b/contrib/config/nacos/go.mod
@@ -4,7 +4,8 @@ go 1.16
 
 require (
 	github.com/go-kratos/kratos/v2 v2.1.0
-	github.com/nacos-group/nacos-sdk-go v1.0.8
+	github.com/nacos-group/nacos-sdk-go v1.0.9
+	gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b
 )
 
 replace github.com/go-kratos/kratos/v2 => ../../../
diff --git a/contrib/config/nacos/go.sum b/contrib/config/nacos/go.sum
index 6c4d253f..ed1107ef 100644
--- a/contrib/config/nacos/go.sum
+++ b/contrib/config/nacos/go.sum
@@ -6,6 +6,7 @@ github.com/StackExchange/wmi v1.2.1/go.mod h1:rcmrprowKIVzvc+NUiLncP2uuArMWLCbu9
 github.com/aliyun/alibaba-cloud-sdk-go v1.61.18 h1:zOVTBdCKFd9JbCKz9/nt+FovbjPFmb7mUnp8nH9fQBA=
 github.com/aliyun/alibaba-cloud-sdk-go v1.61.18/go.mod h1:v8ESoHo4SyHmuB4b1tJqDHxfTGEciD+yhvOU/5s1Rfk=
 github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
+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/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
 github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
@@ -94,8 +95,8 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w
 github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
 github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 h1:Esafd1046DLDQ0W1YjYsBW+p8U2u7vzgW2SQVmlNazg=
 github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
-github.com/nacos-group/nacos-sdk-go v1.0.8 h1:8pEm05Cdav9sQgJSv5kyvlgfz0SzFUUGI3pWX6SiSnM=
-github.com/nacos-group/nacos-sdk-go v1.0.8/go.mod h1:hlAPn3UdzlxIlSILAyOXKxjFSvDJ9oLzTJ9hLAK1KzA=
+github.com/nacos-group/nacos-sdk-go v1.0.9 h1:sMvrp6tZj4LdhuHRsS4GCqASB81k3pjmT2ykDQQpwt0=
+github.com/nacos-group/nacos-sdk-go v1.0.9/go.mod h1:hlAPn3UdzlxIlSILAyOXKxjFSvDJ9oLzTJ9hLAK1KzA=
 github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
 github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
 github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
@@ -119,6 +120,7 @@ github.com/tebeka/strftime v0.1.3 h1:5HQXOqWKYRFfNyBMNVc9z5+QzuBtIXy03psIhtdJYto
 github.com/tebeka/strftime v0.1.3/go.mod h1:7wJm3dZlpr4l/oVK0t1HYIc4rMzQ2XJlOMIUJUJH6XQ=
 github.com/tklauser/go-sysconf v0.3.9/go.mod h1:11DU/5sG7UexIrp/O6g35hrWzu0JxlwQ3LSFUzyeuhs=
 github.com/tklauser/numcpus v0.3.0/go.mod h1:yFGUr7TUHQRAhyqBcEg0Ge34zDBAsIvJJcyE6boqnA8=
+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/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
 go.opentelemetry.io/otel v1.0.0/go.mod h1:AjRVh9A5/5DE7S+mZtTR6t8vpKKryam+0lREnfmS4cg=
diff --git a/contrib/encoding/msgpack/go.sum b/contrib/encoding/msgpack/go.sum
index e0f307f8..e96832c1 100644
--- a/contrib/encoding/msgpack/go.sum
+++ b/contrib/encoding/msgpack/go.sum
@@ -44,7 +44,6 @@ github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw
 github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ=
 github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
 github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
@@ -124,7 +123,6 @@ golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
 golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
 golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
 google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
@@ -152,7 +150,6 @@ google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpAD
 google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
 google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
 google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
-google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ=
 google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
diff --git a/contrib/encoding/msgpack/msgpack.go b/contrib/encoding/msgpack/msgpack.go
index e4837dc1..4272b16b 100644
--- a/contrib/encoding/msgpack/msgpack.go
+++ b/contrib/encoding/msgpack/msgpack.go
@@ -1,8 +1,9 @@
 package msgpack
 
 import (
-	"github.com/go-kratos/kratos/v2/encoding"
 	"github.com/vmihailenco/msgpack/v5"
+
+	"github.com/go-kratos/kratos/v2/encoding"
 )
 
 // Name is the name registered for the msgpack compressor.
diff --git a/contrib/registry/discovery/README.md b/contrib/registry/discovery/README.md
index 1fa34097..48bd654f 100644
--- a/contrib/registry/discovery/README.md
+++ b/contrib/registry/discovery/README.md
@@ -1,2 +1,4 @@
+# Discovery Registry
+
 ## [discovery](https://github.com/bilibili/discovery)
 
diff --git a/contrib/registry/kubernetes/registry.go b/contrib/registry/kubernetes/registry.go
index f1e3b95e..16adf076 100644
--- a/contrib/registry/kubernetes/registry.go
+++ b/contrib/registry/kubernetes/registry.go
@@ -12,7 +12,6 @@ import (
 	"strings"
 	"time"
 
-	"github.com/go-kratos/kratos/v2/registry"
 	jsoniter "github.com/json-iterator/go"
 	corev1 "k8s.io/api/core/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -22,6 +21,8 @@ import (
 	"k8s.io/client-go/kubernetes"
 	listerv1 "k8s.io/client-go/listers/core/v1"
 	"k8s.io/client-go/tools/cache"
+
+	"github.com/go-kratos/kratos/v2/registry"
 )
 
 // Defines the key name of specific fields
@@ -166,7 +167,7 @@ func (s *Registry) Service(name string) ([]*registry.ServiceInstance, error) {
 	if err != nil {
 		return nil, err
 	}
-	var ret []*registry.ServiceInstance
+	ret := make([]*registry.ServiceInstance, 0, len(pods))
 	for _, pod := range pods {
 		if pod.Status.Phase != corev1.PodRunning {
 			continue
@@ -342,14 +343,14 @@ func getProtocolMapByEndpoints(endpoints []string) (protocolMap, error) {
 }
 
 func getProtocolMapFromPod(pod *corev1.Pod) (protocolMap, error) {
-	protocolMap := protocolMap{}
+	protoMap := protocolMap{}
 	if s := pod.Annotations[AnnotationsKeyProtocolMap]; !isEmptyObjectString(s) {
-		err := unmarshal(s, &protocolMap)
+		err := unmarshal(s, &protoMap)
 		if err != nil {
 			return nil, &ErrorHandleResource{Namespace: pod.Namespace, Name: pod.Name, Reason: err}
 		}
 	}
-	return protocolMap, nil
+	return protoMap, nil
 }
 
 func getMetadataFromPod(pod *corev1.Pod) (map[string]string, error) {
diff --git a/contrib/registry/nacos/README.md b/contrib/registry/nacos/README.md
new file mode 100644
index 00000000..05c30547
--- /dev/null
+++ b/contrib/registry/nacos/README.md
@@ -0,0 +1,50 @@
+# Nacos Registry
+
+```go
+import (
+		"github.com/go-kratos/kratos/v2"
+		"github.com/go-kratos/kratos/v2/transport/grpc"
+		
+		"github.com/nacos-group/nacos-sdk-go/clients"
+		"github.com/nacos-group/nacos-sdk-go/common/constant"
+    	"github.com/nacos-group/nacos-sdk-go/vo"
+)
+
+sc := []constant.ServerConfig{
+	*constant.NewServerConfig("127.0.0.1", 8848),
+}
+
+cc := constant.ClientConfig{
+	NamespaceId:         "public",
+	TimeoutMs:           5000,
+}
+
+client, err := clients.NewNamingClient(
+	vo.NacosClientParam{
+		ClientConfig:  &cc,
+		ServerConfigs: sc,
+	},
+)
+
+if err != nil {
+	log.Panic(err)
+}
+
+r := nacos.New(client)
+
+// server
+app := kratos.New(
+	kratos.Name("helloworld"),
+	kratos.Registrar(r),
+)
+if err := app.Run(); err != nil {
+	log.Fatal(err)
+}
+
+// client
+conn, err := grpc.DialInsecure(
+	context.Background(),
+	grpc.WithEndpoint("discovery:///helloworld"),
+	grpc.WithDiscovery(r),
+)
+```
\ No newline at end of file
diff --git a/contrib/registry/nacos/go.mod b/contrib/registry/nacos/go.mod
index ca74b472..bf99b958 100644
--- a/contrib/registry/nacos/go.mod
+++ b/contrib/registry/nacos/go.mod
@@ -4,7 +4,7 @@ go 1.16
 
 require (
 	github.com/go-kratos/kratos/v2 v2.1.0
-	github.com/nacos-group/nacos-sdk-go v1.0.8
+	github.com/nacos-group/nacos-sdk-go v1.0.9
 )
 
 replace github.com/go-kratos/kratos/v2 => ../../../
diff --git a/contrib/registry/nacos/go.sum b/contrib/registry/nacos/go.sum
index ad8e5810..97144973 100644
--- a/contrib/registry/nacos/go.sum
+++ b/contrib/registry/nacos/go.sum
@@ -3,6 +3,7 @@ cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMT
 github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
 github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
 github.com/StackExchange/wmi v1.2.1/go.mod h1:rcmrprowKIVzvc+NUiLncP2uuArMWLCbu9SBzvHz7e8=
+github.com/aliyun/alibaba-cloud-sdk-go v1.61.18 h1:zOVTBdCKFd9JbCKz9/nt+FovbjPFmb7mUnp8nH9fQBA=
 github.com/aliyun/alibaba-cloud-sdk-go v1.61.18/go.mod h1:v8ESoHo4SyHmuB4b1tJqDHxfTGEciD+yhvOU/5s1Rfk=
 github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
 github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23 h1:D21IyuvjDCshj1/qq+pCNd3VZOAEI9jy6Bi131YlXgI=
@@ -60,17 +61,21 @@ github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
 github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
 github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
 github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+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/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
 github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
 github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
 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 h1:MrUvLMLTMxbqFJ9kzlvat/rYZqZnW3u4wkLzWTaFwKs=
 github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
+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/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
 github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
@@ -84,10 +89,12 @@ github.com/lestrrat/go-file-rotatelogs v0.0.0-20180223000712-d3151e2a480f h1:sgU
 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/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 h1:Esafd1046DLDQ0W1YjYsBW+p8U2u7vzgW2SQVmlNazg=
 github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
-github.com/nacos-group/nacos-sdk-go v1.0.8 h1:8pEm05Cdav9sQgJSv5kyvlgfz0SzFUUGI3pWX6SiSnM=
-github.com/nacos-group/nacos-sdk-go v1.0.8/go.mod h1:hlAPn3UdzlxIlSILAyOXKxjFSvDJ9oLzTJ9hLAK1KzA=
+github.com/nacos-group/nacos-sdk-go v1.0.9 h1:sMvrp6tZj4LdhuHRsS4GCqASB81k3pjmT2ykDQQpwt0=
+github.com/nacos-group/nacos-sdk-go v1.0.9/go.mod h1:hlAPn3UdzlxIlSILAyOXKxjFSvDJ9oLzTJ9hLAK1KzA=
 github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
 github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
 github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
@@ -97,7 +104,9 @@ github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:
 github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
 github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
 github.com/shirou/gopsutil/v3 v3.21.8/go.mod h1:YWp/H8Qs5fVmf17v7JNZzA0mPJ+mS2e9JdiUF9LlKzQ=
+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/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
 github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
@@ -222,6 +231,7 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8
 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/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
+gopkg.in/ini.v1 v1.42.0 h1:7N3gPTt50s8GuLortA00n8AqRTk75qOP98+mTPpgzRk=
 gopkg.in/ini.v1 v1.42.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
 gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
diff --git a/contrib/registry/nacos/registry.go b/contrib/registry/nacos/registry.go
index f36e4c2f..56414ef7 100644
--- a/contrib/registry/nacos/registry.go
+++ b/contrib/registry/nacos/registry.go
@@ -7,9 +7,10 @@ import (
 	"net/url"
 	"strconv"
 
-	"github.com/go-kratos/kratos/v2/registry"
 	"github.com/nacos-group/nacos-sdk-go/clients/naming_client"
 	"github.com/nacos-group/nacos-sdk-go/vo"
+
+	"github.com/go-kratos/kratos/v2/registry"
 )
 
 var (
@@ -155,7 +156,7 @@ func (r *Registry) GetService(ctx context.Context, serviceName string) ([]*regis
 	if err != nil {
 		return nil, err
 	}
-	var items []*registry.ServiceInstance
+	items := make([]*registry.ServiceInstance, 0, len(res))
 	for _, in := range res {
 		items = append(items, &registry.ServiceInstance{
 			ID:        in.InstanceId,
diff --git a/contrib/registry/nacos/watcher.go b/contrib/registry/nacos/watcher.go
index 9696a864..3cb1d0f7 100644
--- a/contrib/registry/nacos/watcher.go
+++ b/contrib/registry/nacos/watcher.go
@@ -10,9 +10,7 @@ import (
 	"github.com/nacos-group/nacos-sdk-go/vo"
 )
 
-var (
-	_ registry.Watcher = (*watcher)(nil)
-)
+var _ registry.Watcher = (*watcher)(nil)
 
 type watcher struct {
 	serviceName string
@@ -46,36 +44,34 @@ func newWatcher(ctx context.Context, cli naming_client.INamingClient, serviceNam
 }
 
 func (w *watcher) Next() ([]*registry.ServiceInstance, error) {
-	for {
-		select {
-		case <-w.ctx.Done():
-			return nil, w.ctx.Err()
-		case <-w.watchChan:
-		}
-		res, err := w.cli.GetService(vo.GetServiceParam{
-			ServiceName: w.serviceName,
-			GroupName:   w.groupName,
-			Clusters:    w.clusters,
+	select {
+	case <-w.ctx.Done():
+		return nil, w.ctx.Err()
+	case <-w.watchChan:
+	}
+	res, err := w.cli.GetService(vo.GetServiceParam{
+		ServiceName: w.serviceName,
+		GroupName:   w.groupName,
+		Clusters:    w.clusters,
+	})
+	if err != nil {
+		return nil, err
+	}
+	items := make([]*registry.ServiceInstance, 0, len(res.Hosts))
+	for _, in := range res.Hosts {
+		items = append(items, &registry.ServiceInstance{
+			ID:        in.InstanceId,
+			Name:      res.Name,
+			Version:   in.Metadata["version"],
+			Metadata:  in.Metadata,
+			Endpoints: []string{fmt.Sprintf("%s://%s:%d", in.Metadata["kind"], in.Ip, in.Port)},
 		})
-		if err != nil {
-			return nil, err
-		}
-		var items []*registry.ServiceInstance
-		for _, in := range res.Hosts {
-			items = append(items, &registry.ServiceInstance{
-				ID:        in.InstanceId,
-				Name:      res.Name,
-				Version:   in.Metadata["version"],
-				Metadata:  in.Metadata,
-				Endpoints: []string{fmt.Sprintf("%s://%s:%d", in.Metadata["kind"], in.Ip, in.Port)},
-			})
-		}
-		return items, nil
 	}
+	return items, nil
 }
 
 func (w *watcher) Stop() error {
 	w.cancel()
-	//close
+	// close
 	return nil
 }
diff --git a/contrib/registry/zookeeper/register.go b/contrib/registry/zookeeper/register.go
index 22062bb0..3f73e64f 100644
--- a/contrib/registry/zookeeper/register.go
+++ b/contrib/registry/zookeeper/register.go
@@ -8,8 +8,9 @@ import (
 	"sync/atomic"
 	"time"
 
-	"github.com/go-kratos/kratos/v2/registry"
 	"github.com/go-zookeeper/zk"
+
+	"github.com/go-kratos/kratos/v2/registry"
 )
 
 var (
@@ -70,9 +71,11 @@ func New(zkServers []string, opts ...Option) (*Registry, error) {
 }
 
 func (r *Registry) Register(ctx context.Context, service *registry.ServiceInstance) error {
-	var data []byte
-	var err error
-	if err := r.ensureName(r.opts.rootPath, []byte("")); err != nil {
+	var (
+		data []byte
+		err  error
+	)
+	if err = r.ensureName(r.opts.rootPath, []byte("")); err != nil {
 		return err
 	}
 	serviceNamePath := path.Join(r.opts.rootPath, service.Name)
@@ -113,9 +116,9 @@ func (r *Registry) GetService(ctx context.Context, serviceName string) ([]*regis
 	if err != nil {
 		return nil, err
 	}
-	var items []*registry.ServiceInstance
+	items := make([]*registry.ServiceInstance, 0, len(servicesID))
 	for _, service := range servicesID {
-		var item = &registry.ServiceInstance{}
+		item := &registry.ServiceInstance{}
 		servicePath := path.Join(serviceNamePath, service)
 		serviceInstanceByte, _, err := r.conn.Get(servicePath)
 		if err != nil {
@@ -135,7 +138,7 @@ func (r *Registry) Watch(ctx context.Context, serviceName string) (registry.Watc
 	set, ok := r.registry[serviceName]
 	if !ok {
 		set = &serviceSet{
-			watcher:     make(map[*watcher]struct{}, 0),
+			watcher:     make(map[*watcher]struct{}),
 			services:    &atomic.Value{},
 			serviceName: serviceName,
 		}
diff --git a/contrib/registry/zookeeper/watcher.go b/contrib/registry/zookeeper/watcher.go
index 9430e9ce..c56f3d08 100644
--- a/contrib/registry/zookeeper/watcher.go
+++ b/contrib/registry/zookeeper/watcher.go
@@ -6,9 +6,7 @@ import (
 	"github.com/go-kratos/kratos/v2/registry"
 )
 
-var (
-	_ registry.Watcher = &watcher{}
-)
+var _ registry.Watcher = &watcher{}
 
 type watcher struct {
 	ctx    context.Context
@@ -25,9 +23,7 @@ func (w watcher) Next() (services []*registry.ServiceInstance, err error) {
 	}
 	ss, ok := w.set.services.Load().([]*registry.ServiceInstance)
 	if ok {
-		for _, s := range ss {
-			services = append(services, s)
-		}
+		services = append(services, ss...)
 	}
 	return
 }
diff --git a/examples/go.mod b/examples/go.mod
index 111ccb31..07a17bf6 100644
--- a/examples/go.mod
+++ b/examples/go.mod
@@ -28,7 +28,7 @@ require (
 	github.com/grpc-ecosystem/grpc-gateway/v2 v2.5.0
 	github.com/hashicorp/consul/api v1.9.1
 	github.com/labstack/echo/v4 v4.5.0
-	github.com/nacos-group/nacos-sdk-go v1.0.8
+	github.com/nacos-group/nacos-sdk-go v1.0.9
 	github.com/nicksnyder/go-i18n/v2 v2.1.2
 	github.com/prometheus/client_golang v1.11.0
 	github.com/segmentio/kafka-go v0.4.17
diff --git a/examples/go.sum b/examples/go.sum
index a87f760e..1b7a48ec 100644
--- a/examples/go.sum
+++ b/examples/go.sum
@@ -465,6 +465,8 @@ github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRW
 github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
 github.com/nacos-group/nacos-sdk-go v1.0.8 h1:8pEm05Cdav9sQgJSv5kyvlgfz0SzFUUGI3pWX6SiSnM=
 github.com/nacos-group/nacos-sdk-go v1.0.8/go.mod h1:hlAPn3UdzlxIlSILAyOXKxjFSvDJ9oLzTJ9hLAK1KzA=
+github.com/nacos-group/nacos-sdk-go v1.0.9 h1:sMvrp6tZj4LdhuHRsS4GCqASB81k3pjmT2ykDQQpwt0=
+github.com/nacos-group/nacos-sdk-go v1.0.9/go.mod h1:hlAPn3UdzlxIlSILAyOXKxjFSvDJ9oLzTJ9hLAK1KzA=
 github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg=
 github.com/nats-io/jwt v0.3.2/go.mod h1:/euKqTS1ZD+zzjYrY7pseZrTtWQSjujC7xjPc8wL6eU=
 github.com/nats-io/nats-server/v2 v2.1.2/go.mod h1:Afk+wRZqkMQs/p45uXdrVLuab3gwv3Z8C4HTBu8GD/k=
@@ -748,7 +750,6 @@ golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzB
 golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
 golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
 golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
-golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo=
 golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
 golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
diff --git a/examples/http/README.md b/examples/http/README.md
index 1c2df553..120b8c86 100644
--- a/examples/http/README.md
+++ b/examples/http/README.md
@@ -7,8 +7,8 @@ $ go run gin/main.go
 ```
 2、From a different terminal, access the api to see the output:
 ```shell
-$ curl http://127.0.0.1:8000/home
-Hello Gin!
+$ curl http://127.0.0.1:8000/helloworld/gin
+{"welcome":"gin"}
 ```
 
 ## mux
@@ -30,4 +30,4 @@ $ go run static/main.go
 2、Access the following url with your browser:
 ```
 http://127.0.0.1:8000/assets
-```
\ No newline at end of file
+```
diff --git a/go.sum b/go.sum
index 4f903fdb..51155df6 100644
--- a/go.sum
+++ b/go.sum
@@ -70,17 +70,12 @@ github.com/shirou/gopsutil/v3 v3.21.8 h1:nKct+uP0TV8DjjNiHanKf8SAuub+GNsbrOtM9Nl
 github.com/shirou/gopsutil/v3 v3.21.8/go.mod h1:YWp/H8Qs5fVmf17v7JNZzA0mPJ+mS2e9JdiUF9LlKzQ=
 github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
 github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
-github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
 github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
 github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
 github.com/tklauser/go-sysconf v0.3.9 h1:JeUVdAOWhhxVcU6Eqr/ATFHgXk/mmiItdKeJPev3vTo=
 github.com/tklauser/go-sysconf v0.3.9/go.mod h1:11DU/5sG7UexIrp/O6g35hrWzu0JxlwQ3LSFUzyeuhs=
 github.com/tklauser/numcpus v0.3.0 h1:ILuRUQBtssgnxw0XXIjKUC56fgnOrFoQQ/4+DeU2biQ=
 github.com/tklauser/numcpus v0.3.0/go.mod h1:yFGUr7TUHQRAhyqBcEg0Ge34zDBAsIvJJcyE6boqnA8=
-github.com/vmihailenco/msgpack/v5 v5.3.4 h1:qMKAwOV+meBw2Y8k9cVwAy7qErtYCwBzZ2ellBfvnqc=
-github.com/vmihailenco/msgpack/v5 v5.3.4/go.mod h1:7xyJ9e+0+9SaZT0Wt1RGleJXzli6Q/V5KbhBonMG9jc=
-github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g=
-github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds=
 github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
 go.opentelemetry.io/otel v1.0.0 h1:qTTn6x71GVBvoafHK/yaRUmFzI4LcONZD0/kXxl5PHI=
 go.opentelemetry.io/otel v1.0.0/go.mod h1:AjRVh9A5/5DE7S+mZtTR6t8vpKKryam+0lREnfmS4cg=
diff --git a/hack/.lintcheck_failures b/hack/.lintcheck_failures
index 80388962..8b137891 100644
--- a/hack/.lintcheck_failures
+++ b/hack/.lintcheck_failures
@@ -1,3 +1,1 @@
-./contrib/registry/nacos
-./contrib/registry/kubernetes
-./contrib/registry/zookeeper
+
diff --git a/middleware/recovery/recovery.go b/middleware/recovery/recovery.go
index 94f3eb54..4637bf02 100644
--- a/middleware/recovery/recovery.go
+++ b/middleware/recovery/recovery.go
@@ -56,7 +56,7 @@ func Recovery(opts ...Option) middleware.Middleware {
 					buf := make([]byte, 64<<10) //nolint:gomnd
 					n := runtime.Stack(buf, false)
 					buf = buf[:n]
-					logger.Errorf("%v: %+v\n%s\n", rerr, req, buf)
+					logger.WithContext(ctx).Errorf("%v: %+v\n%s\n", rerr, req, buf)
 
 					err = op.handler(ctx, req, rerr)
 				}
diff --git a/selector/balancer.go b/selector/balancer.go
index 9e5accbd..dbd64bbb 100644
--- a/selector/balancer.go
+++ b/selector/balancer.go
@@ -19,6 +19,9 @@ type BalancerBuilder interface {
 type WeightedNode interface {
 	Node
 
+	// Raw returns the original node
+	Raw() Node
+
 	// Weight is the runtime calculated weight
 	Weight() float64
 
diff --git a/selector/default_selector.go b/selector/default_selector.go
index 0e08d615..af4455f6 100644
--- a/selector/default_selector.go
+++ b/selector/default_selector.go
@@ -38,7 +38,11 @@ func (d *Default) Select(ctx context.Context, opts ...SelectOption) (selected No
 	if len(candidates) == 0 {
 		return nil, nil, ErrNoAvailable
 	}
-	return d.Balancer.Pick(ctx, candidates)
+	wn, done, err := d.Balancer.Pick(ctx, candidates)
+	if err != nil {
+		return nil, nil, err
+	}
+	return wn.Raw(), done, nil
 }
 
 // Apply update nodes info.
diff --git a/selector/node/direct/direct.go b/selector/node/direct/direct.go
index 9e409849..62b30ed7 100644
--- a/selector/node/direct/direct.go
+++ b/selector/node/direct/direct.go
@@ -13,12 +13,12 @@ const (
 )
 
 var (
-	_ selector.WeightedNode        = &node{}
+	_ selector.WeightedNode        = &Node{}
 	_ selector.WeightedNodeBuilder = &Builder{}
 )
 
-// node is endpoint instance
-type node struct {
+// Node is endpoint instance
+type Node struct {
 	selector.Node
 
 	// last lastPick timestamp
@@ -30,23 +30,27 @@ type Builder struct{}
 
 // Build create node
 func (*Builder) Build(n selector.Node) selector.WeightedNode {
-	return &node{Node: n, lastPick: 0}
+	return &Node{Node: n, lastPick: 0}
 }
 
-func (n *node) Pick() selector.DoneFunc {
+func (n *Node) Pick() selector.DoneFunc {
 	now := time.Now().UnixNano()
 	atomic.StoreInt64(&n.lastPick, now)
 	return func(ctx context.Context, di selector.DoneInfo) {}
 }
 
 // Weight is node effective weight
-func (n *node) Weight() float64 {
+func (n *Node) Weight() float64 {
 	if n.InitialWeight() != nil {
 		return float64(*n.InitialWeight())
 	}
 	return defaultWeight
 }
 
-func (n *node) PickElapsed() time.Duration {
+func (n *Node) PickElapsed() time.Duration {
 	return time.Duration(time.Now().UnixNano() - atomic.LoadInt64(&n.lastPick))
 }
+
+func (n *Node) Raw() selector.Node {
+	return n.Node
+}
diff --git a/selector/node/ewma/node.go b/selector/node/ewma/node.go
index 06b37178..2f2ff7e6 100644
--- a/selector/node/ewma/node.go
+++ b/selector/node/ewma/node.go
@@ -20,12 +20,12 @@ const (
 )
 
 var (
-	_ selector.WeightedNode        = &node{}
+	_ selector.WeightedNode        = &Node{}
 	_ selector.WeightedNodeBuilder = &Builder{}
 )
 
-// node is endpoint instance
-type node struct {
+// Node is endpoint instance
+type Node struct {
 	selector.Node
 
 	// client statistic data
@@ -53,7 +53,7 @@ type Builder struct {
 
 // Build create a weighted node.
 func (b *Builder) Build(n selector.Node) selector.WeightedNode {
-	s := &node{
+	s := &Node{
 		Node:       n,
 		lag:        0,
 		success:    1000,
@@ -64,11 +64,11 @@ func (b *Builder) Build(n selector.Node) selector.WeightedNode {
 	return s
 }
 
-func (n *node) health() uint64 {
+func (n *Node) health() uint64 {
 	return atomic.LoadUint64(&n.success)
 }
 
-func (n *node) load() (load uint64) {
+func (n *Node) load() (load uint64) {
 	now := time.Now().UnixNano()
 	avgLag := atomic.LoadInt64(&n.lag)
 	lastPredictTs := atomic.LoadInt64(&n.predictTs)
@@ -117,7 +117,7 @@ func (n *node) load() (load uint64) {
 }
 
 // Pick pick a node.
-func (n *node) Pick() selector.DoneFunc {
+func (n *Node) Pick() selector.DoneFunc {
 	now := time.Now().UnixNano()
 	atomic.StoreInt64(&n.lastPick, now)
 	atomic.AddInt64(&n.inflight, 1)
@@ -170,11 +170,15 @@ func (n *node) Pick() selector.DoneFunc {
 }
 
 // Weight is node effective weight.
-func (n *node) Weight() (weight float64) {
+func (n *Node) Weight() (weight float64) {
 	weight = float64(n.health()*uint64(time.Second)) / float64(n.load())
 	return
 }
 
-func (n *node) PickElapsed() time.Duration {
+func (n *Node) PickElapsed() time.Duration {
 	return time.Duration(time.Now().UnixNano() - atomic.LoadInt64(&n.lastPick))
 }
+
+func (n *Node) Raw() selector.Node {
+	return n.Node
+}
diff --git a/transport/grpc/balancer.go b/transport/grpc/balancer.go
index 94b3d29b..9d0da64d 100644
--- a/transport/grpc/balancer.go
+++ b/transport/grpc/balancer.go
@@ -50,19 +50,15 @@ type Builder struct {
 // Build creates a grpc Picker.
 func (b *Builder) Build(info base.PickerBuildInfo) gBalancer.Picker {
 	nodes := make([]selector.Node, 0)
-	subConns := make(map[string]gBalancer.SubConn)
 	for conn, info := range info.ReadySCs {
-		if _, ok := subConns[info.Address.Addr]; ok {
-			continue
-		}
-		subConns[info.Address.Addr] = conn
-
 		ins, _ := info.Address.Attributes.Value("rawServiceInstance").(*registry.ServiceInstance)
-		nodes = append(nodes, selector.NewNode(info.Address.Addr, ins))
+		nodes = append(nodes, &grpcNode{
+			Node:    selector.NewNode(info.Address.Addr, ins),
+			subConn: conn,
+		})
 	}
 	p := &Picker{
 		selector: b.builder.Build(),
-		subConns: subConns,
 	}
 	p.selector.Apply(nodes)
 	return p
@@ -70,7 +66,6 @@ func (b *Builder) Build(info base.PickerBuildInfo) gBalancer.Picker {
 
 // Picker is a grpc picker.
 type Picker struct {
-	subConns map[string]gBalancer.SubConn
 	selector selector.Selector
 }
 
@@ -87,10 +82,9 @@ func (p *Picker) Pick(info gBalancer.PickInfo) (gBalancer.PickResult, error) {
 	if err != nil {
 		return gBalancer.PickResult{}, err
 	}
-	sub := p.subConns[n.Address()]
 
 	return gBalancer.PickResult{
-		SubConn: sub,
+		SubConn: n.(*grpcNode).subConn,
 		Done: func(di gBalancer.DoneInfo) {
 			done(info.Ctx, selector.DoneInfo{
 				Err:           di.Err,
@@ -113,3 +107,8 @@ func (t Trailer) Get(k string) string {
 	}
 	return ""
 }
+
+type grpcNode struct {
+	selector.Node
+	subConn gBalancer.SubConn
+}
diff --git a/transport/http/client.go b/transport/http/client.go
index fcd29d2c..b792bccc 100644
--- a/transport/http/client.go
+++ b/transport/http/client.go
@@ -232,27 +232,7 @@ func (client *Client) Invoke(ctx context.Context, method, path string, args inte
 
 func (client *Client) invoke(ctx context.Context, req *http.Request, args interface{}, reply interface{}, c callInfo, opts ...CallOption) error {
 	h := func(ctx context.Context, in interface{}) (interface{}, error) {
-		var done func(context.Context, selector.DoneInfo)
-		if client.r != nil {
-			var (
-				err  error
-				node selector.Node
-			)
-			if node, done, err = client.opts.selector.Select(ctx); err != nil {
-				return nil, errors.ServiceUnavailable("NODE_NOT_FOUND", err.Error())
-			}
-			if client.insecure {
-				req.URL.Scheme = "http"
-			} else {
-				req.URL.Scheme = "https"
-			}
-			req.URL.Host = node.Address()
-			req.Host = node.Address()
-		}
 		res, err := client.do(ctx, req, c)
-		if done != nil {
-			done(ctx, selector.DoneInfo{Err: err})
-		}
 		if res != nil {
 			cs := csAttempt{res: res}
 			for _, o := range opts {
@@ -284,16 +264,39 @@ func (client *Client) Do(req *http.Request, opts ...CallOption) (*http.Response,
 			return nil, err
 		}
 	}
-	return client.do(req.Context(), req, c)
+	ctx := req.Context()
+
+	return client.do(ctx, req, c)
 }
 
 func (client *Client) do(ctx context.Context, req *http.Request, c callInfo) (*http.Response, error) {
+	var done func(context.Context, selector.DoneInfo)
+	if client.r != nil {
+		var (
+			err  error
+			node selector.Node
+		)
+		if node, done, err = client.opts.selector.Select(ctx); err != nil {
+			return nil, errors.ServiceUnavailable("NODE_NOT_FOUND", err.Error())
+		}
+		if client.insecure {
+			req.URL.Scheme = "http"
+		} else {
+			req.URL.Scheme = "https"
+		}
+		req.URL.Host = node.Address()
+		req.Host = node.Address()
+	}
 	resp, err := client.cc.Do(req)
+	if err == nil {
+		err = client.opts.errorDecoder(ctx, resp)
+	}
+
 	if err != nil {
 		return nil, err
 	}
-	if err := client.opts.errorDecoder(ctx, resp); err != nil {
-		return nil, err
+	if done != nil {
+		done(ctx, selector.DoneInfo{Err: err})
 	}
 	return resp, nil
 }


Test patch:
diff --git a/contrib/config/nacos/config_test.go b/contrib/config/nacos/config_test.go
new file mode 100644
index 00000000..02f44b16
--- /dev/null
+++ b/contrib/config/nacos/config_test.go
@@ -0,0 +1,108 @@
+package config
+
+import (
+	"fmt"
+	"net"
+	"testing"
+	"time"
+
+	kconfig "github.com/go-kratos/kratos/v2/config"
+	"github.com/nacos-group/nacos-sdk-go/clients"
+	"github.com/nacos-group/nacos-sdk-go/common/constant"
+	"github.com/nacos-group/nacos-sdk-go/vo"
+	"gopkg.in/yaml.v3"
+)
+
+func getIntranetIP() string {
+	addrs, err := net.InterfaceAddrs()
+	if err != nil {
+		return "127.0.0.1"
+	}
+
+	for _, address := range addrs {
+		if ipnet, ok := address.(*net.IPNet); ok && !ipnet.IP.IsLoopback() {
+			if ipnet.IP.To4() != nil {
+				return ipnet.IP.String()
+			}
+		}
+	}
+	return "127.0.0.1"
+}
+
+func TestGetConfig(t *testing.T) {
+	ip := getIntranetIP()
+	// ctx := context.Background()
+
+	sc := []constant.ServerConfig{
+		*constant.NewServerConfig(ip, 8848),
+	}
+
+	cc := constant.ClientConfig{
+		TimeoutMs:           5000,
+		NotLoadCacheAtStart: true,
+		LogDir:              "/tmp/nacos/log",
+		CacheDir:            "/tmp/nacos/cache",
+		RotateTime:          "1h",
+		MaxAge:              3,
+		LogLevel:            "debug",
+	}
+
+	// a more graceful way to create naming client
+	client, err := clients.NewConfigClient(
+		vo.NacosClientParam{
+			ClientConfig:  &cc,
+			ServerConfigs: sc,
+		},
+	)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	dataID := "test.yaml"
+	group := "test"
+	_, err = client.PublishConfig(vo.ConfigParam{DataId: dataID, Group: group, Content: `
+logger:
+  level: info
+`})
+	if err != nil {
+		t.Fatal(err)
+	}
+	time.Sleep(1 * time.Second)
+	c := kconfig.New(
+		kconfig.WithSource(
+			NewConfigSource(client, WithGroup(group), WithDataID(dataID)),
+		),
+		kconfig.WithDecoder(func(kv *kconfig.KeyValue, v map[string]interface{}) error {
+			return yaml.Unmarshal(kv.Value, v)
+		}),
+	)
+
+	if err = c.Load(); err != nil {
+		t.Fatal(err)
+	}
+
+	name, err := c.Value("logger.level").String()
+	if err != nil {
+		t.Fatal(err)
+	}
+	fmt.Println("get value", name)
+
+	done := make(chan bool)
+	err = c.Watch("logger.level", func(key string, value kconfig.Value) {
+		fmt.Println(key, " value change", value)
+		done <- true
+	})
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	_, err = client.PublishConfig(vo.ConfigParam{DataId: dataID, Group: group, Content: `
+logger:
+  level: debug
+`})
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	<-done
+}
diff --git a/contrib/registry/nacos/registry_test.go b/contrib/registry/nacos/registry_test.go
new file mode 100644
index 00000000..800bec46
--- /dev/null
+++ b/contrib/registry/nacos/registry_test.go
@@ -0,0 +1,209 @@
+package nacos
+
+import (
+	"context"
+	"log"
+	"net"
+	"testing"
+	"time"
+
+	"github.com/go-kratos/kratos/v2/registry"
+	"github.com/nacos-group/nacos-sdk-go/clients"
+	"github.com/nacos-group/nacos-sdk-go/common/constant"
+	"github.com/nacos-group/nacos-sdk-go/vo"
+)
+
+func getIntranetIP() string {
+	addrs, err := net.InterfaceAddrs()
+	if err != nil {
+		return "127.0.0.1"
+	}
+
+	for _, address := range addrs {
+		if ipnet, ok := address.(*net.IPNet); ok && !ipnet.IP.IsLoopback() {
+			if ipnet.IP.To4() != nil {
+				return ipnet.IP.String()
+			}
+		}
+	}
+	return "127.0.0.1"
+}
+
+func TestRegistry(t *testing.T) {
+	ip := getIntranetIP()
+	serviceName := "golang-sms@grpc"
+	ctx := context.Background()
+
+	sc := []constant.ServerConfig{
+		*constant.NewServerConfig(ip, 8848),
+	}
+
+	cc := constant.ClientConfig{
+		NamespaceId:         "public", // namespace id
+		TimeoutMs:           5000,
+		NotLoadCacheAtStart: true,
+		LogDir:              "/tmp/nacos/log",
+		CacheDir:            "/tmp/nacos/cache",
+		RotateTime:          "1h",
+		MaxAge:              3,
+		LogLevel:            "debug",
+	}
+
+	// a more graceful way to create naming client
+	client, err := clients.NewNamingClient(
+		vo.NacosClientParam{
+			ClientConfig:  &cc,
+			ServerConfigs: sc,
+		},
+	)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	_, err = client.RegisterInstance(vo.RegisterInstanceParam{
+		Ip:          "f",
+		Port:        8840,
+		ServiceName: serviceName,
+		Weight:      10,
+		Enable:      true,
+		Healthy:     true,
+		Ephemeral:   true,
+		Metadata:    map[string]string{"idc": "shanghai-xs"},
+	})
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	time.Sleep(time.Second)
+
+	is, err := client.GetService(vo.GetServiceParam{
+		ServiceName: serviceName,
+	})
+	if err != nil {
+		t.Fatal(err)
+	}
+	t.Logf("is %#v", is)
+
+	time.Sleep(time.Second)
+	r := New(client)
+
+	go func() {
+		var w registry.Watcher
+		w, err = r.Watch(ctx, "golang-sms@grpc")
+		if err != nil {
+			log.Fatal(err)
+		}
+		for {
+			var res []*registry.ServiceInstance
+			res, err = w.Next()
+			if err != nil {
+				return
+			}
+			log.Printf("watch: %d", len(res))
+			for _, r := range res {
+				log.Printf("next: %+v", r)
+			}
+		}
+	}()
+
+	time.Sleep(time.Second)
+
+	ins, err := r.GetService(ctx, serviceName)
+	if err != nil {
+		t.Fatal(err)
+	}
+	for _, in := range ins {
+		t.Logf("ins: %#v", in)
+	}
+
+	time.Sleep(time.Second)
+}
+
+func TestRegistryMany(t *testing.T) {
+	ip := getIntranetIP()
+	serviceName := "golang-sms@grpc"
+	// ctx := context.Background()
+
+	sc := []constant.ServerConfig{
+		*constant.NewServerConfig(ip, 8848),
+	}
+
+	cc := constant.ClientConfig{
+		NamespaceId:         "public", // namespace id
+		TimeoutMs:           5000,
+		NotLoadCacheAtStart: true,
+		LogDir:              "/tmp/nacos/log",
+		CacheDir:            "/tmp/nacos/cache",
+		RotateTime:          "1h",
+		MaxAge:              3,
+		LogLevel:            "debug",
+	}
+
+	// a more graceful way to create naming client
+	client, err := clients.NewNamingClient(
+		vo.NacosClientParam{
+			ClientConfig:  &cc,
+			ServerConfigs: sc,
+		},
+	)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	_, err = client.RegisterInstance(vo.RegisterInstanceParam{
+		Ip:          "f1",
+		Port:        8840,
+		ServiceName: serviceName,
+		Weight:      10,
+		Enable:      true,
+		Healthy:     true,
+		Ephemeral:   true,
+		Metadata:    map[string]string{"idc": "shanghai-xs"},
+	})
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	_, err = client.RegisterInstance(vo.RegisterInstanceParam{
+		Ip:          "f2",
+		Port:        8840,
+		ServiceName: serviceName,
+		Weight:      10,
+		Enable:      true,
+		Healthy:     true,
+		Ephemeral:   true,
+		Metadata:    map[string]string{"idc": "shanghai-xs"},
+	})
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	_, err = client.RegisterInstance(vo.RegisterInstanceParam{
+		Ip:          "f3",
+		Port:        8840,
+		ServiceName: serviceName,
+		Weight:      10,
+		Enable:      true,
+		Healthy:     true,
+		Ephemeral:   true,
+		Metadata:    map[string]string{"idc": "shanghai-xs"},
+	})
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	time.Sleep(time.Second)
+
+	is, err := client.GetService(vo.GetServiceParam{
+		ServiceName: serviceName,
+	})
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	for _, host := range is.Hosts {
+		t.Logf("host: %#v,e: %v", host, err)
+	}
+
+	time.Sleep(time.Second)
+}
diff --git a/contrib/registry/zookeeper/register_test.go b/contrib/registry/zookeeper/register_test.go
index 6e2f92c7..f746b104 100644
--- a/contrib/registry/zookeeper/register_test.go
+++ b/contrib/registry/zookeeper/register_test.go
@@ -22,11 +22,13 @@ func TestRegistry(t *testing.T) {
 	if err != nil {
 		t.Fatal(err)
 	}
-	defer w.Stop()
+	defer func() {
+		_ = w.Stop()
+	}()
 	go func() {
 		for {
-			res, err := w.Next()
-			if err != nil {
+			res, nextErr := w.Next()
+			if nextErr != nil {
 				return
 			}
 			t.Logf("watch: %d", len(res))
@@ -37,7 +39,7 @@ func TestRegistry(t *testing.T) {
 	}()
 	time.Sleep(time.Second)
 
-	if err := r.Register(ctx, s); err != nil {
+	if err = r.Register(ctx, s); err != nil {
 		t.Fatal(err)
 	}
 	time.Sleep(time.Second)
@@ -53,7 +55,7 @@ func TestRegistry(t *testing.T) {
 		t.Errorf("not expected: %+v", res)
 	}
 
-	if err := r.Deregister(ctx, s); err != nil {
+	if err = r.Deregister(ctx, s); err != nil {
 		t.Fatal(err)
 	}
 	time.Sleep(time.Second)
diff --git a/selector/node/direct/direct_test.go b/selector/node/direct/direct_test.go
index cca73368..51689f52 100644
--- a/selector/node/direct/direct_test.go
+++ b/selector/node/direct/direct_test.go
@@ -48,6 +48,6 @@ func TestDirectDefaultWeight(t *testing.T) {
 	time.Sleep(time.Millisecond * 10)
 	done(context.Background(), selector.DoneInfo{})
 	assert.Equal(t, float64(100), wn.Weight())
-	assert.Greater(t, time.Millisecond*15, wn.PickElapsed())
+	assert.Greater(t, time.Millisecond*20, wn.PickElapsed())
 	assert.Less(t, time.Millisecond*5, wn.PickElapsed())
 }
diff --git a/selector/p2c/p2c_test.go b/selector/p2c/p2c_test.go
index 747345a1..32db03b7 100644
--- a/selector/p2c/p2c_test.go
+++ b/selector/p2c/p2c_test.go
@@ -56,12 +56,12 @@ func TestWrr3(t *testing.T) {
 		}()
 	}
 	group.Wait()
-	assert.Greater(t, count1, int64(2000))
-	assert.Less(t, count1, int64(4000))
-	assert.Greater(t, count2, int64(2000))
-	assert.Less(t, count2, int64(4000))
-	assert.Greater(t, count3, int64(2000))
-	assert.Less(t, count3, int64(4000))
+	assert.Greater(t, count1, int64(1500))
+	assert.Less(t, count1, int64(4500))
+	assert.Greater(t, count2, int64(1500))
+	assert.Less(t, count2, int64(4500))
+	assert.Greater(t, count3, int64(1500))
+	assert.Less(t, count3, int64(4500))
 }
 
 func TestEmpty(t *testing.T) {
diff --git a/selector/selector_test.go b/selector/selector_test.go
index 8168c9bb..3c0fa13e 100644
--- a/selector/selector_test.go
+++ b/selector/selector_test.go
@@ -17,6 +17,11 @@ type mockWeightedNode struct {
 	lastPick int64
 }
 
+// Raw returns the original node
+func (n *mockWeightedNode) Raw() Node {
+	return n.Node
+}
+
 // Weight is the runtime calculated weight
 func (n *mockWeightedNode) Weight() float64 {
 	if n.InitialWeight() != nil {