孤尽训练营打卡日记day26--redis分布式锁

前言

        秒杀是电商平台一个非常重要的功能,在这种高并发的情况下,怎么控制不超库存呢?那就是用锁。但是我们现在都是分布式系统,也就会诞生另外的一个问题。怎么加一个全局的锁,传统的 synchronize 或 lock 锁不行,因为会有多台实例,那么应该加什么锁呢?今天跟着刘雪松老师一起学习一下分布式锁。

Redis 锁原理

        借助 setnx 和 expire 两个redis命令完成

setnx:当key不存在,将key设置为value ,存在不做任何操作,返回 0

setnx [key] [value]

setnx lock "123"

expire:设置key 的过期时间

expire [key] [time]

expire lock 10  单位秒

加锁两个条件

  • 能加锁
  • 形成锁的互斥

问题:setnx是两个命令,如果执行了setnx,expire失败 ,就会造成锁无法释放

解决:

  • 使用set key value [Ex seconds][Px milliseconds] [NX|XX]
  • 使用 lua 脚本执行,两个命令是个原子操作
setnx lock "123" EX 100 NX
EX seconds 设置失效时长,单位秒
PX milliseconds 设置失效时长,单位毫秒
NX key不存在时设置value
XX key存在时设置value

Jedis 分布式锁实现

Jedis就是集成了redis的一些命令操作,封装了redis的java客户端。提供了连接池管理。'

加锁 set

jedis.set = set key value [Ex seconds][Px milliseconds] [NX|XX]

解锁 del

jedis.del(key)

锁过期问题:

线程一持有锁超时 20秒,执行10秒的时候,遭遇fullgGC ,STW导致任务挂起,超过20秒,线程二开始执行,fullGC结束,线程一继续执行,导致数据混乱

1、增加乐观锁,线程一的version 为1 ,线程二的version 2 ,当线程一回来的时候,发现版本不一致,不予执行

2、看门狗,是一个后台线程,会定期检测是否线程一是否还持有锁,如果还持有锁,延长时间

(只对dislock.lock 有效,显式指定时间的看门狗无用 )

redisson分布式锁

Redisson

        是基于netty的redis 客户端。不但能操作原生的Redis 数据结构,还能为使用者提供了一系列具有分布式特性的常用工具类,实现了分布式锁。

Redisson 分布式锁

        RLock 分布式锁和JUC的lock方法相似。RLock接口继承了Lock接口

RLock disLock = client.getLock("DISLOCK");
disLock.lock();  // 默认 30s
=======================
disLock.tryLock(2000, 150000, TimeUnit.MILLISECONDS);

// 2000 等待时间
// 150000 持有时间
// TimeUnit..MILLISECONDS  单位

 

// 可重入锁
disLock.tryLock(2000, 15000, TimeUnit.MILLISCONDS); 
// 释放锁
disLock.unlock();

 分段锁

        可以使用分段的方式,以空间换时间,为了达到每秒600个订单,将锁分为 120 段,一秒操作五次,120段就是 600。

        首先将数据分成一段一段的存储,然后给每一段数据配一把锁,当一个线程占用锁访问其中一个段数据的时候,其他段的数据也能被其他线程访问。

ConcurrentHashMap 用的就是分段锁。容器里有多把锁,每一把锁用于锁容器其中一部分数据,那么当多线程访问容器里不同数据段的数据时,线程间就不会存在锁竞争,从而可以有效的提高并发访问效率。

行而不辍,未来可期。                         --《荀子·修身》

参考文档:刘雪松老师的PPT

猜你喜欢

转载自blog.csdn.net/qq_35056844/article/details/121444764