之前講到單機redis的為了保證數據安全,必須做好數據備份等基礎工作。但是如果流量越來越大,
redis的讀寫請求壓力越來越大,到了一個極限值,性能依舊不夠用我們應該如何處理?
這邊文章就分為以下幾步來一次介紹redis讀寫分離:
- 1、兩個問題分析redis瓶頸
- 2、解釋什么是讀寫分離以及讀寫分離流程與原理
- 3、讀寫分離對于數據的安全意義
- 4、docker搭建一主兩從讀寫分離的實戰(zhàn)(附帶配置和操作流程)
- 5、總結
1、兩個問題分析redis瓶頸
所以先看看一下兩個問題:
- 1.redis不能支撐高并發(fā)的瓶頸在哪里?
- 第一,一臺redis的性能首先和機器性能,業(yè)務復雜度,以及redis操作的復雜度這三點是密切相關的。
- 如果是單純的String ,key,value操作,性能一般能到1-5w qps。
- 第二,當一臺性能不夠用,可以橫向擴展機器,就能達到擴容的效果。

- 2.如何redis要支撐超過10w+的并發(fā),那應該怎么做?
- 單機redis幾乎不可能超過10w+,除非機器性能非常好,物理機,維護好,操作簡單
- 所以必須能橫向擴展,采取讀寫分離主從架構(master - slave)
- 一個主節(jié)點,只寫數據
- 多個從節(jié)點,主節(jié)點把數據同步給多個從節(jié)點
- 然后讀就從從節(jié)點讀,分攤讀壓力,從節(jié)點還可以橫向擴展

注意:讀寫分離是分攤讀請求的壓力,如果是寫請求的操作瓶頸,需要通過cluster讓多節(jié)點寫,
或者通過異步隊列,異步完成寫操作的方式解決
2、解釋什么是讀寫分離以及讀寫分離流程與原理
讀寫分離就是基于redis replication搭建多個redis節(jié)點,然后分為master主節(jié)點,slave從節(jié)點。
master節(jié)點主要作用是接收所有寫請求,寫數據,然后同步到slave。然后多個slave節(jié)點,每個都有
全量的數據,分攤讀請求。簡單是說,就是master只負責寫和同步數據到slave,slave只負責讀。
這種架構適用于讀多寫少的系統(tǒng),slave可以橫向擴展,接收更多的讀請求。

master和slave數據同步的完整流程
首先介紹一下復制過程中的一些核心機制
-
offset
- master和slave都會維護一個offset
- 主要作用是在全量復制過程中記錄上方的數據差異
- slave每秒都會上報自己的offset給master,同時master也會保存每個slave的offset
- 這個倒不是說特定就用在全量復制的,主要是master和slave都要知道各自的數據的offset,才能知道互相之間的數據不一致的情況
-
backlog
- master node有一個backlog,默認是1MB大小
- master node給slave node復制數據時,也會將數據在backlog中同步寫一份
- backlog主要是用來做全量復制中斷后的增量復制的
-
master run id
- info server,可以看到master run id
- 如果根據host+ip定位master node,是不靠譜的,如果master node重啟或者數據出現了變化,那么slave node應該根據不同的run id區(qū)分,run id不同就做全量復制
- 如果需要不更改run id重啟redis,可以使用redis-cli debug reload命令
-
psync
- 從節(jié)點使用psync從master node進行復制,psync runid offset
- master node會根據自身的情況返回響應信息,可能是FULLRESYNC runid offset觸發(fā)全量復制,可能是CONTINUE觸發(fā)增量復
-
heartbeat
- 主從節(jié)點互相都會發(fā)送heartbeat信息
- master默認每隔10秒發(fā)送一次heartbeat,salve node每隔1秒發(fā)送一個heartbeat
-
主從復制的斷點續(xù)傳
- 如果主從復制過程中,網絡連接斷開了,那么可以接著上次復制的地方,連續(xù)復制下去,而不是從頭開始復制一份
- master node會在內存中存一個backlog,master和skave都會保存一個replica offset 還有一個master id ,offset就是保存在backlog中的,如果master和slave網絡連接斷掉了,slave會讓master從上次的replica offset 開始繼續(xù)復制。但是如果沒有找到對應的offset,那么就會執(zhí)行一次 resynchronhronization
數據復制流程:
-
復制的完整流程
- msater就是根據slave發(fā)送的psync中的offset來從backlog中獲取數據的
- slave node內部有個定時任務,每秒檢查是否有新的master node要連接和復制,如果發(fā)現,就跟master node建立socket網絡連接。
- slave node發(fā)送ping命令給master node
- master node第一次執(zhí)行全量復制,將所有數據發(fā)給slave node
- master node后續(xù)持續(xù)將寫命令,異步增量復制給slave node
主從復制的完整的基本流程.png
-
全量復制
- 當slave剛連上來,或者master重啟,run id不一致,就執(zhí)行全量復制
- master執(zhí)行bgsave,在本地生成一份rdb快照文件
- master node將rdb快照文件發(fā)送給salve node,如果rdb復制時間超過60秒(repl-timeout),那么slave node就會認為復制失敗,可以適當調節(jié)大這個參數
- master node在生成rdb時,會將所有新的寫命令緩存在內存中,在salve node保存了rdb之后,再將新的寫命令復制給salve node
- slave node接收到rdb之后,清空自己的舊數據,然后重新加載rdb到自己的內存中,同時基于舊的數據版本對外提供服務
- 如果slave node開啟了AOF,那么會立即執(zhí)行BGREWRITEAOF,重寫AOF
- 注意:
- master node將rdb快照文件發(fā)送給salve node,如果rdb復制時間超過60秒(repl-timeout),那么slave node就會認為復制失敗,可以適當調節(jié)大這個參數
- 對于千兆網卡的機器,一般每秒傳輸100MB,6G文件,很可能超過60s
- client-output-buffer-limit slave 256MB 64MB 60,如果在復制期間,內存緩沖區(qū)持續(xù)消耗超過64MB,或者一次性超過256MB,那么停止復制,復制失敗
- rdb生成、rdb通過網絡拷貝、slave舊數據的清理、slave aof rewrite,很耗費時間
- 如果復制的數據量在4G~6G之間,那么很可能全量復制時間消耗到1分半到2分鐘
-
增量復制
- 如果全量復制過程中,master-slave網絡連接斷掉,那么salve重新連接master時,會觸發(fā)增量復制
- master直接從自己的backlog中獲取部分丟失的數據,發(fā)送給slave node,默認backlog就是1MB
- msater就是根據slave發(fā)送的psync中的offset來從backlog中獲取數據的
-
異步復制
- master每次接收到寫命令之后,先在內部寫入數據,然后異步發(fā)送給slave node

