Redis入門(七):Redis分散式鎖(單機模式/叢集模式)
阿新 • • 發佈:2018-12-15
Redis 實現分散式鎖
單機模式的Redis分散式鎖
- 優缺點
- 實現比較輕,大多數時候能滿足需求;因為是單機單例項部署,如果redis服務宕機,那麼所有需要獲取分散式鎖的地方均無法獲取鎖,將全部阻塞,需要做好降級處理。
- 當鎖過期後,執行任務的程序還沒有執行完,但是鎖因為自動過期已經解鎖,可能被其它程序重新加鎖,這就造成多個程序同時獲取到了鎖,這需要額外的方案來解決這種問題。
- 實現程式碼
import redis.clients.jedis.Jedis; import java.util.Collections; public class JedisDistributedLock
叢集模式的Redis分散式鎖 Redlock
-
優缺點
- Redlock是Redis的作者antirez給出的叢集模式的Redis分散式鎖,它基於N個完全獨立的Redis節點
- 部分節點宕機,依然可以保證鎖的可用性
- 當某個節點宕機後,又立即重啟了,可能會出現兩個客戶端同時持有同一把鎖,如果節點設定了持久化,出現這種情況的機率會降低
- 和單機模式Redis鎖相比,實現難度要大一些
-
實現程式碼
- 搭建redis叢集
# 安裝指定版本的redis cd /opt wget http://download.redis.io/releases/redis-3.2.8.tar.gz tar xzf redis-3.2.8.tar.gz && rm redis-3.2.8.tar.gz cd redis-3.2.8 make
# 構建redis叢集 cd mkdir cluster-test cd cluster-test mkdir conf logs bin # 拷貝客戶端伺服器檔案 rsync -avp /opt/redis-3.2.8/src/redis-server bin/ rsync -avp /opt/redis-3.2.8/src/redis-cli bin/ # 配置檔案 for i in 7000 7001 7002 7003 7004 7005; do cat << EOF > conf/${i}.conf port ${i} cluster-enabled yes cluster-config-file nodes-${i}.conf cluster-node-timeout 5000 appendonly yes logfile "logs/${i}.log" appendfilename "appendonly-${i}.aof" EOF done # 啟動 cd ${HOME}/cluster-test for i in 7000 7001 7002 7003 7004 7005; do ./bin/redis-server ./conf/${i}.conf & done # 建立叢集 sudo apt-get install -y ruby rubygems gem install redis cd /opt/redis-3.2.8/src/ ./redis-trib.rb create --replicas 1 127.0.0.1:7000 127.0.0.1:7001 127.0.0.1:7002 127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005 # 測試 cd ${HOME}/cluster-test/ ./bin/redis-cli -c -p 7000 cluser nodes # 停止 #cd ${HOME}/cluster-test #for i in 7000 7001 7002 7003 7004 7005; do #./bin/redis-cli -p ${i} shutdown && echo "redis ${i} 已停止" #done
指令碼執行後,出現如下日誌,說明叢集搭建成功
>>> Creating cluster >>> Performing hash slots allocation on 6 nodes... Using 3 masters: 127.0.0.1:7000 127.0.0.1:7001 127.0.0.1:7002 Adding replica 127.0.0.1:7003 to 127.0.0.1:7000 Adding replica 127.0.0.1:7004 to 127.0.0.1:7001 Adding replica 127.0.0.1:7005 to 127.0.0.1:7002 M: d0e3588845a839052d9e611853740edd3b348966 127.0.0.1:7000 slots:0-5460 (5461 slots) master M: 4f5518e78c1ea1c25bab0d0147f12c0281fd5f96 127.0.0.1:7001 slots:5461-10922 (5462 slots) master M: 5724fb03c4527389be0d556c5dc5419a12d367c5 127.0.0.1:7002 slots:10923-16383 (5461 slots) master S: 1206f7a76b8050b10e2e602fad422faee95efdb5 127.0.0.1:7003 replicates d0e3588845a839052d9e611853740edd3b348966 S: 8f421f529c86cefbf033e1e3a1687a9767802bd2 127.0.0.1:7004 replicates 4f5518e78c1ea1c25bab0d0147f12c0281fd5f96 S: d94710251235efde7da4073cc4ff104d9298bd0f 127.0.0.1:7005 replicates 5724fb03c4527389be0d556c5dc5419a12d367c5 Can I set the above configuration? (type 'yes' to accept): yes >>> Nodes configuration updated >>> Assign a different config epoch to each node >>> Sending CLUSTER MEET messages to join the cluster Waiting for the cluster to join... >>> Performing Cluster Check (using node 127.0.0.1:7000) M: d0e3588845a839052d9e611853740edd3b348966 127.0.0.1:7000 slots:0-5460 (5461 slots) master 1 additional replica(s) S: 8f421f529c86cefbf033e1e3a1687a9767802bd2 127.0.0.1:7004 slots: (0 slots) slave replicates 4f5518e78c1ea1c25bab0d0147f12c0281fd5f96 S: 1206f7a76b8050b10e2e602fad422faee95efdb5 127.0.0.1:7003 slots: (0 slots) slave replicates d0e3588845a839052d9e611853740edd3b348966 M: 4f5518e78c1ea1c25bab0d0147f12c0281fd5f96 127.0.0.1:7001 slots:5461-10922 (5462 slots) master 1 additional replica(s) S: d94710251235efde7da4073cc4ff104d9298bd0f 127.0.0.1:7005 slots: (0 slots) slave replicates 5724fb03c4527389be0d556c5dc5419a12d367c5 M: 5724fb03c4527389be0d556c5dc5419a12d367c5 127.0.0.1:7002 slots:10923-16383 (5461 slots) master 1 additional replica(s) [OK] All nodes agree about slots configuration. >>> Check for open slots... >>> Check slots coverage... [OK] All 16384 slots covered.
- redis-cluster簡單叢集示例圖
- 使用Redission構建redLock
Redis叢集使用分片的方式儲存鍵值對,redis-cluster採用slot(槽)的概念,一共16384個槽位,分佈在叢集中的所有master例項上。儲存資料時,直接對key值做CRC16校驗後得到的校驗值對16384取模,將鍵值對儲存到對應的槽位所在的例項上。
import org.redisson.Redisson; import org.redisson.api.RAtomicLong; import org.redisson.api.RedissonClient; import org.redisson.config.Config; /** * Created by Haiyoung on 2018/8/11. */ public class RedissonManager { private static final String RAtomicName = "genId_"; private static Config config = new Config(); private static RedissonClient redisson = null; public static void init(){ try{ config.useClusterServers() .setScanInterval(200000)//設定叢集狀態掃描間隔 .setMasterConnectionPoolSize(10000)//設定對於master節點的連線池中連線數最大為10000 .setSlaveConnectionPoolSize(10000)//設定對於slave節點的連線池中連線數最大