redis cluster集群方案詳解

?1 概要介紹

1.1 應用場景

緩存:相對靜態(tài)、或變化緩慢的數(shù)據(jù),可以利用緩存降低數(shù)據(jù)庫IO壓力,提升性能

分布式鎖:集群環(huán)境下對同一個資源的競爭,可借助redis來實現(xiàn)對資源加鎖。可查閱redis官方redlock相關介紹

秒殺:在redis中進行預處理,充當緩沖,將處理結(jié)果延遲持久化到數(shù)據(jù)庫。規(guī)避高并發(fā)對DB的壓力

計算器:每次操作加1,redis天然支持計數(shù)的api操作

消息隊列:功能太簡單,一般不用

分布式session

限數(shù):每60秒獲取一次驗證碼,設置key、value、失效時間1分鐘到redis,每次獲取校驗碼進行先驗證redis是否有值即可

防爬蟲緩存穿透:

請求透過緩存層,直接命中DB,并發(fā)量大,造成DB層宕機

造成緩存穿透的基本原因有兩個。第一,自身業(yè)務代碼或者數(shù)據(jù)出現(xiàn)問 題,第二,一些惡意攻擊、爬蟲等造成大量空命中。 解決方案:在redis中保存失效期較短的空緩存。

1.2 不適合做什么

不適合用來做長期持久化數(shù)據(jù)

不適合用來做大數(shù)據(jù)量的頻繁存取,容易阻塞。適合短頻快的數(shù)據(jù)存取。

1.3數(shù)據(jù)結(jié)構

key-value鍵值對,value的數(shù)據(jù)類型包括:string、hash、set、zset(有序集合)、list等。redis是用C語言編寫的,如果對數(shù)據(jù)結(jié)構與算法還有印象的同學應該很親切。

常用的string 與hash,學會運用這兩類即可。

1.4單線程架構

redis接收客戶端的請求,把執(zhí)行命令插入一個隊列中,然后逐個被執(zhí)行。因為是單線程架構,所以不會有兩個命令在同一時刻執(zhí)行,redis他自身是線程安全的,這個特性很重要。

單線程為什么還這么快?redis的命令操作都是在內(nèi)存中進行,可以在納秒級別就處理完,使用了epoll非阻塞IO(想深入了解可以去查閱網(wǎng)上資料),單線程也就省卻了線程切換的CPU消耗。

了解單線程模型有助于我們做出更好的部署決策,如果在一臺多核主機上部署一個實例,太浪費CPU資源了。

?

2 架構原理

redis官方集群模式包括:單節(jié)點、一主一從,一主多從、哨兵模式、cluster模式等。開源方案codis實現(xiàn)的代理模式等等。

其他模式的優(yōu)缺點這里就不講了,這里講講cluster模式的優(yōu)點:

高性能:客戶端直連模式,沒有代理轉(zhuǎn)發(fā)。redis自身處理客戶端請求飛快,納秒級別

高并發(fā):普通的硬件配置,單節(jié)點可支持10WQPS

高可用:單個主節(jié)點宕機不影響整體集群的服務能力,可通過自動健康檢查、故障轉(zhuǎn)移將從節(jié)點升級為主節(jié)點

可彈性擴展:在線水平擴展數(shù)據(jù)容量、吞吐量、主從節(jié)點個數(shù)等

2.1 redis cluster方案架構圖


?2.2 方案說明

以上圖所示的三主三從集群為例,每個主節(jié)點處理各自的數(shù)據(jù),提供讀寫能力,從節(jié)點異步復制主節(jié)點的數(shù)據(jù)。假設給每個redis實例分配了8G的最大內(nèi)存,總的數(shù)據(jù)容量大小為24G(如果想繼續(xù)擴充數(shù)據(jù)容量,繼續(xù)加主節(jié)點)。單個redis實例的最大內(nèi)存不建議超過10G。

2.3 數(shù)據(jù)分布

