分析redis的各種使用情景

使用docker-compose演示redis的各種使用情景,最後介紹了codiskubernetes方案

總結

模式 特點
單機版-RDB 備份快,但數據可能不完整
單機版-AOF 備份慢,但是數據比較完整
1主N從 讀寫分離的典範
樹狀主從(N級緩存) 爲了規避主重啓導致的大規模全量複製,但是需要維持每一箇中間master的健康
主從自動切換(Sentinel) 在主從的基礎上加了Sentinel角色,通過Sentinel實現主從的自動切換
集羣(N主N從) 基於slot的key分片,客戶端支持得不是很多,所以用的人不多

單機版

RDB模式(默認模式)

定期快照模式

version: '3'
services:   
    redis-master: 
        image: redis
        ports: 
        - "12660:6379"
        expose:
          - "6379"
        networks:
        - default        
        entrypoint:
        - redis-server
        volumes:
          - ./data:/data

AOF模式

逐一寫入,數據比較完整,文件較大,但恢復較慢

version: '3'
services:   
    redis-master: 
        image: redis
        ports: 
        - "12660:6379"
        expose:
          - "6379"
        networks:
        - default        
        entrypoint:
        - redis-server 
        - --appendonly yes
        volumes:
          - ./data:/data

主從複製版

1主N從

這種模式簡單粗暴,但是master一旦重啓,多從節點全量複製,IO將會比較繁重

version: '3'
services:   
    redis-master: 
        image: redis
        ports: 
        - "12660:6379"
        expose:
          - "6379"
        networks:
        - default        
        entrypoint:
        - redis-server 
        - --save 1 1
        volumes:
          - ./data:/data
    redis-slave1: 
        image: redis
        ports: 
        - "12661:6379"
        expose:
          - "6379"        
        networks:
        - default             
        entrypoint:
        - redis-server 
        - --slaveof redis-master 6379
        - --slave-serve-stale-data yes
        #當從機與主機斷開連接時,或者當複製仍在進行時,slave仍然會回覆client請求, 儘管數據可能會出現過期或者如果這是第一次同步,數據集可能爲空。
        - --slave-read-only yes
        #0作爲一個特殊的優先級,標識這個slave不能作爲master 
        - --slave-priority 100
    redis-slave2: 
        image: redis
        ports: 
        - "12662:6379"
        expose:
          - "6379"            
        entrypoint:
        - redis-server         
        - --slaveof redis-master 6379
        - --slave-serve-stale-data yes
        #當從機與主機斷開連接時,或者當複製仍在進行時,slave仍然會回覆client請求, 儘管數據可能會出現過期或者如果這是第一次同步,數據集可能爲空。
        - --slave-read-only yes
        #0作爲一個特殊的優先級,標識這個slave不能作爲master 
        - --slave-priority 100

樹狀主從(N級緩存)

從節點作爲主節點.

這種模式規避了單master

version: '3'
services:   
    redis-master: 
        image: redis
        ports: 
        - "12660:6379"
        expose:
          - "6379"
        networks:
        - default        
        entrypoint:
        - redis-server 
        - --save 1 1
        volumes:
          - ./data:/data
    redis-slave1: 
        image: redis
        ports: 
        - "12661:6379"
        expose:
          - "6379"        
        networks:
        - default             
        entrypoint:
        - redis-server 
        - --slaveof redis-master 6379
        - --slave-serve-stale-data yes
        #當從機與主機斷開連接時,或者當複製仍在進行時,slave仍然會回覆client請求, 儘管數據可能會出現過期或者如果這是第一次同步,數據集可能爲空。
        - --slave-read-only yes
        #0作爲一個特殊的優先級,標識這個slave不能作爲master 
        - --slave-priority 100
        # - --masterauth xxx
    redis-slave2: 
        image: redis
        ports: 
        - "12662:6379"
        expose:
          - "6379"            
        entrypoint:
        - redis-server         
        - --slaveof redis-slave1 6379
        - --slave-serve-stale-data yes
        #當從機與主機斷開連接時,或者當複製仍在進行時,slave仍然會回覆client請求, 儘管數據可能會出現過期或者如果這是第一次同步,數據集可能爲空。
        - --slave-read-only yes
        #0作爲一個特殊的優先級,標識這個slave不能作爲master 
        - --slave-priority 100
        # - --masterauth xxx

