日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 运维知识 > 数据库 >内容正文

数据库

Redis哨兵模式(sentinel)学习总结及部署记录(主从复制、读写分离、主从切换)

發(fā)布時間:2025/3/8 数据库 39 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Redis哨兵模式(sentinel)学习总结及部署记录(主从复制、读写分离、主从切换) 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

Redis的集群方案大致有三種:1)redis cluster集群方案;2)master/slave主從方案;3)哨兵模式來進(jìn)行主從替換以及故障恢復(fù)。

一、sentinel哨兵模式介紹
Sentinel(哨兵)是用于監(jiān)控redis集群中Master狀態(tài)的工具,是Redis 的高可用性解決方案,sentinel哨兵模式已經(jīng)被集成在redis2.4之后的版本中。sentinel是redis高可用的解決方案,sentinel系統(tǒng)可以監(jiān)視一個或者多個redis master服務(wù),以及這些master服務(wù)的所有從服務(wù);當(dāng)某個master服務(wù)下線時,自動將該master下的某個從服務(wù)升級為master服務(wù)替代已下線的master服務(wù)繼續(xù)處理請求。

sentinel可以讓redis實(shí)現(xiàn)主從復(fù)制,當(dāng)一個集群中的master失效之后,sentinel可以選舉出一個新的master用于自動接替master的工作,集群中的其他redis服務(wù)器自動指向新的master同步數(shù)據(jù)。一般建議sentinel采取奇數(shù)臺,防止某一臺sentinel無法連接到master導(dǎo)致誤切換。其結(jié)構(gòu)如下:

Redis-Sentinel是Redis官方推薦的高可用性(HA)解決方案,當(dāng)用Redis做Master-slave的高可用方案時,假如master宕機(jī)了,Redis本身(包括它的很多客戶端)都沒有實(shí)現(xiàn)自動進(jìn)行主備切換,而Redis-sentinel本身也是一個獨(dú)立運(yùn)行的進(jìn)程,它能監(jiān)控多個master-slave集群,發(fā)現(xiàn)master宕機(jī)后能進(jìn)行自動切換。Sentinel由一個或多個Sentinel 實(shí)例 組成的Sentinel 系統(tǒng)可以監(jiān)視任意多個主服務(wù)器,以及這些主服務(wù)器屬下的所有從服務(wù)器,并在被監(jiān)視的主服務(wù)器進(jìn)入下線狀態(tài)時,自動將下線主服務(wù)器屬下的某個從服務(wù)器升級為新的主服務(wù)器。

例如下圖所示:

在Server1 掉線后:

升級Server2 為新的主服務(wù)器:

Sentinel版本
Sentinel當(dāng)前最新的穩(wěn)定版本稱為Sentinel 2(與之前的Sentinel 1區(qū)分開來)。隨著redis2.8的安裝包一起發(fā)行。安裝完Redis2.8后,可以在redis2.8/src/里面找到Redis-sentinel的啟動程序。
強(qiáng)烈建議:如果你使用的是redis2.6(sentinel版本為sentinel 1),你最好應(yīng)該使用redis2.8版本的sentinel 2,因?yàn)閟entinel 1有很多的Bug,已經(jīng)被官方棄用,所以強(qiáng)烈建議使用redis2.8以及sentinel 2。

Sentinel狀態(tài)持久化
snetinel的狀態(tài)會被持久化地寫入sentinel的配置文件中。每次當(dāng)收到一個新的配置時,或者新創(chuàng)建一個配置時,配置會被持久化到硬盤中,并帶上配置的版本戳。這意味著,可以安全的停止和重啟sentinel進(jìn)程。

Sentinel作用:?
1)Master狀態(tài)檢測?
2)如果Master異常,則會進(jìn)行Master-Slave切換,將其中一個Slave作為Master,將之前的Master作為Slave。?
3)Master-Slave切換后,master_redis.conf、slave_redis.conf和sentinel.conf的內(nèi)容都會發(fā)生改變,即master_redis.conf中會多一行slaveof的配置,sentinel.conf的監(jiān)控目標(biāo)會隨之調(diào)換。

Sentinel工作方式(每個Sentinel實(shí)例都執(zhí)行的定時任務(wù))
1)每個Sentinel以每秒鐘一次的頻率向它所知的Master,Slave以及其他 Sentinel 實(shí)例發(fā)送一個PING命令。
2)如果一個實(shí)例(instance)距離最后一次有效回復(fù)PING命令的時間超過 own-after-milliseconds 選項(xiàng)所指定的值,則這個實(shí)例會被Sentinel標(biāo)記為主觀下線。?
3)如果一個Master被標(biāo)記為主觀下線,則正在監(jiān)視這個Master的所有 Sentinel 要以每秒一次的頻率確認(rèn)Master的確進(jìn)入了主觀下線狀態(tài)。?
4)當(dāng)有足夠數(shù)量的Sentinel(大于等于配置文件指定的值)在指定的時間范圍內(nèi)確認(rèn)Master的確進(jìn)入了主觀下線狀態(tài),則Master會被標(biāo)記為客觀下線。
5)在一般情況下,每個Sentinel 會以每10秒一次的頻率向它已知的所有Master,Slave發(fā)送 INFO 命令。
6)當(dāng)Master被Sentinel標(biāo)記為客觀下線時,Sentinel 向下線的 Master 的所有Slave發(fā)送 INFO命令的頻率會從10秒一次改為每秒一次。?
7)若沒有足夠數(shù)量的Sentinel同意Master已經(jīng)下線,Master的客觀下線狀態(tài)就會被移除。 若 Master重新向Sentinel 的PING命令返回有效回復(fù),Master的主觀下線狀態(tài)就會被移除。

三個定時任務(wù)
sentinel在內(nèi)部有3個定時任務(wù)
1)每10秒每個sentinel會對master和slave執(zhí)行info命令,這個任務(wù)達(dá)到兩個目的:
a)發(fā)現(xiàn)slave節(jié)點(diǎn)
b)確認(rèn)主從關(guān)系
2)每2秒每個sentinel通過master節(jié)點(diǎn)的channel交換信息(pub/sub)。master節(jié)點(diǎn)上有一個發(fā)布訂閱的頻道(__sentinel__:hello)。sentinel節(jié)點(diǎn)通過__sentinel__:hello頻道進(jìn)行信息交換(對節(jié)點(diǎn)的"看法"和自身的信息),達(dá)成共識。
3)每1秒每個sentinel對其他sentinel和redis節(jié)點(diǎn)執(zhí)行ping操作(相互監(jiān)控),這個其實(shí)是一個心跳檢測,是失敗判定的依據(jù)。

主觀下線
所謂主觀下線(Subjectively Down, 簡稱 SDOWN)指的是單個Sentinel實(shí)例對服務(wù)器做出的下線判斷,即單個sentinel認(rèn)為某個服務(wù)下線(有可能是接收不到訂閱,之間的網(wǎng)絡(luò)不通等等原因)。
主觀下線就是說如果服務(wù)器在down-after-milliseconds給定的毫秒數(shù)之內(nèi), 沒有返回 Sentinel 發(fā)送的 PING 命令的回復(fù), 或者返回一個錯誤, 那么 Sentinel 將這個服務(wù)器標(biāo)記為主觀下線(SDOWN )。
sentinel會以每秒一次的頻率向所有與其建立了命令連接的實(shí)例(master,從服務(wù),其他sentinel)發(fā)ping命令,通過判斷ping回復(fù)是有效回復(fù),還是無效回復(fù)來判斷實(shí)例時候在線(對該sentinel來說是“主觀在線”)。
sentinel配置文件中的down-after-milliseconds設(shè)置了判斷主觀下線的時間長度,如果實(shí)例在down-after-milliseconds毫秒內(nèi),返回的都是無效回復(fù),那么sentinel回認(rèn)為該實(shí)例已(主觀)下線,修改其flags狀態(tài)為SRI_S_DOWN。如果多個sentinel監(jiān)視一個服務(wù),有可能存在多個sentinel的down-after-milliseconds配置不同,這個在實(shí)際生產(chǎn)中要注意。

客觀下線
客觀下線(Objectively Down, 簡稱 ODOWN)指的是多個 Sentinel 實(shí)例在對同一個服務(wù)器做出 SDOWN 判斷, 并且通過 SENTINEL is-master-down-by-addr 命令互相交流之后, 得出的服務(wù)器下線判斷,然后開啟failover。
客觀下線就是說只有在足夠數(shù)量的 Sentinel 都將一個服務(wù)器標(biāo)記為主觀下線之后, 服務(wù)器才會被標(biāo)記為客觀下線(ODOWN)。
只有當(dāng)master被認(rèn)定為客觀下線時,才會發(fā)生故障遷移。
當(dāng)sentinel監(jiān)視的某個服務(wù)主觀下線后,sentinel會詢問其它監(jiān)視該服務(wù)的sentinel,看它們是否也認(rèn)為該服務(wù)主觀下線,接收到足夠數(shù)量(這個值可以配置)的sentinel判斷為主觀下線,既任務(wù)該服務(wù)客觀下線,并對其做故障轉(zhuǎn)移操作。
sentinel通過發(fā)送 SENTINEL is-master-down-by-addr ip port current_epoch runid,(ip:主觀下線的服務(wù)id,port:主觀下線的服務(wù)端口,current_epoch:sentinel的紀(jì)元,runid:*表示檢測服務(wù)下線狀態(tài),如果是sentinel 運(yùn)行id,表示用來選舉領(lǐng)頭sentinel)來詢問其它sentinel是否同意服務(wù)下線。
一個sentinel接收另一個sentinel發(fā)來的is-master-down-by-addr后,提取參數(shù),根據(jù)ip和端口,檢測該服務(wù)時候在該sentinel主觀下線,并且回復(fù)is-master-down-by-addr,回復(fù)包含三個參數(shù):down_state(1表示已下線,0表示未下線),leader_runid(領(lǐng)頭sentinal id),leader_epoch(領(lǐng)頭sentinel紀(jì)元)。
sentinel接收到回復(fù)后,根據(jù)配置設(shè)置的下線最小數(shù)量,達(dá)到這個值,既認(rèn)為該服務(wù)客觀下線。
客觀下線條件只適用于主服務(wù)器: 對于任何其他類型的 Redis 實(shí)例, Sentinel 在將它們判斷為下線前不需要進(jìn)行協(xié)商, 所以從服務(wù)器或者其他 Sentinel 永遠(yuǎn)不會達(dá)到客觀下線條件。只要一個 Sentinel 發(fā)現(xiàn)某個主服務(wù)器進(jìn)入了客觀下線狀態(tài), 這個 Sentinel 就可能會被其他 Sentinel 推選出, 并對失效的主服務(wù)器執(zhí)行自動故障遷移操作。

在redis-sentinel的conf文件里有這么兩個配置:
1)sentinel monitor

四個參數(shù)含義:
masterName這個是對某個master+slave組合的一個區(qū)分標(biāo)識(一套sentinel是可以監(jiān)聽多套master+slave這樣的組合的)。
ip 和 port 就是master節(jié)點(diǎn)的 ip 和 端口號。
quorum這個參數(shù)是進(jìn)行客觀下線的一個依據(jù),意思是至少有 quorum 個sentinel主觀的認(rèn)為這個master有故障,才會對這個master進(jìn)行下線以及故障轉(zhuǎn)移。因?yàn)橛械臅r候,某個sentinel節(jié)點(diǎn)可能因?yàn)樽陨砭W(wǎng)絡(luò)原因,導(dǎo)致無法連接master,而此時master并沒有出現(xiàn)故障,所以這就需要多個sentinel都一致認(rèn)為該master有問題,才可以進(jìn)行下一步操作,這就保證了公平性和高可用。

2)sentinel down-after-milliseconds
這個配置其實(shí)就是進(jìn)行主觀下線的一個依據(jù),masterName這個參數(shù)不用說了,timeout是一個毫秒值,表示:如果這臺sentinel超過timeout這個時間都無法連通master包括slave(slave不需要客觀下線,因?yàn)椴恍枰收限D(zhuǎn)移)的話,就會主觀認(rèn)為該master已經(jīng)下線(實(shí)際下線需要客觀下線的判斷通過才會下線)

那么,多個sentinel之間是如何達(dá)到共識的呢?
這就是依賴于前面說的第二個定時任務(wù),某個sentinel先將master節(jié)點(diǎn)進(jìn)行一個主觀下線,然后會將這個判定通過sentinel is-master-down-by-addr這個命令問對應(yīng)的節(jié)點(diǎn)是否也同樣認(rèn)為該addr的master節(jié)點(diǎn)要做客觀下線。最后當(dāng)達(dá)成這一共識的sentinel個數(shù)達(dá)到前面說的quorum設(shè)置的這個值時,就會對該master節(jié)點(diǎn)下線進(jìn)行故障轉(zhuǎn)移。quorum的值一般設(shè)置為sentinel個數(shù)的二分之一加1,例如3個sentinel就設(shè)置2。

主觀下線(SDOWN)和客觀下線(ODOWN)的更多細(xì)節(jié)
sentinel對于不可用有兩種不同的看法,一個叫主觀不可用(SDOWN),另外一個叫客觀不可用(ODOWN)。SDOWN是sentinel自己主觀上檢測到的關(guān)于master的狀態(tài),ODOWN需要一定數(shù)量的sentinel達(dá)成一致意見才能認(rèn)為一個master客觀上已經(jīng)宕掉,各個sentinel之間通過命令SENTINEL is_master_down_by_addr來獲得其它sentinel對master的檢測結(jié)果。
從sentinel的角度來看,如果發(fā)送了PING心跳后,在一定時間內(nèi)沒有收到合法的回復(fù),就達(dá)到了SDOWN的條件。這個時間在配置中通過is-master-down-after-milliseconds參數(shù)配置。
當(dāng)sentinel發(fā)送PING后,以下回復(fù)之一都被認(rèn)為是合法的:
PING replied with +PONG.
PING replied with -LOADING error.
PING replied with -MASTERDOWN error.
其它任何回復(fù)(或者根本沒有回復(fù))都是不合法的。

從SDOWN切換到ODOWN不需要任何一致性算法,只需要一個gossip協(xié)議:如果一個sentinel收到了足夠多的sentinel發(fā)來消息告訴它某個master已經(jīng)down掉了,SDOWN狀態(tài)就會變成ODOWN狀態(tài)。如果之后master可用了,這個狀態(tài)就會相應(yīng)地被清理掉。
正如之前已經(jīng)解釋過了,真正進(jìn)行failover需要一個授權(quán)的過程,但是所有的failover都開始于一個ODOWN狀態(tài)。
ODOWN狀態(tài)只適用于master,對于不是master的redis節(jié)點(diǎn)sentinel之間不需要任何協(xié)商,slaves和sentinel不會有ODOWN狀態(tài)。

配置版本號
為什么要先獲得大多數(shù)sentinel的認(rèn)可時才能真正去執(zhí)行failover呢?
當(dāng)一個sentinel被授權(quán)后,它將會獲得宕掉的master的一份最新配置版本號,當(dāng)failover執(zhí)行結(jié)束以后,這個版本號將會被用于最新的配置。因?yàn)榇蠖鄶?shù)sentinel都已經(jīng)知道該版本號已經(jīng)被要執(zhí)行failover的sentinel拿走了,所以其他的sentinel都不能再去使用這個版本號。這意味著,每次failover都會附帶有一個獨(dú)一無二的版本號。我們將會看到這樣做的重要性。而且,sentinel集群都遵守一個規(guī)則:如果sentinel A推薦sentinel B去執(zhí)行failover,B會等待一段時間后,自行再次去對同一個master執(zhí)行failover,這個等待的時間是通過failover-timeout配置項(xiàng)去配置的。從這個規(guī)則可以看出,sentinel集群中的sentinel不會再同一時刻并發(fā)去failover同一個master,第一個進(jìn)行failover的sentinel如果失敗了,另外一個將會在一定時間內(nèi)進(jìn)行重新進(jìn)行failover,以此類推。
redis sentinel保證了活躍性:如果大多數(shù)sentinel能夠互相通信,最終將會有一個被授權(quán)去進(jìn)行failover.
redis sentinel也保證了安全性:每個試圖去failover同一個master的sentinel都會得到一個獨(dú)一無二的版本號。

配置傳播
一旦一個sentinel成功地對一個master進(jìn)行了failover,它將會把關(guān)于master的最新配置通過廣播形式通知其它sentinel,其它的sentinel則更新對應(yīng)master的配置。
一個faiover要想被成功實(shí)行,sentinel必須能夠向選為master的slave發(fā)送SLAVEOF NO ONE命令,然后能夠通過INFO命令看到新master的配置信息。
當(dāng)將一個slave選舉為master并發(fā)送SLAVEOF NO ONE后,即使其它的slave還沒針對新master重新配置自己,failover也被認(rèn)為是成功了的,然后所有sentinels將會發(fā)布新的配置信息。
新配在集群中相互傳播的方式,就是為什么我們需要當(dāng)一個sentinel進(jìn)行failover時必須被授權(quán)一個版本號的原因。
每個sentinel使用##發(fā)布/訂閱##的方式持續(xù)地傳播master的配置版本信息,配置傳播的##發(fā)布/訂閱##管道是:__sentinel__:hello。
因?yàn)槊恳粋€配置都有一個版本號,所以以版本號最大的那個為標(biāo)準(zhǔn)。

舉個例子:
假設(shè)有一個名為mymaster的地址為192.168.10.202:6379。一開始,集群中所有的sentinel都知道這個地址,于是為mymaster的配置打上版本號1。一段時候后mymaster死了,有一個sentinel被授權(quán)用版本號2對其進(jìn)行failover。如果failover成功了,假設(shè)地址改為了192.168.10.202:9000,此時配置的版本號為2,進(jìn)行failover的sentinel會將新配置廣播給其他的sentinel,由于其他sentinel維護(hù)的版本號為1,發(fā)現(xiàn)新配置的版本號為2時,版本號變大了,說明配置更新了,于是就會采用最新的版本號為2的配置。
這意味著sentinel集群保證了第二種活躍性:一個能夠互相通信的sentinel集群最終會采用版本號最高且相同的配置。

sentinel的"仲裁會"
前面我們談到,當(dāng)一個master被sentinel集群監(jiān)控時,需要為它指定一個參數(shù),這個參數(shù)指定了當(dāng)需要判決master為不可用,并且進(jìn)行failover時,所需要的sentinel數(shù)量,可以稱這個參數(shù)為票數(shù)

