基于Golang客户端实现Nacos服务注册发现和配置管理
背景
最近需要把Golang实现的一个web项目集成到基于Spring Cloud Alibaba的微服务体系中,走Spring Cloud Gateway网关路由实现统一的鉴权入口。
软件版本
组件名称 | 组件版本 |
---|---|
Nacos | 2.2.0 |
Go | 1.21.0 |
Gin | v1.9.1 |
Nacos-sdk-go | v2.2.5 |
Spring Cloud | 2021.0.2 |
Spring Cloud Alibaba | 2021.0.1.0 |
服务注册发现
项目图示
服务注册和发现
Golang客户端的注册发现使用的Nacos官方仓库里面的一个实现:https://github.com/nacos-group/nacos-sdk-go,我这边的实现大多数也是参考的官方提供的样例。
首先,初始化clientConfig和serverConfig的配置
sc := []constant.ServerConfig{
*constant.NewServerConfig("localhost", 8848, constant.WithContextPath("/nacos")),
}
cc := *constant.NewClientConfig(
constant.WithNamespaceId("xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"),
constant.WithTimeoutMs(5000),
constant.WithNotLoadCacheAtStart(true),
constant.WithLogDir("/tmp/nacos/log"),
constant.WithCacheDir("/tmp/nacos/cache"),
constant.WithUsername("nacos"),
constant.WithPassword("nacos"),
)
创建服务发现客户端
client, _ := clients.NewNamingClient(
vo.NacosClientParam{
ClientConfig: &cc,
ServerConfigs: sc,
},
)
服务注册
// 注册服务
registerServiceInstance(client, vo.RegisterInstanceParam{
Ip: getHostIp(),
Port: 8777,
ServiceName: ServiceName,
Weight: 10,
Enable: true,
Healthy: true,
Ephemeral: true,
})
// 注册服务
func registerServiceInstance(nacosClient naming_client.INamingClient, param vo.RegisterInstanceParam) {
success, err := nacosClient.RegisterInstance(param)
if !success || err != nil {
panic("register Service Instance failed!")
}
}
// 获取本机ip地址
func getHostIp() string {
conn, err := net.Dial("udp", "8.8.8.8:53")
if err != nil {
fmt.Println("get current host ip err: ", err)
return ""
}
addr := conn.LocalAddr().(*net.UDPAddr)
ip := strings.Split(addr.String(), ":")[0]
return ip
}
启动服务,验证ok
客户端负载均衡
作为Go语言初学者,没有详细去了解Go中类似@LoadBalanced或者Feign的框架(后续可能会补充一下),然后我这边就是获取实例解析IP和端口信息,然后直接使用Go原生的http库进行的调用。
获取实例方法
// 获取一个健康的实例
func selectOneHealthyInstance(client naming_client.INamingClient, serviceName string) (instance *model.Instance) {
instances, err := client.SelectOneHealthyInstance(vo.SelectOneHealthInstanceParam{
ServiceName: serviceName,
})
if err != nil {
panic("SelectOneHealthyInstance failed!")
}
return instances
}
具体调用
func hello(c *gin.Context) {
name := c.Param("name")
instance := selectOneHealthyInstance(NamingClient, "server-java")
url := fmt.Sprintf("http://%s:%d/hello/%s", instance.Ip, instance.Port, name)
resp, _ := http.Get(url)
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
c.String(http.StatusOK, string(body))
}
在server-java中,提供了一个rest接口
/**
* 启动类
*
* @author yuanzhihao
* @since 2024/3/4
*/
@RestController
@RequestMapping
@SpringBootApplication
public class Application {
@GetMapping("/hello/{name}")
public String hello(@PathVariable("name") String name) {
return "Hello " + name;
}
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
请求 http://localhost:8777/hello/yuan, 调用成功
配置管理
图示
第一步和注册发现一样,初始化clientConfig和serverConfig的配置,略
创建动态配置客户端
configClient, _ := clients.NewConfigClient(
vo.NacosClientParam{
ClientConfig: &cc,
ServerConfigs: sc,
},
)
拉取指定data-id的配置
config, _ := ConfigClient.GetConfig(vo.ConfigParam{
DataId: ServiceName,
})
fmt.Printf("config is " + config)
我这边写了一个rest的接口,可以指定获取某个具体配置的值
// 初始化服务端
func ServerSetup() {
r := gin.Default()
r.GET("/hello/:name", hello)
r.GET("/config", getSpecifiedConfig)
r.Run(":8777")
}
// 获取指定的配置
func getSpecifiedConfig(c *gin.Context) {
param := c.DefaultQuery("name", "")
config, _ := ConfigClient.GetConfig(vo.ConfigParam{
DataId: ServiceName,
})
fmt.Printf("config is " + config)
// 解析YAML数据
var data map[string]interface{}
err := yaml.Unmarshal([]byte(config), &data)
if err != nil {
fmt.Println("error unmarshalling YAML", err)
}
value := getValue(data, param)
c.String(http.StatusOK, "param [ "+param+" ] value is "+value)
}
func getValue(data map[string]interface{}, keyPath string) string {
keys := strings.Split(keyPath, ".")
var value interface{} = data
for _, key := range keys {
if v, ok := value.(map[string]interface{}); ok {
value = v[key]
} else {
return ""
}
}
if v, ok := value.(string); ok {
return v
}
return fmt.Sprintf("%v", value)
}
配置client-go如下
my:
name: yuan
age: 27
city: Nanjing
调用请求 http://localhost:8777/config?name=my.name,http://localhost:8777/config?name=my.age ok
结语
参考地址:https://github.com/nacos-group/nacos-sdk-go
代码地址:https://github.com/yzh19961031/blogDemo/tree/master/go-nacos