并发更新,除了悲观锁/乐观锁,还有什么典型方案?

共 937字,需浏览 2分钟

 ·

2021-08-20 15:10

如果是多线程更新同一个对象或者数据结构,显而易见,可以加各种线程锁来实现。

日常工作中,更常见的是多台应用服务器(多个进程)同时更新DB,或者Redis,这种情况下,解决的办法都有哪些呢?


我们知道,如果是DB,可以使用DB自带的悲观锁(select ... for update),或者乐观锁(也就是给数据加版本号,CAS机制)。


但对于Redis,第1,没有悲观锁机制;第2,乐观锁机制,在大并发量场景下并不适用。那如果要并发更新,还有什么好的办法?


  1. 分布式锁 -  不靠谱

分布式锁本身如果要高性能,很多也是用Redis实现的。用Redis实现的分布式锁解决Redis的并发更新问题,没解决好并发更新,又引入了“分布式锁”这个大坑。

  为什么说“分布式锁”是个大坑,后续再来讲。


  2. 串行化

     锁会造成数据的串行化访问,相当于是在DB/KV内部对请求进行排队。与其如此,不如在应用层面做排队,可靠性更强,性能也有保证。具体分为2种方式:

(1)异步写(异步并发更新)

如果并发更新的结果,不需要同步返回,那可以把所有的并发请求都写入到一个消息中间件(比如Kafka),然后单线程消费,避免并发问题。这个,在大数据场景中尤为实用,比如Spark/Flink,要多个Task并发更新Mysql/Redis。


(2)同步写(同步并发更新)

这就需要在应用服务器的内存中有一个队列,处理请求的线程把请求放入队列之后,不给客户端端返回,而是等待队列处理结果。

同样,单线程去取这个队列,然后更新DB/Redis,把结果放入另外一个Response队列,通知处理线程去取,返回给客户端。

这个办法有个前提:路由要做一致性Hash,保证同一个用户的请求,落入到同1台应用服务器,如果落到2台上面,虽然1台内部有队列是串行的,2台之间还是会并发更新DB/Redis,造成数据错乱。


浏览 90
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报