cluster集群方案,采用的是虛擬槽分區(qū),槽范圍是0-16383,有16384個槽。集群中有3個主節(jié)點,每個節(jié)點大致負責5500個槽的讀寫,節(jié)點會維護自身負責的虛擬槽。

鍵所對應的哈希值通過如下公式計算:CRC16(key)%16384。目前常見的redisson、jedis等客戶端工具都已實現(xiàn),推薦使用redisson,jedis可以棄療。

redisson客戶端初始化的時候,會加載集群的元數(shù)據(jù)信息,創(chuàng)建連接池。包括IP 端口 哈希槽的映射關系。

在實際使用時,set key value命令會計算hash值,把key-value設置到對應的主節(jié)點上。

?2.4 數(shù)據(jù)持久化 RDB VS AOF

?2.4.1 RDB全量持久化

父進程執(zhí)行fork操作創(chuàng)建子進程,fork操作過程中父進程會阻塞,阻塞的時間跟所用內(nèi)存大小成正比,要求redis實例最大不要超過10G。由子進程去創(chuàng)建最新的RDB文件。

什么時候會發(fā)生持久化操作呢?1、人工執(zhí)行bgsave命令;2、達到配置文件中指定的約束條件

rdb文件放置在哪里? dbfilename 配置項指定

RDB的優(yōu)點:redis重啟恢復數(shù)據(jù)的時候速度很快

RDB的缺點: 無法實時持久化,fork會阻塞父進程

關閉RDB配置 :save “”

2.4.2 AOF增量持久化

默認是關閉的,配置 appendonly yes 開啟。appendfilename 指定文件名,保存的路徑與RDB一樣,通過dir指定

所有的操作命令會追加到aof_buf緩沖區(qū),根據(jù)策略appendsync everysec 每秒同步到磁盤上的AOF文件。

aof文件重寫壓縮過程中也會執(zhí)行fork操作。

redis重啟時可以加載aof文件進行數(shù)據(jù)恢復。

RDB與AOF各有優(yōu)劣,根據(jù)實際業(yè)務場景選擇合適的方案,甚至不用。

2.4.3 ?redis啟動過程的數(shù)據(jù)恢復

2.4 集群通信

每個節(jié)點會隨機對集群中的部分節(jié)點發(fā)生ping命令,判斷其他節(jié)點的健康狀態(tài),

3 集群安裝與配置

3.1 關鍵配置

protected-mode no 允許外部主機訪問

cluster-enabled yes ?配置為cluster 模式

cluster-config-file nodes-6379.conf? 集群節(jié)點配置信息,包括nodeid,集群信息。此文件非常關鍵,要確保故障轉(zhuǎn)移或者重啟的時候此文件還在,所以如果在docker環(huán)境下要外掛到外部存儲

cluster-node-timeout 2000 ?節(jié)點連接超時,如果集群規(guī)模小,都在同一個網(wǎng)絡環(huán)境下,可以配置的短些,更快的做故障轉(zhuǎn)移

slowlog-log-slower-than ?慢查詢?nèi)罩荆糜谛阅芊治觯a(chǎn)環(huán)境可設置為1000(微妙)

slowlog-max-len ? 保存慢查詢的隊列長度 ,設置為1000

maxclients ?集群支持的最大連接 50000

cluster-slave-validity-factor?設置為0,如果master slave都掛掉,slave跟master失聯(lián)又超過這個數(shù)值*timeout的數(shù)值,就不會發(fā)起選舉了。如果設置為0,就是永遠都會嘗試發(fā)起選舉,嘗試從slave變?yōu)閙ater

cluster-require-full-coverage??設置為no,默認為yes,故障發(fā)現(xiàn)到自動 完成轉(zhuǎn)移期間整個集群是不可用狀態(tài),對于大多數(shù)業(yè)務無法容忍這種情況, 因此要設置為no,當主節(jié)點故障時只影 響它負責槽的相關命令執(zhí)行,不會影響其他主節(jié)點的可用性

save “” ?通用配置,關閉RDB持久化,只使用AOF。

