redis深度剖析: 02 redis主從讀寫分離(讀高併發)

一.原理部分:node

redis不能支撐高併發的瓶頸在哪裏?mysql

單機redis

若是redis要支撐超過10萬+的併發,那應該怎麼作?sql

單機的redis幾乎不太可能說QPS超過10萬+,除非一些特殊狀況,好比你的機器性能特別好,配置特別高,物理機,維護作的特別好,並且你的總體的操做不是太複雜vim

單機在幾萬centos

讀寫分離,通常來講,對緩存,通常都是用來支撐讀高併發的,寫的請求是比較少的,可能寫請求也就一秒鐘幾千,一兩千(瓶頸)緩存

大量的請求都是讀,一秒鐘二十萬次讀安全

讀寫分離網絡

主從架構 -> 讀寫分離 -> 支撐10萬+讀QPS的架構架構

不用redis承載很高的併發,要靠mysql來支撐的狀況,通常出如今須要不少的 強事物 的狀況下

redis主從的最最基本原理:

redis主從的核心機制:

(1)redis採用異步方式複製數據到slave節點,不過redis 2.8開始,slave node會週期性地確認本身每次複製的數據量

(2)一個master node是能夠配置多個slave node的

(3)slave node也能夠鏈接其餘的slave node

(4)slave node作複製的時候,是不會block master node的正常工做的

(5)slave node在作複製的時候,也不會block對本身的查詢操做,它會用舊的數據集來提供服務; 可是複製完成的時候,須要刪除舊數據集,加載新數據集,這個時候就會暫停對外服務了

(6)slave node主要用來進行橫向擴容,作讀寫分離,擴容的slave node能夠提升讀的吞吐量

master持久化對於主從架構的安全保障的意義:

若是採用了主從架構,那麼建議必須開啓master node的持久化!

master -> RDB和AOF都關閉了 -> 所有在內存中

master宕機,重啓,是沒有本地數據能夠恢復的,而後就會直接認爲本身IDE數據是空的

master就會將空的數據集同步到slave上去,全部slave的數據所有清空

100%的數據丟失

master節點,必需要使用持久化機制

第二個,master的各類備份方案,萬一說本地的全部文件丟失了; 從備份中挑選一份rdb去恢復master; 這樣才能確保master啓動的時候,是有數據的

即便採用了後續講解的高可用機制,slave node能夠自動接管master node,可是也可能sentinal尚未檢測到master failure,master node就自動重啓了,仍是可能致使上面的全部slave node數據清空故障

主從架構的核心原理:

(1)當啓動一個slave node的時候,它會發送一個PSYNC命令給master node

(2)若是這是slave node從新鏈接master node,那麼master node僅僅會複製給slave部分缺乏的數據; 不然若是是slave node第一次鏈接master node,那麼會觸發一次full resynchronization

(3)開始full resynchronization的時候,master會啓動一個後臺線程,開始生成一份RDB快照文件,同時還會將從客戶端收到的全部寫命令緩存在內存中。RDB文件生成完畢以後,master會將這個RDB發送給slave,slave會先寫入本地磁盤,而後再從本地磁盤加載到內存中。而後master會將內存中緩存的寫命令發送給slave,slave也會同步這些數據。

(4)slave node若是跟master node有網絡故障,斷開了鏈接,會自動重連。master若是發現有多個slave node都來從新鏈接,僅僅會啓動一個rdb save操做,用一份數據服務全部slave node。

正常狀況下,寫數據,就是master 寫入成果以後,會給到slave一個寫命令,slave執行寫命令同步數據完成

主從複製斷點續傳:

master node會在內存中常見一個backlog,master和slave都會保存一個replica offset還有一個master id,offset就是保存在backlog中的。若是master和slave網絡鏈接斷掉了,slave會讓master從上次的replica offset開始繼續複製

可是若是沒有找到對應的offset,那麼就會執行一次resynchronization

無磁盤化複製:

master在內存中直接建立rdb,而後發送給slave,不會在本身本地落地磁盤了

也能夠去把無磁盤化打開,走master 本身的RDB持久化機制落到磁盤上,複製的時候不觸發拍攝快照

