一.原理部分: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主從