不過,當(dāng)failover主備切換真正被觸發(fā)后,failover并不會馬上進(jìn)行,還需要sentinel中的大多數(shù)sentinel授權(quán)后才可以進(jìn)行failover。
當(dāng)ODOWN時,failover被觸發(fā)。failover一旦被觸發(fā),嘗試去進(jìn)行failover的sentinel會去獲得“大多數(shù)”sentinel的授權(quán)(如果票數(shù)比大多數(shù)還要大的時候,則詢問更多的sentinel)
這個區(qū)別看起來很微妙,但是很容易理解和使用。例如,集群中有5個sentinel,票數(shù)被設(shè)置為2,當(dāng)2個sentinel認(rèn)為一個master已經(jīng)不可用了以后,將會觸發(fā)failover,但是,進(jìn)行failover的那個sentinel必須先獲得至少3個sentinel的授權(quán)才可以實(shí)行failover。
如果票數(shù)被設(shè)置為5,要達(dá)到ODOWN狀態(tài),必須所有5個sentinel都主觀認(rèn)為master為不可用,要進(jìn)行failover,那么得獲得所有5個sentinel的授權(quán)。

選舉領(lǐng)頭sentinel(即領(lǐng)導(dǎo)者選舉)
一個redis服務(wù)被判斷為客觀下線時,多個監(jiān)視該服務(wù)的sentinel協(xié)商,選舉一個領(lǐng)頭sentinel,對該redis服務(wù)進(jìn)行故障轉(zhuǎn)移操作。選舉領(lǐng)頭sentinel遵循以下規(guī)則:
1)所有的sentinel都有公平被選舉成領(lǐng)頭的資格。
2)所有的sentinel都有且只有一次將某個sentinel選舉成領(lǐng)頭的機(jī)會(在一輪選舉中),一旦選舉某個sentinel為領(lǐng)頭,不能更改。
3)sentinel設(shè)置領(lǐng)頭sentinel是先到先得,一旦當(dāng)前sentinel設(shè)置了領(lǐng)頭sentinel,以后要求設(shè)置sentinel為領(lǐng)頭請求都會被拒絕。
4)每個發(fā)現(xiàn)服務(wù)客觀下線的sentinel,都會要求其他sentinel將自己設(shè)置成領(lǐng)頭。
5)當(dāng)一個sentinel(源sentinel)向另一個sentinel(目sentinel)發(fā)送is-master-down-by-addr ip port current_epoch runid命令的時候,runid參數(shù)不是*,而是sentinel運(yùn)行id,就表示源sentinel要求目標(biāo)sentinel選舉其為領(lǐng)頭。
6)源sentinel會檢查目標(biāo)sentinel對其要求設(shè)置成領(lǐng)頭的回復(fù),如果回復(fù)的leader_runid和leader_epoch為源sentinel,表示目標(biāo)sentinel同意將源sentinel設(shè)置成領(lǐng)頭。
7)如果某個sentinel被半數(shù)以上的sentinel設(shè)置成領(lǐng)頭,那么該sentinel既為領(lǐng)頭。
8)如果在限定時間內(nèi),沒有選舉出領(lǐng)頭sentinel,暫定一段時間,再選舉。

為什么要選領(lǐng)導(dǎo)者?
簡單來說,就是因?yàn)橹荒苡幸粋€sentinel節(jié)點(diǎn)去完成故障轉(zhuǎn)移。
sentinel is-master-down-by-addr這個命令有兩個作用,一是確認(rèn)下線判定,二是進(jìn)行領(lǐng)導(dǎo)者選舉。
選舉過程:
1)每個做主觀下線的sentinel節(jié)點(diǎn)向其他sentinel節(jié)點(diǎn)發(fā)送上面那條命令,要求將它設(shè)置為領(lǐng)導(dǎo)者。
2)收到命令的sentinel節(jié)點(diǎn)如果還沒有同意過其他的sentinel發(fā)送的命令(還未投過票),那么就會同意,否則拒絕。
3)如果該sentinel節(jié)點(diǎn)發(fā)現(xiàn)自己的票數(shù)已經(jīng)過半且達(dá)到了quorum的值,就會成為領(lǐng)導(dǎo)者
4)如果這個過程出現(xiàn)多個sentinel成為領(lǐng)導(dǎo)者,則會等待一段時間重新選舉。

Redis Sentinel的主從切換方案
Redis 2.8版開始正式提供名為Sentinel的主從切換方案,通俗的來講,Sentinel可以用來管理多個Redis服務(wù)器實(shí)例,可以實(shí)現(xiàn)一個功能上實(shí)現(xiàn)HA的集群,Sentinel主要負(fù)責(zé)三個方面的任務(wù)
1)監(jiān)控(Monitoring): Sentinel 會不斷地檢查你的主服務(wù)器和從服務(wù)器是否運(yùn)作正常。
2)提醒(Notification): 當(dāng)被監(jiān)控的某個 Redis 服務(wù)器出現(xiàn)問題時, Sentinel 可以通過 API 向管理員或者其他應(yīng)用程序發(fā)送通知。
3)自動故障遷移(Automatic failover): 當(dāng)一個主服務(wù)器不能正常工作時, Sentinel 會開始一次自動故障遷移操作, 它會將失效主服務(wù)器的其中一個從服務(wù)器升級為新的主服務(wù)器, 并讓失效主服務(wù)器的其他從服務(wù)器改為復(fù)制新的主服務(wù)器; 當(dāng)客戶端試圖連接失效的主服務(wù)器時, 集群也會向客戶端返回新主服務(wù)器的地址, 使得集群可以使用新主服務(wù)器代替失效服務(wù)器。

Redis Sentinel 是一個分布式系統(tǒng), 可以在一個架構(gòu)中運(yùn)行多個 Sentinel 進(jìn)程(progress), 這些進(jìn)程使用流言協(xié)議(gossip protocols)來接收關(guān)于主服務(wù)器是否下線的信息, 并使用投票協(xié)議(agreement protocols)來決定是否執(zhí)行自動故障遷移, 以及選擇哪個從服務(wù)器作為新的主服務(wù)器。
一個簡單的主從結(jié)構(gòu)加sentinel集群的架構(gòu)圖如下:

上圖是一主一從節(jié)點(diǎn),加上兩個部署了sentinel的集群,sentinel集群之間會互相通信,溝通交流redis節(jié)點(diǎn)的狀態(tài),做出相應(yīng)的判斷并進(jìn)行處理,這里的主觀下線狀態(tài)和客觀下線狀態(tài)是比較重要的狀態(tài),它們決定了是否進(jìn)行故障轉(zhuǎn)移
可以 通過訂閱指定的頻道信息,當(dāng)服務(wù)器出現(xiàn)故障得時候通知管理員
客戶端可以將 Sentinel 看作是一個只提供了訂閱功能的 Redis 服務(wù)器,你不可以使用 PUBLISH 命令向這個服務(wù)器發(fā)送信息,但你可以用 SUBSCRIBE 命令或者 PSUBSCRIBE 命令, 通過訂閱給定的頻道來獲取相應(yīng)的事件提醒。 一個頻道能夠接收和這個頻道的名字相同的事件。 比如說, 名為 +sdown 的頻道就可以接收所有實(shí)例進(jìn)入主觀下線(SDOWN)狀態(tài)的事件。

個人認(rèn)為,Sentinel實(shí)現(xiàn)的最主要的一個功能就是能做到自動故障遷移,即當(dāng)某一個master掛了的時候,可以自動的將某一個slave提升為新的master,且原master的所有slave也都自動的將自己的master改為新提升的master,這樣我們的程序的可用性大大提高了。只要redis安裝完成,Sentinel就安裝完成了,Sentinel集成在redis里了。

Sentinel支持集群(可以部署在多臺機(jī)器上,也可以在一臺物理機(jī)上通過多端口實(shí)現(xiàn)偽集群部署)
很顯然,只使用單個sentinel進(jìn)程來監(jiān)控redis集群是不可靠的,當(dāng)sentinel進(jìn)程宕掉后(sentinel本身也有單點(diǎn)問題,single-point-of-failure)整個集群系統(tǒng)將無法按照預(yù)期的方式運(yùn)行。所以有必要將sentinel集群,這樣有幾個好處:
1)即使有一些sentinel進(jìn)程宕掉了,依然可以進(jìn)行redis集群的主備切換;
2)如果只有一個sentinel進(jìn)程,如果這個進(jìn)程運(yùn)行出錯,或者是網(wǎng)絡(luò)堵塞,那么將無法實(shí)現(xiàn)redis集群的主備切換(單點(diǎn)問題);
3)如果有多個sentinel,redis的客戶端可以隨意地連接任意一個sentinel來獲得關(guān)于redis集群中的信息。

sentinel集群注意事項(xiàng)
1)只有Sentinel 集群中大多數(shù)服務(wù)器認(rèn)定master主觀下線時master才會被認(rèn)定為客觀下線,才可以進(jìn)行故障遷移,也就是說,即使不管我們在sentinel monitor中設(shè)置的數(shù)是多少,就算是滿足了該值,只要達(dá)不到大多數(shù),就不會發(fā)生故障遷移。
2)官方建議sentinel至少部署三臺,且分布在不同機(jī)器。這里主要考慮到sentinel的可用性,假如我們只部署了兩臺sentinel,且quorum設(shè)置為1,也可以實(shí)現(xiàn)自動故障遷移,但假如其中一臺sentinel掛了,就永遠(yuǎn)不會觸發(fā)自動故障遷移,因?yàn)橛肋h(yuǎn)達(dá)不到大多數(shù)sentinel認(rèn)定master主觀下線了。
3)sentinel monitor配置中的master IP盡量不要寫127.0.0.1或localhost,因?yàn)榭蛻舳?#xff0c;如jedis獲取master是根據(jù)這個獲取的,若這樣配置,jedis獲取的ip則是127.0.0.1,這樣就可能導(dǎo)致程序連接不上master
4)當(dāng)sentinel 啟動后會自動的修改sentinel.conf文件,如已發(fā)現(xiàn)的master的slave信息,和集群中其它sentinel 的信息等,這樣即使重啟sentinel也能保持原來的狀態(tài)。注意,當(dāng)集群服務(wù)器調(diào)整時,如更換sentinel的機(jī)器,或者新配置一個sentinel,請不要直接復(fù)制原來運(yùn)行過得sentinel配置文件,因?yàn)槠淅锩孀詣由闪艘陨险f的那些信息,我們應(yīng)該復(fù)制一個新的配置文件或者把自動生成的信息給刪掉。
5)當(dāng)發(fā)生故障遷移的時候,master的變更記錄與slave更換master的修改會自動同步到redis的配置文件,這樣即使重啟redis也能保持變更后的狀態(tài)。

每個 Sentinel 都需要定期執(zhí)行的任務(wù)
每個 Sentinel 以每秒鐘一次的頻率向它所知的主服務(wù)器、從服務(wù)器以及其他 Sentinel 實(shí)例發(fā)送一個 PING 命令。
如果一個實(shí)例(instance)距離最后一次有效回復(fù) PING 命令的時間超過 down-after-milliseconds 選項(xiàng)所指定的值, 那么這個實(shí)例會被 Sentinel 標(biāo)記為主觀下線。 一個有效回復(fù)可以是: +PONG 、 -LOADING 或者 -MASTERDOWN 。
如果一個主服務(wù)器被標(biāo)記為主觀下線, 那么正在監(jiān)視這個主服務(wù)器的所有 Sentinel 要以每秒一次的頻率確認(rèn)主服務(wù)器的確進(jìn)入了主觀下線狀態(tài)。
如果一個主服務(wù)器被標(biāo)記為主觀下線, 并且有足夠數(shù)量的 Sentinel (至少要達(dá)到配置文件指定的數(shù)量)在指定的時間范圍內(nèi)同意這一判斷, 那么這個主服務(wù)器被標(biāo)記為客觀下線。
在一般情況下, 每個 Sentinel 會以每 10 秒一次的頻率向它已知的所有主服務(wù)器和從服務(wù)器發(fā)送 INFO 命令。 當(dāng)一個主服務(wù)器被 Sentinel 標(biāo)記為客觀下線時, Sentinel 向下線主服務(wù)器的所有從服務(wù)器發(fā)送 INFO 命令的頻率會從 10 秒一次改為每秒一次。
當(dāng)沒有足夠數(shù)量的 Sentinel 同意主服務(wù)器已經(jīng)下線, 主服務(wù)器的客觀下線狀態(tài)就會被移除。 當(dāng)主服務(wù)器重新向 Sentinel 的PING 命令返回有效回復(fù)時, 主服務(wù)器的主管下線狀態(tài)就會被移除。

Sentinel之間和Slaves之間的自動發(fā)現(xiàn)機(jī)制
雖然sentinel集群中各個sentinel都互相連接彼此來檢查對方的可用性以及互相發(fā)送消息。但是你不用在任何一個sentinel配置任何其它的sentinel的節(jié)點(diǎn)。因?yàn)閟entinel利用了master的發(fā)布/訂閱機(jī)制去自動發(fā)現(xiàn)其它也監(jiān)控了統(tǒng)一master的sentinel節(jié)點(diǎn)。
通過向名為__sentinel__:hello的管道中發(fā)送消息來實(shí)現(xiàn)。
同樣,你也不需要在sentinel中配置某個master的所有slave的地址,sentinel會通過詢問master來得到這些slave的地址的。
每個sentinel通過向每個master和slave的發(fā)布/訂閱頻道__sentinel__:hello每秒發(fā)送一次消息,來宣布它的存在。
每個sentinel也訂閱了每個master和slave的頻道__sentinel__:hello的內(nèi)容,來發(fā)現(xiàn)未知的sentinel,當(dāng)檢測到了新的sentinel,則將其加入到自身維護(hù)的master監(jiān)控列表中。
每個sentinel發(fā)送的消息中也包含了其當(dāng)前維護(hù)的最新的master配置。如果某個sentinel發(fā)現(xiàn)
自己的配置版本低于接收到的配置版本,則會用新的配置更新自己的master配置。
在為一個master添加一個新的sentinel前,sentinel總是檢查是否已經(jīng)有sentinel與新的sentinel的進(jìn)程號或者是地址是一樣的。如果是那樣,這個sentinel將會被刪除,而把新的sentinel添加上去。

sentinel和redis身份驗(yàn)證
當(dāng)一個master配置為需要密碼才能連接時,客戶端和slave在連接時都需要提供密碼。
master通過requirepass設(shè)置自身的密碼,不提供密碼無法連接到這個master。
slave通過masterauth來設(shè)置訪問master時的密碼。
但是當(dāng)使用了sentinel時,由于一個master可能會變成一個slave,一個slave也可能會變成master,所以需要同時設(shè)置上述兩個配置項(xiàng)。

Sentinel API
在默認(rèn)情況下, Sentinel 使用 TCP 端口 26379 (普通 Redis 服務(wù)器使用的是 6379 )。Sentinel 接受 Redis 協(xié)議格式的命令請求, 所以你可以使用 redis-cli 或者任何其他 Redis 客戶端來與 Sentinel 進(jìn)行通訊。有兩種方式可以和 Sentinel 進(jìn)行通訊:
1)是通過直接發(fā)送命令來查詢被監(jiān)視 Redis 服務(wù)器的當(dāng)前狀態(tài), 以及 Sentinel 所知道的關(guān)于其他 Sentinel 的信息, 諸如此類。
2)是使用發(fā)布與訂閱功能, 通過接收 Sentinel 發(fā)送的通知: 當(dāng)執(zhí)行故障轉(zhuǎn)移操作, 或者某個被監(jiān)視的服務(wù)器被判斷為主觀下線或者客觀下線時, Sentinel 就會發(fā)送相應(yīng)的信息。

Sentinel命令(即登錄到sentinel節(jié)點(diǎn)后執(zhí)行的命令,比如執(zhí)行"redis-cli -h 192.168.10.203 -p 26379"命令后,才可以執(zhí)行下面命令)
PING?:返回 PONG 。
SENTINEL masters?:列出所有被監(jiān)視的主服務(wù)器,以及這些主服務(wù)器的當(dāng)前狀態(tài);
SENTINEL slaves ?:列出給定主服務(wù)器的所有從服務(wù)器,以及這些從服務(wù)器的當(dāng)前狀態(tài);
SENTINEL get-master-addr-by-name ?: 返回給定名字的主服務(wù)器的 IP 地址和端口號。 如果這個主服務(wù)器正在執(zhí)行故障轉(zhuǎn)移操作, 或者針對這個主服務(wù)器的故障轉(zhuǎn)移操作已經(jīng)完成, 那么這個命令返回新的主服務(wù)器的 IP 地址和端口號;
SENTINEL reset ?: 重置所有名字和給定模式 pattern 相匹配的主服務(wù)器。 pattern 參數(shù)是一個 Glob 風(fēng)格的模式。 重置操作清楚主服務(wù)器目前的所有狀態(tài), 包括正在執(zhí)行中的故障轉(zhuǎn)移, 并移除目前已經(jīng)發(fā)現(xiàn)和關(guān)聯(lián)的, 主服務(wù)器的所有從服務(wù)器和 Sentinel ;
SENTINEL failover ?: 當(dāng)主服務(wù)器失效時, 在不詢問其他 Sentinel 意見的情況下, 強(qiáng)制開始一次自動故障遷移。?(不過發(fā)起故障轉(zhuǎn)移的 Sentinel 會向其他 Sentinel 發(fā)送一個新的配置,其他 Sentinel 會根據(jù)這個配置進(jìn)行相應(yīng)的更新)

SENTINEL MONITOR ?這個命令告訴sentinel去監(jiān)聽一個新的master
SENTINEL REMOVE ?命令sentinel放棄對某個master的監(jiān)聽
SENTINEL SET ?這個命令很像Redis的CONFIG SET命令,用來改變指定master的配置。支持多個。例如以下實(shí)例:SENTINEL SET objects-cache-master down-after-milliseconds 1000
只要是配置文件中存在的配置項(xiàng),都可以用SENTINEL SET命令來設(shè)置。這個還可以用來設(shè)置master的屬性,比如說quorum(票數(shù)),而不需要先刪除master,再重新添加master。例如:SENTINEL SET objects-cache-master quorum 5

客戶端可以通過SENTINEL get-master-addr-by-name 獲取當(dāng)前的主服務(wù)器IP地址和端口號,以及SENTINEL slaves 獲取所有的Slaves信息。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

[root@redis-master ~]# redis-cli -h 192.168.10.202 -p 6379 INFO|grep role

role:slave

