高可用Redis(八):Redis主從複製

來源:互聯網
上載者:User

標籤:不用   memory   添加   sync   簡單   int   手動   erp   角色   

1.Redis複製的原理和最佳化1.1 Redis單機的問題1.1.1 機器故障

在一台伺服器上部署一個Redis節點,如果機器發生主板損壞,硬碟損壞等問題,不能在短時間修複完成,就不能處理Redis操作了,這就是單機可能存在的問題

同樣的,伺服器正常運行,但是Redis主進程發生宕機事件,此時只需要重啟Redis就可以了。如果不考慮在Redis重啟期間的效能損失,可以考慮Redis的單機部署

Redis單機部署出現故障時,把Redis遷移到另一台伺服器上,此時需要把發生故障的Redis中的資料同步到新部署的Redis節點,這也需要很高的成本

1.1.2 容量瓶頸

一台伺服器有16G記憶體,此時分配12G記憶體運行Redis

如果有新需求:Redis需要佔用32G或者64G等更多的記憶體,此時這台伺服器就不能滿足需求了,此時可以考慮更換一台更大記憶體的伺服器,也可以用多台伺服器組成一個Redis叢集來滿足這個需求

1.1.3 QPS瓶頸

根據Redis官方的說法,單台Redis可以支援10萬的QPS,如果現在的業務需要100萬的QPS,此時可以考慮使用Redis分布式

2.什麼是主從複製2.1 一主一從模型

一個Redis節點為master節點(主節點),負責對外提供服務。

另一個節點為slave節點(從節點),負責同步主節點的資料,以達到備份的效果。當主節點發生宕機等故障時,從節點也可以對外提供服務

如所示

2.2 一主多從模型

一個Redis節點為master節點(主節點),負責對外提供服務。

多個節點為slave節點(從節點)。每個slave都會對主節點中的資料進行備份,以達到更加高可用的效果。這種情況下就算master和一個slave同時發生宕機故障,其餘的slave仍然可以對外讀提供服務,並保證資料不會丟失

當master有很多讀寫,達到Redis的極限閥值,可以使用多個slave節點對Redis的讀操作進行分流,有效實現流量的分流和負載平衡,所以一主多從也可以做讀寫分離

2.3 讀寫分離模型

master節點負責寫資料,同時用戶端可以從slave節點讀取資料

3.主從複製作用

對資料提供了多個備份,這些備份資料可以大大提高Redis的讀效能,是Redis高可用或者分布式的基礎

4.主從複製的配置4.1 slaveof命令

取消複製

4.2 設定檔配置

修改Redis設定檔/etc/redis.conf

slaveof <masterip> <masterport>         # masterip為主節點IP地址,masterport為主節點連接埠slave-read-only yes                     # 從節點只做讀操作,不做寫操作,保證主從裝置資料相同
4.3 兩種主從配置方式比較
使用命令列配置無需重啟Redis,可以實現統一配置使用設定檔方式配置不變於管理,而且需要重啟Redis
4.4 例子

有兩台虛擬機器,作業系統都是CentOS 7.5

一台虛擬機器的IP地址為192.168.81.100,做master一台虛擬機器的IP地址為192.168.81.101,做slave
第一步:在192.168.81.101虛擬機器操作
[[email protected] ~]# vi /etc/redis.conf              # 修改Redis設定檔    bind 0.0.0.0                                # 可以從外部串連Redis服務端    slaveof 192.168.81.100 6379                 # 設定master的IP地址和連接埠

然後儲存修改,啟動Redis