maxmemory 8GBRedis默認無限使用服務器內(nèi)存,為防止極端情況下導致系統(tǒng)內(nèi)存耗 盡,建議所有的Redis進程都要配置maxmemory,要保證機器本身有30%左右的閑置內(nèi)存

maxmemory-policy ?volatile-lru?內(nèi)存剔除策略

logfile “”? 默認為空,則在控制臺打印,否則輸出日志到指定的log文件

3.2 注意事項

操作系統(tǒng)本身的最大連接數(shù)設置open ?files建議設置為65535,redis的最大連接數(shù)受此限制。

ulimit -a 可以查看所有配置

修改: vim /etc/security/limits.conf

主節(jié)點平均分配到不同的機器上,否則容易造成單點故障以及復制風暴。

操作系統(tǒng)關閉THP:

vim /etc/rc.d/rc.local

增加下列內(nèi)容:

if test -f /sys/kernel/mm/transparent_hugepage/enabled; then

echo never > /sys/kernel/mm/transparent_hugepage/enabled

fi

if test -f /sys/kernel/mm/transparent_hugepage/defrag; then

echo never > /sys/kernel/mm/transparent_hugepage/defrag

fi

然后給rc.local添加可執(zhí)行權限:chmod +x /etc/rc.d/rc.local。重啟生效


slave-read-only集群模式下無效,cluster集群模式下,從節(jié)點默認是處于冷備的狀態(tài),不提供讀寫服務。需要客戶端去開啟從節(jié)點的readonly,推薦用redisson java客戶端工具,jedis不支持。

redis總共16個數(shù)據(jù)庫,默認使用第0個數(shù)據(jù)庫,集群模式下只能用第0數(shù)據(jù)庫。多數(shù)據(jù)庫功能就算單節(jié)點部署方案也不建議使用,這點知道即可。

3.3 修改linux連接數(shù)限制

切換到root用戶修改配置sysctl.conf?

vim /etc/sysctl.conf

添加配置:

vm.max_map_count=655360

vm.overcommit_memory=1

net.core.somaxconn= 1024

vim /etc/security/limits.conf?

添加

* soft?nofile?65536

* hard?nofile?65536

* soft nproc 65536

* hard nproc 65536

vi /etc/security/limits.d/20-nproc.conf?

?#加大普通用戶限制 也可以改為unlimited

?* soft nproc 40960?

?root soft nproc unlimited


reboot或者重新登錄

3.4 linux環(huán)境下安裝

wget?http://download.redis.io/releases/redis-4.0.7.tar.gz

tar xzf?redis-4.0.7.tar.gz

cd?redis-4.0.7

yum -y install gcc

編譯安裝:make install?

Redis編譯安裝之后,src和/usr/local/bin目錄下多了幾個以redis開頭可執(zhí)行文 件

啟動redis:

cd? /redis/data? 當前工作目錄是默認的根目錄

redis-server ?/redis/data/redis.conf ??

?配置文件方式啟動方式,也是推薦的方案,將定制的配置文件放在/redis/data目錄,

?/redis/data此時就是根目錄

停止redis:redis-cli shutdown ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?不要用kill,太粗暴,可能導致數(shù)據(jù)丟失

集群至少需要6節(jié)點,3主3從,準備至少6個節(jié)點。

3.4.1?啟動節(jié)點

啟動6個節(jié)點:redis-server redis.conf?,確保該目錄下沒有AOF RDB文件,否則不能加入集群。


3.4.2?節(jié)點握手

? 節(jié)點彼此之間通過gossip協(xié)議(“謠言”協(xié)議了解一下),一個節(jié)點連接其他5個節(jié)點即可。

127.0.0.1:6379>cluster meet 127.0.0.1 6382?

>cluster ?nodes ?查看集群信息

>cluster info ?查看集群狀態(tài),此時不可用

3.4.3? 分配槽

redis-cli -h 127.0.0.1 -p 6379 cluster addslots {0...5461}

3.4.4 分配子節(jié)點

127.0.0.1:6382>cluster replicate cfb28ef1deee4e0fa78da86abe5d24566744411e?