[root@redis-master ~]# redis-cli -h 192.168.10.203 -p 6379 INFO|grep role

role:slave

[root@redis-master ~]# redis-cli -h 192.168.10.205 -p 6379 INFO|grep role

role:master

登錄任意一個節(jié)點(diǎn)的sentinel,進(jìn)行相關(guān)命令的操作(下面命令例子中的redisMaster是sentinel監(jiān)控redis主從狀態(tài)時定義的master名稱)

1)sentinel masters?? 羅列所有sentinel 監(jiān)視相關(guān)的master

[root@redis-master ~]# redis-cli -h 192.168.10.205 -p 26379

192.168.10.205:26379> sentinel masters

2)sentinel master masterName?? 列出一個master相關(guān)的的信息

[root@redis-master ~]# redis-cli -h 192.168.10.205 -p 26379

192.168.10.205:26379> sentinel master redisMaster

3)sentinel slaves masterName?? 列出一個master相應(yīng)的slave組相關(guān)的數(shù)據(jù)

[root@redis-master ~]# redis-cli -h 192.168.10.205 -p 26379

192.168.10.205:26379> sentinel slaves redisMaster

4)sentinel sentinels masterName?? 列出master相關(guān)的sentinels組其他相關(guān)的信息

[root@redis-master ~]# redis-cli -h 192.168.10.205 -p 26379

192.168.10.205:26379> sentinel sentinels redisMaster

5)sentinel get-master-addr-by-name masterName?? 獲取master-name相關(guān)的 ip addr 的信息

[root@redis-master ~]# redis-cli -h 192.168.10.205 -p 26379

192.168.10.205:26379> sentinel get-master-addr-by-name redisMaster

1)?"192.168.10.205"

2)?"6379"

增加或刪除Sentinel
由于有sentinel自動發(fā)現(xiàn)機(jī)制,所以添加一個sentinel到你的集群中非常容易,你所需要做的只是監(jiān)控到某個Master上,然后新添加的sentinel就能獲得其他sentinel的信息以及master所有的slaves。
如果你需要添加多個sentinel,建議你一個接著一個添加,這樣可以預(yù)防網(wǎng)絡(luò)隔離帶來的問題。你可以每個30秒添加一個sentinel。最后你可以用SENTINEL MASTER mastername來檢查一下是否所有的sentinel都已經(jīng)監(jiān)控到了master。
刪除一個sentinel顯得有點(diǎn)復(fù)雜:因?yàn)閟entinel永遠(yuǎn)不會刪除一個已經(jīng)存在過的sentinel,即使它已經(jīng)與組織失去聯(lián)系很久了。
要想刪除一個sentinel,應(yīng)該遵循如下步驟:
1)停止所要刪除的sentinel
2)發(fā)送一個SENTINEL RESET * 命令給所有其它的sentinel實(shí)例,如果你想要重置指定master上面的sentinel,只需要把*號改為特定的名字,注意,需要一個接一個發(fā),每次發(fā)送的間隔不低于30秒。
3)檢查一下所有的sentinels是否都有一致的當(dāng)前sentinel數(shù)。使用SENTINEL MASTER mastername 來查詢。

刪除舊master或者不可達(dá)slave
sentinel永遠(yuǎn)會記錄好一個Master的slaves,即使slave已經(jīng)與組織失聯(lián)好久了。這是很有用的,因?yàn)閟entinel集群必須有能力把一個恢復(fù)可用的slave進(jìn)行重新配置。
并且,failover后,失效的master將會被標(biāo)記為新master的一個slave,這樣的話,當(dāng)它變得可用時,就會從新master上復(fù)制數(shù)據(jù)。
然后,有時候你想要永久地刪除掉一個slave(有可能它曾經(jīng)是個master),你只需要發(fā)送一個SENTINEL RESET master命令給所有的sentinels,它們將會更新列表里能夠正確地復(fù)制master數(shù)據(jù)的slave。

發(fā)布與訂閱信息(sentinel的日志文件里可以看到這些信息)
客戶端可以將 Sentinel 看作是一個只提供了訂閱功能的 Redis 服務(wù)器: 你不可以使用 PUBLISH 命令向這個服務(wù)器發(fā)送信息, 但你可以用 SUBSCRIBE 命令或者 PSUBSCRIBE 命令, 通過訂閱給定的頻道來獲取相應(yīng)的事件提醒。

一個頻道能夠接收和這個頻道的名字相同的事件。 比如說, 名為 +sdown 的頻道就可以接收所有實(shí)例進(jìn)入主觀下線(SDOWN)狀態(tài)的事件。

通過執(zhí)行 "PSUBSCRIBE * "命令可以接收所有事件信息(即訂閱所有消息)。

以下列出的是客戶端可以通過訂閱來獲得的頻道和信息的格式: 第一個英文單詞是頻道/事件的名字, 其余的是數(shù)據(jù)的格式。

注意, 當(dāng)格式中包含 instance details 字樣時, 表示頻道所返回的信息中包含了以下用于識別目標(biāo)實(shí)例的內(nèi)容.

以下是所有可以收到的消息的消息格式,如果你訂閱了所有消息的話。第一個單詞是頻道的名字,其它是數(shù)據(jù)的格式。
注意:以下的instance details的格式是:
@
如果這個redis實(shí)例是一個master,那么@之后的消息就不會顯示。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

+reset-master -- 當(dāng)master被重置時.

????+slave -- 當(dāng)檢測到一個slave并添加進(jìn)slave列表時.

????+failover-state-reconf-slaves -- Failover狀態(tài)變?yōu)閞econf-slaves狀態(tài)時

????+failover-detected -- 當(dāng)failover發(fā)生時

????+slave-reconf-sent -- sentinel發(fā)送SLAVEOF命令把它重新配置時

????+slave-reconf-inprog -- slave被重新配置為另外一個master的slave,但數(shù)據(jù)復(fù)制還未發(fā)生時。

????+slave-reconf-done? -- slave被重新配置為另外一個master的slave并且數(shù)據(jù)復(fù)制已經(jīng)與master同步時。

????-dup-sentinel -- 刪除指定master上的冗余sentinel時 (當(dāng)一個sentinel重新啟動時,可能會發(fā)生這個事件).

????+sentinel -- 當(dāng)master增加了一個sentinel時。

????+sdown -- 進(jìn)入SDOWN狀態(tài)時;

????-sdown -- 離開SDOWN狀態(tài)時。

????+odown -- 進(jìn)入ODOWN狀態(tài)時。

????-odown -- 離開ODOWN狀態(tài)時。

????+new-epoch -- 當(dāng)前配置版本被更新時。

????+try-failover -- 達(dá)到failover條件,正等待其他sentinel的選舉。

????+elected-leader -- 被選舉為去執(zhí)行failover的時候。

????+failover-state-select-slave -- 開始要選擇一個slave當(dāng)選新master時。

????no-good-slave -- 沒有合適的slave來擔(dān)當(dāng)新master

????selected-slave -- 找到了一個適合的slave來擔(dān)當(dāng)新master

????failover-state-send-slaveof-noone -- 當(dāng)把選擇為新master的slave的身份進(jìn)行切換的時候。

????failover-end-for-timeout -- failover由于超時而失敗時。

????failover-end -- failover成功完成時。

????switch-master -- 當(dāng)master的地址發(fā)生變化時。通常這是客戶端最感興趣的消息了。

????+tilt -- 進(jìn)入Tilt模式。

????-tilt -- 退出Tilt模式。

可以看出,使用Sentinel命令和發(fā)布訂閱兩種機(jī)制就能很好的實(shí)現(xiàn)和客戶端的集成整合:
使用get-master-addr-by-name和slaves指令可以獲取當(dāng)前的Master和Slaves的地址和信息;而當(dāng)發(fā)生故障轉(zhuǎn)移時,即Master發(fā)生切換,可以通過訂閱的+switch-master事件獲得最新的Master信息。

sentinel.conf中的notification-script
在sentinel.conf中可以配置多個sentinel notification-script , 如sentinel notification-script mymaster ./check.sh
這個是在群集failover時會觸發(fā)執(zhí)行指定的腳本。腳本的執(zhí)行結(jié)果若為1,即稍后重試(最大重試次數(shù)為10);若為2,則執(zhí)行結(jié)束。并且腳本最大執(zhí)行時間為60秒,超時會被終止執(zhí)行。

目前會存在該腳本被執(zhí)行多次的問題,網(wǎng)上查找資料獲得的解釋是:腳本分為兩個級別, SENTINEL_LEADER 和 SENTINEL_OBSERVER ,前者僅由領(lǐng)頭 Sentinel 執(zhí)行(一個 Sentinel),而后者由監(jiān)視同一個 master 的所有 Sentinel 執(zhí)行(多個 Sentinel)。

無failover時的配置糾正
即使當(dāng)前沒有failover正在進(jìn)行,sentinel依然會使用當(dāng)前配置去設(shè)置監(jiān)控的master。特別是:
1)根據(jù)最新配置確認(rèn)為slaves的節(jié)點(diǎn)卻聲稱自己是master(上文例子中被網(wǎng)絡(luò)隔離后的的redis3),這時它們會被重新配置為當(dāng)前master的slave。
2)如果slaves連接了一個錯誤的master,將會被改正過來,連接到正確的master。

Slave選舉與優(yōu)先級
當(dāng)一個sentinel準(zhǔn)備好了要進(jìn)行failover,并且收到了其他sentinel的授權(quán),那么就需要選舉出一個合適的slave來做為新的master。

slave的選舉主要會評估slave的以下幾個方面:
1)與master斷開連接的次數(shù)
2)Slave的優(yōu)先級
3)數(shù)據(jù)復(fù)制的下標(biāo)(用來評估slave當(dāng)前擁有多少master的數(shù)據(jù))
4)進(jìn)程ID

如果一個slave與master失去聯(lián)系超過10次,并且每次都超過了配置的最大失聯(lián)時間(down-after-milliseconds),如果sentinel在進(jìn)行failover時發(fā)現(xiàn)slave失聯(lián),那么這個slave就會被sentinel認(rèn)為不適合用來做新master的。
更嚴(yán)格的定義是,如果一個slave持續(xù)斷開連接的時間超過
(down-after-milliseconds * 10) + milliseconds_since_master_is_in_SDOWN_state
就會被認(rèn)為失去選舉資格。

符合上述條件的slave才會被列入master候選人列表,并根據(jù)以下順序來進(jìn)行排序:
1)sentinel首先會根據(jù)slaves的優(yōu)先級來進(jìn)行排序,優(yōu)先級越小排名越靠前。
2)如果優(yōu)先級相同,則查看復(fù)制的下標(biāo),哪個從master接收的復(fù)制數(shù)據(jù)多,哪個就靠前。
3)如果優(yōu)先級和下標(biāo)都相同,就選擇進(jìn)程ID較小的那個。

一個redis無論是master還是slave,都必須在配置中指定一個slave優(yōu)先級。要注意到master也是有可能通過failover變成slave的。
如果一個redis的slave優(yōu)先級配置為0,那么它將永遠(yuǎn)不會被選為master。但是它依然會從master哪里復(fù)制數(shù)據(jù)。

故障轉(zhuǎn)移
所謂故障轉(zhuǎn)移就是當(dāng)master宕機(jī),選一個合適的slave來晉升為master的操作,redis-sentinel會自動完成這個,不需要我們手動來實(shí)現(xiàn)。

一次故障轉(zhuǎn)移操作大致分為以下流程:
發(fā)現(xiàn)主服務(wù)器已經(jīng)進(jìn)入客觀下線狀態(tài)。
對我們的當(dāng)前集群進(jìn)行自增, 并嘗試在這個集群中當(dāng)選。
如果當(dāng)選失敗, 那么在設(shè)定的故障遷移超時時間的兩倍之后, 重新嘗試當(dāng)選。 如果當(dāng)選成功, 那么執(zhí)行以下步驟:
選出一個從服務(wù)器,并將它升級為主服務(wù)器。
向被選中的從服務(wù)器發(fā)送 SLAVEOF NO ONE 命令,讓它轉(zhuǎn)變?yōu)橹鞣?wù)器。
通過發(fā)布與訂閱功能, 將更新后的配置傳播給所有其他 Sentinel , 其他 Sentinel 對它們自己的配置進(jìn)行更新。
向已下線主服務(wù)器的從服務(wù)器發(fā)送 SLAVEOF 命令, 讓它們?nèi)?fù)制新的主服務(wù)器。
當(dāng)所有從服務(wù)器都已經(jīng)開始復(fù)制新的主服務(wù)器時, 領(lǐng)頭 Sentinel 終止這次故障遷移操作。
每當(dāng)一個 Redis 實(shí)例被重新配置(reconfigured) —— 無論是被設(shè)置成主服務(wù)器、從服務(wù)器、又或者被設(shè)置成其他主服務(wù)器的從服務(wù)器 —— Sentinel 都會向被重新配置的實(shí)例發(fā)送一個 CONFIG REWRITE 命令, 從而確保這些配置會持久化在硬盤里。

Sentinel 使用以下規(guī)則來選擇新的主服務(wù)器:
在失效主服務(wù)器屬下的從服務(wù)器當(dāng)中, 那些被標(biāo)記為主觀下線、已斷線、或者最后一次回復(fù) PING 命令的時間大于五秒鐘的從服務(wù)器都會被淘汰。
在失效主服務(wù)器屬下的從服務(wù)器當(dāng)中, 那些與失效主服務(wù)器連接斷開的時長超過 down-after 選項(xiàng)指定的時長十倍的從服務(wù)器都會被淘汰。
在經(jīng)歷了以上兩輪淘汰之后剩下來的從服務(wù)器中, 我們選出復(fù)制偏移量(replication offset)最大的那個從服務(wù)器作為新的主服務(wù)器; 如果復(fù)制偏移量不可用, 或者從服務(wù)器的復(fù)制偏移量相同, 那么帶有最小運(yùn)行 ID 的那個從服務(wù)器成為新的主服務(wù)器。

Sentinel 自動故障遷移的一致性特質(zhì)
Sentinel 自動故障遷移使用 Raft 算法來選舉領(lǐng)頭(leader) Sentinel , 從而確保在一個給定的紀(jì)元(epoch)里, 只有一個領(lǐng)頭產(chǎn)生。

這表示在同一個紀(jì)元中, 不會有兩個 Sentinel 同時被選中為領(lǐng)頭, 并且各個 Sentinel 在同一個紀(jì)元中只會對一個領(lǐng)頭進(jìn)行投票。

更高的配置紀(jì)元總是優(yōu)于較低的紀(jì)元, 因此每個 Sentinel 都會主動使用更新的紀(jì)元來代替自己的配置。

簡單來說, 可以將 Sentinel 配置看作是一個帶有版本號的狀態(tài)。 一個狀態(tài)會以最后寫入者勝出(last-write-wins)的方式(也即是,最新的配置總是勝出)傳播至所有其他 Sentinel 。

舉個例子, 當(dāng)出現(xiàn)網(wǎng)絡(luò)分割(network partitions)時, 一個 Sentinel 可能會包含了較舊的配置, 而當(dāng)這個 Sentinel 接到其他 Sentinel 發(fā)來的版本更新的配置時, Sentinel 就會對自己的配置進(jìn)行更新。

如果要在網(wǎng)絡(luò)分割出現(xiàn)的情況下仍然保持一致性, 那么應(yīng)該使用 min-slaves-to-write 選項(xiàng), 讓主服務(wù)器在連接的從實(shí)例少于給定數(shù)量時停止執(zhí)行寫操作, 與此同時, 應(yīng)該在每個運(yùn)行 Redis 主服務(wù)器或從服務(wù)器的機(jī)器上運(yùn)行 Redis Sentinel 進(jìn)程。

Sentinel 狀態(tài)的持久化
Sentinel 的狀態(tài)會被持久化在 Sentinel 配置文件里面。每當(dāng) Sentinel 接收到一個新的配置, 或者當(dāng)領(lǐng)頭 Sentinel 為主服務(wù)器創(chuàng)建一個新的配置時, 這個配置會與配置紀(jì)元一起被保存到磁盤里面。這意味著停止和重啟 Sentinel 進(jìn)程都是安全的。

Sentinel 在非故障遷移的情況下對實(shí)例進(jìn)行重新配置
即使沒有自動故障遷移操作在進(jìn)行, Sentinel 總會嘗試將當(dāng)前的配置設(shè)置到被監(jiān)視的實(shí)例上面。 特別是:

根據(jù)當(dāng)前的配置, 如果一個從服務(wù)器被宣告為主服務(wù)器, 那么它會代替原有的主服務(wù)器, 成為新的主服務(wù)器, 并且成為原有主服務(wù)器的所有從服務(wù)器的復(fù)制對象。
那些連接了錯誤主服務(wù)器的從服務(wù)器會被重新配置, 使得這些從服務(wù)器會去復(fù)制正確的主服務(wù)器。
不過, 在以上這些條件滿足之后, Sentinel 在對實(shí)例進(jìn)行重新配置之前仍然會等待一段足夠長的時間, 確??梢越邮盏狡渌?Sentinel 發(fā)來的配置更新, 從而避免自身因?yàn)楸4媪诉^期的配置而對實(shí)例進(jìn)行了不必要的重新配置。

總結(jié)來說,故障轉(zhuǎn)移分為三個步驟:

1)從下線的主服務(wù)的所有從服務(wù)里面挑選一個從服務(wù),將其轉(zhuǎn)成主服務(wù)
sentinel狀態(tài)數(shù)據(jù)結(jié)構(gòu)中保存了主服務(wù)的所有從服務(wù)信息,領(lǐng)頭sentinel按照如下的規(guī)則從從服務(wù)列表中挑選出新的主服務(wù);
刪除列表中處于下線狀態(tài)的從服務(wù);
刪除最近5秒沒有回復(fù)過領(lǐng)頭sentinel info信息的從服務(wù);
刪除與已下線的主服務(wù)斷開連接時間超過 down-after-milliseconds*10毫秒的從服務(wù),這樣就能保留從的數(shù)據(jù)比較新(沒有過早的與主斷開連接);
領(lǐng)頭sentinel從剩下的從列表中選擇優(yōu)先級高的,如果優(yōu)先級一樣,選擇偏移量最大的(偏移量大說明復(fù)制的數(shù)據(jù)比較新),如果偏移量一樣,選擇運(yùn)行id最小的從服務(wù)。

2)已下線主服務(wù)的所有從服務(wù)改為復(fù)制新的主服務(wù)
挑選出新的主服務(wù)之后,領(lǐng)頭sentinel 向原主服務(wù)的從服務(wù)發(fā)送 slaveof 新主服務(wù) 的命令,復(fù)制新master。