[[email protected] ~]# systemctl stop firewalld        # 關閉firewalld防火牆[[email protected] ~]# systemctl start redis           # 啟動slave上的Redis服務端[[email protected] ~]# ps aux | grep redis-server      # 查看redis-server的進程redis      2319  0.3  0.8 155204 18104 ?        Ssl  09:55   0:00 /usr/bin/redis-server 0.0.0.0:6379root       2335  0.0  0.0 112664   968 pts/2    R+   09:56   0:00 grep --color=auto redis[[email protected] ~]# redis-cli                       # 啟動Redis用戶端127.0.0.1:6379> info replication                # 查看Redis的複製資訊 查看192.168.81.101機器上的Redis的info# Replicationrole:slave                                      # 角色為slavemaster_host:192.168.81.100                      # 主節點IP為192.168.81.100master_port:6379                                # 主節點連接埠為6379master_link_status:upmaster_last_io_seconds_ago:5master_sync_in_progress:0slave_repl_offset:155slave_priority:100slave_read_only:1connected_slaves:0master_repl_offset:0repl_backlog_active:0repl_backlog_size:1048576repl_backlog_first_byte_offset:0repl_backlog_histlen:0
第二步:在192.168.81.100虛擬機器上操作
[[email protected] ~]# systemctl stop firewalld        # 關閉firewalld防火牆 [[email protected] ~]# vi /etc/redis.conf              # 修改Redis設定檔       bind 0.0.0.0然後儲存修改,啟動Redis[[email protected] ~]# systemctl start redis           # 啟動master上的Redis[[email protected] ~]# ps aux | grep redis-server      # 查看redis-server進程redis      2529  0.2  1.8 155192 18192 ?        Ssl  17:55   0:00 /usr/bin/redis-server 0.0.0.0:6379root       2536  0.0  0.0 112648   960 pts/2    R+   17:56   0:00 grep --color=auto redis[[email protected] ~]# redis-cli                       # 啟動master上的redis-cli用戶端127.0.0.1:6379> info replication                    # 查看192.168.81.100機器上Redis的資訊# Replicationrole:master                                         # 角色為主節點connected_slaves:1                                  # 串連一個從節點slave0:ip=192.168.81.101,port=6379,state=online,offset=141,lag=2        # 從節點的資訊master_repl_offset:141repl_backlog_active:1repl_backlog_size:1048576repl_backlog_first_byte_offset:2repl_backlog_histlen:140127.0.0.1:6379> set hello world                     # 向主節點寫入資料OK127.0.0.1:6379> info server# Serverredis_version:3.2.10redis_git_sha1:00000000redis_git_dirty:0redis_build_id:c8b45a0ec7dc67c6redis_mode:standaloneos:Linux 3.10.0-514.el7.x86_64 x86_64arch_bits:64multiplexing_api:epollgcc_version:4.8.5process_id:2529run_id:7091f874c7c3eeadae873d3e6704e67637d8772b     # 注意這個run_idtcp_port:6379uptime_in_seconds:488uptime_in_days:0hz:10lru_clock:12784741executable:/usr/bin/redis-serverconfig_file:/etc/redis.conf
第三步:回到192.168.81.101這台從節點上操作
127.0.0.1:6379> get hello                   # 擷取‘hello‘的值,可以擷取到"world"127.0.0.1:6379> set a b                     # 向192.168.81.101從節點寫入資料,失敗(error) READONLY You can‘t write against a read only slave.127.0.0.1:6379> slaveof no one              # 取消從節點設定OK127.0.0.1:6379> info replication            # 查看192.168.81.101機器,已經不再是從節點,而變成主節點了# Replicationrole:master                                 # 變成主節點了connected_slaves:0master_repl_offset:787repl_backlog_active:0repl_backlog_size:1048576repl_backlog_first_byte_offset:0repl_backlog_histlen:0127.0.0.1:6379> dbsize                      # 查看192.168.81.101上Redis所有資料大小(integer) 2
第四步:回到192.168.81.100虛擬機器
127.0.0.1:6379> mset a b c d e f            # 向192.168.81.100上的Redis集合中寫入資料OK  127.0.0.1:6379> dbsize                      # Redis中資料大小為5(integer) 5
第五步:查看192.168.81.100虛擬機器上Redis的日誌
[[email protected] ~]# tail /var/log/redis/redis.log       # 查看Redis最後10行日誌2529:M 14 Oct 17:55:09.448 * DB loaded from disk: 0.026 seconds2529:M 14 Oct 17:55:09.448 * The server is now ready to accept connections on port 63792529:M 14 Oct 17:55:10.118 * Slave 192.168.81.101:6379 asks for synchronization2529:M 14 Oct 17:55:10.118 * Partial resynchronization not accepted: Runid mismatch (Client asked for runid ‘9f93f85bce758b9c48e72d96a182a2966940cf52‘, my runid is ‘7091f874c7c3eeadae873d3e6704e67637d8772b‘)         # 與192.168.81.100裝置上通過info命令查看到的run_id相同2529:M 14 Oct 17:55:10.118 * Starting BGSAVE for SYNC with target: disk     # 執行BGSAVE命令成功2529:M 14 Oct 17:55:10.119 * Background saving started by pid 25322532:C 14 Oct 17:55:10.158 * DB saved on disk2532:C 14 Oct 17:55:10.159 * RDB: 12 MB of memory used by copy-on-write2529:M 14 Oct 17:55:10.254 * Background saving terminated with success2529:M 14 Oct 17:55:10.256 * Synchronization with slave 192.168.81.101:6379 succeeded   # 向192.168.81.101同步資料成功
第六步:回到192.168.81.101虛擬機器
127.0.0.1:6379> slaveof 192.168.81.100 6379     # 把192.168.81.101重新設定為192.168.81.100的從節點OK127.0.0.1:6379> dbsize(integer) 5127.0.0.1:6379> mget a1) "b"
第七步:查看192.168.81.101虛擬機器上Redis的日誌
[[email protected] ~]# tail /var/log/redis/redis.log               # 查看Redis最後10行日誌2319:S 14 Oct 09:55:17.625 * MASTER <-> SLAVE sync started2319:S 14 Oct 09:55:17.625 * Non blocking connect for SYNC fired the event.2319:S 14 Oct 09:55:17.626 * Master replied to PING, replication can continue...2319:S 14 Oct 09:55:17.626 * Trying a partial resynchronization (request 9f93f85bce758b9c48e72d96a182a2966940cf52:16).2319:S 14 Oct 09:55:17.628 * Full resync from master: 7091f874c7c3eeadae873d3e6704e67637d8772b:1                  # 從master節點全量複製資料2319:S 14 Oct 09:55:17.629 * Discarding previously cached master state.2319:S 14 Oct 09:55:17.763 * MASTER <-> SLAVE sync: receiving 366035 bytes from master                  # 顯示從master同步的資料大小2319:S 14 Oct 09:55:17.765 * MASTER <-> SLAVE sync: Flushing old data       # slave清空原來的資料2319:S 14 Oct 09:55:17.779 * MASTER <-> SLAVE sync: Loading DB in memory    # 載入同步過來的RDB檔案2319:S 14 Oct 09:55:17.804 * MASTER <-> SLAVE sync: Finished with success
5.全量複製和部分複製5.1 全量複製5.1.1 run_id的概念

