博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
分布式锁
阅读量:6574 次
发布时间:2019-06-24

本文共 3416 字,大约阅读时间需要 11 分钟。

应用场景

具体的应用场景

为什么要使用分布式锁

1.单机

同一个进程里的不同线程,访问同一个数据。

不同的线程,为什么会访问同一个数据呢?

比如,
1.单例对象
2.数据库里的数据

这些情况,都可能会访问同一个数据。


2.多机

就是不同的进程,访问同一个数据。

不同的进程,为什么会访问同一个数据呢? 比如,数据库里的数据,缓存里的数据。

缓存里的数据?之前阿里面试支付,解决幂等问题的时候,就有问到这个问题。面试官想要问的就是,分布式锁。

解决方案

首先,得明白一个问题,就是这个锁,必须是存储在所有进程都能够访问的地方。然后,具体访问的时候,同一时刻只有一个进程可以拿到这个锁。


有三种

1.基于数据库
mysql
2.基于缓存
redis
set命令
3.基于分布式协调
zookeeper存储service的目录服务。其实,也就是利用了第三方软件存储数据的功能,不管那个第三方软件是数据库、缓存、分布式协调,本质上都是为了哪一个第三方中介软件存储这个锁,使得所有进程都可以访问到这个锁,至于具体是什么软件,还真不要紧。

基于数据库mysql

其实,有好几种解决方案

1.基于键的唯一性约束
2.基于行锁

基于键的唯一性约束

比如,设计一张表,现在表里面有个方法字段,方法字段唯一性约束。

写的时候,如果有多线程访问,只有一个线程能写数据成功,其他失败。

很明显,这样会带来很多问题?比如,其他的线程不是失败,而是必须阻塞获取锁。如何阻塞?可以使用while循环。

基于排它锁/行锁

实现原理

就是查询数据库记录的时候,数据库会对当前查询上排他锁,其他查询不能查询——直到别的查询执行完毕释放锁。


步骤

1.进程1查询记录
获取到锁,执行接下来的代码。

2.进程2查询同一个记录 //比如,每个方法,弄一条记录

阻塞直到获取到锁。
因为进程1执行完以下几个步骤1.执行查询锁,相当于是获取到了锁2.执行业务代码3.释放锁connection.commit() 之后,进程2就可以获取到锁了。这个阻塞是数据库mysql本身支持的。


基于数据库排他锁做分布式锁

在查询语句后面增加for update,数据库会在查询过程中给数据库表增加排他锁 (注意: InnoDB 引擎在加锁的时候,只有通过索引进行检索的时候才会使用行级锁,否则会使用表级锁。这里我们希望使用行级锁,就要给要执行的方法字段名添加索引,值得注意的是,这个索引一定要创建成唯一索引,否则会出现多个重载方法之间无法同时被访问的问题。重载方法的话建议把参数类型也加上。)。当某条记录被加上排他锁之后,其他线程无法再在该行记录上增加排他锁。

我们可以认为获得排他锁的线程即可获得分布式锁,当获取到锁之后,可以执行方法的业务逻辑,执行完方法之后,通过connection.commit()操作来释放锁。

这种方法可以有效的解决上面提到的无法释放锁和阻塞锁的问题。

阻塞锁? for update语句会在执行成功后立即返回,在执行失败时一直处于阻塞状态,直到成功。 锁定之后服务宕机,无法释放?使用这种方式,服务宕机之后数据库会自己把锁释放掉。 但是还是无法直接解决数据库单点和可重入问题。

这里还可能存在另外一个问题,虽然我们对方法字段名使用了唯一索引,并且显示使用 for update 来使用行级锁。但是,MySQL 会对查询进行优化,即便在条件中使用了索引字段,但是否使用索引来检索数据是由 MySQL 通过判断不同执行计划的代价来决定的,如果 MySQL 认为全表扫效率更高,比如对一些很小的表,它就不会使用索引,这种情况下 InnoDB 将使用表锁,而不是行锁。如果发生这种情况就悲剧了。。。

还有一个问题,就是我们要使用排他锁来进行分布式锁的 lock,那么一个排他锁长时间不提交,就会占用数据库连接。一旦类似的连接变得多了,就可能把数据库连接池撑爆。

基于redis

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

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

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

基于zookeeper

这种实践当中不常用。因为zookeeper主要是设计用来协调分布式服务的。

分布式锁必须实现以下几点要求

分布式锁服务一般需要能够保证:

1.排它锁

同一时刻只能有一个线程持有锁
2.阻塞
指的是,阻塞等待直到获取到锁。
具备阻塞锁特性,且能够及时从阻塞状态被唤醒。
3.可重入
锁能够可重入

