【分布式系统】分布式事务与一致性协议:从理论到实践
引言
分布式事务是分布式系统中的核心难题,确保多个节点之间的数据一致性是构建可靠系统的关键。本文将详细介绍分布式事务的概念、一致性协议和实现方案。
一、分布式事务概述
1.1 ACID原则
| 特性 |
说明 |
| 原子性 |
事务要么全部成功,要么全部失败 |
| 一致性 |
事务执行前后数据状态一致 |
| 隔离性 |
多个事务并发执行互不干扰 |
| 持久性 |
事务提交后数据永久保存 |
1.2 CAP定理
┌─────────────────────────────────────────────────────┐
│ CAP定理 │
├─────────────────────────────────────────────────────┤
│ Consistency (一致性) │
│ ↖ ↗ │
│ ↘ ── ── ↙ │
│ Availability (可用性) Partition Tolerance │
│ (分区容错性) │
└─────────────────────────────────────────────────────┘
CAP权衡:
- CP: 一致性 + 分区容错性 (牺牲可用性)
- AP: 可用性 + 分区容错性 (牺牲一致性)
- CA: 一致性 + 可用性 (不现实,无法应对分区)
二、分布式事务协议
2.1 两阶段提交(2PC)
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ Coordinator│ │ Participant 1│ │ Participant 2│
│ (协调者) │ │ (参与者1) │ │ (参与者2) │
└──────┬───────┘ └───────┬─────────┘ └───────┬─────────┘
│ │ │
│ Phase 1: Prepare │ │
│─────────────────────>│ │
│ │ 执行事务准备 │
│ │ 锁定资源 │
│ │<────────────────────│
│ │ │
│ │ YES/NO │
│<─────────────────────│ │
│ │ │
│ │ Phase 1: Prepare │
│ │─────────────────────>│
│ │ │ 执行事务准备
│ │ │ 锁定资源
│ │ │ YES/NO
│ │<─────────────────────│
│ │ │
│ │ │
│ Phase 2: Commit │ │
│─────────────────────>│ │
│ │ 提交事务 │
│ │ 释放资源 │
│ │<────────────────────│
│ │ │
│ │ Commit │
│ │─────────────────────>│
│ │ │ 提交事务
│ │ │ 释放资源
│ │<─────────────────────│
▼ ▼ ▼
2.2 三阶段提交(3PC)
class ThreePhaseCommit:
def __init__(self):
self.state = 'idle'
self.participants = []
def can_commit(self):
"""阶段1: 询问参与者是否可以提交"""
self.state = 'can_commit'
for p in self.participants:
if not p.can_commit():
return False
return True
def pre_commit(self):
"""阶段2: 预提交"""
self.state = 'pre_commit'
for p in self.participants:
p.pre_commit()
def do_commit(self):
"""阶段3: 执行提交"""
self.state = 'do_commit'
for p in self.participants:
p.commit()
self.state = 'committed'
2.3 Paxos算法
class Proposer:
def __init__(self, proposer_id):
self.proposer_id = proposer_id
self.proposal_number = 0
def prepare(self, acceptors):
"""准备阶段"""
self.proposal_number += 1
promises = []
for acceptor in acceptors:
response = acceptor.promise(self.proposal_number)
if response:
promises.append(response)
if len(promises) >= (len(acceptors) // 2) + 1:
# 找到最高编号的接受值
highest_value = max(promises, key=lambda x: x[0])[1]
return highest_value
def accept(self, acceptors, value):
"""接受阶段"""
accepts = []
for acceptor in acceptors:
if acceptor.accept(self.proposal_number, value):
accepts.append(True)
return len(accepts) >= (len(acceptors) // 2) + 1
三、分布式事务实现
3.1 本地消息表模式
class OrderService:
def create_order(self, order_data):
# 1. 创建订单
order = Order.create(order_data)
# 2. 记录本地消息
LocalMessage.create({
'message_id': str(uuid.uuid4()),
'topic': 'order_created',
'payload': {'order_id': order.id},
'status': 'pending'
})
# 3. 发送消息(可能失败)
try:
message_queue.send('order_created', {'order_id': order.id})
LocalMessage.update(status='sent')
except Exception:
# 消息发送失败,等待重试
pass
def retry_failed_messages(self):
"""重试失败的消息"""
messages = LocalMessage.filter(status='pending')
for msg in messages:
try:
message_queue.send(msg.topic, msg.payload)
msg.status = 'sent'
msg.save()
except Exception:
# 记录失败次数,超过阈值告警
msg.retry_count += 1
msg.save()
3.2 Saga模式
class OrderSaga:
def __init__(self):
self.steps = []
def add_step(self, action, compensation):
"""添加步骤和补偿动作"""
self.steps.append({
'action': action,
'compensation': compensation
})
def execute(self):
"""执行Saga"""
completed_steps = []
for i, step in enumerate(self.steps):
try:
step['action']()
completed_steps.append(i)
except Exception as e:
# 回滚已完成的步骤
for j in reversed(completed_steps):
self.steps[j]['compensation']()
raise e
# 使用示例
saga = OrderSaga()
saga.add_step(
action=create_order,
compensation=rollback_order
)
saga.add_step(
action=reserve_inventory,
compensation=release_inventory
)
saga.add_step(
action=process_payment,
compensation=refund_payment
)
saga.execute()
3.3 TCC模式
class TCCService:
def try_(self, order_id):
"""尝试阶段"""
# 检查库存
inventory = Inventory.get(order_id.product_id)
if inventory.quantity < order_id.quantity:
raise Exception("库存不足")
# 冻结库存
inventory.reserved += order_id.quantity
inventory.save()
def confirm(self, order_id):
"""确认阶段"""
inventory = Inventory.get(order_id.product_id)
inventory.quantity -= order_id.quantity
inventory.reserved -= order_id.quantity
inventory.save()
def cancel(self, order_id):
"""取消阶段"""
inventory = Inventory.get(order_id.product_id)
inventory.reserved -= order_id.quantity
inventory.save()
四、一致性级别
4.1 强一致性
# 使用分布式锁实现强一致性
def transfer_money(from_account, to_account, amount):
lock = acquire_lock('transfer_lock')
try:
# 读取账户余额
from_balance = get_balance(from_account)
to_balance = get_balance(to_account)
# 检查余额
if from_balance < amount:
raise Exception("余额不足")
# 更新账户余额
update_balance(from_account, from_balance - amount)
update_balance(to_account, to_balance + amount)
finally:
release_lock('transfer_lock')
4.2 最终一致性
# 使用消息队列实现最终一致性
class PaymentService:
def process_payment(self, order_id, amount):
# 扣除用户余额
user_balance.decrement(amount)
# 发送消息通知订单服务
message_queue.send('payment_completed', {
'order_id': order_id,
'amount': amount
})
class OrderService:
def handle_payment_completed(self, message):
# 更新订单状态
order = Order.get(message['order_id'])
order.status = 'paid'
order.save()
4.3 会话一致性
# 确保用户会话内的数据一致性
class SessionConsistency:
def __init__(self):
self.session_cache = {}
def get_data(self, user_id, key):
"""获取数据,优先从会话缓存获取"""
session_key = f"{user_id}:{key}"
if session_key in self.session_cache:
return self.session_cache[session_key]
# 从数据库获取
data = db.query(f'SELECT * FROM data WHERE user_id = {user_id}')
# 更新会话缓存
self.session_cache[session_key] = data
return data
def update_data(self, user_id, key, value):
"""更新数据,同时更新会话缓存"""
session_key = f"{user_id}:{key}"
# 更新数据库
db.execute(f'UPDATE data SET value = {value} WHERE user_id = {user_id}')
# 更新会话缓存
self.session_cache[session_key] = value
五、分布式锁
5.1 Redis分布式锁
def acquire_lock(lock_name, timeout=10):
"""获取分布式锁"""
identifier = str(uuid.uuid4())
end = time.time() + timeout
while time.time() < end:
# SET NX(不存在时设置)+ EX(过期时间)
if redis_client.set(lock_name, identifier, nx=True, ex=timeout):
return identifier
time.sleep(0.01)
return None
def release_lock(lock_name, identifier):
"""释放分布式锁"""
# 使用Lua脚本保证原子性
script = """
if redis.call('get', KEYS[1]) == ARGV[1] then
return redis.call('del', KEYS[1])
else
return 0
end
"""
redis_client.eval(script, 1, lock_name, identifier)
5.2 ZooKeeper分布式锁
from kazoo.client import KazooClient
class ZookeeperLock:
def __init__(self, zk_hosts):
self.zk = KazooClient(hosts=zk_hosts)
self.zk.start()
def acquire(self, lock_path):
"""获取锁"""
# 创建临时有序节点
node = self.zk.create(
f"{lock_path}/lock-",
b'',
ephemeral=True,
sequence=True
)
# 获取所有子节点
children = self.zk.get_children(lock_path)
children.sort()
# 检查是否是最小节点
if node == f"{lock_path}/{children[0]}":
return True
# 监听前一个节点
prev_node = f"{lock_path}/{children[children.index(node.split('/')[-1]) - 1]}"
event = threading.Event()
@self.zk.DataWatch(prev_node)
def watch(data, stat):
if stat is None:
event.set()
event.wait()
return True
def release(self, lock_path):
"""释放锁"""
# 删除节点
self.zk.delete(f"{lock_path}/lock-*")
六、实战案例:订单支付系统
6.1 架构设计
class OrderPaymentSystem:
def __init__(self):
self.order_service = OrderService()
self.payment_service = PaymentService()
self.inventory_service = InventoryService()
self.message_queue = MessageQueue()
def process_order(self, order_data):
"""处理订单"""
saga = OrderSaga()
# 添加步骤
saga.add_step(
action=lambda: self.order_service.create(order_data),
compensation=lambda: self.order_service.cancel(order_data['id'])
)
saga.add_step(
action=lambda: self.inventory_service.reserve(order_data),
compensation=lambda: self.inventory_service.release(order_data)
)
saga.add_step(
action=lambda: self.payment_service.charge(order_data),
compensation=lambda: self.payment_service.refund(order_data)
)
# 执行Saga
saga.execute()
# 发送订单完成消息
self.message_queue.send('order_completed', {'order_id': order_data['id']})
6.2 数据一致性保障
class ConsistencyManager:
def __init__(self):
self.transaction_log = []
def begin_transaction(self):
"""开始事务"""
transaction_id = str(uuid.uuid4())
self.transaction_log.append({
'transaction_id': transaction_id,
'operations': [],
'status': 'pending'
})
return transaction_id
def record_operation(self, transaction_id, operation):
"""记录操作"""
for tx in self.transaction_log:
if tx['transaction_id'] == transaction_id:
tx['operations'].append(operation)
break
def commit(self, transaction_id):
"""提交事务"""
for tx in self.transaction_log:
if tx['transaction_id'] == transaction_id:
tx['status'] = 'committed'
break
def rollback(self, transaction_id):
"""回滚事务"""
for tx in self.transaction_log:
if tx['transaction_id'] == transaction_id:
# 逆序执行补偿操作
for op in reversed(tx['operations']):
op['compensation']()
tx['status'] = 'rolled_back'
break
七、常见问题与解决方案
7.1 网络分区
| 场景 |
解决方案 |
| 网络中断 |
使用超时机制和重试 |
| 脑裂问题 |
使用Quorum机制 |
| 数据不一致 |
使用最终一致性 |
7.2 事务超时
| 场景 |
解决方案 |
| 长时间事务 |
拆分事务 |
| 锁超时 |
设置合理的超时时间 |
| 资源占用 |
使用超时释放机制 |
7.3 数据丢失
| 场景 |
解决方案 |
| 消息丢失 |
使用持久化消息队列 |
| 数据损坏 |
使用校验和 |
| 存储故障 |
使用冗余存储 |
八、结语
分布式事务是构建可靠分布式系统的关键技术。通过选择合适的一致性协议和实现方案,可以在可用性和一致性之间找到平衡。希望本文能帮助你理解分布式事务的原理和实践。
#分布式系统 #分布式事务 #一致性 #2PC #Saga