首页  >  文章  >  Java  >  如何使用Redis实现分布式锁

如何使用Redis实现分布式锁

PHPz
PHPz原创
2024-08-31 18:31:04744浏览

我是哑巴

嗯,每当我们在本地系统中工作时,一切都像黄油一样工作。这就是为什么我们称“没有比 127.0.0.1 更好的地方了”,但醒来面对现实

How to implement a Distributed Lock using Redis

生产中的事情并不总是按预期进行。大多数情况下,当您运行应用程序的多个实例时。

How to implement a Distributed Lock using Redis

?正如您所看到的,如果我们的应用程序的多个实例正在运行,并且假设我们的客户端发出请求,将用户标记为数据库中的付费用户。

  • 客户端将请求我们的服务器
  • 请求将到达我们的负载均衡器
  • 其中一个实例将收到请求并向我们的数据库发出写入查询

看起来还不错吧?到目前为止没问题吧。

嗯,是的,到目前为止没有问题。但是如果我们想编写这样的业务逻辑怎么办:-

  • 从数据库中获取用户
  • 检查用户是否是免费用户或已付费
  • 如果免费,则将其标记为付费并保存在数据库中
  • 如果已付款,请在回复中发送“已付款”。

⚡️ 众所周知(假设我们在这里使用 MySQL)MySQL 数据库符合 ACID,这意味着任何查询都将是原子的和隔离的。这意味着 MySQL 查询将以原子方式运行,要么通过,要么失败。但中间不会退出。

?但这里有一个问题。想想,想想……

  • 第 1 步:我们正在获取用户(原子事务)
  • 第 2 步:在代码中运行一些业务逻辑
  • 第3步:如果用户未付款则更新MySQL记录(原子交易)

如果在第 2 步,又有一个取消付款的请求,然后该查询首先运行并将用户标记为免费,然后运行第 3 步并将用户标记为已付费,将会发生什么情况。

??万岁,用户甚至无需付费即可访问我们的产品。

锁定

✅救星Locks来了
How to implement a Distributed Lock using Redis

?锁是一种结构,一次只允许一个线程进入临界区(不应被多个工作线程访问的代码块)

因此,我们将在操作完成之前获取锁定并在操作完成后释放:-

  • 第0步:尝试获取()锁
  • 第 1 步:如果获取,我们将获取用户(原子事务)
  • 第 2 步:在代码中运行一些业务逻辑
  • 第3步:如果用户未付款则更新MySQL记录(原子事务)
  • 第四步:release() 锁

?问题

现在,问题来了,如果我们使用一些内存锁数据结构或任何基于内存的锁,它将适合我们的应用程序的一个实例。其他运行相同代码并在数据库中更新的实例怎么样?

分布式锁的概念来了

?分布式锁

How to implement a Distributed Lock using Redis

这里的锁充当一种集中式服务,如果我们服务的一个实例获取了锁,那么其他实例就无法使用同一个密钥。

支付服务中可以使用什么键?

?对于进行付款的用户,密钥可以是=“PAYMENT_”+ user_id + amount

的组合

这对于每个用户来说都是唯一的。并且当用户付款或取消付款时,该密钥将保持不变。因此,当一个操作发生时,其他操作无法继续,因为这两个操作将尝试获取同一键。

? Key、获取锁、释放锁到底是什么?最重要的是,redis 是如何使用的?


?使用Redis实现分布式锁

使用 Redis 的单个实例:-

How to implement a Distributed Lock using Redis

但是单个 Redis 实例存在以下几个问题:-

  • 单个实例可能会失败并且获取的锁可能无法释放
  • 如果使用两个实例(主副本),则一个客户端将获取一个实例上的锁
  • 主服务器必须与副本进行相同的通信才能同步。这种通信本身就是异步通信

?因此,如果在主服务器上获取了锁,并且在与副本通信时,如果主服务器在与副本同步之前发生故障。副本将成为主服务器,其中同一密钥上的锁将可用于获取之前在主服务器上获取的锁。

即使有两个实例(主副本),我们服务的两个实例也将能够获取 Redis 上的锁。

使用 Redlock 算法:-

获取锁:- 我们将尝试在具有锁过期时间的多个 Redis 实例上获取锁
锁验证:- 如果主要 Redis 实例为客户端获取了锁,则将被视为已获取锁
释放锁:- 释放锁时,所有实例都释放锁

How to implement a Distributed Lock using Redis

是的,就是这样。

❤️ 感谢您的阅读,并订阅我们的时事通讯以获取更多此类文章:- https://www.serversidedigest.com/

欲了解更多信息:-

  • Java 中的 Jedis:- https://redis.io/docs/latest/develop/connect/clients/java/jedis/
  • Golang 中的 Redis 客户端:- https://github.com/redis/go-redis

以上是如何使用Redis实现分布式锁的详细内容。更多信息请关注PHP中文网其他相关文章!

声明:
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn