Redis/sentinel/cluster

sentinel:
上一篇提到了主從切換,sentinel的作用是將這個過程自動化,實現高可用。
它的主要功能有以下幾點:

  • 不時地監控redis是否按照預期良好地運行;
  • 如果發現某個redis節點運行出現狀況,能夠通知另外一個進程(例如它的客戶端);
  • 能夠進行自動切換。當一個master節點不可用時,能夠選舉出master的多個slave(如果有超過一個slave的話)中的一個來作為新的master,其它的slave節點會將它所追隨的master的地址改為被提升為master的slave的新地址。

Sentinel本身也支持集群,只使用單個sentinel進程來監控redis集群是不可靠的,當sentinel進程宕掉后,sentinel本身也有單點問題。所以有必要將sentinel集群,這樣有幾個好處:

  • 如果只有一個sentinel進程,如果這個進程運行出錯,或者是網絡堵塞,那么將無法實現redis集群的主備切換(單點問題)。
  • 如果有多個sentinel,redis的客戶端可以隨意地連接任意一個sentinel來獲得關于redis集群中的信息。
  • sentinel集群自身也需要多數機制,也就是2個sentinel進程時,掛掉一個另一個就不可用了。

在默認情況下,Sentinel 使用TCP端口26379(普通 Redis 服務器使用的是 6379)。Sentinel 接受 Redis 協議格式的命令請求, 所以可以使用 redis-cli 或者任何其他 Redis 客戶端來與 Sentinel 進行通訊。

# redis-cli -p 26379
127.0.0.1:26379> ping
PONG

啟動sentinel:
配置文件:

port 26329
sentinel monitor myredis 127.0.0.1 6379 2
sentinel down-after-milliseconds mymaster 60000
sentinel failover-timeout mymaster 180000
sentinel parallel-syncs mymaster 1
sentinel notification-script <master-name> <script-path>
  • 第一行port指定sentinel端口。
  • 第二行monitor配置指示 Sentinel 去監視一個名為 myredis 的主redis實例。Sentinel的配置文件中不必說明此主實例屬下的從實例,因為Sentinel實例可以通過詢問主實例來獲得所有從實例的信息。
    行末2表示將這個主實例判斷為失效至少需要2個 Sentinel 進程的同意,只要同意 Sentinel 的數量不達標,自動failover就不會執行。
  • down-after-milliseconds 選項指定了 Sentinel 認為Redis實例已經失效所需的毫秒數。當實例超過該時間沒有返回PING,或者直接返回錯誤, 那么 Sentinel 將這個實例標記為主觀下線(subjectively down,簡稱 SDOWN )。
  • failover-timeout表示如果在該時間(ms)內未能完成failover操作,則認為該failover失敗。
  • parallel-syncs如果全部從實例一起對新的主實例進行同步, 那么就可能會造成所有從Redis實例在短時間內全部不可用的情況出現。可以通過將這個值設為 1 來保證每次只有一個slave處于不能處理命令請求的狀態。
  • notification-script指定sentinel檢測到該監控的redis實例指向的實例異常時,調用的報警腳本。該配置項可選。

啟動Sentinel:
Sentinel只是一個運行在特殊模式下的 Redis實例, 你可以在啟動一個普通 Redis實例時通過給定 –sentinel 選項來啟動 Redis Sentinel 實例。如:
redis-server /path/to/sentinel.conf --sentinel
當然也可以運行Redis自帶的redis-sentinel,如:
redis-sentinel /path/to/sentinel.conf