Redis每次啟動時,都有一個隨機ID來標識Redis,這個隨機ID就是上面通過info命令查看得到的run_id

查看192.168.81.101虛擬機器上的run_id和位移量

[[email protected] ~]# redis-cli info server |grep run_idrun_id:7e366f6029d3525177392e98604ceb5195980518[[email protected] ~]# redis-cli info |grep master_repl_offsetmaster_repl_offset:0

查看192.168.91.100虛擬機器上的run_id和位移量

[[email protected] ~]# redis-cli info server | grep run_idrun_id:7091f874c7c3eeadae873d3e6704e67637d8772b[[email protected] ~]# redis-cli info | grep master_repl_offsetmaster_repl_offset:4483

run_id是一個非常重要的標識。

在上面的例子裡,192.168.81.101做為slave去複製192.168.81.100這個master上的資料,會擷取192.168.81.100機器上對應的run_id在192.168.81.101上做一個標識

當192.168.81.100機器上的Redis的run_id發生改變,意味著192.168.81.100機器上的Redis發生重啟操作或者別的重大變化,192.168.81.101就會把192.168.81.100上的資料全部同步到192.168.81.101上,這就是全量複製的概念

5.1.2 offset的概念

位移量(offset)就是資料寫入量的位元組數。

在192.168.81.100的Redis上寫入資料時,master就會記錄寫了多少資料,並記錄在位移量中。

在192.168.81.100上的操作,會同步到192.168.81.101機器上,192.168.81.101上的Redis也會記錄位移量。

當兩台機器上的位移量相同時,代表資料同步完成

位移量是部分複製很重要的依據

查看192.168.81.100機器上Redis的位移量

127.0.0.1:6379> info replication    # 查看複製資訊# Replicationrole:masterconnected_slaves:1slave0:ip=192.168.81.101,port=6379,state=online,offset=8602,lag=0master_repl_offset:8602             # 此時192.168.81.100上的位移量是8602repl_backlog_active:1repl_backlog_size:1048576repl_backlog_first_byte_offset:2repl_backlog_histlen:8601127.0.0.1:6379> set k1 v1           # 向192.168.81.100寫入資料OK127.0.0.1:6379> set k2 v2           # 向192.168.81.100寫入資料OK127.0.0.1:6379> set k3 v3           # 向192.168.81.100寫入資料OK127.0.0.1:6379> info replication    # 查看複製資訊# Replicationrole:masterconnected_slaves:1slave0:ip=192.168.81.101,port=6379,state=online,offset=8759,lag=1master_repl_offset:8759             # 寫入資料後192.168.81.100上的位移量是8759repl_backlog_active:1repl_backlog_size:1048576repl_backlog_first_byte_offset:2repl_backlog_histlen:8758

查看192.168.81.101機器上Redis的位移量

