<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          一文把Redis主從復(fù)制、哨兵、Cluster三種模式摸透

          共 13776字,需瀏覽 28分鐘

           ·

          2020-08-24 20:13

          概述

          Redis作為緩存的高效中間件,在我們?nèi)粘5拈_發(fā)中被頻繁的使用,今天就來說一說Redis的四種模式,分別是「單機(jī)版、主從復(fù)制、哨兵、以及集群模式」

          可能,在一般公司的程序員使用單機(jī)版基本都能解決問題,在Redis的官網(wǎng)給出的數(shù)據(jù)是10W QPS,這對(duì)于應(yīng)付一般的公司綽綽有余了,再不行就來個(gè)主從模式,實(shí)現(xiàn)讀寫分離,性能又大大提高。

          但是,我們作為有抱負(fù)的程序員,僅限于單機(jī)版和主從模式的crud是不行的,至少也要了解「哨兵」「集群模式」的原理,這樣面試的時(shí)候才能和面試官扯皮啊。

          之前對(duì)于Redis方面也是寫了比較多的文章,如:「Redis的基本數(shù)據(jù)類型和底層的實(shí)現(xiàn)原理、事務(wù)、持久化、分布式鎖、訂閱預(yù)發(fā)布」等,可以說是比較全面的教程了,這篇講完基本就全了,我會(huì)把文章系統(tǒng)的整理成pdf,分享給大家。

          先來個(gè)整理的Redis大綱,可能還有不完整的地方,若是有不完整的,可以在留言區(qū)補(bǔ)充,我后續(xù)會(huì)加進(jìn)去。

          單機(jī)

          單機(jī)版的Redis就比較簡(jiǎn)單了,基本90%的程序員都是用過,官網(wǎng)推薦操作Redis的第三方依賴庫是Jedis,在SpringBoot項(xiàng)目中,引入下面依賴就可以直接使用了:


          ???redis.clients
          ???jedis
          ???${jedis.version}

          優(yōu)點(diǎn)

          單機(jī)版的Redis也有很多優(yōu)點(diǎn),比如實(shí)現(xiàn)實(shí)現(xiàn)簡(jiǎn)單、維護(hù)簡(jiǎn)單、部署簡(jiǎn)單、維護(hù)成本非常低,不需要其它額外的開支。

          缺點(diǎn)

          但是,因?yàn)槭菃螜C(jī)版的Redis所以也存在很多的問題,比如最明顯的單點(diǎn)故障問題,一個(gè)Redis掛了,所有的請(qǐng)求就會(huì)直接打在了DB上。

          并且一個(gè)Redis抗并發(fā)數(shù)量也是有限的,同時(shí)要兼顧讀寫兩種請(qǐng)求,只要訪問量一上來,Redis就受不了了,另一方面單機(jī)版的Redis數(shù)據(jù)量存儲(chǔ)也是有限的,數(shù)據(jù)量一大,再重啟Redis的時(shí)候,就會(huì)非常的慢,所以局限性也是比較大的。

          實(shí)操搭建

          單機(jī)版的搭建教程,在網(wǎng)上有非常多的全面的教程,基本就是傻瓜式操作,特別是在本地搭建的話,基本使用yum快捷方便,幾句命令就搞定了,這里推薦一個(gè)搭建教程:https://www.cnblogs.com/ zuidongfeng/p/8032505.html。

          上面這個(gè)教程講的非常的詳細(xì),環(huán)境的搭建本來是運(yùn)維的工作,但是作為程序員嘗試自己去搭建環(huán)境還是有必要的,而且搭建環(huán)境這種東西,基本就是一勞永逸,搭建一次,可能下次換電腦或者重裝虛擬機(jī)才會(huì)再次搭建。

          這里也放出redis常用的redis.conf的配置項(xiàng),并且附帶注釋,看我是不是很暖男:

          daemonize?yes??//?設(shè)置后臺(tái)啟動(dòng),一般設(shè)置yes
          pidfile?/var/run/redis.pid?//?edis以守護(hù)進(jìn)程方式運(yùn)行時(shí),redis默認(rèn)會(huì)把pid寫入/var/run/redis.pid文件
          port?6379?//?默認(rèn)端口為6379
          bind?127.0.0.1 //主機(jī)地址,設(shè)置0.0.0.0表示都可以訪問。127.0.0.1表示只允許本機(jī)訪問
          timeout?900??//?客戶端閑置多長(zhǎng)時(shí)間后關(guān)閉連接,如果指定為0,表示關(guān)閉該功能
          logfile?stdout?//?日志記錄方式,默認(rèn)為標(biāo)準(zhǔn)輸出
          logfile?"./redis7001.log"??#?指明日志文件名
          databases?16?//?設(shè)置數(shù)據(jù)庫的數(shù)量,默認(rèn)數(shù)據(jù)庫為0
          save??//有多少次更新操作,就將數(shù)據(jù)同步到數(shù)據(jù)文件
          ?Redis默認(rèn)配置文件中提供了三個(gè)條件:
          ?save?900?1?//900秒(15分鐘)內(nèi)有1個(gè)更改
          ?save?300?10?//300秒(5分鐘)內(nèi)有10個(gè)更改
          ?save?60?10000??//?60秒內(nèi)有10000個(gè)更改
          rdbcompression?yes?//?指定存儲(chǔ)至本地?cái)?shù)據(jù)庫時(shí)是否壓縮數(shù)據(jù)
          dbfilename?dump.rdb?//指定本地?cái)?shù)據(jù)庫文件名
          dir?./????//指定本地?cái)?shù)據(jù)庫存放目錄
          slaveof??//?主從同步設(shè)置,設(shè)置主數(shù)據(jù)庫的ip和端口
          #?如果非零,則設(shè)置SO_KEEPALIVE選項(xiàng)來向空閑連接的客戶端發(fā)送ACK
          tcp-keepalive?60
          #?默認(rèn)如果開啟RDB快照(至少一條save指令)并且最新的后臺(tái)保存失敗,Redis將會(huì)停止接受寫操作
          #?這將使用戶知道數(shù)據(jù)沒有正確的持久化到硬盤,否則可能沒人注意到并且造成一些災(zāi)難
          stop-writes-on-bgsave-error?yes
          #?默認(rèn)如果開啟RDB快照(至少一條save指令)并且最新的后臺(tái)保存失敗,Redis將會(huì)停止接受寫操作。
          stop-writes-on-bgsave-error?yes
          #?當(dāng)導(dǎo)出到?.rdb?數(shù)據(jù)庫時(shí)是否用LZF壓縮字符串對(duì)象
          rdbcompression?yes
          #?版本5的RDB有一個(gè)CRC64算法的校驗(yàn)和放在了文件的最后。這將使文件格式更加可靠。
          rdbchecksum?yes
          #?持久化數(shù)據(jù)庫的文件名
          dbfilename?dump-master.rdb
          #?工作目錄
          dir?/usr/local/redis-4.0.8/redis_master/
          #?slav服務(wù)連接master的密碼
          masterauth?testmaster123
          #?當(dāng)一個(gè)slave失去和master的連接,或者同步正在進(jìn)行中,slave的行為可以有兩種:
          #1)?如果 slave-serve-stale-data 設(shè)置為?"yes"?(默認(rèn)值),slave會(huì)繼續(xù)響應(yīng)客戶端請(qǐng)求,可能是正常數(shù)據(jù),或者是過時(shí)了的數(shù)據(jù),也可能是還沒獲得值的空數(shù)據(jù)。
          #?2)?如果?slave-serve-stale-data?設(shè)置為?"no",slave會(huì)回復(fù)"正在從master同步
          #?(SYNC with master in progress)"來處理各種請(qǐng)求,除了 INFO 和 SLAVEOF 命令。
          slave-serve-stale-data?yes
          #?配置是否僅讀
          slave-read-only?yes
          #?如果你選擇“yes”Redis將使用更少的TCP包和帶寬來向slaves發(fā)送數(shù)據(jù)。但是這將使數(shù)據(jù)傳輸?shù)絪lave上有延遲,Linux內(nèi)核的默認(rèn)配置會(huì)達(dá)到40毫秒
          #?如果你選擇了?"no"?數(shù)據(jù)傳輸?shù)絪alve的延遲將會(huì)減少但要使用更多的帶寬
          repl-disable-tcp-nodelay?no
          #?slave的優(yōu)先級(jí),優(yōu)先級(jí)數(shù)字小的salve會(huì)優(yōu)先考慮提升為master
          slave-priority?100
          #?密碼驗(yàn)證
          requirepass?testmaster123
          # redis實(shí)例最大占用內(nèi)存,一旦內(nèi)存使用達(dá)到上限,Redis會(huì)根據(jù)選定的回收策略(參見:
          #?maxmemmory-policy)刪除key
          maxmemory?3gb
          #?最大內(nèi)存策略:如果達(dá)到內(nèi)存限制了,Redis如何選擇刪除key。
          # volatile-lru ->?根據(jù)LRU算法刪除帶有過期時(shí)間的key。
          # allkeys-lru ->?根據(jù)LRU算法刪除任何key。
          # volatile-random ->?根據(jù)過期設(shè)置來隨機(jī)刪除key, 具備過期時(shí)間的key。?
          # allkeys->random ->?無差別隨機(jī)刪, 任何一個(gè)key。?
          #?volatile-ttl?->?根據(jù)最近過期時(shí)間來刪除(輔以TTL),?這是對(duì)于有過期時(shí)間的key?
          # noeviction ->?誰也不刪,直接在寫操作時(shí)返回錯(cuò)誤。
          maxmemory-policy?volatile-lru
          #?AOF開啟
          appendonly?no
          #?aof文件名
          appendfilename?"appendonly.aof"
          # fsync()?系統(tǒng)調(diào)用告訴操作系統(tǒng)把數(shù)據(jù)寫到磁盤上,而不是等更多的數(shù)據(jù)進(jìn)入輸出緩沖區(qū)。
          #?有些操作系統(tǒng)會(huì)真的把數(shù)據(jù)馬上刷到磁盤上;有些則會(huì)盡快去嘗試這么做。
          # Redis支持三種不同的模式:
          # no:不要立刻刷,只有在操作系統(tǒng)需要刷的時(shí)候再刷。比較快。
          # always:每次寫操作都立刻寫入到aof文件。慢,但是最安全。
          # everysec:每秒寫一次。折中方案。?
          appendfsync?everysec
          #?如果AOF的同步策略設(shè)置成?"always"?或者?"everysec",并且后臺(tái)的存儲(chǔ)進(jìn)程(后臺(tái)存儲(chǔ)或?qū)懭階OF
          #?日志)會(huì)產(chǎn)生很多磁盤I/O開銷。某些Linux的配置下會(huì)使Redis因?yàn)?fsync()系統(tǒng)調(diào)用而阻塞很久。
          #?注意,目前對(duì)這個(gè)情況還沒有完美修正,甚至不同線程的 fsync()?會(huì)阻塞我們同步的write(2)調(diào)用。
          #?為了緩解這個(gè)問題,可以用下面這個(gè)選項(xiàng)。它可以在 BGSAVE 或 BGREWRITEAOF 處理時(shí)阻止主進(jìn)程進(jìn)行fsync()。
          #?這就意味著如果有子進(jìn)程在進(jìn)行保存操作,那么Redis就處于"不可同步"的狀態(tài)。
          #?這實(shí)際上是說,在最差的情況下可能會(huì)丟掉30秒鐘的日志數(shù)據(jù)。(默認(rèn)Linux設(shè)定)
          #?如果你有延時(shí)問題把這個(gè)設(shè)置成"yes",否則就保持"no",這是保存持久數(shù)據(jù)的最安全的方式。
          no-appendfsync-on-rewrite?yes
          #?自動(dòng)重寫AOF文件
          auto-aof-rewrite-percentage?100
          auto-aof-rewrite-min-size?64mb
          #?AOF文件可能在尾部是不完整的(這跟system關(guān)閉有問題,尤其是mount?ext4文件系統(tǒng)時(shí)
          #?沒有加上data=ordered選項(xiàng)。只會(huì)發(fā)生在os死時(shí),redis自己死不會(huì)不完整)。
          #?那redis重啟時(shí)load進(jìn)內(nèi)存的時(shí)候就有問題了。
          #?發(fā)生的時(shí)候,可以選擇redis啟動(dòng)報(bào)錯(cuò),并且通知用戶和寫日志,或者load盡量多正常的數(shù)據(jù)。
          #?如果aof-load-truncated是yes,會(huì)自動(dòng)發(fā)布一個(gè)log給客戶端然后load(默認(rèn))。
          #?如果是no,用戶必須手動(dòng)redis-check-aof修復(fù)AOF文件才可以。
          #?注意,如果在讀取的過程中,發(fā)現(xiàn)這個(gè)aof是損壞的,服務(wù)器也是會(huì)退出的,
          #?這個(gè)選項(xiàng)僅僅用于當(dāng)服務(wù)器嘗試讀取更多的數(shù)據(jù)但又找不到相應(yīng)的數(shù)據(jù)時(shí)。
          aof-load-truncated?yes
          #?Lua?腳本的最大執(zhí)行時(shí)間,毫秒為單位
          lua-time-limit?5000
          #?Redis慢查詢?nèi)罩究梢杂涗洺^指定時(shí)間的查詢
          slowlog-log-slower-than?10000
          #?這個(gè)長(zhǎng)度沒有限制。只是要主要會(huì)消耗內(nèi)存。你可以通過 SLOWLOG RESET 來回收內(nèi)存。
          slowlog-max-len?128
          #?客戶端的輸出緩沖區(qū)的限制,可用于強(qiáng)制斷開那些因?yàn)槟撤N原因從服務(wù)器讀取數(shù)據(jù)的速度不夠快的客戶端
          client-output-buffer-limit?normal?0?0?0
          client-output-buffer-limit?slave?256mb?64mb?60
          client-output-buffer-limit?pubsub?32mb?8mb?60
          #?當(dāng)一個(gè)子進(jìn)程重寫AOF文件時(shí),文件每生成32M數(shù)據(jù)會(huì)被同步
          aof-rewrite-incremental-fsync?yes

          由于,單機(jī)版的Redis在并發(fā)量比較大的時(shí)候,并且需要較高性能和可靠性的時(shí)候,單機(jī)版基本就不適合了,于是就出現(xiàn)了「主從模式」

          主從模式

          原理

          主從的原理還算是比較簡(jiǎn)單的,一主多從,「主數(shù)據(jù)庫(master)可以讀也可以寫(read/write),從數(shù)據(jù)庫僅讀(only read)」

          但是,主從模式一般實(shí)現(xiàn)「讀寫分離」「主數(shù)據(jù)庫僅寫(only write)」,減輕主數(shù)據(jù)庫的壓力,下面一張圖搞懂主從模式的原理:

          主從模式原理就是那么簡(jiǎn)單,那他執(zhí)行的過程(工作機(jī)制)又是怎么樣的呢?再來一張圖:

          當(dāng)開啟主從模式的時(shí)候,他的具體工作機(jī)制如下:

          1. 當(dāng)slave啟動(dòng)后會(huì)向master發(fā)送SYNC命令,master節(jié)點(diǎn)收到從數(shù)據(jù)庫的命令后通過bgsave保存快照(「RDB持久化」),并且期間的執(zhí)行的些命令會(huì)被緩存起來。
          2. 然后master會(huì)將保存的快照發(fā)送給slave,并且繼續(xù)緩存期間的寫命令。
          3. slave收到主數(shù)據(jù)庫發(fā)送過來的快照就會(huì)加載到自己的數(shù)據(jù)庫中。
          4. 最后master講緩存的命令同步給slave,slave收到命令后執(zhí)行一遍,這樣master與slave數(shù)據(jù)就保持一致了。

          優(yōu)點(diǎn)

          之所以運(yùn)用主從,是因?yàn)橹鲝囊欢ǔ潭壬辖鉀Q了單機(jī)版并發(fā)量大,導(dǎo)致請(qǐng)求延遲或者redis宕機(jī)服務(wù)停止的問題。

          從數(shù)據(jù)庫分擔(dān)主數(shù)據(jù)庫的讀壓力,若是主數(shù)據(jù)庫是只寫模式,那么實(shí)現(xiàn)讀寫分離,主數(shù)據(jù)庫就沒有了讀壓力了。

          另一方面解決了單機(jī)版單點(diǎn)故障的問題,若是主數(shù)據(jù)庫掛了,那么從數(shù)據(jù)庫可以隨時(shí)頂上來,綜上來說,主從模式一定程度上提高了系統(tǒng)的可用性和性能,是實(shí)現(xiàn)哨兵和集群的基礎(chǔ)。

          主從同步以異步方式進(jìn)行同步,期間Redis仍然可以響應(yīng)客戶端提交的查詢和更新的請(qǐng)求。

          缺點(diǎn)

          主從模式好是好,他也有自己的缺點(diǎn),比如數(shù)據(jù)的一致性問題,假如主數(shù)據(jù)庫寫操作完成,那么他的數(shù)據(jù)會(huì)被復(fù)制到從數(shù)據(jù)庫,若是還沒有即使復(fù)制到從數(shù)據(jù)庫,讀請(qǐng)求又來了,此時(shí)讀取的數(shù)據(jù)就不是最新的數(shù)據(jù)。

          若是從主同步的過程網(wǎng)絡(luò)出故障了,導(dǎo)致主從同步失敗,也會(huì)出現(xiàn)問題數(shù)據(jù)一致性的問題。

          主從模式不具備自動(dòng)容錯(cuò)和恢復(fù)的功能,一旦主數(shù)據(jù)庫,從節(jié)點(diǎn)晉升為主數(shù)據(jù)庫的過程需要人為操作,維護(hù)的成本就會(huì)升高,并且主節(jié)點(diǎn)的寫能力、存儲(chǔ)能力都會(huì)受到限制。

          實(shí)操搭建

          下面的我們來實(shí)操搭建一下主從模式,主從模式的搭建還是比較簡(jiǎn)單的,我這里一臺(tái)centos 7虛擬機(jī),使用開啟redis多實(shí)例的方法搭建主從。

          redis中開啟多實(shí)例的方法,首先創(chuàng)建一個(gè)文件夾,用于存放redis集群的配置文件:

          mkdir?redis

          然后粘貼復(fù)制redis.conf配置文件:

          cp?/root/redis-4.0.6/redis.conf?/root/redis/redis-6379.conf
          cp?/root/redis-4.0.6/redis.conf?/root/redis/redis-6380.conf
          cp?/root/redis-4.0.6/redis.conf?/root/redis/redis-6381.conf

          復(fù)制三份配置文件,一主兩從,6379端口作為主數(shù)據(jù)庫(master),6380、6381作為從數(shù)據(jù)庫(slave)。

          首先是配置主數(shù)據(jù)庫的配置文件:vi redis-6379.conf

          bind?0.0.0.0?#?注釋掉或配置成0.0.0.0表示任意IP均可訪問。
          protected-mode?no?#?關(guān)閉保護(hù)模式,使用密碼訪問。
          port?6379??#?設(shè)置端口,6380、6381依次為6380、6381。
          timeout?30?#?客戶端連接空閑多久后斷開連接,單位秒,0表示禁用
          daemonize?yes?#?在后臺(tái)運(yùn)行
          pidfile?/var/run/redis_6379.pid??#?pid進(jìn)程文件名,6380、6381依次為redis_6380.pid、redis_6381.pid
          logfile?/root/reids/log/6379.log?#?日志文件,6380、6381依次為6380.log、6381.log
          save?900?1?# 900s內(nèi)至少一次寫操作則執(zhí)行bgsave進(jìn)行RDB持久化
          save?300?10
          save?60?10000?
          rdbcompression?yes?#是否對(duì)RDB文件進(jìn)行壓縮,建議設(shè)置為no,以(磁盤)空間換(CPU)時(shí)間
          dbfilename?dump.rdb?#?RDB文件名稱
          dir?/root/redis/datas?#?RDB文件保存路徑,AOF文件也保存在這里
          appendonly?yes?#?表示使用AOF增量持久化的方式
          appendfsync?everysec?#?可選值?always,?everysec,no,建議設(shè)置為everysec
          requirepass?123456?#?設(shè)置密碼

          然后,就是修改從數(shù)據(jù)庫的配置文件,在從數(shù)據(jù)庫的配置文件中加入以下的配置信息:

          slaveof?127.0.0.1?6379?#?配置master的ip,port
          masterauth?123456?#?配置訪問master的密碼
          slaveof-serve-stale-data?no?

          接下來就是啟動(dòng)三個(gè)redis實(shí)例,啟動(dòng)的命令,先cd到redis的src目錄下,然后執(zhí)行:

          ./redis-server?/root/redis/6379.conf
          ./redis-server?/root/redis/6380.conf
          ./redis-server?/root/redis/6381.conf

          通過命令ps -aux | grep redis,查看啟動(dòng)的redis進(jìn)程:如上圖所示,表示啟動(dòng)成功,下面就開始進(jìn)入測(cè)試階段。

          測(cè)試

          我這里使用SecureCRT作為redis連接的客戶端,同時(shí)啟動(dòng)三個(gè)SecureCRT,分別連接redis1的三個(gè)實(shí)例,啟動(dòng)時(shí)指定端口以及密碼:

          ./redis-cli?-p?6379?-a?123456

          啟動(dòng)后,在master(6379),輸入:set name 'ldc',在slave中通過get name,可以查看:

          數(shù)據(jù)同步成功,這有幾個(gè)坑一個(gè)是redis.conf中沒有設(shè)置對(duì)bind,會(huì)導(dǎo)致非本機(jī)的ip被過濾掉,一般配置0.0.0.0就可以了。

          另一個(gè)是沒有配置密碼requirepass 123456,會(huì)導(dǎo)致IO一直連接異常,這個(gè)是我遇到的坑,后面配置密碼后就成功了。

          還有,就是查看redis的啟動(dòng)日志可以發(fā)現(xiàn)有兩個(gè)warning,雖然不影響搭建主從同步,看著挺煩人的,但是有些人會(huì)遇到,有些人不會(huì)遇到。

          但是,我這個(gè)人比較有強(qiáng)迫癥,百度也是有解決方案的,這里就不講了,交給你們自己解決,這里只是告訴你有這個(gè)問題,有些人看都不看日志的,看到啟動(dòng)成功就認(rèn)為萬事大吉了,也不看日志,這習(xí)慣并不好。

          哨兵模式

          原理

          哨兵模式是主從的升級(jí)版,因?yàn)橹鲝牡某霈F(xiàn)故障后,不會(huì)自動(dòng)恢復(fù),需要人為干預(yù),這就很蛋疼啊。

          在主從的基礎(chǔ)上,實(shí)現(xiàn)哨兵模式就是為了監(jiān)控主從的運(yùn)行狀況,對(duì)主從的健壯進(jìn)行監(jiān)控,就好像哨兵一樣,只要有異常就發(fā)出警告,對(duì)異常狀況進(jìn)行處理。

          所以,總的概括來說,哨兵模式有以下的優(yōu)點(diǎn)(功能點(diǎn)):

          1. 「監(jiān)控」:監(jiān)控master和slave是否正常運(yùn)行,以及哨兵之間也會(huì)相互監(jiān)控
          2. 「自動(dòng)故障恢復(fù)」:當(dāng)master出現(xiàn)故障的時(shí)候,會(huì)自動(dòng)選舉一個(gè)slave作為master頂上去。

          哨兵模式的監(jiān)控配置信息,是通過配置從數(shù)據(jù)庫的sentinel monitor 來指定的,比如:

          //?mymaster?表示給master數(shù)據(jù)庫定義了一個(gè)名字,后面的是master的ip和端口,1表示至少需要一個(gè)Sentinel進(jìn)程同意才能將master判斷為失效,如果不滿足這個(gè)條件,則自動(dòng)故障轉(zhuǎn)移(failover)不會(huì)執(zhí)行
          sentinel?monitor?mymaster?127.0.0.1?6379?1

          節(jié)點(diǎn)通信

          當(dāng)然還有其它的配置信息,其它配置信息,在環(huán)境搭建的時(shí)候再說。當(dāng)哨兵啟動(dòng)后,會(huì)與master建立一條連接,用于訂閱master的_sentinel_:hello頻道。

          該頻道用于獲取監(jiān)控該master的其它哨兵的信息。并且還會(huì)建立一條定時(shí)向master發(fā)送INFO命令獲取master信息的連接。

          「當(dāng)哨兵與master建立連接后,定期會(huì)向(10秒一次)master和slave發(fā)送INFO命令,若是master被標(biāo)記為主觀下線,頻率就會(huì)變?yōu)?秒一次。」

          并且,定期向_sentinel_:hello頻道發(fā)送自己的信息,以便其它的哨兵能夠訂閱獲取自己的信息,發(fā)送的內(nèi)容包含「哨兵的ip和端口、運(yùn)行id、配置版本、master名字、master的ip端口還有master的配置版本」等信息。

          以及,「定期的向master、slave和其它哨兵發(fā)送PING命令(每秒一次),以便檢測(cè)對(duì)象是否存活」,若是對(duì)方接收到了PING命令,無故障情況下,會(huì)回復(fù)PONG命令。

          所以,哨兵通過建立這兩條連接、通過定期發(fā)送INFO、PING命令來實(shí)現(xiàn)哨兵與哨兵、哨兵與master之間的通信。

          這里涉及到一些概念需要理解,INFO、PING、PONG等命令,后面還會(huì)有MEET、FAIL命令,以及主觀下線,當(dāng)然還會(huì)有客觀下線,這里主要說一下這幾個(gè)概念的理解:

          1. INFO:該命令可以獲取主從數(shù)據(jù)庫的最新信息,可以實(shí)現(xiàn)新結(jié)點(diǎn)的發(fā)現(xiàn)
          2. PING:該命令被使用最頻繁,該命令封裝了自身節(jié)點(diǎn)和其它節(jié)點(diǎn)的狀態(tài)數(shù)據(jù)。
          3. PONG:當(dāng)節(jié)點(diǎn)收到MEET和PING,會(huì)回復(fù)PONG命令,也把自己的狀態(tài)發(fā)送給對(duì)方。
          4. MEET:該命令在新結(jié)點(diǎn)加入集群的時(shí)候,會(huì)向老節(jié)點(diǎn)發(fā)送該命令,表示自己是個(gè)新人
          5. FAIL:當(dāng)節(jié)點(diǎn)下線,會(huì)向集群中廣播該消息。

          上線和下線

          當(dāng)哨兵與master相同之后就會(huì)定期一直保持聯(lián)系,若是某一時(shí)刻哨兵發(fā)送的PING在指定時(shí)間內(nèi)沒有收到回復(fù)(sentinel down-after-milliseconds master-name milliseconds 配置),那么發(fā)送PING命令的哨兵就會(huì)認(rèn)為該master「主觀下線」Subjectively Down)。

          因?yàn)橛锌赡苁巧诒c該master之間的網(wǎng)絡(luò)問題造成的,而不是master本身的原因,所以哨兵同時(shí)會(huì)詢問其它的哨兵是否也認(rèn)為該master下線,若是認(rèn)為該節(jié)點(diǎn)下線的哨兵達(dá)到一定的數(shù)量(「前面的quorum字段配置」),就會(huì)認(rèn)為該節(jié)點(diǎn)「客觀下線」Objectively Down)。

          若是沒有足夠數(shù)量的sentinel同意該master下線,則該master客觀下線的標(biāo)識(shí)會(huì)被移除;若是master重新向哨兵的PING命令回復(fù)了客觀下線的標(biāo)識(shí)也會(huì)被移除。

          選舉算法

          當(dāng)master被認(rèn)為客觀下線后,又是怎么進(jìn)行故障恢復(fù)的呢?原來哨兵中首先選舉出一個(gè)老大哨兵來進(jìn)行故障恢復(fù),選舉老大哨兵的算法叫做「Raft算法」

          1. 發(fā)現(xiàn)master下線的哨兵(sentinelA)會(huì)向其它的哨兵發(fā)送命令進(jìn)行拉票,要求選擇自己為哨兵大佬。
          2. 若是目標(biāo)哨兵沒有選擇其它的哨兵,就會(huì)選擇該哨兵(sentinelA)為大佬。
          3. 若是選擇sentinelA的哨兵超過半數(shù)(半數(shù)原則),該大佬非sentinelA莫屬。
          4. 如果有多個(gè)哨兵同時(shí)競(jìng)選,并且可能存在票數(shù)一致的情況,就會(huì)等待下次的一個(gè)隨機(jī)時(shí)間再次發(fā)起競(jìng)選請(qǐng)求,進(jìn)行新的一輪投票,直到大佬被選出來。

          選出大佬哨兵后,大佬哨兵就會(huì)對(duì)故障進(jìn)行自動(dòng)回復(fù),從slave中選出一名slave作為主數(shù)據(jù)庫,選舉的規(guī)則如下所示:

          1. 所有的slave中slave-priority優(yōu)先級(jí)最高的會(huì)被選中。
          2. 若是優(yōu)先級(jí)相同,會(huì)選擇偏移量最大的,因?yàn)槠屏坑涗浿鴶?shù)據(jù)的復(fù)制的增量,越大表示數(shù)據(jù)越完整。
          3. 若是以上兩者都相同,選擇ID最小的。

          通過以上的層層篩選最終實(shí)現(xiàn)故障恢復(fù),當(dāng)選的slave晉升為master,其它的slave會(huì)向新的master復(fù)制數(shù)據(jù),若是down掉的master重新上線,會(huì)被當(dāng)作slave角色運(yùn)行。

          優(yōu)點(diǎn)

          哨兵模式是主從模式的升級(jí)版,所以在系統(tǒng)層面提高了系統(tǒng)的可用性和性能、穩(wěn)定性。當(dāng)master宕機(jī)的時(shí)候,能夠自動(dòng)進(jìn)行故障恢復(fù),需不要人為的干預(yù)。

          哨兵與哨兵之間、哨兵與master之間能夠進(jìn)行及時(shí)的監(jiān)控,心跳檢測(cè),及時(shí)發(fā)現(xiàn)系統(tǒng)的問題,這都是彌補(bǔ)了主從的缺點(diǎn)。

          缺點(diǎn)

          哨兵一主多從的模式同樣也會(huì)遇到寫的瓶頸,已經(jīng)存儲(chǔ)瓶頸,若是master宕機(jī)了,故障恢復(fù)的時(shí)間比較長(zhǎng),寫的業(yè)務(wù)就會(huì)受到影響。

          增加了哨兵也增加了系統(tǒng)的復(fù)雜度,需要同時(shí)維護(hù)哨兵模式。

          實(shí)操搭建

          最后,我們進(jìn)行一下哨兵模式的搭建,配置哨兵模式還是比較簡(jiǎn)單的,在上面配置的主從模式的基礎(chǔ)上,同時(shí)創(chuàng)建一個(gè)文件夾用于存放三個(gè)哨兵的配置文件:

          mkdir?/root/redis-4.0.6/sentinel.conf??/root/redis/sentinel/sentinel1.conf?
          mkdir?/root/redis-4.0.6/sentinel.conf??/root/redis/sentinel/sentinel2.conf?
          mkdir?/root/redis-4.0.6/sentinel.conf??/root/redis/sentinel/sentinel3.conf?

          分別在這三個(gè)文件中添加如下配置:

          daemonize?yes?#?在后臺(tái)運(yùn)行
          sentinel?monitor?mymaster?127.0.0.1?6379?1?#?給master起一個(gè)名字mymaster,并且配置master的ip和端口
          sentinel?auth-pass?mymaster?123456?#?master的密碼
          port?26379?#另外兩個(gè)配置36379,46379端口
          sentinel?down-after-milliseconds?mymaster?3000?#?3s未回復(fù)PING就認(rèn)為master主觀下線
          sentinel?parallel-syncs?mymaster?2??#?執(zhí)行故障轉(zhuǎn)移時(shí),最多可以有2個(gè)slave實(shí)例在同步新的master實(shí)例
          sentinel?failover-timeout?mymaster?100000?#?如果在10s內(nèi)未能完成故障轉(zhuǎn)移操作認(rèn)為故障轉(zhuǎn)移失敗

          配置完后分別啟動(dòng)三臺(tái)哨兵:

          ./redis-server?sentinel1.conf?--sentinel
          ./redis-server?sentinel2.conf?--sentinel
          ./redis-server?sentinel3.conf?--sentinel

          然后通過:ps -aux|grep redis進(jìn)行查看:可以看到三臺(tái)redis實(shí)例以及三個(gè)哨兵都已經(jīng)正常啟動(dòng),現(xiàn)登陸6379,通過INFO Repliaction查看master信息:

          當(dāng)前master為6379,然后我們來測(cè)試一下哨兵的自動(dòng)故障恢復(fù),直接kill掉6379進(jìn)程,然后通過登陸6380再次查看master的信息:

          可以看到當(dāng)前的6380角色是master,并且6380可讀可寫,而不是只讀模式,這說明我們的哨兵是起作用了,搭建成功,感興趣的可以自行搭建,也有可能你會(huì)踩一堆的坑。

          Cluster模式

          最后,Cluster是真正的集群模式了,哨兵解決和主從不能自動(dòng)故障恢復(fù)的問題,但是同時(shí)也存在難以擴(kuò)容以及單機(jī)存儲(chǔ)、讀寫能力受限的問題,并且集群之前都是一臺(tái)redis都是全量的數(shù)據(jù),這樣所有的redis都冗余一份,就會(huì)大大消耗內(nèi)存空間。

          集群模式實(shí)現(xiàn)了Redis數(shù)據(jù)的分布式存儲(chǔ),實(shí)現(xiàn)數(shù)據(jù)的分片,每個(gè)redis節(jié)點(diǎn)存儲(chǔ)不同的內(nèi)容,并且解決了在線的節(jié)點(diǎn)收縮(下線)和擴(kuò)容(上線)問題。

          集群模式真正意義上實(shí)現(xiàn)了系統(tǒng)的高可用和高性能,但是集群同時(shí)進(jìn)一步使系統(tǒng)變得越來越復(fù)雜,接下來我們來詳細(xì)的了解集群的運(yùn)作原理。

          數(shù)據(jù)分區(qū)原理

          集群的原理圖還是很好理解的,在Redis集群中采用的是虛擬槽分區(qū)算法,會(huì)把redis集群分成16384 個(gè)槽(0 -16383)。

          比如:下圖所示三個(gè)master,會(huì)把0 -16383范圍的槽可能分成三部分(0-5000)、(5001-11000)、(11001-16383)分別數(shù)據(jù)三個(gè)緩存節(jié)點(diǎn)的槽范圍。

          當(dāng)客戶端請(qǐng)求過來,會(huì)首先通過對(duì)key進(jìn)行CRC16 校驗(yàn)并對(duì) 16384 取模(CRC16(key)%16383)計(jì)算出key所在的槽,然后再到對(duì)應(yīng)的槽上進(jìn)行取數(shù)據(jù)或者存數(shù)據(jù),這樣就實(shí)現(xiàn)了數(shù)據(jù)的訪問更新。

          之所以進(jìn)行分槽存儲(chǔ),是將一整堆的數(shù)據(jù)進(jìn)行分片,防止單臺(tái)的redis數(shù)據(jù)量過大,影響性能的問題。

          節(jié)點(diǎn)通信

          節(jié)點(diǎn)之間實(shí)現(xiàn)了將數(shù)據(jù)進(jìn)行分片存儲(chǔ),那么節(jié)點(diǎn)之間又是怎么通信的呢?這個(gè)和前面哨兵模式講的命令基本一樣。

          首先新上線的節(jié)點(diǎn),會(huì)通過 Gossip 協(xié)議向老成員發(fā)送Meet消息,表示自己是新加入的成員。

          老成員收到Meet消息后,在沒有故障的情況下會(huì)恢復(fù)PONG消息,表示歡迎新結(jié)點(diǎn)的加入,除了第一次發(fā)送Meet消息后,之后都會(huì)發(fā)送定期PING消息,實(shí)現(xiàn)節(jié)點(diǎn)之間的通信。

          通信的過程中會(huì)為每一個(gè)通信的節(jié)點(diǎn)開通一條tcp通道,之后就是定時(shí)任務(wù),不斷的向其它節(jié)點(diǎn)發(fā)送PING消息,這樣做的目的就是為了了解節(jié)點(diǎn)之間的元數(shù)據(jù)存儲(chǔ)情況,以及健康狀況,以便即使發(fā)現(xiàn)問題。

          數(shù)據(jù)請(qǐng)求

          上面說到了槽信息,在Redis的底層維護(hù)了unsigned char myslots[CLUSTER_SLOTS/8] 一個(gè)數(shù)組存放每個(gè)節(jié)點(diǎn)的槽信息。

          因?yàn)樗且粋€(gè)二進(jìn)制數(shù)組,只有存儲(chǔ)0和1值,如下圖所示:

          這樣數(shù)組只表示自己是否存儲(chǔ)對(duì)應(yīng)的槽數(shù)據(jù),若是1表示存在該數(shù)據(jù),0表示不存在該數(shù)據(jù),這樣查詢的效率就會(huì)非常的高,類似于布隆過濾器,二進(jìn)制存儲(chǔ)。

          比如:集群節(jié)點(diǎn)1負(fù)責(zé)存儲(chǔ)0-5000的槽數(shù)據(jù),但是此時(shí)只有0、1、2存儲(chǔ)有數(shù)據(jù),其它的槽還沒有存數(shù)據(jù),所以0、1、2對(duì)應(yīng)的值為1。

          并且,每個(gè)redis底層還維護(hù)了一個(gè)clusterNode數(shù)組,大小也是16384,用于儲(chǔ)存負(fù)責(zé)對(duì)應(yīng)槽的節(jié)點(diǎn)的ip、端口等信息,這樣每一個(gè)節(jié)點(diǎn)就維護(hù)了其它節(jié)點(diǎn)的元數(shù)據(jù)信息,便于及時(shí)的找到對(duì)應(yīng)的節(jié)點(diǎn)。

          當(dāng)新結(jié)點(diǎn)加入或者節(jié)點(diǎn)收縮,通過PING命令通信,及時(shí)的更新自己clusterNode數(shù)組中的元數(shù)據(jù)信息,這樣有請(qǐng)求過來也就能及時(shí)的找到對(duì)應(yīng)的節(jié)點(diǎn)。

          有兩種其它的情況就是,若是請(qǐng)求過來發(fā)現(xiàn),數(shù)據(jù)發(fā)生了遷移,比如新節(jié)點(diǎn)加入,會(huì)使舊的緩存節(jié)點(diǎn)數(shù)據(jù)遷移到新結(jié)點(diǎn)。

          請(qǐng)求過來發(fā)現(xiàn)舊節(jié)點(diǎn)已經(jīng)發(fā)生了數(shù)據(jù)遷移并且數(shù)據(jù)被遷移到新結(jié)點(diǎn),由于每個(gè)節(jié)點(diǎn)都有clusterNode信息,通過該信息的ip和端口。此時(shí)舊節(jié)點(diǎn)就會(huì)向客戶端發(fā)一個(gè)MOVED 的重定向請(qǐng)求,表示數(shù)據(jù)已經(jīng)遷移到新結(jié)點(diǎn)上,你要訪問這個(gè)新結(jié)點(diǎn)的ip和端口就能拿到數(shù)據(jù),這樣就能重新獲取到數(shù)據(jù)。

          倘若正在發(fā)正數(shù)據(jù)遷移呢?舊節(jié)點(diǎn)就會(huì)向客戶端發(fā)送一個(gè)ASK 重定向請(qǐng)求,并返回給客戶端遷移的目標(biāo)節(jié)點(diǎn)的ip和端口,這樣也能獲取到數(shù)據(jù)。

          擴(kuò)容和收縮

          擴(kuò)容和收縮也就是節(jié)點(diǎn)的上線和下線,可能節(jié)點(diǎn)發(fā)生故障了,故障自動(dòng)回復(fù)的過程(節(jié)點(diǎn)收縮)。

          節(jié)點(diǎn)的收縮和擴(kuò)容時(shí),會(huì)重新計(jì)算每一個(gè)節(jié)點(diǎn)負(fù)責(zé)的槽范圍,并發(fā)根據(jù)虛擬槽算法,將對(duì)應(yīng)的數(shù)據(jù)更新到對(duì)應(yīng)的節(jié)點(diǎn)。

          還有前面的講的新加入的節(jié)點(diǎn)會(huì)首先發(fā)送Meet消息,詳細(xì)可以查看前面講的內(nèi)容,基本一樣的模式。

          以及發(fā)生故障后,哨兵老大節(jié)點(diǎn)的選舉,master節(jié)點(diǎn)的重新選舉,slave怎樣晉升為master節(jié)點(diǎn),可以查看前面哨兵模式選舉過程。

          優(yōu)點(diǎn)

          集群模式是一個(gè)無中心的架構(gòu)模式,將數(shù)據(jù)進(jìn)行分片,分布到對(duì)應(yīng)的槽中,每個(gè)節(jié)點(diǎn)存儲(chǔ)不同的數(shù)據(jù)內(nèi)容,通過路由能夠找到對(duì)應(yīng)的節(jié)點(diǎn)負(fù)責(zé)存儲(chǔ)的槽,能夠?qū)崿F(xiàn)高效率的查詢。

          并且集群模式增加了橫向和縱向的擴(kuò)展能力,實(shí)現(xiàn)節(jié)點(diǎn)加入和收縮,集群模式是哨兵的升級(jí)版,哨兵的優(yōu)點(diǎn)集群都有。

          缺點(diǎn)

          緩存的最大問題就是帶來數(shù)據(jù)一致性問題,在平衡數(shù)據(jù)一致性的問題時(shí),兼顧性能與業(yè)務(wù)要求,大多數(shù)都是以最終一致性的方案進(jìn)行解決,而不是強(qiáng)一致性。

          并且集群模式帶來節(jié)點(diǎn)數(shù)量的劇增,一個(gè)集群模式最少要6臺(tái)機(jī),因?yàn)橐獫M足半數(shù)原則的選舉方式,所以也帶來了架構(gòu)的復(fù)雜性。

          slave只充當(dāng)冷備,并不能緩解master的讀的壓力。

          實(shí)操搭建

          集群模式的部署比較簡(jiǎn)單,只要在redis.conf加入下面的配置信息即可:

          port?6379#?本示例6個(gè)節(jié)點(diǎn)端口分別為6379、6380、6381、6382、6383、6384
          daemonize?yes?#?r后臺(tái)運(yùn)行?
          pidfile?/var/run/redis_6379.pid?#?分別對(duì)應(yīng)6379、6380、6381、6382、6383、6384
          cluster-enabled?yes?#?開啟集群模式?
          masterauth?123456#?如果設(shè)置了密碼,需要指定master密碼
          cluster-config-file?nodes_6379.conf?#?集群的配置文件,同樣對(duì)應(yīng)6379、6380、6381、6382、6383、6384六個(gè)節(jié)點(diǎn)
          cluster-node-timeout?10000?#?請(qǐng)求超時(shí)時(shí)間

          同時(shí)開啟這六個(gè)實(shí)例,通過下面的命令將這六個(gè)實(shí)例以集群的方式運(yùn)行

          ./redis-cli?--cluster?create?--cluster-replicas?1?127.0.0.1:6379?127.0.0.1:6380?127.0.0.1:6381??127.0.0.1:6382??127.0.0.1:6383??127.0.0.1:6384??-a?123456

          這樣就實(shí)現(xiàn)了集群的搭建,好了這一期就完成了,看了一下字?jǐn)?shù)一共1.7W字,原創(chuàng)不易,看完點(diǎn)個(gè)在看和分享,不要白嫖我,傳承中華民族的良好美德。

          1.?人人都能看懂的 6 種限流實(shí)現(xiàn)方案!

          2.?一個(gè)空格引發(fā)的“慘案“

          3.?大型網(wǎng)站架構(gòu)演化發(fā)展歷程

          4.?Java語言“坑爹”排行榜TOP 10

          5. 我是一個(gè)Java類(附帶精彩吐槽)

          6. 看完這篇Redis緩存三大問題,保你能和面試官互扯

          7. 程序員必知的 89 個(gè)操作系統(tǒng)核心概念

          8. 深入理解 MySQL:快速學(xué)會(huì)分析SQL執(zhí)行效率

          9. API 接口設(shè)計(jì)規(guī)范

          10. Spring Boot 面試,一個(gè)問題就干趴下了!



          掃碼二維碼關(guān)注我


          ·end·

          —如果本文有幫助,請(qǐng)分享到朋友圈吧—

          我們一起愉快的玩耍!



          你點(diǎn)的每個(gè)贊,我都認(rèn)真當(dāng)成了喜歡


          瀏覽 59
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  伊人无码不卡电影网 | 人人操人人网站大全 | 免费a视频在线 | 好干干成人免费视频 | 狠操视频 |