分布式系统题目答案(3)

共 2375字,需浏览 5分钟

 ·

2021-06-02 09:44

整理下分布式系统问题的答案(1)

分布式系统题目答案(2)


8、MySQL 如何实现 XA 规范?

说 XA 规范之前,需要先说明一下 MySQL 及 InnoDB 引擎中涉及到的日志:

  • 重做日志(redo log),数据真正更改前,会先把相关操作写入 redo 日志,遇到意外情况,待系统恢复后,可以根据日志继续完成记录中的更改操作。

  • 回滚日志(undo log),记录事务开始前数据的状态,更改在执行一半时发生意外,就可以根据撤消日志恢复到更改之前的状态。

  • 二进制日志(binlog),MySQL sever 层维护的一种二进制日志,记录了所有的 DDL 和 DML 语句,主要用来复制和恢复。


XA 规范是由 X/Open 组织提出的分布式事务规范,主要定义了事务协调者(Transaction Manager)和资源管理器(Resource Manager)之间的接口。
XA 事务由两阶段提交实现:

  • Prepare 阶段,Transaction Manager 向 Resource Manager 发送prepare 指令,Resource Manager 收到指令执行操作,返回是否可以提交。

  • Commit 阶段,Transaction Manager 收到 Resource Manager 返回结果,有不可提交或超时的情况,向 Resource Manager 发出回滚指令;若都可以提交,则发出提交指令。


MySQL 单机 XA 的实现,binlog 作为协调者,在事务提交时,则需要将提交信息写入二进制日志。


分布式的 XA 的实现,通过代理层使用 START/ END / PREPARE / COMMIT 这些指令完成分布式事务。


9、TCC 事务模型的实现

目的是解决复杂业务中,跨表跨库等大颗粒度资源锁定的问题,基于业务层面的事务定义,锁粒度完全由业务自己控制。

TCC 把事务运行过程分成 Try、Confirm/Cancel 两个阶段,每个阶段的逻辑由业务代码控制,避免长事务,获取更高性能。


Try 阶段:调用 Try 接口,尝试执行业务,完成所有业务检查,预留业务资源

Confirm/Cancel阶段:提交或取消,接口幂等、允许失败重试。


TCC 主要把数据库 XA 中的二阶段提交,提升到微服务层面实现,解决了跨服务的业务操作原子性问题。


TCC 的不足主要体现在对微服务的侵入性强,需要对业务系统进行改造,业务逻辑的每个分支都需要实现 try、Confirm、Cancel 三个操作,并且 Confirm、Cancel 必须保证幂等。


实现 TCC 模型的组件:

Seata TCC 模式、Tcc-transaction、ByteTCC、Spring-cloud-rest-tcc 等。


10、分布式锁如何实现

常用三种实现方式:
1、基于数据库的实现,依赖数据库的唯一性来实现资源锁定

-- 建表
CREATE TABLE `t_lock` (
`lock_name` varchar(64NOT NULL DEFAULT '' COMMENT '锁定的方法或者资源',
PRIMARY KEY (`lock_name`)
ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- 尝试加锁
insert into t_lock(lock_name) values ('lock_name');


执行 insert 语句尝试加锁,插入成功代表加锁成功,执行完成,删除记录释放锁。


但基于数据库实现的分布式锁,存在很多问题,如:需要数据库高可用防止单点故障、需要自行解决超时锁释放的问题、处理锁可重入需要修改表结构加上线程唯一标识进行判断、数据库连接资源比较宝贵。所以生产环境一般不使用这种方式。


2、基于 Redis 实现

  • setnx + expire,设置缓存值 + 过期时间,由于两个指令非原子操作,仍然可能存在 setnx 成功 expire 失败的情况导致锁不会释放的情况。

  • Redis 2.8 新增了 SETEX 指令支持 setnx + expire 的原子操作,但如果过期时间设置过短,会导致锁提前释放。所以业务操作不要时间太长;set 的 value 给一个随机数,释放时线程持有值与redis缓存值进行比对,相同才给予释放;记录上下游链路,异常情况进行追踪、人工介入处理。

  • 在 redis 集群环境下,数据同步是异步的,所以会存在加锁数据未同步到其他节点,导致其他线程依然可以加锁成功的情况。为解决这个问题,redis 作者推荐使用 Redlock 算法,Redisson 内置了对 Redlock 的实现。


3、基于 zookeeper 实现

利用 zk 支持临时顺序节点的特性实现分布式锁。

  • 当客户端对某个方法加锁时,在 ZooKeeper 中该方法对应的指定节点目录下,生成一个唯一的临时有序节点。

  • 判断是否获取锁,只需要判断持有的节点是否是有序节点中序号最小的一个。

  • 释放锁时,将这个临时节点删除。

  • 客户端 watch 持有节点的子节点变动,若有变动则激活获取锁的竞争。


实际开发中一般使用 Apache Curator 来快速实现分布式锁。

浏览 19
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报