• Docker實戰之Redis-Cluster集群

    概述

    接上一篇Docker實戰之MySQL主從復制, 這里是Docker實戰系列的第二篇,主要進行Redis-Cluster集群環境的快速搭建。Redis作為基于鍵值對的NoSQL數據庫,具有高性能、豐富的數據結構、持久化、高可用、分布式等特性,同時Redis本身非常穩定,已經得到業界的廣泛認可和使用。

    在Redis中,集群的解決方案有三種

    1. 主從復制
    2. 哨兵機制
    3. Cluster

    Redis Cluster是Redis的分布式解決方案,在 3.0 版本正式推出。

    集群方案的對比

    1. 主從復制

    同Mysql主從復制的原因一樣,Redis雖然讀取寫入的速度都特別快,但是也會產生讀壓力特別大的情況。為了分擔讀壓力,Redis支持主從復制,讀寫分離。一個Master可以有多個Slaves。

    優點

    • 數據備份
    • 讀寫分離,提高服務器性能

    缺點

    • 不能自動故障恢復,RedisHA系統(需要開發)
    • 無法實現動態擴容

    2. 哨兵機制

    Redis Sentinel是社區版本推出的原生高可用解決方案,其部署架構主要包括兩部分:Redis Sentinel集群和Redis數據集群。

    其中Redis Sentinel集群是由若干Sentinel節點組成的分布式集群,可以實現故障發現、故障自動轉移、配置中心和客戶端通知。Redis Sentinel的節點數量要滿足2n+1(n>=1)的奇數個。

    優點

    • 自動化故障恢復

    缺點

    • Redis 數據節點中 slave 節點作為備份節點不提供服務
    • 無法實現動態擴容

    3. Redis-Cluster

    Redis Cluster是社區版推出的Redis分布式集群解決方案,主要解決Redis分布式方面的需求,比如,當遇到單機內存,并發和流量等瓶頸的時候,Redis Cluster能起到很好的負載均衡的目的。

    Redis Cluster著眼于提高并發量

    群集至少需要3主3從,且每個實例使用不同的配置文件。

    在redis-cluster架構中,redis-master節點一般用于接收讀寫,而redis-slave節點則一般只用于備份, 其與對應的master擁有相同的slot集合,若某個redis-master意外失效,則再將其對應的slave進行升級為臨時redis-master。

    在redis的官方文檔中,對redis-cluster架構上,有這樣的說明:在cluster架構下,默認的,一般redis-master用于接收讀寫,而redis-slave則用于備份,當有請求是在向slave發起時,會直接重定向到對應key所在的master來處理。 但如果不介意讀取的是redis-cluster中有可能過期的數據并且對寫請求不感興趣時,則亦可通過readonly命令,將slave設置成可讀,然后通過slave獲取相關的key,達到讀寫分離。具體可以參閱redis官方文檔等相關內容

    優點

    • 解決分布式負載均衡的問題。具體解決方案是分片/虛擬槽slot。
    • 可實現動態擴容
    • P2P模式,無中心化

    缺點

    • 為了性能提升,客戶端需要緩存路由表信息
    • Slave在集群中充當“冷備”,不能緩解讀壓力

    網絡規劃

    這里沒有搭建虛擬機環境,全部在本地部署。本機的ip為 192.168.124.5

    ip port
    192.168.124.5 7001
    192.168.124.5 7002
    192.168.124.5 7003
    192.168.124.5 7004
    192.168.124.5 7005
    192.168.124.5 7006

    Redis配置文件

    在docker環境中,配置文件映射宿主機的時候,(宿主機)必須有配置文件。附件在這里。大家可以根據自己的需求定制配置文件。

    下邊是我的配置文件 redis-cluster.tmpl

    # redis端口
    port ${PORT}
    # 關閉保護模式
    protected-mode no
    # 開啟集群
    cluster-enabled yes
    # 集群節點配置
    cluster-config-file nodes.conf
    # 超時
    cluster-node-timeout 5000
    # 集群節點IP host模式為宿主機IP
    cluster-announce-ip 192.168.124.5
    # 集群節點端口 7001 - 7006
    cluster-announce-port ${PORT}
    cluster-announce-bus-port 1${PORT}
    # 開啟 appendonly 備份模式
    appendonly yes
    # 每秒鐘備份
    appendfsync everysec
    # 對aof文件進行壓縮時,是否執行同步操作
    no-appendfsync-on-rewrite no
    # 當目前aof文件大小超過上一次重寫時的aof文件大小的100%時會再次進行重寫
    auto-aof-rewrite-percentage 100
    # 重寫前AOF文件的大小最小值 默認 64mb
    auto-aof-rewrite-min-size 64mb

    由于節點IP相同,只有端口上的差別,現在通過腳本 redis-cluster-config.sh 批量生成配置文件

    for port in `seq 7001 7006`; do \
      mkdir -p ./redis-cluster/${port}/conf \
      && PORT=${port} envsubst < ./redis-cluster.tmpl > ./redis-cluster/${port}/conf/redis.conf \
      && mkdir -p ./redis-cluster/${port}/data; \
    done

    生成的配置文件如下圖

    Docker環境搭建

    這里還是通過docker-compose進行測試環境的docker編排。

    version: '3.7'
    
    services:
      redis7001:
        image: 'redis'
        container_name: redis7001
        command:
          ["redis-server", "/usr/local/etc/redis/redis.conf"]
        volumes:
          - ./redis-cluster/7001/conf/redis.conf:/usr/local/etc/redis/redis.conf
          - ./redis-cluster/7001/data:/data
        ports:
          - "7001:7001"
          - "17001:17001"
        environment:
          # 設置時區為上海,否則時間會有問題
          - TZ=Asia/Shanghai
    
    
      redis7002:
        image: 'redis'
        container_name: redis7002
        command:
          ["redis-server", "/usr/local/etc/redis/redis.conf"]
        volumes:
          - ./redis-cluster/7002/conf/redis.conf:/usr/local/etc/redis/redis.conf
          - ./redis-cluster/7002/data:/data
        ports:
          - "7002:7002"
          - "17002:17002"
        environment:
          # 設置時區為上海,否則時間會有問題
          - TZ=Asia/Shanghai
    
    
      redis7003:
        image: 'redis'
        container_name: redis7003
        command:
          ["redis-server", "/usr/local/etc/redis/redis.conf"]
        volumes:
          - ./redis-cluster/7003/conf/redis.conf:/usr/local/etc/redis/redis.conf
          - ./redis-cluster/7003/data:/data
        ports:
          - "7003:7003"
          - "17003:17003"
        environment:
          # 設置時區為上海,否則時間會有問題
          - TZ=Asia/Shanghai
    
    
      redis7004:
        image: 'redis'
        container_name: redis7004
        command:
          ["redis-server", "/usr/local/etc/redis/redis.conf"]
        volumes:
          - ./redis-cluster/7004/conf/redis.conf:/usr/local/etc/redis/redis.conf
          - ./redis-cluster/7004/data:/data
        ports:
          - "7004:7004"
          - "17004:17004"
        environment:
          # 設置時區為上海,否則時間會有問題
          - TZ=Asia/Shanghai
    
    
      redis7005:
        image: 'redis'
        container_name: redis7005
        command:
          ["redis-server", "/usr/local/etc/redis/redis.conf"]
        volumes:
          - ./redis-cluster/7005/conf/redis.conf:/usr/local/etc/redis/redis.conf
          - ./redis-cluster/7005/data:/data
        ports:
          - "7005:7005"
          - "17005:17005"
        environment:
          # 設置時區為上海,否則時間會有問題
          - TZ=Asia/Shanghai
    
    
      redis7006:
        image: 'redis'
        container_name: redis7006
        command:
          ["redis-server", "/usr/local/etc/redis/redis.conf"]
        volumes:
          - ./redis-cluster/7006/conf/redis.conf:/usr/local/etc/redis/redis.conf
          - ./redis-cluster/7006/data:/data
        ports:
          - "7006:7006"
          - "17006:17006"
        environment:
          # 設置時區為上海,否則時間會有問題
          - TZ=Asia/Shanghai
    

    啟動結果如圖

    集群配置

    redis集群官方提供了配置腳本,4.x和5.x略有不同,具體可參見集群配置

    下邊是我自己的環境

    docker exec -it redis7001 redis-cli -p 7001 -a 123456 --cluster create 192.168.124.5:7001 192.168.124.5:7002 192.168.124.5:7003 192.168.124.5:7004 192.168.124.5:7005 192.168.124.5:7006 --cluster-replicas 1

    看到如下結果說明集群配置成功

    集群測試

    接下來進行一些集群的基本測試

    1. 查看集群通信是否正常

    redis7001主節點對它的副本節點redis7005進行ping操作。

    -h host -p port -a pwd

    ?  docker docker exec -it redis7001 redis-cli -h 192.168.124.5 -p 7005 -a 123456 ping
    
    Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
    PONG

    2. 測試簡單存儲

    redis7001主節點客戶端操作redis7003主節點

    ?  docker docker exec -it redis7001 redis-cli -h 192.168.124.5 -p 7003 -a 123456
    
    Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
    192.168.124.5:7003> set name admin
    (error) MOVED 5798 192.168.124.5:7002

    由于Redis Cluster會根據key進行hash運算,然后將key分散到不同slots,name的hash運算結果在redis7002節點上的slots中。所以我們操作redis7003寫操作會自動路由到7002。然而error提示無法路由?沒關系,差一個 -c 參數而已。

    再次運行查看結果如下:

    ?  docker docker exec -it redis7001 redis-cli -h 192.168.124.5 -p 7003 -a 123456 -c
    
    Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
    192.168.124.5:7003> set name admin
    -> Redirected to slot [5798] located at 192.168.124.5:7002
    OK
    192.168.124.5:7002> get name
    "admin"
    192.168.124.5:7002>

    3. 查看集群狀態

    4. 查看slots分片

    5. 查看集群信息

    6. 測試讀寫分離

    試試看,發現讀不到,原來在redis cluster中,如果你要在slave讀取數據,那么需要帶先執行 readonly 指令,然后 get key

    7. 簡單壓測

    選項 描述
    -t 指定命令
    -c 客戶端連接數
    -n 總請求數
    -d set、get的value大小(單位byte)

    測試如下

    ?  docker docker exec -it redis7001 bash
    root@cbc6e76a3ed2:/data# redis-benchmark -h 192.168.124.5 -p 7001 -t set -c 100 -n 50000 -d 20
    ====== SET ======
      50000 requests completed in 10.65 seconds
      100 parallel clients
      20 bytes payload
      keep alive: 1
    
    0.00% <= 2 milliseconds
    0.01% <= 3 milliseconds
    ...
    100.00% <= 48 milliseconds
    100.00% <= 49 milliseconds
    4692.63 requests per second

    這里沒啥實際意義,在工作業務上大家可以根據QPS和主機配置進行壓測,計算規劃出節點數量。

    容災演練

    現在我們殺掉主節點redis7001,看從節點redis7005是否會接替它的位置。

    docker stop redis7001

    再試著啟動7001,它將自動作為slave掛載到7005

    SpringBoot配置Redis集群

    在SpringBoot2.x版本中,redis默認的連接池已經更換為Lettuce,而不再是jedis。

    1. 在pom.xml中引入相關依賴
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-data-redis</artifactId>
            </dependency>
            <dependency>
                <groupId>org.apache.commons</groupId>
                <artifactId>commons-pool2</artifactId>
            </dependency>
    1. application.yml
    spring:
      redis:
        timeout: 6000
        password: 123456
        cluster:
          max-redirects: 3 # 獲取失敗 最大重定向次數 
          nodes:
            - 192.168.124.5:7001
            - 192.168.124.5:7002
            - 192.168.124.5:7003
            - 192.168.124.5:7004
            - 192.168.124.5:7005
            - 192.168.124.5:7006
        lettuce:
          pool:
            max-active: 1000 #連接池最大連接數(使用負值表示沒有限制)
            max-idle: 10 # 連接池中的最大空閑連接
            min-idle: 5 # 連接池中的最小空閑連接
            max-wait: -1 # 連接池最大阻塞等待時間(使用負值表示沒有限制)
      cache:
        jcache:
          config: classpath:ehcache.xml
    1. redis配置
    @Configuration
    @AutoConfigureAfter(RedisAutoConfiguration.class)
    public class RedisConfig {
        @Bean
        public RedisTemplate<String, Object> redisCacheTemplate(LettuceConnectionFactory redisConnectionFactory) {
            RedisTemplate<String, Object> template = new RedisTemplate<>();
            template.setKeySerializer(new StringRedisSerializer());
            template.setValueSerializer(new GenericJackson2JsonRedisSerializer());
            template.setConnectionFactory(redisConnectionFactory);
            return template;
        }
    }
    1. 基本測試
    @SpringBootTest
    public class RedisTest {
    
        @Autowired
        private RedisTemplate<String, String> redisTemplate;
    
        @Test
        public void test() {
            redisTemplate.opsForValue().set("name", "admin");
            String name = redisTemplate.opsForValue().get("name");
            System.out.println(name); //輸出admin
        }
    }

    總結

    通過以上演示,基本上可以在本地環境下用我們的Redis Cluster集群了。最后再上一張本地映射文件的最終樣子,幫助大家了解Redis持久化及集群相關的東西。感興趣的小伙伴可以自行測試并查看其中的內容。

    內容如有錯漏,還望大家不吝賜教,同時,歡迎大家關注公眾號【當我遇上你】,你們的支持就是我寫作的最大動力。

    參考

    • https://redis.io/topics/cluster-tutorial

    公眾號 【當我遇上你】

    posted @ 2020-03-01 19:17  當我遇上你csy  閱讀(...)  評論(...編輯  收藏
    贵州快三平台贵州快三主页贵州快三网站贵州快三官网贵州快三娱乐贵州快三开户贵州快三注册贵州快三是真的吗贵州快三登入贵州快三快三贵州快三时时彩贵州快三手机app下载贵州快三开奖 漳浦县 | 灵武市 | 石首市 | 巴彦县 | 合水县 | 静安区 | 博爱县 | 凤翔县 | 阿巴嘎旗 | 东安县 | 天祝 | 桃江县 | 湘阴县 | 宜州市 | 鲁山县 | 虞城县 | 滕州市 | 尼勒克县 | 申扎县 | 镇坪县 | 郁南县 | 栖霞市 | 曲沃县 | 平武县 | 家居 | 九龙坡区 | 汝阳县 | 梨树县 | 泸定县 | 湖州市 | 西和县 | 德惠市 | 开平市 | 米泉市 | 闻喜县 | 凤台县 | 临颍县 | 虞城县 | 开封市 | 慈利县 | 南乐县 | 宝丰县 | 镇江市 | 海门市 | 安国市 | 庆阳市 | 新宁县 | 淳安县 | 五寨县 | 潼南县 | 利辛县 | 日喀则市 | 罗山县 | 临城县 | 太康县 | 甘肃省 | 铜鼓县 | 毕节市 | 垫江县 | 辉南县 | 临沂市 | 改则县 | 张家港市 | 孝感市 | 纳雍县 | 丁青县 | 米脂县 | 秦皇岛市 | 景东 | 临桂县 | 慈利县 | 蒙城县 | 交口县 | 伊吾县 | 玉林市 | 高青县 | 右玉县 | 南华县 | 浮梁县 | 中西区 | 荥阳市 | 治多县 | 浦江县 | 荥经县 | 义乌市 | 梧州市 | 聂拉木县 | 曲周县 | 安溪县 | 滕州市 | 广东省 | 衡南县 | 邵阳县 | 兴山县 | 武宁县 | 昌图县 | 呼和浩特市 | 莱西市 | 鄂伦春自治旗 | 颍上县 | 安平县 | 潼关县 | 临颍县 | 肃北 | 凤翔县 | 莱芜市 | 策勒县 | 合肥市 | 若尔盖县 | 垣曲县 | 宁津县 | 龙陵县 | 牡丹江市 | 景德镇市 | 北海市 | 米林县 | 伽师县 | 巴楚县 | 普安县 | 大关县 | 宁南县 | 石渠县 | 蕉岭县 | 山东省 | 盘锦市 | 伊吾县 | 商丘市 | 大港区 | 边坝县 | 宁都县 | 奇台县 | 巨野县 | 同心县 | 姜堰市 | 礼泉县 | 集贤县 | 兴义市 | 耿马 | 壶关县 | 温州市 | 濮阳县 | 郴州市 | 普定县 | 榆林市 | 应用必备 | 乡宁县 | 保定市 | 昌平区 | 阜康市 | 沾益县 | 宁明县 | 吉安县 | 徐汇区 | 西吉县 | 会同县 | 长岭县 | 金秀 | 荣成市 | 东城区 | 永州市 | 阿拉尔市 | 黄山市 | 松潘县 | 沿河 | 西乌珠穆沁旗 | 城口县 | 曲麻莱县 | 晋城 | 汉沽区 | 克拉玛依市 | 九台市 | 白山市 | 安泽县 | 和龙市 | 东丰县 | 唐海县 | 革吉县 | 三台县 | 东明县 | 五台县 | 乐业县 | 开原市 | 钟山县 | 扎赉特旗 | 北碚区 | 逊克县 | 苍溪县 | 海城市 | 新田县 | 镇康县 | 盐山县 | 宣城市 | 茌平县 | 湘潭市 | 太康县 | 淮阳县 | 常宁市 | 潮安县 | 秭归县 | 铅山县 | 涟水县 | 抚松县 | 区。 | 惠东县 | 文水县 | 田林县 | 大港区 |