面试题答案
一键面试1. 分布式事务协议选择 - 两阶段提交(2PC)
两阶段提交是一种常用的分布式事务协议,分为准备阶段(投票阶段)和提交阶段。
2. Python代码实现
事务发起
import threading
import mysql.connector
# 模拟多个数据库连接
db1 = mysql.connector.connect(user='user', password='password', host='127.0.0.1', database='db1')
db2 = mysql.connector.connect(user='user', password='password', host='127.0.0.1', database='db2')
def execute_transaction():
# 事务发起,开始准备阶段
prepare_result = []
threads = []
def prepare_db1():
cursor = db1.cursor()
try:
cursor.execute('START TRANSACTION')
cursor.execute('UPDATE table1 SET column1 = "value1" WHERE condition')
prepare_result.append(True)
except Exception as e:
prepare_result.append(False)
finally:
cursor.close()
def prepare_db2():
cursor = db2.cursor()
try:
cursor.execute('START TRANSACTION')
cursor.execute('UPDATE table2 SET column2 = "value2" WHERE condition')
prepare_result.append(True)
except Exception as e:
prepare_result.append(False)
finally:
cursor.close()
t1 = threading.Thread(target=prepare_db1)
t2 = threading.Thread(target=prepare_db2)
threads.append(t1)
threads.append(t2)
for t in threads:
t.start()
for t in threads:
t.join()
if all(prepare_result):
# 提交阶段
for t in threads:
t = threading.Thread(target=commit_db1) if t == t1 else threading.Thread(target=commit_db2)
t.start()
else:
# 回滚阶段
for t in threads:
t = threading.Thread(target=rollback_db1) if t == t1 else threading.Thread(target=rollback_db2)
t.start()
def commit_db1():
cursor = db1.cursor()
try:
cursor.execute('COMMIT')
except Exception as e:
print(f"Commit error in db1: {e}")
finally:
cursor.close()
def commit_db2():
cursor = db2.cursor()
try:
cursor.execute('COMMIT')
except Exception as e:
print(f"Commit error in db2: {e}")
finally:
cursor.close()
def rollback_db1():
cursor = db1.cursor()
try:
cursor.execute('ROLLBACK')
except Exception as e:
print(f"Rollback error in db1: {e}")
finally:
cursor.close()
def rollback_db2():
cursor = db2.cursor()
try:
cursor.execute('ROLLBACK')
except Exception as e:
print(f"Rollback error in db2: {e}")
finally:
cursor.close()
if __name__ == '__main__':
execute_transaction()
db1.close()
db2.close()
事务协调
在上述代码中,execute_transaction
函数负责协调事务。它先开启多线程分别对不同数据库进行准备操作,收集准备结果。根据准备结果决定是进入提交阶段还是回滚阶段。
提交/回滚操作
- 提交操作:如果所有数据库准备成功,开启多线程分别对每个数据库执行
COMMIT
操作。 - 回滚操作:如果有任何一个数据库准备失败,开启多线程分别对每个数据库执行
ROLLBACK
操作。
3. 方案可能存在的问题及解决方案
单点故障
- 问题:协调者(这里代码中的
execute_transaction
函数类似协调者角色)如果在准备阶段之后、提交或回滚之前崩溃,可能导致部分参与者处于不确定状态。 - 解决方案:引入冗余协调者,使用选举算法(如 Paxos、Raft)来保证在主协调者故障时,备用协调者可以接替工作。
网络分区
- 问题:网络分区可能导致协调者与参与者之间通信中断,部分参与者无法收到提交或回滚指令。
- 解决方案:设置超时机制,参与者在等待协调者指令超时时,可以根据自身状态进行处理(例如,若处于准备状态且超时,回滚事务)。同时,协调者在故障恢复或网络恢复后,重新发送指令给未响应的参与者。
性能问题
- 问题:两阶段提交涉及多次网络交互,性能开销较大。
- 解决方案:可以考虑优化网络配置,减少网络延迟。在应用层面,尽量减少分布式事务的使用,能在单个数据库内完成的事务优先在单个数据库内处理。对于性能要求极高的场景,可以探索更轻量级的分布式事务方案,如TCC(Try - Confirm - Cancel)模式。