实战:工作中对并发问题的处理
问题发生在快递分拣的流程中,我尽可能将业务背景简化,让大家只关注并发问题本身。
(资料图)
分拣业务针对每个快递包裹都会生成一个任务,我们称它为 task。task 中有两个字段需要关注,一个是分拣中发生的异常(exp_type),另一个是分拣任务的状态(status)。另外,需要关注分拣状态上报接口,通过它来记录分拣过程中的异常和状态变更。
一般情况下,分拣机在分拣异常发生时会及时调用接口上报,在分拣完成时调用接口来标记为完成状态,两次接口调用的时间间隔较长,不会发生并发问题。
但是有一种特殊的分拣机,它不会在异常发生时及时上报,而是在分拣完成时将分拣过程中发生的异常和分拣结果一起上报,那么此时分拣状态上报接口在同一时间内就会有两次调用,这时便发生了预期外的并发问题。
我们先看下分拣状态上报接口的执行流程:
先查询到该分拣任务 task,默认情况下 exp_type 和 status 均为默认值0分拣异常修改 task 中的 exp_type,分拣完成修改 status 字段信息修改完成将 task 写入并发问题发生的图示如下:
数据库初始值为1, 0, 0
,分拣异常和分拣完成几乎同时上报,它们都读取到该值。分拣异常动作将 exp_type 修改为9,写入数据库,此时数据库值为1, 9, 0
;分拣完成动作将 status 修改为1,写入数据库,使得数据库最终值为1, 0, 1
,它将异常字段的值覆盖掉了。正常情况下,最终值应该为1, 9, 1
,分拣完成动作应该读取到分拣异常完成后的值1, 9, 0
后再进行修改才对。
发生这个问题的原因很容易就能发现:两个事务同时执行读取-修改-写入序列,其中一个写操作在没有合并另一个写操作变更的情况下,直接覆盖了另一个写操作的结果,所以导致了数据的丢失。
这种问题是比较典型的丢失更新问题,可以通过对数据库读操作加锁或者改变数据库的隔离级别为可串行化使事务串行执行的方式进行避免。下面我会将大家在讨论避免丢失更新问题时提出的方案进行介绍,并尽可能的用代码来表现它们。
2.1 数据库读操作加锁和可串行化隔离级别我们可以考虑:如果对每条Task数据修改的事务都是在当前事务完成之后才允许后续事务进行修改,使事务串行执行,那么我们就能够避免这种情况。比较直接的实现是通过显式加锁来实现,如下
select exp_type, statusfrom taskwhere id = 1for update;
先查询该行数据的事务会获取到该行数据的排他锁,后续针对该数据的所有读写请求都会被阻塞,直到先前事务执行完将锁释放。
这样通过加锁的方式实现了事务的串行执行。但是,在为SQL添加加锁语句时,需要确定是不是为该行数据加锁而不是锁住了整个表,如果是后者,那么可能会造成系统性能严重下降,而且还需要关注有哪些业务场景使用到了该SQL,是否存在长时间执行的只读事务使用,如果存在的话可能会出现因加锁导致延迟和系统性能下降,所以需要谨慎的评估。
此外,可串行化的数据库隔离级别也能保证事务的串行执行,不过它针对的是所有事务。一般情况下为了保证性能,我们不会采用这种方案(默认使用MySQL可重复读隔离级别)。
2.2 针对业务只修改必要字段MySQL的InnoDB引擎实现可串行化隔离级别采用的是2PL机制:在第一阶段事务执行时获取锁,第二阶段事务执行完成释放锁。
如果异常状态请求仅修改 exp_type 字段,分拣完成仅修改 status 字段的话,那么我们可以梳理一下业务逻辑,仅将必要修改的字段写入数据库,这样就不会发生丢失更新的异常,如下代码所示:
// 处理异常状态请求,封装修改数据的对象Task task = new Task();tast.setId(id);task.setExpType(expType);// 更改数据taskService.updateById(task);
在执行修改数据前,创建一个新的修改对象,并只为其必要修改字段赋值。但是还需要考虑的是:如果这个业务流程处理已经很复杂了,很可能不清楚该为哪些字段赋值而导致再发生新的异常,所以采用这种方法需要对业务足够熟悉,并且在修改完后进行充分的测试。
2.3 分布式锁分布式锁的方法与方法一类似,都是通过加锁的方式来保证同时只有一个事务执行,区别是方法一的锁加在了数据库层,而分布式锁是借助Redis来实现。
这种实现方式的好处是锁的粒度小,发生锁争抢仅限于单个包裹,无需像数据库加锁一样去考虑锁的粒度和对相关业务的影响。伪代码如下所示:
// 分布式锁KEYString distributedKey = String.format(DISTRIBUTED_KEY_PREFIX, packageNo);try { // 分布式锁阻塞同一包裹号的修改 lock(distributedKey); // 处理业务逻辑 handler();} finally { // 执行完解锁 redissonDistributedLocker.unlock(distributedKey);}
需要注意,lock()
加锁方法要保证加锁失败或发生其他异常情况不影响业务逻辑的执行,并设定好锁持有时间和等待锁的阻塞时间,此外解锁方法务必添加到finally代码块中保证锁的释放。
CAS是乐观的解决方案,它一般通过在数据库中增加时间戳列来记录上次数据更改的时间,当新的事务执行时,需要比对读取时该行数据的时间戳和数据库中保存的时间戳是否一致,以此来判断事务执行期间是否有其他事务修改过该行数据,只有在没有发生改变的情况下才允许更新,否则需要重试这个事务。样例SQL如下所示:
update taskset exp_type = #{expType}, status = #{status}, ts = #{currentTs}where id = #{id} and ts = #{readTs}
它的原理不难理解,但是实现起来可能会存在困难,因为需要考虑在执行失败后该如何重试,重试的方式和重试的次数需要根据业务去判断。
巨人的肩膀《数据密集型应用系统设计》第七章 事务作者:京东物流 王奕龙
来源:京东云开发者社区 自猿其说Tech 转载请注明出处
标签:
推荐
- 实战:工作中对并发问题的处理
- 老人骑车带娃闯电动闸门被撞后索赔,法院判了
- 古岘镇拆除户外广告,开展“透窗”整治行动
- 珍宝岛:融资净偿还300.66万元,融资余额1.11亿元(08-14)
- 煮粥用什么淀粉勾芡好喝
- 8999元起!小米MIX Fold 3折叠屏手机正式发布:潜望长焦镜头
- 可游可赏可感知 领略“乐陵制造”魅力 乐陵市推出特色“工业旅游”线路
- 市场监管总局:上半年食品安全监督抽检不合格率2.40%
- 中国平安前7月保费收入5213.46亿元 同比增长7.2%
- 中方车队在巴基斯坦遇袭 外交部:已要求巴方严惩凶手
- 股东户数最新变动:利德曼(300289)股东户数2.16万户,较上期减少0.14%
- 2023年郑州张信哲演唱会官网订票
- “马特达蒙”上演直男癌:《最后的决斗》——移动云盘电影资源
- 非金属建材周报(23年第32周):政策有望继续发力 关注淡旺季切换基本面改善
- 展示银领风采 余晖皆放异彩——金阳街道碧海社区老年学校参加第二届生命文化艺术节
- ST开元:子公司与许继换电签署项目合作协议
- 2023挑战者中国·贺兰山汽车越野文化嘉年华活动 将于10月3日开幕
- 大冰箱4249元 家庭厨房必备
- 只有你韩国百度云 只有你韩版电影百度云
- 内蒙古四子王旗举办首届羊杂美食节
- 南北向大宗交易机制启动|予菲视点
- 每日晨报
- 湘村“向云端”丨乡间跳动的“积分”带动会同智慧乡村治理
- 火车票为何全程有票 而中途站无票?铁路部门回应来了
- 栖霞龙潭菱角进入丰采期 满塘翠绿菱飘香 水中捞起“金元宝”
- 【第四届中国(甘肃)中医药产业博览会】严把检验关 确保中药材质量安全
- 连云港石油开展新能源夏季安全检查
- 国家金融监管总局要求保险业加快开展防汛救灾理赔
- 国米闪电完成飞翼换将 张康阳成交易推手还击尤文图斯
- 斯基拉:吉达国民和那不勒斯达成协议,泽林斯基转会费为3200万欧
- 逆转新西兰!李凯尔杀神,付豪+2内还行,后卫辣眼,乔帅满头汗
- 重磅!加大吸引外商投资力度,国务院最新发布
- 压缩性骨折治疗方法?(压缩性骨折治疗方法)
- 湖南省邵阳市2023-08-13 19:15发布暴雨黄色预警
- 沪指重回2900点 北向资金半日净流入超60亿
- 「大兴调查研究」省委老干部局:以调查研究推动老干部工作高质量发展
- word段落间距怎么调整 word段落间距
- 产业链争先布局 出口爆发式增长!我国动力电池高质量“续航”
- 杭州一公司给全体员工发放千万奖励网友:慕了别人家的公司 具体是啥状况呢
- 再等99天,四大生肖财运上上签,鸿运当头,小金库满满
- 香港特异功能电影(特异功能电影)
- 北京今天下午西南山区有雨,地质灾害风险仍较高,请注意防范
- 整理父亲遗物时有惊人发现!男子直奔派出所……
- 刀郎归来,江湖已变
- 雷劈屋顶!孩子幸免手机
- 吸血鬼:最广为人知的西方传说恐怖生物
- 张镇麟第一个到场!考察敌情脸色严肃,就等着击溃德国约战加拿大
- 车评头条:水滴石穿 试驾华晨中华H330
- 宁波宁昌电气有限公司(关于宁波宁昌电气有限公司简述)
- MATLAB命令“xpbombs”玩扫雷
- 阿维塔亮相重庆车展,CEO谭本宏宣布推出ADS高阶功能包
- 【白圣女与黑牧师】动画第五集自截屏 表情包
- 陕西大雁塔导游词(优秀4篇)
- 妻子举报医生老公,官方通报
- 原神稻妻有多少个宝箱 原神宝箱
- 绝地追击 《绝地追击》发布“亡命围剿”预告 基本情况讲解
- 女娲和伏羲是谁的孩子(女娲和伏羲生下了谁)
- 生态环境部将加强汛期饮用水水源环境监管切实保障人民群众饮水安全
- 创历史新高,路特斯2023上半年业绩发布
- 如何科学吃瓜“室温超导”?
- 内蒙古移动全力做好强降雨应急通信保障
- 马赫电混DH-i/外形时尚 风神皓瀚将于今晚上市
- 西安市喂子坪村山洪泥石流已造成2人死亡16人失联 抢险救援正在进行
- 上半年全国能源重点项目完成投资额超万亿元
- 8月10日基金净值:招商中证红利ETF最新净值1.5002,涨0.41%
- 师父电影迅雷下载(师父电影完整版下载)
- 每日技巧分享:如何将视频中的文字提取出来?
- 人兽(关于人兽的基本详情介绍)
- 大乐透23092期晒票,一朝习惯,万事易办
- 金龙鱼上半年净利润不足10亿元,同比下滑51.13%
- 2万亿ETF市场迎多项利好!涉及产品创新、市场定价和流动性
- 澳大利亚首度举办“马拉巴尔”军演,美日印澳派舰机参加
- 监外执行和缓刑有什么区别吗
- 计算机网络功能有哪些_计算机网络功能有哪些
- 一拖股份:公司不生产轴承产品,所需轴承均为外购
- 铠甲勇士捕将变身器什么时候出 公测上线时间预告
- 商业化拐点临近!旧金山允许无人驾驶出租车不受限行驶
- 金橙子股东户数增加1.77%,户均持股12.78万元
- 官媒指四大一线城市楼市调控方案已上报中央,中国救市料推“这两招”
- 暑假出行别辜负了安全提醒
- 中国信通院:6月国内手机市场出货量2214.9万部,5G手机占比78.2%
- 古文宋有富人天雨墙坏其子曰(宋有富人天雨墙坏翻译)
- 广州南沙区社保个人缴费标准2023是多少 广州南沙区社保个人和企业分别交多少钱
- 凌玮科技:公司官网已作更新,现可正常浏览在线视频
- 医药领域掀起反腐风暴 各地自查自纠公布举报电话
- 绝地求生新作黑色预算预计2025年发售,玩绝地求生推荐什么加速器?
- 泰拉瑞亚快速治疗状态介绍
- 活动预告!盛兴幼儿园夏日主题活动免费报名啦!
- 奥泰生物:8月10日融资买入109.09万元,融资融券余额7483.37万元
- 《博德之门3》日本玩家不满:没有日语支持
- 前7月铁路完成固定资产投资3713亿元
- 荆门检察全体人员深入学习贯彻全省检察长研讨班精神
- 18岁女生称醉酒后遭网约车司机性侵:鉴定结果未出,检方作出不予批捕决定
- 飞鹤发半年盈利预警:净利润或同比跌超36%
- 巴加快054系列服役,强化自身海军实力,对抗印度海军有优势
- 8月10日基金净值:南方潜力新蓝筹混合A最新净值1.8658,涨0.64%
- 原神清籁岛旧宝怎么解密(清籁岛旧宝解密攻略)
- 这样“垃圾”的世界第一,不要也罢
- 一方不愿意离婚怎么判
- 南威软件:全资子公司建设公司北京总部项目