1. 程式人生 > >Spring整合Redis之哨兵與故障轉移

Spring整合Redis之哨兵與故障轉移

前言

上篇部落格談到了Spring整合redis叢集以及故障轉移演示,會發現redis叢集模式存在一個很明顯的問題:當某個主節點及其所有從節點掛掉,整個叢集因為缺少該節點負責範圍的雜湊槽(hash slot)而宕掉,不具高可用性。redis引入了哨兵(sentinel)模式,能很好解決叢集模式存在的不足。引用官網,redis哨兵系統有三個作用:

  • 監控(Monitoring): Sentinel 會不斷地檢查你的主伺服器和從伺服器是否運作正常。
  • 提醒(Notification): 當被監控的某個 Redis 伺服器出現問題時, Sentinel 可以通過 API 向管理員或者其他應用程式傳送通知。
  • 自動故障遷移(Automatic failover): 當一個主伺服器不能正常工作時, Sentinel 會開始一次自動故障遷移操作, 它會將失效主伺服器的其中一個從伺服器升級為新的主伺服器, 並讓失效主伺服器的其他從伺服器改為複製新的主伺服器; 當客戶端試圖連線失效的主伺服器時, 叢集也會向客戶端返回新主伺服器的地址, 使得叢集可以使用新主伺服器代替失效伺服器。

本文主要講解spring整合redis sentinel及故障轉移示例,以此加深理解。

環境準備

筆者已經預先搭建好Redis Sentinel,環境如下:

  • OS:CentOS release 6.5 (Final)
  • Redis版本:4.0.1
role ip port
Redis Master 192.168.48.31 6379
Redis Slave1 192.168.48.32 6379
Redis Slave0 192.168.48.33 6379
Redis Sentinel 192.168.48.31 26379
Redis Sentinel 192.168.48.32 26379
Redis Sentinel 192.168.48.33 26379

客戶端連線主節點,檢視Redis Master相關資訊

redis-cli -h 192.168.48.31 info Replication

Redis Master相關資訊

Redis Sentinel啟動資訊

Redis Sentinel啟動資訊

客戶端連線sentinel節點,檢視Redis Sentinel相關資訊

redis-cli -h 192.168.48.31 -p 26379 info Sentinel

Redis Sentinel相關資訊

spring整合redis sentinel

step1、maven依賴引入

<dependencies>
    <dependency>
        <groupId>org.springframework.data</groupId>
        <artifactId>spring-data-redis</artifactId>
        <version>1.8.6.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>redis.clients</groupId>
        <artifactId>jedis</artifactId>
        <version>2.9.0</version>
    </dependency>
</dependencies>

step2、配置ConnectionFactory

構造JedisConnectionFactory例項,注入池配置poolConfig和哨兵配置sentinelConfig

<bean id="jedisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
    <constructor-arg name="sentinelConfig" ref="redisSentinelConfiguration"/>
    <constructor-arg name="poolConfig" ref="jedisPoolConfig" />
</bean>

step3、配置JedisPoolConfig

<bean id="jedisPoolConfig"   class="redis.clients.jedis.JedisPoolConfig" >
    <property name="minIdle" value="${redis.minIdle}" />
    <property name="maxIdle" value="${redis.maxIdle}" />
    <property name="maxTotal" value="${redis.maxActive}" />
    <property name="maxWaitMillis" value="${redis.maxWait}" />
    <property name="testOnBorrow" value="${redis.testOnBorrow}" />
    <property name="testOnReturn" value="true" />
    <property name="testWhileIdle" value="true" />
</bean>

配置檔案spring-redis.properties內容

redis.minIdle=50
redis.maxIdle=200
redis.maxActive=100
redis.maxWait=3000
redis.testOnBorrow=true

step4、配置RedisSentinelConfiguration

和叢集配置一樣,sentinel也有兩種配置方式

1.sentinels設值注入

