rpcx 官方技术博客

使用 Nacos 作为服务注册中心

2019.11.22

Nacos 是阿里巴巴推出来的一个新开源项目,这是一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台。

Nacos 致力于帮助您发现、配置和管理微服务。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据及流量管理。

Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。 Nacos 是构建以“服务”为中心的现代应用架构 (例如微服务范式、云原生范式) 的服务基础设施。

看它的github上很多的公司都在使用,其中不乏一些知名的互联网厂商,如果 rpcx 支持 Nacos, 那么众多的厂商可以利用公司既有的服务发现基础设置,直接方便的使用rpcx实现微服务,以及编写客户端实现服务治理。现在,这种可能编成了现实,rpcx 现在支持 Nacos作为注册中心,底层使用[nacos-sdk-go](https://github.com/nacos-group/nacos-sdk-go)访问 Nacos服务。

微博内部其实有一个类似的基础平台, 叫Vintage, 微博的所有的 Motan 服务都依赖它。 设计的特性和概念 和 Nacos 类似,只可惜没有开源。

现在,让我们看看使用 Nacos 注册中心是多么的方便, 本文使用公开的 console.nacos.io 作为 Nacos服务, 你也可以下载 Nacos应用自己部署一套 N acos环境。 如果你的公司已经部署了 Nacos,你也可以使用自己公司的 Nacos 。

服务端实现

服务器端需要增加serverplugin.NacosRegisterPlugin插件,它负责自动把服务注册到Nacos上,所以这里我们增加了一个addRegistryPlugin方法配置Nacos插件。

NacosRegisterPlugin的配置也很简单, 你需要配置clientConfig,这是 nacos client的一些参数,超时设置、缓存设置、日志等等。serverConfig定义了nacos服务器的地址和端口。如果你的服务区分cluster, 你还可以定义cluster参数。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
package main

import (
	"flag"
	"log"

	"github.com/nacos-group/nacos-sdk-go/common/constant"
	example "github.com/rpcx-ecosystem/rpcx-examples3"
	"github.com/smallnest/rpcx/server"
	"github.com/smallnest/rpcx/serverplugin"
)

var (
	addr = flag.String("addr", "127.0.0.1:8972", "server address")
)

func addRegistryPlugin(s *server.Server) {
	clientConfig := constant.ClientConfig{
		TimeoutMs:            10 * 1000,
		ListenInterval:       30 * 1000,
		BeatInterval:         5 * 1000,
		NamespaceId:          "public",
		CacheDir:             "./cache",
		LogDir:               "./log",
		UpdateThreadNum:      20,
		NotLoadCacheAtStart:  true,
		UpdateCacheWhenEmpty: true,
	}

	serverConfig := []constant.ServerConfig{{
		IpAddr: "console.nacos.io",
		Port:   80,
	}}

	r := &serverplugin.NacosRegisterPlugin{
		ServiceAddress: "tcp@" + *addr,
		ClientConfig:   clientConfig,
		ServerConfig:   serverConfig,
		Cluster:        "test",
	}
	err := r.Start()
	if err != nil {
		log.Fatal(err)
	}
	s.Plugins.Add(r)
}

我们还是使用Arith服务做例子,它有一个Mul乘法服务和一个Add服务。只需要下面几行代码,我们就把一个Go struct对象暴露成rpcx服务。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13

func main() {
	flag.Parse()

	s := server.NewServer()
	addRegistryPlugin(s)

	s.RegisterName("Arith", new(example.Arith), "")
	err := s.Serve("tcp", *addr)
	if err != nil {
		panic(err)
	}
}

客户端的实现

对应的,客户端也需要配置Nacos插件。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
package main

import (
	"context"
	"flag"
	"log"
	"time"

	"github.com/nacos-group/nacos-sdk-go/common/constant"
	example "github.com/rpcx-ecosystem/rpcx-examples3"
	"github.com/smallnest/rpcx/client"
)

func configNacos() client.ServiceDiscovery {
	clientConfig := constant.ClientConfig{
		TimeoutMs:            10 * 1000,
		ListenInterval:       30 * 1000,
		BeatInterval:         5 * 1000,
		NamespaceId:          "public",
		CacheDir:             "./cache",
		LogDir:               "./log",
		UpdateThreadNum:      20,
		NotLoadCacheAtStart:  true,
		UpdateCacheWhenEmpty: true,
	}

	serverConfig := []constant.ServerConfig{{
		IpAddr: "console.nacos.io",
		Port:   80,
	}}

	return client.NewNacosDiscovery("Arith", "test", clientConfig, serverConfig)

}

因为需要访问 Nacos服务,这里也需要ClientConfigServerConfig两个配置, 如果需要cluster配置,也把cluster的值传给Nacos插件,插件的第一个参数是要访问的服务的名称。

现在你就可以访问服务了,client不知道服务器的地址和端口,它是通过nacos查询到的:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
func main() {
	flag.Parse()

	d := configNacos()
	xclient := client.NewXClient("Arith", client.Failover, client.RoundRobin, d, client.DefaultOption)
	defer xclient.Close()

	args := &example.Args{
		A: 10,
		B: 20,
	}

	for {
		reply := &example.Reply{}
		err := xclient.Call(context.Background(), "Mul", args, reply)
		if err != nil {
			log.Printf("failed to call: %v\n", err)
			time.Sleep(5 * time.Second)
			continue
		}

		log.Printf("%d * %d = %d", args.A, args.B, reply.C)

		time.Sleep(5 * time.Second)
	}
}

你可以看log文件,结果被输出到日志文件中。