實現微服務註冊的高效利器:gRPC 與 Nacos 集成教程

一、golang gRPC 註冊 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
cd pb
protoc --go_out=plugins=grpc:./ *.proto
// 啓動 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 配置中心

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