gRPC etcd 服务注册与发现、自定义负载均衡

news/2024/12/21 23:01:08/

本文首发在这里
考虑这种常见情景:服务多开,正常连接采用轮询负载均衡,但若服务有状态,重连则需进入之前的服务

本文其实主要在讨论以下两篇官方文档

  • gRPC naming and discovery
  • Custom Load Balancing Policies

实现依赖即将废弃的resolver.Address.Metadata,其实也仅是想复用已有的官方代码

自定义负载均衡并未依照示例,官方可能也是想展示更多细节,提供的明显不是最简单的实现方式,毕竟都是支持Service Config集成自定义配置的,也是需要熟悉endpointsharding和pickfirst相关逻辑的,所以不太适合用来入门

反观官方源码中roundrobin,基于baseBalancer仅实现Picker的方式,才真是将代码写在了刀刃上

服务启动clientv3.Put,服务关闭clientv3.Delete,创建租约并借助Lease.KeepAlive确保服务异常退出时因未自动续期而删除

通过context.WithValue携带ServiceID实现选择指定服务的连接

其余看看便知的就不赘述啦

server.go

package mainimport ("context""flag""fmt""log""log/slog""net""os""os/signal""github.com/panshiqu/golang/discovery""github.com/panshiqu/golang/utils""google.golang.org/grpc"pb "google.golang.org/grpc/examples/features/proto/echo"
)var id = flag.Int("id", 1, "id")
var env = flag.String("env", "dev", "environment")
var host = flag.String("h", "127.0.0.1", "host")type echoServer struct {pb.UnimplementedEchoServer
}func (s *echoServer) UnaryEcho(ctx context.Context, req *pb.EchoRequest) (*pb.EchoResponse, error) {return &pb.EchoResponse{Message: fmt.Sprintf("%s (from %d)", req.Message, *id)}, nil
}func main() {flag.Parse()lis, err := net.Listen("tcp", fmt.Sprintf("%s:0", *host))if err != nil {log.Fatal(utils.Wrap(err))}s := grpc.NewServer()pb.RegisterEchoServer(s, &echoServer{})addr := fmt.Sprintf("%s:%d", *host, lis.Addr().(*net.TCPAddr).Port)service, err := discovery.Register("http://127.0.0.1:2379", fmt.Sprintf("%s/game", *env), addr, *id)if err != nil {log.Fatal(utils.Wrap(err))}go func() {if err := s.Serve(lis); err != nil {slog.Error("serve", slog.Any("err", err))}}()c := make(chan os.Signal, 1)signal.Notify(c, os.Interrupt)sig := <-cslog.Info("notify", slog.Any("signal", sig))if err := service.Release(); err != nil {slog.Error("release", slog.Any("err", err))}s.GracefulStop()
}

client.go

package mainimport ("context""flag""fmt""log""time""github.com/panshiqu/golang/balancer"_ "github.com/panshiqu/golang/balancer""github.com/panshiqu/golang/utils"clientv3 "go.etcd.io/etcd/client/v3""go.etcd.io/etcd/client/v3/naming/resolver""google.golang.org/grpc""google.golang.org/grpc/credentials/insecure"pb "google.golang.org/grpc/examples/features/proto/echo"
)var id = flag.Int("id", 0, "id")func main() {flag.Parse()cli, err := clientv3.NewFromURL("http://127.0.0.1:2379")if err != nil {log.Fatal(utils.Wrap(err))}etcdResolver, err := resolver.NewBuilder(cli)if err != nil {log.Fatal(utils.Wrap(err))}cc, err := grpc.NewClient("etcd:///discovery/dev/game", grpc.WithResolvers(etcdResolver), grpc.WithDefaultServiceConfig(`{"loadBalancingConfig":[{"custom_round_robin":{}}]}`), grpc.WithTransportCredentials(insecure.NewCredentials()))if err != nil {log.Fatal(utils.Wrap(err))}defer cc.Close()ec := pb.NewEchoClient(cc)ctx := context.Background()if *id != 0 {ctx = context.WithValue(ctx, balancer.ServiceID, fmt.Sprint(*id))}for {r, err := ec.UnaryEcho(ctx, &pb.EchoRequest{Message: "hi"})if err != nil {log.Fatal(utils.Wrap(err))}fmt.Println(r)time.Sleep(time.Second)}
}

