负载均衡的业务场景是这样的,我们的服务在运行时会有多个实例,当服务被调用时,我们需要确定哪个服务实例来处理请求。
对于后端服务实例来说,负载均衡就是一个调度器,它将发送给被调用服务的每一个请求,按照一定的策略分配给服务实例组中的一个实例,确保能高效、正确地提供服务。
负载均衡的关键点
从负载均衡处理的业务场景来看,负载均衡有两个关键点:
- 高效地提供服务,这是后端服务实例组的资源运行效率问题。负载均衡需要考虑到各个实例性能差异的情况,让每一个实例都能充分发挥它的能力,不要出现一些实例负载比较高,而另一些实例负载非常低的情况。即负载均衡要有公平性。
- 正确地提供服务,这是后端服务对外表现出的整体结果。负载均衡需要确保外部对后端服务的请求,一定能被路由到可以提供正确服务的实力上。如果后端服务实例时有状态的,我们就需要考虑每个请求携带的状态,然后根据状态信息,将请求正确路由到后端服务实例上。即负载均衡要有正确性。
在不同的业务场景中,我们对负载均衡策略进行设计时,影响最大的因素是后端服务是否存在状态,后端实例有状态,负载均衡就需要关心请求的状态。
无状态的负载均衡
无状态的负载均衡策略就是指不需要关心请求的状态。即服务实例不在本地机器或者内存中存储状态信息,这些信息会存储到一个中心存储器中,例如MySQL、Redis等。
接下来我们来看一下无状态负载均衡的策略。
轮询
轮询的策略非常简单,只需要将请求按照顺序分配给多个实例,不用再做其他的处理。
轮询在路由时,不利用请求的状态信息,在公平性方面,因为它只是按顺序分配请求,所以适用于请求的工作负载和服务实例的处理能力差异都比较小的情况。
权重轮询
权重轮询的策略是指为每一个后端服务实例分配一个权重,分配请求的数量和实例的权重成正比轮询。例如有两个实例A、B,假设我们设置A的权重是20,B的权重是80,那么负载均衡会将20%的请求数量分配给A,80%的请求数量分配给B。
权重轮询也不利用请求的状态信息,在公平性方面,因为权重策略会按权重比例分配请求数,所以我们可以利用它解决实例的处理能力差异问题,它的公平性要比轮询策略好。
半状态负的负载均衡
半状态的负载均衡是指虽然利用请求的状态信息进行路由,但是仅仅进行简单的规则处理,它不保证路由的正确性,正确性由后端服务实例来保证。
另外,一些服务实例会在内存中缓存一些状态数据,用于提升系统的性能,如果一个请求被路由到错误的实例中,该实例可以立即通过中心存储,读取出所需要的数据,然后在内存中重建并缓存正确的处理请求,不会导致请求出现错误。
半状态的负载均衡将请求按照一定的策略进行路由,后端服务实例可以利用路由规则进行优化。
Hash
Hash负载均衡策略是指将请求的状态信息,按照一定的Hash算法固定分配到一个实例上,例如按照请求的来源IP地址或者用户的ID,将同一个来源IP地址或者用户ID请求固定到一个实例上。
公平性方面,在不考虑Hash算法均匀性的情况下,Hash策略会按照Hash值按摩等分,它和轮询策略类似,不能解决请求的工作负载和服务实例的处理能力差异的问题。
一致性Hash
一致性 Hash 和 Hash 策略最大的区别在于,一致性 Hash 是对固定值 232 求模,不会随着机器数量的变化而变化,所以对于同一个 Request ID , iRequest 是始终稳定不变的,这样就解决了 Hash 的策略在实例数量发送变化后,几乎所有的分配关系都会发生变化的问题。
关于一致性 Hash 策略公平性的问题,一致性 Hash 是通过增加虚拟节点的方法来解决的,在 Hash 环中路由到虚拟实例的请求,会被路由到它的真实实例上。
全状态的负载均衡
全状态的负载均衡是指负载均衡策略不仅仅利用请求的状态信息进行路由,并且在后端服务实例有状态的情况下,依然保证路由的正确性。
全状态的负载均衡一般以路由服务的形式存在,在路由服务里面,都会存储后端实例 ID 和状态信息的索引,在进行请求路由的时候,路由服务从请求的状态信息中获得索引的标识,通过查询索引获得后端实例的 ID,然后再进行路由。
此文章为极客时间4月份Day05学习笔记,内容来自《深入浅出分布式技术原理》课程。