分布式锁_基本理解

分布式锁

简介

锁:在编程中锁(lock)或互斥(mutual)同步机制,用于在多线程(或进程)中对资源的访问限制。锁主要作用是互斥排他、并发控制策略。

分布式锁的实现: 基于数据库实现,基于缓存(Redis)实现,基于Zookeeper实现。

第三方开源实现:curator(基于Zookeeper实现),redission(基于Redis实现)

数据库分布式锁

利用数据库的行锁实现。

支持行锁的数据库:MySql的InnerDB引擎支持行锁, PostgreSQL支持行锁,Oracle等。

例如有个表:

distribute_lock

distribute_lock表记录

说明: 为 resource_code 添加唯一索引。用于加行锁时走索引。

加行锁操作:

  1. 先关闭事务自动提交。
  2. 例如给资源"testcode" 加锁:select id, resource_code from distribute_lock where resource_code = 'testcode' for update;
  3. 释放锁:commit

举例说明:

conn 1 执行 :select id, resource_code from distribute_lock where resource_code = 'testcode' for update;
conn 2 执行: select id, resource_code from distribute_lock where resource_code = 'testcode' for update;
conn 1 查询成功(获得锁)返回,此时***conn 2*** 等待
conn 1 执行: commit 释放锁
conn 2 查询成功(获得锁)返回
conn 2 执行:commit 释放锁

时序图如下:

  ┌─────────────┐                      ┌───────────────┐                       ┌──────────────┐
  │    conn 1   │                      │   Database    │                       │    conn 2    │
  └──────┬──────┘                      └───────┬───────┘                       └────────┬─────┘
         │                                     │                                        │
         │    1. select ... for update         │                                        │
         │                                     │                                        │
         ├────────────────────────────────────►│         2. select ... for update       |
         │                                     │◄───────────────────────────────────────┤
         │                                     │ conn2 wait                             │
         │                           return    │                                        │
         │◄────────────────────────────────────┤                                        │
         │                                     │                                        │
         │   commit                            │                                        │
         ├────────────────────────────────────►│   return                               │
         │                                     │───────────────────────────────────────►│
         │                                     │                                        │
         │                                     │                            commit      │
         │                                     │◄───────────────────────────────────────┤
         │                                     │                                        │

高可用场景:

​ 数据库进行主备架构,使用LVS进行VIP。

​ 客户端发现链接断开,进行回滚操作。

高并发场景:

​ 性能瓶颈在于单数据库,可以进行分库分表。

​ 每个库都对应一个备库,将不同的资源分片到不同的库和表中。

​ 数据库扩展性根据分库分表的策略。比较难。

高性能场景:

​ 利用分库分表。

实践部分分布式锁_数据库分布式锁实践


Redis 分布式锁

使用redis的单线程原理,通过set命令根据key不存在则设置成功并返回。设置成功即获得锁。

set resource_name my_random_value NX PX 30000
# SET key value [EX seconds] [PX milliseconds] [NX|XX]

EX: seconds, 过期时间
NX:不存在则设置, 将键的过期时间设置为 seconds 毫秒
XX: 只在键已经存在时, 才对键进行设置操作
PX: milliseconds, 将键的过期时间设置为 milliseconds
my_random_value: 设置随机数,校验正确才能删除锁。
校验正确才删除锁需要用到LUA脚本如下:

if redis.call("get", KEYS[1])  == ARGV[1] then
	return redis.call('del', KEYS[1])
else 
	return 0
end

问题:为什么进行KEY的过期设置

当心如果一个客户端获取锁之后,没有释放锁,则导致资源不可用了。

问题: 如果业务耗时,在锁过期时候,被自动释放,如何处理?

开启一个线程,定时去延续锁的过期时间。

问题:如果业务线程和监听线程都因系统CPU资源耗尽,处理慢,锁没有自动续期,如何处理?

根据业务情况,判断锁释放失败进行回滚操作。

实践部分分布式锁_Redis分布式锁实践


Zookeeper 分布式锁

使用Zookeeper的顺序临时节点特性。创建的节点是顺序编号的且唯一。

最小的顺序号获取锁。

其他去监听前一个顺序节点(既:比他小一个值的顺序号节点),这里主要是为了控制获取锁的顺序。

释放锁,只要删除对应的顺序临时节点即可

其他客户端就可以通过监听事件,获取锁了。

例如:

  1. client_a, client_b, client_c 都创建临时节点 resource_
    client_a 创建resource_00000000
    client_b 创建resource_00000001
    client_c 创建resource_00000002

  2. 客户端查询所有子节点, 判断是否获取锁
    client_a创建的 resource_00000000 为最小,则获取锁。
    其他客户处分别监听比他小的顺序节点。client_b监听 resource_00000001client_c监听 resource_00000002.

  3. client_a 删除节点 resource_00000000 释放锁,则 client_b 获取通知,获取锁。以此类推。


  ┌────┐
  │  / │
  └──┬─┘
     │   ┌─────────┐
     └───┤resources│
         └─┬───────┘
           │
           │    ┌─────────────────┐            create     ┌────────────┐
           ├────┤resource_00000000│◄──────────────────────┤  client_a  │
           │    └─────────▲───────┘                       └────────────┘
           │              │                    watch
           │              └─────────────────────────────────────┐
           │                                                    │
           │    ┌─────────────────┐            create     ┌─────┴──────┐
           ├────┤resource_00000001│◄──────────────────────┤  client_b  │
           │    └──────────▲──────┘                       └────────────┘
           │               │                   watch
           │               └─────────────────────────────────────┐
           │                                                     │
           │    ┌─────────────────┐            create     ┌──────┴─────┐
           ├────┤resource_00000002│◄──────────────────────┤  client_c  │
           │    └─────────────────┘                       └────────────┘
           │
           │    ┌─────────────────┐
           └────┤       ...       │
                └─────────────────┘

实践部分: 分布式锁_Zookeeper分布式锁实践

curator实践
redission实践

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值