Redis單機搭建主從

Redis單機主從切換部署說明


準備工作

redis.io下載部署包 :redis-3.2.8.tar.gz

新建主從目錄

make -p /usr/local/redis/master/

make -p /usr/local/redis/slave/

分別在兩個目錄下面安裝redis

tar –zxf redis-3.2.8.tar.gz

cd redis-3.2.8

make #編譯

make test #期望全部測試通過

可能出現問題:缺少gcc或者tcl組件,使用命令yum install gcc或者 yum install tcl

修改配置參數

修改master_redis配置

cd /usr/local/redis/master/redis-3.2.8/

vi redis.conf

bind 127.0.0.1 —-> bind 本機IP(綁定地址)

daemonize no —-> daemonize yes(不影響當前會話,啓動過程隱藏,守護進程)

protected-mode yes —> protected-mode no(關閉保護模式,其他服務器可訪問)

修改slave_redis配置

cd /usr/local/redis/slave/redis-3.2.8/

vi redis.conf

bind 127.0.0.1 —-> bind 本機IP(綁定地址)

daemonize no —-> daemonize yes(不影響當前會話,啓動過程隱藏,守護進程)

protected-mode yes —> protected-mode no(關閉保護模式,其他服務器可訪問)

port 6379 —> port 6380(修改端口)

slaveof master_redis所在機器IP 6379

pidfile /var/run/redis_ 6379.pid —-> pidfile /var/run/redis_ 6380.pid

redis以守護進程方式運行時,系統默認會把pid寫入/var/run/redis.pid,可以通過pidfile指 定pid文件

啓動master_ redis和slave_ redis並使用客戶端連接

cd /usr/local/redis/master/redis-3.2.8/src/

./redis-server /usr/local/redis/master/redis-3.2.8/redis.conf(加載配置文件)

./redis-cli -h IP -p 6379 (客戶端連接master_redis)

cd /usr/local/redis/slave/redis-3.2.8/src/

./redis-server /usr/local/redis/slave/redis-3.2.8/redis.conf(加載配置文件)

./redis-cli -h IP -p 6380 (客戶端連接slave_redis)

使用 info 命令查看redis主從信息

master_redis客戶端連接下執行: info replication

顯示:role:master connected_slaves:1

slave_redis客戶端連接下執行: info replication

顯示:role:slave master_ link_ status:up

測試主從複製,讀寫分離

master_redis客戶端連接下執行:set name zhangsan

master_redis客戶端連接下執行:get name 結果: zhangsan

slave_redis客戶端連接下執行:get name 結果: zhangsan

slave_redis客戶端連接下執行:set name lisi

