三個重要的標準:
---大型緩存架構中需要首先說一下:
海量數據:支持海量數據緩存,支持大規模數據;
高并發:在億級QPS的場景下,可以做到滿足業務需求;
高可用:表示redis可以做到并且盡可能的做到可以持續使用。比如全年保持99.99%的時間處在可用狀態,除非遇到各種斷電等特殊災害;
-------------------------------------------------------------------------------------------------------
商品詳情頁的系統架構介紹-->兩種設計類型:
小型電商:
靜態模板是固定的 數據庫中的數據全量喧嚷到模板中,下次請求來了直接返回,速度也很快;
缺點:當數據上億的時候,如果模板改定,把這些所有的數據在MySQL中取出后渲染進模板,非常耗時,不現實;
大型電商
-- 使用大型的高級緩存架構:
設計緩存數據生產服務模塊;
不需要再進行全量重新渲染,直接將最新的html模板推送到Nginx服務器,請求過來后直接在nginx本地進行渲染進模板中返回請求;
************redis單機理論 ************
redis的重要性:
------------------------------------------------------------------------------------------
虛擬機環境設置[1]
---- 安裝ISO + 配置網絡 + 安裝JDK+Perl + SSH免密通信:
虛擬機中安裝centos
啟動一個virtual box虛擬機管理軟件 使用CentOS 6.5鏡像即可,CentOS-6.5-i386-minimal.iso
配置網絡
vi /etc/sysconfig/network-scripts/ifcfg-eth0 ---- 修改linux的網絡配置
刪除對應的項目,保留如下的配置:
DEVICE=eth0TYPE=EthernetONBOOT=yesBOOTPROTO=dhcp
wq保存;
重啟網絡:service network restart使用ifconfig查詢當前自動分配的網址;
將當前的網址設置為靜態ip,加入下面的靜態配置:
BOOTPROTO=staticIPADDR=192.168.0.XNETMASK=255.255.255.0GATEWAY=192.168.0.1
網絡服務重啟:service network restart
配置hosts【相當于給本機起別名】
vi /etc/hosts
192.168.0.X eshop-cache01其他主機,添加類似配置。實現本機的hostname到ip地址的映射
配置SecureCRT【本人使用的Xshell 感覺也很好用】
此時就可以使用SecureCRT從本機連接到虛擬機進行操作了
關閉linux防火墻
service iptables stopservice ip6tables stopchkconfig iptables offchkconfig ip6tables off
vi /etc/selinux/configSELINUX=disabled
關閉windows的防火墻
配置yum
yum clean allyum makecacheyum install wget
------------------------------------------------------------------------------------------
在每個CentOS中都安裝JAVA和Perl
(WinSCP,就是在windows宿主機和linux虛擬機之間互相傳遞文件的一個工具。)
(1)安裝JDK
1、將jdk-7u60-linux-i586.rpm通過WinSCP上傳到虛擬機中2、安裝JDK:rpm -ivh jdk-7u65-linux-i586.rpm3、配置jdk相關的環境變量vi .bashrcexport JAVA_HOME=/usr/java/latestexport PATH=$PATH:$JAVA_HOME/binsource .bashrc4、測試jdk安裝是否成功:java -version
(2)安裝Perl
yum install -y gcc
wget http://www.cpan.org/src/5.0/perl-5.16.1.tar.gztar -xzf perl-5.16.1.tar.gzcd perl-5.16.1./Configure -des -Dprefix=/usr/local/perlmake && make test && make installperl -v
為什么要裝perl?我們整個大型電商網站的詳情頁系統,復雜。java+nginx+lua,需要perl。
perl,是一個基礎的編程語言的安裝,Tomcat,跑java web應用
------------------------------------------------------------------------------------------
3、在4個虛擬機中安裝CentOS集群
(1)按照上述步驟,再安裝三臺一模一樣環境的linux機器(2)另外三臺機器的hostname分別設置為eshop-cache02,eshop-cache03,eshop-cache04(3)安裝好之后,在每臺機器的hosts文件里面,配置好所有的機器的ip地址到hostname的映射關系
比如說,在eshop-cache01的hosts里面
192.168.31.187 eshop-cache01192.168.31.xxx eshop-cache02192.168.31.xxx eshop-cache03192.168.31.xxx eshop-cache04
------------------------------------------------------------------------------------------
4、配置4臺CentOS為ssh免密碼互相通信【此時四臺linux虛擬機可以通過ssh實現無密碼輸入通信】
(1)首先在四臺機器上配置對本機的ssh免密碼登錄ssh-keygen -t rsa生成本機的公鑰,過程中不斷敲回車即可,ssh-keygen命令默認會將公鑰放在/root/.ssh目錄下cd /root/.sshcp id_rsa.pub authorized_keys將公鑰復制為authorized_keys文件,此時使用ssh連接本機就不需要輸入密碼了
(2)接著配置三臺機器互相之間的ssh免密碼登錄使用ssh-copy-id -i hostname命令將本機的公鑰拷貝到指定機器的authorized_keys文件中
虛擬機環境設置[2]:
---- 單機版Redis安裝以及生產環境設置(開機自啟動)
1、安裝單機版tcl + redis
1. wget http://downloads.sourceforge.net/tcl/tcl8.6.1-src.tar.gz2. tar -xzvf tcl8.6.1-src.tar.gz3. cd /usr/local/tcl8.6.1/unix/4. ./configure5. make && make install
6. 使用redis-3.2.8.tar.gz(截止2017年4月的最新穩定版)7. tar -zxvf redis-3.2.8.tar.gz8. cd redis-3.2.89. make && make test && make install
------------------------------------------------------------------------
2、redis的生產環境啟動方案
如果一般的學習課程,你就隨便用redis-server啟動一下redis,做一些實驗,這樣的話,沒什么意義
1. 要把redis作為一個系統的daemon進程去運行的,每次系統啟動,redis進程一起啟動
(1)redis utils目錄下,有個redis_init_script腳本(2)將redis_init_script腳本拷貝到linux的/etc/init.d目錄中(初始化目錄),將redis_init_script重命名為redis_6379,6379是我們希望這個redis實例監聽的端口號(3)修改redis_6379腳本的第6行的REDISPORT,設置為相同的端口號(默認就是6379)(4)創建兩個目錄:
/etc/redis(存放redis的配置文件),
/var/redis/6379(存放redis的持久化文件,也就是后面要使用的redis備份)(5)修改redis配置文件(默認在根目錄下,redis.conf),拷貝到/etc/redis目錄中,修改名稱為6379.conf
(6)修改redis.conf中的部分配置為生產環境
daemonize yes 讓redis以daemon進程運行(守護線程,可以理解為java運行時的jvm線程,在后臺進行service服務)
pidfile /var/run/redis_6379.pid 設置redis的pid文件位置 【/var/run 目錄下放的是各程序的pid】
port 6379 設置redis的監聽端口號
dir /var/redis/6379 設置持久化文件的存儲位置
(7)啟動redis,執行cd /etc/init.d, chmod 777 redis_6379,
./redis_6379 start
(8)確認redis進程是否啟動,ps -ef | grep redis
(9)讓redis跟隨系統啟動自動啟動
在redis_6379腳本中,最上面,加入兩行注釋
# chkconfig: 2345 90 10
# description: Redis is a persistent key-value database
在Xshell中執行 chkconfig redis_6379 on
------------------------------------------------------------------------
3、redis cli的使用
redis-cli SHUTDOWN,連接本機的6379端口停止redis進程;
redis-cli -h 127.0.0.1 -p 6379 SHUTDOWN,制定要連接的ip和端口號
redis-cli PING,ping redis的端口,看是否正常
redis-cli,進入交互式命令行:
存取刪測試:
set k1 v1
get k1
del k1
------------------------------------------------------------------------------------------------
redis的使用以及原理分析:
redis的技術,包括4塊:
redis各種數據結構和命令的使用,包括java api的使用,這類操作命令其他的博客非常完善,可以經常性的查詢熟悉;redis一些特殊的解決方案的使用,pub/sub消息系統,分布式鎖,輸入的自動完成等;redis日常的管理相關的命令;redis企業級的集群部署和架構;
1、redis持久化的意義:
Note:
--- Redis在不使用備份的情況下會產生緩存雪崩問題,也就是redis宕機后,沒有備份的情況下,所有查詢操作全部直接涌入數據庫,導致數據庫機器宕機;
兩種備份方式分析:
---下邊堆 redis 寫如數據的兩種方式進行分析:
原理圖:
redis 的 AOF 下的 rewrite 機制原理:
AOF和RDB兩種模式:
AOF機制對每條寫入命令作為日志,以Append-only的模式寫入一個日志文件中,在redis重啟的時候,可以通過回放AOF日志中的寫入指令來重新構建整個數據集
如果我們想要redis僅僅作為純內存的緩存來用,那么可以禁止RDB和AOF所有的持久化機制【但是采用這種方式的項目是個高危項目】
通過RDB或AOF,都可以將redis內存中的數據給持久化到磁盤上面來,然后可以將這些數據備份到別的地方去,比如云服務
如果redis掛了,服務器上的內存和磁盤上的數據都丟了,可以從云服務上拷貝回來之前的數據,放到指定的目錄中,然后重新啟動redis,redis就會自動根據持久化數據文件中的數據,去恢復內存中的數據,繼續對外提供服務【這個地方就可以看出redis確實很高級】
如果同時使用RDB和AOF兩種持久化機制,那么在redis重啟的時候,會使用AOF來重新構建數據,因為AOF中的數據更加完整
RDB持久化機制,對redis中的數據執行周期性的持久化,也就是每個固定的時間去做一次內存快照的保存工作,適合做冷備份。
-------------------------------------------------------------------------------------
RDB持久化機制的優點
(1)RDB會生成多個數據文件,每個數據文件都代表了某一個時刻中redis的數據,這種多個數據文件的方式,非常適合做冷備,可以將這種完整的數據文件發送到一些遠程的安全存儲上去,比如說Amazon的S3云服務上去,在國內可以是阿里云的ODPS分布式存儲上,以預定好的備份策略來定期備份redis中的數據
(2)RDB對redis對外提供的讀寫服務,影響非常小,可以讓redis保持高性能,因為redis主進程只需要fork一個子進程,讓子進程執行磁盤IO操作來進行RDB持久化即可
(3)相對于AOF持久化機制來說,直接基于RDB數據文件【AOF為指令日志】來重啟和恢復redis進程,更加快速。【rdb基于數據,恢復速度快】
-------------------------------------------------------------------------------------
RDB持久化機制的缺點
(1)如果想要在redis故障時,盡可能少的丟失數據,那么RDB沒有AOF好。
一般來說,RDB數據快照文件,都是每隔5分鐘,或者更長時間生成一次,這個時候就得接受一旦redis進程宕機,那么會丟失最近5分鐘的數據。
(2)RDB每次在fork子進程來執行RDB快照數據文件生成的時候,如果數據文件特別大,可能會導致對客戶端提供的服務暫停數毫秒,或者甚至數秒
-------------------------------------------------------------------------------------
AOF持久化機制的優點
(1)AOF可以更好的保護數據不丟失,一般AOF會每隔1秒,通過一個后臺線程執行一次fsync操作,最多丟失1秒鐘的數據。
(2)AOF日志文件以append-only模式寫入,所以沒有任何磁盤尋址的開銷,寫入性能非常高,而且文件不容易破損,即使文件尾部破損,也很容易修復
(3)AOF日志文件即使過大的時候,出現后臺重寫操作,也不會影響客戶端的讀寫。因為在rewrite log的時候,會對其中的指導進行壓縮,創建出一份需要恢復數據的最小日志出來。在創建新日志文件的時候,老的日志文件還是照常寫入。當新的merge后的日志文件ready的時候,再交換新老日志文件即可。
(4)AOF日志文件的命令通過非常可讀的方式進行記錄,這個特性非常適合做災難性的誤刪除的緊急恢復。比如某人不小心用 【 flushall 】 命令清空了所有數據,只要這個時候后臺rewrite還沒有發生,那么就可以立即拷貝AOF文件,將最后一條flushall命令給刪了,然后再將該AOF文件放回去,就可以通過恢復機制,自動恢復所有數據。
-------------------------------------------------------------------------------------
AOF持久化機制的缺點
(1)對于同一份數據來說,AOF日志文件通常比RDB數據快照文件更大
(2)AOF開啟后,支持的寫QPS會比RDB支持的寫QPS低,因為AOF一般會配置成每秒fsync一次日志文件,當然,每秒一次fsync,性能也還是很高的
(3)以前AOF發生過bug,就是通過AOF記錄的日志,進行數據恢復的時候,沒有恢復一模一樣的數據出來。所以說,類似AOF這種較為復雜的基于命令日志/merge/回放的方式,比基于RDB每次持久化一份完整的數據快照文件的方式,更加脆弱一些,容易有bug。不過AOF就是為了避免rewrite過程導致的bug,因此每次rewrite并不是基于舊的指令日志進行merge的,而是基于當時內存中的數據進行指令的重新構建,這樣健壯性會好很多。
-------------------------------------------------------------------------------------
linux環境下 redis 的默認配置中 AOF 模式是關閉的 可以從配置文件 appendonly=no 看到,而 默認打開的是 RDB 模式;
在兩種模式都開啟的情況下,做數據恢復的時候優先使用AOF的數據;
下面重點對AOF模式的配置進行分析:
設置appendonly=yes;
設置appendfsync,對于設置linux緩存oscache支持的選項 always, everysec,no;
設置auto-aof-rewrite-percentage 1-100 用來設置現在aof文件大小相比于上次rewrite時空間增加的比例 比如設置為100 則表示 在比上一次增大了一倍時再次rewrite
設置auto-aof-rewrite-min-size XXmb 最小rewrite空間大小,以mb為單位,必須超過該空間才有可能觸發rewrite,每次都會進行比較;
AOF的 rewrite 過程描述:
rewrite的實現圖,在創建新aof文件時如果有新的client加入數據時的場景,新的數據會都保存在新舊aof文件中后再刪除舊的aof文件;
redis的數據受損修復功功能:
2、企業級的數據備份方案
RDB非常適合做冷備,每次生成之后,就不會再有修改了。
1、數據備份方案
(1)寫linux的定時任務調度腳本,使用crontab定時調度腳本去做數據備份(2)每小時都copy一份rdb的備份,到一個目錄中去,僅僅保留最近48小時的備份(3)每天都保留一份當日的rdb的備份,到一個目錄中去,僅僅保留最近1個月的備份【相當于每個月保存30份備份】(4)每次copy備份的時候,都把太舊的備份給刪了(5)每天晚上將當前服務器上所有的數據備份,發送一份到遠程的云服務上去【云服務上以為單位】
2、數據恢復方案
(1)如果是redis進程掛掉,那么重啟redis進程即可,直接基于AOF日志文件恢復數據
(2)如果是redis進程所在機器掛掉,那么重啟機器后,嘗試重啟redis進程,嘗試直接基于AOF日志文件進行數據恢復,AOF沒有破損,也是可以直接基于AOF恢復的,AOF append-only,順序寫入,如果AOF文件破損,那么用 redis-check-aof fix【損壞部分容忍丟失,其實只丟失了一秒的數據量】
(3)如果redis當前最新的AOF和RDB文件出現了丟失/損壞,那么可以嘗試基于該機器上當前的某個最新的RDB數據副本進行數據恢復
當前最新的AOF和RDB文件都出現了丟失/損壞到無法恢復,一般不是機器的故障,人為
/var/redis/6379下的文件給刪除了,找到RDB最新的一份備份,小時級的備份可以了,小時級的肯定是最新的,copy到redis里面去,就可以恢復到某一個小時的數據
容災演練
停止redis,關閉aof,拷貝rdb備份,重啟redis,確認數據恢復,直接在命令行熱修改redis配置,打開aof,這個redis就會將內存中的數據對應的日志,寫入aof文件中,此時aof和rdb兩份數據文件的數據就同步了。
redis config set
熱修改配置參數,可能配置文件中的實際的參數沒有被持久化的修改,再次停止redis,手動修改配置文件,打開aof的命令,再次重啟redis。
(4)如果當前機器上的所有RDB文件全部損壞,那么從遠程的云服務上拉取最新的RDB快照回來恢復數據。
(5)如果是發現有重大的數據錯誤,比如某個小時上線的程序一下子將數據全部污染了,數據全錯了,那么可以選擇某個更早的時間點,對數據進行恢復
********** redis 三點式集群的搭建[重點] **********
單機的redis的一般場景下的極限值差不多讀的QPS在5萬左右,當然也收服務器的性能配置影響,所以高于這個極限值很大的境況下,redis隨時有崩掉的危險,那么
怎么做到更高的QPS呢,總的思路就是讀寫分離,同時增加讀的redis個數,因為在通常的場景下,讀遠遠大于寫;
這就引出了redis的主從結構話設計;
主從結構框架配置 必須實現 master 的持久化!!!
主從reids間的同步原理:
redis的主從通信基本流程:
runid的作用:
redis replication復制原理總結:
1、復制的完整流程
(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
2、數據同步相關的核心機制
指的就是第一次slave連接msater的時候,執行的全量復制,那個過程里面你的一些細節的機制
(1)master和slave都會維護一個offset
master會在自身不斷累加offset,slave也會在自身不斷累加offsetslave每秒都會上報自己的offset給master,同時master也會保存每個slave的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命令
(4)psync
從節點使用psync從master node進行復制,psync runid offsetmaster node會根據自身的情況返回響應信息,可能是FULLRESYNC runid offset觸發全量復制,可能是CONTINUE觸發增量復制
3、全量復制
(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,如果在復制期間,內存緩沖區持續消耗超過64MB,或者一次性超過256MB,那么停止復制,復制失敗(6)slave node接收到rdb之后,清空自己的舊數據,然后重新加載rdb到自己的內存中,同時基于舊的數據版本對外提供服務(7)如果slave node開啟了AOF,那么會立即執行BGREWRITEAOF,重寫AOF
rdb生成、rdb通過網絡拷貝、slave舊數據的清理、slave aof rewrite,很耗費時間
如果復制的數據量在4G~6G之間,那么很可能全量復制時間消耗到1分半到2分鐘
4、增量復制
(1)如果全量復制過程中,master-slave網絡連接斷掉,那么salve重新連接master時,會觸發增量復制(2)master直接從自己的backlog中獲取部分丟失的數據,發送給slave node,默認backlog就是1MB(3)msater就是根據slave發送的psync中的offset來從backlog中獲取數據的
5、heartbeat
主從節點互相都會發送heartbeat信息
master默認每隔10秒發送一次heartbeat,salve node每隔1秒發送一個heartbeat
6、異步復制
master每次接收到寫命令之后,現在內部寫入數據,然后異步發送給slave node
虛擬機配置主從結構的redis連接:
1、在slave node上配置如下即可:
slaveof 192.168.X.X 6379
2、強制讀寫分離
基于主從復制架構,實現讀寫分離 redis slave node必須設置為只讀模式,默認開啟,
slave-read-only yes
開啟了只讀的redis slave node,會拒絕所有的寫操作,這樣可以強制搭建成讀寫分離的架構
3、集群安全認證
master上啟用安全認證,requirepass passwd slave上設置連接口令,masterauth passwd
兩個passwd需要保持一致
4、bind 對應的 IP
在master 和 slave 上都設置bind IP,默認為127.0.0.1 這里需要設置自己的虛擬機的ip
----------------------------------------------
5、進行驗證
先開啟master,使用
redis-cli -h IP -a passwd
命令操作,本人操作過,如果不加 -a passwd參數會出現 (error) NOAUTH Authentication required.錯誤,輸入后進入redis命令號 輸入
info replication
------------------------------------------------
進行驗證
驗證結果
【從中也可以看到 master和slave的offset此時是不一致的】
6、然后開啟slave從redis; 輸入
redis-cli -h IP
然后輸入
info replication
進行信息驗證;
驗證結果
主從數據驗證:
master:
slave:
可以看到master的RDB數據已經傳到了slave中; 同時我們也可以知道,如果在slave上試圖添加數據,會被無情的拒絕;
----------------------------------------------------- 更新至2018.8.19 22.46 -----------------------------------------------------
對搭建的主從架構進行QPS壓力測試
進入 redis 安裝目錄的 src目錄下;
執行
redis-benchmark -h IP -c n1 -n n2 -d n3
進行測試
-c <clients> Number of parallel connections (default 50)
-n <requests> Total number of requests (default 100000)
-d <size> Data size of SET/GET value in bytes (default 2)
本人機器測試如下:
我們可以看到 在Get操作中 QPS 為 76863 相當于每秒1.7W的訪問量,虛擬機的配置為1G內存單CPU,如果進行水平擴容2臺,架構由一臺master加三臺slave,則支持7.6W*2 = 22W的QPS,當然在生產場景下,與訪問的數據大小存在關系;
redis實現99.99%高可用
------------------------------------------------------------------------------------------
----主備切換
在主從架構中slave發生問題時,如果是一臺slave出現問題,不會影響整個架構的運行,因為其他的slave會頂替該宕機的slave,但是如果master出現了宕機,就沒有機器繼續給
slave機器復制數據,所以這時候需要采用一種機制來實現高可用性;
如何實現緩存架構的高可用性
-----【增加哨兵 Sentinel Node】
------------------------------------------------------------------------------------------
經典的三點哨兵集群介紹:
-----【為什么最少是3個哨兵,因為只要quorum 和 majority 都滿足的情況下才可以進行故障轉移】
如果哨兵集群中一個哨兵認為主節點宕機了,這種情況為sdowm,也就是主觀宕機,此時可能存在誤判,所以需要設置quorum,比如有三臺機器,quorum設置
為2,則在有兩臺機器認為是sdown的情況下,變為odowm,也就是客觀宕機,此時的判斷一般是準確的。
哨兵是redis集群架構中非常重要的一個組件,主要功能如下:
(1)集群監控,負責監控redis master和slave進程是否正常工作(2)消息通知,如果某個redis實例有故障,那么哨兵負責發送消息作為報警通知給管理員(3)故障轉移,如果master node掛掉了,會自動轉移到slave node上(4)配置中心,如果故障轉移發生了,通知client客戶端新的master地址
哨兵本身也是分布式的,作為一個哨兵集群去運行,互相協同工作
(1)故障轉移時,判斷一個master node是宕機了,需要大部分的哨兵都同意才行,涉及到了分布式選舉的問題(2)即使部分哨兵節點掛掉了,哨兵集群還是能正常工作的,因為如果一個作為高可用機制重要組成部分的故障轉移系統本身是單點的,那就很坑爹了
哨兵的核心知識 ----- 哨兵+redis部署架構
(1)哨兵至少需要3個實例,來保證自己的健壯性(2)哨兵 + redis主從的部署架構,是不會保證數據零丟失的,只能保證redis集群的高可用性(3)對于哨兵 + redis主從這種復雜的部署架構,盡量在測試環境和生產環境,都進行充足的測試和演練
------------------------------------------------------------------------------------------
哨兵模式的虛擬機模擬配置:
首先說一下這里有個坑爹的地方就是 坑了我三天才得以解決,就是哨兵在監視master 和 slave的時候,都需要配置密碼,sentinel auth-pass mymaster redis-pass 這一步我配置的過程中漏掉了,導致哨兵一直監視不了主從架構,所以在配置的過程中一定要加上;
基本配置:
哨兵默認用26379端口,默認不能跟其他機器在指定端口連通,只能在本地訪問
mkdir /etc/sentinal
mkdir -p /var/sentinal/5000
/etc/sentinal/5000.conf
在5000.conf文件中進行配置:
port 5000
bind 192.168.1.108
dir /var/sentinal/5000
sentinel monitor mymaster 192.168.1.108 6379 2
sentinel down-after-milliseconds mymaster 30000 //超過多少毫秒跟一個redis實例斷了連接,哨兵就可能認為這個redis實例掛了
sentinel failover-timeout mymaster 60000 //執行故障轉移的timeout超時時長
sentinel parallel-syncs mymaster 1 //選舉出新的master后 一次性把幾個slave掛載上去
sentinel auth-pass mymaster redis-pass
port 5000
bind 192.168.1.109
dir /var/sentinal/5000
sentinel monitor mymaster 192.168.1.108 6379 2
sentinel down-after-milliseconds mymaster 30000
sentinel failover-timeout mymaster 60000
sentinel parallel-syncs mymaster 1
sentinel auth-pass mymaster redis-pass
port 5000
bind 192.168.1.105
dir /var/sentinal/5000
sentinel monitor mymaster 192.168.1.108 6379 2
sentinel down-after-milliseconds mymaster 30000
sentinel failover-timeout mymaster 60000
sentinel parallel-syncs mymaster 1
sentinel auth-pass mymaster redis-pass
3、啟動哨兵進程 在eshop-cache01、eshop-cache02、eshop-cache03三臺機器上,分別啟動三個哨兵進程,組成一個集群,觀察一下日志的輸出
redis-sentinel /etc/sentinal/5000.conf
redis-server /etc/sentinal/5000.conf --sentinel
日志里會顯示出來,每個哨兵都能去監控到對應的redis master,并能夠自動發現對應的slave,哨兵之間互相會自動進行發現,用的就是之前說的pub/sub,消息發布和訂閱channel消息系統和機制
4、檢查哨兵狀態 redis-cli -h 192.168.1.108 -p 5000
sentinel master mymaster
SENTINEL slaves mymaster
SENTINEL sentinels mymaster
SENTINEL get-master-addr-by-name mymaster
配置成功后的運行截圖:
master的哨兵信息:
Slave上的哨兵信息:
master的哨兵監視信息:
slave的監視信息:
模式master 宕機后的情景:
將master的端口關閉掉,或者直接關閉master虛擬機,
------------------------------------------------------------------------------------------
在Master宕機以及分裂的異常情況下的處理方案:
Master宕機
第一種情況:在client不斷往master寫入數據,在準備將數據異步拷貝給各個slave的時候,此時master宕機的情況下,哨兵會選舉新的master,然后clinet就會向
新的master寫入數據,此時原來的master里邊原來寫入的那塊數據就丟失了;
分裂的情況
第二種情況腦裂:
也就是master由于異常原因,獨立出slave所在的網絡,但是master可以繼續工作,但此時哨兵檢測到master的異常后,重新選出一個slave作為新的master,
此時的場景下存在了兩個master,在新的master選舉出來之前,然后client繼續向原來的master寫入數據,當選舉新master完成后,原來的master恢復被被設置
為slave,此時舊的master緩存的數據就會被覆蓋,導致數據丟失;
------------------------------------------------------------------
1、兩種數據丟失的情況
主備切換的過程,可能會導致數據丟失
(1)異步復制導致的數據丟失
因為master -> slave的復制是異步的,所以可能有部分數據還沒復制到slave,master就宕機了,此時這些部分數據就丟失了
(2)腦裂導致的數據丟失
腦裂,也就是說,某個master所在機器突然脫離了正常的網絡,跟其他slave機器不能連接,但是實際上master還運行著
此時哨兵可能就會認為master宕機了,然后開啟選舉,將其他slave切換成了master
這個時候,集群里就會有兩個master,也就是所謂的腦裂
此時雖然某個slave被切換成了master,但是可能client還沒來得及切換到新的master,還繼續寫向舊master的數據可能也丟失了
因此舊master再次恢復的時候,會被作為一個slave掛到新的master上去,自己的數據會清空,重新從新的master復制數據
------------------------------------------------------------------
解決方案:
在redis的配置文件配置參數:
min-slaves-to-write 1min-slaves-max-lag 10
要求至少有1個slave,數據復制和同步的延遲不能超過10秒,如果說一旦所有的slave,數據復制和同步的延遲都超過了10秒鐘,那么這個時候,master就不會再接收任何請求了.
要求至少有1個slave,數據復制和同步的延遲不能超過10秒
如果說一旦所有的slave,數據復制和同步的延遲都超過了10秒鐘,那么這個時候,master就不會再接收任何請求了
上面兩個配置可以減少異步復制和腦裂導致的數據丟失
(1)減少異步復制的數據丟失
有了min-slaves-max-lag這個配置,就可以確保說,一旦slave復制數據和ack延時太長,就認為可能master宕機后損失的數據太多了,那么就拒絕寫請求[可能redis會處理暫時寫入,保存到自己一個緩存區,詳見上邊的“處理圖”],這樣可以把master宕機時由于部分數據未同步到slave導致的數據丟失降低的可控范圍內
(2)減少腦裂的數據丟失
如果一個master出現了腦裂,跟其他slave丟了連接,那么上面兩個配置可以確保說,如果不能繼續給指定數量的slave發送數據,而且slave超過10秒沒有給自己ack消息,那么就直接拒絕客戶端的寫請求
這樣腦裂后的舊master就不會接受client的新數據,也就避免了數據丟失
上面的配置就確保了,如果跟任何一個slave丟了連接,在10秒后發現沒有slave給自己ack,那么就拒絕新的寫請求
因此在腦裂場景下,最多就丟失10秒的數據
------------------------------------------------------------------------------------------
如何在保持讀寫分離+高可用的架構下,還能橫向擴容支撐1T+海量數據
1、redis cluster vs. replication + sentinal
replication + sentinal:如果你的數據量很少,主要是承載高并發高性能的場景,比如你的緩存一般就幾個G,單機足夠了一個mater,多個slave,要幾個slave跟你的要求的讀吞吐量有關系,
然后自己搭建一個sentinal集群,去保證redis主從架構的高可用性,就可以了。
redis cluster:主要是針對海量數據+高并發+高可用的場景,海量數據,如果你的數據量很大,那么建議就用redis cluster
2、單機redis在海量數據面前的瓶頸
3、怎么才能夠突破單機瓶頸,讓redis支撐海量數據?
4、redis的集群架構
redis cluster
支撐N個redis master node,每個master node都可以掛載多個slave node
讀寫分離的架構,對于每個master來說,寫就寫到master,然后讀就從mater對應的slave去讀
高可用,因為每個master都有salve節點,那么如果mater掛掉,redis cluster這套機制,就會自動將某個slave切換成master
redis cluster(多master + 讀寫分離 + 高可用)
我們只要基于redis cluster去搭建redis集群即可,不需要手工去搭建replication復制+主從架構+讀寫分離+哨兵集群+高可用
*************redis clustor 介紹與搭建 *********
------針對海量數據+高并發+高可用的場景
講解分布式數據存儲的核心算法,數據分布的算法:
hash算法 -> 一致性hash算法(memcached) -> redis cluster,hash slot算法
用不同的算法,就決定了在多個master節點的時候,數據如何分布到這些節點上去,解決這個問題。
簡單的取模 hash函數實現:
【嚴重的弊端,對機器的個數進行取模】
一致性hash算法:
對于一致性hash算法熱點問題的改進:
redis slot的實現原理:
以前寫的內容是master機器和slave機器分離,分別負責讀寫,但是到了 redis cluster之后,就不再讀寫分離,所有的讀和寫都是通過master進行的;
針對key進行hash slot運算找slot;
關于redis cluster不再使用三點哨兵集群模式那種讀寫分離的架構,所有的讀和寫都通過master就可以,如果想提高讀或者寫的QPS,則我們只需要進行水平擴容,增加master就可以,其中
多臺slave的作用是為了增加高可用,用來做主備切換使用;
理論補充部分:
---- 記得需要補充;------ 2019-3-31補充如下:
**********************
1、redis cluster 搭建部署:
停止之前所有的實例,包括redis主從和哨兵集群,使用 redis cluster。
redis cluster: 自動,master+slave復制和讀寫分離,master+slave高可用和主備切換,支持多個master的hash slot支持數據分布式存儲。
1、redis cluster的重要配置
cluster-enabled <yes/no>
cluster-config-file <filename>:
這是指定一個文件,供cluster模式下的redis實例將集群狀態保存在那里,包括集群中其他機器的信息,比如節點的上線和下限,故障轉移,不是我們去維護的,給它指定一個文件,讓redis自己去維護的
cluster-node-timeout <milliseconds>:
節點存活超時時長,超過一定時長,認為節點宕機,master宕機的話就會觸發主備切換,slave宕機就不會提供服務
2、在三臺機器上啟動6個redis實例 --- 以其中一臺舉例 ---
(1)在eshop-cache01上部署目錄
/etc/redis/XXX (存放redis的配置文件)
/var/redis/XXX (存放redis的持久化文件)
(2)編寫配置文件
redis cluster集群,要求至少3個master,去組成一個高可用,健壯的分布式的集群,每個master都建議至少給一個slave,3個master,3個slave,最少的要求,正式環境下,建議都是說在6臺機器上去搭建,至少3臺機器。
保證,每個master都跟自己的slave不在同一臺機器上,如果是6臺自然更好,一個master+一個slave就死了
3臺機器去搭建6個redis實例的redis cluster:
拿一臺舉例
-------------------------------------------------------
mkdir -p /etc/redis-cluster
mkdir -p /var/log/redis
mkdir -p /var/redis/7001
port 7001
cluster-enabled yes
cluster-config-file /etc/redis-cluster/node-7001.conf
cluster-node-timeout 15000
daemonize yes
pidfile /var/run/redis_7001.pid
dir /var/redis/7001
logfile /var/log/redis/7001.log
bind 192.168.31.187
appendonly yes
-------------------------------------------------------
至少要用3個master節點啟動,每個master加一個slave節點,先選擇6個節點,啟動6個實例,將上面的配置文件,在/etc/redis下放6個,分別為:
eshop-cache01:
7001.conf,7002.conf,
eshop-cache02:
7003.conf,7004.conf,
eshop-cache03:
7005.conf,7006.conf
(3)準備生產環境的啟動腳本
在/etc/init.d下,放6個啟動腳本,分別為: redis_7001, redis_7002, redis_7003, redis_7004, redis_7005, redis_7006
每個啟動腳本內,都修改對應的端口號,如下圖:
(4)分別在3臺機器上,啟動6個redis實例
將每個配置文件中的slaveof給刪除
3、創建集群
下面方框內的內容廢棄掉
=======================================================================
wget https://cache.ruby-lang.org/pub/ruby/2.3/ruby-2.3.1.tar.gz
tar -zxvf ruby-2.3.1.tar.gz
./configure -prefix=/usr/local/ruby
make && make install
cd /usr/local/ruby
cp bin/ruby /usr/local/bin
cp bin/gem /usr/local/bin
wget http://rubygems.org/downloads/redis-3.3.0.gem
gem install -l ./redis-3.3.0.gem
gem list --check redis gem
=======================================================================
因為,以前比如公司里面搭建集群,公司里的機器的環境,運維會幫你做好很多事情
在講課的話,我們手工用從零開始裝的linux虛擬機去搭建,那肯定會碰到各種各樣的問題
yum install -y ruby
yum install -y rubygems
gem install redis
cp /usr/local/redis-3.2.8/src/redis-trib.rb /usr/local/bin
redis-trib.rb create --replicas 1 192.168.31.187:7001 192.168.31.187:7002 192.168.31.19:7003 192.168.31.19:7004 192.168.31.227:7005 192.168.31.227:7006
--replicas: 每個master有幾個slave
6臺機器,3個master,3個slave,盡量自己讓master和slave不在一臺機器上
yes
redis-trib.rb check 192.168.31.187:7001
4、讀寫分離+高可用+多master
讀寫分離:每個master都有一個slave
高可用:master宕機,slave自動被切換過去
多master:橫向擴容支持更大數據量
2、redis cluster的實驗,多master寫入,主從復制,高可用
redis cluster搭建起來了
redis cluster,提供了多個master,數據可以分布式存儲在多個master上; 每個master都帶著slave,自動就做讀寫分離; 每個master如果故障,那么久會自動將slave切換成master,高可用
redis cluster的基本功能,來測試一下
1、實驗多master寫入 -> 海量數據的分布式存儲
你在redis cluster寫入數據的時候,其實是你可以將請求發送到任意一個master上去執行
但是,每個master都會計算這個key對應的CRC16值,然后對16384個hashslot取模,找到key對應的hashslot,找到hashslot對應的master
如果對應的master就在自己本地的話,set mykey1 v1,mykey1這個key對應的hashslot就在自己本地,那么自己就處理掉了
但是如果計算出來的hashslot在其他master上,那么就會給客戶端返回一個moved error,告訴你,你得到哪個master上去執行這條寫入的命令
什么叫做多master的寫入,就是每條數據只能存在于一個master上,不同的master負責存儲不同的數據,分布式的數據存儲
100w條數據,5個master,每個master就負責存儲20w條數據,分布式數據存儲
大型的java系統架構,還專注在大數據系統架構,分布式,分布式存儲,hadoop hdfs,分布式資源調度,hadoop yarn,分布式計算,hadoop mapreduce/hive
分布式的nosql數據庫,hbase,分布式的協調,zookeeper,分布式通用計算引擎,spark,分布式的實時計算引擎,storm
如果你要處理海量數據,就涉及到了一個名詞,叫做大數據,只要涉及到大數據,那么其實就會涉及到分布式
redis cluster,分布式
因為我來講java系統的架構,有時候跟其他人不一樣,純搞java,但是我因為工作時間很長,早期專注做java架構,好多年,大數據興起,就一直專注大數據系統架構
大數據相關的系統,也涉及很多的java系統架構,高并發、高可用、高性能、可擴展、分布式系統
會給大家稍微拓展一下知識面,從不同的角度去講解一塊知識
redis,高并發、高性能、每日上億流量的大型電商網站的商品詳情頁系統的緩存架構,來講解的,redis是作為大規模緩存架構中的底層的核心存儲的支持
高并發、高性能、每日上億流量,redis持久化 -> 災難的時候,做數據恢復,復制 -> 讀寫分離,擴容slave,支撐更高的讀吞吐,redis怎么支撐讀QPS超過10萬,幾十萬; 哨兵,在redis主從,一主多從,怎么保證99.99%可用性; redis cluster,海量數據
java架構課,架構思路和設計是很重要的,但是另外一點,我希望能夠帶著大家用真正java架構師的角度去看待一些技術,而不是僅僅停留在技術的一些細節的點
給大家從一些大數據的角度,去分析一下我們java架構領域中的一些技術
天下武功,都出自一脈,研究過各種大數據的系統,redis cluster講解了很多原理,跟elasticsearch,很多底層的分布式原理,都是類似的
redis AOF,fsync
elasticsearch建立索引的時候,先寫內存緩存,每秒鐘把數據刷入os cache,接下來再每隔一定時間fsync到磁盤上去
redis cluster,寫可以到任意master,任意master計算key的hashslot以后,告訴client,重定向,路由到其他mater去執行,分布式存儲的一個經典的做法
elasticsearch,建立索引的時候,也會根據doc id/routing value,做路由,路由到某個其他節點,重定向到其他節點去執行
分布式的一些,hadoop,spark,storm里面很多核心的思想都是類似的
后面,馬上把redis架構給講完之后,就開始講解業務系統的開發,包括高并發的商品詳情頁系統的大型的緩存架構,jedis cluster相關api去封裝和測試對redis cluster的訪問
jedis cluster api,就可以自動針對多個master進行寫入和讀取
2、實驗不同master各自的slave讀取 -> 讀寫分離
在這個redis cluster中,如果你要在slave讀取數據,那么需要帶上readonly指令,get mykey1
redis-cli -c -h xxxx -p xxxxx
啟動,就會自動進行各種底層的重定向的操作
實驗redis cluster的讀寫分離的時候,會發現有一定的限制性,默認情況下,redis cluster的核心的理念,主要是用slave做高可用的,每個master掛一兩個slave,主要是做數據的熱備,還有master故障時的主備切換,實現高可用的
redis cluster默認是不支持slave節點讀或者寫的,跟我們手動基于replication搭建的主從架構不一樣的
slave node,readonly,get,這個時候才能在slave node進行讀取
redis cluster,主從架構是出來,讀寫分離,復雜了點,也可以做,jedis客戶端,對redis cluster的讀寫分離支持不太好的
默認的話就是讀和寫都到master上去執行的
如果你要讓最流行的jedis做redis cluster的讀寫分離的訪問,那可能還得自己修改一點jedis的源碼,成本比較高
要不然你就是自己基于jedis,封裝一下,自己做一個redis cluster的讀寫分離的訪問api
核心的思路,就是說,redis cluster的時候,就沒有所謂的讀寫分離的概念了
讀寫分離,是為了什么,主要是因為要建立一主多從的架構,才能橫向任意擴展slave node去支撐更大的讀吞吐量
redis cluster的架構下,實際上本身master就是可以任意擴展的,你如果要支撐更大的讀吞吐量,或者寫吞吐量,或者數據量,都可以直接對master進行橫向擴展就可以了
也可以實現支撐更高的讀吞吐的效果
不會去跟大家直接講解的,很多東西都要帶著一些疑問,未知,實際經過一些實驗和操作之后,讓你體會的更加深刻一些
redis cluster,主從架構,讀寫分離,沒說錯,沒有撒謊
redis cluster,不太好,server層面,jedis client層面,對master做擴容,所以說擴容master,跟之前擴容slave,效果是一樣的
3、實驗自動故障切換 -> 高可用性
redis-trib.rb check 192.168.31.187:7001
比如把master1,187:7001,殺掉,看看它對應的19:7004能不能自動切換成master,可以自動切換
切換成master后的19:7004,可以直接讀取數據
再試著把187:7001給重新啟動,恢復過來,自動作為slave掛載到了19:7004上面去
3、實現redis cluster的水平擴容
redis cluster模式下,不建議做物理的讀寫分離了
我們建議通過master的水平擴容,來橫向擴展讀寫吞吐量,還有支撐更多的海量數據
redis單機,讀吞吐是5w/s,寫吞吐2w/s
擴展redis更多master,那么如果有5臺master,不就讀吞吐可以達到總量25/s QPS,寫可以達到10w/s QPS
redis單機,內存,6G,8G,fork類操作的時候很耗時,會導致請求延時的問題
擴容到5臺master,能支撐的總的緩存數據量就是30G,40G
100臺,600G,800G,甚至1T+,海量數據
----------------------------------------------------------
redis是怎么擴容的
------- 加入master 加入slave
1、加入新master
mkdir -p /var/redis/7007
port 7007cluster-enabled yescluster-config-file /etc/redis-cluster/node-7007.confcluster-node-timeout 15000daemonize yespidfile /var/run/redis_7007.piddir /var/redis/7007logfile /var/log/redis/7007.logbind 192.168.31.227appendonly yes
搞一個7007.conf,再搞一個redis_7007啟動腳本
手動啟動一個新的redis實例,在7007端口上
redis-trib.rb add-node 192.168.31.227:7007 192.168.31.187:7001
redis-trib.rb check 192.168.31.187:7001
連接到新的redis實例上,cluster nodes,確認自己是否加入了集群,作為了一個新的master,
2、reshard一些數據過去
resharding的意思就是把一部分hash slot從一些node上遷移到另外一些node上
redis-trib.rb reshard 192.168.31.187:7001
要把之前3個master上,總共4096個hashslot遷移到新的第四個master上去
How many slots do you want to move (from 1 to 16384)? 4096
檢查一下分配的情況:
3、添加node作為slave
eshop-cache03
mkdir -p /var/redis/7008
port 7008cluster-enabled yescluster-config-file /etc/redis-cluster/node-7008.confcluster-node-timeout 15000daemonize yespidfile /var/run/redis_7008.piddir /var/redis/7008logfile /var/log/redis/7008.logbind 192.168.31.227appendonly yes
redis-trib.rb add-node --slave --master-id 28927912ea0d59f6b790a50cf606602a5ee48108 192.168.31.227:7008 192.168.31.187:7001
檢查加入情況:
4、刪除node
先用resharding將數據都移除到其他節點,確保node為空之后,才能執行remove操作
先將slot移空
移空后執行刪除:
redis-trib.rb del-node 192.168.31.187:7001 bd5a40a6ddccbd46a0f4a2208eb25d2453c2a8db
2個是1365,1個是1366
當你清空了一個master的hashslot時,redis cluster就會自動將其slave掛載到其他master上去
這個時候就只要刪除掉master就可以了
4、slave的自動遷移
---------為什么要存在冗余slave
比如現在有10個master,每個有1個slave,然后新增了3個slave作為冗余,有的master就有2個slave了,有的master出現了salve冗余
如果某個master的slave掛了,那么redis cluster會自動遷移一個冗余的slave給那個master
只要多加一些冗余的slave就可以了
為了避免的場景,就是說,如果你每個master只有一個slave,萬一說一個slave死了,然后很快,master也死了,那可用性還是降低了
但是如果你給整個集群掛載了一些冗余slave,那么某個master的slave死了,冗余的slave會被自動遷移過去,作為master的新slave,此時即使那個master也死了
還是有一個slave會切換成master的
之前有一個master是有冗余slave的,直接讓其他master其中的一個slave死掉,然后看有冗余slave會不會自動掛載到那個master
自動化遷移后:
5、redis cluster的核心原理分析:gossip通信、jedis smart定位、主備切換一、節點間的內部通信機制
1、基礎通信原理
(1)redis cluster節點間采取gossip協議進行通信
跟集中式不同,不是將集群元數據(節點信息,故障,等等)集中存儲在某個節點上,而是互相之間不斷通信,保持整個集群所有節點的數據是完整的
維護集群的元數據用得,集中式,一種叫做gossip
集中式:好處在于,元數據的更新和讀取,時效性非常好,一旦元數據出現了變更,立即就更新到集中式的存儲中,其他節點讀取的時候立即就可以感知到; 不好在于,所有的元數據的跟新壓力全部集中在一個地方,可能會導致元數據的存儲有壓力
gossip:好處在于,元數據的更新比較分散,不是集中在一個地方,更新請求會陸陸續續,打到所有節點上去更新,有一定的延時,降低了壓力; 缺點,元數據更新有延時,可能導致集群的一些操作會有一些滯后
我們剛才做reshard,去做另外一個操作,會發現說,configuration error,達成一致
(2)10000端口
每個節點都有一個專門用于節點間通信的端口,就是自己提供服務的端口號+10000,比如7001,那么用于節點間通信的就是17001端口
每隔節點每隔一段時間都會往另外幾個節點發送ping消息,同時其他幾點接收到ping之后返回pong
(3)交換的信息
故障信息,節點的增加和移除,hash slot信息,等等
2、gossip協議
gossip協議包含多種消息,包括ping,pong,meet,fail,等等
meet: 某個節點發送meet給新加入的節點,讓新節點加入集群中,然后新節點就會開始與其他節點進行通信
redis-trib.rb add-node
其實內部就是發送了一個gossip meet消息,給新加入的節點,通知那個節點去加入我們的集群
ping: 每個節點都會頻繁給其他節點發送ping,其中包含自己的狀態還有自己維護的集群元數據,互相通過ping交換元數據
每個節點每秒都會頻繁發送ping給其他的集群,ping,頻繁的互相之間交換數據,互相進行元數據的更新
pong: 返回ping和meet,包含自己的狀態和其他信息,也可以用于信息廣播和更新
fail: 某個節點判斷另一個節點fail之后,就發送fail給其他節點,通知其他節點,指定的節點宕機了
3、ping消息深入
ping很頻繁,而且要攜帶一些元數據,所以可能會加重網絡負擔
每個節點每秒會執行10次ping,每次會選擇5個最久沒有通信的其他節點
當然如果發現某個節點通信延時達到了cluster_node_timeout / 2,那么立即發送ping,避免數據交換延時過長,落后的時間太長了
比如說,兩個節點之間都10分鐘沒有交換數據了,那么整個集群處于嚴重的元數據不一致的情況,就會有問題
所以cluster_node_timeout可以調節,如果調節比較大,那么會降低發送的頻率
每次ping,一個是帶上自己節點的信息,還有就是帶上1/10其他節點的信息,發送出去,進行數據交換
至少包含3個其他節點的信息,最多包含總節點-2個其他節點的信息
-------------------------------------------------------------------------------------------------------
二、面向集群的jedis內部實現原理
開發,jedis,redis的java client客戶端,redis cluster,jedis cluster api
jedis cluster api與redis cluster集群交互的一些基本原理
1、基于重定向的客戶端
redis-cli -c,自動重定向
(1)請求重定向
客戶端可能會挑選任意一個redis實例去發送命令,每個redis實例接收到命令,都會計算key對應的hash slot
如果在本地就在本地處理,否則返回moved給客戶端,讓客戶端進行重定向
cluster keyslot mykey,可以查看一個key對應的hash slot是什么
用redis-cli的時候,可以加入-c參數,支持自動的請求重定向,redis-cli接收到moved之后,會自動重定向到對應的節點執行命令
(2)計算hash slot
計算hash slot的算法,就是根據key計算CRC16值,然后對16384取模,拿到對應的hash slot
用hash tag可以手動指定key對應的slot,同一個hash tag下的key,都會在一個hash slot中,比如set mykey1:{100}和set mykey2:{100}
(3)hash slot查找
節點間通過gossip協議進行數據交換,就知道每個hash slot在哪個節點上
2、smart jedis
(1)什么是smart jedis
基于重定向的客戶端,很消耗網絡IO,因為大部分情況下,可能都會出現一次請求重定向,才能找到正確的節點
所以大部分的客戶端,比如java redis客戶端,就是jedis,都是smart的
本地維護一份hashslot -> node的映射表,緩存,大部分情況下,直接走本地緩存就可以找到hashslot -> node,不需要通過節點進行moved重定向
(2)JedisCluster的工作原理
在JedisCluster初始化的時候,就會隨機選擇一個node,初始化hashslot -> node映射表,同時為每個節點創建一個JedisPool連接池
每次基于JedisCluster執行操作,首先JedisCluster都會在本地計算key的hashslot,然后在本地映射表找到對應的節點
如果那個node正好還是持有那個hashslot,那么就ok; 如果說進行了reshard這樣的操作,可能hashslot已經不在那個node上了,就會返回moved
如果JedisCluter API發現對應的節點返回moved,那么利用該節點的元數據,更新本地的hashslot -> node映射表緩存
重復上面幾個步驟,直到找到對應的節點,如果重試超過5次,那么就報錯,JedisClusterMaxRedirectionException
jedis老版本,可能會出現在集群某個節點故障還沒完成自動切換恢復時,頻繁更新hash slot,頻繁ping節點檢查活躍,導致大量網絡IO開銷
jedis最新版本,對于這些過度的hash slot更新和ping,都進行了優化,避免了類似問題
(3)hashslot遷移和ask重定向
如果hash slot正在遷移,那么會返回ask重定向給jedis
jedis接收到ask重定向之后,會重新定位到目標節點去執行,但是因為ask發生在hash slot遷移過程中,所以JedisCluster API收到ask是不會更新hashslot本地緩存
已經可以確定說,hashslot已經遷移完了,moved是會更新本地hashslot->node映射表緩存的
-------------------------------------------------------------------------------------------------------
三、高可用性與主備切換原理
redis cluster的高可用的原理,幾乎跟哨兵是類似的
1、判斷節點宕機
如果一個節點認為另外一個節點宕機,那么就是pfail,主觀宕機
如果多個節點都認為另外一個節點宕機了,那么就是fail,客觀宕機,跟哨兵的原理幾乎一樣,sdown,odown
在cluster-node-timeout內,某個節點一直沒有返回pong,那么就被認為pfail
如果一個節點認為某個節點pfail了,那么會在gossip ping消息中,ping給其他節點,如果超過半數的節點都認為pfail了,那么就會變成fail
2、從節點過濾
對宕機的master node,從其所有的slave node中,選擇一個切換成master node
檢查每個slave node與master node斷開連接的時間,如果超過了cluster-node-timeout * cluster-slave-validity-factor,那么就沒有資格切換成master
這個也是跟哨兵是一樣的,從節點超時過濾的步驟
3、從節點選舉
哨兵:對所有從節點進行排序,slave priority,offset,run id
每個從節點,都根據自己對master復制數據的offset,來設置一個選舉時間,offset越大(復制數據越多)的從節點,選舉時間越靠前,優先進行選舉
所有的master node開始slave選舉投票,給要進行選舉的slave進行投票,如果大部分master node(N/2 + 1)都投票給了某個從節點,那么選舉通過,那個從節點可以切換成master
從節點執行主備切換,從節點切換為主節點
4、與哨兵比較
整個流程跟哨兵相比,非常類似,所以說,redis cluster功能強大,直接集成了replication和sentinal的功能
----------------------------------------------------------------------------------------------------
兩套不同的redis緩存架構適用的不同場景
----我們主要使用的是redis cluster模式的緩存框架
************實戰環節**********
億級流量商品詳情頁的緩存架構:
我們之前的三十講,主要是在講解redis如何支撐海量數據、高并發讀寫、高可用服務的架構,redis架構。redis架構,在我們的真正類似商品詳情頁讀高并發的系統中,redis就是底層的緩存存儲的支持。
從這一講開始,我們正式開始做業務系統的開發億級流量以上的電商網站的商品詳情頁的系統,商品詳情頁系統,大量的業務,十幾個人做一兩年,堆出來復雜的業務系統
幾十個小時的課程,講解復雜的業務,把整體的架構給大家講解清楚,然后濃縮和精煉里面的業務,提取部分業務,做一些簡化,把整個詳情頁系統的流程跑出來。
架構,骨架,有少量的業務,血和肉,把整個項目串起來,在業務背景下,去學習架構。
講解商品詳情頁系統,緩存架構,90%大量的業務代碼(沒有什么技術含量),10%的最優技術含量的就是架構,上億流量,每秒QPS幾萬,上十萬的,讀并發,緩存架構
架構理解:
采用三級緩存:nginx本地緩存+redis分布式緩存+tomcat堆緩存的多級緩存架構
時效性要求非常高的數據:庫存
一般來說,顯示的庫存,都是時效性要求會相對高一些,因為隨著商品的不斷的交易,庫存會不斷的變化。
當然,我們就希望當庫存變化的時候,盡可能更快將庫存顯示到頁面上去,而不是說等了很長時間,庫存才反應到頁面上去。
時效性要求不高的數據:時效性要求不高的數據:商品的基本信息(名稱、顏色、版本、規格參數,等等)。
時效性高:商品價格/庫存等時效性要求高的數據,而且種類較少,采取相關的服務系統每次發生了變更的時候,直接采取數據庫和redis緩存雙寫的方案,這樣緩存的時效性最高。
時效性不高:商品基本信息等時效性不高的數據,而且種類繁多,來自多種不同的系統,采取MQ異步通知的方式,寫一個數據生產服務,監聽MQ消息,然后異步拉取服務的數據,更新tomcat jvm緩存+redis緩存
-------------------------------------------------------------------------------
nginx+lua腳本做頁面動態生成的工作,每次請求過來,優先從nginx本地緩存中提取各種數據,結合頁面模板,生成需要的頁面如果nginx本地緩存過期了,那么就從nginx到redis中去拉取數據,更新到nginx本地
如果redis中也被LRU算法清理掉了,那么就從nginx走http接口到后端的服務中拉取數據,數據生產服務中,現在本地tomcat里的jvm堆緩存中找,ehcache,如果也被LRU清理掉了,那么就重新發送請求到源頭的服務中去拉取數據,然后再次更新tomcat堆內存緩存+redis緩存,并返回數據給nginx,nginx緩存到本地