下班地铁上无聊引发的问题思考特此记录,有不严谨的地方请指正
分布式事务
分布式下最大的难点就是跨库的分布式事务问题,目前主要有两套解决方案
1 事务补偿性
2 最终一致性
第一种事务补偿性方案更注重原子性,既是要么同时成功,要么同时失败;其中涉及到子事务和主事务,主事务用来维护每个库的子事务,大概原理既是其中一个子事务失败,主事务要进行补偿(撤销或者追加)操作,达到数据原子性要求,可以注意到维护多个子事务这样的成本很高
第二种最终一致性的事务方案更注重最终数据的一致性,既是理想化的假设数据的新增更新删除操作是万无一失百分百一定准确执行到数据库,实现原理基本都是借助Mq消息队列使操作经过队列持久化,由订阅队列的消费者执行mq发过来的操作,借助mq的持久化功能,如果操作失败,可不断尝试或者由人工干预直到成功达到数据最终一致性,这里需要注意如果不断尝试依旧失败为了避免队列阻塞可熔断放弃尝试把操作发送到其他地方持久化。后续再由人工操作执行失败的操作。
另一个这类借助mq解决最终一致性还要注意事务的先后顺序问题。如果是有先后顺序的场景,例如下单新增订单,扣款新增流水,这种可先进行扣款操作和减库存(并发下减库稍后讨论),然后新增流水和创建订单到队列,只要塞入队列既认为操作数据合法返回ok,实际操作由队列慢慢消化到数据库,因为队列持久化保证了数据最终一致又保证了用户体验
高并发问题
高并发最直观场景莫过于秒杀业务
秒杀涉及到最重要的库存加减
如果并发很大如何保证库存有序的减呢
第一种方式既是就要借助数据库特性控制并发比如sqlserver有TimeStamp二进制时间戳,这种数据类型与时间日期都无关,他只是表明数据库数据修改发生的相对顺序,在TimeStamp所在行任意列数据发生修改时sqlserver会自动在当前TimeStamp基础上增加一个递增量,如果其他用户进行更新操作,数据库会比对此TimeStamp数据是否一致,一致即可更新,否则不允许,但是其他数据库比如Mysql没有TimeStamp的机制支持,此时也可换其他思路解决同样问题,既是新增一列任意数据类型例如int类型的A列,再写一个触发器例如更新操作时拿此时需要更新的A列与数据库A列比对,如果一致允许更新操作,并在此时A列基础上再 1,如果不一致拒绝更新
第二种方式既是:借助队列特性(管道one by one) 或者redis特性(单线程)对库存数进行操(单线程异步IO一般情况下由于避免了线程上下文切换会获得比多线程更好的性能)作。这里需要注意的是因为减库存是个要控制并发的问题,所以我们借助版号TimeStamp;队列或者单线程原理的redis来控制并发,这样就不可避免的变为同步产生排队现象,为了缩短排队时间,可把库存总数切割成多份进行“消费”