栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

数据并发批处理的控制

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

数据并发批处理的控制

背景:

我们有一批数据在数据库里,要进行到期处理并推送到mq,处理并推送小于等于当前时间的数据.

需求:

1.我们要求任务处理服务要做到高可靠性,因此需要搞成多机分布式服务,即使一个服务挂了,还有别的服务可以使用可以处理

2.保障各个服务均可以同时拿到数据进行高效处理

3.数据不能重复处理

 

方式一.悲观锁形式:事务+select for update

本文先提供一个没有采用的方式--采用事务加select for update的形式

1.开启事务

2.从task表里selce for update 锁定一批数据

3.处理数据

4.更新这批task

5.提交事务

这么做呢就有个非常严重的问题,---同一时刻只有一个有效服务如果A系统拿到了数据,开始了事务但是没提交,那么B系统同样的条件也会查到同一批还没处理好提交的数据,此时B系统该查询线程就会阻塞等待A提交事务.这么看问题就来了,这里虽然保障了同一时刻只有一个服务可以拿到并处理一批数据,但是也导致了效率特别低,而且后面无论扩展多少服务应用都没啥用。

方式二.预更新+lock_key方式 (无锁,我们目前采用的方式) 

 

 

步骤解释:

0.数据库里增加一个字段lockkey

1.先去数据库拿小于等于当前时间的一批status为1(待发送)的数据

2.根据这批数据的id ids更新这批数据为status=2(发送中),lockKey=一个唯一数(防止两个服务拿到同一批更新的数据,我们用的是redis的一个自增id)

3.根据ids和locaKey查询出本批次哪些数据被本轮处理函数更新了(这就是好处,如果我们没用加lock_key,那么第二个系统更新的数据条数不等于拿到的数据数据条数只能回滚从新拿,而我们这里加了lockkey之后更新了多少就代表本批次有效数据是多少,我们只处理有效数据即可,也不用回滚)

4.把这部分数据发到MQ上

5.异常捕捉

如果次数大于5,将数据置为status=4,记录操作日志(基本不会出现,一般只有1,mq连不上,2,数据有问题)

如果我们成功发送数据到MQ,将数据库该条数据状态置为3(成功发送)

如果过程中出现异常,redis里记录该key的失败次数,如果次数小于5,将数据重新置为status=1,下次查询的时候可以重新拿到。

 方式三.redis zset 双写服务--强烈推荐

 

 

1.向mysql写任务的时候同步的向redis zset里写一份,并设置score为自己的搜索条件,比如我这里是发送时间

2.所有的服务消费数据直接从redis zet直接消费,获取小于等于当前时间的一个批次数据(比如100条).

3.利用从redis拿的数据去mysql里拿数据

这种方式是我觉得最好的方案了,完全保障了每个服务每次处理mysql的数据都是互不相同的数据,完全避免了竞争问题.

但是我们目前没有用这种方案,原因是...目前我们redis内存只申请到一个比较小的内存,而zset采用的跳跃表结构虽然保障了数据查询非常快速,但是也非常占用内存,预估了一下按照我们的数据量起码要存储300万数据,用到的内存量是3~4G之间,好家伙直接把我们所有内存都用了,其他服务还用个屁...而且这玩意为了保障数据安全,不进行数据淘汰起码还要留个1G空闲安全空间....那肯定就用不了了. 

 

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/750661.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号