3)將已下線的主服務(wù)設(shè)置成新的主服務(wù)的從服務(wù),當(dāng)其回復(fù)正常時,復(fù)制新的主服務(wù),變成新的主服務(wù)的從服務(wù)
同理,當(dāng)已下線的服務(wù)重新上線時,sentinel會向其發(fā)送slaveof命令,讓其成為新主的從。

溫馨提示:還可以向任意sentinel發(fā)生sentinel failover 進(jìn)行手動故障轉(zhuǎn)移,這樣就不需要經(jīng)過上述主客觀和選舉的過程。

sentinel.conf文件配置參數(shù)解釋

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

1)sentinel monitor mymaster 192.168.10.202 6379 2

Sentine監(jiān)聽的maste地址,第一個參數(shù)是給master起的名字,第二個參數(shù)為master IP,第三個為master端口,第四個為當(dāng)該master掛了的時候,若想將該master判為失效,

在Sentine集群中必須至少2個Sentine同意才行,只要該數(shù)量不達(dá)標(biāo),則就不會發(fā)生故障遷移。也就是說只要有2個sentinel認(rèn)為master下線,就認(rèn)為該master客觀下線,

啟動failover并選舉產(chǎn)生新的master。通常最后一個參數(shù)不能多于啟動的sentinel實(shí)例數(shù)。

這個配置是sentinel需要監(jiān)控的master/slaver信息,格式為sentinel monitor ?

其中應(yīng)該小于集群中slave的個數(shù),當(dāng)失效的節(jié)點(diǎn)數(shù)超過了,則認(rèn)為整個體系結(jié)構(gòu)失效

不過要注意, 無論你設(shè)置要多少個 Sentinel 同意才能判斷一個服務(wù)器失效, 一個 Sentinel 都需要獲得系統(tǒng)中多數(shù)(majority) Sentinel 的支持, 才能發(fā)起一次自動故障遷移,

并預(yù)留一個給定的配置紀(jì)元 (configuration Epoch ,一個配置紀(jì)元就是一個新主服務(wù)器配置的版本號)。

??

換句話說, 在只有少數(shù)(minority) Sentinel 進(jìn)程正常運(yùn)作的情況下, Sentinel 是不能執(zhí)行自動故障遷移的。

-----------------------------------------------------------------------------------------------

2)sentinel down-after-milliseconds mymaster 30000

表示master被當(dāng)前sentinel實(shí)例認(rèn)定為失效的間隔時間。

master在多長時間內(nèi)一直沒有給Sentine返回有效信息,則認(rèn)定該master主觀下線。也就是說如果多久沒聯(lián)系上redis-servevr,認(rèn)為這個redis-server進(jìn)入到失效(SDOWN)狀態(tài)。

??

如果服務(wù)器在給定的毫秒數(shù)之內(nèi), 沒有返回 Sentinel 發(fā)送的 PING 命令的回復(fù), 或者返回一個錯誤, 那么 Sentinel 將這個服務(wù)器標(biāo)記為主觀下線(subjectively down,簡稱 SDOWN )。

不過只有一個 Sentinel 將服務(wù)器標(biāo)記為主觀下線并不一定會引起服務(wù)器的自動故障遷移: 只有在足夠數(shù)量的 Sentinel 都將一個服務(wù)器標(biāo)記為主觀下線之后, 服務(wù)器才會被標(biāo)記為客觀下線

(objectively down, 簡稱 ODOWN ), 這時自動故障遷移才會執(zhí)行。

將服務(wù)器標(biāo)記為客觀下線所需的 Sentinel 數(shù)量由對主服務(wù)器的配置決定。

-----------------------------------------------------------------------------------------------

3)sentinel parallel-syncs mymaster 2

當(dāng)在執(zhí)行故障轉(zhuǎn)移時,設(shè)置幾個slave同時進(jìn)行切換master,該值越大,則可能就有越多的slave在切換master時不可用,可以將該值設(shè)置為1,即一個一個來,這樣在某個

slave進(jìn)行切換master同步數(shù)據(jù)時,其余的slave還能正常工作,以此保證每次只有一個從服務(wù)器處于不能處理命令請求的狀態(tài)。

??

parallel-syncs 選項(xiàng)指定了在執(zhí)行故障轉(zhuǎn)移時, 最多可以有多少個從服務(wù)器同時對新的主服務(wù)器進(jìn)行同步, 這個數(shù)字越小, 完成故障轉(zhuǎn)移所需的時間就越長。

??

如果從服務(wù)器被設(shè)置為允許使用過期數(shù)據(jù)集(參見對 redis.conf 文件中對 slave-serve-stale-data 選項(xiàng)的說明), 那么你可能不希望所有從服務(wù)器都在同一時間向新的主服務(wù)器發(fā)送同步請求,

因?yàn)楸M管復(fù)制過程的絕大部分步驟都不會阻塞從服務(wù)器, 但從服務(wù)器在載入主服務(wù)器發(fā)來的 RDB 文件時, 仍然會造成從服務(wù)器在一段時間內(nèi)不能處理命令請求: 如果全部從服務(wù)器一起對新的主

服務(wù)器進(jìn)行同步, 那么就可能會造成所有從服務(wù)器在短時間內(nèi)全部不可用的情況出現(xiàn)。

當(dāng)新master產(chǎn)生時,同時進(jìn)行"slaveof"到新master并進(jìn)行"SYNC"的slave個數(shù)。?

默認(rèn)為1,建議保持默認(rèn)值?

在salve執(zhí)行salveof與同步時,將會終止客戶端請求。?

此值較大,意味著"集群"終止客戶端請求的時間總和和較大。?

此值較小,意味著"集群"在故障轉(zhuǎn)移期間,多個salve向客戶端提供服務(wù)時仍然使用舊數(shù)據(jù)。?

-----------------------------------------------------------------------------------------------

4)sentinel can-failover mymaster?yes

在sentinel檢測到O_DOWN后,是否對這臺redis啟動failover機(jī)制

-----------------------------------------------------------------------------------------------

5)sentinel auth-pass mymaster 20180408

設(shè)置sentinel連接的master和slave的密碼,這個需要和redis.conf文件中設(shè)置的密碼一樣

-----------------------------------------------------------------------------------------------

6)sentinel failover-timeout mymaster 180000

failover過期時間,當(dāng)failover開始后,在此時間內(nèi)仍然沒有觸發(fā)任何failover操作,當(dāng)前sentinel將會認(rèn)為此次failoer失敗。?

執(zhí)行故障遷移超時時間,即在指定時間內(nèi)沒有大多數(shù)的sentinel 反饋master下線,該故障遷移計劃則失效

-----------------------------------------------------------------------------------------------

7)sentinel config-epoch mymaster 0

選項(xiàng)指定了在執(zhí)行故障轉(zhuǎn)移時, 最多可以有多少個從服務(wù)器同時對新的主服務(wù)器進(jìn)行同步。這個數(shù)字越小, 完成故障轉(zhuǎn)移所需的時間就越長。

-----------------------------------------------------------------------------------------------

8)sentinel notification-script mymaster?/var/redis/notify.sh

當(dāng)failover時,可以指定一個"通知"腳本用來告知當(dāng)前集群的情況。

腳本被允許執(zhí)行的最大時間為60秒,如果超時,腳本將會被終止(KILL)

-----------------------------------------------------------------------------------------------

9)sentinel leader-epoch mymaster 0

同時一時間最多0個slave可同時更新配置,建議數(shù)字不要太大,以免影響正常對外提供服務(wù)。

基于以上細(xì)節(jié)知識梳理,總結(jié)出sentinel的工作原理

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

首先要能理解SDOWN和ODOWN這兩個詞的含義,上面已經(jīng)詳細(xì)介紹了它們倆。在此再提一下:

SDOWN:subjectively down,直接翻譯的為"主觀"失效,即當(dāng)前sentinel實(shí)例認(rèn)為某個redis服務(wù)為"不可用"狀態(tài).

ODOWN:objectively down,直接翻譯為"客觀"失效,即多個sentinel實(shí)例都認(rèn)為master處于"SDOWN"狀態(tài),那么此時master將處于ODOWN,ODOWN可以簡單理解為master已經(jīng)被集群確定

為"不可用",將會開啟failover.

SDOWN適合于master和slave,但是ODOWN只會使用于master;當(dāng)slave失效超過"down-after-milliseconds"后,那么所有sentinel實(shí)例都會將其標(biāo)記為"SDOWN"。

1) SDOWN與ODOWN轉(zhuǎn)換過程:

每個sentinel實(shí)例在啟動后,都會和已知的slaves/master以及其他sentinels建立TCP連接,并周期性發(fā)送PING(默認(rèn)為1秒)

在交互中,如果redis-server無法在"down-after-milliseconds"時間內(nèi)響應(yīng)或者響應(yīng)錯誤信息,都會被認(rèn)為此redis-server處于SDOWN狀態(tài)。

如果SDOWN的server為master,那么此時sentinel實(shí)例將會向其他sentinel間歇性(一秒)發(fā)送"is-master-down-by-addr "指令并獲取響應(yīng)信息,如果足夠多的

sentinel實(shí)例檢測到master處于SDOWN,那么此時當(dāng)前sentinel實(shí)例標(biāo)記master為ODOWN...其他sentinel實(shí)例做同樣的交互操作。

配置項(xiàng)"sentinel monitor ",如果檢測到master處于SDOWN狀態(tài)的slave個數(shù)達(dá)到,那么此時此sentinel實(shí)例將會認(rèn)為

master處于ODOWN。每個sentinel實(shí)例將會間歇性(10秒)向master和slaves發(fā)送"INFO"指令,如果master失效且沒有新master選出時,每1秒發(fā)送一次"INFO";"INFO"的主要目的就是

獲取并確認(rèn)當(dāng)前集群環(huán)境中slaves和master的存活情況。

經(jīng)過上述過程后,所有的sentinel對master失效達(dá)成一致后,開始failover.

2) Sentinel與slaves"自動發(fā)現(xiàn)"機(jī)制:

在sentinel的配置文件中(local-sentinel.conf),都指定了port,此port就是sentinel實(shí)例偵聽其他sentinel實(shí)例建立鏈接的端口.在集群穩(wěn)定后,最終會每個sentinel實(shí)例之間都

會建立一個tcp鏈接,此鏈接中發(fā)送"PING"以及類似于"is-master-down-by-addr"指令集,可用用來檢測其他sentinel實(shí)例的有效性以及"ODOWN"和"failover"過程中信息的交互.

在sentinel之間建立連接之前,sentinel將會盡力和配置文件中指定的master建立連接.sentinel與master的連接中的通信主要是基于pub/sub來發(fā)布和接收信息,發(fā)布的信息內(nèi)容包

括當(dāng)前sentinel實(shí)例的偵聽端口:

+sentinel sentinel 127.0.0.1:26579 127.0.0.1 26579 ....?

發(fā)布的主題名稱為"__sentinel__:hello";同時sentinel實(shí)例也是"訂閱"此主題,以獲得其他sentinel實(shí)例的信息.由此可見,環(huán)境首次構(gòu)建時,在默認(rèn)master存活的情況下,所有的

sentinel實(shí)例可以通過pub/sub即可獲得所有的sentinel信息,此后每個sentinel實(shí)例即可以根據(jù)+sentinel信息中的"ip+port"和其他sentinel逐個建立tcp連接即可.不過需要提醒

的是,每個sentinel實(shí)例均會間歇性(5秒)向"__sentinel__:hello"主題中發(fā)布自己的ip+port,目的就是讓后續(xù)加入集群的sentinel實(shí)例也能或得到自己的信息。

根據(jù)上文,我們知道在master有效的情況下,即可通過"INFO"指令獲得當(dāng)前master中已有的slave列表;此后任何slave加入集群,master都會向"主題中"發(fā)布"+slave 127.0.0.1:6579 ..",

那么所有的sentinel也將立即獲得slave信息,并和slave建立鏈接并通過PING檢測其存活性.

補(bǔ)充一下,每個sentinel實(shí)例都會保存其他sentinel實(shí)例的列表以及現(xiàn)存的master/slaves列表,各自的列表中不會有重復(fù)的信息(不可能出現(xiàn)多個tcp連接),對于sentinel將使用ip+port

做唯一性標(biāo)記,

對于master/slaver將使用runid做唯一性標(biāo)記,其中redis-server的runid在每次啟動時都不同.

3) Leader選舉:

其實(shí)在sentinels故障轉(zhuǎn)移中,仍然需要一個"Leader"來調(diào)度整個過程:master的選舉以及slave的重配置和同步。當(dāng)集群中有多個sentinel實(shí)例時,如何選舉其中一個sentinel為leader呢?

在配置文件中"can-failover""quorum"參數(shù),以及"is-master-down-by-addr"指令配合來完成整個過程。

A)?"can-failover"用來表明當(dāng)前sentinel是否可以參與"failover"過程,如果為"YES"則表明它將有能力參與"Leader"的選舉,否則它將作為"Observer",observer參與leader選舉投票但

不能被選舉;

B)?"quorum"不僅用來控制master ODOWN狀態(tài)確認(rèn),同時還用來選舉leader時最小"贊同票"數(shù);

C)?"is-master-down-by-addr",它可以用來檢測"ip + port"的master是否已經(jīng)處于SDOWN狀態(tài),不過此指令不僅能夠獲得master是否處于SDOWN,同時它還額外的返回當(dāng)前sentinel

本地"投票選舉"的Leader信息(runid);

每個sentinel實(shí)例都持有其他的sentinels信息,在Leader選舉過程中(當(dāng)為leader的sentinel實(shí)例失效時,有可能master server并沒失效,注意分開理解),sentinel實(shí)例將從所有的

sentinels集合中去除"can-failover = no"和狀態(tài)為SDOWN的sentinels,在剩余的sentinels列表中按照runid按照"字典"順序排序后,取出runid最小的sentinel實(shí)例,并將它"投票選舉"

為Leader,并在其他sentinel發(fā)送的"is-master-down-by-addr"指令時將推選的runid追加到響應(yīng)中。每個sentinel實(shí)例都會檢測"is-master-down-by-addr"的響應(yīng)結(jié)果,如果"投票選舉"的

leader為自己,且狀態(tài)正常的sentinels實(shí)例中,"贊同者"的自己的sentinel個數(shù)不小于(>=) 50% + 1,且不小與,那么此sentinel就會認(rèn)為選舉成功且leader為自己。

在sentinel.conf文件中,我們期望有足夠多的sentinel實(shí)例配置"can-failover yes",這樣能夠確保當(dāng)leader失效時,能夠選舉某個sentinel為leader,以便進(jìn)行failover。如果leader無法產(chǎn)生,

比如較少的sentinels實(shí)例有效,那么failover過程將無法繼續(xù).

4) failover過程:

在Leader觸發(fā)failover之前,首先wait數(shù)秒(隨即0~5),以便讓其他sentinel實(shí)例準(zhǔn)備和調(diào)整(有可能多個leader??),如果一切正常,那么leader就需要開始將一個salve提升為master,此slave

必須為狀態(tài)良好(不能處于SDOWN/ODOWN狀態(tài))且權(quán)重值最低(redis.conf中)的,當(dāng)master身份被確認(rèn)后,開始failover

A)"+failover-triggered": Leader開始進(jìn)行failover,此后緊跟著"+failover-state-wait-start",wait數(shù)秒。

B)"+failover-state-select-slave": Leader開始查找合適的slave

C)"+selected-slave": 已經(jīng)找到合適的slave

D)?"+failover-state-sen-slaveof-noone": Leader向slave發(fā)送"slaveof no one"指令,此時slave已經(jīng)完成角色轉(zhuǎn)換,此slave即為master

E)?"+failover-state-wait-promotition": 等待其他sentinel確認(rèn)slave

F)"+promoted-slave":確認(rèn)成功

G)"+failover-state-reconf-slaves": 開始對slaves進(jìn)行reconfig操作。

H)"+slave-reconf-sent":向指定的slave發(fā)送"slaveof"指令,告知此slave跟隨新的master

I)"+slave-reconf-inprog": 此slave正在執(zhí)行slaveof + SYNC過程,如過slave收到"+slave-reconf-sent"之后將會執(zhí)行slaveof操作。

J)"+slave-reconf-done": 此slave同步完成,此后leader可以繼續(xù)下一個slave的reconfig操作。循環(huán)G)

K)"+failover-end": 故障轉(zhuǎn)移結(jié)束

L)"+switch-master":故障轉(zhuǎn)移成功后,各個sentinel實(shí)例開始監(jiān)控新的master。

二、redis sentinel 主從切換(failover)的容災(zāi)環(huán)境部署記錄

redis主從復(fù)制簡單來說:
A)Redis的復(fù)制功能是支持多個數(shù)據(jù)庫之間的數(shù)據(jù)同步。一類是主數(shù)據(jù)庫(master)一類是從數(shù)據(jù)庫(slave),主數(shù)據(jù)庫可以進(jìn)行讀寫操作,當(dāng)發(fā)生寫操作的時候自動將數(shù)據(jù)同步到從數(shù)據(jù)庫,而從數(shù)據(jù)庫一般是只讀的,并接收主數(shù)據(jù)庫同步過來的數(shù)據(jù),一個主數(shù)據(jù)庫可以有多個從數(shù)據(jù)庫,而一個從數(shù)據(jù)庫只能有一個主數(shù)據(jù)庫。
B)通過redis的復(fù)制功能可以很好的實(shí)現(xiàn)數(shù)據(jù)庫的讀寫分離,提高服務(wù)器的負(fù)載能力。主數(shù)據(jù)庫主要進(jìn)行寫操作,而從數(shù)據(jù)庫負(fù)責(zé)讀操作。

Redis主從復(fù)制流程簡圖

redis主從復(fù)制的大致過程:
1)當(dāng)一個從數(shù)據(jù)庫啟動時,會向主數(shù)據(jù)庫發(fā)送sync命令,
2)主數(shù)據(jù)庫接收到sync命令后會開始在后臺保存快照(執(zhí)行rdb操作),并將保存期間接收到的命令緩存起來
3)當(dāng)快照完成后,redis會將快照文件和所有緩存的命令發(fā)送給從數(shù)據(jù)庫。
4)從數(shù)據(jù)庫收到后,會載入快照文件并執(zhí)行收到的緩存的命令。

