Redis如何处理高并发问题?
众所周知,Redis和RabbtiMQ是高并发利器,但是如何用Redis处理高并发问题呢?我们一步步来看。
先看一个秒杀Demo,设置一个库存的字段,每次执行减少1个库存。
如果是单线程访问,我们可以把热点数据设置一个key字段,保存到Redis中,如果value(库存)>0,value-1,然后再把库存数量重新设置到Redis当中。如果多线程并发访问,就会出现脏数据,也就是超卖问题。这个时候我们可以采用加同步锁解决,线程每次访问都获取锁,执行完代码别的线程才能重新获取锁
这时候基本解决单机部署的并发问题。
所以如果是单机部署项目,可以考虑直接用Redis缓存+锁机制处理!
那如果是分布式集群部署呢? 我们继续看。
synchronized在分布式集群中失效,这时我们应该想到用Redis自带的setnx key value解决同步锁失效问题。
还是设置一个锁字段名,利用setnx命令设置到Redis 中,并设置if判断,如果已存在返回flase,不存在返回true,每访问一次,value-1,再把数量重新设置回去,最后释放锁。
但是,如果如果碰见异常问题,可能执行不到释放锁,这会造成其他线程一直无法拿到锁,这时我们可以用try catch finally解决问题(finally保证重点代码块一定能执行)。但是还有问题,如果业务代码执行比较长,或者网络延迟抖动,其他线程只能等待锁释放,这时我们可以给key设置过期时间,为了保证原子性操作我们这样写。
看上去很完美,但是还有一些极端情况,比如设置过期时间10s,第一个线程执行逻辑用了10s,来不及释放锁,锁就过期了,第二个线程一看没有锁,直接对加锁,10s又没执行完,这时就会出现锁失效情况。这时我们可以考虑验证一下客户端的id,设置一个唯一的id,保证加锁和释放锁是同一个客户端。
到这,基本解决了分布式场景下并发问题。
但是如果碰见更极端的情况(finally代码块中出现问题),可能还会导致锁失效,这时我们可以考虑锁续命来解决问题。
同样,用Redis的儿子Redisson来解决分布式锁的问题,更简单。
这里就不详细解释Redisson了,给大家看下Redisson的原理图。