Redis Sentinel的分布式特性介紹
Redis Sentinel是一個分布式系統,Sentinel運行在有許多Sentinel進程互相合作的環境下,它本身就是這樣被設計的。有許多Sentinel進程互相合作的優點如下: 當多個Sentinel同意一個master不再可用的時候,就執行故障檢測。這明顯降低了錯誤機率。 即使並非全部的Sentinel都在工作,Sentinel也可以正常工作,這種特性,讓系統非常的健康。
所有的Sentinels,Redis執行個體,串連到Sentinel和Redis的用戶端,本身就是一個有著特殊性質的大型分布式系統。在這篇文章中,我將通過執行個體的形式從部署Redis Sentinel叢集、使用Redis的Master Slave的模式部署Redis叢集來介紹在Spring項目中如何使用Redis Sentinel實現緩衝系統的高可用。
部署之前瞭解關於Sentinel的基本東西 一個健康的叢集部署,至少需要三個Sentinel執行個體 三個Sentinel執行個體應該被放在失敗獨立的電腦上或虛擬機器中,比如說不同的物理機或者在不同的可用性區域域上執行的虛擬機器。 Sentinel + Redis 分布式系統在失敗期間並不確保寫入請求被儲存,因為Redis使用非同步複製。可是有很多部署Sentinel的 方式來讓視窗把丟失寫入限制在特定的時刻,當然也有另外的不安全的方式來部署。 用戶端必須支援Sentinel。大多數用戶端庫都支援Sentinel,但並不是全部。 沒有高可用的設定是安全的,如果你在你的測試環境沒有經常去測試,或者甚至在生產環境中你也沒有經常去測試,如果Sentinel正常工作。 但是你或許有一個錯誤的配置而僅僅只是在很晚的時候才出現(淩晨3點你的主節點宕掉了)。 Sentinel,Docker ,其他的網路位址轉譯表,連接埠映射應該很小心的使用:Docker執行連接埠重新對應,破壞Sentinel自動探索另外的Sentinel進程和一個主節點的從節點列表。在文章的稍後部分查看更過關於Sentinel和Docker的資訊。
執行個體介紹 本執行個體通過部署3個Redis Sentinel實現Sentinel執行個體的高可用。 本執行個體通過部署1個Redis Master執行個體,3個Slave執行個體實現Redis緩衝的高可用。
Redis Master執行個體和Slave執行個體部署
下載並安裝Redis,此文不講解,具體可參考http://blog.csdn.net/zyhlwzy/article/details/78366265。
可參考Redis主從(Master-Slave)複製(Replication)設定一文第8節Redis主從複製實戰的部署方式部署Master-Slave,但是需要注意的是,本文需要的是一個Master執行個體,3個Slave執行個體。
Redis執行個體資訊如下:
IP |
Port |
備忘 |
192.168.199.126 |
6379 |
Master |
192.168.199.249 |
6382 |
Slave |
192.168.199.249 |
6383 |
Slave |
192.168.199.249 |
6384 |
Slave |
配置Master
下載並安裝Redis,此文不講解,具體可參考http://blog.csdn.net/zyhlwzy/article/details/78366265。
Master的配置很簡單,我們開啟守護進程即可(示範執行個體不設定驗證資訊,如有需要自行設定)。
進入redis設定檔目錄(/data/redis/redis-4.0.1/redis.conf)編輯redis.conf進行如下配置。
daemonize yes
配置Slave
下載並安裝Redis,此文不講解,具體可參考http://blog.csdn.net/zyhlwzy/article/details/78366265。
建立Slave設定檔目錄,拷貝redis.conf到對應目錄並進行配置。
mkdir /data/redis/clustercd /data/redis/clustermkdir -p 6382cp /data/redis/redis-4.0.1/redis.conf /data/redis/cluster/6382/redis-6382.confmkdir -p 6383cp /data/redis/redis-4.0.1/redis.conf /data/redis/cluster/6383/redis-6383.confmkdir -p 6384cp /data/redis/redis-4.0.1/redis.conf /data/redis/cluster/6384/redis-6384.conf
3個Slave執行個體的設定檔內容,注意修改下面加粗字型部分的內容即可(注意注釋掉的要去掉注釋),其他都相同:
配置選項 |
選項值 |
說明 |
daemonize |
yes |
預設情況下 redis 不是作為守護進程啟動並執行,如果你想讓它在後台運行,你就把它改成 yes。 |
pidfile |
/data/redis/cluster/6382/redis-6382.pid |
當redis作為守護進程啟動並執行時候,預設情況下它會寫一個 pid 到 /var/run/redis.pid 檔案裡面 |
port |
6382 |
監聽連接埠號碼,預設為 6379,如果你設為 0 ,redis 將不在 socket 上監聽任何用戶端串連。 |
database |
1 |
設定資料庫的數目。 |
cluster-enabled |
no |
啟用或停用叢集 |
cluster-config-file |
/data/redis/cluster/6382/nodes-6382.conf |
叢集設定檔,啟動時自動產生 |
cluster-node-timeout |
15000 |
節點互聯逾時時間,單位毫秒 |
cluster-migration-barrier |
1 |
這個參數表示的是,一個主節點在擁有多少個好的從節點的時候就要割讓一個從節點出來。 |
cluster-require-full-coverage |
yes |
如果叢集中某些key space沒有被叢集中任何節點覆蓋,叢集將停止接受寫入 |
appendonly |
yes |
啟用aof持久化方式 |
dir |
/data/redis/cluster/6382/ |
節點資料持久化存放目錄 |
slaveof |
192.168.199.126 6379 |
Master節點配置 |
如果配置成功並啟動,通過用戶端工具串連到Master時,輸入如下命令
info replication
將會得到如下結果
# Replicationrole:masterconnected_slaves:3slave0:ip=192.168.199.249,port=6384,state=online,offset=1127147,lag=1slave1:ip=192.168.199.249,port=6383,state=online,offset=1127292,lag=1slave2:ip=192.168.199.249,port=6382,state=online,offset=1127292,lag=1master_replid:beba8e13c44c5a4afcf8c82889b524b2f76faa22master_replid2:0000000000000000000000000000000000000000master_repl_offset:1127292second_repl_offset:-1repl_backlog_active:1repl_backlog_size:1048576repl_backlog_first_byte_offset:78717repl_backlog_histlen:1048576
Redis Sentinel部署
3個Redis Sentinel資訊如下
IP |
Port |
備忘 |
192.168.199.126 |
26379 |
Sentinel |
192.168.199.126 |
26479 |
Sentinel |
192.168.199.126 |
26579 |
Sentinel |
Redis安裝完成之後,在redis目錄(本執行個體是redis-4.0.1)下會有一個sentinel.conf檔案,建立sentinel目錄並將該設定檔拷貝進去重新命名為自訂的sentinel設定檔。
mkdir /data/redis/sentinelcp /data/redis/redis-4.0.1/sentinel.conf /data/redis/sentinel/sentinel_26379.confcp /data/redis/redis-4.0.1/sentinel.conf /data/redis/sentinel/sentinel_26479.confcp /data/redis/redis-4.0.1/sentinel.conf /data/redis/sentinel/sentinel_26579.conf
sentinel_26379.conf配置內容:
protected-mode noport 26379sentinel monitor mymaster 192.168.199.249 6384 2sentinel failover-timeout mymaster 60000sentinel config-epoch mymaster 1sentinel leader-epoch mymaster 1sentinel known-slave mymaster 192.168.199.126 6379
sentinel_26479.conf配置內容:
protected-mode noport 26479sentinel monitor mymaster 192.168.199.249 6384 2sentinel failover-timeout mymaster 60000sentinel config-epoch mymaster 1sentinel leader-epoch mymaster 1sentinel known-slave mymaster 192.168.199.126 6379
sentinel_26579.conf配置內容:
protected-mode noport 26579sentinel monitor mymaster 192.168.199.249 6384 2sentinel failover-timeout mymaster 60000sentinel config-epoch mymaster 1sentinel leader-epoch mymaster 1sentinel known-slave mymaster 192.168.199.126 6379
啟動Redis Master執行個體
進入Redis Master伺服器Redis bin目錄,執行以下命令:
./redis-server /data/redis/redis-4.0.1/redis.conf
啟動Redis Slave執行個體
進入Redis Slave伺服器Redis bin目錄,執行以下命令:
./redis-server /data/redis/cluster/6382/redis-6382.conf./redis-server /data/redis/cluster/6383/redis-6383.conf./redis-server /data/redis/cluster/6384/redis-6384.conf
啟動Sentinel執行個體
進入Redis Slave伺服器Redis bin目錄,執行以下命令:
./redis-sentinel /data/redis/sentinel/sentinel_26379.conf ./redis-sentinel /data/redis/sentinel/sentinel_26479.conf ./redis-sentinel /data/redis/sentinel/sentinel_26579.conf
如果啟動時出現如下資訊,表示啟動成功
Maven配置
<dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>2.9.0</version> </dependency> <dependency> <groupId>org.springframework.data</groupId> <artifactId>spring-data-redis</artifactId> <version>1.7.5.RELEASE</version></dependency>
在config.properties中增加如下配置
#Redis sentinel使用redis.sentinel1.host=192.168.199.126redis.sentinel1.port=26379redis.sentinel2.host=192.168.199.126redis.sentinel2.port=26479redis.sentinel3.host=192.168.199.126redis.sentinel3.port=26579redis.sentinel.masterName=mymaster
建立spring-redis-sentinel.xml設定檔,寫入如下資訊
<?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:context="http://www.springframework.org/schema/context" xmlns:jdbc="http://www.springframework.org/schema/jdbc" xmlns:jee="http://www.springframework.org/schema/jee" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:util="http://www.springframework.org/schema/util" xmlns:task="http://www.springframework.org/schema/task" xmlns:cache="http://www.springframework.org/schema/cache" xmlns:c='http://www.springframework.org/schema/c' xmlns:p="http://www.springframework.org/schema/p" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-4.0.xsd http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-4.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-4.0.xsd http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache-3.1.xsd" default-lazy-init="true"> <!-- 開啟spring cache註解功能 --> <cache:annotation-driven cache-manager="redisCacheManager" /> <context:annotation-config /> <context:property-placeholder ignore-unresolvable="true" location="classpath:config.properties" /> <!-- Redis --> <bean id="poolConfig" class="redis.clients.jedis.JedisPoolConfig"> <property name="maxTotal" value="${redis.maxTotal}" /> <property name="maxIdle" value="${redis.maxIdle}" /> <property name="maxWaitMillis" value="${redis.maxWait}" /> <property name="testOnBorrow" value="${redis.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="${redis.sentinel.masterName}"></property> </bean> </property> <property name="sentinels"> <set> <bean class="org.springframework.data.redis.connection.RedisNode"> <constructor-arg name="host" value="${redis.sentinel1.host}"></constructor-arg> <constructor-arg name="port" value="${redis.sentinel1.port}"></constructor-arg> </bean> <bean class="org.springframework.data.redis.connection.RedisNode"> <constructor-arg name="host" value="${redis.sentinel2.host}"></constructor-arg> <constructor-arg name="port" value="${redis.sentinel2.port}"></constructor-arg> </bean> <bean class="org.springframework.data.redis.connection.RedisNode"> <constructor-arg name="host" value="${redis.sentinel3.host}"></constructor-arg> <constructor-arg name="port" value="${redis.sentinel3.port}"></constructor-arg> </bean> </set> </property> </bean> <!-- redis伺服器中心 --> <bean id="jedisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory"> <constructor-arg name="sentinelConfig" ref="sentinelConfiguration"></constructor-arg> <constructor-arg name="poolConfig" ref="poolConfig"></constructor-arg> </bean> <bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate"> <property name="connectionFactory" ref="jedisConnectionFactory" /> <property name="keySerializer"> <bean class="org.springframework.data.redis.serializer.StringRedisSerializer" /> </property> <property name="valueSerializer"> <bean class="org.springframework.data.redis.serializer.JdkSerializationRedisSerializer" /> </property> </bean> <!-- redis緩衝管理器 --> <bean id="redisCacheManager" class="org.springframework.data.redis.cache.RedisCacheManager"> <constructor-arg name="redisOperations" ref="redisTemplate" /> </bean> <bean id="redisUtils" class="ron.blog.blog_service.utils.RedisUtils" /></beans>
在spring-context.xml引入spring-redis-sentinel.xml
<import resource="classpath:spring-redis-sentinel.xml" />
編寫Redis協助類RedisUtils
public class RedisUtils { /** * RedisTemplate是一個簡化Redis資料訪問的一個協助類, * 此類對Redis命令進行進階封裝,通過此類可以調用ValueOperations和ListOperations等等方法。 */ @Autowired private RedisTemplate<Serializable, Object> redisTemplate; /** * 大量刪除對應的value * * @param keys */