负载均衡
关于负载均衡相关的一些介绍
负载均衡 将超过单节点承受能力的流量分配给多个节点
要点
- 服务发现 - 如何识别或路由到最终的业务应用
- 产品选型 - 采用什么产品、硬件、架构
- 负载算法
一、服务发现
即关于负载均衡的路径信息该在哪个节点维护
一般来说数据流有 3 个区域: 客户端 -> 负载均衡器(lb) -> N 个上游服务器(service)
方案一: 在客户端配置
即最终访问哪个节点是由客户端决定的,有多种细分方案
-
客户端硬编码; 客户端有一个服务列表,每次请求按设定规则随机或轮询选择一个地址进行访问;
-
客户端指定服务器转发; 客户端在http请求 的 header 头增减一个决定路由的字段, 服务器端LB再根据这个字段进行转发到指定服务器;
-
服务接口列表: 客户先请求一个服务器接口, 获取一个可用地址列表, 然后选一个再发起业务请求, 类似 DNS或注册中心的机制;
优点: 简单, 可控, 客户端调试时很容易定位到这个请求是哪个服务器处理的;
缺点: 极端情况下变更服务节点可能需要同时改这三个区域的配置;
方案二: 在 LB 上配置
很好理解, 传统的 nginx, haprox 等都是这样做的;
即 LB 根据自身独立的负载规则转发到后端应用;
优点: 好理解, 可控程度高
缺点: 后端变更后(如新增节点), 需要再改一次 lb 的配置
方案三: 在后端服务上配置
核心是 lb 动态获取后端服务的变化, 有多种细分实现方法;
-
方法一: lb 提供一个接口, 后端应用服务上线时主动去注册, 下线时主动注销;
-
方法二: 有一个公共注册中心或配置中心(etcd, consul, redis, eureka, mysql 等), service 去注册和注销, lb 动态去拉取更新, 或者是 lb 进行 watch 监听;
这两个方法都存在的问题: 程序异常停止没主动下线时的问题, 需要配合健康检查;
-
方法三: 和方法二差不多, 但 lb 不是监听注册中心, 而是监听 docker, kubernetes 等组件的 api, 服务一有变动立即可知;
程序内部不需要引入注册类的库, 历史老旧应用无需改造即可适配, 特别适合云原生环境; -
后端服务器重定向到目标地址。
优点: 一次变更只需要后端的服务改一次
缺点: 假设某个节点服务异常, 希望隔离流量待排查, 而不是直接下线服务时, 比较麻烦;
方案选择
根据实际情况选
- 绝对性能型 - 优先客户端负载
- 方便可控型 - 优先 lb 配置
- 自动化程度要求高 - 就由后端配置
- 如果是云原生或微服务场景也更推荐由后端应用控制
LB 的一次连接和二次连接模式
一次连接: 负载均衡器对数据包仅做转发, 而不对后端重新发起三次握手, 类似交换机, 不记录状态;
二次连接: 和一次连接相对应, 在 tcp 转发时候, 对后端重新进行了三次握手,代理模式,有状态记录;
不严谨的话可以通过简单对比源端口是否有改变来简单判断是一次连接还是二次连接, 端口没改变, 可以理解为一次连接, 有改变就是二次连接
替代方案
使用队列来替代负载均衡, 改用生产者消费者模型, 去除了转发算法