• grpc使用consul做服务注册与发现


    目录结构:

     client/main.go:

    1. package main
    2. import (
    3. "context"
    4. "demo/config"
    5. "demo/proto"
    6. "fmt"
    7. "log"
    8. "time"
    9. _ "github.com/mbobakov/grpc-consul-resolver"
    10. "google.golang.org/grpc"
    11. "google.golang.org/grpc/credentials/insecure"
    12. )
    13. func main() {
    14. var srvClient proto.GreeterClient
    15. // 服务
    16. if conn := InitSrvConn(config.ServiceName); conn != nil {
    17. srvClient = proto.NewGreeterClient(conn)
    18. }
    19. req := &proto.HelloRequest{
    20. Name: "",
    21. }
    22. for i := 0; i < 1000; i++ {
    23. req.Name = fmt.Sprintf("james%d", i)
    24. resp, err := srvClient.SayHello(context.Background(), req)
    25. if err != nil {
    26. log.Fatalln(err)
    27. }
    28. log.Println(resp.Message)
    29. time.Sleep(time.Second)
    30. }
    31. }
    32. // 同时完成了服务发现和负载均衡算法(轮询)
    33. func InitSrvConn(srvName string) *grpc.ClientConn {
    34. conn, err := grpc.Dial(
    35. fmt.Sprintf("consul://%s:%d/%s?healthy=true&wait=14s",
    36. config.ConsulIp, config.ConsulPort, srvName),
    37. grpc.WithTransportCredentials(insecure.NewCredentials()),
    38. // grpc目前似乎只支持轮询的负载均衡算法
    39. grpc.WithDefaultServiceConfig(`{"loadBalancingPolicy": "round_robin"}`),
    40. )
    41. if err != nil {
    42. log.Println("service层服务发现出错: ", err)
    43. return nil
    44. }
    45. return conn
    46. }

    ptoto/greet.proto

    1. syntax = "proto3";
    2. option go_package = ".;proto";
    3. service Greeter{
    4. rpc SayHello(HelloRequest) returns (HelloReply);
    5. }
    6. message HelloRequest{
    7. string name = 1;
    8. }
    9. message HelloReply{
    10. string message = 1;
    11. }

    server/main.go

    1. package main
    2. import (
    3. "context"
    4. "demo/proto"
    5. "flag"
    6. "fmt"
    7. "log"
    8. "net"
    9. "os"
    10. "os/signal"
    11. "syscall"
    12. "demo/config"
    13. "github.com/hashicorp/consul/api"
    14. uuid "github.com/satori/go.uuid"
    15. "google.golang.org/grpc"
    16. "google.golang.org/grpc/health"
    17. "google.golang.org/grpc/health/grpc_health_v1"
    18. )
    19. type Server struct{}
    20. var (
    21. Port *int
    22. IP *string
    23. )
    24. func (s Server) SayHello(ctx context.Context, request *proto.HelloRequest) (*proto.HelloReply, error) {
    25. return &proto.HelloReply{Message: fmt.Sprintf("hello %s from %s:%d", request.Name, *IP, *Port)}, nil
    26. }
    27. func main() {
    28. // 设置本地服务启动的ip和端口号
    29. // 默认ip如果改成127.0.0.1会导致consul健康检查失败
    30. IP = flag.String("ip", "192.168.168.6", "ip地址")
    31. Port = flag.Int("port", 8100, "端口号")
    32. flag.Parse()
    33. g := grpc.NewServer()
    34. proto.RegisterGreeterServer(g, &Server{})
    35. tcpAddr := fmt.Sprintf("%s:%d", *IP, *Port)
    36. log.Printf("service listen:%s", tcpAddr)
    37. lis, err := net.Listen("tcp", tcpAddr)
    38. if err != nil {
    39. log.Panicln("failed to listen:" + err.Error())
    40. }
    41. // 注册健康检查
    42. grpc_health_v1.RegisterHealthServer(g, health.NewServer())
    43. // 将当前grpc服务注册到consul
    44. serviceId := uuid.NewV4().String()
    45. client, err := RegisterGRPCService(*IP, config.ServiceName, serviceId, *Port, nil)
    46. if err != nil {
    47. log.Panicln("grpc服务注册失败:", err)
    48. }
    49. // 将启动服务的部分放到协程里面,使得后面监听终止信号的部分可以被执行
    50. go func() {
    51. err = g.Serve(lis)
    52. if err != nil {
    53. log.Panicln("failed to start grpc:" + err.Error())
    54. }
    55. }()
    56. // 接收终止信号
    57. quit := make(chan os.Signal)
    58. signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
    59. <-quit
    60. if err = client.Agent().ServiceDeregister(serviceId); err != nil {
    61. log.Println("服务注销失败")
    62. } else {
    63. log.Println("服务注销成功")
    64. }
    65. }
    66. // 函数功能:将grpc服务注册到consul
    67. // 参数说明
    68. // address:待注册的服务的ip
    69. // name:服务名称
    70. // id:服务id
    71. // port:服务端口
    72. // tags:服务标签
    73. func RegisterGRPCService(address, name, id string, port int, tags []string) (*api.Client, error) {
    74. cfg := api.DefaultConfig()
    75. // 设置consul服务运行所在的ip和端口
    76. cfg.Address = fmt.Sprintf("%s:%d", config.ConsulIp, config.ConsulPort)
    77. //cfg.Address的ip可以是127.0.0.1
    78. client, err := api.NewClient(cfg)
    79. if err != nil {
    80. log.Panic(err)
    81. }
    82. // 生成健康检查对象
    83. check := &api.AgentServiceCheck{
    84. // 这里的ip不可以是127.0.0.1
    85. GRPC: fmt.Sprintf("%s:%d", address, port), // 服务的运行地址
    86. Timeout: "5s", // 超过此时间说明服务状态不健康
    87. Interval: "5s", // 每5s检查一次
    88. DeregisterCriticalServiceAfter: "30s", // 失败多久后注销服务
    89. }
    90. // 生成注册对象
    91. registration := &api.AgentServiceRegistration{
    92. Name: name,
    93. ID: id,
    94. Address: address,
    95. Port: port,
    96. Tags: tags,
    97. Check: check,
    98. }
    99. // 注册服务
    100. return client, client.Agent().ServiceRegister(registration)
    101. }

    运行步骤:

    1 启动consul

    2 使用protoc工具生成greet.pb.go

    3 启动多个服务端

    4 启动客户端

    运行结果大致如下,

     

  • 相关阅读:
    罗永浩讽刺iPhone“那么伟大又那么不要脸”;北欧囚犯正在训练AI大模型;ChatGPT治怪病丨RTE开发者日报 Vol.51
    【算法篇-搜索与图论】适合算法入门小白理解的深度优先搜索(DFS )以及解决全排列数字
    attempt to compare nil with number -- 黑马点评出现问题
    iTOP-RK3588开发板rknn_multiple_input_demo 体验
    将docker镜像打包成tar.gz包
    【Prometheus】Node Exporter常用查询PromQL 语句大总结
    区块链实训教程(3)--使用虚拟机安装Ubuntu
    MySQL 创建用户,修改用户,授权,删除用户等操作命令
    linux 下安装chrome 和 go
    VR全景算不算好的创业项目?有哪些特性?
  • 原文地址:https://blog.csdn.net/kankan231/article/details/126083953