注意:redis2.8之前的版本:當(dāng)主從數(shù)據(jù)庫同步的時候從數(shù)據(jù)庫因?yàn)榫W(wǎng)絡(luò)原因斷開重連后會重新執(zhí)行上述操作,不支持?jǐn)帱c(diǎn)續(xù)傳。redis2.8之后支持?jǐn)帱c(diǎn)續(xù)傳。

0)Redis主從結(jié)構(gòu)支持一主多從+n個sentinel模式,信息如下:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

192.168.10.202?? redis-master??? redis(6379)、sentinel(26379)

192.168.10.203?? redis-slave01?? redis(6379)、sentinel(26379)

192.168.10.205?? redis-slave02?? redis(6379)、sentinel(26379)?

??

關(guān)閉三個節(jié)點(diǎn)機(jī)器的iptables和selinux(所有節(jié)點(diǎn)機(jī)器上都要操作)

[root@redis-master ~]# /etc/init.d/iptables stop

[root@redis-master ~]# vim /etc/sysconfig/selinux

......

SELINUX=disabled

[root@redis-master ~]# setenforce 0

[root@redis-master ~]# getenforce

Permissive

??

注意:本案例采用1主2從+3 sentinel的集群模式,所有從節(jié)點(diǎn)的配置都一樣。

a)redis服務(wù)器上各自存在一個Sentinel,監(jiān)控本機(jī)redis的運(yùn)行情況,并通知給閉路環(huán)上其它的redis節(jié)點(diǎn);
b)當(dāng)master發(fā)生異常(例如:宕機(jī)和斷電等)導(dǎo)致不可運(yùn)行時,Sentinel將通知給其它節(jié)點(diǎn),而剩余節(jié)點(diǎn)上的Sentinel將重新選舉出新的master,而原來的master重新恢復(fù)正常后,則一直扮演slave角色;
c)規(guī)定整個架構(gòu)體系中,master提供讀寫服務(wù),而slave只提供讀取服務(wù)。

1)redis一鍵安裝(三個節(jié)點(diǎn)上都要操作)

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

[root@redis-master ~]# cd /usr/local/src/

[root@redis-master src]# vim install_redis.sh

#!/usr/bin/env bash

# It's Used to be install redis.

# Created on 2018/04/08 11:18.

# @author: wangshibo.

# Version: 1.0

???

function?install_redis () {

#################################################################################################

????????cd?/usr/local/src

????????if?[ ! -f?" redis-4.0.1.tar.gz"?];?then

???????????wget http://download.redis.io/releases/redis-4.0.1.tar.gz

????????fi

????????cd?/usr/local/src

????????tar?-zxvf?/usr/local/src/redis-4.0.1.tar.gz

????????cd?redis-4.0.1

????????make?PREFIX=/usr/local/redis?install

????????mkdir?-p?/usr/local/redis/{etc,var}

????????rsync?-avz redis.conf??/usr/local/redis/etc/

????????sed?-i?'s@pidfile.*@pidfile /var/run/redis-server.pid@'?/usr/local/redis/etc/redis.conf

????????sed?-i?"s@logfile.*@logfile /usr/local/redis/var/redis.log@"?/usr/local/redis/etc/redis.conf

????????sed?-i?"s@^dir.*@dir /usr/local/redis/var@"?/usr/local/redis/etc/redis.conf

????????sed?-i?'s/daemonize no/daemonize yes/g'?/usr/local/redis/etc/redis.conf

????????sed?-i?'s/^# bind 127.0.0.1/bind 0.0.0.0/g'?/usr/local/redis/etc/redis.conf

?#################################################################################################

}

???

install_redis

[root@redis-master src]# chmod 755 install_redis.sh

[root@redis-master src]# sh -x install_redis.sh

2)redis啟停腳本(三個節(jié)點(diǎn)上都要操作)

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

[root@redis-master src]# vim /etc/init.d/redis-server

#!/bin/bash

#

# redis - this script starts and stops the redis-server daemon

#

# chkconfig:?? - 85 15

# description:? Redis is a persistent key-value database

# processname: redis-server

# config:????? /usr/local/redis/etc/redis.conf

# config:????? /etc/sysconfig/redis

# pidfile:???? /usr/local/redis/var/redis-server.pid

??

# Source function library.

.?/etc/rc.d/init.d/functions

??

# Source networking configuration.

.?/etc/sysconfig/network

??

# Check that networking is up.

[?"$NETWORKING"?=?"no"?] &&?exit?0

??

redis="/usr/local/redis/bin/redis-server"

prog=$(basename?$redis)

??

REDIS_CONF_FILE="/usr/local/redis/etc/redis.conf"

??

[ -f?/etc/sysconfig/redis?] && .?/etc/sysconfig/redis

??

lockfile=/var/lock/subsys/redis-server

??

start() {

????[ -x $redis ] ||?exit?5

????[ -f $REDIS_CONF_FILE ] ||?exit?6

????echo?-n $"Starting $prog: "

????daemon $redis $REDIS_CONF_FILE

????retval=$?

????echo

????[ $retval -eq?0 ] &&?touch?$lockfile

????return?$retval

}

??

stop() {

????echo?-n $"Stopping $prog: "

????killproc $prog

????retval=$?

????echo

????[ $retval -eq?0 ] &&?rm?-f $lockfile

????return?$retval

}

??

restart() {

????stop

????start

}

??

reload() {

????echo?-n $"Reloading $prog: "

????killproc $redis -HUP

????RETVAL=$?

????echo

}

??

force_reload() {

????restart

}

??

rh_status() {

????status $prog

}

??

rh_status_q() {

????rh_status >/dev/null?2>&1

}

??

case?"$1"?in

????start)

????????rh_status_q &&?exit?0

????????$1

????????;;

????stop)

????????rh_status_q ||?exit?0

????????$1

????????;;

????restart)

????????$1

????????;;

????reload)

????????rh_status_q ||?exit?7

????????$1

????????;;

????force-reload)

????????force_reload

????????;;

????status)

????????rh_status

????????;;

????condrestart|try-restart)

????????rh_status_q ||?exit?0

????????????;;

????*)

????????echo?$"Usage: $0 {start|stop|status|restart|condrestart|try-restart|reload|force-reload}"

????????exit?2

esac

執(zhí)行權(quán)限

[root@redis-master src]# chmod 755 /etc/init.d/redis-server

3)redis-sentinel啟停腳本示例(三個節(jié)點(diǎn)上都要操作)

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

[root@redis-master src]# vim /etc/init.d/redis-sentinel

#!/bin/bash

#

# redis-sentinel - this script starts and stops the redis-server sentinel daemon

#

# chkconfig:?? - 85 15

# description:? Redis sentinel

# processname: redis-server

# config:????? /usr/local/redis/etc/sentinel.conf

# config:????? /etc/sysconfig/redis

# pidfile:???? /usr/local/redis/var/redis-sentinel.pid

??

# Source function library.

.?/etc/rc.d/init.d/functions

??

# Source networking configuration.

.?/etc/sysconfig/network

??

# Check that networking is up.

[?"$NETWORKING"?=?"no"?] &&?exit?0

??

redis="/usr/local/redis/bin/redis-sentinel"

prog=$(basename?$redis)

??

REDIS_CONF_FILE="/usr/local/redis/etc/sentinel.conf"

??

[ -f?/etc/sysconfig/redis?] && .?/etc/sysconfig/redis

??

lockfile=/var/lock/subsys/redis-sentinel

??

start() {

????[ -x $redis ] ||?exit?5

????[ -f $REDIS_CONF_FILE ] ||?exit?6

????echo?-n $"Starting $prog: "

????daemon $redis $REDIS_CONF_FILE --sentinel

????retval=$?

????echo

????[ $retval -eq?0 ] &&?touch?$lockfile

????return?$retval

}

??

stop() {

????echo?-n $"Stopping $prog: "

????killproc $prog

????retval=$?

????echo

????[ $retval -eq?0 ] &&?rm?-f $lockfile

????return?$retval

}

??

restart() {

????stop

????start

}

??

reload() {

????echo?-n $"Reloading $prog: "

????killproc $redis -HUP

????RETVAL=$?

????echo

}

??

force_reload() {

????restart

}

??

rh_status() {

????status $prog

}

??

rh_status_q() {

????rh_status >/dev/null?2>&1

}

??

case?"$1"?in

????start)

????????rh_status_q &&?exit?0

????????$1

????????;;

????stop)

????????rh_status_q ||?exit?0

????????$1

????????;;

????restart)

????????$1

????????;;

????reload)

????????rh_status_q ||?exit?7

????????$1

????????;;

????force-reload)

????????force_reload

????????;;

????status)

????????rh_status

????????;;

????condrestart|try-restart)

????????rh_status_q ||?exit?0

????????????;;

????*)

????????echo?$"Usage: $0 {start|stop|status|restart|condrestart|try-restart|reload|force-reload}"

????????exit?2

esac

執(zhí)行權(quán)限:

[root@redis-master src]# chmod 755 /etc/init.d/redis-sentinel

4)配置redis.conf

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

a)編輯redis-master主節(jié)點(diǎn)的redis.conf文件

[root@redis-master src]# mkdir -p /usr/local/redis/data/redis

[root@redis-master src]# cp /usr/local/redis/etc/redis.conf /usr/local/redis/etc/redis.conf.bak

[root@redis-master src]# vim /usr/local/redis/etc/redis.conf

bind 0.0.0.0

daemonize?yes

pidfile?"/usr/local/redis/var/redis-server.pid"

port 6379

tcp-backlog 128

timeout 0

tcp-keepalive 0

loglevel notice

logfile?"/usr/local/redis/var/redis-server.log"

databases 16

save 900 1??

save 300 10

save 60 10000

stop-writes-on-bgsave-error?yes

rdbcompression?yes

rdbchecksum?yes

dbfilename dump.rdb

dir?"/usr/local/redis/data/redis"

#masterauth "20180408"??????????????????????? #master設(shè)置密碼保護(hù),即slave連接master時的密碼

#requirepass "20180408"?????????????????????? #設(shè)置Redis連接密碼,如果配置了連接密碼,客戶端在連接Redis時需要通過AUTH 命令提供密碼,默認(rèn)關(guān)閉

slave-serve-stale-data?yes

slave-read-only?yes

repl-diskless-sync?no

repl-diskless-sync-delay 5

repl-disable-tcp-nodelay no

slave-priority 100

appendonly?yes????????????????????????????????#打開aof持久化

appendfilename?"appendonly.aof"

appendfsync everysec??????????????????????????# 每秒一次aof寫

no-appendfsync-on-rewrite no

auto-aof-rewrite-percentage 100

auto-aof-rewrite-min-size 64mb

aof-load-truncated?yes

lua-time-limit 5000

slowlog-log-slower-than 10000

slowlog-max-len 128

latency-monitor-threshold 0

notify-keyspace-events?""

hash-max-ziplist-entries 512

hash-max-ziplist-value 64

list-max-ziplist-entries 512

list-max-ziplist-value 64

set-max-intset-entries 512

zset-max-ziplist-entries 128

zset-max-ziplist-value 64

hll-sparse-max-bytes 3000

activerehashing?yes

client-output-buffer-limit normal 0 0 0

client-output-buffer-limit slave 256mb 64mb 60

client-output-buffer-limit pubsub 32mb 8mb 60

hz 10

aof-rewrite-incremental-fsync?yes

注意:

上面配置中masterauth和requirepass表示設(shè)置密碼保護(hù),如果設(shè)置了密碼,則連接redis后需要執(zhí)行"auth 20180408"密碼后才能操作其他命令。這里我不設(shè)置密碼。

b)編輯redis-slave01和redis-slave02兩個從節(jié)點(diǎn)的redis.conf文件

[root@redis-slave01 src]# mkdir -p /usr/local/redis/data/redis

[root@redis-slave01 src]# cp /usr/local/redis/etc/redis.conf /usr/local/redis/etc/redis.conf.bak

[root@redis-slave01 src]# vim /usr/local/redis/etc/redis.conf

bind 0.0.0.0

daemonize?yes

pidfile?"/usr/local/redis/var/redis-server.pid"

port 6379

tcp-backlog 128

timeout 0

tcp-keepalive 0

loglevel notice

logfile?"/usr/local/redis/var/redis-server.log"

databases 16

save 900 1??

save 300 10

save 60 10000

stop-writes-on-bgsave-error?yes

rdbcompression?yes

rdbchecksum?yes

dbfilename dump.rdb

dir?"/usr/local/redis/data/redis"

#masterauth "20180408"???????????????

#requirepass "20180408"??????

slaveof 192.168.10.202 6379??????????????????#相對主redis配置,多添加了此行???????

slave-serve-stale-data?yes

slave-read-only?yes??????????????????????????#從節(jié)點(diǎn)只讀,不能寫入

repl-diskless-sync?no

repl-diskless-sync-delay 5

repl-disable-tcp-nodelay no

slave-priority 100

appendonly?yes???????????????????????????

appendfilename?"appendonly.aof"

appendfsync everysec????????????????????????

no-appendfsync-on-rewrite no

auto-aof-rewrite-percentage 100

auto-aof-rewrite-min-size 64mb

aof-load-truncated?yes

lua-time-limit 5000

slowlog-log-slower-than 10000

slowlog-max-len 128

latency-monitor-threshold 0

notify-keyspace-events?""

hash-max-ziplist-entries 512

hash-max-ziplist-value 64

list-max-ziplist-entries 512

list-max-ziplist-value 64

set-max-intset-entries 512

zset-max-ziplist-entries 128

zset-max-ziplist-value 64

hll-sparse-max-bytes 3000

activerehashing?yes

client-output-buffer-limit normal 0 0 0

client-output-buffer-limit slave 256mb 64mb 60

client-output-buffer-limit pubsub 32mb 8mb 60

hz 10

aof-rewrite-incremental-fsync?yes

5)配置sentinel.conf(這個默認(rèn)沒有,需要自建)。三個節(jié)點(diǎn)的配置一樣。

1

2

3

4

5

6

7

8

9

10

11

12

[root@redis-master src]# mkdir -p /usr/local/redis/data/sentinel

[root@redis-master src]# vim /usr/local/redis/etc/sentinel.conf

port 26379

pidfile?"/usr/local/redis/var/redis-sentinel.pid"

dir?"/usr/local/redis/data/sentinel"

daemonize?yes

protected-mode no

logfile?"/usr/local/redis/var/redis-sentinel.log"

sentinel monitor redisMaster 192.168.10.202 6379 2?

sentinel down-after-milliseconds redisMaster 10000?

sentinel parallel-syncs redisMaster 1

sentinel failover-timeout redisMaster 60000?

6)啟動redis和sentinel(三個節(jié)點(diǎn)都要操作)

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

設(shè)置系統(tǒng)變量

[root@redis-slave02 src]# vim /etc/profile

.......

export?PATH=$PATH:/usr/local/redis/bin

[root@redis-slave02 src]# source /etc/profile

啟動redis和sentinel

[root@redis-master src]# /etc/init.d/redis-server start

Starting redis-server:???????????????????????????????????? [? OK? ]

[root@redis-master src]# /etc/init.d/redis-sentinel start

Starting redis-sentinel:?????????????????????????????????? [? OK? ]

[root@redis-master src]# lsof -i:6379

COMMAND??? PID USER?? FD?? TYPE? DEVICE SIZE/OFF?NODE NAME

redis-ser 2297 root??? 6u? IPv4 7819726????? 0t0? TCP *:6379 (LISTEN)

redis-ser 2297 root??? 8u? IPv4 7819778????? 0t0? TCP 192.168.10.202:6379->192.168.10.202:56226 (ESTABLISHED)

redis-ser 2297 root??? 9u? IPv4 7819780????? 0t0? TCP 192.168.10.202:6379->192.168.10.202:56228 (ESTABLISHED)

redis-sen 2315 root??? 8u? IPv4 7819777????? 0t0? TCP 192.168.10.202:56226->192.168.10.202:6379 (ESTABLISHED)

redis-sen 2315 root??? 9u? IPv4 7819779????? 0t0? TCP 192.168.10.202:56228->192.168.10.202:6379 (ESTABLISHED)

[root@redis-master src]# lsof -i:26379

COMMAND??? PID USER?? FD?? TYPE? DEVICE SIZE/OFF?NODE NAME

redis-sen 2315 root??? 6u? IPv6 7819772????? 0t0? TCP *:26379 (LISTEN)

redis-sen 2315 root??? 7u? IPv4 7819773????? 0t0? TCP *:26379 (LISTEN)

7)查看redis和sentinel信息

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

1)查看三個節(jié)點(diǎn)的redis的主從關(guān)系

[root@redis-master src]# redis-cli -h 192.168.10.202 -p 6379 INFO|grep role

role:master

[root@redis-master src]# redis-cli -h 192.168.10.203 -p 6379 INFO|grep role

role:slave

[root@redis-master src]# redis-cli -h 192.168.10.205 -p 6379 INFO|grep role

role:slave

??

從上面信息可以看出,192.168.10.202是master,192.168.10.203和192.168.10.205是slave

??

2)查看Master節(jié)點(diǎn)信息:

[root@redis-master src]# redis-cli -h 192.168.10.202 -p 6379 info Replication

# Replication

role:master

connected_slaves:2

slave0:ip=192.168.10.203,port=6379,state=online,offset=61480,lag=0

slave1:ip=192.168.10.205,port=6379,state=online,offset=61480,lag=0

master_replid:96a1fd63d0ad9e7903851a82382e32d690667bcc

master_replid2:0000000000000000000000000000000000000000

master_repl_offset:61626

second_repl_offset:-1

repl_backlog_active:1

repl_backlog_size:1048576

repl_backlog_first_byte_offset:1

repl_backlog_histlen:61626

??

從上面信息看出,此時192.168.10.202的角色為master,有兩個slave(203和205)被連接成功.

??

此時打開master的sentinel.conf,在末尾可看到如下自動寫入的內(nèi)容:

[root@redis-master src]# cat /usr/local/redis/etc/sentinel.conf

port 26379

pidfile?"/usr/local/redis/var/redis-sentinel.pid"

dir?"/usr/local/redis/data/sentinel"

daemonize?yes

protected-mode no

logfile?"/usr/local/redis/var/redis-sentinel.log"

sentinel myid c165761901b5ea3cd2d622bbf13f4c99eb73c1bc

sentinel monitor redisMaster 192.168.10.202 6379 2

sentinel down-after-milliseconds redisMaster 10000

sentinel failover-timeout redisMaster 60000

# Generated by CONFIG REWRITE

sentinel config-epoch redisMaster 0

sentinel leader-epoch redisMaster 0