<bean id="redisSentinelConfiguration" class="org.springframework.data.redis.connection.RedisSentinelConfiguration">
    <property name="sentinels">
        <set>
            <bean name="sentinelNode1" class="org.springframework.data.redis.connection.RedisNode">
                <constructor-arg name="host" value="192.168.48.31"/>
                <constructor-arg name="port" value="26379"/>
            </bean>
            <bean name="sentinelNode2" class="org.springframework.data.redis.connection.RedisNode">
                <constructor-arg name="host" value="192.168.48.32"/>
                <constructor-arg name="port" value="26379"/>
            </bean>
            <bean name="sentinelNode3" class="org.springframework.data.redis.connection.RedisNode">
                <constructor-arg name="host" value="192.168.48.33"/>
                <constructor-arg name="port" value="26379"/>
            </bean>
        </set>
    </property>
    <property name="master">
        <bean name="masterNode" class="org.springframework.data.redis.connection.RedisNode">
            <!--必須指定主節點名稱-->
            <property name="name" value="mymaster"/>
            <constructor-arg name="host" value="192.168.48.31"/>
            <constructor-arg name="port" value="6379"/>
        </bean>
    </property>
</bean>

2.propertySource構造注入

<bean id="redisSentinelConfiguration" class="org.springframework.data.redis.connection.RedisSentinelConfiguration">
    <constructor-arg name="propertySource" ref="propertySource"/>
</bean>

<bean name="propertySource" class="org.springframework.core.io.support.ResourcePropertySource">
    <constructor-arg name="location" value="classpath:spring-redis-sentinel.properties" />
</bean>

spring-redis-sentinel.properties內容:

#哨兵監控主redis節點名稱,必選
spring.redis.sentinel.master=mymaster
#哨兵節點
spring.redis.sentinel.nodes=192.168.48.31:26379,192.168.48.32:26379,192.168.48.33:26379

RedisSentinelConfiguration原始碼中這兩個配置屬性常量:

private static final String REDIS_SENTINEL_MASTER_CONFIG_PROPERTY = "spring.redis.sentinel.master";
private static final String REDIS_SENTINEL_NODES_CONFIG_PROPERTY = "spring.redis.sentinel.nodes";

RedisSentinelConfiguration原始碼

step5、配置RedisTemplate

然後配置RedisTemplate,用於redis命令操作

<bean id="stringRedisTemplate" class="org.springframework.data.redis.core.StringRedisTemplate" p:connection-factory-ref="jedisConnectionFactory"/>

step6、測試

package example;

import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;

public class SpringMain {

    public static void main(String[] args) throws InterruptedException {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:spring-redis.xml");
        StringRedisTemplate template = context.getBean(StringRedisTemplate.class);
        ValueOperations<String, String> valueOperations = template.opsForValue();
        valueOperations.set("foo","bar");
        context.destroy();
    }
}

由於主從複製,Master(48.31)、Slave1(48.32)、Slave0(48.33)能檢視到相同的結果:

master的foo值
slave1的foo值
slave2的foo值

到此,spring整合redis sentinel完成,完整配置如下:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:p="http://www.springframework.org/schema/p" xmlns:redis="http://www.springframework.org/schema/redis"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/redis http://www.springframework.org/schema/redis/spring-redis.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

    <context:property-placeholder location="classpath:*.properties" ignore-unresolvable="true" />

    <!-- Jedis ConnectionFactory -->
    <bean id="jedisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
        <constructor-arg name="sentinelConfig" ref="redisSentinelConfiguration"/>
        <constructor-arg name="poolConfig" ref="jedisPoolConfig" />
    </bean>

    <bean id="redisSentinelConfiguration" class="org.springframework.data.redis.connection.RedisSentinelConfiguration">
        <constructor-arg name="propertySource" ref="propertySource"/>
