redis 集羣搭建(含SpringBoot 相關配置代碼)

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: 123

server:
  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;
    }
}

聲明:部分圖片及敘述借鑑自其他博友,對此表示感謝!!!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章