Sentinel集群:
1.和其他集群不同,你無須設置其他Sentinel的地址,Sentinel進程可以通過發布與訂閱來自動發現正在監視相同主實例的其他Sentinel。當一個 Sentinel 發現一個新的 Sentinel 時,它會將新的 Sentinel 添加到一個列表中,這個列表保存了 Sentinel 已知的,監視同一個主服務器的所有其他Sentinel。
2.Sentinel集群中的Sentinel不會再同一時刻并發去failover同一個master,第一個進行failover的Sentinel如果失敗了(上文配置的failover-timeout),另外一個才會重新進行failover,以此類推。
3.當Sentinel將一個slave選舉為master并發送SLAVE OF NO ONE后,即使其它的slave還沒針對新master重新配置自己,failover也被認為是成功了。
4.上述過度過程中,若此時重啟old master,則redis集群將處于無master狀態,此時只能手動修改配置文件,然后重新啟動集群.
5.Master-Slave切換后,Sentinel會改寫master,slave和sentinel的conf配置文件。
6.一旦一個Sentinel成功地對一個master進行了failover,它將會把關于master的最新配置通過廣播形式通知其它sentinel,其它的Sentinel則更新對應master的配置。

例子:
啟動redis:

/etc/redis/redis-m.conf
daemonize yes
pidfile /var/run/redis/redis-server-m.pid
port 6379
loglevel notice
logfile /var/log/redis/redis-server-m.log
databases 16
##disable snapshot
save ""
dir /app/redis-m
appendonly yes
appendfilename "appendonly.aof"
##not to be a slave
#slaveof no one

/etc/redis/redis-s1.conf
daemonize yes
pidfile /var/run/redis/redis-server-s1.pid
port 6380
loglevel warning
logfile /var/log/redis/redis-server-s1.log
databases 16
##disable snapshot
save ""
dir /app/redis-s1
appendonly yes
appendfilename "appendonly.aof"
##to be a slave
slaveof 127.0.0.1 6379

/etc/redis/redis-s2.conf
daemonize yes
pidfile /var/run/redis/redis-server-s2.pid
port 6381
loglevel warning
logfile /var/log/redis/redis-server-s2.log
databases 16
##disable snapshot,enable AOF
save ""
dir /app/redis-s2
appendonly yes
appendfilename "appendonly.aof"
##to be a slave
slaveof 127.0.0.1 6379

查看進程實例:

ps -ef | grep redis
root     17560     1  0 09:48 ?        00:00:00 redis-server *:6379                 
root     17572     1  0 09:48 ?        00:00:00 redis-server *:6380                  
root     17609     1  0 09:49 ?        00:00:00 redis-server *:6381

redis-cli
127.0.0.1:6379> info replication
# Replication
role:master
connected_slaves:2
slave0:ip=127.0.0.1,port=6380,state=online,offset=547,lag=0
slave1:ip=127.0.0.1,port=6381,state=online,offset=547,lag=1
master_repl_offset:547
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:2
repl_backlog_histlen:546

啟動sentinel:

sentinel1.conf
port 26379
sentinel monitor myredis 127.0.0.1 6379 2
sentinel down-after-milliseconds myredis 60000
sentinel failover-timeout myredis 180000
sentinel parallel-syncs myredis 1
sentinel notification-script myredis /etc/redis/log-issues.sh

sentinel2.conf
port 26380
sentinel monitor myredis 127.0.0.1 6379 2
sentinel down-after-milliseconds myredis 60000
sentinel failover-timeout myredis 180000
sentinel parallel-syncs myredis 1
sentinel notification-script myredis /etc/redis/log-issues.sh

log-issues.sh
#!/bin/bash
echo "master failovered at `date`" > /root/redis_issues.log

-------啟動--------
nohup redis-sentinel /etc/redis/sentinel1.conf
nohup redis-sentinel /etc/redis/sentinel2.conf

連接:

127.0.0.1:26379> sentinel masters
1)  1) "name"
    2) "myredis"
    3) "ip"
    4) "127.0.0.1"
    5) "port"
    6) "6379"
    7) "runid"
    8) "a88ffd6548e333f3ac895cf1b890ef32a527dd66"
......
   37) "parallel-syncs"
   38) "1"
   39) "notification-script"
   40) "/etc/redis/log-issues.sh"
127.0.0.1:26379> sentinel slaves myredis
1)  1) "name"
    2) "127.0.0.1:6381"
    3) "ip"
    4) "127.0.0.1"
    5) "port"
    6) "6381"
......
2)  1) "name"
    2) "127.0.0.1:6380"
    3) "ip"
    4) "127.0.0.1"
    5) "port"
    6) "6380"

