女朋友也能看懂的Zookeeper分布式锁原理

介绍

许多场景中,数据一致性是一个比较重要的话题,在单机环境中,我们可以通过Java提供的并发API来解决;而在分布式环境(会遇到网络故障、消息重复、消息丢失等各种问题)下要复杂得多,比如电商的库存扣减,秒杀活动,集群定时任务执行等需要进程互斥的场景。本文主要探讨如何利用Zookeeper来实现分布式锁,对比了一些其他方案分布式锁的优缺点。至于使用何种,要因自己的业务场景去决定,没有绝对的方案。

分布式锁是什么?

分布式锁是控制分布式系统之间同步访问共享资源的一种方式。

实现分布式锁注意点:

锁的可重入性(递归调用不应该被阻塞、避免死锁)

锁的超时(避免死锁、死循环等意外情况)

锁的阻塞(保证原子性等)

锁的特性支持(阻塞锁、可重入锁、公平锁、联锁、信号量、读写锁)

使用分布式锁注意点:

分布式锁的开销(分布式锁一般能不用就不用,有些场景可以用乐观锁代替)

加锁的粒度(控制加锁的粒度,可以优化系统的性能)

加锁的方式

常见的实现分布式锁方案


数据库

基于数据库表唯一索引

最简单的方式就是直接创建一张锁表,当我们要锁住某个方法或资源时,我们就在该表中增加一条记录,想要释放锁的时候就删除这条记录。给某字段添加唯一性约束,如果有多个请求同时提交到数据库的话,数据库会保证只有一个操作可以成功,那么我们就可以认为操作成功的那个线程获得了该方法的锁,可以执行方法体内容。

但会引入数据库单点、无失效时间、不阻塞、不可重入等问题。

基于数据库排他锁

如果使用的是MySql的InnoDB引擎,在查询语句后面增加for update,数据库会在查询过程中(须通过唯一索引查询)给数据库表增加排他锁,我们可以认为获得排它锁的线程即可获得分布式锁,通过 connection.commit() 操作来释放锁。

会引入数据库单点、不可重入、无法保证一定使用行锁、排他锁,所以有可能长时间不提交导致占用数据库连接等问题。

优缺点

优点:

直接借助数据库,容易理解。

缺点

会引入更多的问题,使整个方案变得越来越复杂

操作数据库需要一定的开销,有一定的性能问题

使用数据库的行级锁并不一定靠谱,尤其是当我们的锁表并不大的时候

缓存

相比较于基于数据库实现分布式锁的方案来说,基于缓存来实现在性能方面会表现的更好一点,目前有很多成熟的缓存产品,包括Redis、memcached、tair等。

基于 redis 的 setnx()、expire() 方法做分布式锁

setnx 的含义就是 SET if Not Exists,其主要有两个参数 setnx(key, value)。该方法是原子的,如果 key 不存在,则设置当前 key 成功,返回 1;如果当前 key 已经存在,则设置当前 key 失败,返回 0。

expire 设置过期时间,要注意的是 setnx 命令不能设置 key 的超时时间,只能通过 expire() 来对 key 设置。

原文>>>:

你可能感兴趣的:(女朋友也能看懂的Zookeeper分布式锁原理)