3.5 借助redis-trib工具進行自動化創(chuàng)建集群

手工創(chuàng)建集群過程很繁瑣。官方提供了redis-trib.rb工具來實現(xiàn)集群管理。

3.5.1 ruby環(huán)境準備

-- 下載ruby?

wget https:// cache.ruby-lang.org/pub/ruby/2.3/ruby-2.3.1.tar.gz?

-- 安裝ruby?

tar xvf ruby-2.3.1.tar.gz?

cd??ruby-2.3.1

./configure -prefix=/usr/local/ruby?

make

make install?

cd /usr/local/ruby?

sudo cp bin/ruby /usr/local/bin?

sudo cp bin/gem /usr/local/bin

--安裝rubygem redis依賴

wget http:// rubygems.org/downloads/redis-3.3.0.gem?

gem install -l redis-3.3.0.gem?

如果提示缺少zlib ,


進入ruby項目文件夾:

#cd ext/zlib

#ruby ./extconf.rb

#make?

#make install

---安裝redis-trib.rb

sudo cp /{redis_home}/src/redis-trib.rb /usr/local/bin

--測試是否安裝成功

>redis-trib.rb?

3.5.2 啟動6個節(jié)點

3.5.3 創(chuàng)建集群

redis-trib.rb create --replicas 1 127.0.0.1:6481 127.0.0.1:6482 127.0.0.1:6483 127.0.0.1:6484 127.0.0.1:6485 127.0.0.1:6486

出現(xiàn)提示創(chuàng)建3主3從集群的時候,輸入yes即可。

3.6 腳本自動化

運維人員可以將腳本做一些完善,在linux下自動化創(chuàng)建安裝redis節(jié)點,自動化創(chuàng)建集群

4 集群在線擴容

1)準備新節(jié)點

2)?加入集群?

3)遷移槽和數(shù)據(jù)

在生產(chǎn)環(huán)境可以用redis-trib.rb工具來做集群擴容,做到半自動化,建議運維人員在測試環(huán)境先摸透整個流程。


添加節(jié)點:

redis-trib.rb add-node 127.0.0.1:6385 127.0.0.1:6379?

遷移槽:

1、redis-trib.rb reshard 10.42.202.243:6000 ? #任意指定一個節(jié)點,以便獲取集群信息

2、接下來要你輸入需要遷移的槽數(shù)量 :2000

3、輸入目標節(jié)點的nodeid

4、輸入源節(jié)點的ID ,要是主節(jié)點的id,輸入done表示結(jié)束

5、輸入yes,開搞吧

6、為新增的主節(jié)點添加slave:

redis-trib.rb add-node --slave ip:port masterip:port

5 故障轉(zhuǎn)移原理

5.1 集群內(nèi)部通信

集群內(nèi)部采用gossip協(xié)議進行通信,節(jié)點之間交換彼此的信息,使用了單獨的TCP端口,默認是6379+10000。詳細過程請閱讀“redis開發(fā)與運維.PDF”


5.2 故障發(fā)現(xiàn)

當集群少量節(jié)點出行故障時,能通過自動化故障轉(zhuǎn)移保證集群的高可用。那是怎么發(fā)現(xiàn)故障節(jié)點的呢?

包括兩個環(huán)節(jié):主觀下線pfail (單個節(jié)點認為另一個節(jié)點下線,將它標記為pfail) 、客觀下線 fail(節(jié)點彼此之間通過信息交換,大家達成共識了,都認為該節(jié)點下線,標記為fail)

這里所說的“大家達成共識了”,指的是主節(jié)點投票超過半數(shù)以上,就是說如果是3主3從集群,至少要有2個主節(jié)點認為該節(jié)點下線,從節(jié)點沒資格參與投票。

如果是主節(jié)點,就要進行故障轉(zhuǎn)移了

5.3 故障轉(zhuǎn)移?

主節(jié)點發(fā)生故障了,從節(jié)點收到fail廣播消息,從節(jié)點會嘗試發(fā)起選舉