sentinel reset : 重置所有名字和給定模式 pattern 相匹配的主服務器。 pattern 參數是一個 Glob 風格的模式。 重置操作清除該sentinel的所保存的所有狀態信息,并進行一次重新的發現過程。

127.0.0.1:26379> sentinel reset myredis
(integer) 1

sentinel failover :進行一次主動的failover。即在不詢問其他 Sentinel 意見的情況下, 強制開始一次自動故障遷移 。發起故障轉移的 Sentinel 會向其他 Sentinel 發送一個新的配置,其他 Sentinel 會根據這個配置進行相應的更新。

127.0.0.1:26379> sentinel failover myredis
OK

master切換到了localhost:6381上:

127.0.0.1:26379> sentinel get-master-addr-by-name myredis
1) "127.0.0.1"
2) "6381"
## redis-cli中
redis-cli
127.0.0.1:6379> info replication
# Replication
role:slave
master_host:127.0.0.1
master_port:6381
master_link_status:up

客戶端:
sentinel 的 failover 過程對客戶端是透明的,以Java Jedis為例:

public class RedisSentinelClient {

    /**
     * @param args
     */
    public static void main(String[] args) {
        Set sentinels = new HashSet();
        sentinels.add(new HostAndPort("172.30.37.73", 26379).toString());
        sentinels.add(new HostAndPort("172.30.37.73", 26380).toString());
        sentinels.add(new HostAndPort("172.30.37.73", 26381).toString());
        JedisSentinelPool sentinelPool = new JedisSentinelPool("myredis", sentinels);
        System.out.println("Current master: " + sentinelPool.getCurrentHostMaster().toString());
        
        Jedis master = sentinelPool.getResource();
        master.set("username","tom");
        sentinelPool.returnResource(master);
        
        Jedis master2 = sentinelPool.getResource();
        String value = master2.get("username");
        System.out.println("username: " + value);
        master2.close();
        sentinelPool.destroy();
    }

}

cluster:
1.一個 Redis 集群包含 16384 個哈希槽(hash slot),數據庫中的每個鍵都屬于這 16384 個哈希槽的其中一個,集群中的每個節點負責處理一部分哈希槽。 例如一個集群有三個節點,其中:
節點 A 負責處理 0 號至 5500 號哈希槽。
節點 B 負責處理 5501 號至 11000 號哈希槽。
節點 C 負責處理 11001 號至 16384 號哈希槽。
這種將哈希槽分布到不同節點的做法使得用戶可以很容易地向集群中添加或者刪除節點。例如:
如果用戶將新節點 D 添加到集群中, 那么集群只需要將節點 A 、B 、 C 中的某些槽移動到節點 D 就可以了。
如果用戶要從集群中移除節點 A , 那么集群只需要將節點 A 中的所有哈希槽移動到節點 B 和節點 C , 然后再移除空白(不包含任何哈希槽)的節點 A 就可以了。
2.Redis 集群對節點使用了主從復制功能: 集群中的每個節點都有 1 個至 N 個復制品(replica), 其中一個復制品為主節點(master), 而其余的 N-1 個復制品為從節點(slave)。
3.Redis 集群的節點間通過Gossip協議通信。

命令:

