一、樂觀鎖概述
樂觀鎖是一種並發控制機制,它假定在數據變更時不會有衝突發生,因此不會像悲觀鎖一樣在操作時先加鎖。
在Redis中,樂觀鎖常用於多線程、多用戶同時操作同一個數據的場景,例如秒殺、搶購、投票等。
二、Redis實現樂觀鎖的常用方法
1. WATCH/MULTI/EXEC
Redis通過 WATCH/MULTI/EXEC 指令實現樂觀鎖。這種方式基於事務,所以必須使用 Redis 2.0.0 版本以上才能使用。它的具體實現步驟如下:
// PHP代碼示例
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
$key = 'goods_1001';
$quantity = 10;
$redis->watch($key); // 監聽商品庫存
$currentQuantity = $redis->get($key);
if ($currentQuantity unwatch(); // 取消監聽
echo '庫存不足';
} else {
$redis->multi(); // 開啟事務
$redis->decrby($key, $quantity); // 減少商品庫存
$redis->exec(); // 提交事務
echo '扣減成功';
}
2. Redis分布式鎖
分布式鎖基於SETNX(SET if Not eXists)指令實現。使用 SETNX 可以在Redis中創建一個不存在的Key,如果該Key已存在,則設置失敗,返回0,設置成功返回1。
在使用Redis分布式鎖時,應該注意以下問題:
(1)由於每個客戶端都是獨立的,所以在執行一個操作時可能會有多個客戶端同時重複執行。我們需要解決相互之間的干擾。
(2)如果Redis分布式鎖的Key在SETNX後會因某種原因過期,那麼仍然存在多個進程同時競爭鎖的情況。
// PHP代碼示例
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
$key = 'lock_key';
$value = uniqid(); // 生成唯一值作為鎖的值
$expire = 10; // 鎖過期時間,單位為秒
if ($redis->setnx($key, $value)) { // SETNX創建Key
$redis->expire($key, $expire); // 設置Key過期時間
echo '加鎖成功';
// TODO:執行業務邏輯
$redis->del($key); // 釋放鎖
} else {
echo '加鎖失敗';
}
三、實戰應用:Redis實現秒殺系統
下面結合Redis實現秒殺系統,以更形象地認識樂觀鎖。
假設有100個商品,每個用戶最多能夠購買3個,當庫存不足時不允許繼續購買。
系統的實現思路如下:
(1)使用 Redis 分布式鎖保證操作的同步。
(2)在 Redis 中存儲每個用戶的購買次數。
(3)通過 Redis 事務,先鎖定 Redis 中的庫存和用戶購買次數,再判斷庫存和用戶購買次數是否充足,若充足扣減庫存和購買次數。
// PHP代碼示例
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
$key = 'goods_1001';
$quantity = 10;
$user_id = 101;
$user_key = "user_{$user_id}";
$user_limit = 3;
$lock_key = 'lock_key';
$lock_expire = 10;
// 獲取分布式鎖
while (!$redis->setnx($lock_key, uniqid())) {
usleep(1000); // 暫停1ms再次嘗試
}
$redis->expire($lock_key, $lock_expire);
// 判斷商品庫存是否充足
$redis->watch($key, $user_key);
$currentQuantity = $redis->get($key);
$currentUserLimit = $redis->get($user_key) ?? 0;
if ($currentQuantity >= $quantity && $currentUserLimit multi();
$redis->incrby($user_key, 1); // 記錄用戶購買次數+1
$redis->decrby($key, $quantity); // 商品庫存-10
// 執行Redis事務
$res = $redis->exec();
if ($res) {
echo '購買成功';
} else {
echo '購買失敗';
}
} else {
echo '購買失敗,庫存不足或購買次數已達上限';
}
$redis->del($lock_key); // 釋放分布式鎖
總結
本文詳細介紹了Redis樂觀鎖的實現方式,其中包括使用 Redis 事務和 Redis 分布式鎖兩種方式。在實際應用中,需要根據具體業務場景選擇合適的方式來實現樂觀鎖。希望能對讀者有所幫助。
原創文章,作者:ASBQA,如若轉載,請註明出處:https://www.506064.com/zh-hant/n/372658.html
微信掃一掃
支付寶掃一掃