手把手实现分布式锁
进程中的锁
1.互斥锁
2.自旋锁
3.读写锁
4.信号量
5.条件变量
6.原子变量以及内存屏障
进程间通信
1.pipe
2.FIFO
3.信号量
4.信号
5.消息队列
6.共享内存
7.socket
1.条件变量为什么与互斥锁协同
条件的判断是一个临界资源,需要互斥锁保护
2.哪些锁是自己加锁自己释放锁?哪些是自己加锁,可能由别的线程释放锁?
互斥锁,自旋锁;信号量和条件变量可能由别的线程释放锁;
pthread_mutex_lock(&mtx);
while (condition) //解决了虚假唤醒的问题
pthread_cond_wait(&cond, &mtx);
pthread_mutex_unlock(&mtx);
pthread_mutex_lock(&mtx);
pthread_mutex_unlock(&mtx);
pthread_cond_signal(&cond);
pthread_cond_broadcast(&cond);
为什么会产生虚假唤醒(pthread_cond_wait会返回,但其实条件并不满足)问题:
1.条件变量有可能会被信号打断
信号 -1 = read errno = EINTR
2.信号劫持
3.多处理实现过程中出现的bug:signal可能会唤醒多个
分布式锁是什么类型的锁?
在分布式场景中实现互斥类型的锁
分布式:运行的节点可能在不同机器或不同网段当中,节点间通信通过socket
互斥类型:同一时刻只允许一个执行体进入临界资源
解决了什么问题?
在分布式场景中,同时只允许一个节点执行某类任务
什么场景下
分布式场景中
行为:加锁,解锁-》网络交互-》锁超时功能,由锁存储的所在节点来实现
加锁对象和解锁对象必须为同一个 -》除了因为网络异常而造成锁超时情况
分布式锁特性
1.互斥性:
锁打上标记:加锁
锁取消标记:解锁
标记:执行体的唯一标识
2.锁超时
3.可用性
3.1合理时间内得到合理的回复
3.2实现
3.2.1计算型(网关)-> 开多个备份点
3.2.2存储型 ->多个备份点/主从切换
4.容错性 一致性来解决(半数以上)
4.1 raft一致性算法
4.2 redlock
分布式锁类型
重入锁和非重入锁:允许同一个线程多次持有锁
公平锁和非公平锁
公平锁:排队
非公平锁:轮询
公平锁 互斥锁
非公平锁 自旋锁
实现重点
锁是一种资源,需要存储;同时要保证可用性,避免锁失效 ->一个进程多线程中的锁资源存储在进程中
互斥语义:将锁打标记
1.加锁对象和解锁对象必须为同一个
2.解锁时需要判断当前持有锁的对象是否是自己
加锁解锁行为是网络通信,需要锁超时->进程是资源的容器,线程是执行的单元
怎么获知持有锁对象的释放锁行为?
主动探寻->非公平锁
被动通知
是否允许同一持锁对象多次加锁?重入锁,非重入锁
MySQL中
特征:关系型数据库、表
实现:锁的存储->表
获取锁和释放锁->字段
互斥语义:
唯一性约束->unique key primary key
利用innodb中的S锁和X锁互斥
锁超时:
另起进程
表增加一个字段:加锁时间戳
定时检测是否超时
delete from lock where lock type = "act_lock"
其他进程怎么获取锁:
实现定时器
主动探寻
总结:
可用性依赖数据库;若数据库是单点,挂掉将导致业务系统不可用;
还需额外实现锁失效的问题;解锁失败,其他线程将无法获得锁;
Redis中
分布式锁流程
尝试获取锁:
获取锁成功,操作临界资源,操作结束尝试释放锁
获取锁失败,订阅解锁信息
尝试释放锁:
释放锁成功,广播解锁信息;
释放锁失败(说明此时持有锁对象不是自己),获得锁失效时间;
特性:内存数据库,数据结构数据库
实现:锁存储
锁存储:set lock uuid nx ex 30
获取和释放锁:
set lock uuid nx ex 30
需要通过lua脚本先要确定是否是持锁对象,然后del lock
互斥语义 nx
锁超时 ex expire pexpire
其他进程怎么获取锁 可以通过广播的方式 sub/pub
递归锁
动态库
1.runtime path
2.ld.so.conf动态库缓存查找
3.系统路径 PATH
总结:
可用性依赖redis的可用性
容错性很差,redis采用的异步复制,数据可能丢失
效率最高的一种分布式锁
最安全的redis分布式锁
etcd实现公平锁
性能出发:redis>etcd>mysql
完备性:etcd>redis>mysql
选择:都有选择etcd,如果只有mysql不会为了实现分布式锁加入redis或etcd,有etcd选择etcd。
文章参考于<零声教育>的C/C++linux服务期高级架构系统教程学习:https://ke.qq.com/course/417774?flowToken=1020253