<!--        <property name="sentinels">
            <set>
                <bean name="sentinelNode1" class="org.springframework.data.redis.connection.RedisNode">
                    <constructor-arg name="host" value="192.168.48.31"/>
                    <constructor-arg name="port" value="26379"/>
                </bean>
                <bean name="sentinelNode2" class="org.springframework.data.redis.connection.RedisNode">
                    <constructor-arg name="host" value="192.168.48.32"/>
                    <constructor-arg name="port" value="26379"/>
                </bean>
                <bean name="sentinelNode3" class="org.springframework.data.redis.connection.RedisNode">
                    <constructor-arg name="host" value="192.168.48.33"/>
                    <constructor-arg name="port" value="26379"/>
                </bean>
            </set>
        </property>
        <property name="master">
            <bean name="masterNode" class="org.springframework.data.redis.connection.RedisNode">
                &lt;!&ndash;必須指定主節點名稱&ndash;&gt;
                <property name="name" value="mymaster"/>
                <constructor-arg name="host" value="192.168.48.31"/>
                <constructor-arg name="port" value="6379"/>
            </bean>
        </property>-->
    </bean>

    <bean name="propertySource" class="org.springframework.core.io.support.ResourcePropertySource">
        <constructor-arg name="location" value="classpath:spring-redis-sentinel.properties" />
    </bean>

    <!-- JedisPoolConfig definition -->
    <bean id="jedisPoolConfig"   class="redis.clients.jedis.JedisPoolConfig" >
        <property name="minIdle" value="${redis.minIdle}" />
        <property name="maxIdle" value="${redis.maxIdle}" />
        <property name="maxTotal" value="${redis.maxActive}" />
        <property name="maxWaitMillis" value="${redis.maxWait}" />
        <property name="testOnBorrow" value="${redis.testOnBorrow}" />
        <property name="testOnReturn" value="true" />
        <property name="testWhileIdle" value="true" />
    </bean>

    <!-- redis template definition -->
    <bean id="stringRedisTemplate" class="org.springframework.data.redis.core.StringRedisTemplate" p:connection-factory-ref="jedisConnectionFactory"/>

sentinel故障轉移

為驗證故障轉移,我們關閉Master節點

shutdown

關閉Master節點

Sentinel監控日誌:

Sentinel監控日誌

簡單解釋下日誌資訊:

  • +sdown 表示監控節點主觀下線(單個Sentinel例項對伺服器做出的下線判斷)
  • +odown 表示監控節點客觀下線(多個Sentinel例項對伺服器做出的sdown判斷),sentinel.config中配置達到2個sdown(quorum引數配置)便判斷為客觀下線
  • +switch-master 從slave節點中選個作為新的主節點,Slave1(192.168.48.32:6379)

檢視該節點資訊,發現他的角色已經變為master,原先的Slave0(192.168.48.33:6379)變成新master的slave:

redis-cli -h 192.168.48.32 info Replication

新Master節點

接下來再來測試一種情況:在故障節點重啟之前傳送寫命令,故障節點重啟後資料是否會複製過來?

valueOperations.set("foo1","bar1");

結果:

新master的foo1值

重啟原來的Master節點(192.168.48.31:6379)

重啟原Master節點後

原先的Master重啟後變成了新Master的從節點了,試著檢視foo1的值

foo1值同步過來了

可見,重啟後,新的從節點會複製新的master節點,保證資料一致性。

參考

相關推薦

Spring整合Redis哨兵故障轉移