(error)READONLY You can`t write against a read only slave.(slave_redis只讀)

配置主從切換

準備sentinel.conf配置文件

    #守護進程,隱藏啓動,不影響當前session
    daemonize yes  

    #關閉保護模式,類似於防火牆的功能
    protected-mode no   

    #sentinel 端口默認26379
    port  

    #哨兵監控的主redis 的IP 和端口,會自動監控到slave
    #sentinel monitor <master-name> <ip> <redis-port> <quorum>
    #告訴sentinel去監聽地址爲ip:port的一個master,quorum是一個數字,指明當有多少個sentinel認爲一個master失效時,master纔算真正失效         
    sentinel monitor master1 IP 6379 1

    #master被當前sentinel實例認定爲“失效”的間隔時間.
    #sentinel down-after-milliseconds <mastername> <millseconds>  
    #如果當前sentinel與master直接的通訊中(不斷髮送程序包,並接受響應),在指定時間內沒有響應或者響應錯誤代碼,那麼當前sentinel就認爲master失效  
    sentinel down-after-milliseconds master1 5000

    #當failover(故障轉移)開始後,在此時間內仍然沒有觸發任何failover操作,當前sentinel將會認爲此次failover失敗
    sentinel failover-timeout master1 15000

    #當新master產生時,可以同時進行slaveof到新master並進行“SYNC”(同步)的slave個數。(建議使用默認值1)
    #在salve執行salveof與同步時,將會終止客戶端請求。此值較大,意味着“集羣”終止客戶端請求的時間總和和較大.
    #此值較小,意味着“集羣”在故障轉移期間,多個salve向客戶端提供服務時仍然使用舊數據.
    sentinel parallel-syncs master1 1

配置主從切換

ps -ef | grep redis kill掉當前所有redis進程

rm -f /usr/local/redis/master/redis-3.2.8/sentinel.conf

rm -f /usr/local/redis/slave/redis-3.2.8/sentinel.conf

將準備好的sentinel.conf分別放置於對應目錄下面(替換剛剛刪除的兩個conf文件)

cd /usr/local/redis/slave/redis-3.2.8/

vi sentinel.conf 修改 port 26379 —> port 26380

重新啓動主從redis

cd /usr/local/redis/master/redis-3.2.8/src/

./redis-server /usr/local/redis/master/redis-3.2.8/redis.conf

cd /usr/local/redis/slave/redis-3.2.8/src/

./redis-server /usr/local/redis/slave/redis-3.2.8/redis.conf

啓動主從redis的sentinel(哨兵)

cd /usr/local/redis/master/redis-3.2.8/src/

./redis-sentinel /usr/local/redis/master/redis-3.2.8/sentinel.conf

cd /usr/local/redis/slave/redis-3.2.8/src/

./redis-sentinel /usr/local/redis/slave/redis-3.2.8/sentienl.conf

ps -ef | grep redis 此時應該有四個進程(redis主從 + 兩個哨兵)

使用客戶端查看哨兵監控情況

使用客戶端連接兩個sentinel

cd /usr/local/redis/master/redis-3.2.8/src/

./redis-cli -h IP 26379

cd /usr/local/redis/slave/redis-3.2.8/src/

./redis-cli -h IP 26380

使用 info sentinel查看稍定監控詳情,顯示name=master1,status=ok,address=IP:6379(兩個哨兵共同監控master_redis)

測試主從自動切換(具體操作參考上面命令)

kill 掉master_redis服務

然後使用客戶端連接slave_redis

使用info replication 查看slave_ redis連接信息,會發現,slave_ redis已經升級爲master_ redis

再使用客戶端重新連接sentinel,使用info sentinel命令查看兩個哨兵監控信息,會發現監控地址變成了address=IP:6380

重新啓動kill 掉的master_ redis服務,啓動後客戶端連接,使用info replication命令查看,會發現role:slave (重新啓動後自動變成slave_ redis)

Java代碼實現redis主從

public class JedisUtil {


 private final static String REDIS_HOST = "172.20.1.47";
 private final static Integer REDIS_PORT = 6379;
 private final static Integer REDIS_MaxActive = 200;
 private final static Integer REDIS_MaxIdle = 1000;
 private final static Integer REDIS_MaxWait = 512;
 private final static Integer REDIS_ConnTimeout = 2000;
 private final static Integer REDIS_RetryNum = 3;
 private final static String SENTINEL_HOST_1 = "172.20.1.47:26381";
 private final static String SENTINEL_HOST_2 = "172.20.1.47:26380";
 private final static String CLUSTER_NAME = "master1";

/**
 * 私有構造器.
 */
private JedisUtil() {

}

private static Map<String, JedisSentinelPool> maps = new HashMap<String, JedisSentinelPool>();

/**
 * 獲取連接池.
 * 
 * @return 連接池實例
 */
private static JedisSentinelPool getPool() {
    String key = REDIS_HOST + ":" + REDIS_PORT;
    Set<String> sentinels = new HashSet<String>();
    String hostAndPort1 = SENTINEL_HOST_1;
    String hostAndPort2 = SENTINEL_HOST_2;
    sentinels.add(hostAndPort1);
    sentinels.add(hostAndPort2);
    String clusterName = CLUSTER_NAME;

    JedisSentinelPool redisSentinelJedisPool = null;
    if (!maps.containsKey(key)) {
        JedisPoolConfig config = new JedisPoolConfig();
        config.setMaxTotal(REDIS_MaxActive);
        config.setMaxIdle(REDIS_MaxIdle);
        config.setMaxWaitMillis(REDIS_MaxWait);
        config.setTestOnBorrow(true);
        config.setTestOnReturn(true);
        try {
            /**
             * 如果你遇到 java.net.SocketTimeoutException: Read timed out exception的異常信息 請嘗試在構造JedisPool的時候設置自己的超時值. JedisPool默認的超時時間是2秒(單位毫秒)
             */
            redisSentinelJedisPool = new JedisSentinelPool(clusterName, sentinels, config, REDIS_ConnTimeout);

            maps.put(key, redisSentinelJedisPool);
        } catch (Exception e) {
            e.printStackTrace();
        }
    } else {
        redisSentinelJedisPool = maps.get(key);
    }
    return redisSentinelJedisPool;
}

/**
 * 類級的內部類,也就是靜態的成員式內部類,該內部類的實例與外部類的實例 沒有綁定關係,而且只有被調用到時纔會裝載,從而實現了延遲加載。
 */
private static class RedisUtilHolder {
    /**
     * 靜態初始化器,由JVM來保證線程安全
     */
    private static JedisUtil instance = new JedisUtil();
}

/**
 * 當getInstance方法第一次被調用的時候,它第一次讀取 RedisUtilHolder.instance,導致RedisUtilHolder類得到初始化;而這個類在裝載並被初始化的時候,會初始化它的靜
 * 態域,從而創建RedisUtil的實例,由於是靜態的域,因此只會在虛擬機裝載類的時候初始化一次,並由虛擬機來保證它的線程安全性。 這個模式的優勢在於,getInstance方法並沒有被同步,並且只是執行一個域的訪問,因此延遲初始化並沒有增加任何訪問成本。
 */
public static JedisUtil getInstance() {
    return RedisUtilHolder.instance;
}

/**
 * 獲取Redis實例.
 * 
 * @return Redis工具類實例
 */
public Jedis getJedis() {
    Jedis jedis = null;
    int count = 0;
    do {
        try {
            jedis = getPool().getResource();
        } catch (Exception e) {
            e.printStackTrace();
            // 銷燬對象
            if (jedis != null) {

                jedis.close();
            }
        }
        count++;
    } while (jedis == null && count < REDIS_RetryNum);
    return jedis;
}

/**
 * 釋放redis實例到連接池.
 * 
 * @param jedis redis實例
 */
public void closeJedis(Jedis jedis) {
    if (jedis != null) {
        jedis.close();
    }
}

}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章