//集群(cluster)  
CLUSTER INFO 打印集群的信息  
CLUSTER NODES 列出集群當前已知的所有節點(node),以及這些節點的相關信息。   
//節點(node)  
CLUSTER MEET <ip> <port> 將 ip 和 port 所指定的節點添加到集群當中,讓它成為集群的一份子。  
CLUSTER FORGET <node_id> 從集群中移除 node_id 指定的節點。  
CLUSTER REPLICATE <node_id> 將當前節點設置為 node_id 指定的節點的從節點。  
CLUSTER SAVECONFIG 將節點的配置文件保存到硬盤里面。   
//槽(slot)  
CLUSTER ADDSLOTS <slot> [slot ...] 將一個或多個槽(slot)指派(assign)給當前節點。  
CLUSTER DELSLOTS <slot> [slot ...] 移除一個或多個槽對當前節點的指派。  
CLUSTER FLUSHSLOTS 移除指派給當前節點的所有槽,讓當前節點變成一個沒有指派任何槽的節點。  
CLUSTER SETSLOT <slot> NODE <node_id> 將槽 slot 指派給 node_id 指定的節點,如果槽已經指派給另一個節點,那么先讓另一個節點刪除該槽>,然后再進行指派。  
CLUSTER SETSLOT <slot> MIGRATING <node_id> 將本節點的槽 slot 遷移到 node_id 指定的節點中。  
CLUSTER SETSLOT <slot> IMPORTING <node_id> 從 node_id 指定的節點中導入槽 slot 到本節點。  
CLUSTER SETSLOT <slot> STABLE 取消對槽 slot 的導入(import)或者遷移(migrate)。   
//鍵 (key)  
CLUSTER KEYSLOT <key> 計算鍵 key 應該被放置在哪個槽上。  
CLUSTER COUNTKEYSINSLOT <slot> 返回槽 slot 目前包含的鍵值對數量。  
CLUSTER GETKEYSINSLOT <slot> <count> 返回 count 個 slot 槽中的鍵。 

啟動集群:
Redis Cluster如果數據冗余是1的話,至少要3個Master和3個Slave

192.168.XXX.XXX:7000
192.168.XXX.XXX:7001
192.168.XXX.XXX:7002
192.168.XXX.XXX:7003
192.168.XXX.XXX:7004
192.168.XXX.XXX:7005

配置文件:

bind 192.168.XXX.XXX //不能綁定到192.168.XXX.XXX或localhost,否則指導客戶端重定向時會報”Connection refused”的錯誤。
port 7000
daemonize yes //后臺運行
cluster-enabled yes //開啟Cluster
cluster-require-full-coverage no //默認是yes,只要有結點宕機導致16384個槽沒全被覆蓋,整個集群就全部停止服務,改為no。
cluster-config-file nodes_7000.conf //集群配置文件,這個配置文件不是要我們去配的,而是Redis運行時保存配置的文件,所以我們也不可以修改這個文件。
cluster-node-timeout 5000 //超時多久則認為它宕機了。
appendonly yes
logfile ./redis_7000.log

啟動各節點:redis-server redis_700X.conf
安裝基于ruby的集群工具:

yum install ruby rubygems -y
wget https://rubygems.org/downloads/redis-3.2.1.gem
gem install -l redis-3.2.1.gem
cp redis-3.2.1/src/redis-trib.rb /usr/local/bin/redis-trib //復制集群管理程序到/usr/local/bin

創建集群:

redis-trib create --replicas 1 127.0.0.1:7000 127.0.0.1:7001 127.0.0.1:7002 127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005

--replicas 1 表示我們希望為集群中的每個主節點創建一個從節點,以上命令的意思就是讓 redis-trib 程序創建一個包含三個主節點和三個從節點的集群。

測試:

$ redis-cli -c -p 7000  
redis 127.0.0.1:7000> set foo bar  
-> Redirected to slot [12182] located at 127.0.0.1:7002  
OK  
redis 127.0.0.1:7002> set hello world  
-> Redirected to slot [866] located at 127.0.0.1:7000  
OK  
redis 127.0.0.1:7000> get foo  
-> Redirected to slot [12182] located at 127.0.0.1:7002  
"bar"  
redis 127.0.0.1:7000> get hello  
-> Redirected to slot [866] located at 127.0.0.1:7000  
"world"  

值被放到了相應節點的Hash槽中,redis-cli不斷在700X節點之前重定向跳轉。如果啟動時不加-c選項的話,就能看到以錯誤形式顯示出的MOVED重定向消息。

重新分片:
重分片基本上就是從部分節點移動哈希槽到另外一部分節點上去,像創建集群一樣也是通過使用 redis-trib 工具來完成。

添加新節點:
現在按照相同方法啟動了兩個新實例7010,7011。其中7010為主,7011為從。