主從自動切換(Sentinel模式)

這時需要引入 Sentinel 的概念

Redis 的 Sentinel 系統用於管理多個 Redis 服務器(instance), 該系統執行以下三個任務:

  1. 監控(Monitoring): Sentinel 會不斷地檢查你的主服務器和從服務器是否運作正常。
  2. 提醒(Notification): 當被監控的某個 Redis 服務器出現問題時, Sentinel 可以通過 API 向管理員或者其他應用程序發送通知。
  3. 自動故障遷移(Automatic failover): 當一個主服務器不能正常工作時, Sentinel 會開始一次自動故障遷移操作, 它會將失效主服務器的其中一個從服務器升級爲新的主服務器, 並讓失效主服務器的其他從服務器改爲複製新的主服務器; 當客戶端試圖連接失效的主服務器時, 集羣也會向客戶端返回新主服務器的地址, 使得集羣可以使用新主服務器代替失效服務器。

默認的Sentinel配置去掉註釋後長這樣

port 26379
daemonize no
pidfile /var/run/redis-sentinel.pid
logfile ""
dir /tmp
# 監視主服務器,下線master需要2個Sentinel同意
sentinel monitor mymaster redis-master 6379 2
# 30秒內有效回覆視爲master健康,否則下線
sentinel down-after-milliseconds mymaster 30000
# 故障轉移時,從服務器同部數最大值
sentinel parallel-syncs mymaster 1
# 1. 同一個sentinel對同一個master兩次failover之間的間隔時間。
# 2. 當一個slave從一個錯誤的master那裏同步數據開始計算時間。直到slave被糾正爲向正確的master那裏同步數據時。
# 3.當想要取消一個正在進行的failover所需要的時間。  
# 4.當進行failover時,配置所有slaves指向新的master所需的最大時間。不過,即使過了這個超時,slaves依然會被正確配置爲指向master,但是就不按parallel-syncs所配置的規則來了。
sentinel failover-timeout mymaster 90000

基本格式是sentinel <選項的名字> <主服務器的名字> <選項的值>

原本我想通過docker-compose up --scale redis-sentinel=3直接啓動3個容器,結果發現這容器竟然會修改配置文件,所以只能分開寫了

初版

# docker-compose up --scale redis-sentinel=3 雖然可以啓動,但是3個容器同時寫同一個文件,感覺不是很好
version: '3'
services:   
    redis-master: 
        image: redis
        ports: 
        - "12660:6379"
        expose:
          - "6379"  
        entrypoint:
        - redis-server 
        - --save 1 1
        volumes:
          - ./data:/data
        # 重啓策略改爲no手動讓他宕機模擬主從切換
        restart: "no"
    redis-slave1: 
        image: redis
        ports: 
        - "12661:6379"
        expose:
          - "6379"          
        entrypoint:
        - redis-server 
        - --slaveof redis-master 6379
        - --slave-serve-stale-data yes
        #當從機與主機斷開連接時,或者當複製仍在進行時,slave仍然會回覆client請求, 儘管數據可能會出現過期或者如果這是第一次同步,數據集可能爲空。
        - --slave-read-only yes
        #0作爲一個特殊的優先級,標識這個slave不能作爲master 
        - --slave-priority 100
        # - --masterauth xxx
    redis-slave2: 
        image: redis
        ports: 
        - "12662:6379"
        expose:
          - "6379"            
        entrypoint:
        - redis-server         
        - --slaveof redis-slave1 6379
        - --slave-serve-stale-data yes
        #當從機與主機斷開連接時,或者當複製仍在進行時,slave仍然會回覆client請求, 儘管數據可能會出現過期或者如果這是第一次同步,數據集可能爲空。
        - --slave-read-only yes
        #0作爲一個特殊的優先級,標識這個slave不能作爲master 
        - --slave-priority 100
        # - --masterauth xxx
    redis-sentinel:
        image: redis
        expose:
          - "26379"
        entrypoint:
        - redis-server
        - /usr/local/etc/redis/redis.conf
        - --sentinel
        volumes:
        - ./redis-sentinel.conf:/usr/local/etc/redis/redis.conf

最終版:

version: '3'
services:   
    redis-master: 
        image: redis
        ports: 
        - "12660:6379"
        expose:
          - "6379"  
        entrypoint:
        - redis-server 
        - --save 1 1
        volumes:
          - ./data:/data
        # 重啓策略改爲no手動讓他宕機模擬主從切換
        restart: "no"
    redis-slave1: 
        image: redis
        ports: 
        - "12661:6379"
        expose:
          - "6379"          
        entrypoint:
        - redis-server 
        - --slaveof redis-master 6379
        - --slave-serve-stale-data yes
        #當從機與主機斷開連接時,或者當複製仍在進行時,slave仍然會回覆client請求, 儘管數據可能會出現過期或者如果這是第一次同步,數據集可能爲空。
        - --slave-read-only yes
        #0作爲一個特殊的優先級,標識這個slave不能作爲master 
        - --slave-priority 100
        # - --masterauth xxx
    redis-slave2: 
        image: redis
        ports: 
        - "12662:6379"
        expose:
          - "6379"            
        entrypoint:
        - redis-server         
        - --slaveof redis-slave1 6379
        - --slave-serve-stale-data yes
        #當從機與主機斷開連接時,或者當複製仍在進行時,slave仍然會回覆client請求, 儘管數據可能會出現過期或者如果這是第一次同步,數據集可能爲空。
        - --slave-read-only yes
        #0作爲一個特殊的優先級,標識這個slave不能作爲master 
        - --slave-priority 100
        # - --masterauth xxx
    redis-sentinel1:
        image: redis
        expose:
          - "26379"
        entrypoint:
        - redis-server
        - /usr/local/etc/redis/redis.conf
        - --sentinel
        volumes:
        - ./redis-sentinel1.conf:/usr/local/etc/redis/redis.conf
    redis-sentinel2:
        image: redis
        expose:
          - "26379"
        entrypoint:
        - redis-server
        - /usr/local/etc/redis/redis.conf
        - --sentinel
        volumes:
        - ./redis-sentinel2.conf:/usr/local/etc/redis/redis.conf
    redis-sentinel3:
        image: redis
        expose:
          - "26379"
        entrypoint:
        - redis-server
        - /usr/local/etc/redis/redis.conf
        - --sentinel
        volumes:
        - ./redis-sentinel3.conf:/usr/local/etc/redis/redis.conf

sentinel啓動之後,配置發生了變化

這些內容沒了

sentinel monitor mymaster redis-master 6379 2
sentinel down-after-milliseconds mymaster 30000
sentinel parallel-syncs mymaster 1

變成

sentinel myid 3ae98d6815c1a9b941f8283b7e48bfeef7435905
sentinel deny-scripts-reconfig yes
# Generated by CONFIG REWRITE
sentinel config-epoch mymaster 0
sentinel leader-epoch mymaster 0
sentinel known-replica mymaster 172.24.0.4 6379
sentinel known-sentinel mymaster 172.24.0.7 26379 19ac7e0519e3c30a75e23bac34a7033594256c54
sentinel known-sentinel mymaster 172.24.0.5 26379 c596734a7f55ba2b6c7e3e81562aa6687e45fdeb
sentinel current-epoch 0

之後通過docker psdocker stop手動停掉了master那個容器,sentinel發覺了,並重新選主.

此時通過redis-cli輸入info,發現它已經成功變成了可以寫入數據的master

# Generated by CONFIG REWRITE
sentinel config-epoch mymaster 1
sentinel leader-epoch mymaster 1
sentinel known-replica mymaster 172.24.0.3 6379
sentinel known-replica mymaster 172.24.0.2 6379
sentinel known-sentinel mymaster 172.24.0.7 26379 19ac7e0519e3c30a75e23bac34a7033594256c54
sentinel known-sentinel mymaster 172.24.0.5 26379 c596734a7f55ba2b6c7e3e81562aa6687e45fdeb
sentinel current-epoch 1