sentinel known-slave redisMaster 192.168.10.203 6379

sentinel known-slave redisMaster 192.168.10.205 6379

sentinel known-sentinel redisMaster 192.168.10.205 26379 cc25d5f0e37803e888732d63deae3761c9f91e1d

sentinel known-sentinel redisMaster 192.168.10.203 26379 e1505ffc65f787871febfde2f27b762f70cddd71

sentinel current-epoch 0

??

[root@redis-master ~]# redis-cli -h 192.168.10.205 -p 26379 info Sentinel

# Sentinel

sentinel_masters:1

sentinel_tilt:0

sentinel_running_scripts:0

sentinel_scripts_queue_length:0

sentinel_simulate_failure_flags:0

master0:name=redisMaster,status=ok,address=192.168.10.202:6379,slaves=2,sentinels=3

3)查看Slave節(jié)點(diǎn)信息:

??

先查看salve01節(jié)點(diǎn)信息

[root@redis-slave01 src]# redis-cli -h 192.168.10.203 -p 6379 info Replication

# Replication

role:slave

master_host:192.168.10.202

master_port:6379

master_link_status:up

master_last_io_seconds_ago:0

master_sync_in_progress:0

slave_repl_offset:96744

slave_priority:100

slave_read_only:1

connected_slaves:0

master_replid:96a1fd63d0ad9e7903851a82382e32d690667bcc

master_replid2:0000000000000000000000000000000000000000

master_repl_offset:96744

second_repl_offset:-1

repl_backlog_active:1

repl_backlog_size:1048576

repl_backlog_first_byte_offset:1

repl_backlog_histlen:96744

??

此時192.168.10.203的角色為slave,它們所屬的master為220。

此時打開slave的sentinel.conf,在末尾可看到如下自動寫入的內(nèi)容:

[root@redis-slave01 src]# cat /usr/local/redis/etc/sentinel.conf

port 26379

pidfile?"/usr/local/redis/var/redis-sentinel.pid"

dir?"/usr/local/redis/data/sentinel"

daemonize?yes

protected-mode no

logfile?"/usr/local/redis/var/redis-sentinel.log"

sentinel myid e1505ffc65f787871febfde2f27b762f70cddd71

sentinel monitor redisMaster 192.168.10.202 6379 2

sentinel down-after-milliseconds redisMaster 10000

sentinel failover-timeout redisMaster 60000

# Generated by CONFIG REWRITE

sentinel config-epoch redisMaster 0

sentinel leader-epoch redisMaster 0

sentinel known-slave redisMaster 192.168.10.203 6379

sentinel known-slave redisMaster 192.168.10.205 6379

sentinel known-sentinel redisMaster 192.168.10.205 26379 cc25d5f0e37803e888732d63deae3761c9f91e1d

sentinel known-sentinel redisMaster 192.168.10.202 26379 c165761901b5ea3cd2d622bbf13f4c99eb73c1bc

sentinel current-epoch 0

[root@redis-slave01 ~]# redis-cli -h 192.168.10.203 -p 26379 info Sentinel

# Sentinel

sentinel_masters:1

sentinel_tilt:0

sentinel_running_scripts:0

sentinel_scripts_queue_length:0

sentinel_simulate_failure_flags:0

master0:name=redisMaster,status=ok,address=192.168.10.202:6379,slaves=2,sentinels=3

同樣查看slave02節(jié)點(diǎn)的信息

[root@redis-slave02 src]# redis-cli -h 192.168.10.205 -p 6379 info Replication

# Replication

role:slave

master_host:192.168.10.202

master_port:6379

master_link_status:up

master_last_io_seconds_ago:0

master_sync_in_progress:0

slave_repl_offset:99678

slave_priority:100

slave_read_only:1

connected_slaves:0

master_replid:96a1fd63d0ad9e7903851a82382e32d690667bcc

master_replid2:0000000000000000000000000000000000000000

master_repl_offset:99678

second_repl_offset:-1

repl_backlog_active:1

repl_backlog_size:1048576

repl_backlog_first_byte_offset:170

repl_backlog_histlen:99509

??

[root@redis-slave02 src]# cat /usr/local/redis/etc/sentinel.conf

port 26379

pidfile?"/usr/local/redis/var/redis-sentinel.pid"

dir?"/usr/local/redis/data/sentinel"

daemonize?yes

protected-mode no

logfile?"/usr/local/redis/var/redis-sentinel.log"

sentinel myid cc25d5f0e37803e888732d63deae3761c9f91e1d

sentinel monitor redisMaster 192.168.10.202 6379 2

sentinel down-after-milliseconds redisMaster 10000

sentinel failover-timeout redisMaster 60000

# Generated by CONFIG REWRITE

sentinel config-epoch redisMaster 0

sentinel leader-epoch redisMaster 0

sentinel known-slave redisMaster 192.168.10.205 6379

sentinel known-slave redisMaster 192.168.10.203 6379

sentinel known-sentinel redisMaster 192.168.10.203 26379 e1505ffc65f787871febfde2f27b762f70cddd71

sentinel known-sentinel redisMaster 192.168.10.202 26379 c165761901b5ea3cd2d622bbf13f4c99eb73c1bc

sentinel current-epoch 0

[root@redis-slave02 ~]# redis-cli -h 192.168.10.205 -p 26379 info Sentinel

# Sentinel

sentinel_masters:1

sentinel_tilt:0

sentinel_running_scripts:0

sentinel_scripts_queue_length:0

sentinel_simulate_failure_flags:0

master0:name=redisMaster,status=ok,address=192.168.10.202:6379,slaves=2,sentinels=3

8)客戶端寫入測試數(shù)據(jù)

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

客戶端連接master節(jié)點(diǎn),寫入一條數(shù)據(jù)

[root@redis-master src]# redis-cli? -h 192.168.10.202 -p 6379

192.168.10.202:6379>?set?name kevin;

OK

192.168.10.202:6379> get name;

"kevin";

然后客戶端再連接任意slave節(jié)點(diǎn),通過get獲取上面的那條數(shù)據(jù)

[root@redis-master src]# redis-cli? -h 192.168.10.203 -p 6379

192.168.10.203:6379> get name

"kevin;"

192.168.10.203:6379>?set?name grace;

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

192.168.10.203:6379>

[root@redis-master src]# redis-cli? -h 192.168.10.205 -p 6379

192.168.10.205:6379> get name

"kevin;"

192.168.10.205:6379>?set?name grace;

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

192.168.10.205:6379>

由上面測試信息可知,master節(jié)點(diǎn)可以寫入,可以讀取;而slave節(jié)點(diǎn)默認(rèn)只能讀取,不能寫入!這就實(shí)現(xiàn)了主從復(fù)制,讀寫分離了!

9)模擬故障(通過sentinel實(shí)現(xiàn)主從切換,sentinel也要部署多臺,即集群模式,防止單臺sentinel掛掉情況)

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172

173

174

175

176

177

178

179

180

181

182

183

184

185

186

187

188

189

190

191

192

193

194

195

196

197

198

199

1)關(guān)掉任意一個slave節(jié)點(diǎn)(比如關(guān)閉掉slave01節(jié)點(diǎn)),所有節(jié)點(diǎn)的sentinel都可以檢測到,出現(xiàn)如下示例信息:

[root@redis-master src]# redis-cli? -h 192.168.10.203 -p 6379

192.168.10.203:6379> get name

"kevin;"

192.168.10.203:6379>?set?name grace;

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

192.168.10.203:6379>?shutdown?????????????????????????????

not connected>

說明:shutdown命令表示關(guān)閉redis

從上可看出203被sentinel檢測到已處于關(guān)閉狀態(tài),此時再來查看剩余節(jié)點(diǎn)的主從信息,它們的角色不會發(fā)生變化,只是master上的connected_slaves變?yōu)榱?。

[root@redis-master src]# redis-cli? -h 192.168.10.202 -p 6379 info replication

# Replication

role:master

connected_slaves:1

slave0:ip=192.168.10.205,port=6379,state=online,offset=219376,lag=1

master_replid:96a1fd63d0ad9e7903851a82382e32d690667bcc

master_replid2:0000000000000000000000000000000000000000

master_repl_offset:219376

second_repl_offset:-1

repl_backlog_active:1

repl_backlog_size:1048576

repl_backlog_first_byte_offset:1

repl_backlog_histlen:219376

查看sentinel日志(任意節(jié)點(diǎn)上查看),發(fā)現(xiàn)203節(jié)點(diǎn)已經(jīng)進(jìn)入"+sdown"狀態(tài)

[root@redis-master src]# tail -f /usr/local/redis/var/redis-sentinel.log

2315:X 08 May 18:49:51.429 * Increased maximum number of?open?files to 10032 (it was originally?set?to 1024).

2315:X 08 May 18:49:51.431 * Running mode=sentinel, port=26379.

2315:X 08 May 18:49:51.431?# WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128.

2315:X 08 May 18:49:51.463?# Sentinel ID is c165761901b5ea3cd2d622bbf13f4c99eb73c1bc

2315:X 08 May 18:49:51.463?# +monitor master redisMaster 192.168.10.202 6379 quorum 2

2315:X 08 May 18:50:11.544 * +slave slave 192.168.10.203:6379 192.168.10.203 6379 @ redisMaster 192.168.10.202 6379

2315:X 08 May 18:50:11.574 * +slave slave 192.168.10.205:6379 192.168.10.205 6379 @ redisMaster 192.168.10.202 6379

2315:X 08 May 18:50:15.088 * +sentinel sentinel e1505ffc65f787871febfde2f27b762f70cddd71 192.168.10.203 26379 @ redisMaster 192.168.10.202 6379

2315:X 08 May 18:50:16.075 * +sentinel sentinel cc25d5f0e37803e888732d63deae3761c9f91e1d 192.168.10.205 26379 @ redisMaster 192.168.10.202 6379

2315:X 08 May 19:06:07.669?# +sdown slave 192.168.10.203:6379 192.168.10.203 6379 @ redisMaster 192.168.10.202 6379

然后重啟上面被關(guān)閉的slave節(jié)點(diǎn)(即192.168.10.203),所有節(jié)點(diǎn)的sentinel都可以檢測到,可看出221又被sentinel檢測到已處于可用狀態(tài),此時再來查看節(jié)點(diǎn)的主從信息,

它們的角色仍然不會發(fā)生變化,master上的connected_slaves又變?yōu)榱?

[root@redis-slave01 src]# /etc/init.d/redis-server restart

Stopping redis-server:???????????????????????????????????? [FAILED]

Starting redis-server:???????????????????????????????????? [? OK? ]

[root@redis-slave01 src]# /etc/init.d/redis-server restart

Stopping redis-server:???????????????????????????????????? [? OK? ]

Starting redis-server:???????????????????????????????????? [? OK? ]

[root@redis-master src]# redis-cli? -h 192.168.10.202 -p 6379 info replication

# Replication

role:master

connected_slaves:2

slave0:ip=192.168.10.205,port=6379,state=online,offset=268216,lag=0

slave1:ip=192.168.10.203,port=6379,state=online,offset=268070,lag=1

master_replid:96a1fd63d0ad9e7903851a82382e32d690667bcc

master_replid2:0000000000000000000000000000000000000000

master_repl_offset:268216

second_repl_offset:-1

repl_backlog_active:1

repl_backlog_size:1048576

repl_backlog_first_byte_offset:1

repl_backlog_histlen:268216

查看sentinel日志(任意節(jié)點(diǎn)上查看),發(fā)現(xiàn)203節(jié)點(diǎn)已經(jīng)進(jìn)入"-sdown"狀態(tài)

[root@redis-master src]# tail -f /usr/local/redis/var/redis-sentinel.log

2315:X 08 May 18:49:51.429 * Increased maximum number of?open?files to 10032 (it was originally?set?to 1024).

2315:X 08 May 18:49:51.431 * Running mode=sentinel, port=26379.

2315:X 08 May 18:49:51.431?# WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128.

2315:X 08 May 18:49:51.463?# Sentinel ID is c165761901b5ea3cd2d622bbf13f4c99eb73c1bc

2315:X 08 May 18:49:51.463?# +monitor master redisMaster 192.168.10.202 6379 quorum 2

2315:X 08 May 18:50:11.544 * +slave slave 192.168.10.203:6379 192.168.10.203 6379 @ redisMaster 192.168.10.202 6379

2315:X 08 May 18:50:11.574 * +slave slave 192.168.10.205:6379 192.168.10.205 6379 @ redisMaster 192.168.10.202 6379

2315:X 08 May 18:50:15.088 * +sentinel sentinel e1505ffc65f787871febfde2f27b762f70cddd71 192.168.10.203 26379 @ redisMaster 192.168.10.202 6379

2315:X 08 May 18:50:16.075 * +sentinel sentinel cc25d5f0e37803e888732d63deae3761c9f91e1d 192.168.10.205 26379 @ redisMaster 192.168.10.202 6379

2315:X 08 May 19:06:07.669?# +sdown slave 192.168.10.203:6379 192.168.10.203 6379 @ redisMaster 192.168.10.202 6379

2315:X 08 May 19:10:14.965 * +reboot slave 192.168.10.203:6379 192.168.10.203 6379 @ redisMaster 192.168.10.202 6379

2315:X 08 May 19:10:15.020?# -sdown slave 192.168.10.203:6379 192.168.10.203 6379 @ redisMaster 192.168.10.202 6379

=======================================================================================================

2)關(guān)掉master節(jié)點(diǎn)(即192.168.10.202),待所有節(jié)點(diǎn)的sentinel都檢測到后(稍等一會,2-3秒鐘時間),再來查看兩個Slave節(jié)點(diǎn)的主從信息,發(fā)現(xiàn)其中一個節(jié)點(diǎn)的角色通過選舉后會成為

master節(jié)點(diǎn)了!

[root@redis-master src]# redis-cli? -h 192.168.10.202 -p 6379

192.168.10.202:6379>?shutdown

not connected>

查看sentinel日志(任意節(jié)點(diǎn)上查看),發(fā)現(xiàn)202節(jié)點(diǎn)已經(jīng)進(jìn)入"+sdown"狀態(tài)

[root@redis-master src]# tail -f /usr/local/redis/var/redis-sentinel.log

2315:X 08 May 19:17:03.722?# +failover-state-reconf-slaves master redisMaster 192.168.10.202 6379

2315:X 08 May 19:17:03.760 * +slave-reconf-sent slave 192.168.10.203:6379 192.168.10.203 6379 @ redisMaster 192.168.10.202 6379

2315:X 08 May 19:17:04.015 * +slave-reconf-inprog slave 192.168.10.203:6379 192.168.10.203 6379 @ redisMaster 192.168.10.202 6379

2315:X 08 May 19:17:04.459?# -odown master redisMaster 192.168.10.202 6379

2315:X 08 May 19:17:05.047 * +slave-reconf-done?slave 192.168.10.203:6379 192.168.10.203 6379 @ redisMaster 192.168.10.202 6379

2315:X 08 May 19:17:05.131?# +failover-end master redisMaster 192.168.10.202 6379

2315:X 08 May 19:17:05.131?# +switch-master redisMaster 192.168.10.202 6379 192.168.10.205 6379

2315:X 08 May 19:17:05.131 * +slave slave 192.168.10.203:6379 192.168.10.203 6379 @ redisMaster 192.168.10.205 6379

2315:X 08 May 19:17:05.131 * +slave slave 192.168.10.202:6379 192.168.10.202 6379 @ redisMaster 192.168.10.205 6379

2315:X 08 May 19:17:15.170?# +sdown slave 192.168.10.202:6379 192.168.10.202 6379 @ redisMaster 192.168.10.205 6379

[root@redis-slave01 src]# redis-cli -h 192.168.10.203 -p 6379 INFO|grep role

role:slave

[root@redis-slave01 src]# redis-cli -h 192.168.10.205 -p 6379 INFO|grep role?????

role:master

[root@redis-slave01 src]# redis-cli? -h 192.168.10.205 -p 6379 info replication

# Replication

role:master

connected_slaves:1

slave0:ip=192.168.10.203,port=6379,state=online,offset=348860,lag=1

master_replid:a51f87958cea0b1e8fe2c83542ca6cebace53bf7

master_replid2:96a1fd63d0ad9e7903851a82382e32d690667bcc

master_repl_offset:349152

second_repl_offset:342824

repl_backlog_active:1

repl_backlog_size:1048576

repl_backlog_first_byte_offset:170

repl_backlog_histlen:348983

[root@redis-slave01 src]# redis-cli? -h 192.168.10.203 -p 6379 info replication

# Replication

role:slave

master_host:192.168.10.205

master_port:6379

master_link_status:up

master_last_io_seconds_ago:0

master_sync_in_progress:0

slave_repl_offset:347546

slave_priority:100

slave_read_only:1

connected_slaves:0

master_replid:a51f87958cea0b1e8fe2c83542ca6cebace53bf7

master_replid2:96a1fd63d0ad9e7903851a82382e32d690667bcc

master_repl_offset:347546

second_repl_offset:342824

repl_backlog_active:1

repl_backlog_size:1048576

repl_backlog_first_byte_offset:283207

repl_backlog_histlen:64340

由上可知,當(dāng)master節(jié)點(diǎn)(即192.168.10.202)的redis關(guān)閉后,slave02節(jié)點(diǎn)(即192.168.10.205)變成了新的master節(jié)點(diǎn),而slave01(即192.168.10.203)成為

了slave02的從節(jié)點(diǎn)!

192.168.10.205節(jié)點(diǎn)此時被選舉為master,此時打開的205節(jié)點(diǎn)的redis.conf文件,slaveof配置項(xiàng)已被自動刪除了。

而203從節(jié)點(diǎn)的redis.conf文件中slaveof配置項(xiàng)的值被自動修改為192.168.10.205 6379。

[root@redis-slave02 src]# cat /usr/local/redis/etc/redis.conf|grep slaveof

[root@redis-slave01 src]# cat /usr/local/redis/etc/redis.conf|grep slaveof

slaveof 192.168.10.205 6379

在這個新master上(即192.168.10.205)執(zhí)行諸如set這樣的寫入操作將被成功執(zhí)行

[root@redis-slave01 src]# redis-cli? -h 192.168.10.205 -p 6379

192.168.10.205:6379>?set?name beijing;

OK

[root@redis-master src]# redis-cli? -h 192.168.10.203 -p 6379

192.168.10.203:6379> get name

"beijing;"

192.168.10.203:6379>?set?name tianjin;

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

192.168.10.203:6379>

