我们的业务是:用户向我们平台下订单时,需要在redis中更新用户余额,我们是中间平台,上游处理用户的订单返回通知我们,这时我们根据成败来更新mysql余额和redis。 问题来了~~,在高并发下,订单总额与用户的余额有很大出入,原因是在频繁更新redis,存在前后不同步的现象! 请教大神们,对于这种问题怎么处理比较好啊?
client.getAsync(‘freeze’ + orderObj[‘customer_id’]).then(result => { //1.从redis中读取值 if (result) { async.parallel({ updateRedisfreeze: function(done) { //2.更新reids client.incrbyfloatAsync(‘freeze’ + orderObj[‘customer_id’], ‘-’ + orderObj[‘order_fee’]) }, updateCustomer: function(done) { //3.更新数据库记录 customer.update({ customer_feezed_balance: freeze }, { where: { id: orderObj[‘customer_id’] } }) }, createOrder: function(done) { //4.数据库创建新记录 order.create(orderObj) }, deleteOrder: function(done) { client.delAsync(orderNo); /5./删除redis一条记录 } }, function(err, result) { console.log(‘one:’, result.updateRedisfreeze); console.log(‘two:’, result.updateCustomer); console.log(‘three:’, result.createOrder); console.log(‘four:’, result.deleteOrder); }) 在高并发下,怎么做到以上几步类似于数据库事务的操作,保证每次的执行具有原子性?
其实对于业务来说,钱最重要,我们的解决方案是只要牵涉钱的,都去加排他锁,保证更新金额不出现脏读.
一律排队处理,处理完一个再去处理下一个
@qimenxiaozi ,你说的排它锁是redis你们的watch->multi?
@chloe ,用消息队列吧!?
不做update操作不行吗?只做insert就可以了啊,保存一份交易记录。 余额读取的可不是有redis?
@jiangliqin 用消息队列的话可以用rabbitmq
@bing6 ,你说得对,后来给成了你说的了
@chloe ,其实不一定用消息队列,只要是能控制并发就行,比如async.queue,bagpipe等
保持处理速度均匀,多高的并发都不怕
@jiangliqin 看着办,适合项目就行
@yakczh ,这处理速度真不是自己能控制的,尤其是有上下游的情况
@jiangliqin 不明白为什么要用async.parallel?
如果相关操作存在先后关系,parallel并不确定谁先执行,谁后执行,几个操作执行顺序是不确定的。
@coordcn ,呵呵,上面操作其实是有问题,后来改了。至于你说的parallel是不关联的并行这是对的,我上面也不存在先后关系。没讲明白,让你误解了。。。
问下楼主,这问题后来怎么处理的?
@imhered 主要靠redis,后来再批量插进数据库,避免频繁操作数据库
@jiangliqin 你的问题不是redis里的数据脏读了么? 怎么解决脏读的?
@imhered 我上面描述的问题很复杂,对于出现脏读的部分,我们用redis-lock解决的啊
@jiangliqin redis-lock? 是这个吗? https://www.npmjs.com/package/node-redis-lock
@imhered yes!