2019/03/18

Redis HA Master / Slave + Redis Sentinel on CentOS 7

有鑑於網路上有很多前輩都有寫Redis的介紹,我在此就不寫了XD
不過推薦可以看大陸有很多牛逼得前輩文章寫得不錯

那這次實驗的配置有4台host

  • 1台Redis Sentinel,IP為192.168.126.136 Port 26379
  • 1台Redis Master,IP為192.168.126.133 Port 6379
  • 2台Redis Slave,IP為192.168.126.134 Port 6380和192.168.126.135 Port 6381






配置如下

# Overcommit memory setting 
vi /etc/sysctl.conf
vm.overcommit_memory = 1

# Reboot
reboot


# Edit Redis config
vi /etc/redis.conf


Master(192.168.126.133 6379)
    # Protected mode
    protected-mode yes
    # Bind IP
    bind 192.168.126.133 127.0.0.1
    # Port 6379
    port 6379
    # Daemon
    daemonize yes
    supervised systemd
    # PID
    pidfile "/var/run/redis_6379.pid"
    # Master password
    masterauth "password"
    # Min slave to write
    min-slaves-to-write 1
    # network delay max
    min-slaves-max-lag 10
    # Password
    requirepass "password"


Slave 1(192.168.126.134 6380)
    # Protected mode
    protected-mode yes
    # Bind IP
    bind 192.168.126.134 127.0.0.1
    # Port 6380
    port 6380
    # Daemon
    daemonize yes
    supervised systemd
    # PID
    pidfile "/var/run/redis_6380.pid"
    # Master password
    masterauth "password"
    # Min slave to write
    min-slaves-to-write 1
    # network delay max
    min-slaves-max-lag 10
    # Password
    requirepass "password"
    # Master = 192.168.126.133 6379
    slaveof 192.168.126.133 6379


Slave 2(192.168.126.135)
    # Protected mode
    protected-mode yes
    # Bind IP
    bind 192.168.126.135 127.0.0.1
    # Port 6381
    port 6381
    # Daemon
    daemonize yes
    supervised systemd
    # PID
    pidfile "/var/run/redis_6381.pid"
    # Master密碼
    masterauth "password"
    # Min slave to write
    min-slaves-to-write 1
    # network delay max
    min-slaves-max-lag 10
    # Password
    requirepass "password"
    # Master = 192.168.126.133 6379
    slaveof 192.168.126.133 6379


# Add Redis to firewall
firewall-cmd --add-port=6379/tcp --permanent
firewall-cmd --add-port=6380/tcp --permanent
firewall-cmd --add-port=6381/tcp --permanent
firewall-cmd --reload


# Start Redis
redis-server /etc/redis.conf


# Show Redis replication
redis-cli -h 192.168.126.133 -p 6379 -a password info replication
redis-cli -h 192.168.126.134 -p 6380 -a password info replication
redis-cli -h 192.168.126.135 -p 6381 -a password info replication


# Show log and status
cat /var/log/redis/redis.log


# Edit Redis Sentinel
vi /etc/redis-sentinel.conf


# Bind IP
bind 192.168.126.136 127.0.0.1
# Protected mode
protected-mode yes
# Port 26379
port 26379
# Dir
dir "/tmp"
sentinel myid 784086e6b6db80a7ba2af6a3cefeccb0f4d54978


# Sentinel監視該mymaster Redis如果該服務器失效則需要1個Sentinel則可判定為失效
# Sentinel數量不足則自動故障遷移機制則不會啟動
sentinel monitor mymaster 192.168.126.133 6379 1


# 5秒內Redis沒有回應則是視為Subjectively down(SDOWN)
sentinel down-after-milliseconds mymaster 5000
# 100秒內沒有failover成功就算失敗。
sentinel failover-timeout mymaster 100000
# Redis Sentinel password
sentinel auth-pass mymaster password


# Add Redis Sentinel to firewall
firewall-cmd --add-port=26379/tcp --permanent
firewall-cmd --reload


# Start sentinel
# redis-sentinel /etc/redis-sentinel.conf 
# equals
# redis-server /etc/redis-sentinel.conf  --sentinel
redis-server /etc/redis-sentinel.conf  --sentinel


# Show log and status
cat /var/log/redis/sentinel.log


# Show Redis Sentinel Info
redis-cli -h 192.168.126.136 -p 26379 -a password info Sentinel



Java程式碼:

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPoolConfig;
import redis.clients.jedis.JedisSentinelPool;
import redis.clients.jedis.exceptions.JedisConnectionException;

import java.io.*;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Properties;
import java.util.Set;

public class RedisTest {
    private JedisSentinelPool pool;
    private Jedis jedis;
    private static Properties properties = new Properties();