127.0.0.1:6379> info replication    # 查看複製資訊# Replicationrole:slavemaster_host:192.168.81.100master_port:6379master_link_status:upmaster_last_io_seconds_ago:8master_sync_in_progress:0slave_repl_offset:8602slave_priority:100slave_read_only:1connected_slaves:0master_repl_offset:0                # 此時192.168.81.101上的位移量是8602repl_backlog_active:0repl_backlog_size:1048576repl_backlog_first_byte_offset:0repl_backlog_histlen:0127.0.0.1:6379> get k1"v1"127.0.0.1:6379> get k2"v2"127.0.0.1:6379> get k3"v3"127.0.0.1:6379> info replication    # 查看複製資訊# Replicationrole:slavemaster_host:192.168.81.100master_port:6379master_link_status:upmaster_last_io_seconds_ago:7master_sync_in_progress:0slave_repl_offset:8759              # 同步資料後192.168.81.101上的位移量是8759slave_priority:100slave_read_only:1connected_slaves:0master_repl_offset:0repl_backlog_active:0repl_backlog_size:1048576repl_backlog_first_byte_offset:0repl_backlog_histlen:0

如果主從節點上的offset差距太大,說明從節點沒有從主節點同步資料,主從節點之間的串連出現問題:比如網路,阻塞,緩衝區等

5.1.3 全量複製的概念

如果一個主節點上已經寫入很多資料,此時從節點不僅同步已經有的資料,同時同步slave在同步期間master上被寫入的資料(如果在同步期間master被寫入資料),以達到資料完全同步的目的,這就是Redis的全量複製的功能

Redis的master會把當前的RDB檔案同步給slave,在此期間master中寫入的資料會被寫入複製緩衝區(repl_back_buffer)中,當RDB檔案同步到slave完成,master通過位移量的對比,把複製緩衝區(repl_back_buffer)中的資料同步給slave

Redis使用psync命令進行資料全量複製和部分複製

psync命令有兩個參數:run_id和位移量

psync命令的步驟:

1.在slave第一次向master同步資料時,不知道master的run_id和offset,使用`psync ? -1`命令向master發起同步請求2.master接受請求後,知道slave是做全量複製,master就會把run_id和offset響應給slave3.slave儲存master發送過來的run_id和offset4.master響應slave後,執行BGSAVE命令把當前所有資料產生RDB檔案,然後將RDB檔案同步給slave5.Redis中的repl_back_buffer複製緩衝區可以記錄產生RDB檔案之後到同步完成這個時間段時寫入的資料,然後把這些資料也同步給slave6.slave執行flushall命令清空slave中原有的資料,然後從RDB檔案讀取所有的資料,保證slave與master中資料的同步

如所示:

5.1.4 全量複製的開銷
  • 全量複製的開銷非常大
  • master執行BGSAVE命令會消耗一定時間
  • BGSAVE命令會fork子進程,對CPU,記憶體和硬碟都有一個消耗
  • master將RDB檔案傳輸給slave的時間,傳輸過程中也會佔用一定的網路頻寬
  • slave清除原有資料的時間,如果slave中原有資料比較多,清空原有資料也會消耗一定的時間
  • slave載入RDB檔案會消耗一定時間
  • 可能的AOF檔案重寫的時間:RDB檔案載入完成,如果slave節點的AOF功能開啟,則會執行AOF重寫操作,保證AOF檔案中儲存最新的資料

    5.4 全量複製的問題

除了上面提到的開銷,如果master和slave之間的網路出現問題,則在一段時間內slave上同步的資料就會丟失

解決這個問題的最好辦法就是再做一次全量複製,同步master中所有資料

Redis 2.8版本中添加了部分複製的功能,如果發生master和slave之間的網路出現問題時,使用部分複製儘可能的減少遺失資料的可能,而不用全部複製

5.2 部分複製

當master與slave之間的串連斷開時,master在寫入資料同時也會把寫入的資料儲存到repl_back_buffer複製緩衝區中

當master與slave之間的網路連通後,slave會執行psync {offset} {run_id}命令,offset是slave節點上的位移量

master接收到slave傳輸的位移量,會與repl_back_buffer複製緩衝區中的offset做對比,
如果接收到的offset小於repl_back_buffer中記錄的位移量,master就會把兩個位移量之間的資料發送給slave,slave同步完成,slave中的資料就與master中的資料一致

如所示

6. 主從複製故障6.1 slave宕機

這種架構讀寫分離情況下,宕機的slave無法從master中同步資料

6.2 master宕機

Redis的master就無法提供服務了,只有slave可以提供資料讀取服務

解決方案:把其中一個slave為成master,以提供寫入資料功能,另外一台slave重新做為新的master的從節點,提供讀取資料功能,這種解決方案依然需要手動完成