其他主節(jié)點接收到選舉消息,會進行投票,超過半數(shù)以上通過才可以完成選舉。

(詳細過程請閱讀redis開發(fā)與運維.pdf)

故障主節(jié)點也算在投票數(shù)內(nèi),假設集群內(nèi)節(jié)點規(guī)模是3主3從,其中有2 個主節(jié)點部署在一臺機器上,當這臺機器宕機時,由于從節(jié)點無法收集到 3/2+1個主節(jié)點選票將導致故障轉(zhuǎn)移失敗。這個問題也適用于故障發(fā)現(xiàn)環(huán) 節(jié)。因此部署集群時所有主節(jié)點最少需要部署在3臺物理機上才能避免單點 問題。

6 集群運維注意事項

? 在上線之前進行故障轉(zhuǎn)移測試,及時發(fā)現(xiàn)問題,鍛煉掌握集群運維能力

?學會從cpu ?網(wǎng)絡 存儲 日志各個層面進行日常運維

6.1 常用命令

redis-cli -p 6000 -h host?

redis-cli -p 6000 shutdown

cluster nodes??

6.2 基準測試工具

redis-benchmark -h 11.4.74.44? -p 6000? -c 100 -n 20000

基準測試的數(shù)據(jù)由于key value? 大小 網(wǎng)絡因素等,并不能直接等同于生產(chǎn)環(huán)境的qps,但是可以做大致參考。

6.3 運維案例

用戶報的一個故障:

org.redisson.client.RedisException:?ERR?max?number?of?clients?reached.?channel:?[id:?0x136f239c,?L:/11.13.49.91:34666?-?R:/11.4.74.47:6000]?command:?(READONLY),?params:?[]

排查過程:首先確認內(nèi)核配置無誤

/etc/sysctl.conf ?fs.file-max=65535

ulimit -n ?最大文件描述符? ?65536

redis.conf配置:max clients 50000 ? ?timeout ?0

使用redis-cli工具:info ?clients查看當前客戶端連接數(shù) ?,發(fā)現(xiàn)快占滿了,接近5w,wtf這怎么可能。。

查看所有client:client list

查看timeout配置:config get timeout? ? 0 ,這是問題根源之一

臨時性設置timeout:config set timeout 150

monitor命令可以顯示當前redis執(zhí)行的命令,發(fā)現(xiàn)同一個ip有很多重復性的占用連接。

反查這些ip實例的日志,發(fā)現(xiàn)應用程序不能正常啟動,一直重啟,導致一直重復創(chuàng)建連接,又缺乏超時釋放的策略

先干掉不能啟動的幾個應用實例。

解決方案:一定要設置redis.conf的timeout 60,不能讓空閑連接占著茅坑不拉屎,把所有連接耗盡。容器一定要配置健康檢查,如果發(fā)現(xiàn)反復重啟的,要格外關注。

舉一反三:rocketmq、kafka、es呢


7 ?針對開發(fā)人員

?7.1 熟悉redis架構原理

別拿他當黑盒用,了解哪些操作會導致redis阻塞。否則就是給自己挖坑

7.2 使用redisson 而不是jedis

很傻瓜化的一個java客戶端,磨刀不誤砍柴工,多查看官網(wǎng)api文檔,如果你用的很辛苦,那可能是你的姿勢不對

?7.3 redis使用規(guī)范

在實際生產(chǎn)環(huán)境中,不可能給每個應用都建一套redis集群,一般是按業(yè)務領域分。

為了防止key沖突,各個應用直接約定key值加上約定的前綴來區(qū)分。


7.4 批量設置

在cluster模式下,對mset? mget命令限制很多,要求批量設置的key 都在同一臺redis實例上,否則報異常。

有什么替代方案呢?用hashmap

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,797評論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,179評論 3 414
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,628評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,642評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,444評論 6 405
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 54,948評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,040評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,185評論 0 287
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,717評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 40,602評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,794評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,316評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 44,045評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,418評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,671評論 1 281
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,414評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,750評論 2 370

推薦閱讀更多精彩內(nèi)容