一、问题
站点收到并发请求需要串行处理,或者并行执行的业务某个环节需要串行处理。
二、分析
1,只能针对操作同一条数据的业务处理串行处理,整体必须并行处理。
2,因为执行速度很快,发生并发时,最好每一条都被执行,而不是返回“请稍后重试”,需要等待和重试。
3,支持分布式部署,同时有多个节点。
4,如果整体请求量特别大且处理需要时间,那么理应采用异步和队列。用队列消费的时候,应该也只是调取业务方法,队列本身不应该关心业务上面的事情。且队列消费应该也是并发的。
三、解决方案
方案一:数据库多版本并发控制(mvcc)
本质是利用数据库update串行执行机制。数据行加版本,假如有A、B两个事务针对同一条数据处理。
事务B修改版本为1的数据,发现修改了0行,知道同时有别人修改过数据,回滚。有的数据库有隐藏字段用于mvcc,不用自己维护一个版本字段。
缺点:
1,要求业务处理对数据有修改,否则如果业务处理只查询不需要修改数据就没法用了,不能为了修改而增加修改逻辑。不过如果只是查询而没有数据变更,一般也不需要串行执行。
2,这种方式依赖于事务,如果程序执行过程没有事务,最后一步发现版本变更了,,前面执行的逻辑无法回滚。
不推荐
方案二:依赖数据库锁(悲观锁)
当一个事务开始执行,读取数据的时候就加锁,让其他操作等待,实现整体业务操作是串行化的,一个业务操作开始~结束,另一个业务操作才开始。
通过锁解决方案一中要求业务处理支持事务的问题。锁需要设置超时时间,防止死锁
缺点:需要为行数据进行锁定。频繁的加锁、解锁,影响效率。
不推荐。
方案三:分布式锁
最好不在数据库上操作实现串行化,增大数据库压力,在程序执行过程中实现串行。比如可以通过redis分布式锁实现,具体请自行搜索,哈哈。不一定要用redis,任何方式实现了分布式锁都可以,哪怕自己弄个数据库来实现都行(redis也是数据库的一种)。
当然如果你是单机的,可以在程序中加线程锁控制,每种语言都有。但是不推荐,如果以后升级集群部署了,估计会忘记改。