【分布式锁】什么是分布式锁?分布式锁的作用?

什么是分布式锁

分布式锁是一种用于在分布式系统中协调多个节点对共享资源的访问的机制。它确保在多个节点并发访问时,只有一个节点可以在某个时刻拥有特定资源的访问权,从而避免数据不一致、竞争条件或资源冲突的问题。常用的实现方式有Redis,Zookeeper。我们这篇主要讲解Redis.

为什么要使用分布式锁?为什么不直接使用本地锁呢?

因为本地锁是JVM级别的,它只能锁住当前线程,经过分布式部署之后,每台服务器在并发情况下只能锁住一个线程,因此需要使用分布式锁。
在这里插入图片描述
这种情况下经过Nginx反向代理后,如果使用本地锁,只能锁住当前线程。

为什么Redis可以实现分布式锁

由于Redis本身可以被多个客户端共享访问,因此可以作为存储锁的容器。而且Redis中set还有个NX选项,作用是如果集合中存在key就插入失败,如果不存在,则插入成功。我们可以基于这个实现分布式锁。即当集合中不存在该key时,插入成功,表示获取到锁了,如果插入失败,说明此时没有获取到锁。

注意事项

需要加上过期时间避免当前线程由于某些原因导致无法释放锁,从而造成其他线程无法获取锁

在这里插入图片描述

### 分布式锁的特性 分布式锁需要满足特定的特性以确保在分布式系统中能够正常工作。以下是分布式锁的主要特性: - **互斥性**:分布式锁必须保证同一时间只有一个客户端能够持有锁,从而避免多个节点同时访问共享资源[^3]。 - **可重入性**:支持一个线程多次获取同一个锁,并且只有当该线程释放相同次数的锁后,其他线程才能获取该锁[^3]。 - **锁超时释放**:为了避免死锁问题,分布式锁通常会设置一个超时时间,超过该时间后锁会被自动释放[^3]。 - **高性能和高可用性**:锁的获取和释放操作需要高效,能够支持高并发场景;同时需要具备高可用机制,防止锁服务不可用导致系统故障[^3]。 - **安全性**:锁只能被持有它的客户端删除,其他客户端无法删除不属于自己的锁[^3]。 - **阻塞性**:支持阻塞和非阻塞两种方式获取锁,阻塞方式会在锁被占用时等待,而非阻塞方式则直接返回失败[^3]。 - **公平性**:支持公平锁和非公平锁两种类型,公平锁按照请求顺序分配锁,而非公平锁则不保证顺序[^3]。 ### 分布式锁的实现方法 分布式锁可以通过多种方式实现,以下是一些常见的实现方法及其特点: #### 1. 基于 Redis 的实现 Redis 是一种内存数据库,其单线程特性和原子操作使其成为实现分布式锁的理想选择。基于 Redis分布式锁主要依赖 `SETNX`(Set if Not Exists)命令来实现锁的获取和释放[^4]。以下是具体实现步骤: - 使用 `SETNX` 命令尝试设置一个键值对,如果键不存在则设置成功,表示获取锁成功。 - 设置锁的过期时间,防止死锁发生。 - 在释放锁时,确保只有持有锁的客户端能够删除对应的键值对。 代码示例: ```python import redis import time client = redis.StrictRedis() def acquire_lock(lock_name, acquire_timeout=10): identifier = str(uuid.uuid4()) end = time.time() + acquire_timeout while time.time() < end: if client.setnx(lock_name, identifier): client.expire(lock_name, 10) # 设置锁的过期时间 return identifier time.sleep(0.001) return None def release_lock(lock_name, identifier): script = """ if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end """ return client.eval(script, 1, lock_name, identifier) ``` #### 2. 基于 ZooKeeper 的实现 ZooKeeper 是一种分布式协调服务,通过其临时顺序节点可以实现分布式锁。以下是其实现原理: - 创建一个临时顺序节点,ZooKeeper 会为每个节点分配一个全局唯一的递增序号。 - 客户端检查当前创建的节点是否是序号最小的节点,如果是,则表示获取锁成功。 - 释放锁时,删除对应的临时节点即可[^2]。 #### 3. 基于版本字段的乐观锁 乐观锁通过版本号或时间戳来控制并发访问。以下是其实现方式: - 每次更新数据时,先读取当前版本号或时间戳。 - 更新时比较当前版本号与数据库中的版本号,如果一致则更新成功,否则更新失败。 - 这种方式适用于读多写少的场景,但不适用于需要长时间持有锁的场景[^4]。 ### 总结 分布式锁的实现方式各有优劣,基于 Redis 的实现简单高效,适合大多数场景;基于 ZooKeeper 的实现功能强大,但复杂度较高;基于版本字段的乐观锁适用于特定场景,但不支持长时间锁持有。
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值