数据库高并发之事务分析

预备:
为下文能表述清晰,预定义如下:
1、对一个key-value对象[对关系数据库则为pk-else],key称为变量,value称为值。
2、对下文提到的变量更新,主要指变量的变更按:insert[首次]+update[无数次]+delete[可能的] 的方式进行,对于变量仅insert或仅insert+delete的变更方式,虽平台也要覆盖,但不属于分析范围。
3、对于变量更新中的update操作,存在两种更新类型
覆盖型:指更新属性中全为覆盖类[=]更新,或核心属性为覆盖类,非核心有增减类但即便因故[不完全回滚考虑]丢失个别次更新也无关大局的[如非精确估量计数等]。
增减型:指更新属性中全为增减类[+=或-=]更新的,或核心属性为增减类,非核心有覆盖类但即便因故[不完全回滚考虑]丢失个别次更新也无关大局的[如更新时间等]。
目前业务层面上多为增减型更新。

分析一:计算节点和更新[控制节点+db]分离,且间隔时长可能较长[CSN批量处理或CN宕掉等]。
影响1:CSN接到计算任务后,需缓存计算过程中得到的变量最新值,至下个计算任务时清空缓存。
影响2:如某变量的计算对其值状态存在敏感性[即计算时读值和更新时当前值已变化可能会导致原计算结果失效的],暂称为状态敏感型变量[以下无特别说明仅按该类型变量分析],需在变量更新前对当前值状态做原计算结果有效性校验。
状态敏感型变量大致分类:
读值匹配型:依赖于读值的变量计算结果在更新时要求当前值和读时值强相关。通常要求当前值等于读值。 
区间匹配型:依赖于读值的变量计算结果在更新时要求当前值可偏离读时值但必须介于一定偏离区间的。通常要求计算结果坐落的业务区间和当前值所处业务区间仍匹配。如:阶梯型累计量、封顶型代付等。

分析二:多数据节点,且每个节点自管理事务[BDS服务],无全局者或协调者。一笔交易如跨多节点,可能产生数据非一致性。
通常采用以下两种模式:
全局者:在涉及节点的语句都执行成功后[如任一执行失败[原计算结果有效性校验失败+语句异常+节点宕掉],调用已执行节点的事务回滚],触发这些节点的事务提交,仅在非第一个提交失败[节点宕掉]时,产生数据非一致性。
自管理:各节点分别执行语句并根据执行结果进行事务提交或回滚,执行失败[原计算结果有效性校验失败+语句异常+节点宕掉]节点,产生数据非一致性。
第三代采用了自管理模式,因此数据非一致性的概率较现网[全局者]大增。需要进行相应的修复处理。

分析三:数据非一致性的修复处理方案。
跨节点交易通常采用以下两种方案:
反向回滚:即事务补偿机制。对每个正向操作,提供相应的完全反向操作。当出现节点事务失败时,调用已成功节点的反向操作,实现逻辑的完全回滚。这种方案问题在于在正向和反向操作间隙,如数据状态被他人修改,可能已无法完成完全反向操作[除非已成功操作上也设定业务层面的锁,虽已提交但对他人来说仍不可用或谨用]。因此完全反向操作对变量的状态敏感性和更新方式都有严苛要求,分析如下:
1、状态敏感型变量,在不采用业务锁模式情况下,基本不考虑提供反向操作。[否则会出现类似以下场景:设100为阶梯临界值,100之前费率为x,100之后费率为y。A交易子事务A1以96+2提交[A1费用=2x],后B交易事务98+3提交[B费用=2x+y],如此后A交易因另一子事务A2异常需回滚A1[101-2=99],后续A交易重做并成功,即A1以99+2提交[A1费用=x+y],虽前后累计值101相同,但费用不同且后者是错误的]
2、非状态敏感型变量,要考虑更新方式:
对覆盖型,需保留更新前旧值[历史表等方式],才可能提供反向操作。
对增减型,可以考虑提供反向操作。
正向续做:对于之前因原计算结果有效性校验失败导致的执行失败,即便续做也无济于事。为规避该情况,考虑在业务层面上设计一种预备[完成原计算结果有效性校验]+提交[完成语句执行+事务提交]的两阶段提交方式。
第三代采用了正向续做方案,因此需要业务层面上实现两阶段提交。

分析四:正向续做的两阶段提交设计
一、对应跨节点交易,框架固化为以下几步:
0、计算
1、保存计算结果到会话[会话状态:已保存]
2、加锁[即预备阶段,实现:幂等设计+原计算结果有效性校验+预锁[固化自身状态有效性+通知他人状态预变更]]
3、更新会话状态[会话状态:已加锁]
4、更新[即提交阶段,实现:幂等设计+更新语句执行+删预锁]
5、更新会话状态[会话状态:已更新]
以上除0外均存在事务。
0或1如断点,重做时判断无会话记录从0做起,最终以1成功执行时保存的计算结果做后续处理。
2或3如断点,重做时判断会话状态为已创建则从2做起[因此要求2幂等]
4或5如断点,重做时判断会话状态为已加锁则从4做起[因此要求4幂等]
重做时判断会话状态为已更新则跳过以上所有步骤进行后续处理。
二、对应单节点交易,框架仅为以下几步:
0、计算
1、更新[实现:原计算结果有效性校验+更新语句执行+保存计算结果到会话[会话状态:已更新]]

分析五:跨节点的[加锁]和[更新]步骤设计
一、非状态敏感型变量
该类变量计算结果恒有效,则根据上面分析,[加锁]=幂等设计,[更新]=幂等设计+更新语句执行。
1、如更新语句本身是幂等的[insert可通过pk防止重复,update为覆盖型更新,delete重复执行效果不变],则[加锁]=null,[更新]=更新语句执行。
2、如更新语句本身非幂等的[update为增减型更新],为防止重复执行,考虑也在加锁环节通过锁[暂称为幂等锁]的方式产生痕迹,以此判断是否已执行过。则[加锁]=有自身幂等锁?返回:加幂等锁,[更新]=有自身幂等锁?更新语句执行+删幂等锁:返回。
但这种场景优先考虑将更新语句调整为幂等。
二、状态敏感型变量
1、读值匹配型
更新时通常要求当前值等于读时值,当前值不存在有效的偏离空间。故在加锁阶段采用独占锁方式,一旦计算结果有效性校验通过则独占,他人校验则立即失败。又幂等设计可依据独占锁产生的痕迹实现[见上文],则[加锁]=有自身独占锁?返回:原计算结果有效性校验+独占锁,[更新]=有自身独占锁?更新语句执行+删独占锁:返回。
2、区间匹配型
更新时通常对当前值要求比较宽容,其即便偏离读时值但不超过计算结果坐落的区间则仍有效。故采用预占锁方式,一旦计算结果有效性校验通过则预占部分区间剩余量,他人校验需参考该预占情况。又幂等设计可依据预占锁产生的痕迹实现[见上文],则[加锁]=有自身预占锁?返回:原计算结果有效性校验+预占锁,[更新]=有自身预占锁?更新语句执行+删独占锁:返回。

分析六:锁的实现
一、锁的基本实现可以是两种模式
1、锁记录方式[key+value+lockid]。加锁:新增锁记录;删锁:删除锁记录
2、锁标识方式[key+lockid]。加锁:更新lockid为self;删除:更新lockid为null。
二、锁的分类
分析五提到三种锁类型:幂等锁、独占锁、预占锁。
幂等锁:与他人无关,仅自身幂等识别用。则同一变量同一时刻可存在多把幂等锁。
独占锁:与他人强相关,非此即彼。则同一变量同一时刻仅存在一把独占锁。
预占锁:与他人弱相关,一定空间内可共存。则同一变量同一时刻可存在多把预占锁。
根据以上,则如下实现较合理:
锁记录方式:幂等锁、预占锁
锁标识方式:独占锁
独占锁亦可采用锁记录方式,但幂等锁和预占锁无法采用锁标识方式。

分析七:原计算结果有效性校验的实现
一、幂等锁
无需校验。
二、独占锁
1、看是否已有非自身锁,有即校验失败。
2、如没有,看当前值是否符合要求,不符合即校验失败。
3、看当前值之前,需冻结当前值,直至加锁环节结束。
三、预占锁
1、看当前值+所有非自身锁的预占值+自身将要预占值,如已不同于原计算结果坐落的区间,即校验失败。
2、看当前值+所有非自身锁的预占值之前,需冻结以上,直至加锁环节结束。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

鱼松鼠

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值