實現微服務註冊的高效利器:gRPC 與 Nacos 集成教程
一、golang gRPC 註冊 nacos
-
github 地址 nacos-sdk-go(opens new window)
-
nacos 官網
1、目錄結構
2、pb/person.proto
syntax = "proto3";
option go_package = "./person";
package pb;
message Person {
string name = 1;
int32 age = 2;
}
// 添加 rpc服務
service hello {
rpc sayHello (Person) returns (Person);
}
3、nacos-server8800/nacos_server.go
package main
import (
"awesomeProject/pb/person"
"context"
"fmt"
"net"
"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"
"google.golang.org/grpc"
)
// 定義類
type Children struct {
}
// 綁定類方法, 實現藉口
func (this *Children) SayHello(ctx context.Context, p *person.Person) (*person.Person, error) {
p.Name = "hello " + p.Name
return p, nil
}
func main() {
RegisterNacos()
//////////////////////以下爲 grpc 服務遠程調用//////////////////////////////
// 1.初始化 grpc 對象,
grpcServer := grpc.NewServer()
// 2.註冊服務
person.RegisterHelloServer(grpcServer, new(Children))
// 3.設置監聽, 指定 IP/port
listener, err := net.Listen("tcp", "127.0.0.1:8800")
if err != nil {
fmt.Println("Listen err:", err)
return
}
defer listener.Close()
fmt.Println("服務啓動... ")
// 4. 啓動服務
grpcServer.Serve(listener)
}
func RegisterNacos() {
// 創建clientConfig
clientConfig := constant.ClientConfig{
//NamespaceId: "e525eafa-f7d7-4029-83d9-008937f9d468", // 如果需要支持多namespace,我們可以場景多個client,它們有不同的NamespaceId。當namespace是public時,此處填空字符串。
TimeoutMs: 5000,
NotLoadCacheAtStart: true,
LogDir: "/tmp/nacos/log",
CacheDir: "/tmp/nacos/cache",
RotateTime: "1h",
MaxAge: 3,
LogLevel: "debug",
}
// 至少一個ServerConfig
serverConfigs := []constant.ServerConfig{
{
IpAddr: "127.0.0.1",
ContextPath: "/nacos",
Port: 8848,
Scheme: "http",
},
}
// 創建服務發現客戶端 (推薦)
namingClient, err := clients.NewNamingClient(
vo.NacosClientParam{
ClientConfig: &clientConfig,
ServerConfigs: serverConfigs,
},
)
if err != nil {
fmt.Println("clients.NewNamingClient err,", err)
}
success, err := namingClient.RegisterInstance(vo.RegisterInstanceParam{
Ip: "127.0.0.1",
Port: 8800,
ServiceName: "demo.go",
Weight: 10,
Enable: true,
Healthy: true,
Ephemeral: true,
Metadata: map[string]string{"idc": "shanghai"},
ClusterName: "cluster-a", // 默認值DEFAULT
GroupName: "group-a", // 默認值DEFAULT_GROUP
})
if !success {
return
} else {
fmt.Println("namingClient.RegisterInstance Success")
}
}
4、nacos-client/nacos_client.go
package main
import (
"awesomeProject/pb/person"
"context"
"fmt"
"strconv"
"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"
"google.golang.org/grpc"
)
func main() {
// 創建clientConfig
clientConfig := constant.ClientConfig{
//NamespaceId: "e525eafa-f7d7-4029-83d9-008937f9d468", // 如果需要支持多namespace,我們可以場景多個client,它們有不同的NamespaceId。當namespace是public時,此處填空字符串。
TimeoutMs: 5000,
NotLoadCacheAtStart: true,
LogDir: "/tmp/nacos/log",
CacheDir: "/tmp/nacos/cache",
RotateTime: "1h",
MaxAge: 3,
LogLevel: "debug",
}
// 至少一個ServerConfig
serverConfigs := []constant.ServerConfig{
{
IpAddr: "127.0.0.1",
ContextPath: "/nacos",
Port: 8848,
Scheme: "http",
},
}
// 創建服務發現客戶端的另一種方式 (推薦)
namingClient, err := clients.NewNamingClient(
vo.NacosClientParam{
ClientConfig: &clientConfig,
ServerConfigs: serverConfigs,
},
)
// SelectAllInstance可以返回全部實例列表,包括healthy=false,enable=false,weight<=0
instances, err := namingClient.SelectAllInstances(vo.SelectAllInstancesParam{
ServiceName: "demo.go",
GroupName: "group-a", // 默認值DEFAULT_GROUP
Clusters: []string{"cluster-a"}, // 默認值DEFAULT
})
fmt.Println(instances)
// SelectOneHealthyInstance將會按加權隨機輪詢的負載均衡策略返回一個健康的實例
// 實例必須滿足的條件:health=true,enable=true and weight>0
instance, err := namingClient.SelectOneHealthyInstance(vo.SelectOneHealthInstanceParam{
ServiceName: "demo.go",
GroupName: "group-a", // 默認值DEFAULT_GROUP
Clusters: []string{"cluster-a"}, // 默認值DEFAULT
})
addr := instance.Ip + ":" + strconv.Itoa(int(instance.Port))
fmt.Println(addr)
//////////////////////以下爲 grpc 服務遠程調用//////////////////////////////
// 1. 鏈接服務
//grpcConn, _ := grpc.Dial("127.0.0.1:8800", grpc.WithInsecure())
// 使用 服務發現consul 上的 IP/port 來與服務建立鏈接
grpcConn, _ := grpc.Dial(addr, grpc.WithInsecure())
// 2. 初始化 grpc 客戶端
grpcClient := person.NewHelloClient(grpcConn)
var person person.Person
person.Name = "Andy"
person.Age = 18
// 3. 調用遠程函數
p, err := grpcClient.SayHello(context.TODO(), &person)
fmt.Println(p, err)
}
5、nacos-server8801/nacos_server.go
package main
import (
"awesomeProject/pb/person"
"context"
"fmt"
"net"
"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"
"google.golang.org/grpc"
)
// 定義類
type Children struct {
}
// 綁定類方法, 實現藉口
func (this *Children) SayHello(ctx context.Context, p *person.Person) (*person.Person, error) {
p.Name = "hello " + p.Name
return p, nil
}
func main() {
RegisterNacos()
//////////////////////以下爲 grpc 服務遠程調用//////////////////////////////
// 1.初始化 grpc 對象,
grpcServer := grpc.NewServer()
// 2.註冊服務
person.RegisterHelloServer(grpcServer, new(Children))
// 3.設置監聽, 指定 IP/port
listener, err := net.Listen("tcp", "127.0.0.1:8801")
if err != nil {
fmt.Println("Listen err:", err)
return
}
defer listener.Close()
fmt.Println("服務啓動... ")
// 4. 啓動服務
grpcServer.Serve(listener)
}
func RegisterNacos() {
// 創建clientConfig
clientConfig := constant.ClientConfig{
//NamespaceId: "e525eafa-f7d7-4029-83d9-008937f9d468", // 如果需要支持多namespace,我們可以場景多個client,它們有不同的NamespaceId。當namespace是public時,此處填空字符串。
TimeoutMs: 5000,
NotLoadCacheAtStart: true,
LogDir: "/tmp/nacos/log",
CacheDir: "/tmp/nacos/cache",
RotateTime: "1h",
MaxAge: 3,
LogLevel: "debug",
}
// 至少一個ServerConfig
serverConfigs := []constant.ServerConfig{
{
IpAddr: "127.0.0.1",
ContextPath: "/nacos",
Port: 8848,
Scheme: "http",
},
}
// 創建服務發現客戶端 (推薦)
namingClient, err := clients.NewNamingClient(
vo.NacosClientParam{
ClientConfig: &clientConfig,
ServerConfigs: serverConfigs,
},
)
if err != nil {
fmt.Println("clients.NewNamingClient err,", err)
}
success, err := namingClient.RegisterInstance(vo.RegisterInstanceParam{
Ip: "127.0.0.1",
Port: 8801,
ServiceName: "demo.go",
Weight: 10,
Enable: true,
Healthy: true,
Ephemeral: true,
Metadata: map[string]string{"idc": "shanghai"},
ClusterName: "cluster-a", // 默認值DEFAULT
GroupName: "group-a", // 默認值DEFAULT_GROUP
})
if !success {
return
} else {
fmt.Println("namingClient.RegisterInstance Success")
}
}
6、運行服務端測試
- 運行命令安裝包
go mod tidy
- 生成 protobuf 文件
cd pb
protoc --go_out=plugins=grpc:./ *.proto
-
保證nacos服務正常運行:
http://127.0.0.1:8848/nacos -
運行服務端
// 啓動 server8000
xiaonaiqiang1@ZBMac-C02CW08SM nacos-grpc-gotest % cd nacos-server8800
xiaonaiqiang1@ZBMac-C02CW08SM nacos-server8800 % go run nacos_server.go
// 啓動server8801
xiaonaiqiang1@ZBMac-C02CW08SM nacos-grpc-gotest % cd nacos-server8801
xiaonaiqiang1@ZBMac-C02CW08SM nacos-server8801 % go run nacos_server.go
啓動客戶端測試負載均衡
xiaonaiqiang1@ZBMac-C02CW08SM nacos-grpc-gotest % cd nacos-client
// 運行第一次訪問的是 127.0.0.1:8800
xiaonaiqiang1@ZBMac-C02CW08SM nacos-client % go run nacos_client.go
127.0.0.1:8800
// 運行第一次訪問的是 127.0.0.1:8801
xiaonaiqiang1@ZBMac-C02CW08SM nacos-client % go run nacos_client.go
127.0.0.1:8801
- 查看 nacos 服務註冊的狀態
二、接入 nacos 配置中心
1、管理 nacos
- 新建命名空間
添加配置
添加配置文件
2、配置中心使用
package main
import (
"fmt"
"github.com/BurntSushi/toml"
"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"
"time"
)
type User struct {
Name string `toml:"name" json:"name"`
}
func main() {
sc := []constant.ServerConfig{{
IpAddr: "127.0.0.1",
Port: 8848,
}}
cc := constant.ClientConfig{
// 如果需要支持多namespace,我們可以場景多個client,它們有不同的NamespaceId,當namespace是public時,此處填空字符串。
NamespaceId: "743b45f1-b34d-4dfa-8ae8-2304682945a4",
TimeoutMs: 5000,
NotLoadCacheAtStart: true,
LogDir: "log",
CacheDir: "cache",
LogLevel: "debug",
}
configClient, err := clients.CreateConfigClient(map[string]interface{}{
"serverConfigs": sc,
"clientConfig": cc,
})
if err != nil {
panic(err)
}
// 配置拉取
content, err := configClient.GetConfig(vo.ConfigParam{
DataId: "user-web.toml",
Group: "dev",
})
if err != nil {
panic(err)
}
fmt.Println("第一次啓動讀取----->", content) //字符串 - yaml
u := User{}
_, err = toml.Decode(content, &u)
if err != nil {
fmt.Println(err)
}
fmt.Println("第一次讀取name爲---->", u.Name)
// 配置監聽
err = configClient.ListenConfig(vo.ConfigParam{
DataId: "user-web.toml",
Group: "dev",
OnChange: func(namespace, group, dataId, data string) {
fmt.Println("配置文件發生了變化...")
fmt.Println("group:" + group + ", dataId:" + dataId + ", data:" + data)
_, err = toml.Decode(data, &u)
fmt.Println("文件修改後結果---->", u.Name)
},
})
time.Sleep(300 * time.Second)
}
/*
第一次啓動讀取-----> name = "root"
文件修改後結果----> root
配置文件發生了變化...
group:dev, dataId:user-web.toml, data:name = "root1"
文件修改後結果----> root1
*/
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/qW1dx-dKbllpNBqkkGspqA