Redis常見的幾種主要使用方式:
-
Redis 多副本(主從)
port 6666
daemonize yes
requirepass 123
# 服務器配置masterauth作用主要是爲了後期sentinel引入後重新選舉master並且7000端口redis重新加入主從複製時必備的,否則會出現權限不足
masterauth 123
slaveof 172.31.53.175 6666 (從服務器添加)
logfile ./redislog_louie.log
dir ./
#bind 192.168.250.132 127.0.0.1 # 0.0.0.0
RDB:
save 20 1
# 自動保存策略,20秒內有一個key發生變化就自動保存
dbfilename rdb_louie.rdb
# rdb文件名
stop-writes-on-bgsave-error yes
# 發生錯誤中斷寫入,建議開啓
rdbcompression yes
# 數據文件壓縮,建議開啓
rdbchecksum yes
# 開啓crc64錯誤校驗,建議開啓
AOF:
appendonly yes
# 開啓aof
appendfilename aof_louie.aof
# aof 日誌文件名
appendfsync everysec
# 每秒記錄一次日誌,建議everysec
no-appendfsync-on-rewrite yes
# 重寫過程中是否向日志文件寫入,yes 代表rewrite過程中,不向aof文件中追加信息,rewrite結束後再寫入,no 代表rewrite執行的同時,也向aof追加信息
auto-aof-rewrite-percentage 100
# 觸發重寫文件增長百分比 默認100%
auto-aof-rewrite-min-size 64mb
# 觸發重寫最小aof文件尺寸
../src/redis-cli -c -p 9001 -a 123 info Replication
優點:特點就是主從實例間數據實時同步,並且提供數據持久化和備份策略,可以實現同時對外提供服務和讀寫分離策略。
缺點:主節點掛掉,需要手動的晉升一個從節點作爲主節點,同時需要需要業務方變更配置,主庫的寫能力受到單機的限制
Redis Sentinel(哨兵)
進入服務器的redis文件夾下,創建一個文件名爲 sentinel-26379.conf 配置文件,文件內容如下
port 26379
daemonize yes
logfile "26379.log"
dir "./"
sentinel monitor mymaster 172.31.53.175 7000 2
sentinel down-after-milliseconds mymaster 30000
sentinel parallel-syncs mymaster 1
sentinel failover-timeout mymaster 15000
sentinel auth-pass mymaster 123
bind 0.0.0.0
其他的集羣複製改port 即可
參數介紹:
sentinel monitor <master-name> <ip> <redis-port> <quorum>
告訴sentinel去監聽地址爲ip:port的一個master,這裏的master-name可以自定義,quorum是一個數字,指明當有多少個sentinel認爲一個master失效時,master纔算真正失效
sentinel auth-pass <master-name> <password>
設置連接master和slave時的密碼,注意的是sentinel不能分別爲master和slave設置不同的密碼,因此master和slave的密碼應該設置相同。
sentinel down-after-milliseconds <master-name> <milliseconds>
這個配置項指定了需要多少失效時間,一個master纔會被這個sentinel主觀地認爲是不可用的。 單位是毫秒,默認爲30秒
sentinel parallel-syncs <master-name> <numslaves>
這個配置項指定了在發生failover主備切換時最多可以有多少個slave同時對新的master進行 同步,這個數字越小,完成failover所需的時間就越長,但是如果這個數字越大,就意味着越 多的slave因爲replication而不可用。可以通過將這個值設爲 1 來保證每次只有一個slave 處於不能處理命令請求的狀態。
sentinel failover-timeout <master-name> <milliseconds>
failover-timeout 可以用在以下這些方面:
1. 同一個sentinel對同一個master兩次failover之間的間隔時間。
2. 當一個slave從一個錯誤的master那裏同步數據開始計算時間。直到slave被糾正爲向正確的master那裏同步數據時。
3.當想要取消一個正在進行的failover所需要的時間。
4.當進行failover時,配置所有slaves指向新的master所需的最大時間。不過,即使過了這個超時,slaves依然會被正確配置爲指向master,但是就不按parallel-syncs所配置的規則來了。
./redis-sentinel sentinel-port.conf 配置文件啓動哨兵
哨兵是一個獨立的進程
優點:解決上面主從的痛點,提供監控、提醒、自動故障轉移三個方面的優化。
監控:通過心跳機制,不斷地檢查主服務器、從服務器和sentinel節點 是否運作正常。
提醒:當謀個服務器出現問題,Sentinel 可以通過api 像管理員發送通知。
自動故障轉移:當主服務器不能正常工作時, Sentinel 會開始一次自動故障遷移操作, 它會將失效主服務器的其中一個從服務器升級爲新的主服務器, 並讓其他從服務器改爲複製新的主服務器; 當客戶端試圖連接失效的主服務器時, 集羣也會向客戶端返回新主服務器的地址, 使得集羣可以使用新主服務器代替失效服務器。主服務器恢復後,就成爲了一個從服務器。
Redis Cluster
配置文件內容爲如下:其他的配置文件修改一下端口以及log文件、日誌文件即可。其中中間部分cluster代表
daemonize yes
port 7000
logfile 7000.log
#masterauth 123
#requirepass 123
dir ./
bind 192.168.250.129 127.0.0.1
cluster-enabled yes
cluster-config-file nodes_7000.conf
cluster-node-timeout 15000
appendonly yes
appendfilename aof-7000.aof
appendfsync everysec
no-appendfsync-on-rewrite yes
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
工作原理:
Redis 集羣是一個提供在多個Redis節點間共享數據的程序集。下圖以三個master節點和三個slave節點作爲示例。Redis 集羣有16384個哈希槽,每個key通過CRC16校驗後對16384取模來決定放置哪個槽。集羣的每個節點負責一部分hash槽,如圖中slots所示。
其內部中也需要配置主從,並且內部也是採用哨兵模式,如果有半數節點發現某個異常節點,共同決定更改異常節點的狀態,如果改節點是主節點,則對應的從節點自動頂替爲主節點,當原先的主節點上線後,則會變爲從節點。
如果集羣中的master沒有slave節點,則master掛掉後整個集羣就會進入fail狀態,因爲集羣的slot映射不完整。如果集羣超過半數以上的master掛掉,無論是否有slave,集羣都會進入fail狀態。
根據官方推薦 集羣部署至少要3臺以上的master節點。那麼接下來就開始部署吧
優點:採用去中心化的思想,沒有中心節點的說法。自動實現負載均衡與高可用。(是主從複製和哨兵模式的結合版)
解決了redis-Sentinel 主服務器的寫壓力 ,將主服務器做成集羣,每個主節點都有從節點。
方案對比,方案確定
Redis 多副本(主從):master節點宕機,沒有主動的選舉機制(主節點寫,從節點讀) 至少3臺服務器
Redis-Sentinel:發現master宕機後能進行自動切換,解決一主多從master 節點宕機,寫數據的問題(主備切換) 至少3臺服務器
Redis-Cluster:多個主節點,減輕了主節點的壓力。 至少3臺服務器 (3組master - slave )
所以:這裏最佳的高可用方式是官方推薦的Redis-Cluster
部署方式
1.Sentinel節點不應該部署在一臺物理機上。
2.部署至少三個且奇數個的Sentinel節點
環境配置:
第一:準備3臺服務器,每臺服務器運行兩個redis
主機說明 |
主機IP |
端口 |
Redis |
172.31.53.175 |
7000 7001 |
Redis |
172.31.53.175 |
7002 7003 |
Redis |
172.31.53.175 |
7004 7005
|
在每一臺服務器上我們添加一下配置文件
分別爲:redis-7000.conf redis-7001.conf redis-7002.conf redis-7003.conf redis-7004.conf redis-7005.conf
配置文件內容爲如下:其他的配置文件修改一下端口以及log文件、日誌文件即可。其中中間部分cluster代表集羣設置。
daemonize yes
#masterauth 123
#requirepass 123
port 7000
logfile 7000.log
dir ./
bind 192.168.250.129 127.0.0.1
cluster-enabled yes
cluster-config-file nodes_7000.conf
cluster-node-timeout 15000
appendonly yes
appendfilename aof-7000.aof
appendfsync everysec
no-appendfsync-on-rewrite yes
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
上面文件都配置好後,即可啓動
啓動後我們就可以創建集羣
注意:
在redis5.0後 創建集羣統一使用redis-cli,
./src/redis-cli --cluster create 172.31.53.175:7000 172.31.53.175:7001 172.31.53.175:7002 172.31.53.175:7003 172.31.53.175:7004 172.31.53.175:7005 --cluster-replicas 1
之前的版本使用redis-trib.rb, hostname -i
./redis-trib.rb create --replicas 1 172.31.53.175:7000 172.31.53.175:7001 172.31.53.175:7002 172.31.53.175:7003 172.31.53.175:7004 172.31.53.175:7005
具體的可以參照redis官方網站查看
https://redis.io/topics/cluster-tutorial
創建集羣命令:其中 cluster-replicas 1 代表 一個master後有幾個slave,1代表爲1個slave節點
驗證一下集羣是否創建成功
登錄redis客戶端 ./src/redis-cli -c -p 7000, -c 參數代表連接到集羣中
我們先看一下主從配對情況,根據node ID匹配可以得出配比。如下:紅色圈出來的爲標註,大家可以看看是否有對應的ID,這樣我們就區分了主從節點的關係了。
驗證數據匹配是否採用哈希槽的方式。大家可自行測試一下。發現我在7000客戶端設置的數據,被分配到7002上了。
如果是使用redis-trib.rb工具構建集羣,集羣構建完成前不要配置密碼,集羣構建完畢再通過config set + config rewrite命令逐個機器設置密碼
客戶端實現
Yml:
spring:
redis:
timeout: 60000ms
cluster:
max-redirects: 3
nodes:
- 47.105.102.123:7001
- 47.105.102.123:7002
- 47.105.102.123:7003
- 47.105.102.123:7004
- 47.105.102.123:7005
- 47.105.102.123:7000
lettuce:
pool:
max-active: 1000
max-idle: 10
min-idle: 5
max-wait: -1
@Configuration
public class RedisConfiguration {
@Autowired
private RedisProperties redisProperties;
@Bean
public LettuceConnectionFactory redisConnectionFactory() {
RedisClusterConfiguration redisClusterConfiguration = new RedisClusterConfiguration(redisProperties.getCluster().getNodes());
redisClusterConfiguration.setMaxRedirects(redisProperties.getCluster().getMaxRedirects());
redisClusterConfiguration.setPassword(redisProperties.getPassword());
//支持自適應集羣拓撲刷新和靜態刷新源
ClusterTopologyRefreshOptions clusterTopologyRefreshOptions = ClusterTopologyRefreshOptions.builder()
.enablePeriodicRefresh()
.enableAllAdaptiveRefreshTriggers()
.refreshPeriod(Duration.ofSeconds(redisProperties.getTimeout().getSeconds()))
.build();
ClusterClientOptions clusterClientOptions = ClusterClientOptions.builder()
.topologyRefreshOptions(clusterTopologyRefreshOptions).build();
//從優先,讀寫分離,讀從可能存在不一致,最終一致性CP
LettuceClientConfiguration lettuceClientConfiguration = LettuceClientConfiguration.builder()
.readFrom(ReadFrom.SLAVE_PREFERRED)
.clientOptions(clusterClientOptions).build();
return new LettuceConnectionFactory(redisClusterConfiguration, lettuceClientConfiguration);
}
@Bean
public RedisTemplate<Object, Object> redisTemplate(LettuceConnectionFactory redisConnectionFactory) {
RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(redisConnectionFactory);
redisTemplate.setKeySerializer(new StringRedisSerializer());
// redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
}
備註:
<!-- lettuce客戶端需要使用到 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
哨兵模式:客戶端
spring:
redis:
timeout: 60000ms
lettuce:
pool:
max-active: 1000
max-idle: 10
min-idle: 5
max-wait: -1
sentinel:
master: mymaster
nodes: 47.105.102.123:29000,47.105.102.123:29001,47.105.102.123:29002
password: 123server:
port: 9999
@Configuration
public class RedisConfiguration {
@Autowired
private RedisProperties redisProperties;
@Bean
public LettuceConnectionFactory redisConnectionFactory() {
List<RedisNode> nodes = redisProperties.getSentinel().getNodes().stream().map(e -> new RedisNode(e.split(":")[0], Integer.valueOf(e.split(":")[1])))
.collect(Collectors.toList());
RedisSentinelConfiguration redisClusterConfiguration = new RedisSentinelConfiguration();
redisClusterConfiguration.setSentinels(new HashSet<>(nodes));
redisClusterConfiguration.setPassword(redisProperties.getPassword());
redisClusterConfiguration.setMaster(redisProperties.getSentinel().getMaster());
//從優先,讀寫分離,讀從可能存在不一致,最終一致性CP
LettuceClientConfiguration lettuceClientConfiguration = LettuceClientConfiguration.builder()
.readFrom(ReadFrom.SLAVE_PREFERRED)
.build();
return new LettuceConnectionFactory(redisClusterConfiguration, lettuceClientConfiguration);
}
@Bean
public RedisTemplate<Object, Object> redisTemplate(LettuceConnectionFactory redisConnectionFactory) {
RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(redisConnectionFactory);
redisTemplate.setKeySerializer(new StringRedisSerializer());
// redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
}
聲明:部分圖片及敘述借鑑自其他博友,對此表示感謝!!!