service-分布式锁的实现
分布式锁的背景
用途:分布式环境下保证数据一致性,常见场景秒杀抢单。
常见的锁方案如下:
- 基于数据库实现分布式锁
- 基于缓存,实现分布式锁,如redis
- 基于Zookeeper实现分布式锁
实现方式(三种)
mysql实现
基于MySQL的行锁(悲观锁)实现,查询语句加上for update
;
1 | select * from order_table where id = 'xxx' for update |
优点:理解起来简单,不需要维护额外的第三方中间件(比如Redis,Zk)。
缺点:虽然容易理解但是实现起来较为繁琐,需要自己考虑锁超时,加事务等等。性能局限于数据库,一般对比缓存来说性能较低。对于高并发的场景并不是很适合。
redis实现分布式锁
基于setnx
实现
1 | $lock = $redis->setnx($redis_key . $this->id, time()); |
这个实现存在两个步骤,非原子性,很是问题。
基于nx和ex实现,对于单点redis是最完美的实现方式了,但是无法避免redis机器挂掉特殊情况。
1 | $lock = $this->redis_cli->set($key, "value", ['nx', 'ex' => 100]); |
解决单点问题可使用redis的redlock锁,可详看这两篇(多看几遍):
http://zhangtielei.com/posts/blog-redlock-reasoning.html ,
http://zhangtielei.com/posts/blog-redlock-reasoning-part2.html
优点:对于Redis实现简单,性能对比ZK和Mysql较好。如果不需要特别复杂的要求,那么自己就可以利用setNx进行实现,如果自己需要复杂的需求的话那么可以利用或者借鉴Redission。对于一些要求比较严格的场景来说的话可以使用RedLock。
缺点:需要维护Redis集群,如果要实现RedLock那么需要维护更多的集群。
更新日志
20191225更新,圣诞节快乐,@all