重啟192.168.10.202節(jié)點(diǎn)的redis,待所有節(jié)點(diǎn)的sentinel都檢測到后,再來查看所有節(jié)點(diǎn)的主從信息,此時192.168.10.205節(jié)點(diǎn)的master角色不會被重新?lián)屨?#xff0c;

而192.168.10.202節(jié)點(diǎn)的角色會從原來的master變?yōu)榱藄lave。

[root@redis-master src]# /etc/init.d/redis-server restart

Stopping redis-server:???????????????????????????????????? [FAILED]

Starting redis-server:???????????????????????????????????? [? OK? ]

[root@redis-master src]# /etc/init.d/redis-server restart

Stopping redis-server:???????????????????????????????????? [? OK? ]

Starting redis-server:???????????????????????????????????? [? OK? ]

[root@redis-master src]# redis-cli -h 192.168.10.202 -p 6379 INFO|grep role

role:slave

[root@redis-master src]# redis-cli -h 192.168.10.203 -p 6379 INFO|grep role

role:slave

[root@redis-master src]# redis-cli -h 192.168.10.205 -p 6379 INFO|grep role

role:master

[root@redis-master src]# redis-cli? -h 192.168.10.205 -p 6379 info replication

# Replication

role:master

connected_slaves:2

slave0:ip=192.168.10.203,port=6379,state=online,offset=545410,lag=1

slave1:ip=192.168.10.202,port=6379,state=online,offset=545410,lag=1

master_replid:a51f87958cea0b1e8fe2c83542ca6cebace53bf7

master_replid2:96a1fd63d0ad9e7903851a82382e32d690667bcc

master_repl_offset:545556

second_repl_offset:342824

repl_backlog_active:1

repl_backlog_size:1048576

repl_backlog_first_byte_offset:170

repl_backlog_histlen:545387

[root@redis-master src]# redis-cli? -h 192.168.10.202 -p 6379

192.168.10.202:6379> get name

"beijing;"

此時登錄192.168.10.202節(jié)點(diǎn)的redis,執(zhí)行"get name"得到的值為beijing,而不是原來的kevin,因?yàn)?92.168.10.202節(jié)點(diǎn)的redis重啟后會自動從新的master中同步

數(shù)據(jù)。此時打開192.168.10.202節(jié)點(diǎn)的redis.conf文件,會在末尾找到如下信息:

[root@redis-master src]# cat /usr/local/redis/etc/redis.conf|grep slaveof

slaveof 192.168.10.205 6379

到此,已經(jīng)驗(yàn)證出了redis sentinel可以自行實(shí)現(xiàn)主從的故障切換了!

10)客戶端如何連接redis sentinel?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

客戶端配置連接的是sentinel信息,比如連接sentinel.conf文件中定義的master名稱。在sentinel監(jiān)聽時,當(dāng)master節(jié)點(diǎn)掛了,它會在slave節(jié)點(diǎn)中自動選舉出新

的master節(jié)點(diǎn),而當(dāng)掛了的老master節(jié)點(diǎn)重新恢復(fù)后就會成為新的slave節(jié)點(diǎn)。對于客戶端來說,redis主從切換后它不需要修改連接配置。

下面列出幾個客戶端連接redis sentinel的例子

1)java客戶端在jedis中使用redis sentinel哨兵方式連接

<?xml version="1.0"?encoding="UTF-8"?>

"http://www.springframework.org/schema/beans">

????id="jedisPoolConfig"?class="redis.clients.jedis.JedisPoolConfig">

?????????"maxTotal"?value="1000"/>

?????????"maxIdle"?value="10"/>

?????????"minIdle"?value="1"/>

?????????"maxWaitMillis"?value="30000"/>

?????????"testOnBorrow"?value="true"/>

?????????"testOnReturn"?value="true"/>

?????????"testWhileIdle"?value="true"/>

????</bean>

????id="cacheService"?class="sentinel.CacheServiceImpl"?destroy-method="destroy">

????????"jedisSentinlePool">

????????????"redis.clients.jedis.JedisSentinelPool">

?????????????????"0"?value="mymaster"?/>

?????????????????"1">

?????????????????????<set>

?????????????????????????192.168.10.202:26379</value>

?????????????????????????192.168.10.203:26379</value>

?????????????????????????192.168.10.205:26379</value>

?????????????????????</set>

?????????????????</constructor-arg>

?????????????????"2"?ref="jedisPoolConfig"?/>

????????????</bean>

????????</property>

????</bean>

</beans>

2)python連接redis sentinel集群(需要安裝python redis客戶端,即執(zhí)行"pip install redis")

#!/usr/bin/env python

# -*- coding:utf-8 -*-

import?redis

from redis.sentinel?import?Sentinel

# 連接哨兵服務(wù)器(主機(jī)名也可以用域名)

sentinel = Sentinel([('192.168.10.202', 26379),

?????????????????????('192.168.10.203', 26379),

?????????????????????('192.168.10.205', 26379)

?????????????],

????????????????????socket_timeout=0.5)

# 獲取主服務(wù)器地址

master = sentinel.discover_master('mymaster')

print(master)

# 輸出:('192.168.10.202', 26379)

# 獲取從服務(wù)器地址

slave = sentinel.discover_slaves('mymaster')

print(slave)

# 輸出:[('192.168.10.203', 26379), ('192.168.10.205', 26379), ('172.31.0.5', 26379)]

# 獲取主服務(wù)器進(jìn)行寫入

master = sentinel.master_for('mymaster', socket_timeout=0.5, password='redis_auth_pass', db=15)

w_ret = master.set('foo',?'bar')

# 輸出:True

# # 獲取從服務(wù)器進(jìn)行讀取(默認(rèn)是round-roubin)

slave = sentinel.slave_for('mymaster', socket_timeout=0.5, password='redis_auth_pass', db=15)

r_ret = slave.get('foo')

print(r_ret)

# # 輸出:bar

3)Java客戶端連接Redis(單sentinel).

下面例子中好的redisMaster和20180408是在sentinel.conf中定義的master名稱和連接密碼

package com.hiifit.cloudplatform.gaia.test;

import?java.util.HashSet;

import?java.util.Set;

import?redis.clients.jedis.Jedis;

import?redis.clients.jedis.JedisSentinelPool;

public class RedisSentinelTest {

????@SuppressWarnings("deprecation")

????public static void main(String[] args) {

????????Set sentinels = new HashSet();

????????String hostAndPort1 =?"192.168.10.205:26379";

????????sentinels.add(hostAndPort1);

????????String clusterName =?"redisMaster";

????????String password =?"20180408";

????????JedisSentinelPool redisSentinelJedisPool = new JedisSentinelPool(clusterName,sentinels,password);

????????Jedis jedis = null;

????????try {

????????????jedis = redisSentinelJedisPool.getResource();

????????????jedis.set("key",?"value");

????????} catch (Exception e) {

????????????e.printStackTrace();

????????} finally {

????????????redisSentinelJedisPool.returnBrokenResource(jedis);

????????}

????????redisSentinelJedisPool.close();

????}

}

總結(jié)

以上是生活随笔為你收集整理的Redis哨兵模式(sentinel)学习总结及部署记录(主从复制、读写分离、主从切换)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。