repl-diskless-sync yes

repl-diskless-sync-delay 5  #等待必定時長再開始複製,由於要等更多slave從新鏈接過來

過時key處理:

slave不會過時key,只會等待master過時key。若是master過時了一個key,或者經過LRU淘汰了一個key,那麼會模擬一條del命令發送給slave。

主從原理深度剖析:

複製的完整流程:

(1)slave node啓動僅僅保存master node信息,包括master node的host和ip,可是複製流程沒開始

master host 和 ip 是從哪兒來的,redis.conf裏面的slaveof配置的

(2)slave node內部有一個定時任務,每秒檢查是否有新的master node要鏈接和複製,若是發現,就跟master node創建socket鏈接

(3)slave node發送ping命令給master node

(4)口令認證,若是master設置了requirepass,那麼salve node必須發送masterauth的口令過去進行認證

(5)master node第一次執行全量複製,將全部數據發給slave node

(6)master node後續持續將寫命令,異步複製給slave node

數據同步相關的核心機制:(這裏指的是slave第一次鏈接master(全量))

(1)master 和slave 都會維護一個offset

master會在自身不端累加offset,slave也會在自身不端累加offset

slave每秒會都上報本身的offset給master,同時master也會保存每一個slave的offset

offset不光是用在全量複製,主要是master和slave都要知道各自數據的offset,才能知道雙方數據是否一致

(2)backlog

master node有一個backlog,默認是1MB大小

master node給slave node複製數據時,也會將數據再backlog中同步寫一份

backlog主要是用來作全量複製中斷開時候的增量複製的

(3)master run id

info server,能夠看到master run id

若是根據host+ip定位master node,是不靠譜的,若是master node重啓或者數據出現了變化,那麼slave node應該根據不一樣的run id區分,run id不一樣就作全量複製

若是須要不更改run id重啓redis,可使用redis-cli debug reload命令

也就是說,咱們若是給slave換了一個master,slave 會根據master run id發生變化而從新全量更新數據

(4)psync

從節點使用psync從master node進行復制,psync runid offset

master node會根據自身的狀況返回響應信息,多是FULLRESYNC runid offset觸發全量複製,多是CONTINUE觸發增量複製

全量複製:

(1)master執行bgsave,在本地生成一份rdb快照文件

(2)master node將rdb快照文件發送給salve node,若是rdb複製時間超過60秒(repl-timeout),那麼slave node就會認爲複製失敗,能夠適當調節大這個參數

(3)對於千兆網卡的機器,通常每秒傳輸100MB,6G文件,極可能超過60s

(4)master node在生成rdb時,會將全部新的寫命令緩存在內存中,在salve node保存了rdb以後,再將新的寫命令複製給salve node

(5)client-output-buffer-limit slave 256MB 64MB 60,若是在複製期間(60秒),內存緩衝區持續消耗超過64MB,或者一次性超過256MB,那麼中止複製,複製失敗

(6)slave node接收到rdb以後,清空本身的舊數據,而後從新加載rdb到本身的內存中,同時基於舊的數據版本對外提供服務

(7)若是slave node開啓了AOF,那麼會當即執行BGREWRITEAOF,重寫AOF

rdb生成、rdb經過網絡拷貝、slave舊數據的清理、slave aof rewrite,很耗費時間

若是複製的數據量在4G~6G之間,那麼極可能全量複製時間消耗到1分半到2分鐘

增量複製:

(1)若是全量複製過程當中,master-slave網絡鏈接斷掉,那麼salve從新鏈接master時,會觸發增量複製

(2)master直接從本身的backlog中獲取部分丟失的數據,發送給slave node,默認backlog就是1MB

(3)msater就是根據slave發送的psync中的offset來從backlog中獲取數據的

heartbeat:

主從節點互相都會發送heartbeat信息

master默認每隔10秒發送一次heartbeat,salve node每隔1秒發送一個heartbeat

異步複製:

master每次接收到寫命令以後,如今內部寫入數據,而後異步發送給slave node

二.配置主從複製

兩臺主機:

系統環境:centos7.3

masterIP:192.168.92.100       端口6379

