Redis 的 Sentinel 系統用於管理多個 Redis 服務器(instance),Redis 的 Sentinel 爲Redis提供了高可用性。使用哨兵模式創建一個可以不用人爲干預而應對各種故障的Redis部署。
該系統執行以下三個任務:
監控(Monitoring):Sentinel會不斷地檢查你的主服務器和從服務器是否允許正常。
提醒(Notification):當被監控的某個Redis服務器出現問題時,Sentinel可以通過API向管理員或者其他應用程序發送通知。
自動故障遷移(Automatic failover): (1)當一個主服務器不能正常工作時,Sentinel會開始一次自動故障遷移操作,他會將失效主服務器的其中一個從服務器升級爲新的主服務器,並讓失效主服務器的其他從服務器改爲複製新的主服務器;
(2)客戶端試圖連接失敗的主服務器時,集羣也會向客服端返回新主服務器的地址,是的集羣可以使用新主服務器代替失效服務器。
sentinel的分佈式特性
Redis Sentinel 是一個分佈式系統, 你可以在一個架構中運行多個 Sentinel 進程(progress), 這些進程使用流言協議(gossip protocols)來接收關於主服務器是否下線的信息, 並使用投票協議(agreement protocols)來決定是否執行自動故障遷移, 以及選擇哪個從服務器作爲新的主服務器。
單個sentinel進程來監控redis集羣是不可靠的,當sentinel進程宕掉後(sentinel本身也有單點問題,single-point-of-failure)整個集羣系統將無法按照預期的方式運行。所以有必要將sentinel集羣,這樣有幾個好處:
有一些sentinel進程宕掉了,依然可以進行redis集羣的主備切換;
如果只有一個sentinel進程,如果這個進程運行出錯,或者是網絡堵塞,那麼將無法實現redis集羣的主備切換(單點問題);
如果有多個sentinel,redis的客戶端可以隨意地連接任意一個sentinel來獲得關於redis集羣中的信息
一個健壯的部署至少需要三個哨兵實例。
關於redis主從複製的一些特點:
1.一個master可以有多個slave
2.除了多個slave連到相同的master外,slave也可以連接其他slave形成圖狀結構
3.主從複製不會阻塞master。也就是說當一個或多個slave與master進行初次同步數據時,master可以繼續處理client發來的請求。相反slave在初次同步數據時則會阻塞不能處理client的請求。
4.主從複製可以用來提高系統的可伸縮性,我們可以用多個slave 專門用於client的讀請求,比如sort操作可以使用slave來處理。也可以用來做簡單的數據冗餘
5.可以在master禁用數據持久化,只需要註釋掉master 配置文件中的所有save配置,然後只在slave上配置數據持久化。
6.可以用於讀寫分離和容災恢復。
新建sentinel.conf文件
# 這個是Redis6379配置內容,其他文件同理新增然後改一下端口即可,26380
#當前Sentinel服務運行的端口
protected-mode no
port 26381
# 哨兵監聽的主服務器 後面的1表示主機掛掉以後進行投票,只需要1票就可以從機變主機
sentinel monitor mymaster 127.0.0.1 6379 2
# 3s內mymaster無響應,則認爲mymaster宕機了
sentinel down-after-milliseconds mymaster 3000
#如果10秒後,mysater仍沒啓動過來,則啓動failover
sentinel failover-timeout mymaster 10000
# 執行故障轉移時, 最多有1個從服務器同時對新的主服務器進行同步
sentinel parallel-syncs mymaster 1
# 設置哨兵sentinel 連接主從的密碼 注意必須爲主從設置一樣的驗證密碼,沒有的話不用設置
sentinel auth-pass mymaster 123456
在2個文件夾下面都放入此文件,只是端口不同分別啓動2個redis以及2個哨兵,
哨兵啓動命令爲redis-server.exe sentinel.conf --sentinel我們會發現報錯
Creating Server TCP listening socket *:26379: listen: UnKnown error
經過網上查詢得知是沒有配置bind參數的原因,增加bind參數後sentinel.conf文件如下
# 這個是Redis6379配置內容,其他文件同理新增然後改一下端口即可,26380 26381
#當前Sentinel服務運行的端口
port 26381
bind 127.0.0.1
# 哨兵監聽的主服務器
sentinel monitor mymaster 127.0.0.1 6379 2
# 3s內mymaster無響應,則認爲mymaster宕機了
sentinel down-after-milliseconds mymaster 3000
#如果10秒後,mysater仍沒啓動過來,則啓動failover
sentinel failover-timeout mymaster 10000
# 執行故障轉移時, 最多有1個從服務器同時對新的主服務器進行同步
sentinel parallel-syncs mymaster 1
sentinel monitor [master-group-name] [ip] [port] [quorum]
- master-group-name:master名稱(可以自定義)
- ip port : IP地址和端口號
- quorun:票數,Sentinel需要協商同意master是否可到達的數量。
第一行配置指示 Sentinel 去監視一個名爲 mymaster 的主服務器, 這個主服務器的 IP 地址爲 127.0.0.1 , 端口號爲 6379 , 而將這個主服務器判斷爲失效至少需要 2 個 Sentinel 同意 (只要同意 Sentinel 的數量不達標,自動故障遷移就不會執行)。
票數在本文中:redis集羣中有3個sentinel實例,其中master掛掉啦,這裏設置票數爲2,表示有2個sentinel認爲master掛掉啦,才能被認爲是正真的掛掉啦
分別啓動2個redis以及2個哨兵,哨兵啓動命令爲redis-server.exe sentinel.conf --sentinel
Jedis客戶端使用Sentinel
import java.util.HashSet;
import java.util.Set;import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPoolConfig;
import redis.clients.jedis.JedisSentinelPool;public class RedisManagerUtil {
private static JedisSentinelPool pool = null;
// 自帶的哨兵模式 JedisSentinelPool, 並在一開始初始化連接池
static {
try {
JedisPoolConfig config = new JedisPoolConfig();
// 控制一個pool可分配多少個jedis實例,通過pool.getResource()來獲取;
// 如果賦值爲-1,則表示不限制;如果pool已經分配了maxActive個jedis實例,則此時pool的狀態爲exhausted(耗盡)。
config.setMaxTotal(Integer.valueOf(1000));
// 控制一個pool最多有多少個狀態爲idle(空閒的)的jedis實例。
config.setMaxIdle(Integer.valueOf(20));
// 表示當borrow(引入)一個jedis實例時,最大的等待時間,如果超過等待時間,則直接拋出JedisConnectionException;
config.setMinEvictableIdleTimeMillis(Integer.valueOf(-1));
// 在borrow一個jedis實例時,是否提前進行validate操作;如果爲true,則得到的jedis實例均是可用的;
config.setTestOnBorrow(Boolean.valueOf(true));// master名稱和配置文件中配置的要一樣
String master = "mymaster";
//setinel客戶端提供了master自動發現功能
Set<String> sentinels = new HashSet<String>();
sentinels.add("127.0.0.1:26379");
sentinels.add("127.0.0.1:26380");
sentinels.add("127.0.0.1:26381");pool = new JedisSentinelPool(master, sentinels, config);
} catch (Exception e) {
e.printStackTrace();
}
}/**
* 構建redis連接池
*
* @return JedisPool
*/
public static JedisSentinelPool getPool() {
return pool;
}/**
* 返還到連接池
*
* @param pool
* @param redis
*/
public static void returnResource(JedisSentinelPool pool, Jedis redis) {
if (redis != null) {
try {
pool.returnResource(redis);
} catch (Exception e) {
e.printStackTrace();
}
}
}/**
* 測試redis線程池是否正常
* @param args
*/
public static void main(String[] args) {
JedisSentinelPool pool = RedisPoolAPIManager.getPool();
Jedis redis = pool.getResource();
System.out.println("redis = " + redis);if(redis != null){
returnResource(pool,redis);
}
}
}
總結:
Redis-Sentinel是Redis官方推薦的高可用性(HA) 解決方案,Redis-sentinel本身也是一個獨立運行的進程,它能監控多個master-slave集羣,發現master宕機後能進行自動切換。Sentinel可以監視任意多個主服務器(複用),以及主服務器屬下的從服務器,並在被監視的主服務器下線時,自動執行故障轉移操作。
爲了防止sentinel的單點故障,可以對sentinel進行集羣化,創建多個sentinel。