Files
interview/questions/consistency-hash.md
yasinshaw 71e3497bfd feat: add comprehensive system design interview questions
- design-seckill.md: 秒杀系统设计
- design-shorturl.md: 短链接系统设计
- design-lbs.md: LBS附近的人系统设计
- design-im.md: 即时通讯系统设计
- design-feed.md: 社交信息流系统设计

Each document includes:
- Requirements analysis and data volume assessment
- Technical challenges
- System architecture design
- Database design
- Caching strategies
- Scalability considerations
- Practical project experience
- Alibaba P7 level additional points

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-28 23:43:36 +08:00

428 lines
8.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 一致性哈希算法
## 问题
1. 什么是一致性哈希?解决了什么问题?
2. 一致性哈希的原理是什么?
3. 什么是虚拟节点?为什么需要虚拟节点?
4. 一致性哈希在负载均衡、分布式缓存中的应用
5. 一致性哈希有哪些优缺点?
6. 在实际项目中如何实现一致性哈希?
---
## 标准答案
### 1. 传统哈希的问题
#### **场景:分布式缓存**
假设有 3 台缓存服务器:
```
Server A, Server B, Server C
```
使用传统哈希:`hash(key) % N`
```java
int serverIndex = hash(key) % 3; // 3 台服务器
```
**问题:服务器扩容/缩容**
新增一台服务器Server D
```
原来hash(key) % 3
现在hash(key) % 4
结果:大部分 key 的路由都变了!
- 缓存全部失效
- 数据库压力激增
```
**示例**
```
3 台服务器时:
hash("user:1") % 3 = 1 → Server B
hash("user:2") % 3 = 2 → Server C
4 台服务器时(新增 Server D
hash("user:1") % 4 = 2 → Server C变了
hash("user:2") % 4 = 3 → Server D变了
影响75% 的缓存失效
```
---
### 2. 一致性哈希原理
#### **核心思想**
将服务器和数据都映射到**哈希环**上:
- 顺时针查找最近的服务器
- 服务器变化时,只影响相邻数据
**哈希环**0 - 2^32-1
```
0
Server A ──────────── Server B
↗ ↘
↗ ↘
↑ ↓
| ↓
Server D ←────────────→ Server C
2^32-1
```
---
#### **算法步骤**
**步骤 1映射服务器到环**
```java
// 服务器 IP → 哈希值
hash("192.168.1.10") 1000 Server A
hash("192.168.1.11") 5000 Server B
hash("192.168.1.12") 10000 Server C
```
**步骤 2映射数据到环**
```java
// 数据 Key → 哈希值
hash("user:1") 2000
hash("user:2") 6000
hash("user:3") 15000
```
**步骤 3顺时针查找服务器**
```
user:1 (2000) → Server B (5000) // 顺时针第一个服务器
user:2 (6000) → Server C (10000)
user:3 (15000) → Server A (1000 环绕)
```
---
#### **Java 实现**
```java
public class ConsistentHash<T> {
private final TreeMap<Long, T> ring = new TreeMap<>();
private final int virtualNodes; // 虚拟节点数
public ConsistentHash(int virtualNodes) {
this.virtualNodes = virtualNodes;
}
// 添加节点
public void addNode(T node) {
for (int i = 0; i < virtualNodes; i++) {
String virtualNodeName = node.toString() + "#" + i;
long hash = hash(virtualNodeName);
ring.put(hash, node);
}
}
// 移除节点
public void removeNode(T node) {
for (int i = 0; i < virtualNodes; i++) {
String virtualNodeName = node.toString() + "#" + i;
long hash = hash(virtualNodeName);
ring.remove(hash);
}
}
// 获取节点
public T getNode(String key) {
if (ring.isEmpty()) {
return null;
}
long hash = hash(key);
// 顺时针查找
Map.Entry<Long, T> entry = ring.ceilingEntry(hash);
if (entry == null) {
// 环绕到第一个节点
entry = ring.firstEntry();
}
return entry.getValue();
}
// 哈希函数FNV1_32_HASH
private long hash(String key) {
final long p = 16777619;
long hash = 2166136261L;
for (byte b : key.getBytes()) {
hash = (hash ^ b) * p;
}
hash += hash << 13;
hash ^= hash >> 7;
hash += hash << 3;
hash ^= hash >> 17;
hash += hash << 5;
return hash & 0xffffffffL;
}
}
```
**使用示例**
```java
// 创建一致性哈希环
ConsistentHash<String> consistentHash = new ConsistentHash<>(150);
// 添加服务器
consistentHash.addNode("192.168.1.10"); // Server A
consistentHash.addNode("192.168.1.11"); // Server B
consistentHash.addNode("192.168.1.12"); // Server C
// 获取路由
String server = consistentHash.getNode("user:1001");
System.out.println("路由到服务器: " + server);
// 新增服务器
consistentHash.addNode("192.168.1.13"); // Server D
// 只有部分数据受影响
```
---
### 3. 虚拟节点
#### **问题:数据倾斜**
**场景**
```
哈希环:
Server A (1000)
Server B (5000)
Server C (10000)
数据分布:
A: 2000 条
B: 500 条
C: 500 条
数据倾斜A 的负载远大于 B、C
```
**原因**
- 节点少,哈希分布不均
- 真实服务器数量有限
---
#### **解决方案:虚拟节点**
**原理**
每个真实节点映射多个虚拟节点:
```
真实节点 A
├─ 虚拟节点 A#1 → 1000
├─ 虚拟节点 A#2 → 3000
├─ 虚拟节点 A#3 → 7000
└─ ...
真实节点 B
├─ 虚拟节点 B#1 → 2000
├─ 虚拟节点 B#2 → 4000
└─ ...
真实节点 C
├─ 虚拟节点 C#1 → 5000
└─ ...
```
**效果**
```
数据分布:
A: 1000 条25%
B: 1000 条25%
C: 1000 条25%
D: 1000 条25%
均衡度:高
```
**虚拟节点数量**
- 一般100-150 个
- 更多:更均衡,但内存占用大
---
### 4. 一致性哈希的应用
#### **应用 1分布式缓存Redis Cluster**
```java
// Redis 集群路由
public class RedisClusterRouter {
private final ConsistentHash<JedisPool> consistentHash;
public RedisClusterRouter(List<JedisPool> pools) {
this.consistentHash = new ConsistentHash<>(150);
for (JedisPool pool : pools) {
consistentHash.addNode(pool);
}
}
public Jedis getJedis(String key) {
JedisPool pool = consistentHash.getNode(key);
return pool.getResource();
}
}
```
**优点**
- 扩容/缩容影响小
- 数据迁移量小
---
#### **应用 2负载均衡Nginx**
```nginx
# Nginx 一致性哈希配置
upstream backend {
consistent_hash $request_uri;
server 192.168.1.10:8080;
server 192.168.1.11:8080;
server 192.168.1.12:8080;
}
```
**效果**
- 相同请求路由到同一服务器
- 会话保持(无需 Sticky Session
---
#### **应用 3分库分表**
```java
// 分库路由
public class ShardingRouter {
private final ConsistentHash<String> dbRouter;
public ShardingRouter(List<String> databases) {
this.dbRouter = new ConsistentHash<>(100);
for (String db : databases) {
dbRouter.addNode(db);
}
}
public String getDatabase(String userId) {
return dbRouter.getNode(userId);
}
}
```
---
### 5. 一致性哈希的优缺点
#### **优点**
1. **最小化数据迁移**
- 新增节点:只影响相邻节点数据
- 移除节点:只影响该节点数据
2. **良好的容错性**
- 节点故障:数据自动迁移到下一个节点
- 平滑恢复:节点恢复后数据自动迁移回来
3. **可扩展性**
- 支持动态增删节点
- 适合大规模分布式系统
---
#### **缺点**
1. **数据倾斜**
- 节点少时分布不均
- 需要虚拟节点解决
2. **实现复杂**
- 相比简单哈希复杂度高
- 需要维护哈希环
3. **内存占用**
- 虚拟节点占用内存
- 节点多时内存开销大
---
### 6. 实际项目经验
#### **案例Redis 集群扩容**
**场景**
- 现有 3 台 Redis每台 10 万 key
- 新增 2 台 Redis
**不使用一致性哈希**
```
迁移量10 万 × 5/6 ≈ 8.3 万 key83%
```
**使用一致性哈希**
```
迁移量10 万 × 2/5 ≈ 4 万 key40%
```
**实现**
```java
// 1. 新节点上线
JedisPool newPool1 = new JedisPool("192.168.1.13");
JedisPool newPool2 = new JedisPool("192.168.1.14");
consistentHash.addNode(newPool1);
consistentHash.addNode(newPool2);
// 2. 数据迁移
for (String key : allKeys) {
JedisPool newPool = consistentHash.getNode(key);
JedisPool oldPool = oldMapping.get(key);
if (newPool != oldPool) {
// 迁移数据
migrateData(key, oldPool, newPool);
}
}
```
---
### 7. 阿里 P7 加分项
**深度理解**
- 理解一致性哈希的数学原理(哈希函数、分布均匀性)
- 理解虚拟节点数量对均衡度的影响
- 了解其他哈希算法(如 Rendezvous Hash
**实战经验**
- 有使用一致性哈希实现分库分表的经验
- 有处理数据倾斜和迁移的经验
- 有一致性哈希在生产环境的调优经验
**架构能力**
- 能设计支持平滑扩容的分片集群
- 能设计数据迁移的灰度方案
- 有一致性哈希的监控和告警经验
**技术选型**
- 了解 Redis Cluster、Cassandra 等系统的一致性哈希实现
- 了解 Nginx、HAProxy 等负载均衡器的一致性哈希配置
- 能根据业务特点选择合适的哈希算法