slaveIP:192.168.92.101         端口6379

一、安裝

在兩臺主機上安裝redis

[root@localhost ~]# tar zxf redis-3.2.3.tar.gz

[root@localhost  ~]# cd redis-3.2.3/

[root@localhost  redis-3.2.3]# make&& make install

[root@localhost  redis-3.2.3]# cd utils/

[root@localhost  utils]# ./install_server.sh

#按照默認位置便可(回車下去就好)

Welcome to the redis service installer

This script will help you easily set up a running redis server

Please select the redis port for this instance: [6379]

Selecting default: 6379

Please select the redisconfig file name [/etc/redis/6379.conf]

Selected default - /etc/redis/6379.conf

Please select the redis log file name [/var/log/redis_6379.log]

Selected default - /var/log/redis_6379.log

Please select the data directory for this instance [/var/lib/redis/6379]

Selected default - /var/lib/redis/6379

Please select the redis executable path [/usr/local/bin/redis-server]

Selected config:

Port : 6379

Config file : /etc/redis/6379.conf

Log file : /var/log/redis_6379.log

Data dir : /var/lib/redis/6379

Executable : /usr/local/bin/redis-server

CliExecutable : /usr/local/bin/redis-cli

Is this ok? Then press ENTER to go on or Ctrl-C to abort.

Copied /tmp/6379.conf => /etc/init.d/redis_6379

Installing service...

Successfully added to chkconfig!

Successfully added to runlevels 345!

Starting Redis server...

Installation successful!

二、主從配置

一、修改master主配置文件

#vim /etc/redis/6379.conf

bind 127.0.0.1 192.168.92.100                 #增長一個192.168.92.100的地址

daemonize  yes                                         #no 改成yes

requirepass  pwd@123                              # 設置登陸密碼

二、修改slave主配置文件

#vim /etc/redis/6379.conf

bind 127.0.0.1 192.168.92.101                  #增長一個192.168.92.101的地址

daemonize  yes                                         #no 改成yes

requirepass  pwd@123                              # 設置登陸密碼

slaveof  192.168.92.100 6379                 #設置master的地址和端口號

masterauth pwd@123                              #設置master的密碼

三、啓動master和slave

啓動master

# /etc/init.d/redis_6379 restart

啓動slave

# /etc/init.d/redis_6379 restart

四、建立數據測試主從

master上建立數據

#redis-cli -p 6379 -a pwd@123

127.0.0.1:6379> set name abc

OK

127.0.0.1:6379> get name

"abc"

在slave上查看數據

#redis-cli -p 6379 -a pwd@123

127.0.0.1:6379> get name

"abc"

五、默認是讀寫分離的slave沒有寫入權限(slave上操做)

127.0.0.1:6379> set name 123

(error) READONLY You can't write against a read only slave.

三、主從切換

一、停掉master上的redis(master上操做)

#redis-cli -n 6379 -a pwd@123 shutdown

#redis-cli -p 6379

Could not connect to Redis at 127.0.0.1:6379: Connection refused

not connected>

二、將從redis設成主redis(slave上操做)

#redis-cli -p 6379 -a pwd@123 slaveof NO ONE

OK

三、測試slave是否能寫入數據了(slave上操做)

#redis-cli -p 6379 -a pwd@123

127.0.0.1:6379> set name 123

OK

127.0.0.1:6379> get name

"123"

四、原來的主redis恢復正常了,要從新切換回去

1)將如今的slave上的數據進行保存(slave上操做)

127.0.0.1:6379> save

OK

2)將slave上的dump.rdb文件拷貝到master上(slave上操做)

#scp /var/lib/redis/6379/dump.rdb 192.168.92.100:/var/lib/redis/6379/

3)啓動原來的master(master上操做)

#redis-server /etc/redis/6379.conf                #或者用 # /etc/init.d/redis_6379 restart

4)在slave中切換(slave 上操做)

#redis-cli -p 6379 -a pwd@123 slaveof 192.168.92.100 6379

OK

5)到這裏就切換回來了,回到了一個最初的狀態


# 後續繼續發表 Redis Sentinel 深度剖析,完善redis主從

相關文章
相關標籤/搜索