请说出为什么不用mysql做分布式锁而用redis做分布式的原因
时间: 2023-08-11 14:37:34 浏览: 291
使用 Redis 做分布式锁有以下几个原因:
1. Redis 基于内存,读写速度快,适合作为分布式锁的存储介质。
2. Redis 提供 SETNX(SET if Not eXists)命令可以实现分布式锁的原子性操作,避免了多个客户端同时获取锁的问题。
3. Redis 提供了 EXPIRE 命令可以为锁设置过期时间,避免因为客户端程序异常而导致锁一直存在的问题。
4. Redis 的订阅与发布功能可以实现分布式锁的自动释放,避免了客户端程序异常时锁未能及时释放的问题。
综上所述,Redis 具有高性能、原子性、可靠性等优点,适合作为分布式锁的存储介质。
相关问题
利用mysql实现分布式锁
在MySQL中实现分布式锁通常涉及到两个主要步骤:首先,创建一个共享资源的唯一标识;其次,使用乐观锁或悲观锁机制来获取和释放锁。这里我们重点讨论两种常见的策略:
1. **乐观锁(版本号或TTL)**:
- 使用`SELECT ... FOR UPDATE`语句,其中包含一个行级锁定条件(如版本号)。每次尝试更新时检查当前版本是否与预期一致。如果一致,则更新并返回成功,否则重试。这假设大多数情况下不会有并发冲突。
```sql
BEGIN TRANSACTION;
SET @version = (SELECT version FROM shared_resource WHERE id = ? FOR UPDATE);
IF (@version = current_version) THEN
-- 更新资源
UPDATE shared_resource SET version = version + 1 WHERE id = ? AND version = @version;
COMMIT;
ELSE
ROLLBACK; -- 冲突,回滚操作
END IF;
```
2. **悲观锁(行锁或表锁)**:
- 使用`SELECT ... FOR UPDATE NOWAIT`或`SELECT ... LOCK IN SHARE MODE`获取独占锁。`FOR UPDATE`会使查询阻塞直到锁被释放,而`LOCK IN SHARE MODE`则不会阻止其他事务读取,但会阻止写入。
- 这种方式可能更适合高并发场景,因为即使有多个客户端请求锁,也会有一个先获得锁,然后其他客户端等待。
```sql
START TRANSACTION;
SELECT * FROM shared_resource WHERE id = ? FOR UPDATE NOWAIT;
-- 执行操作
COMMIT;
```
需要注意的是,MySQL的分布式锁并不推荐用于强一致性需求高的场景,因为它依赖于单点数据库。真正的分布式锁解决方案可能会考虑使用像Redis这样的键值存储服务,或者使用基于分布式协调器(如Zookeeper、Etcd)的方案。
用C++手写redis分布式锁
手写Redis分布式锁的一个常见方法是使用Redis的SETNX命令和EXPIRE命令。SETNX用于设置一个键值对,只有在键不存在的情况下才能设置成功,用于表示获取锁的操作。EXPIRE用于设置键的过期时间,确保在获取锁的客户端崩溃或网络故障的情况下,锁最终会被释放。
下面是一个用C语言手写Redis分布式锁的简单示例代码:
```c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/wait.h>
#include <signal.h>
#include <errno.h>
#include <hiredis/hiredis.h>
#define REDIS_HOST "localhost"
#define REDIS_PORT 6379
#define LOCK_KEY "my_lock"
#define LOCK_EXPIRE_TIME 10
int main() {
pid_t child_pid;
int status;
// 创建子进程
child_pid = fork();
if (child_pid == 0) {
// 子进程获取锁
redisContext *redis_conn = redisConnect(REDIS_HOST, REDIS_PORT);
if (redis_conn == NULL || redis_conn->err) {
printf("连接Redis失败\n");
exit(1);
}
// 设置锁
redisReply *reply = redisCommand(redis_conn, "SETNX %s 1", LOCK_KEY);
if (reply == NULL || reply->type == REDIS_REPLY_ERROR || reply->integer != 1) {
printf("获取锁失败\n");
exit(1);
}
// 设置锁的过期时间
reply = redisCommand(redis_conn, "EXPIRE %s %d", LOCK_KEY, LOCK_EXPIRE_TIME);
if (reply == NULL || reply->type == REDIS_REPLY_ERROR || reply->integer != 1) {
printf("设置锁的过期时间失败\n");
exit(1);
}
printf("获取锁成功\n");
// 模拟业务操作
sleep(5);
// 释放锁
reply = redisCommand(redis_conn, "DEL %s", LOCK_KEY);
if (reply == NULL || reply->type == REDIS_REPLY_ERROR || reply->integer != 1) {
printf("释放锁失败\n");
exit(1);
}
printf("释放锁成功\n");
// 关闭Redis连接
redisFree(redis_conn);
exit(0);
} else if (child_pid > 0) {
// 等待子进程结束
waitpid(child_pid, &status, 0);
if (WIFEXITED(status)) {
printf("子进程正常结束\n");
} else if (WIFSIGNALED(status)) {
printf("子进程异常结束\n");
}
} else {
printf("创建子进程失败\n");
exit(1);
}
return 0;
}
```
在这个示例中,使用了 hiredis 库来连接 Redis,并通过 SETNX 和 EXPIRE 命令实现分布式锁的获取和释放。主进程创建一个子进程,子进程尝试获取锁并进行业务操作,然后释放锁。主进程等待子进程的结束并打印相应信息。
注意:这只是一个简单的示例,实际应用中可能需要考虑更多的场景,比如锁的重入、超时处理等。<span class="em">1</span><span class="em">2</span><span class="em">3</span>
#### 引用[.reference_title]
- *1* *2* *3* [分布式锁_Redis分布式锁+Redisson分布式锁+Zookeeper分布式锁+Mysql分布式锁(原版)](https://blog.csdn.net/guan1843036360/article/details/127827270)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"]
[ .reference_list ]
阅读全文