Redis集羣部署及Springboot架構下應用(Cluster分區集羣模式)

導航

主從集羣
哨兵集羣
分區集羣

環境:

redis:5.0.8
Springboot: 2.2.3.RELEASE
redis安裝參見:CentOS7下安裝Redis(單機版)

集羣方式及配置

基礎配置集羣配置:

#後臺運行(守護進程)
daemonize yes 
#去除保護模式(允許遠程訪問)
protected-mode no
#去除綁定(遠程訪問)
#bind 127.0.0.1
# 設置密碼
requirepass redispwd

本次配置基於同一機器不通端口做集羣,當redis位於不同機器時,部分配置可以省去(以下配置過程中會說明/【單機非必須】:當前機器僅運行一個redis實例)

Cluster分區集羣

Cluster分區集羣表現形式爲數據均勻分佈在其中一個分區節點上(預設虛擬槽的範圍爲0到16383,每個節點間共享數據槽範圍)。
特別注意:cluster分區集羣要求至少三個節點
修改節點1配置 6379
拷貝一份配置文件命名爲redis-cluster6379.conf(來源安裝目錄:redis-5.0.8/redis.conf)
修改配置

# db寫入磁盤目錄位置(文件夾路徑如果不存在,需要手動創建):【單機非必須】
dir ./cluster6379 
#日誌目錄,默認運行命令時的目錄【單機非必須】
logfile "./cluster6379/cluster6379.log"
#pid寫入位置,默認/var/run/redis_6379.pid【單機非必須】
pidfile "/var/run/redis_6379.pid"
# 開啓集羣 
cluster-enabled yes

修改節點2配置 6380
拷貝redis-cluster6379.conf 命名爲redis-cluster6380.conf

# redis端口【單機非必須】
port 6380
 # db寫入磁盤目錄位置(文件夾路徑如果不存在,需要手動創建):【單機非必須】
dir ./cluster6380
#日誌目錄,默認運行命令時的目錄【單機非必須】
logfile "./cluster6380/cluster6380.log"
#pid寫入位置,默認/var/run/redis_6379.pid【單機非必須】
pidfile /var/run/redis_6380.pid

修改節點3配置 6381
拷貝redis-cluster6379.conf 命名爲redis-cluster6381.conf

# redis端口【單機非必須】
port 6381
 # db寫入磁盤目錄位置(文件夾路徑如果不存在,需要手動創建):【單機非必須】
dir ./cluster6381
#日誌目錄,默認運行命令時的目錄【單機非必須】
logfile "./cluster6381/cluster6381.log"
#pid寫入位置,默認/var/run/redis_6379.pid【單機非必須】
pidfile /var/run/redis_6381.pid

啓動節點1(6379)、節點2(6380)、節點3(6381)

./bin/redis-server redis-cluster6379.conf 
./bin/redis-server redis-cluster6380.conf
./bin/redis-server redis-cluster6381.conf

在這裏插入圖片描述
查看6379狀態及cluster 節點
在這裏插入圖片描述
查看6380狀態及cluster 節點
在這裏插入圖片描述
對比發現,這是兩個不同的集羣(槽點分佈沒有顯示,如果不理解繼續向下看即可)。
配置集羣關係
這裏需要注意的是,redis5.0.8已經不支持redis-trib.rb配置集羣了
在這裏插入圖片描述
使用redis-cli配置集羣
測試一下少於三個的集羣會發生什麼?

 ./bin/redis-cli --cluster create 192.168.1.17:6379 192.168.1.17:6380 --cluster-replicas 0 -a redispwd

注: -a參數後面跟的是密碼,如果沒有密碼可以不設置此參數
執行結果:
在這裏插入圖片描述
尷尬不!!!
配置集羣

 ./bin/redis-cli --cluster create 192.168.1.17:6379 192.168.1.17:6380 192.168.1.17:6381 --cluster-replicas 0 -a redispwd

在這裏插入圖片描述
注意,中間有個詢問,輸入yes即可
分別查看三個基點的節點信息
在這裏插入圖片描述在這裏插入圖片描述在這裏插入圖片描述
可以看到槽點分佈情況如下(對比未配置集羣時的狀態-無槽點信息):