前言 上篇部落格談到了Spring整合redis叢集以及故障轉移演示,會發現redis叢集模式存在一個很明顯的問題:當某個主節點及其所有從節點掛掉,整個叢集因為缺少該節點負責範圍的雜湊槽(hash slot)而宕掉,不具高可用性。redis引入了哨兵(sent

spring整合redis單機版redis叢集版

前言: 有時候我們部署了叢集版的redis,還希望開發的時候使用單機版(畢竟省事兒),但是比較常用的Java客戶端(Jedis和Lettuce)的單機和叢集api是不統一的。經過調研,發現spring-data-redis可以實現這個需求,本文就是將spring-data-

Spring整合HibernateAnnotationSessionFactoryBeanLocalSessionFactoryBean

Spring整合Hibernate由兩種形式 1、繼續使用Hibernate的對映檔案*.hbm.xml 2、使用jpa形式的pojo物件, 去掉*.hbm.xml檔案 一、繼續使用Hibernate的對映檔案*.hbm.xml 此時Spring的配置檔案中的Seesio

Spring data redis spring 系統整合

第一步: 新增依賴(以maven為例) <!--     redis相關jar包依賴    -->          <dependency> &

Redis哨兵模式Sentinel配置啟動(五)

14. quorum rom 修改 rewrite 最大 不可用 log 不可 一、介紹   上一篇我們已經介紹了Redis的主從復制,傳送門:《Redis高可用之主從復制實踐(四)》,想必大家對redis已經有一個概念了,那麽問題來了,如果redis主從復制的mast

spring實戰4 spring整合redis哨兵

前言 開始 建專案 新建spring-redis-sentinel web專案 導包 <dependency> <groupId>org.springframework</groupId>

VCSA 6.5 HA 配置五:故障轉移測試

center style justify 接著上篇文章配置完成VCSA的高可用後,其是否真的能實現高可用的效果,本篇文章將會一探究竟手動故障切換在vCenter HA配置頁面可以看到當前的主動節點、被動節點和見證節點;在例行維護或者其他時候可以手動執行故障切換通過右上方的"啟動故障切換" ,在一般

spring整合redis

data sch throws ack xid .org source protect pid 1,利用spring-data-redis整合 項目使用的pom.xml: <project xmlns="http://maven.apache.org/POM/4.0

Spring整合Redis做數據緩存(Windows環境)

端口號 init 技術分享 factory redis-cli @service tab long 配置 當我們一個項目的數據量很大的時候,就需要做一些緩存機制來減輕數據庫的壓力,提升應用程序的性能,對於java項目來說,最常用的緩存組件有Redis、Ehcache和Mem

Spring整合Redis(spring-data-redis)

nds 獲取 可能 div 普通 工具 long red 等待 歷經幾天看了大量的博客資料,差不多算是搞定了,目前只是針對單個數據源,集群暫時沒研究 maven依賴 <properties> <!-- redis 版本 --> &l

網站性能優化小結和spring整合redis

remove utf ota turn tor package process 基本屬性 version 現在越來越多的地方需要非關系型數據庫了,最近網站優化,當然從頁面到服務器做了相應的優化後,通過在線網站測試工具與之前沒優化對比,發現有顯著提升。 服務器優化目前主要優化

spring 整合 redis的配置

index row val return created log idea pass truct   廢話不說,直接上代碼:   1、先添加依賴包 <!--redis--> <dependency>

Spring整合Struts2的配置測試

png 額外 步驟 圖片 xml文件 顯示 img 一個 輸出 整合目的     讓Spring的IOC容器管理Struts2的Action 整合步驟     1、新建一個Web項目     2、加入Spring的jar包和添加Spring的配置文件     3、在

Redis的集群(故障轉移)

全量 tex 關註 是否 ont val start 事件 neu Redis集群自身實現了高可用,當集群內少量節點出現故障時通過自動故障轉移保證集群可以正常對外提供服務。故障發現1. 主觀下線當cluster-node-timeout時間內某節點無法與另一個節點順利完成p

Spring整合Redis報ClassCastException

最近在用Spring註解方式Cacheable 整合Redis的時候,報ClassCastException 異常,我方法返回值是一個PageVo, 報不能將PageVo 不能轉換成String 型別。一開始網上搜都是說SpringBoot整合方案,但我用的是Spring的方式的,後來看過幾

Spring整合Redis註解實現

之前我們說了Spring這個Redis,使用RedisTemplate 實現,不過有些地方也過於麻煩,因此Spring 團隊對 Jedis 進行了封裝,獨立為 spring-data-redis 專案,配合 spring 特性並整合 Jedis 的一些命令和方法。並提供了相關注解,幫助我們快

Spring整合redis帶測試用例Demo完整程式碼

專案結構 jar包 <!--redis--> <dependency> <groupId>redis.clients</groupId> <artifa

【nosql-redisspring整合redis

環境: MAVEN+SPRING+MYBATIS+MYSQL+REDIS 1 pom.xml檔案下載依賴: <dependency> <groupId>org.springframework.data</groupId> &

Spring整合redis叢集

目錄 1,說明 6,使用 1,說明 本文使用的客戶端為jedisCluster.它已經封裝了一些常用操作。故只需根據自己需要再進行封裝即可。 2,jar版本 使用的jar包的版本如下 jedis-2.9.0.jar(據網上反饋,只有這個版

redis哨兵(Sentinel)

Redis-Sentinel是redis官方推薦的高可用性解決方案,當用redis作master-slave的高可用時,如果master本身宕機,redis本身或者客戶端都沒有實現主從切換的功能。 而redis-sentinel就是一個獨立執行的程序,用於監控多個master-slave叢集,自動發現m