外观
负载均衡
约 1432 字大约 5 分钟
2025-07-13
负载均衡
常见的负载均衡策略
一般而言,有以下几种常见的负载均衡策略。
轮询策略
轮询策略是最容易想到也是应用最广泛的负载均衡策略。轮询策略会顺序地从服务器列表中选择一个节点,请求会均匀地落在各个服务器上。轮询适合各个节点性能接近,并且没有状态的情况,但是在实际开发中,不同节点之间性能往往很难相同,这时候就可以应用另一种加权轮询策略。
加权轮询
加权轮询是对轮询策略的优化,给每个节点添加不同的权重。举个简单的例子,在实际开发中通常使用数组的数据结构来实现轮询,比如现在我有 A、B、C 三个节点,就可以在数组中添加 1、2、3 的数据,分别对应三个节点。现在我进行一个加权调整,让 1、2、3 对应 A,4、5 对应 B、C,这时候继续进行轮询,不同节点的权重就有变化了。
随机策略
随机策略和轮询相似,从列表中随机的取一个。我们都学过概率论的课程,真正的随机是很难实现的,所以如果访问量不是很大,最好不要应用随机策略,可能会导致请求不均匀。
最小响应时间
这个主要是在一些对请求延时敏感的场景中,在进行路由时,会优先发送给响应时间最小的节点。
最小并发数策略
你可以对比最小响应时间,最小并发策略会记录当前时刻每个节点正在处理的事务数,在路由时选择并发最小的节点。最小并发策略可以比较好地反应服务器运行情况,适用于对系统负载较为敏感的场景。
一致性哈希
在负载均衡策略中,可以应用一致性哈希,减少节点扩展时的数据失效或者迁移的情况。维基百科对一致性哈希是这么定义的:
一致性哈希是一种特殊的哈希算法。在使用一致性哈希算法后,哈希表槽位数(大小)的改变平均只需要对 K/n 个关键字重新映射,其中 K 是关键字的数量,n 是槽位数量。然而在传统的哈希表中,添加或删除一个槽位几乎需要对所有关键字进行重新映射。
一致性哈希通过一个哈希环实现,Hash 环的基本思路是获取所有的服务器节点 hash 值,然后获取 key 的 hash,与节点的 hash 进行对比,找出顺时针最近的节点进行存储和读取。
以电商中的商品数据为例,假设我们有 4 台缓存服务器:
- A 服务器,地址 hash 结果是 100
- B 服务器,地址 hash 结果是 200
- C 服务器,地址 hash 结果是 300
- D 服务器,地址 hash 结果是 400
现在有某条数据的 Key 进行哈希操作,得到 200,则存储在 B 服务器;某条数据的 Key 进行哈希操作,得到 260,则存储在 C 服务器;某条数据的 Key 进行哈希操作,得到 500,则存储在 A 服务器。
一致性哈希算法在扩展时,只需要迁移少量的数据就可以。例如,我们刚才的例子中,如果 D 服务器下线,原先路由到 D 服务器的数据,只要顺时针迁移到 A 服务器就可以,其他服务器不受影响,我们只需要移动一台机器的数据即可。
一致性哈希虽然对扩容和缩容友好,但是存在另外一个问题,就很容易出现数据倾斜。
相信你已经考虑到了,假设我们有 A、B、C 一直到 J 服务器,总共 10 台,组成一个哈希环。如果从 F 服务器一直到 J 服务器的 5 个节点宕机,那么这 5 台服务器原来的访问,都会被转移到服务器 A 之上,服务器的流量可能是原来的 5 倍或者更高,直到把服务器 A 打爆,这时候流量继续转移到 B 服务器,就出现我们在第 34 课时提到的缓存雪崩。
那么数据倾斜是如何解决的呢? 一个方案就是添加虚拟节点,对服务器节点也进行哈希操作,在整个哈希环上,均匀添加若干个节点。比如 a1 和 a2 都属于 A 节点,b1、b2 都属于 B 节点,这样在哈希时可以平衡各个节点的数据。
另外,在面试中,面试官可能会要求你实现一致性哈希算法。以 Java 为例,可以应用 TreeMap 这个数据结构。
TreeMap 基于红黑树实现,元素默认按照 keys 的自然排序排列,对外开放了一个 tailMap(K fromKey) 方法,该方法可以返回比 fromKey 顺序的下一个节点,大大简化了一致性哈希的实现。这里我就不添加代码了,感兴趣的同学可以去动手模拟实现一下。
数据存储
SQL vs NoSQL(文档/列存储/图),分库分表策略
缓存
读写策略(Cache-Aside/Write-through),缓存击穿/雪崩解决方案
消息队列
Kafka的副本同步、RabbitMQ的交换机模型