电竞比分网-中国电竞赛事及体育赛事平台

分享

Redis Sentinel主從高可用方案(附Jedis Sentinel教程)

 KILLKISS 2016-07-22

Redis Sentinel主從高可用方案(附Jedis Sentinel教程)

本文介紹一種通過(guò)Jed和Sentinel實(shí)現(xiàn)Redis集群(主從)的高可用方案,該方案需要使用Jedis2.2.2及以上版本(強(qiáng)制),Redis2.8及以上版本(可選,Sentinel最早出現(xiàn)在Redis2.4中,Redis2.8中Sentinel更加穩(wěn)定),

附:
Redis Cluster集群主從方案:http://wosyingjun./blog/2289220
Redis Sentinel主從高可用方案:http://wosyingjun./blog/2289593

一、Sentinel介紹

Sentinel是Redis的高可用性(HA)解決方案,由一個(gè)或多個(gè)Sentinel實(shí)例組成的Sentinel系統(tǒng)可以監(jiān)視任意多個(gè)主服務(wù)器,以及這些主服務(wù)器屬下的所有從服務(wù)器,并在被監(jiān)視的主服務(wù)器進(jìn)行下線狀態(tài)時(shí),自動(dòng)將下線主服務(wù)器屬下的某個(gè)從服務(wù)器升級(jí)為新的主服務(wù)器,然后由新的主服務(wù)器代替已下線的主服務(wù)器繼續(xù)處理命令請(qǐng)求。Redis提供的sentinel(哨兵)機(jī)制,通過(guò)sentinel模式啟動(dòng)redis后,自動(dòng)監(jiān)控master/slave的運(yùn)行狀態(tài),基本原理是:心跳機(jī)制+投票裁決

  • 監(jiān)控(Monitoring): Sentinel 會(huì)不斷地檢查你的主服務(wù)器和從服務(wù)器是否運(yùn)作正常。
  • 提醒(Notification): 當(dāng)被監(jiān)控的某個(gè) Redis 服務(wù)器出現(xiàn)問(wèn)題時(shí), Sentinel 可以通過(guò) API 向管理員或者其他應(yīng)用程序發(fā)送通知。
  • 自動(dòng)故障遷移(Automatic failover): 當(dāng)一個(gè)主服務(wù)器不能正常工作時(shí), Sentinel 會(huì)開(kāi)始一次自動(dòng)故障遷移操作, 它會(huì)將失效主服務(wù)器的其中一個(gè)從服務(wù)器升級(jí)為新的主服務(wù)器, 并讓失效主服務(wù)器的其他從服務(wù)器改為復(fù)制新的主服務(wù)器; 當(dāng)客戶端試圖連接失效的主服務(wù)器時(shí), 集群也會(huì)向客戶端返回新主服務(wù)器的地址, 使得集群可以使用新主服務(wù)器代替失效服務(wù)器。

二、Sentinel的主從原理

   

之前介紹過(guò)為什么Jedis要用2.2.2及以上版本,因?yàn)橹鲝膶?shí)例地址(IP PORT)是不同的,當(dāng)故障發(fā)生進(jìn)行主從切換后,應(yīng)用程序無(wú)法知道新地址,故在Jedis2.2.2中新增了對(duì)Sentinel的支持,應(yīng)用通過(guò)redis.clients.jedis.JedisSentinelPool.getResource()取得的Jedis實(shí)例會(huì)及時(shí)更新到新的主實(shí)例地址。

三、Redis Sentinel配置

這里我采用2個(gè)哨兵,1個(gè)主redis,2個(gè)從redis的方式,配置文件如下:

sentinel_63791.conf 配置:

port 63791
daemonize yes
logfile "/var/log/sentinel_63791.log"
#master-1
sentinel monitor master-1 192.168.78.99 6379 2
sentinel down-after-milliseconds master-1 5000
sentinel failover-timeout master-1 18000
sentinel auth-pass master-1 hundsun@1
sentinel parallel-syncs master-1 1

sentinel_63792.conf 配置:

port 63792
daemonize yes
logfile "/var/log/sentinel_63792.log"
#master-1
sentinel monitor master-1 192.168.78.99 6379 2
sentinel down-after-milliseconds master-1 5000
sentinel failover-timeout master-1 18000
sentinel auth-pass master-1 hundsun@1
sentinel parallel-syncs master-1 1

redis_master_6379.conf 配置:
在原配置文件中作如下修改:

port 6379
daemonize yes
requirepass hundsun@1
masterauth hundsun@1

redis_slave_6380.conf 配置:
在原配置文件中作如下修改:

