golang grpc 负载均衡的方法
微服务架构里面,每个服务都会有很多节点,如果流量分配不均匀,会造成资源的浪费,甚至将一些机器压垮,这个时候就需要负载均衡,最简单的一种策略就是轮询,顺序依次选择不同的节点访问。
grpc 在客户端提供了负载均衡的实现,并提供了服务地址解析和更新的接口(默认提供了 DNS 域名解析的支持),方便不同服务的集成
使用示例
conn, err := grpc.Dial( "", grpc.WithInsecure(), // 负载均衡,使用 consul 作服务发现 grpc.WithBalancer(grpc.RoundRobin(grpclb.NewConsulResolver( "127.0.0.1:8500", "grpc.health.v1.add", ))), )
创建连接的时候可以使用 WithBalancer 选项来指定负载均衡策略,这里使用 RoundRobin 算法,其实就是轮询策略
与 consul 的集成
有了负载均衡策略,还需要一个地址解析和更新策略,可以使用 DNS 服务来实现,但如果我们使用 consul 来做服务的注册和发现,可以通过实现 ‘naming.Resolver' 和 ‘naming.Watcher' 接口来支持
- naming.Resolver: 实现地址解析
- naming.Watcher: 实现节点的变更,添加或者删除
func NewConsulResolver(address string, service string) naming.Resolver { return &consulResolver{ address: address, service: service, } } type consulResolver struct { address string service string } func (r *consulResolver) Resolve(target string) (naming.Watcher, error) { config := api.DefaultConfig() config.Address = r.address client, err := api.NewClient(config) if err != nil { return nil, err } return &consulWatcher{ client: client, service: r.service, addrs: map[string]struct{}{}, }, nil } type consulWatcher struct { client *api.Client service string addrs map[string]struct{} lastIndex uint64 } func (w *consulWatcher) Next() ([]*naming.Update, error) { for { services, metainfo, err := w.client.Health().Service(w.service, "", true, &api.QueryOptions{ WaitIndex: w.lastIndex, // 同步点,这个调用将一直阻塞,直到有新的更新 }) if err != nil { logrus.Warn("error retrieving instances from Consul: %v", err) } w.lastIndex = metainfo.LastIndex addrs := map[string]struct{}{} for _, service := range services { addrs[net.JoinHostPort(service.Service.Address, strconv.Itoa(service.Service.Port))] = struct{}{} } var updates []*naming.Update for addr := range w.addrs { if _, ok := addrs[addr]; !ok { updates = append(updates, &naming.Update{Op: naming.Delete, Addr: addr}) } } for addr := range addrs { if _, ok := w.addrs[addr]; !ok { updates = append(updates, &naming.Update{Op: naming.Add, Addr: addr}) } } if len(updates) != 0 { w.addrs = addrs return updates, nil } } } func (w *consulWatcher) Close() { // nothing to do }
参考链接
gRPC Name Resolution: https://github.com/grpc/grpc/blob/master/doc/naming.md
Load Balancing in gRPC: https://github.com/grpc/grpc/blob/master/doc/load-balancing.md
dns_resolver: https://github.com/grpc/grpc-go/blob/30fb59a4304034ce78ff68e21bd25776b1d79488/naming/dns_resolver.go
代码地址: https://github.com/hatlonely/hellogolang/blob/master/sample/addservice/cmd/client/main.go
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。
- Go-指针、传值与传引用、垃圾回收
- SEO分享:彻底禁止搜索引擎抓取/收录动态页面或指定路径的方法
- Go-defer,panic,recover
- SEO技巧:Shell脚本自动提交网站404死链到搜索引擎
- Nginx发布1.9.0版本,新增支持TCP代理和负载均衡的stream模块
- WordPress4.2升级修复补丁:解决大量404请求以及评论表情路径及尺寸异常问题
- Linux系统编译安装Redis以及主从复制配置小记
- Go-Maps
- 为WordPress开启Nginx缩略图功能,七牛从此陌路
- 为网站开启Nginx缓存加速,支持html伪静态页面
- 解决WordPress升级4.2后调用国外图片导致大量404请求的问题
- JS代码实现浏览器网页标题的动态切换,略微提高网站粘性
- Go-List
- 分享张戈博客自用的php网址在线转换二维码的API源码
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法