節點 槽點範圍
6379 0-5460
6380 5461-10922
6381 10923-16381

數據寫入及讀取
分別在6397、6380、6381節點上set一個相同的key
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
可以看到key [testkey]只能在節點6379上插入,其他節點上插入會提示錯誤並告訴可供插入的節點信息。

使用redis-cli新增節點

修改節點4配置 6382
拷貝redis-cluster6379.conf 命名爲redis-cluster6382.conf

#redis端口【單機非必須】
port 6382
 # db寫入磁盤目錄位置(文件夾路徑如果不存在,需要手動創建):【單機非必須】
dir ./cluster6382
#日誌目錄,默認運行命令時的目錄【單機非必須】
logfile "./cluster6382/cluster6382.log"
#pid寫入位置,默認/var/run/redis_6379.pid【單機非必須】
pidfile /var/run/redis_6382.pid

啓動節點4【6382】

./bin/redis-server redis-cluster6382.conf

在這裏插入圖片描述
此時6382是個獨立的節點
在這裏插入圖片描述在這裏插入圖片描述 添加節點4【6382】到集羣

#-a 後面跟的是密碼,如果沒有密碼則不需要-a參數 
#add-node 後面的參數形式 new_host:new_port existing_host:existing_port
./bin/redis-cli --cluster add-node 192.168.1.17:6382 192.168.1.17:6380 -a redispwd

在這裏插入圖片描述
給節點4【6382】分配槽點
查看節點信息:
在這裏插入圖片描述 節點添加成功後未分配槽點

./bin/redis-cli --cluster reshard 192.168.1.17:6379 -a redispwd

執行過程中有詢問

#準備挪出來多少個槽點
How many slots do you want to move (from 1 to 16384)? 800
#哪個節點準備接受新分配的槽點
What is the receiving node ID? 18936b87abadcb66135e243fa3fe49e88e8bbdc7
#準備從哪些節點上挪出這800(向上看這個數的來源)個槽點
Please enter all the source node IDs.
	# 所有節點
  Type 'all' to use all the nodes as source nodes for the hash slots.
  #指定節點
  Type 'done' once you entered all the source nodes IDs.
Source node #1: all
#是否執行reshare
Do you want to proceed with the proposed reshard plan (yes/no)? yes

在這裏插入圖片描述查看節點信息:
在這裏插入圖片描述節點擴容完成

使用redis-cli刪除節點

刪除節點需要經過以下兩步驟
1. 轉移槽點
這一步跟添加節點後的槽點一樣,大致過程爲,挪出來所需要的節點數 -> 選擇接收數據的節點 -> 選擇挪出的節點

#挪出多少槽點(5195),把6380節點挪出來,節點數在該詢問上面,不需要你計算
How many slots do you want to move (from 1 to 16384)? 5195
#哪個節點接收(18936b87abadcb66135e243fa3fe49e88e8bbdc7)6382節點接收
What is the receiving node ID? 18936b87abadcb66135e243fa3fe49e88e8bbdc7
#從哪挪
Please enter all the source node IDs.
 Type 'all' to use all the nodes as source nodes for the hash slots.
 Type 'done' once you entered all the source nodes IDs.
 #6380上挪,如果需要刪除多個節點,繼續回車填寫下一個就行,填寫完畢最後一個節點鍵入‘done’即可完成
Source node #1: 50a78a3daad0e95ed04e10ac2e115fbc3ff1f9da
Source node #2: done

在這裏插入圖片描述查看節點信息:
在這裏插入圖片描述
不再有槽點分配

2. 刪除節點

./bin/redis-cli --cluster del-node 192.168.1.17:6380 50a78a3daad0e95ed04e10ac2e115fbc3ff1f9da -a redispwd

在這裏插入圖片描述在這裏插入圖片描述節點已刪除
需要注意的是,當節點上分配的有槽點時是不允許刪除的
在這裏插入圖片描述

Cluster分區集羣在Springboot中的配置

1. pom引入

 <!-- springboot整合redis -->
  <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-data-redis</artifactId>
  </dependency>

