文档章节

分布式锁实现

九分石人
 九分石人
发布于 07/11 17:33
字数 1986
阅读 23
收藏 0

行业解决方案、产品招募中!想赚钱就来传!>>>

基于数据库实现分布式锁:

基于数据库表:

要实现分布式锁,最简单的方法可能就是直接创建一张锁表,然后通过操作该表中的数据来实现了。

当我们要锁住某个方法或资源时,我们就在该表中增加一条记录,想要释放锁的时候就删除这条记录。

问题:

  1. 这把锁强依赖数据库的可用性,数据库是一个单点,一旦数据库挂掉,会导致业务系统不可用。
  2. 这把锁没有失效时间,一旦解锁操作失败,就会导致锁记录一直在数据库中,其他线程无法再获得锁。
  3. 这把锁只能是非阻塞的,因为数据的insert操作,一旦插入失败就会报错。没有获得锁的线程并不会进入排队队列,要想再次获得锁就要再次触发获得锁操作。
  4. 这把锁是非重入的,同一个线程在没有获得锁之前无法再次获得该锁。因为数据库中数据已经存在了。

解决:

  1. 数据库是单点:两个数据库,数据之间双向同步,一旦挂掉快速切换到备库。
  2. 没有失效时间:定时任务,每隔一定时间清理数据库中的超时数据。
  3. 非阻塞的:while循环,直到insert成功在返回。
  4. 非重入的:在数据库表中加个字段,记录当前获得锁的主机信息和线程信息,下次在获取锁时先查询数据库,如果当前机器的主机信息和线程信息在数据库中可以查到的话,直接把锁分配给它就可以。

基于数据库排他锁:

可以借助数据中自带的锁来实现分布式锁。 通过数据库的排他锁,基于InnoDB引擎。

总结:

使用数据库来实现分布式锁,这两种方式都是依赖数据库的一张表,一种是通过表中记录的存在情况确定当前是否有锁存在,另一种是通过数据库的排他锁来实现分布式锁。

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

缺点:会有各种各样的问题,在解决问题的过程中,会使整个方案变得越来越复杂。操作数据库会有一定的开销,性能问题需要考虑。使用数据库的行级锁并不一定靠谱,尤其是当我们的锁表并不大的时候。

基于缓存实现分布式锁:

相对于基于数据库实现分布式锁的方案来说,基于缓存来实现在性能方面会表现的更好一点。而且很多缓存是可以集群部署的,可以解决单点问题。

目前有很多成熟的缓存产品,Redis,memcached。

问题:

  1. 这把锁没有失效时间,一旦解锁失败,就会导致锁记录一直在缓存中,其他线程无法再次获得锁。
  2. 这把锁只能是非阻塞的,无论成功还是失败都直接返回。
  3. 这把锁是非重入的,一个线程获得锁之后,在释放锁之前,无法再次获得该锁,因为key已经存在,无法进行put操作。

解决:

  1. 没有失效时间:设置固定时间,到期后自动删除。失效时间比较难以确定,时间太短,方法没执行完释放锁,就会产生并发问题;时间太长,其他线程就要浪费很多时间。
  2. 非阻塞:while重复执行。
  3. 非可重入:在一个线程获取到锁之后,把当前主机信息和线程信息保存起来,下次再获取前先检查自己是不是当前锁的拥有者。

总结:

优点:性能好,实现起来较为方便。

缺点:通过超时来控制锁的失效时间并不是十分的靠谱。

基于Zookeeper实现分布式锁:

基于zookeeper临时有序节点可实现的分布式锁。

大致思想为:每个客户端对每个方法加锁时,在zookeeper上的与该方法对应的指定节点的目录下,生成一个唯一的瞬时有序节点。判断是否获取锁的方式很简单,只需要判断有序节点中序号最小的一个。当释放锁的时候,只需将这个瞬时节点删除即可。同时,其可以避免服务宕机导致的锁无法释放,而产生死锁的问题。

如何解决前面的问题:

  1. 锁无法释放:使用Zookeeper可以有效的解决锁无法释放的问题,因为在创建的时候,客户端会在zk中创建一个临时节点,一旦客户端获取到锁之后突然挂掉,那么这个临时节点就会自动删除掉。其他客户端就可以再次获得锁。
  2. 非阻塞锁:使用zookeeper可以实现阻塞的锁,客户端可通过在zk中创建顺序节点,并在节点上绑定监听器,一旦节点有变化,zookeeper会通知客户端,客户端可以检查自己创建的节点是不是当前所有节点中序号最小的,如果是,那么自己就获取到锁,便可以执行业务逻辑。
  3. 不可重入:使用zookeeper可以有效解决不可重入的问题,客户端在创建节点时,把当前客户端的主机信息和线程信息直接写入节点中,下次想要获取锁的时候和当前最小节点中的数据对比一下就可以。如果和自己的信息一样,那么自己直接获取到锁,如果不一样就在创建一个临时的顺序节点,参与排队。
  4. 单点问题:使用zookeeper可以有效解决单点问题,zk是集群部署的,只要集群中有半数以上的机器存活,就可以对外提供服务。

