淺談Redis分片集群搭建及其原理
1.Redis分片集群
1.1.搭建分片集群
主從和哨兵可以解決高可用、高并發(fā)讀的問題。但是依然有兩個(gè)問題沒有解決:
- 海量數(shù)據(jù)存儲(chǔ)問題
- 高并發(fā)寫的問題
使用分片集群可以解決上述問題,如圖:
分片集群特征:
- 集群中有多個(gè)master,每個(gè)master保存不同數(shù)據(jù)
- 每個(gè)master都可以有多個(gè)slave節(jié)點(diǎn)
- master之間通過ping監(jiān)測彼此健康狀態(tài)
- 客戶端請(qǐng)求可以訪問集群任意節(jié)點(diǎn),最終都會(huì)被轉(zhuǎn)發(fā)到正確節(jié)點(diǎn)
分片集群需要的節(jié)點(diǎn)數(shù)量較多,這里我們搭建一個(gè)最小的分片集群,包含3個(gè)master節(jié)點(diǎn),每個(gè)master包含一個(gè)slave節(jié)點(diǎn),結(jié)構(gòu)如下:
這里我們會(huì)在同一臺(tái)虛擬機(jī)中開啟6個(gè)redis實(shí)例,模擬分片集群,信息如下:
IP | PORT | 角色 |
---|---|---|
192.168.150.101 | 7001 | master |
192.168.150.101 | 7002 | master |
192.168.150.101 | 7003 | master |
192.168.150.101 | 8001 | slave |
192.168.150.101 | 8002 | slave |
192.168.150.101 | 8003 | slave |
1.2.準(zhǔn)備實(shí)例和配置
刪除之前的7001、7002、7003這幾個(gè)目錄,重新創(chuàng)建出7001、7002、7003、8001、8002、8003目錄:
# 進(jìn)入/tmp目錄 cd /tmp # 刪除舊的,避免配置干擾 rm -rf 7001 7002 7003 # 創(chuàng)建目錄 mkdir 7001 7002 7003 8001 8002 8003
在/tmp下準(zhǔn)備一個(gè)新的redis.conf文件,內(nèi)容如下:
port 6379 # 開啟集群功能 cluster-enabled yes # 集群的配置文件名稱,不需要我們創(chuàng)建,由redis自己維護(hù) cluster-config-file /tmp/6379/nodes.conf # 節(jié)點(diǎn)心跳失敗的超時(shí)時(shí)間 cluster-node-timeout 5000 # 持久化文件存放目錄 dir /tmp/6379 # 綁定地址 bind 0.0.0.0 # 讓redis后臺(tái)運(yùn)行 daemonize yes # 注冊(cè)的實(shí)例ip replica-announce-ip 192.168.150.101 # 保護(hù)模式 protected-mode no # 數(shù)據(jù)庫數(shù)量 databases 1 # 日志 logfile /tmp/6379/run.log
將這個(gè)文件拷貝到每個(gè)目錄下:
# 進(jìn)入/tmp目錄 cd /tmp # 執(zhí)行拷貝 echo 7001 7002 7003 8001 8002 8003 | xargs -t -n 1 cp redis.conf
修改每個(gè)目錄下的redis.conf,將其中的6379修改為與所在目錄一致:
# 進(jìn)入/tmp目錄 cd /tmp # 修改配置文件 printf '%s\n' 7001 7002 7003 8001 8002 8003 | xargs -I{} -t sed -i 's/6379/{}/g' {}/redis.conf
1.3.啟動(dòng)
因?yàn)橐呀?jīng)配置了后臺(tái)啟動(dòng)模式,所以可以直接啟動(dòng)服務(wù):
# 進(jìn)入/tmp目錄 cd /tmp # 一鍵啟動(dòng)所有服務(wù) printf '%s\n' 7001 7002 7003 8001 8002 8003 | xargs -I{} -t redis-server {}/redis.conf
通過ps查看狀態(tài):
ps -ef | grep redis
發(fā)現(xiàn)服務(wù)都已經(jīng)正常啟動(dòng):
如果要關(guān)閉所有進(jìn)程,可以執(zhí)行命令:
ps -ef | grep redis | awk '{print $2}' | xargs kill
或者(推薦這種方式):
printf '%s\n' 7001 7002 7003 8001 8002 8003 | xargs -I{} -t redis-cli -p {} shutdown
1.4.創(chuàng)建集群
雖然服務(wù)啟動(dòng)了,但是目前每個(gè)服務(wù)之間都是獨(dú)立的,沒有任何關(guān)聯(lián)。
我們需要執(zhí)行命令來創(chuàng)建集群,在Redis5.0之前創(chuàng)建集群比較麻煩,5.0之后集群管理命令都集成到了redis-cli中。
1)Redis5.0之前
Redis5.0之前集群命令都是用redis安裝包下的src/redis-trib.rb來實(shí)現(xiàn)的。因?yàn)閞edis-trib.rb是由ruby語言編寫的所以需要安裝ruby環(huán)境。
# 安裝依賴 yum -y install zlib ruby rubygems gem install redis
然后通過命令來管理集群:
# 進(jìn)入redis的src目錄 cd /tmp/redis-6.2.4/src # 創(chuàng)建集群 ./redis-trib.rb create --replicas 1 192.168.150.101:7001 192.168.150.101:7002 192.168.150.101:7003 192.168.150.101:8001 192.168.150.101:8002 192.168.150.101:8003
2)Redis5.0以后
我們使用的是Redis6.2.4版本,集群管理以及集成到了redis-cli中,格式如下:
redis-cli --cluster create --cluster-replicas 1 192.168.150.101:7001 192.168.150.101:7002 192.168.150.101:7003 192.168.150.101:8001 192.168.150.101:8002 192.168.150.101:8003
命令說明:
redis-cli --cluster
或者./redis-trib.rb
:代表集群操作命令create
:代表是創(chuàng)建集群--replicas 1
或者--cluster-replicas 1
:指定集群中每個(gè)master的副本個(gè)數(shù)為1,此時(shí)節(jié)點(diǎn)總數(shù) ÷ (replicas + 1)
得到的就是master的數(shù)量。因此節(jié)點(diǎn)列表中的前n個(gè)就是master,其它節(jié)點(diǎn)都是slave節(jié)點(diǎn),隨機(jī)分配到不同master
運(yùn)行后的樣子:
這里輸入yes,則集群開始創(chuàng)建:
通過命令可以查看集群狀態(tài):
redis-cli -p 7001 cluster nodes
1.5.測試
嘗試連接7001節(jié)點(diǎn),存儲(chǔ)一個(gè)數(shù)據(jù):
# 連接 redis-cli -p 7001 # 存儲(chǔ)數(shù)據(jù) set num 123 # 讀取數(shù)據(jù) get num # 再次存儲(chǔ) set a 1
結(jié)果悲劇了:
這是因?yàn)閍鍵在別的節(jié)點(diǎn)set過了
集群操作時(shí),需要給redis-cli
加上-c
參數(shù)才可以:
redis-cli -c -p 7001
這次可以了:
2.散列插槽原理
2.1.插槽原理
Redis會(huì)把每一個(gè)master節(jié)點(diǎn)映射到0~16383共16384個(gè)插槽(hash slot)上,查看集群信息時(shí)就能看到:
數(shù)據(jù)key不是與節(jié)點(diǎn)綁定,而是與插槽綁定。redis會(huì)根據(jù)key的有效部分計(jì)算插槽值,分兩種情況:
- key中包含"{}",且“{}”中至少包含1個(gè)字符,“{}”中的部分是有效部分
- key中不包含“{}”,整個(gè)key都是有效部分
例如:key是num,那么就根據(jù)num計(jì)算,如果是{zqd}num,則根據(jù)zqd計(jì)算。計(jì)算方式是利用CRC16算法得到一個(gè)hash值,然后對(duì)16384取余,得到的結(jié)果就是slot值。
如圖,在7001這個(gè)節(jié)點(diǎn)執(zhí)行set a 1時(shí),對(duì)a做hash運(yùn)算,對(duì)16384取余,得到的結(jié)果是15495,因此要存儲(chǔ)到103節(jié)點(diǎn)。
到了7003后,執(zhí)行get num
時(shí),對(duì)num做hash運(yùn)算,對(duì)16384取余,得到的結(jié)果是2765,因此需要切換到7001節(jié)點(diǎn)
2.2.小結(jié)
Redis如何判斷某個(gè)key應(yīng)該在哪個(gè)實(shí)例?
- 將16384個(gè)插槽分配到不同的實(shí)例
- 根據(jù)key的有效部分計(jì)算哈希值,對(duì)16384取余
- 余數(shù)作為插槽,尋找插槽所在實(shí)例即可
如何將同一類數(shù)據(jù)固定的保存在同一個(gè)Redis實(shí)例?
- 這一類數(shù)據(jù)使用相同的有效部分,例如key都以{typeId}為前綴
3.集群伸縮
redis-cli --cluster提供了很多操作集群的命令,可以通過下面方式查看:
比如,添加節(jié)點(diǎn)的命令:
3.1.需求分析
需求:向集群中添加一個(gè)新的master節(jié)點(diǎn),并向其中存儲(chǔ) num = 10
- 啟動(dòng)一個(gè)新的redis實(shí)例,端口為7004
- 添加7004到之前的集群,并作為一個(gè)master節(jié)點(diǎn)
- 給7004節(jié)點(diǎn)分配插槽,使得num這個(gè)key可以存儲(chǔ)到7004實(shí)例
這里需要兩個(gè)新的功能:
- 添加一個(gè)節(jié)點(diǎn)到集群中
- 將部分插槽分配到新插槽
3.2.創(chuàng)建新的redis實(shí)例
創(chuàng)建一個(gè)文件夾:
mkdir 7004
拷貝配置文件:
cp redis.conf /7004
修改配置文件:
sed /s/6379/7004/g 7004/redis.conf
啟動(dòng)
redis-server 7004/redis.conf
3.3.添加新節(jié)點(diǎn)到redis
添加節(jié)點(diǎn)的語法如下:
執(zhí)行命令:
redis-cli --cluster add-node 192.168.150.101:7004 192.168.150.101:7001
通過命令查看集群狀態(tài):
redis-cli -p 7001 cluster nodes
如圖,7004加入了集群,并且默認(rèn)是一個(gè)master節(jié)點(diǎn):
但是,可以看到7004節(jié)點(diǎn)的插槽數(shù)量為0,因此沒有任何數(shù)據(jù)可以存儲(chǔ)到7004上
3.4.轉(zhuǎn)移插槽
我們要將num存儲(chǔ)到7004節(jié)點(diǎn),因此需要先看看num的插槽是多少:
如上圖所示,num的插槽為2765.
我們可以將0~3000的插槽從7001轉(zhuǎn)移到7004,命令格式如下:
具體命令如下:
建立連接:
得到下面的反饋:
詢問要移動(dòng)多少個(gè)插槽,我們計(jì)劃是3000個(gè):
新的問題來了:
那個(gè)node來接收這些插槽??
顯然是7004,那么7004節(jié)點(diǎn)的id是多少呢?
復(fù)制這個(gè)id,然后拷貝到剛才的控制臺(tái)后:
這里詢問,你的插槽是從哪里移動(dòng)過來的?
- all:代表全部,也就是三個(gè)節(jié)點(diǎn)各轉(zhuǎn)移一部分
- 具體的id:目標(biāo)節(jié)點(diǎn)的id
- done:沒有了
這里我們要從7001獲取,因此填寫7001的id:
填完后,點(diǎn)擊done,這樣插槽轉(zhuǎn)移就準(zhǔn)備好了:
確認(rèn)要轉(zhuǎn)移嗎?輸入yes:
然后,通過命令查看結(jié)果:
可以看到:
目的達(dá)成。
4.故障轉(zhuǎn)移
集群初識(shí)狀態(tài)是這樣的:
其中7001、7002、7003都是master,我們計(jì)劃讓7002宕機(jī)。
4.1.自動(dòng)故障轉(zhuǎn)移
當(dāng)集群中有一個(gè)master宕機(jī)會(huì)發(fā)生什么呢?
直接停止一個(gè)redis實(shí)例,例如7002:
redis-cli -p 7002 shutdown
1)首先是該實(shí)例與其它實(shí)例失去連接
2)然后是疑似宕機(jī):
3)最后是確定下線,自動(dòng)提升一個(gè)slave為新的master:
4)當(dāng)7002再次啟動(dòng),就會(huì)變?yōu)橐粋€(gè)slave節(jié)點(diǎn)了:
4.2.手動(dòng)故障轉(zhuǎn)移
利用cluster failover命令可以手動(dòng)讓集群中的某個(gè)master宕機(jī),切換到執(zhí)行cluster failover命令的這個(gè)slave節(jié)點(diǎn),實(shí)現(xiàn)無感知的數(shù)據(jù)遷移。其流程如下:
這種failover命令可以指定三種模式:
- 缺?。耗J(rèn)的流程,如圖1~6歩
- force:省略了對(duì)offset的一致性校驗(yàn)
- takeover:直接執(zhí)行第5歩,忽略數(shù)據(jù)一致性、忽略master狀態(tài)和其它master的意見
案例需求:在7002這個(gè)slave節(jié)點(diǎn)執(zhí)行手動(dòng)故障轉(zhuǎn)移,重新奪回master地位
步驟如下:
1)利用redis-cli連接7002這個(gè)節(jié)點(diǎn)
2)執(zhí)行cluster failover命令
如圖:
效果:
5.RedisTemplate訪問分片集群
RedisTemplate底層同樣基于lettuce實(shí)現(xiàn)了分片集群的支持,而使用的步驟與哨兵模式基本一致:
1)引入redis的starter依賴
2)配置分片集群地址
3)配置讀寫分離
與哨兵模式相比,其中只有分片集群的配置方式略有差異,如下:
spring: redis: cluster: nodes: - 192.168.150.101:7001 - 192.168.150.101:7002 - 192.168.150.101:7003 - 192.168.150.101:8001 - 192.168.150.101:8002 - 192.168.150.101:8003
到此這篇關(guān)于淺談Redis分片集群搭建及其原理的文章就介紹到這了,更多相關(guān)Redis分片集群搭建內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
基于redis實(shí)現(xiàn)定時(shí)任務(wù)的方法詳解
這篇文章主要給大家介紹了基于redis實(shí)現(xiàn)定時(shí)任務(wù)的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用redis具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧2019-08-08redis.conf中使用requirepass不生效的原因及解決方法
本文主要介紹了如何啟用requirepass,以及啟用requirepass為什么不會(huì)生效,從代碼層面分析了不生效的原因,以及解決方法,需要的朋友可以參考下2023-07-07Redis權(quán)限和訪問控制的實(shí)現(xiàn)示例
Redis提供了一些機(jī)制來保護(hù)敏感數(shù)據(jù)和限制對(duì)Redis服務(wù)器的訪問,本文主要介紹了Redis權(quán)限和訪問控制的實(shí)現(xiàn)示例,具有一定的參考價(jià)值,感興趣的可以了解一下2023-12-12Redis實(shí)戰(zhàn)之Lettuce的使用技巧詳解
Lettuce?是?Redis?的一款高級(jí)?Java?客戶端,與?Jedis?并列成為最熱門的客戶端之一,目前已成為?SpringBoot?2.0?版本默認(rèn)的?redis?客戶端。本文主要和大家講講Lettuce的使用技巧,感興趣的可以了解一下2022-12-12淺析PHP分布式中Redis實(shí)現(xiàn)Session的方法
這篇文章主要介紹了PHP分布式中Redis實(shí)現(xiàn)Session的方法,文中詳細(xì)介紹了兩種方法的使用方法,并給出了測試的示例代碼,有需要的朋友可以參考借鑒,下面來一起看看吧,2016-12-12