基于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{} = datafor _, 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: yuanage: 27city: 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