Apong's Blog

当你快坚持不住的时候,困难也快坚持不住了

0%

Linux,分布式锁

Linux

链接

链接文件:一个可以“通向”其他文件的文件。

分为 软链接 和 硬链接。

软链接:类似 Windows 的快捷方式,不是一个实质的文件,当链接的文件被销毁后,也就失去作用了

硬链接:直接和 另一个文件 通向 相同的内存,和链接的文件共享文件内容,这边修改了那边也会跟着变

和 Docker 的 Volume 有点像

命令ln -s <linked> <link>

s: symbolic 符号,表示创建软链接(符号链接)

如 ln b.txt a.txt:创建 a 对 b 的硬链接。

注意:硬链接不能指向目录,因为目录只是一个层级,不是文件,无法让你修改。

vi编辑器

打开方式:vi <file>

如果文件不存在则会创建新文件。

vim编辑器中分为三种状态

  1. 命令模式,按下按键不会输入字符,而是执行命令。
  2. 输入模式,可以插入字符
  3. 底线命令模式,在界面最低端,输入命令执行相应操作

命令模式常用

  1. i、a、o,分别是在光标当前、随后、下一行进入输入模式,可以输入字符
  2. u,复原操作
  3. dd,删除这一行
  4. :,切换到底线命令模式

输入模式常用

  1. ctrl + u,撤回操作

底线命令模式

  1. q 退出
  2. q!强制退出,加一个!表示强制的意思
  3. w 保存
  4. wq 保存退出
  5. !暂时离开进入terminal查看信息
  6. set nu 显示行号
  7. set nonu 取消显示行号

分布式锁

在集群部署的情况下,保证某个操作只能单线程执行。

实现方式

  1. MySQL 本身的互斥锁机制(还没学)
  2. Redis setnx 互斥命令
  3. zookeeper 唯一有序节点

定义 Lock 接口

  • boolean tryLock(long timeSec) 尝试获取锁,并设置过期时间,防止服务宕机造成死锁

    MySQL 断连会自动释放,zookeeper 是临时节点

  • void unlock()

防止误删

如果某次操作执行非常慢或者被阻塞了,导致他获取的锁被过期释放了,此时其他线程获取到了新的锁,但由于锁的 key 都是一致的,最后这个被阻塞的操作完成后会误删了其他线程的锁。

一、给锁加上标识

为了误删其他线程的锁,需要再释放之前,判断这把锁是否是为当前线程的锁。

利用 UUID + 线程id 生成不同服务器不同的标识

如果只用id的话,由于这个id是顺序生成的,不同服务器之间会冲突。

二、原子性

既然出现了判断,就会有数据不一致的并发问题。

如果因为 JVM 的 GC 垃圾回收等机制造成了阻塞,导致在判断完之后锁又过期的情况下,又会误删其他线程的锁。

因此,需要保证 判断 和 释放 两个操作的原子性。

这里采用脱离 JVM,让 Redis 执行 lua 脚本的方法。

实现步骤:

  1. 编写 lua 脚本
  2. 借助 StringRedisTemplate 的 execute 方法执行脚本

Redis 会不会产生数据不一致的问题,在查询到标识之后被其他线程改了?多线程?

Redis 在 5 版本之前都是单线程的,而且事务保证了原子性。