高并發(fā)redis - 讀寫分離支撐qps10w+

之前講到單機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。
    • 第二,當一臺性能不夠用,可以橫向擴展機器,就能達到擴容的效果。
單機redis瓶頸.png
  • 2.如何redis要支撐超過10w+的并發(fā),那應該怎么做?
    • 單機redis幾乎不可能超過10w+,除非機器性能非常好,物理機,維護好,操作簡單
    • 所以必須能橫向擴展,采取讀寫分離主從架構(master - slave)
      • 一個主節(jié)點,只寫數據
      • 多個從節(jié)點,主節(jié)點把數據同步給多個從節(jié)點
      • 然后讀就從從節(jié)點讀,分攤讀壓力,從節(jié)點還可以橫向擴展
redis主從架構示意.png

注意:讀寫分離是分攤讀請求的壓力,如果是寫請求的操作瓶頸,需要通過cluster讓多節(jié)點寫,
或者通過異步隊列,異步完成寫操作的方式解決

2、解釋什么是讀寫分離以及讀寫分離流程與原理

讀寫分離就是基于redis replication搭建多個redis節(jié)點,然后分為master主節(jié)點,slave從節(jié)點。
master節(jié)點主要作用是接收所有寫請求,寫數據,然后同步到slave。然后多個slave節(jié)點,每個都有
全量的數據,分攤讀請求。簡單是說,就是master只負責寫和同步數據到slave,slave只負責讀。
這種架構適用于讀多寫少的系統(tǒng),slave可以橫向擴展,接收更多的讀請求。

redis replication基本原理.png

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
redis主從復制的原理.png

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
slave設置成功replication信息.png

驗證數據同步:

  • 首先進入master的redis-cli ,執(zhí)行 set name along
  • 然后去從節(jié)點去執(zhí)行命令:get name ,如果發(fā)現,能獲取到,就說明master把數據同步給了slave

5、總結

  • 當面對讀多寫少的業(yè)務場景,可以選擇redis主從復制,讀寫分離的架構
  • 單機是redis提高qps的瓶頸,好的架構能橫向擴展
  • 主從復制,讀寫分離的一些缺點
    • 如何保證高可用?(這個后面在哨兵中講解)
    • 每個redis都是全量數據,比較浪費內存(后面cluster有解決方案)
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容