中文视频在线播放 | 精品视频免费久久久看 | 欧美性护士 | av在线小说 | 中文在线字幕免费观看 | 亚洲欧美乱综合图片区小说区 | 色婷婷在线视频 | 日本公妇在线观看高清 | 日韩成人免费在线观看 | 国产精品乱看 | 亚洲jizzjizz日本少妇 | 九九视频这里只有精品 | 91传媒91久久久 | 免费看片网站91 | 欧美一区二区日韩一区二区 | 日韩黄色网络 | 激情电影影院 | 中文字幕中文字幕在线中文字幕三区 | 九九精品久久久 | 日本中文在线 | 婷婷激情综合五月天 | 国产色婷婷精品综合在线手机播放 | 亚洲一区视频在线播放 | 日韩爱爱片 | 亚洲精品国产综合99久久夜夜嗨 | 久久理论影院 | 五月婷婷丁香六月 | 九色视频网站 | 国产精品一区二区你懂的 | 亚洲伊人天堂 | 久久久久国产精品一区二区 | www免费在线观看 | 中文字幕中文字幕中文字幕 | 丁香视频全集免费观看 | 成人午夜在线观看 | 在线之家免费在线观看电影 | 五月天综合色激情 | 国产夫妻自拍av | 狠狠干婷婷 | 美女久久久久久 | 久久不射影院 | 亚洲理论在线观看电影 | 色婷婷播放 | www最近高清中文国语在线观看 | 欧美色图亚洲图片 | 国产xxxxx在线观看 | 日韩免费在线观看网站 | 精品国产乱码久久久久久浪潮 | 欧美综合在线观看 | 国产精品入口传媒 | 久久免费看a级毛毛片 | 97视频免费播放 | 日韩电影中文字幕在线观看 | 日韩精品视频一二三 | 青青草国产成人99久久 | 精品在线观看一区二区三区 | 黄色资源在线观看 | 日本精品中文字幕 | 免费看精品久久片 | 玖玖精品在线 | 黄色一区二区在线观看 | 成人av教育| 国产 日韩 在线 亚洲 字幕 中文 | 久久这里有| 91精品视频免费在线观看 | 亚洲精品动漫在线 | 精品人妖videos欧美人妖 | 日韩欧美在线观看一区二区三区 | 一区二区三区 亚洲 | av高清一区 | 欧美日韩首页 | 婷婷色婷婷 | 免费在线观看av网址 | 精品国产伦一区二区三区 | 色视频网址 | 中文字幕国内精品 | 成人av日韩 | 亚洲综合小说 | 五月天久久| 国产呻吟在线 | 日韩色在线 | 亚洲成人网av| 9久久精品 | 欧美成人亚洲 | 免费看国产精品 | 草久在线观看视频 | 欧美久久久久久久久久久 | 国产日韩精品欧美 | av在线色| 精品一区二区免费 | 中文字幕在线专区 | 五月天久久综合 | 亚洲成 人精品 | 久久人人插 | 岛国精品一区二区 | 日韩在线一二三区 | 欧美日本在线观看视频 | 在线观看视频国产 | 午夜在线免费观看 | www.激情五月.com | 国产成人久久77777精品 | av在线网站大全 | 99精品视频在线免费观看 | 亚洲成人麻豆 | 天天射天天干天天操 | 成人av片免费看 | 免费91在线观看 | 在线观看av中文字幕 | 99精品一区二区 | 精品久久免费看 | 国产日本亚洲高清 | 久久99影院 | 缴情综合网五月天 | 欧美日韩在线观看一区二区三区 | 麻豆国产精品va在线观看不卡 | 久久草| 日韩在线无 | 操操操日日 | 亚洲国产精品一区二区久久,亚洲午夜 | 干 操 插 | www.夜色.com | .国产精品成人自产拍在线观看6 | 天天干人人插 | 91精品久久久久久 | 天天操天 | 特级西西444www大精品视频免费看 | 日韩精品视频在线免费观看 | 五月天婷亚洲天综合网精品偷 | 美女视频黄免费的 | 国产精品黄网站在线观看 | 国产精品久久久久久久毛片 | 精品国精品自拍自在线 | 久久久国产一区二区三区四区小说 | 日韩精品国产一区 | 亚洲精品资源在线 | 狠色在线 | 国产美女网站视频 | 国产一区二区三区黄 | 人人干人人超 | 一区二区三区四区精品 | 国产精品黑丝在线观看 | 国产免费人成xvideos视频 | 久久九九国产精品 | 99r在线观看 | 人人爽人人插 | 国产一区视频免费在线观看 | 久久爱资源网 | 99精品国产成人一区二区 | 在线观看中文字幕 | 国产乱码精品一区二区三区介绍 | 天天射狠狠干 | 国产精品美女久久久久久免费 | 激情视频综合网 | 色婷婷久久久综合中文字幕 | 欧美日韩二区三区 | 国产高清av免费在线观看 | 精品人人爽 | 91久久一区二区 | 久久免费视频一区 | 最近在线中文字幕 | 麻豆av一区二区三区在线观看 | www国产在线 | 精品在线观看一区二区 | 国产九色视频在线观看 | 久久精品www人人爽人人 | 亚洲久草在线视频 | 91香蕉视频黄色 | 天堂在线视频免费观看 | 亚洲三级av| 日韩理论片中文字幕 | 亚洲欧洲精品一区二区 | 欧美日韩免费网站 | 在线亚洲天堂网 | 国产在线欧美在线 | www.在线观看视频 | 蜜桃av人人夜夜澡人人爽 | 婷婷丁香视频 | 亚洲国产高清在线 | 综合久久网站 | 国产99一区 | 亚洲观看黄色网 | av资源在线看 | 日本精品久久久久中文字幕 | 国产精品99久久久久久有的能看 | 日韩成人免费在线观看 | 亚洲一二区视频 | 日本黄色一级电影 | 在线观看黄色小视频 | 亚洲精品av中文字幕在线在线 | 97网在线观看 | 亚洲免费观看在线视频 | 免费网站黄 | 国产一区精品在线观看 | 中文字幕在线观看第一区 | 91日韩精品视频 | 天天夜操 | 中文字幕精品一区久久久久 | 日韩大片免费在线观看 | 一级黄网 | 99久久婷婷国产综合精品 | 三级黄色在线 | 日韩免费在线网站 | 国产色a在线观看 | 天天射天天干天天操 | 色综合久久88色综合天天免费 | 久久久三级视频 | 国产123区在线观看 国产精品麻豆91 | 黄色在线成人 | 午夜精品一二三区 | 狂野欧美激情性xxxx欧美 | 日韩国产高清在线 | 日韩免费电影网 | 国产玖玖精品视频 | 久久av免费电影 | 91热视频 | 亚洲国产69| 97综合网| 国产精品 国产精品 | 91精品在线视频观看 | 99视频在线精品国自产拍免费观看 | 国产不卡在线播放 | 999久久久免费精品国产 | 午夜久久福利视频 | 91香蕉视频| 最新日本中文字幕 | 激情在线五月天 | 国产精品免费视频一区二区 | 色婷婷丁香 | 91亚洲精品久久久蜜桃网站 | 精品福利网 | 99超碰在线播放 | 日韩免费不卡视频 | 日韩一级电影在线观看 | 亚洲精品乱码久久久久v最新版 | 亚洲电影影音先锋 | 日韩美女一级片 | 免费看一级黄色大全 | 国产特黄色片 | 成年人视频在线 | 国产精品一区二区中文字幕 | 九九九热 | 国产精品毛片久久蜜 | 国产区精品视频 | 91久久久国产精品 | 99热在线国产精品 | 人人看人人爱 | 国产人在线成免费视频 | 国产成人精品a | 99热这里只有精品国产首页 | 在线视频区 | 91九色国产蝌蚪 | 亚洲精品玖玖玖av在线看 | 最新免费中文字幕 | 久久免费99精品久久久久久 | 人人爱人人射 | 欧美日韩国产亚洲乱码字幕 | 国产精品黑丝在线观看 | 亚洲va在线va天堂 | 在线国产中文字幕 | 久久久影院官网 | 黄色小说18 | 啪嗒啪嗒免费观看完整版 | 日本中文乱码卡一卡二新区 | 国产精品2区 | 日本在线中文在线 | 久久久黄视频 | 欧美成人精品三级在线观看播放 | 久久爱影视i | 麻豆系列在线观看 | 狠狠躁夜夜av| 一级免费观看 | 国产色视频网站 | 欧美性生活免费看 | 久久精品伊人 | 久久久久久久久久国产精品 | 成人久久18免费网站图片 | 精品一二三四五区 | 免费国产在线精品 | 夜夜躁狠狠躁日日躁视频黑人 | 久久婷婷一区 | 91理论片午午伦夜理片久久 | 亚州人成在线播放 | 夜夜操综合网 | .精品久久久麻豆国产精品 亚洲va欧美 | 在线国产一区二区 | 精品少妇一区二区三区在线 | 伊人宗合网 | 成人小视频在线观看免费 | 91麻豆精品国产自产在线游戏 | 激情五月开心 | 日韩欧美一区二区三区在线 | 国产精品亚州 | 日本特黄一级片 | 18性欧美xxxⅹ性满足 | 天天色天天射天天干 | 久久久国产影院 | 天天在线操 | 激情网色 | 天天射网站 | 久久久久国产一区二区三区 | 看片网站黄 | 黄色在线观看www | 久久久亚洲麻豆日韩精品一区三区 | 久草久 | 日韩理论 | 成人黄色毛片 | 亚洲精品久久久久久国 | 四虎永久网站 | 久久久久亚洲最大xxxx | 免费久久久久久久 | 麻花豆传媒一二三产区 | 天天拍夜夜拍 | 在线免费视频你懂的 | 午夜精品一区二区三区在线 | av片免费播放 | 国产精品久久久免费看 | av黄色国产 | 久久影视网 | 国产一级二级三级视频 | 欧美精品二 | 黄色a一级片| 日韩视频免费在线观看 | 日日干激情五月 | 一区二区精品在线观看 | 亚洲美女视频在线观看 | 91尤物在线播放 | 五月婷视频 | 五月天综合网 | 国产999视频 | 97在线精品 | 国产精品日韩在线播放 | 最新成人av | 欧美日韩国产精品一区二区 | 国产人成一区二区三区影院 | 欧美激情综合色综合啪啪五月 | 超碰九九 | 五月天亚洲综合小说网 | 91久久久久久久一区二区 | 久久久午夜精品理论片中文字幕 | 国产精品久久麻豆 | 久草在线视频国产 | 成年人看片| 日韩成人黄色 | 久久久久久久久久久免费视频 | 国精产品999国精产品视频 | 国产一级在线 | 欧美aaaxxxx做受视频 | 狠狠色丁香婷婷综合久小说久 | 亚洲视频免费在线观看 | 亚州成人av在线 | 在线视频 影院 | 色综合中文字幕 | 99re久久资源最新地址 | 日韩69视频 | 色婷婷 亚洲 | 成人在线视频免费观看 | 日韩成人高清在线 | 免费看的黄色网 | 青青啪 | 欧美日韩高清在线观看 | 久久91久久久久麻豆精品 | 97自拍超碰 | 欧美极品少妇xbxb性爽爽视频 | 国产精品久久麻豆 | 成人免费亚洲 | 五月天久久婷 | 特级a毛片| 99热在线国产精品 | 欧美色图亚洲图片 | 久久成人一区二区 | 久一在线 | 黄色a大片| 九九视频在线播放 | 伊人亚洲综合 | 亚洲一级久久 | 亚州av一区 | 中文字幕国产精品 | 午夜av免费看 | 久久www免费人成看片高清 | 免费网站看v片在线a | 亚洲精品视频在线观看免费视频 | 亚洲国产欧美一区二区三区丁香婷 | 天天摸日日摸人人看 | 亚洲欧美成aⅴ人在线观看 四虎在线观看 | 国产91精品久久久久 | 最新国产精品拍自在线播放 | 日韩精品一区二区久久 | 国产精品一区二区美女视频免费看 | 成人免费在线视频观看 | 成人a视频片观看免费 | 色婷婷国产在线 | 亚洲一级片在线观看 | 亚洲精品777| 日本xxxxav | 91久久电影 | 成人少妇影院yyyy | 久久影院亚洲 | 深夜激情影院 | 欧美激情另类文学 | 欧美大香线蕉线伊人久久 | 亚洲人人射 | 最新av网址大全 | 91精品网站| 正在播放久久 | 免费av观看网站 | 精品特级毛片 | 五月婷婷久 | 亚洲国产福利视频 | 亚洲精品午夜久久久久久久 | 黄色三级网站 | 国产成人久久久77777 | 狠狠干我 | 国产精品久久久久久久久久了 | 97在线观看视频免费 | 亚洲精品美女在线 | 欧美日韩在线观看一区二区 | 国产一卡二卡在线 | 色综合久久久久综合体 | 日韩a在线看 | 久久人人看 | 狠狠88综合久久久久综合网 | 久久夜夜夜 | 色婷婷 亚洲 | 午夜精品99久久免费 | 精品国内自产拍在线观看视频 | 99国产精品一区二区 | 久久伊人婷婷 | 在线视频app | 久99久视频 | 五月花婷婷 | 激情久久综合网 | 91精品久久久久久久91蜜桃 | 国产精品美女在线观看 | h视频日本 | 国产精品毛片一区二区三区 | 国产特级毛片aaaaaa高清 | 午夜久久影院 | 日韩高清在线一区二区 | 久久字幕网 | 亚洲一级在线观看 | 91精品国产99久久久久久红楼 | 夜夜夜夜猛噜噜噜噜噜初音未来 | 国产三级精品三级在线观看 | 一区二区在线不卡 | 在线观看中文字幕网站 | 九九热精品视频在线播放 | 精品久久一二三区 | 日韩一区二区三区高清免费看看 | 一级久久久 | 免费在线观看的av网站 | 日韩中文字幕在线 | 丁香激情五月婷婷 | 国产精品乱码一区二区视频 | av中文在线 | 国产精品女同一区二区三区久久夜 | 日韩av电影免费观看 | 69av久久| 国产高清免费 | 久草亚洲视频 | 日韩特级片 | 女人18毛片a级毛片一区二区 | 91免费在线视频 | www操操| 天天操操操操操 | 成人免费观看大片 | 欧美激情综合五月色丁香小说 | 亚洲免费色 | 青青草华人在线视频 | 99r精品视频在线观看 | 99精品欧美一区二区蜜桃免费 | 黄污网| 国产高清免费在线观看 | 久久精品国产一区二区 | 日韩免费视频一区二区 | 婷婷久久综合九色综合 | 韩国av一区二区三区 | 国产精品美女网站 | 波多野结衣综合网 | 特级毛片网站 | 久久精品国产免费看久久精品 | 国产亚洲婷婷免费 | 美女网站色在线观看 | 久久精品中文字幕 | 怡春院av| 亚洲国产69| 欧美日一级片 | 国精产品999国精产品岳 | avav片| 精品国产一区二区三区四 | 欧美一级看片 | 国产精品第72页 | 美女露久久 | av直接看 | 性色av一区二区三区在线观看 | 成人毛片久久 | 三级在线视频播放 | 亚洲美女免费精品视频在线观看 | 最新国产精品亚洲 | 中文字幕黄色av | 久久中文字幕导航 | 国产一区二区三区午夜 | 亚洲欧美视频在线播放 | 在线va网站 | 日韩中文在线字幕 | 久久精品电影 | 欧洲一区精品 | 国产黄色观看 | 五月天综合色激情 | 一区二区三区 中文字幕 | 欧美尹人| 精品久久久久久国产91 | 国产福利精品一区二区 | 国产一区国产精品 | 美女性爽视频国产免费app | 国内外成人免费在线视频 | 丁香六月av| 色婷婷视频在线观看 | 国产成人免费高清 | 亚洲精品在线一区二区 | 欧美专区日韩专区 | 91在线精品视频 | 国产精品永久 | 国精产品满18岁在线 | 97视频在线免费观看 | 亚洲精品影院在线观看 | 超碰97网站| 91网站在线视频 | www,黄视频 | 欧美另类美少妇69xxxx | 九九九热精品 | 国产精品破处视频 | free. 性欧美.com| 色综合天天爱 | 伊人婷婷久久 | 激情黄色av | 日韩免费视频在线观看 | 国产视频一级 | www.狠狠色.com | 天天天天色综合 | 精品亚洲男同gayvideo网站 | 日韩欧美视频在线免费观看 | 中文字幕之中文字幕 | 精品一区二区在线免费观看 | 国产一级做a爱片久久毛片a | 高清日韩一区二区 | 日韩天天综合 | 热re99久久精品国产66热 | 婷婷丁香花五月天 | 亚洲成人在线免费 | av资源中文字幕 | 探花视频免费在线观看 | 黄av资源 | 精品久久五月天 | 国产99久久精品一区二区300 | 碰超人人| 开心丁香婷婷深爱五月 | 人人射| 成年人在线看视频 | 精品福利视频在线观看 | 丁香婷婷色月天 | 欧美日韩另类在线 | a爱爱视频| 精品伊人久久久 | 亚洲综合成人av | 久久久免费观看视频 | 婷婷久久一区二区三区 | 国产精品免费观看网站 | 99国产成+人+综合+亚洲 欧美 | 色综合欧洲 | 日韩久久久久久久 | 日本高清xxxx | 中文字幕av影院 | 一区二区三区在线免费观看 | 美女在线免费观看视频 | 久久免费视频一区 | 81精品国产乱码久久久久久 | 国产黄大片在线观看 | 中文国产字幕在线观看 | 国产亚洲精品久久久久久久久久 | 国产亚洲精品中文字幕 | 色综合久久久久综合99 | 在线观看涩涩 | 国产日产精品一区二区三区四区 | 在线观看电影av | 激情综合五月天 | 久久精品99久久 | 九九热只有这里有精品 | 欧美日韩免费观看一区=区三区 | 色网av | 99国产精品久久久久老师 | www.狠狠操.com | av电影免费在线看 | 亚洲精品欧洲精品 | 国产在线免费av | 激情综合五月 | 久久国产女人 | 久久久久久麻豆 | 亚洲综合视频在线 | 色99在线 | 91在线你懂的 | 91av视频在线观看免费 | 99久久精品免费看国产麻豆 | 婷婷香蕉 | 91精品国产成人 | 精品久久久久久国产 | 久久99精品国产麻豆宅宅 | 日韩精品无 | 亚洲精品国产视频 | 中文久久精品 | 超碰在线1 | 91成人精品一区在线播放 | 91福利视频网站 | 亚洲欧美国产精品va在线观看 | 成年人在线 | 成年人视频免费在线 | 久久国产精品一区二区三区四区 | 三日本三级少妇三级99 | 亚洲精品乱码久久久久 | 色香网 | 综合在线观看色 | 久久婷婷视频 | www色 | 国产精品久久久久久久久久久不卡 | 色综合久久久久网 | 黄色a大片 | 在线视频免费观看 | 中文字幕亚洲综合久久五月天色无吗'' | 8x成人免费视频 | 国产高清av免费在线观看 | 特级黄录像视频 | 国产精品欧美日韩 | 在线日韩三级 | 日韩免费专区 | 国产无套精品久久久久久 | 91亚洲永久精品 | 字幕网资源站中文字幕 | 免费aa大片| 久久久免费高清视频 | 91最新在线 | 日本中文字幕网 | 99精彩视频在线观看免费 | 欧美91精品| 成人国产精品 | 欧美一区影院 | 中文字幕在线看 | 丝袜精品视频 | 激情五月婷婷丁香 | 91热爆视频 | 国产精品四虎 | 狠狠色噜噜狠狠狠狠 | 国产蜜臀av| 精品久久久久国产免费第一页 | 99视频+国产日韩欧美 | 少妇bbbb搡bbbb搡bbbb | 伊人国产在线播放 | www黄色com | 欧美日产在线观看 | 久草在线视频免赞 | 97av在线| 亚洲免费一级电影 | 欧美成天堂网地址 | 亚洲欧洲日韩在线观看 | 久久99操 | 国产精彩视频一区二区 | 日本黄色a级大片 | 亚洲国内精品 | 久久av黄色 | 亚洲欧美日韩在线一区二区 | 日韩精品久久久久久久电影99爱 | 天天操天天操天天操天天操 | 国产午夜三级 | 中文字幕在线观看你懂的 | 天天干,天天干 | 麻豆精品在线 | 麻豆视频一区 | 亚洲精区二区三区四区麻豆 | 国内精品久久久久久 | 国产91对白在线 | 欧美性色xo影院 | 99久久9| 久久综合9988久久爱 | 曰韩在线 | 中文字幕精品久久 | 日韩成人免费在线观看 | a天堂在线看 | 久久在线影院 | 不卡国产视频 | 成人av视屏 | 久久九九久久精品 | 成人毛片一区二区三区 | 国产二区视频在线 | 日韩欧美视频一区二区 | 三级av黄色 | 青青色影院 | 欧美日韩精 | 在线观看国产v片 | 日韩亚洲国产中文字幕 | 亚洲国产精品视频 | www.久久久.com| 2019天天干天天色 | 亚洲精品国产拍在线 | 成人国产精品久久久久久亚洲 | 久久久久久久av | 中文视频在线看 | 青青河边草免费观看 | 亚洲专区视频在线观看 | 欧美aaaxxxx做受视频 | 天天色天天射天天综合网 | 久久国产精品久久国产精品 | 9999在线视频 | 免费视频久久久久久久 | 久久精品视频网站 | 91视频高清免费 | 黄色成人在线观看 | 香蕉在线播放 | 韩日视频在线 | 国产精品成人久久久久 | 少妇视频在线播放 | 亚洲男模gay裸体gay | 黄色成年 | 午夜精品一区二区三区在线观看 | 综合色影院| 欧美成人性网 | 国产精品亚| 五月婷婷六月丁香在线观看 | 日韩a级黄色 | 99热999| 久久国产精品视频免费看 | 三级a毛片 | 成人久久视频 | 免费视频99| 超碰在线91| 国产精品精品视频 | 久久久久亚洲精品成人网小说 | 日韩在线观看你懂得 | 国产91对白在线播 | 夜夜天天干 | 久久久久久久久亚洲精品 | 成人午夜影院 | 六月丁香在线观看 | 免费性网站 | 国产成人久久久77777 | 国产传媒一区在线 | 久草久草在线 | 国产精品久久三 | 久草com| 久久久电影 | 成人在线免费观看视视频 | 色丁香久久 | 亚洲综合视频网 | 婷婷丁香狠狠爱 | 国产精品123 | 五月视频| 亚洲午夜精品一区 | av成人动漫 | 亚洲国产mv | 久久久精品欧美一区二区免费 | 免费毛片aaaaaa | 国产日产欧美在线观看 | 99精品黄色 | 国产精品一二 | 久久国产免费看 | 黄色小说视频在线 | 日韩中文字幕免费在线播放 | 欧美在线观看视频免费 | 三级性生活视频 | 成人影片免费 | 日韩a级黄色片 | 婷婷婷国产在线视频 | 精品国产一区二区三区不卡 | 午夜视频久久久 | 最新婷婷色 | 在线观看一区二区视频 | 国产成人一区二区三区久久精品 | 国产情侣一区 | 成人网在线免费视频 | 欧美大荫蒂xxx | 国产精品久久久久久久久久久久久久 | 精品主播网红福利资源观看 | 国产一区视频在线观看免费 | 亚洲久久视频 | 久久精品综合视频 | 91视频链接 | 亚洲天堂网站 | 97视频在线免费播放 | 久久久久日本精品一区二区三区 | 成人国产精品免费观看 | 人交video另类hd | 欧美成人xxxxxxxx | 午夜电影中文字幕 | 精品一区免费 | www.在线观看av | 成片视频免费观看 | 一区二区三区在线视频111 | 日日噜噜噜噜夜夜爽亚洲精品 | 在线观看av黄色 | 激情图片qvod| av中文字幕在线看 | 国产成人精品久久久久蜜臀 | av一二三区 | 国产午夜一级毛片 | 麻豆视频入口 | 最新日韩在线观看视频 | 久久久噜噜噜久久久 | 免费看污网站 | 亚洲精品视频免费 | 500部大龄熟乱视频使用方法 | 五月天高清欧美mv | 欧美精品一二三 | 十八岁以下禁止观看的1000个网站 | 中文字幕乱码电影 | 在线免费av播放 | 奇米影视四色8888 | 欧美analxxxx| 欧美日韩不卡在线观看 | 福利网址在线观看 | 手机成人av| 97在线视频观看 | 国产黑丝袜在线 | 欧美91在线| 四虎成人精品 | 一区二区精品在线 | av 一区二区三区四区 | www.夜夜爱 | 日日干av | 日韩黄色在线电影 | 亚洲精品视频网站在线观看 | 91精品国自产拍天天拍 | 日韩免费中文字幕 | 色婷婷导航 | 五月开心色 | 日韩在线观看视频在线 | 欧美一区二区三区在线播放 | 狠狠干电影 | 久久精品国产免费 | 一区二区久久久久 | 在线观看国产91 | 日本超碰在线 | 欧美日本在线观看视频 | 久久国产精品免费一区二区三区 | 国产精品亚洲视频 | 日韩免费电影 | 国产黄在线 | av免费看av | 精品久久免费看 | 色综合天天在线 | 高清av网站| 国产糖心vlog在线观看 | 久久不射电影院 | 国产精品21区| 久久呀| 成人在线播放视频 | 97超碰在线播放 | 国内视频 | 91大神精品视频在线观看 | 国产激情小视频在线观看 | 五月天色丁香 | 99精品视频在线观看视频 | 五月婷婷欧美视频 | 国产不卡一 | 成人av网站在线播放 | 97视频精品 | 久久国产经典 | 久久蜜臀一区二区三区av | 日本天天色| 成人免费xyz网站 | 蜜臀av性久久久久av蜜臀妖精 | 久久成人毛片 | 亚洲作爱 | 天天插狠狠干 | 在线日韩中文 | 国产精品久久9 | 国产午夜精品免费一区二区三区视频 | 国产一卡二卡四卡国 | 国产在线免费观看 | 99久久婷婷国产综合亚洲 | 99精品视频免费看 | 特级大胆西西4444www | 国产精品久久久久久一区二区三区 | 日批在线看 | 久久人人爽人人片 | 久久这里 | 日韩欧美电影在线 | 国产黄色精品网站 | 中文字幕免费 | 狠狠狠操 | 天天综合色网 | 九九热久久久 | 久草精品视频在线看网站免费 | 欧美性色xo影院 | 91亚洲精品久久久蜜桃借种 | 国产在线超碰 | av在线电影网站 | 美女视频黄免费的久久 | av成人免费在线观看 | 天天干 夜夜操 | 日韩av成人 | 日韩av播放在线 | 亚洲无人区小视频 | 国产精品成久久久久 | 黄a在线观看 | 激情久久综合 | 黄色一级在线视频 | 五月婷在线播放 | 五月婷婷伊人网 | 四虎影院在线观看av | 日韩在线视频网 | 国产a国产a国产a | 久久综合久久综合久久 | 一区二区三区韩国免费中文网站 | 国产在线a免费观看 | 久久午夜网 | 国产精品久久一 | 久久天天躁狠狠躁亚洲综合公司 | 欧美成人一区二区 | 日韩欧美视频一区二区 | 综合中文字幕 | 在线免费观看视频一区 | 成人免费一级片 | 精品国产一区二区三区蜜臀 | 久影院 | 久久久久久伊人 | 日韩免费在线播放 | 九九久久成人 | 人人澡人摸人人添学生av | 一区二区三区日韩在线 | 99久热 | 99热在线观看免费 | 99在线免费视频观看 | 国产午夜精品av一区二区 | 992tv又爽又黄的免费视频 | 一区二区三区四区不卡 | 亚洲综合成人专区片 | 玖玖爱免费视频 | 国产呻吟在线 | 99久久精品免费看国产麻豆 | 国产精品久久久久久久久久久久冷 | 亚洲国产小视频在线观看 | 国产视频69 | 国产精品久久久久久久免费大片 | 免费黄色在线网站 | 日韩成人邪恶影片 | 色综合久久久久综合99 | 91视频电影 | sesese图片| 婷婷久久一区 | 成人av片在线观看 | 日本精品午夜 | 99热这里有| 久久五月婷婷丁香社区 | 亚洲日日射| 热re99久久精品国产99热 | 亚洲精品自拍 | 成人cosplay福利网站 | 中日韩在线视频 | 成片免费观看视频大全 | 又黄又爽又刺激视频 | 婷婷在线播放 | 麻豆国产精品永久免费视频 | 免费观看黄色12片一级视频 | 色综合网在线 | 97香蕉超级碰碰久久免费软件 | 91在线精品一区二区 | 91在线视频免费观看 | 99九九免费视频 | 在线免费观看视频a | 亚洲综合狠狠干 | 日韩在线观看第一页 | 在线黄色免费 | 久久99精品热在线观看 | 成人黄色av免费在线观看 | 在线亚洲精品 | av免费在线观看网站 | 丰满少妇在线观看网站 | 欧美日韩国产亚洲乱码字幕 | 国产视频资源在线观看 | 色人久久| 日韩成人一级大片 | 中文字幕免 | 天天射天天爱天天干 | 久久久免费电影 | 色爱区综合激月婷婷 | 黄色免费大片 | 最新中文字幕在线观看视频 | 成年人在线观看视频免费 | 久久不卡国产精品一区二区 | 高清av不卡| 国产午夜麻豆影院在线观看 | 中文字幕精品三级久久久 | 99精品99| 国产精品久久电影网 | 麻豆小视频在线观看 | 激情婷婷综合网 | 麻花豆传媒mv在线观看 | 色欧美日韩 | 亚洲国产97在线精品一区 | wwwav视频 | 免费视频黄 |