3、讀寫分離對于數據的安全意義
- 首先,master是必須做數據持久化的,因為這里是數據來源,slave做不做無所謂了。
- 然后,沒個slave都有全量數據,也就可以成為master的一個熱備份,當master掛了,能頂上去
- slave頂替master在后面哨兵繼續(xù)講。
4、docker搭建一主兩從讀寫分離的實戰(zhàn)(附帶配置和操作流程)
都是放在/data/redis/redis.conf下,dir都是容器內的/data目錄。
redis的master節(jié)點配置:
port 6379
requirepass "123456"
dbfilename "dump.rdb"
dir "/data"
logfile "/data/redis.log"
save 10 5
appendonly yes
appendfsync everysec
redis的slave配置(slave的ip和端口,填寫自己的master,我這里是192.168.5.48 6379)
port 6379
requirepass "123456"
slaveof 192.168.5.10 6379
masterauth "123456"
slave-read-only yes
docker啟動腳本
docker run -d --name redis -p 6379:6379 -v /data/redis/:/data/ redis redis-server /data/redis.conf
啟動容器后,查看replication的命令
docker exec -it redis /bin/bash
redis-cli -h 127.0.0.1 -a 123456 -p 6379
info replication
操作步驟
- 準備三臺centos虛擬機(可參照我之前的文章:virtualBox+vagrant搭建多節(jié)點虛機)
- 復制master的redis配置到/data/redis/redis.conf
- 使用docker啟動命令啟動master的redis
- 另外兩臺虛擬機重復上面的操作,唯一不同的就是修改redis.conf內容為上面從節(jié)點的配置,注意修改slave of的ip和端口
-
三個redis都啟動完畢,就在每臺機器上執(zhí)行上面查看replication命令,查看集群是否搭建完畢。下圖是搭建成功的示例。
master設置成功replication信息.png

驗證數據同步:
- 首先進入master的redis-cli ,執(zhí)行
set name along - 然后去從節(jié)點去執(zhí)行命令:
get name,如果發(fā)現,能獲取到,就說明master把數據同步給了slave
5、總結
- 當面對讀多寫少的業(yè)務場景,可以選擇redis主從復制,讀寫分離的架構
- 單機是redis提高qps的瓶頸,好的架構能橫向擴展
- 主從復制,讀寫分離的一些缺點
- 如何保證高可用?(這個后面在哨兵中講解)
- 每個redis都是全量數據,比較浪費內存(后面cluster有解決方案)