此時重啓master,雖然他以server形式啓動,但是角色已經自動被貶爲slave.

此時master沒有變化,所以sentinel的配置內容沒有變

集羣版(N主N從)

集羣基於16384個slot做分片.目前各語言客戶端實現比較少.所以用的人不是很多.

在docker中運行時,需要使用host網絡模式(--net=host)

redis-trib.rb

redis版本<5時,可以用redis-trib.rb建集羣

./redis-trib.rb create --replicas 1 127.0.0.1:7000 127.0.0.1:7001 \
127.0.0.1:7002 127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005

# 引入新節點
./redis-trib.rb add-node 127.0.0.1:7006 <任意節點IP>:<節點端口>

# 重新分片
./redis-trib.rb reshard <任意節點IP>:<節點端口>

redis-cli

=5直接用redis-cli即可.

redis-cli --cluster create 127.0.0.1:7000 127.0.0.1:7001 \
127.0.0.1:7002 127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005 \
--cluster-replicas 1
redis-cli --cluster reshard 127.0.0.1:7000
redis-cli reshard <host>:<port> --cluster-from <node-id> --cluster-to <node-id> --cluster-slots <number of slots> --cluster-yes
redis-cli --cluster add-node 127.0.0.1:7006 127.0.0.1:7000
# Adding a new node as a replica
redis-cli --cluster add-node 127.0.0.1:7006 127.0.0.1:7000 --cluster-slave
redis-cli --cluster add-node 127.0.0.1:7006 127.0.0.1:7000 --cluster-slave --cluster-master-id 3c3a0c74aae0b56170ccb03a76b60cfe7dc1912e
redis-cli --cluster del-node 127.0.0.1:7000 `<node-id>`

集羣指令

CLUSTER REPLICATE <master-node-id>
cluster nodes

Kubernetes

個人覺得吧,redis跟Kubernetes不是特別契合.kubernetes本身有網絡瓶頸的問題,通過svc去訪問,頻繁DNS解析也不好對吧.這對於高頻訪問redis的場景來說是致命的.

而且pod這種易失架構註定了在Kubernetes上面用redis要麼用數據卷掛載,要麼用主從自動切換模式(純內存的話至少要1主2從,並且用反親和度錯開彼此的運行節點).

主從和單機版倒好解決,單機的話掛載好數據卷,主從的話,主和從分開2個deploy/statefulset部署即可.

但是集羣版就比較麻煩.官方的設計還是偏向於傳統二進制人工運維,沒有做到雲原生

看了一下官方的helm chart,也是用的主從模式.

codis

codis是redis集羣沒出來之前,豌豆莢團隊做的一個方案,通過proxy,隔離了後端的redis集羣

優點

  1. 支持Kubernetes
  2. 有web圖形界面,方便運維
  3. Redis獲得動態擴容/縮容的能力,增減redis實例對client完全透明、不需要重啓服務

缺點

  1. 穩定性堪憂
  2. 依賴於國內的豌豆莢團隊開發,迭代速度較慢
  3. 原版的docker鏡像較大,沒有根據組件進行分開
  4. 基於redis 3.x,而且很多原生的redis指令被閹割了
  5. 強依賴註冊中心(Zookeeper、Etcd、Fs)

我們用了幾個月吧,到後期頻繁出現

ERR handle response, backend conn reset

此外,日常觀察發現pod退出/重啓困難.如果某個group節點全部掛掉的話,整個集羣將不可讀寫.

綜上,codis已經影響到了嚴重影響到了我們程序的正確性,決定棄用codis.改爲普通的1主N從的模式.

主掛了之後導致服務不可用 #1356

參考鏈接

  1. 【Redis筆記】 第4篇: redis.conf中Replication配置項說明
  2. Redis 配置文件詳解
  3. redis命令參考
  4. redis主從複製常見的一些坑
  5. Redis 的各項功能解決了哪些問題?
  6. 集羣教程
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章