//添加主節點
redis-trib.rb add-node 192.168.1.100:7010 192.168.1.100:7000
//查看節點信息,7010被成功添加
redis-cli -c -h 192.168.1.100 -p 7000 cluster nodes
...
...
0d1f9c979684e0bffc8230c7bb6c7c0d37d8a5a9 192.168.1.100:7010 master - 0 1442452249525 0 connected
...
...
//添加從節點
redis-trib.rb add-node --slave --master-id 0d1f9c979684e0bffc8230c7bb6c7c0d37d8a5a9 192.168.1.100:7011 192.168.1.100:7000

遷移Slot:

# redis-trib.rb reshard 192.168.1.100:7000 //下面是主要過程  
How many slots do you want to move (from 1 to 16384)? 1000 //設置slot數1000  
What is the receiving node ID? 03ccad2ba5dd1e062464bc7590400441fafb63f2 //新節點node id  
Please enter all the source node IDs.  
 Type 'all' to use all the nodes as source nodes for the hash slots.  
 Type 'done' once you entered all the source nodes IDs.  
Source node #1:all //表示全部節點重新洗牌  
Do you want to proceed with the proposed reshard plan (yes/no)? yes //確認重新分  

刪除節點:
如果刪除的是主節點,她有slot,需要先去掉分配的slot,然后在刪除主節點

# redis-trib.rb reshard 192.168.10.219:6378 //取消分配的slot,下面是主要過程  
How many slots do you want to move (from 1 to 16384)? 1000 //被刪除master的所有slot數量  
What is the receiving node ID? 5d8ef5a7fbd72ac586bef04fa6de8a88c0671052 //接收6378節點slot的master  
Please enter all the source node IDs.  
 Type 'all' to use all the nodes as source nodes for the hash slots.  
 Type 'done' once you entered all the source nodes IDs.  
Source node #1:03ccad2ba5dd1e062464bc7590400441fafb63f2 //被刪除master的node-id  
Source node #2:done     
Do you want to proceed with the proposed reshard plan (yes/no)? yes //取消slot后,reshard  
//現在節點上已經沒有slot
# redis-trib.rb del-node 192.168.10.219:6378 '03ccad2ba5dd1e062464bc7590400441fafb63f2' 

Jedis客戶端:

Set<HostAndPort> jedisClusterNodes = new HashSet<HostAndPort>();
//Jedis Cluster will attempt to discover cluster nodes automatically
jedisClusterNodes.add(new HostAndPort("127.0.0.1", 7379));
JedisCluster jc = new JedisCluster(jedisClusterNodes);
jc.set("foo", "bar");
String value = jc.get("foo");

要點:
Sentinel是一種自動failover的解決方案。Cluster是一種分片的方案,自帶failover,使用Cluster時不需要再用Sentinel。
Sentinel:
1.Sentinel的作用是將主從切換自動化。
2.Sentinel本身也支持集群,用Sentinel集群來監控redis集群。
3.Sentinel集群自身也需要多數機制。(避免單點問題,至少需要三個)
4.Sentinel只是一個運行在特殊模式下的 Redis實例。

通過給定 –sentinel 選項來啟動 Redis Sentinel 實例。如:
redis-server /path/to/sentinel.conf --sentinel
當然也可以運行Redis自帶的redis-sentinel,如:
redis-sentinel /path/to/sentinel.conf

在默認情況下,Sentinel 使用TCP端口26379。 可以使用 redis-cli 進行通訊 redis-cli -p 26379。
4.Sentinel進程可以通過發布與訂閱來自動發現正在監視相同主實例的其他Sentinel,只需監控相同主實例無須設置其他Sentinel的地址。

#配置文件conf中
sentinel monitor myredis 127.0.0.1 6379 2

5.Sentinel 的 failover 過程對代碼客戶端是透明的。


參考:
http://blog.csdn.net/dc_726/article/details/48552531
http://blog.51yip.com/nosql/1726.html
http://carlosfu.iteye.com/blog/2243483

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,983評論 6 537
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,772評論 3 422
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,947評論 0 381
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,201評論 1 315
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,960評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,350評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,406評論 3 444
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,549評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,104評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,914評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,089評論 1 371
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,647評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,340評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,753評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,007評論 1 289
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,834評論 3 395
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,106評論 2 375

推薦閱讀更多精彩內容