2.yml配置(properties配置文件類型自行轉換)

spring:
  redis:
  # 集羣(分片)模式
    cluster:
      max-redirects: 3
      #節點
      nodes:
        - 192.168.1.17:6379
        - 192.168.1.17:6381
        - 192.168.1.17:6382
    # Redis服務器連接密碼(默認爲空)
    password: redispwd
    #jedis連接池信息僅供參考
    jedis:
      pool:
        #連接池最大連接數(使用負值表示沒有限制)
        max-active: 8
        # 連接池最大阻塞等待時間(使用負值表示沒有限制)
        max-wait: -1
        # 連接池中的最大空閒連接
        pool.max-idle: 8
        # 連接池中的最小空閒連接
        pool.min-idle: 0

3.封裝RedisTemplate MyRedisConfig.java


import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.boot.autoconfigure.data.redis.RedisProperties;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisClusterConfiguration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

import java.util.HashSet;

@Configuration
@EnableCaching
public class MyRedisConfig {

    @Bean
    public RedisClusterConfiguration redisClusterConfiguration(RedisProperties redisProperties){
        RedisClusterConfiguration redisClusterConfiguration = new RedisClusterConfiguration(new HashSet<>(redisProperties.getCluster().getNodes()));
        redisClusterConfiguration.setPassword(redisProperties.getPassword().toCharArray());
        return redisClusterConfiguration;
    }
    @Bean
    public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(redisConnectionFactory);
        // 使用Jackson2JsonRedisSerialize 替換默認的jdkSerializeable序列化
        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
        // 設置value的序列化規則和 key的序列化規則
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
        redisTemplate.afterPropertiesSet();
        return redisTemplate;
    }
    /**
     * 對redis字符串類型數據操作
     *
     * @param stringRedisTemplate
     * @return
     */
    @Bean({"valueoperations"})
    public ValueOperations<String, String> valueOperations(StringRedisTemplate stringRedisTemplate) {
        return stringRedisTemplate.opsForValue();
    }
}

4.測試Controller SysController.java


import com.platform.test.common.exception.BusinessException;
import com.platform.test.service.SysService;
import com.platform.test.vo.BaseRespVo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.redis.connection.RedisClusterConfiguration;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpSession;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.concurrent.TimeUnit;

@RestController
@RequestMapping("/sys")
public class SysController {
    static final Logger logger = LoggerFactory.getLogger(SysController.class);
    @Autowired
    @Qualifier("valueoperations")
    ValueOperations<String, String> valueOperations;
    @Autowired
    RedisClusterConfiguration redisClusterConfiguration;
    @Autowired
    RedisTemplate<Object,Object> redisTemplate;
    @Autowired
    SysService sysService;
    final static String REDIS_TEST_KEY_VALUE = "__REDIS_TEST_KEY_VALUE";

    @RequestMapping("/health")
    public BaseRespVo health(HttpSession session) throws BusinessException {
        SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
        HashMap<String, Object> data = new HashMap<>();
        data.put("time-server",sf.format(new Date()));
        data.put("status-redis",checkRedis());
        return new BaseRespVo(data);
    }

    private boolean checkRedis() {
        long time = System.currentTimeMillis();
        if(valueOperations == null){
            return false;
        }
        try {
            valueOperations.set(REDIS_TEST_KEY_VALUE+time,REDIS_TEST_KEY_VALUE,30000, TimeUnit.MILLISECONDS);
            logger.info("寫入redis key: "+ REDIS_TEST_KEY_VALUE+time +" value:"+REDIS_TEST_KEY_VALUE);
            Thread.sleep(100);
            String value = valueOperations.get(REDIS_TEST_KEY_VALUE+time);
            if (value!=null && REDIS_TEST_KEY_VALUE.equals(value)) {
                logger.info("讀取redis key: "+ REDIS_TEST_KEY_VALUE+time +" value:"+value);
                return true;
            }
        }catch (Exception e){
            logger.error("redis test exception!",e);
        }
        return false;
    }
}

執行結果:
在這裏插入圖片描述在這裏插入圖片描述
在這裏插入圖片描述

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