4.不会发生死锁

5.锁服务保证高性能和高可用

memcache

使用memcached的add()方法,用于分布式锁。


具体细节

第四步,使用memcached的add()方法,用于分布式锁:

对于使用memcached的add()方法做分布式锁,这个在互联网公司是一种比较常见的方式,而且基本上可以解决自己手头上的大部分应用场景。

在使用这个方法之前,只要能搞明白memcached的add()和set()的区别,并且知道为什么能用add()方法做分布式锁就好。如果还不知道add()和set()方法,请直接百度吧,这个需要自己了解一下。

我在这里想说明的是另外一个问题,人们在关注分布式锁设计的好坏时,还会重点关注这样一个问题,那就是是否可以避免死锁问题???!!!

如果使用memcached的add()命令对资源占位成功了,那么是不是就完事儿了呢?当然不是!我们需要在add()的使用指定当前添加的这个key的有效时间,如果不指定有效时间,正常情况下,你可以在执行完自己的业务后,使用delete方法将这个key删除掉,也就是释放了占用的资源。但是,如果在占位成功后,memecached或者自己的业务服务器发生宕机了,那么这个资源将无法得到释放。所以通过对key设置超时时间,即便发生了宕机的情况,也不会将资源一直占用,可以避免死锁的问题。


总结

缓存的方案,实现原理都差不多,就是API/方法是原子的/事务的,同一时间,只有一个线程操作成功。具体底层实现?待补充。

最佳实践

使用redis和memcache的原理差不多,也是互联网公司实践采用最多的方案。


常用的四种方案:

1. 基于数据库表做乐观锁,用于分布式锁。  2. 使用memcached的add()方法,用于分布式锁。  3. 使用redis的setnx()、expire()方法,用于分布式锁。  4. 使用redis的setnx()、get()、getset()方法,用于分布式锁。  不常用但是可以用于技术方案探讨的:  1. 使用memcached的cas()方法,用于分布式锁。   2. 使用redis的watch、multi、exec命令,用于分布式锁。  3. 使用zookeeper,用于分布式锁。复制代码

---附加---

应用场景

作用 解决什么问题

数据库事务只能保证单机事务 不能保证分布式多数据库事务 如何解决?使用分布式锁。

使用步骤

同时 只能有一个线程获取到锁。

1.单机事务的锁
编程语言层面 锁对应
数据库层面 支持单机事务

2.分布式事务的锁

同时 访问一个数据的时候 多个线程是互斥的 这样就实现了分布式锁。

如何实现/解决方案

数据库mysql

两种方法

1.数据库表
2.数据库本身的行锁

缓存redis

setnx

必须非空 才能插入成功 否则 插入失败


具体实现步骤

1.如何获取锁
set方法
2.如何释放锁
invalid方法


参考 //官方文档 不知道说什么 有时间再看

协调zookooper

实现原理

1.锁目录
2.锁目录下的资源

开源组件Curator

1.获取锁
2.释放锁

参考

参考

//实践

//redis源码实现分布式锁

转载于:https://juejin.im/post/5d0794ba6fb9a07ea33c1668

你可能感兴趣的文章
在算法横行的时代,仍需要人类把关
查看>>
云存储是否能拯救数据泛滥
查看>>
CDN价格战外P2P重获关注,谁才是幕后推手
查看>>
【★】Web精彩实战之<智能迷宫>
查看>>
【AI手机三国杀】三星Bixby闯入战场,AI功能集成颠覆人机交互
查看>>
新加坡推出人工智能计划AI.SG 迎战人工智能和数据科学关键难题
查看>>
NetApp公司的4KB块写入技术真能容纳更多数据吗?
查看>>
《中国人工智能学会通讯》——11.10 点云局部特征描述子基准评估体系
查看>>
360浏览器清凉新版让手机解暑
查看>>
9月22日云栖精选夜读:脑洞 | 横扫围棋界的AlphaGo竟然出纪录片了!介意剧透者慎点…...
查看>>
亚信安全中标南方电网网络架构优化调整项目 智能联动抑制未知威胁
查看>>
网络安全管理的“模拟人生”
查看>>
新技术将让硬盘密度再提五倍
查看>>
PMC联手云合作伙伴Canonical加入其Ubuntu OpenStack互通性实验室
查看>>
物联网还是泄秘网?嗅探流量即可知用户动向
查看>>
Docker 镜像优化与最佳实践
查看>>
易车网携手玖富 巨额融资后再燃激情
查看>>
专门针对音乐发烧友开发的5款App
查看>>
七牛底层架构再完善 让服务从单一走向多元
查看>>
2T比特每秒!瞻博推出业界最快防火墙
查看>>