How to gracefully rollback operations on error?

s
somehow
楼主 (未名空间)

const doWork = async =() =>
{
try {
await 3rdParthService.step1();
await 3rdParthService.step2();
await mysql.insert(table1);
await mysql.insert(table2);
await mysql.insert(table3);
} catch (e) {
......
}
}

try block里面的任何一步都可能出错,那么catch block应该怎么写比较好?
p
pptwo

你先想明白做到一半停电怎么办,然后再做rollback就容易了。

【 在 somehow (一般宁静) 的大作中提到: 】
: const doWork = async =() =>
: {
: try {
: await 3rdParthService.step1();
: await 3rdParthService.step2();
: await mysql.insert(table1);
: await mysql.insert(table2);
: await mysql.insert(table3);
: } catch (e) {
: ......
: ...................

s
somehow

想不明白

【 在 pptwo (pp) 的大作中提到: 】
: 你先想明白做到一半停电怎么办,然后再做rollback就容易了。

T
TeacherWei

我感觉你把party写错了。
你这是Distributed transaction 吧?
而且我也没看到有 Trans 相应的调用啊。
我建议要不就算了。毕竟,most of the time, it works.

f
fantasist

哪些操作需要rollback?如果只是mysql,用transaction就行

s
sanwadie

分布式交易是比较复杂的,没有简单的方法。如果是Java代码,国内的阿里和华为都给出了自己的开源方案,可用性都还不错,性能吗,你知道的,Java就是靠堆机器。如果自己搞定,可以借鉴他们。

目前有两种方法可以借鉴:

1)可以弄个简单的全局 Transaction Manager,说穿了就是联动commit:通过某种机
制,先完成所有数据库的写,然后一起commit,如果有一个失败,就全部rollback。这个方法改动比较大,是传统数据库two phase commit的分布式实现,并且对infra的稳
定性、可靠性、性能要求高,本身性能(单个交易)比较差,全局 TM需要解决spof

2)补偿方式:对前面的两个svc 建立对应的补偿接口,如果本地数据库修改失败,调
用补偿接口进行反向修改。但这个方式显然不是完美的,在业务逻辑上需要仔细考虑,避免补偿失败。优点:改动小,对硬件,尤其是网络要求低,可以堆机器实现很高的吞吐。缺点:单个交易时间很长,业务逻辑和补偿机制兼容。

另外,如果svc是第三方的,无法修改代码来进行实时补偿或使用全局TM,那么需要在
本地记录全部交易,对失败交易进行事后补偿。总之,先保证所有的交易(成功或失败)都有本地记录,就可以进行实时或事后的rollback,达到所谓的最终一致性

再分享一点自己项目里进行分布式交易的经验:
1) 尽量不要用分布式交易
2)尽量松耦合,让业务逻辑可以做到最终一致性,这样就可以实现事后补偿,实际上
这也是常见的情况,国内所有的大厂的大应用(支付宝、淘宝,京东,银联)都是使用这种方式
3)如果允许,且需要高吞吐,尽量使用补偿方式
4)我们只对和钱有关的个别交易做分布式二阶段提交
T
TeacherWei

赞一个。这位一看就知道是干过的!

当初12306辩论,要是有几位有这个见识的,也不会搞得一地鸡毛。

【 在 sanwadie (三娃爹) 的大作中提到: 】
: 分布式交易是比较复杂的,没有简单的方法。如果是Java代码,国内的阿里和华为都给
: 出了自己的开源方案,可用性都还不错,性能吗,你知道的,Java就是靠堆机器。如果
: 自己搞定,可以借鉴他们。
: 目前有两种方法可以借鉴:
: 1)可以弄个简单的全局 Transaction Manager,说穿了就是联动commit:通过某种机
: 制,先完成所有数据库的写,然后一起commit,如果有一个失败,就全部rollback。这
: 个方法改动比较大,是传统数据库two phase commit的分布式实现,并且对infra的稳
: 定性、可靠性、性能要求高,本身性能(单个交易)比较差,全局 TM需要解决spof
: 2)补偿方式:对前面的两个svc 建立对应的补偿接口,如果本地数据库修改失败,调
: 用补偿接口进行反向修改。但这个方式显然不是完美的,在业务逻辑上需要仔细考虑,
: ...................