port 6380
daemonize yes
requirepass hundsun@1
slaveof 192.168.78.99 6379
masterauth hundsun@1

redis_slave_6381.conf 配置:
在原配置文件中作如下修改:

port 6381
daemonize yes
requirepass hundsun@1
slaveof 192.168.78.99 6379
masterauth hundsun@1

按如下順序依次啟動(dòng)服務(wù):

./redis-server ../conf/redis_master_6379.conf
./redis-server ../conf/redis_slave_6381.conf    
./redis-server ../conf/redis_slave_6382.conf    
./redis-sentinel ../conf/sentinel_63791.conf
./redis-sentinel ../conf/sentinel_63792.conf

查看進(jìn)程是否都已經(jīng)啟動(dòng):

查看master的狀態(tài):

查看slave的狀態(tài):

查看sentinel的狀態(tài):

接下來(lái)驗(yàn)證redis sentinel的主從切換:

  • 首先關(guān)閉主redis(6379)服務(wù)(shutdown)。
  • 查看哨兵,發(fā)現(xiàn)端口號(hào)為6380的從服務(wù)變成了主服務(wù),sentinel自動(dòng)完成了故障切換。

  • 啟動(dòng)剛才被shutdown的6379服務(wù)并查看,發(fā)現(xiàn)它變成了從服務(wù)。

三、Jedis Sentinel教程

Maven依賴:

    <dependency>
        <groupId>redis.clients</groupId>
        <artifactId>jedis</artifactId>
        <version>2.8.0</version>
    </dependency>
    <!-- spring-redis -->
    <dependency>
        <groupId>org.springframework.data</groupId>
        <artifactId>spring-data-redis</artifactId>
        <version>1.6.4.RELEASE</version>
    </dependency>

redis的配置文件:

#redis config
redis.pass=hundsun@1
redis.pool.maxTotal=105
redis.pool.maxIdle=10
redis.pool.maxWaitMillis=60000
redis.pool.testOnBorrow=true

sentinel1.ip=192.168.78.99
sentinel1.port=63791

sentinel2.ip=192.168.78.99
sentinel2.port=63792

Spring的配置文件:

<!-- Redis 配置 -->
<bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
    <property name="maxTotal" value="${redis.pool.maxTotal}" />
    <property name="maxIdle" value="${redis.pool.maxIdle}" />
    <property name="maxWaitMillis" value="${redis.pool.maxWaitMillis}" />
    <property name="testOnBorrow" value="${redis.pool.testOnBorrow}" />
</bean>

<bean id="sentinelConfiguration"
    class="org.springframework.data.redis.connection.RedisSentinelConfiguration">
    <property name="master">
        <bean class="org.springframework.data.redis.connection.RedisNode">
            <property name="name" value="master-1"></property>
        </bean>
    </property>
    <property name="sentinels">
        <set>
            <bean class="org.springframework.data.redis.connection.RedisNode">
                <constructor-arg name="host" value="${sentinel1.ip}"></constructor-arg>
                <constructor-arg name="port" value="${sentinel1.port}"></constructor-arg>
            </bean>
            <bean class="org.springframework.data.redis.connection.RedisNode">
                <constructor-arg name="host" value="${sentinel2.ip}"></constructor-arg>
                <constructor-arg name="port" value="${sentinel2.port}"></constructor-arg>
            </bean>
        </set>
    </property>
</bean>

<!-- Jedis ConnectionFactory連接配置 -->
<bean id="jedisConnectionFactory"
    class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
    <property name="password" value="${redis.pass}"></property>
    <property name="poolConfig" >
        <ref bean="jedisPoolConfig"/>
    </property>
    <constructor-arg name="sentinelConfig" ref="sentinelConfiguration"></constructor-arg>
</bean>

<!-- redisTemplate配置,redisTemplate是對(duì)Jedis的對(duì)redis操作的擴(kuò)展,有更多的操作,封裝使操作更便捷 -->
<bean id="redisTemplate" class="org.springframework.data.redis.core.StringRedisTemplate">
    <property name="connectionFactory" ref="jedisConnectionFactory" />
</bean>

代碼中直接用redisTemplate調(diào)用:

    @Override
    public boolean add(final KeyToken tkey) {
        boolean result = redisTemplate.execute(new RedisCallback<Boolean>() {

            @Override
            public Boolean doInRedis(RedisConnection connection) throws DataAccessException {
                RedisSerializer<String> serializer = getRedisSerializer();
                byte[] key = serializer.serialize(tkey.getIndex());
                byte[] name = serializer.serialize(tkey.getExpire_time());
                return connection.setNX(key, name);
            }

        });
        return result;
    }

 

附件:

 

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多