终端依次执行以下命令试试

go run client.go
go run server.go -id=1
go run server.go -id=2
go run client.go -id=1
# stop server 2

http://www.ppmy.cn/news/1526928.html

相关文章

红外成像人员检测数据集

红外成像人员检测数据集YOLO格式介绍 红外成像技术是一种非接触式的温度测量技术&#xff0c;通过探测物体发出的红外辐射来生成图像。这种技术在人员检测领域有着广泛的应用&#xff0c;尤其是在夜间监控、安全防范、医疗诊断、环境监测等方面。本文将详细介绍一个红外成像人…

小程序面试题八

一、微信小程序如何处理页面间的数据通信&#xff1f; 微信小程序处理页面间的数据通信&#xff0c;可以采用多种方式&#xff0c;这些方法根据具体需求和场景的不同而有所选择。以下是几种常见的页面间数据通信方式&#xff1a; 1. URL 传递参数 适用场景&#xff1a;适用于…

‌内网穿透技术‌总结

内网穿透是一种网络技术&#xff0c;通过它可以使外部网络用户访问内部网络中的设备和服务。一般情况下&#xff0c;内网是无法直接访问的&#xff0c;因为它位于一个封闭的局域网中&#xff0c;无法从外部访问。而通过内网穿透&#xff0c;可以将内部网络中的设备和服务暴露在…

Miracast/WifiDisplay开发相关的深入调研分析-android投屏实战开发

Miracast/WifiDisplay概念介绍 Miracast Miracast是由Wi-Fi联盟于2012年所制定&#xff0c;以Wi-Fi直连&#xff08;Wi-Fi Direct&#xff09;为基础的无线显示标准。支持此标准的消费性电子产品&#xff08;又称3C设备&#xff09;可透过无线方式分享视频画面&#xff0c;例如…

IP 协议分析《实验报告》

目录 一、 实验目的 二、实验设备和环境 三、实验记录 1、实验环境搭建 2、IP 协议分析 1.设置抓包接口 2.IP 报文分析 3.报文长度计算 4.生存时间 TTL 5.分析总结 3、IP分片 1.IP 分片简介 2.捕获分组 3.结果分析 一、 实验目的 1、掌握 IP 协议数据报格式&…

学习记录:js算法(三十三):LRU 缓存

文章目录 LRU 缓存网上思路 总结 LRU 缓存 请你设计并实现一个满足 LRU (最近最少使用) 缓存约束的数据结构。 实现 LRUCache 类&#xff1a; ● LRUCache(int capacity) 以 正整数 作为容量 capacity 初始化 LRU 缓存 ● int get(int key) 如果关键字 key 存在于缓存中&#x…

TypeScript:高级类型

一、交叉类型&#xff08;Intersection Types&#xff09; 交叉类型是将多个类型合并为一个类型。 这让我们可以把现有的多种类型叠加到一起成为一种类型&#xff0c;它包含了所需的所有类型的特性。 例如&#xff0c; Person & Serializable & Loggable同时是 Person …

华为OD机试真题-服务器广播-2024年OD统一考试(E卷)

最新华为OD机试考点合集:华为OD机试2024年真题题库(E卷+D卷+C卷)_华为od机试题库-CSDN博客 题目描述 服务器连接方式包括直接相连,间接相连。A和B直接连接,B和C直接连接,则A和C间接连接直接连接和间接连接都可以发送广播。 给出一个 N*N 数组,代表 N 个服务器 matrix…