主從模式沒有實現故障的自動轉移,這就是Redis的sentinel的作用了

7.開發營運常見的問題7.1 讀寫分離

讀寫分離:master負責寫入資料,把讀取資料的流量分攤到slave節點

讀寫分離一方面可以減輕master的壓力,另一方面又擴充了讀取資料的能力

讀寫分離可以遇到的問題:

7.1.1 複製資料延遲

大多數情況下,master採用非同步方式將資料同步給slave,在這個過程中會有一個時間差

當slave遇到阻塞時,接收資料會有一定延遲,在這個時間段內從slave讀取資料可能會出現資料不一致的情況

可以對master和slave的offset值進行監控,當offset值相差過多時,可以把讀流量轉換到master上,但是這種方式有一定的成本

7.1.2 讀到到期資料

Redis刪除到期資料的方式

方式一:懶惰策略
當Redis操作這個資料時,才會去看這個資料是否到期,如果資料已經到期,會返回一個-2給用戶端,表示查詢的資料已經到期
方式二:
每隔一個周期,Redis會採集一部分key,看這些key是否到期如果到期key非常多或者採樣速度慢於key到期速度時,就會有很多到期key沒有被刪除此時slave會同步包括到期key在內的master上的所有資料由於slave沒有刪除資料的許可權,此時基於讀寫分離的模式,用戶端會從slave中讀取一些到期的資料,也即髒資料
7.1.3 從節點故障

在圖9中,slave宕機,從slave節點遷移為master節點的成本很高

在考慮使用讀寫分離之前,首先要考慮最佳化master節點的問題

Redis的效能很高,可以滿足大部分情境,可以最佳化一些記憶體的配置參數或者AOF的策略,也可以考慮使用Redis分布式

7.2 主從配置不一致

第一種情況是:例如maxmemory不一致:遺失資料

如master節點分配的記憶體為4G,而slave節點分配的記憶體只有2G時,此時雖然可以進行正常的主從複製

但當slave從master同步的資料大於2G時,slave不會拋出異常,但會觸發slave節點的maxmemory-policy策略,對同步的資料進行一部分的淘汰,此時slave中的資料已經不完整了,造成遺失資料的情況

另一種主從配置不一致的情況是:對master節點進行資料結構最佳化,但是沒有對slave做同樣的最佳化,會造成master和slave的記憶體不一致

7.3 規避全量複製7.3.1 全量複製的開銷是非常大的

第一次為一個master配置一個slave時,slave中沒有任何資料,進行全量複製不可避免

解決方案:主從節點的maxmemory不要設定過大,則傳輸和載入RDB檔案的速度會很快,開銷相對會小一些,也可以在使用者訪問量比較低時進行全量複製

7.3.2 節點run_id不匹配

當master重啟時,master的run_id會發生變化。slave在同步資料時發現之前儲存的master的run_id與現在的run_id不匹配,會認為當前master不安全

解決方案:

做一次全量複製,當master發生故障時,slave轉換為master提供資料寫入,或者使用Redis哨兵和叢集

Redis4.0版本中提供新的方法:當master的run_id發生改變時,做容錯移轉可以避免做全量複製

7.3.3 複製緩衝區不足

複製緩衝區的作用是把新的命令寫入到緩衝區中

複製緩衝區實際是一個隊列,預設大小為1MB,即複製緩衝區只能儲存1MB大小的資料

如果slave與master的網路斷開,master就會把新寫入的資料儲存到複製緩衝區中

當寫入到複製緩衝區內的資料小於1MB時,就可以做部分複製,避免全量複製的問題如果新寫入的資料大於1MB時,就只能做全量複製了

在設定檔中修改rel_backlog_size選項來加大複製緩衝區的大小,來減少全量複製的情況出現

7.4 規避複製風暴

主從架構中,master節點重啟時,則master的run_id會發生變化,所有的slave節點都會進行主從複製

master產生RDB檔案,然後所有slave節點都會同步RDB檔案,在這個過程中對master節點的CPU,記憶體,硬碟有很大的開銷,這就是複製風暴

單主節點複製風暴解決方案

更換複製拓樸

單機多部署複製風暴

一台伺服器上的所有節點都是master,如果這台伺服器系統發生重啟,則所有的slave節點都從這台伺服器進行全量複製,會對伺服器造成很大的壓力主節點分散多機器    將master分配到不同的伺服器上
Redis的主從模式簡單總結
一個master可以有多個slave一個slave還可以有slave一個slave只能有一個master資料流向是單向的,只能從master到slave

高可用Redis(八):Redis主從複製

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.