第三章:数据复制¶
3.1 复制模式¶
主从复制¶
主从复制架构:
┌─────────────────────────────────────────────────────────────┐
│ │
│ ┌─────────────┐ │
│ │ Client │ │
│ └──────┬──────┘ │
│ │ │
│ ▼ │
│ ┌─────────────┐ │
│ │ Primary │ ← 写入 │
│ │ (Master) │ │
│ └──────┬──────┘ │
│ │ │
│ │ 复制 │
│ ├────────────────┬────────────────┐ │
│ ▼ ▼ ▼ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ Replica 1 │ │ Replica 2 │ │ Replica 3 │ │
│ │ (Slave) │ │ (Slave) │ │ (Slave) │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
│ ↑ ↑ ↑ │
│ │ │ │ │
│ └────────────────┴────────────────┘ │
│ 读取 │
│ │
│ 特点: │
│ - 写入通过主节点 │
│ - 读取可以分散到从节点 │
│ - 主节点故障需要选举新主 │
│ │
└─────────────────────────────────────────────────────────────┘
多主复制¶
多主复制架构:
┌─────────────────────────────────────────────────────────────┐
│ │
│ 数据中心 A 数据中心 B │
│ ┌─────────────────┐ ┌─────────────────┐ │
│ │ ┌───────────┐ │ │ ┌───────────┐ │ │
│ │ │ Master A │◄─┼──────────┼─►│ Master B │ │ │
│ │ └─────┬─────┘ │ │ └─────┬─────┘ │ │
│ │ │ │ │ │ │ │
│ │ ┌────┴────┐ │ │ ┌────┴────┐ │ │
│ │ ▼ ▼ │ │ ▼ ▼ │ │
│ │ ┌─────┐ ┌─────┐ │ │ ┌─────┐ ┌─────┐ │ │
│ │ │Rep.1│ │Rep.2│ │ │ │Rep.1│ │Rep.2│ │ │
│ │ └─────┘ └─────┘ │ │ └─────┘ └─────┘ │ │
│ └─────────────────┘ └─────────────────┘ │
│ │
│ 特点: │
│ - 多个主节点可写入 │
│ - 需要处理写冲突 │
│ - 适合多地域部署 │
│ │
└─────────────────────────────────────────────────────────────┘
3.2 复制策略¶
同步 vs 异步¶
# 同步复制
def sync_replication(data):
"""同步复制:等待所有副本确认"""
primary.write(data)
for replica in replicas:
success = replica.write_sync(data)
if not success:
raise ReplicationError(f"Replication failed to {replica}")
return Success()
# 异步复制
def async_replication(data):
"""异步复制:立即返回,后台复制"""
primary.write(data)
# 异步发送到副本
for replica in replicas:
threading.Thread(
target=replica.write_async,
args=(data,)
).start()
return Success()
# 半同步复制
def semi_sync_replication(data):
"""半同步:等待至少一个副本确认"""
primary.write(data)
# 等待至少一个副本
confirmed = 0
for replica in replicas:
if replica.write_sync(data):
confirmed += 1
if confirmed >= 1:
break
return Success()
3.3 冲突解决¶
最后写入胜利¶
import time
class LWWRegister:
"""Last-Write-Wins 寄存器"""
def __init__(self):
self.value = None
self.timestamp = 0
def write(self, value):
timestamp = time.time()
if timestamp > self.timestamp:
self.value = value
self.timestamp = timestamp
def merge(self, other):
"""合并其他副本的数据"""
if other.timestamp > self.timestamp:
self.value = other.value
self.timestamp = other.timestamp
向量时钟¶
class VectorClock:
"""向量时钟"""
def __init__(self, node_id):
self.node_id = node_id
self.clock = {}
def increment(self):
"""本地事件递增"""
self.clock[self.node_id] = self.clock.get(self.node_id, 0) + 1
def merge(self, other):
"""合并其他向量时钟"""
for node, time in other.clock.items():
self.clock[node] = max(self.clock.get(node, 0), time)
def compare(self, other):
"""比较两个向量时钟"""
all_nodes = set(self.clock.keys()) | set(other.clock.keys())
self_greater = False
other_greater = False
for node in all_nodes:
self_time = self.clock.get(node, 0)
other_time = other.clock.get(node, 0)
if self_time > other_time:
self_greater = True
elif other_time > self_time:
other_greater = True
if self_greater and not other_greater:
return 1 # self 更新
elif other_greater and not self_greater:
return -1 # other 更新
else:
return 0 # 并发,需要解决冲突
3.4 小结¶
本章介绍了数据复制:
- 主从复制简单但主节点是瓶颈
- 多主复制支持多写但需处理冲突
- 同步复制保证一致性但延迟高
- 向量时钟解决因果顺序
思考题¶
- 如何选择复制策略?
- 如何处理网络分区?
- 如何实现无冲突数据类型?