使用zk实现的分布式锁其实存在一个缺点,那就是性能上可能并没有缓存服务器那么高。因为在每次创建锁和释放锁的过程中,都要动态创建,销毁瞬时节点来实现锁功能。zk中创建和删除节点只能通过leader服务器来执行,然后将数据同步到所有follower机器上。

使用了zk也有可能带来并发问题,只是不常见。由于网络抖动,客户端集群的session连接断了,那么zk以为客户端挂了,就会删除临时节点,这是其他客户端就可以获取到分布式锁了。就可能产生并发问题。这个问题不常见是因为zk有重试机制,一旦zk集群检测不到客户端的心跳,就会重试,多次重试还不行的话就会删除临时节点。

总结:

优点:有效的解决单点问题,不可重入问题,非阻塞问题,以及锁无法释放的问题。实现起来较为简单。

缺点:性能上不如缓存实现分布式锁。需要最zk的原理有所了解。

比较:

理解程度:

数据库>缓存>Zookeeper

实现的复杂性角度:

Zookeeper>=缓存>数据库

性能角度:

缓存>Zookeeper>=数据库

可靠性角度:

Zookeeper>缓存>数据库

上一篇: 分布式事务
九分石人
粉丝 0
博文 24
码字总数 36461
作品 0
杭州
程序员
私信 提问
加载中
请先登录后再评论。
用vertx实现高吞吐量的站点计数器

工具:vertx,redis,mongodb,log4j 源代码地址:https://github.com/jianglibo/visitrank 先看架构图: 如果你不熟悉vertx,请先google一下。我这里将vertx当作一个容器,上面所有的圆圈要...

jianglibo
2014/04/03
3.9K
3
SQLServer实现split分割字符串到列

网上已有人实现sqlserver的split函数可将字符串分割成行,但是我们习惯了split返回数组或者列表,因此这里对其做一些改动,最终实现也许不尽如意,但是也能解决一些问题。 先贴上某大牛写的s...

cwalet
2014/05/21
9.6K
0
Promises/A 和 when() 实现--When.js

When.js 是 cujojs 的轻量级的 Promises/A 和 when() 实现,从 wire.js 的异步核心和 cujojs 的 IOC 容器派生而来。包含很多其他有用的 Promiss 相关概念,例如联合多个 promiss、mapping 和...

匿名
2013/02/15
7.4K
0
工作流管理系统--Pegasus WMS

Pegasus (飞马座)工作流管理系统包括一套技术标准工作流程应用程序中执行帮助许多不同的环境中,包括桌面、校园集群、网格、云。它弥补了科学领域和执行环境通过自 动映射到分布式资源的高层工...

匿名
2013/02/24
5.2K
0
Redis 分片实现--Redis Shard

redis-shard 是 Redis 分区的 Python API ,基于对 key 和 key tag 进行 CRC32 checksum 计算,可参考文章 http://antirez.com/post/redis-presharding.html . 该项目由知乎网开发。 使用限制...

匿名
2012/10/24
5.6K
0

没有更多内容

加载失败,请刷新页面

加载更多

SPSSAU 付费数据研究报告服务

SPSSAU-付费数据分析报告服务(周老师提供) 本文分享自微信公众号 - SPSSAU(spssau)。 如有侵权,请联系 support@oschina.cn 删除。 本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起...

SPSSAU
2017/11/08
0
0
芋艿-springcloud gateway

http://www.iocoder.cn/Spring-Cloud/Spring-Cloud-Gateway/?github springcloud gateway 官方文档 https://cloud.spring.io/spring-cloud-gateway/reference/html/#gatewayfilter-factories......

Java搬砖工程师
39分钟前
5
0
新零售小程序制作流程

最近有很多小伙伴们都在观望新零售小程序,其实新零售小程序制作还是比较简单的,只要你能熟知以下的新零售小程序制作流程,你也可以制作出属于自己的小程序。下面木鱼小铺(www.muyu007.cn)...

木鱼小铺小程序1
40分钟前
5
0
bat增加自定义参数

#xxx.bat --tag=dev1010 --context=3 --cpu=3 --memory=3 --build=1 --update=1 --api-version=1 @echo off setlocal enabledelayedexpansion set COMMANSLINE="%" :STR_VISTOR for /f "toke......

_snake_
42分钟前
3
0
谷歌SEO推广团队,这样管理更高效!

如今不论是外贸企业还是专业的海外推广公司都会组建自己的Google SEO推广团队,可以更有效的做好网站SEO,但是要发挥谷歌SEO推广团队的最大效能,我们并不能随意的让团队成员听之任之,随波逐...

一尘SEO
44分钟前
9
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部