    static {
        InputStream stream = null;
        final File f = new File("Redis.properties");
        try {
            stream = f.exists() ? new FileInputStream("Redis.properties") : new FileInputStream("src/main/resources/Redis.properties");
            properties.load(stream);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }


    private static final JedisPoolConfig getJedisPoolConfig() {
        final int MAX_ACTIVE = Integer.parseInt(properties.getProperty("redis.pool.maxActive"));
        final int MAX_IDLE = Integer.parseInt(properties.getProperty("redis.pool.maxIdle"));
        final int MIN_IDLE = Integer.parseInt(properties.getProperty("redis.pool.minIdle"));
        final long MAX_WAIT_MILLIS = Long.parseLong(properties.getProperty("redis.pool.maxWaitMillis"));
        final int NUM_TESTS_PER_EVICTION_RUN = Integer.parseInt(properties.getProperty("redis.pool.numTestsPerEvictionRun"));
        final long TIME_BETWEEN_EVICTION_RUNS_MILLIS = Long.parseLong(properties.getProperty("redis.pool.timeBetweenEvictionRunsMillis"));
        final long MIN_EVICTABLE_IDLE_TIME_MILLIS = Long.parseLong(properties.getProperty("redis.pool.timeBetweenEvictionRunsMillis"));
        final long SOFT_MIN_EVICTABLE_IDLE_TIME_MILLIS = Long.parseLong(properties.getProperty("redis.pool.softMinEvictableIdleTimeMillis"));
        final boolean TEST_ON_BORROW = Boolean.parseBoolean(properties.getProperty("redis.pool.testOnBorrow"));
        final boolean TEST_WHILE_IDLE = Boolean.parseBoolean(properties.getProperty("redis.pool.testWhileIdle"));
        final boolean TEST_ON_RETURN = Boolean.parseBoolean(properties.getProperty("redis.pool.testOnReturn"));
        final boolean BLOCK_WHEN_EXHAUSTED = Boolean.parseBoolean(properties.getProperty("redis.pool.blockWhenExhausted"));

        JedisPoolConfig config = new JedisPoolConfig();
        config.setMaxTotal(MAX_ACTIVE);
        config.setMaxIdle(MAX_IDLE);
        config.setMinIdle(MIN_IDLE);
        config.setMaxWaitMillis(MAX_WAIT_MILLIS);
        config.setNumTestsPerEvictionRun(NUM_TESTS_PER_EVICTION_RUN);
        config.setTimeBetweenEvictionRunsMillis(TIME_BETWEEN_EVICTION_RUNS_MILLIS);
        config.setMinEvictableIdleTimeMillis(MIN_EVICTABLE_IDLE_TIME_MILLIS);
        config.setSoftMinEvictableIdleTimeMillis(SOFT_MIN_EVICTABLE_IDLE_TIME_MILLIS);
        config.setTestOnBorrow(TEST_ON_BORROW);
        config.setTestWhileIdle(TEST_WHILE_IDLE);
        config.setTestOnReturn(TEST_ON_RETURN);
        config.setBlockWhenExhausted(BLOCK_WHEN_EXHAUSTED);

        return config;
    }

    public static RedisTest getInstance() {
        return new RedisTest();
    }

    private RedisTest() {
        final String MASTER_NAME = properties.getProperty("redis.masterName");
        final String PASSWORD = properties.getProperty("redis.password", "");
        final Set<String> SENTINELS = new HashSet<String>(Arrays.asList(properties.getProperty("redis.sentinels").toString().split(";")));

        this.pool = new JedisSentinelPool(MASTER_NAME, SENTINELS, getJedisPoolConfig(), PASSWORD);
        try {
            this.jedis = this.pool.getResource();
        }catch (JedisConnectionException ex){
            ex.printStackTrace();
        }
    }

    public String set(String key, String value) {
        return this.jedis.set(key, value);
    }

    public String get(String key) {
        return this.jedis.get(key);
    }

}



Redis.properties:

redis.masterName=mymaster
redis.sentinels=192.168.126.136:26379
redis.password=password
redis.pool.maxActive=128
redis.pool.maxIdle=10
redis.pool.minIdle=1
redis.pool.maxWaitMillis=3000
redis.pool.numTestsPerEvictionRun=50
redis.pool.timeBetweenEvictionRunsMillis=3000
redis.pool.minEvictableIdleTimeMillis=1800000
redis.pool.softMinEvictableIdleTimeMillis=10000
redis.pool.testOnBorrow=true
redis.pool.testWhileIdle=true
redis.pool.testOnReturn=true
redis.pool.blockWhenExhausted=true



Master還是133時將其Master關閉

則Master角色會從133轉移至其中一台的Slave



那也可以從下面的路徑來得知目前服務器的狀況
/var/log/redis/sentinel.log
/var/log/redis/redis.log





參考資料:
https://redislabs.com/redis-features/high-availability
https://redis.io/topics/virtual-memory
https://redis.io/topics/admin
https://www.cnblogs.com/youzhibing/p/8466491.html
https://blog.csdn.net/li_haijiang/article/details/76602826
https://blog.csdn.net/liutingxu1/article/details/17116107
https://blog.csdn.net/wzy0623/article/details/82706614
https://medium.com/androvideo/redis-ha-%E9%85%8D%E7%BD%AE-c82ea641a43d
https://dotblogs.com.tw/supershowwei/2016/02/03/123740
https://www.itread01.com/content/1545470113.html
https://codertw.com/%E8%B3%87%E6%96%99%E5%BA%AB/17596/
https://segmentfault.com/a/1190000002680804