Redis 開發與運維

Getting Start

高性能

  • 性能優點的體現
    1. C語言實現的內存管理
    2. epoll的I/O多路複用技術+IO鏈接/關閉/讀寫經過事件實現異步的非阻塞IO
    3. TCP協議
    4. 單線程架構,不會由於高併發對服務器形成太多壓力
    5. Redis內部不支持序列化
    6. 上面幾個特性保證了Redis的高併發性能
    7. 性能指標
      1. 單點併發量:壓力測試
      2. 命令處理速度:每秒數萬次操做
      3. key的數量對性能的影響
      4. 內存大小對性能的影響
  • 單線程架構
    1. Redis提供了不少API,單線程架構不須要擔憂一些API對數據操做的一致性問題
    2. 不會由於高併發對服務器形成太多壓力,從而使得Redis能夠擁有更復雜更豐富的API
    3. Redis被設計爲面向快速執行場景的緩存數據庫應用,內存的讀寫性能自己夠快,多線程帶來的提高在線程切換的影響下並非那麼明顯,單線程避免了線程切換的消耗
    4. epoll的I/O多路複用技術+IO鏈接/讀寫/關閉經過事件實現異步的非阻塞IO,也是性能的保障之一
    5. 綜上所述,選擇單線程已經夠快了(每秒數萬次操做),不須要使用多線程來提速,效果不明顯,複雜度增長
    6. 單線程的弊端
      1. 某個耗時操做會阻塞其它命令的執行
      2. 因此redis使用必須注意單個操做的快速執行特色
      3. 要特別注意耗時API的使用,不然豐富的API反而會成爲Redis的弊端
    7. 單線程架構的優化
      1. 能夠經過大規模服務集羣+耗時優先的負載均衡策略來減少單線程架構帶來的問題
        1. 對服務器內存的消耗會很大,要適度使用
      2. 能夠在同一臺服務器上面部署多個實例,發揮多核CPU的優點
  • 建議用戶直接經過客戶端訪問Redis,不要經過中間服務
    1. 發揮Redis高併發優點, 除非中間服務可以支持高併發,而且服務資源足夠
    2. 客戶端可以發揮更多的Redis豐富的API優點,除非中間服務徹底支持這些API的定製使用要求
    3. 若是用戶爲單個服務定製Redis中間服務,也是好的架構方式,這個與EhCache/Liberator等客戶端服務設計理念同樣

對外數據結構和內部編碼實現

  • 改進或添加內部實現而不影響外部使用
  • 經過配置選項啓用不一樣內部實現

使用場景

  • 做爲高可用二級緩存使用,與其餘數據庫配合
  • 做爲小型高性能數據庫使用

特色

  • 只能作分佈式存儲,不能作全量數據節點的負載均衡
  • 集羣節點經過維護其餘全部節點信息來實現服務發現與故障轉移

下載安裝

  • 源碼安裝
    1. 安裝gcc
    2. 官網: https://redis.io/download
  • rpm安裝
    1. root rpm 安裝 jemalloc
    2. root rpm 安裝 redis
  • 版本
    1. Linux版本模式,偶數爲穩定版

基本操做API

啓停命令

  • redis-cli -v :檢查版本
  • redis-cli -h host -p port save : 持久化
  • 指定參數運行redis
    1. 指定port
      1. src/redis-server --port 8888
    2. 指定持久化目錄
      1. dir
      2. 默認./,可能會遇到寫權限問題致使退出失敗
    3. 指定日誌文件
      1. logfile
    4. 指定配置文件: 配置文件通常又本身集中管理
      1. src/redis-server /path/redis.conf
  • 指定參數中止redis
    1. redis-cli -h host -p port shutdown
    2. 所作的事情
      1. 斷開客戶端鏈接
      2. 生成持久化文件
    3. 經過kill -9起不到上述做用
  • 鏈接,操做Redis
    1. 交互式
      1. redis-cli -h host -p port
      2. set key value
      3. get key
    2. 命令式
      1. redis-cli -h host -p port set key value
    3. 開啓redis-cli客戶端自動重定向
      1. redis-cli -c

Key管理命令

  • rename/renamenx key newname
    1. renamenx 只在newname不存在的時候
    2. value過大可能形成堵塞
  • randomkey
  • exists key1
  • del key1 key2
  • type key1 : 查看對外數據結構
  • object encoding key1 : 查看內部編碼實現

過時

  • expire key seconds: 設置過時時間
  • pexpire key millisenconds : 毫秒後過時
  • expireat key timestamp : 某個時間後過時
  • pexpireat key millisenconds-timestamp : 毫秒級timestamp後過時
  • ttl/pttl key1 : 查看剩餘存活時間
  • persist : 清除過時時間
  • 字符串類型的key在set後會清除過時時間
  • 二級數據結構,不支持內部value的過時時間
  • setex 是原子執行

數據遷移

  • 在同一個Redis的不一樣db間進行數據遷移
    1. move key db :
  • 在不一樣Redis實例中進行數據遷移
    1. dump key + restore key ttl value
      1. dump將數據序列化
      2. restore反序列化, ttl爲過時時間,value爲序列化後的值
    2. migrate host port key destination-db timeout [COPY] [REPLACE] [keys]
      1. destination-db : 數據庫索引,好比0
      2. copy 遷移後不刪除原來數據
      3. replace 目標存在也會覆蓋
      4. keys 遷移多個key,須要設置key爲""

遍歷

  • keys pattern
    1. *,?
    2. [] : [1,4],[1-4]
    3. \x : 轉義
    4. xargs
      1. redis-cli keys key1* | xargs redis-cli del
      2. 不支持*的全量?
      3. 不支持交互式?
  • scan cursor [MATCH pattern] [COUNT count]
    1. cursor:遊標,每次scan返回當前遊標,下次從當前開始,返回0說明完成了
    2. COUNT : 每次的個數,默認10
    3. hscan->hgetall, sscan->smenbers, zscan->zrange
    4. scan過程當中若是存在改動,會影響scan結果的完整性

數據庫管理

  • Redis一個實例能夠存在多個獨立不相關的數據庫,可是建議不使用這種方式,用多個實例的方式來代替多數庫
    1. 單線程架構使得多數據庫使用單一CPU,發揮不了多核的優點
    2. 不一樣數據庫的查詢會相互阻塞,並且問題難以定位
    3. select dbIndex
  • flushdb/flushall
    1. 清除數據庫
  • dbsize, 複雜度是O(1)

配置

  • config set key value
  • config get key
  • config rewite

可能會形成阻塞的命令 : 能夠在副本上面執行阻塞命令

  • keys
  • hgetall key
  • lrange start end
  • smembers key
  • flushdb/flushall

5種數據結構以及API

字符串

  • 特色
    1. 包括字符串,數字,JSON,序列化信息,二進制等
    2. 最大size 512MB
    3. 直接使用字符串
      1. 簡單直觀,能作最細粒度的操做
      2. key的數量龐大,內存開銷大
      3. 信息內聚性差
    4. JSON或者序列化
      1. 只供顯示用的時候性能好,最方便
      2. 轉換過程形成開銷
      3. 操做粒度太粗
  • API
    1. set/setnx/setex/get
    2. mset/mget : 批量存取
    3. 自增加/自減
      1. incr/decr/incrby/decrby/incrbyfloat
    4. append key value
    5. strlen key
    6. getset 返回上一個值
    7. setrange key offest value : 替換指定字符
    8. getrange key start end : 獲取部分字符
  • 內部編碼
    1. int : 8字節
    2. embstr : <= 39字節
    3. war : > 39字節
    4. 根據長度和值自動選擇內部編碼
  • 使用場景
    1. 計數功能 : incr
    2. 限速功能 : 1分鐘5次
      1. set key 1 EX 60 NX
      2. incr key <= 5

Hash : 傳統關係型數據庫的替代方案,打破關係

  • 特色
    1. key:field:value形式,至關於兩級Map
    2. 相比於使用key:json的形式,更加直觀,操做更方便高效
    3. 相比於使用key-field:value的形式,key的數量更少,內存消耗小
    4. 相比於關係型數據庫
      1. 非結構化的數據類型,每一個key能夠有不一樣的field,更靈活
      2. 關係型數據庫能夠作複雜的關聯查詢,Redis實現則很困難
    5. 要充分利用hash/json的優勢,作出最優選擇
  • API
    1. hset key field value
  • 內部編碼
    1. ziplist
      1. 連續存儲,從而節省內存,讀寫比hashtable滿
      2. field個數<512,全部的field值小於64字節
    2. hashtable
      1. 讀寫複雜度爲O(1)

List : 與順序相關的存儲

  • 特色
    1. 有序
    2. 支持不少list操做
  • API
    1. lpust.rpush key value
    2. lrang key start end
  • 內部編碼
    1. ziplist
    2. linkedlist
    3. quicklist : linkedlist 的value 是 ziplist
  • 使用場景
    1. 簡單的消息隊列功能
      1. lpust + brpop
      2. 可啓用多個消費者
    2. 分頁功能
      1. lrang
    3. 按序號查找/修改/刪除

Set : 集合間操做/隨即選擇/去重複

  • 特色
    1. 無序
    2. 無重複
  • API
    1. sadd key
    2. smembers
    3. 支持集合的交集/並集/差集,並可保存結果
  • 內部編碼
    1. intset
    2. hashtable

有序集合 : 按分數排序

  • 特色
    1. 按分數排序
  • API
    1. zadd key score member
    2. zrange key start end
    3. 支持集合的交集/並集/差集
      1. 支持sum/min/max, 默認sum
      2. 可保存結果
  • 內部編碼
    1. ziplist
    2. skiplist
  • 使用場景
    1. 排行榜

特殊功能API

慢查詢

  • 配置
    1. slowlig-log-slower-than : 默認10000
    2. slowlog-max-len : 默認128
  • API
    1. slowlog get/len/reset

發佈訂閱

  • API
    1. publish channel message
    2. subscribe/unsubscribe channels
    3. psubscribe/punsubscribe channel-pattern
      1. 支持*等通配符訂閱
    4. pubsub
      1. channels [pattern] : 查看有訂閱的消息通道
      2. numsub channel : 查看訂閱數量
      3. numpat : 查看經過psubscribe模式訂閱的數量
  • 特性 : 簡單
    1. 不支持消費分區
    2. 不支持消費組,沒法作分佈式消費
    3. 發佈的消息不作持久化

Pipeline

  • 一次組裝的命令個數要適量
  • 只能操做一個Redis實例

GEO

  • geoadd key longitude latitude member
  • geopos key member
  • GEODIST key member1 member2 [unit]
    1. 相同key的地理位置的距離
    2. unit : m/km/mi/ft
  • GEORADIUS/GEORADIUSBYMEMBER key member radius [unit]
    1. 以member 或者經緯度爲中心獲取指定半徑內的member
  • geohash
  • zrem key member
    1. 刪除

事務與Lua

  • 簡單的事務
    1. multi/exec/discard
    2. 不提供運行時錯誤的回滾,只支持命令語法錯誤檢查後不執行
    3. watch key : 在multi以前執行,保證被改動的狀況下事務不執行key相關操做
  • Lua
    1. 經過Lua腳本語言批量執行Redis API

Bitmaps

HyperLogLog

Redis Shell

Redis監控API

客戶端管理

  • CLIENT SETNAME name
  • CLIENT KILL host:port
  • CLIENT PAUSE 10000
    1. 阻塞毫秒數
    2. 不阻塞主從複製,因此能夠用於讓主從複製更上節奏,從而保持一致
  • client list
    1. 獲取客戶端信息,包括 id,name,db
    2. age(存活時間),idle(最近一次空閒時間)
      1. age與idle相近書面client一直空閒可是沒有關閉鏈接
    3. qbuf/qbuf-free
      1. 輸入緩衝區的大小與free
    4. obl/ollomem
      1. 輸出緩衝區的 obl(固定緩衝區的字節長度
      2. oll(動態緩衝區的對象數)
      3. omem(輸出緩衝區使用的大小)
    5. flag :
      1. 客戶端類型 N(Nomel)/M(Master)/S(Slave)等等
    6. sub/psub
      1. 訂閱的消息通道數量
    7. cmd
      1. 最後一次執行的命令

info信息查詢

  • info 統計全部信息
  • info clients
    1. client鏈接數/輸出輸入緩衝區最大值/阻塞的client數
  • info stats
    1. latest_fork_usec : 最近一個fork操做的耗時
  • info Persistence 持久化信息
    1. rdb_last_save_time : 最後一次生成RDB的時間,等同於lastsave API
  • info replication : 主從複製相關信息

monitor

  • 用於監控其餘全部客戶端的操做
  • 會由於輸出緩衝過大的內存問題

2種持久化

RDB

  • bgsave
    1. 主進程fork一個新的子進程來save數據
    2. 不會阻塞Redis,阻塞只發生在fock階段,fock操做通常耗時在每GB 20毫秒左右,建議每一個Redis實例控制在10GB
    3. 觸發gbsave
      1. 配置save m n
      2. shutdown
      3. 主從全量複製
      4. debug reload從新加載redis
  • 優勢
    1. 壓縮的二進制文件,對文件作替換(AOF是作追加),適合全量複製
    2. Load數據速度比AOF快不少
  • 缺點
    1. fork操做消耗比較大,沒法作到秒級別的實時持久化
  • RDB配置
    1. 觸發bgsave配置
      1. save 900 1 : 900秒內有一次數據更新觸發bgsave
      2. save 300 10
      3. save 60 10000
    2. dir :持久化文件目錄
    3. dbfilename : 持久化文件名字
    4. rdbcompression yes
      1. 是否開啓LZF算法對持久化文件進行壓縮
      2. 若是想減輕CPU壓力,能夠設置爲no
    5. rdbchecksum yes
      1. save和load數據時是否對文件進行校驗
      2. 會有10%左右的性能消耗,設置no開啓最高性能

AOF

  • 開啓AOF
    1. appendonly yes : 開啓AOF持久化方式
    2. appendfilename "appendonly.aof" : AOF文件
    3. aof-load-truncated yes : 重啓加載時兼容結尾不完整的AOF文件
  • 寫入命令
    1. 以獨立日誌的方式記錄每次命令,經過從新執行全部命令來load數據
    2. 以Redis協議格式寫入文本,避免二次處理開銷
    3. 命令寫入AOF緩衝,提升性能
  • 文件同步
    1. write() : 將命令寫入AOF緩衝aof_buf,而後返回,系統決定何時寫入硬盤,系統故障會形成數據丟失
    2. fsync() : 阻塞,作強制的硬盤寫入,和fsync/write由操做系統提供支持
    3. appendfsync
      1. always : 每次都調用fsync(),最安全,性能最低,通常不推薦
      2. no : 每次只調用write(),不安全,但性能最高,同步週期可長達30秒左右
      3. everysec : 每次只調用write(),每秒鐘調用一次fsync(),組合安全性和性能,默認配置
        1. everysec雖然不是像always那樣每次都阻塞主線程,但也不像no那樣每次都直接返回
        2. 他會開啓另外一個線程進行fsync(),Redis並不是徹底單線程
        3. 主線程會分析fsync線程,若是距離上次成功小於2秒,直接返回,不然阻塞
        4. 全部everysec最多丟失2秒數據,而不是1秒
  • 重寫機制
    1. 觸發重寫
      1. 手動調用bgrewriteaof命令
      2. 自動觸發重寫
        1. auto-aof-rewrite-min-size 64mb : AOF文件(aof_current_size)大於64M纔會觸發
        2. auto-aof-rewrite-percentage 100 : (aof_current_size - aof_base_size(上一次重寫後的size)) / aof_base_size > 100%
    2. 重寫過程
      1. bgrewriteaof,主進程fork子進程進行從新,fork消耗於bgsave同樣
        1. 重寫操做原理
          1. 過濾超時的數據
          2. 使用內存中的數據從新寫入AOF文件,多餘的舊命令就不存在了
          3. 合併操做,爲防止客戶端緩衝區溢出,以64個元素爲界進行合併
        2. aof-rewrite-incremental-fsync yes : AOF重寫每次批量寫入32M數據到AOF文件,防止磁盤阻塞
      2. 主進程依然響應client請求,原來的AOF流程依然進行,並保存在舊的AOF文件裏
        1. no-appendfsync-on-rewrite yes :在rewrite過程當中。不會調用fsync(),以保證fsync不會被阻塞,可是可能會丟失數據
      3. aof_buf的數據也會保存在到aof_rewrite_buf(AOF重寫緩衝區)
      4. 在子進程完工後主進程將aof_rewrite_buf寫入文件,使用新AOF文件替換老文件
      5. 若是重寫失敗,舊文件還存在,只要no-appendfsync-on-rewrite no,那就不會有數據丟失
  • 重啓加載
    1. 優先load AOF文件,若是文件不存在,load RDB文件進行數據恢復
    2. aof-load-truncated yes : 兼容結尾不完整的AOF文件
    3. 文件校驗與修理
      1. redis-check-aof --fix xxx.aof
      2. diff -u
      3. 手動添加丟失數據

內存與持久化的key管理

  • 惰性刪除+定時刪除
    1. 維護每一個鍵精準的過時刪除會消耗大量CPU,惰性刪除採用客戶端讀取鍵時才分析過時信息進行刪除
    2. 定時刪除防止長久不訪問的的鍵也能被刪除
      1. 慢速模式默認每秒運行10次,每次檢查20個key,若是超過25%的過時,循環執行,直到不超過25%或者25毫秒超時
      2. 超時後Redis每次事件都會執行快速模式,採用1毫秒超時的,而且2秒只能運行1次
  • 內存溢出策略
    1. noeviction : 默認策略,不刪除數據,只響應讀操做,拒絕寫操做並報錯
    2. volatile-lru/allkeys-lru : 用LRU算法(空閒時間)刪除帶有超時設置的key/全部key,直到騰出足夠的空間,若是沒有,回退到noeviction
    3. volatile-random/allkeys-random: 隨機刪除帶有超時設置的key/全部key,直到騰出足夠的空間
    4. volatile-ttl : 更具剩餘存活時間ttl刪除key,沒有回退到noeviction的策略

持久化是性能瓶頸

  1. fork操做耗時與內存大小有關係,建議控制在10G,要儘可能減小fork
  2. fock的子進程的性能影響,主要是對服務器自己的消耗,對Redis主進程的影響可能不大
    1. Redis是CPU密集型服務,避免與計算密集服務公用,避免邦定單核
    2. Linux的寫時複製功能幫助Redis子進程節約一半內存消耗
    3. Redis的瓶頸可能會在硬盤IO方面,避免與存儲服務,消息隊列一同部署,部署多個實例時能夠作分盤,減輕磁盤IO
  3. AOF的always絕對要慎用,即便everysec也是高併發下的Redis住線程阻塞元兇,磁盤IO能力不行啊
    1. 能夠經過iotop工具定位

主從複製

相關配置

  • slaveof
    1. 是配置也是動態API
    2. slave no one : 斷開主從鏈接,從slave變成master,數據不丟失
    3. 切換master, 會刪除以前的數據,從新重新master複製數據
  • masterauth
    1. 若是master配置了requirepass ,須要驗證密碼
  • slave-read-only yes
    1. 從節點因該不容許修改,由於主節點沒法得到這些修改
  • repl-disable-tcp-nodelay no
    1. 默認no,開啓實時傳輸,任何命令都會實時發送到從節點,適合同機房等網絡條件好的狀況
    2. yes,開啓延時傳輸,會合並必定時間內的tcp數據包,減小網絡帶寬壓力,延時時間根據Linux內核,通常40毫秒
    3. 主從部署通常不一樣機器但因儘可能相同區域
  • repl-ping-slave-period 10
    1. 主節點ping從節點的心跳頻率
  • repl-timeout 60
    1. 主從複製的超時
  • slave-serve-stale-data yes
    1. 從節清除數據有加載RDB文件的過程當中,是否響應client
    2. 默認yes,可能形成拿不到數據或者數據與其餘節點不一致的狀況
    3. 若是爲no,client的請求會返回SYNC with master in progress

三種主從拓撲

  • 一主一叢
    1. 適合主節點寫併發量比較大的狀況
    2. 主節點使用RBD,保證主節點性能,從節點使用AOF,保證數據的安全性
    3. 若是主節點沒有持久化,或者RBD,要避免使用自動重啓,會形成從節點由於複製主節點丟失數據,正確的作法是主從調換
  • 一主多從
    1. 可用於但主節點讀壓力,作讀寫分離
    2. 能夠將阻塞命令在其中一臺上進行
    3. 不適合寫併發高的狀況
  • 樹狀結構
    1. 對一主多從結構的優化,下降主節點的複製壓力

複製原理

  • 複製偏移量
    1. 主從節點都會維護本身當前的總數據長度,就是偏移量,記錄在info replication
      1. master_repl_offset/slave_repl_pffset
    2. slave每秒報告本身的offset給主節點
      1. slave0:....offset=....
  • 複製積壓緩衝區
    1. 主節點的命令不但會發送給從節點,還會放入緩衝區
    2. 默認大小1M的先進先出的隊列
    3. 用於部分複製的命令丟失補救措施
  • 運行ID
    1. Redis每次啓動默認運行ID都會改變,保存在info server裏的run_id
    2. 運行ID改變後,會作主從全量複製,以保證對持久化配置/文件的修改不會形成複製的數據遺失
    3. 用debug reload重啓Redis,run_id不變,從而避免全量複製
  • 全量複製
    1. sync/psync
      1. psync ? -1 : 進行全量複製,返回+FULLRESYNC
    2. slave保存主節點run_id和offset
    3. master執行bgsave,保存RDB文件(因此即便Master市AOF,也會存在RDB文件)
    4. master發送RDB文件給slave
      1. 在千兆網卡下,帶寬最大100M/s,默認60s超時時間能夠傳輸6GB的RDB文件
    5. 傳輸RDB文件的過程當中master仍然工做,接受的命令會存放在slave對應的client輸出緩衝區
      1. 默認設置client-output-buffer-limit slave 256mb 64mb 60,60s超出64m或者總量超出256m當即關閉鏈接
    6. slave接受RDB文件後,清空數據,開始加載RDB文件
      1. slave響應client請求見slave-serve-stale-data
    7. 若是slave開啓了AOF,會當即調用bgrewriteaof來生成AOF文件
    8. 全量複製6GB數據耗時大約2分鐘
      1. master生成RDB時間
      2. 傳輸RDB時間
      3. slave清空數據時間
      4. slave加載RDB時間
      5. AOF時間
  • 部分複製
    1. 創建鏈接後,從節點更具本身的保存的run_id和offset發送psync run_id offset請求
    2. 主節點查看run_id和offset,對比複製緩衝區
      1. 若是run_id一致,複製緩衝區有這些數據,返回+CONTINUE進行部分複製
      2. 不然進行全量複製
  • 異步複製
    1. 在建議複製鏈接後,master會異步的發送受到的命令給slave
    2. 異步致使slave會存在數據延遲,延遲受repl-disable-tcp-nodelay影響
    3. 經過計算主從偏移量的差值能夠知道當前延遲的字節數,通常延遲在1s內,也能夠看出是否存在網絡延遲或命令阻塞等狀況
  • 維護心跳
    1. master默認每10秒對ping slave,判斷鏈接狀態,若是斷開超過repl-timeout,則斷開復制鏈接
      1. repl-ping-slave-period 10
    2. 從節點默認每秒發送replconf ack offset,上報本身的offset
      1. 經過對比offset檢查數據是否丟失,若是丟失,發送psync作部分複製
      2. 主節點經過replconf判斷從節點狀態與閾值min-slaves-to-write/min-slaves-max-lag
        1. 好比slave個數小於3個或者slave延遲大於10s,則master不響應write請求

可能形成全量複製的狀況

  • Redis每次啓動默認run_ID都會改變,而後就會產生全量複製
  • 從新選舉master後,run_id改變形成全量複製
  • 主從複製的複製積壓緩衝區過小,容易產生全量複製
  • psync ? -1手動全量複製

Redis Sentinel 哨兵

實現原理

  • 三個定時任務
    1. 每10s向master/slave發送info命令,用於獲取master和slave的拓撲以及變化
    2. 每2s向master的頻道_sentinel_:hello發佈和訂閱對master的判斷
      1. 用於發現其餘sentinel信息
      2. 用於交換對節點的判斷
    3. 每1s對master/slave/sentinel發送ping命令,來判斷是否存活
  • 主觀下線/客觀下線
    1. 若是sentinel對master的ping命令在down-after-milliseconds以後沒ping通,會認爲master主觀下線
    2. sentinel在認爲master下線的時候會經過發送命令相互交換對master的狀態:sentinel is-master-down-by-addr ip port current_epoch runid
      1. current_epoch : 當前配置紀元
      2. runid : 若是是*,表明交換意見,若是是當前sentinel的run_id,表明申請成爲sentinel leader
    3. sentinel收到>=quorum個數sentinel的主觀下線以後,就能確認master已經客觀下線
  • sentinel申請leader
    1. 確認master客觀下線後,sentinel會向其餘sentinel申請成爲leader進行故障轉移
    2. 當獲得超過max(quorum, num/2+1)票後成爲leader
    3. leader選舉很快,基本上誰先完成客觀下線判斷,誰就是leader
  • 故障轉移,選舉slave的過程
    1. 健康度過濾:5秒內沒有ping通的, 與master失聯超過down-after-milliseconds*10的時間的會被過濾
    2. slave-priority裏最高的會被選出,若是沒有,纔會繼續下一步驟
      1. 能夠經過slave-priority參數來自定義slave的優先級
    3. 選擇offset最大的slave,若是沒有選出,纔會繼續下一步驟
    4. 選擇runid最小的

配置詳解

  • sentinel monitor master-name host port quorum
    1. sentinel從master獲取master,slave和其餘sentinel信息進行監控
    2. quorum表明哨兵決策者的數量
      1. 須要幾個哨兵肯定發生故障,建議設置成sentinels/2+1
      2. 須要幾個哨兵進行選舉,去quorum和sentinels/2+1中比較大的
  • sentinel down-after-milliseconds master-9961 30000
    1. sentinel發送ping給redis節點和其餘sentinel節點
    2. 超過多少時間沒有ping通,說明節點發生故障
    3. 超時時間越小,哨兵工做越及時,可是誤判率越高
  • sentinel parallel-syncs master-name 1
    1. 從新選舉master後,slave會向新的master發起複製請求,這時候run_id改變形成全量複製
    2. 設置一次有多少個slave同時進行復制,若是設置成1,因此slave會輪訓進行復制
    3. 越大對master的消耗越大
  • sentinel failover-timeout master-name 180000
    1. 故障轉移任何階段的操做超時,故障轉移失敗
    2. 失敗後再次啓動的時間是超時的2倍
  • sentinel auth-pass master-name admin

部署技巧

  • 部署在不一樣的物理機,實現更好的高可用
  • 部署至少3個奇數個節點
  • 相同業務線的redis用一套sentinel,不一樣的業務線用多套

API

  • sentinel set master-nam key value
    1. 修改配置文件, 會當即更新配置文件
    2. 建議因此sentinel配置保持一致,便於故障轉移達成一致
  • sentinel master/slaves/sentinels master-name
  • sentinel ckquorum master-name
    1. 檢查取當前sentinel總數是否達到quorum的個數
  • sentinel remove master-name
  • sentinel monitor master-name host port quorum
    1. 取消監控/從新監控
  • sentinel failover master-name
    1. 強行故障轉移
    2. 與自動故障轉移同樣,都會改變配置文件
    3. 恢復後會讓以前的master變成slave,也會改變配置文件
  • sentinel flushconfig
    1. 用當前運行配置重置配置文件

Sentinel發佈訂閱頻道 : 能夠經過psubscribe *訂閱所有

  • +reset-master -- 當master被重置時.
  • +slave -- 當檢測到一個slave並添加進slave列表時.
  • +failover-state-reconf-slaves -- Failover狀態變爲reconf-slaves狀態時
  • +failover-detected -- 當failover發生時
  • +slave-reconf-sent -- sentinel發送SLAVEOF命令把它從新配置時
  • +slave-reconf-inprog -- slave被從新配置爲另一個master的slave,但數據複製還未發生時。
  • +slave-reconf-done -- slave被從新配置爲另一個master的slave而且數據複製已經與master同步時。
  • -dup-sentinel -- 刪除指定master上的冗餘sentinel時 (當一個sentinel從新啓動時,可能會發生這個事件).
  • +sentinel -- 當master增長了一個sentinel時。
  • +sdown -- 進入SDOWN狀態時;
  • -sdown -- 離開SDOWN狀態時。
  • +odown -- 進入ODOWN狀態時。
  • -odown -- 離開ODOWN狀態時。
  • +new-epoch -- 當前配置版本被更新時。
  • +try-failover -- 達到failover條件,正等待其餘sentinel的選舉。
  • +elected-leader -- 被選舉爲去執行failover的時候。
  • +failover-state-select-slave -- 開始要選擇一個slave當選新master時。
  • no-good-slave -- 沒有合適的slave來擔當新master
  • selected-slave -- 找到了一個適合的slave來擔當新master
  • failover-state-send-slaveof-noone -- 當把選擇爲新master的slave的身份進行切換的時候。
  • failover-end-for-timeout -- failover因爲超時而失敗時。
  • failover-end -- failover成功完成時。
  • switch-master -- 當master的地址發生變化時。一般這是客戶端最感興趣的消息了。

高可用的讀寫分離

  • 設計思路是經過Sentinel發佈訂閱頻道來獲取從節點的狀態變化
  • 須要本身實現從節點的資源池子維護和切換,好傻,sentinel就不能cover這部分工做麼

集羣

數據分區

  • 分佈式存儲算法
    1. 節點取餘分區
      1. 用hash(key)%N的餘數算出分區順序
      2. 優勢是數據分佈均衡,算法簡單,可是節點數N變化時須要從新計算和分區,大規模數據遷移
      3. 通常使用較大的提早量以便適應數據的增加,而且採用翻倍擴容,防止分區增長過渡頻繁
    2. 一致性哈希分區
      1. hash(key)>=節點的token,則分佈在此節點
      2. 增刪節點隻影響相鄰的節點,若是作數據遷移,那麼只須要遷移兩個節點
      3. 若是不遷移可能形成部分數據沒法命中,適合不須要100%命中的緩存策略
      4. 若是節點少,影響命中的比例就大,因此不遷移的方案只適合節點數多的狀況
      5. 若是要保證數據的均衡,則token的範圍與hash要對應,而且token要均衡分佈
      6. 增刪節點也須要*2或/2來保證token能均衡分佈,可是這樣又形成了50%命中的問題或者大規模遷移數據問題
      7. 要麼數據遷移,要麼忽略數據命中,要麼大規模遷移或不命中,要麼忽略數據均衡分佈,魚與熊掌不能兼得
    3. 虛擬槽分區 : Redis採用的方法
      1. Redis槽的範圍是0-16383,全部槽平均分配給節點
        1. CRC16(key,keylen)計算出散列值
        2. 若是key包含{hash_tag},則使用hash_tag計算散列值,不然用完整key計算
        3. 散列值對16383取餘,使得全部key都能映射到槽
      2. hash_tag的做用
        1. 使得不一樣key可以具備相同槽,從而分配到一個節點
        2. 給集羣下的批處理/Pipeline操做提供可能性
        3. 用於優化Redis IO
      3. 虛擬槽方便了數據遷移,支持節點,槽和key的映射查詢
  • 數據分區帶來的限制
    1. mset/mget等批量操做只支持key在同區的狀況
    2. 事務操做也只支持key在同區的狀況
    3. 只支持一個數據庫
    4. 不支持樹狀結構

搭建集羣

  • 啓動全部節點
    1. cluster-enabled yes
    2. 啓動後會自動生成並維護集羣配置文件, cluster-config-flie node-port.conf, 裏面有每一個節點的nodeId
    3. 目錄結構建議: conf,data,log
  • 手動搭建集羣
    1. 節點握手 : 在某個節點執行命令 cluster meet host port, 來鏈接全部節點
    2. 槽分配 : cluster addslots {0...5461},將全部槽均分給全部master
    3. 從節點 : cluster replicate nodeId
  • redis-trib.rb搭建集羣
    1. 安裝ruby
    2. 安裝rubygem redis依賴
    3. 安裝redis-trib.rb
    4. redis-trib.rb create --replicas 1 host:port host:port host:port host:port host:port host:port
      1. trib會盡量保證主從節點不分配在同一機器下
  • 集羣驗證與查詢
    1. cluster nodes : 查看節點信息
    2. cluster info
    3. cluster slots:查看槽分佈狀況
      1. 全部節點會分享信息,任何節點都能查詢全部槽的分佈狀況
    4. redis-trib.rb check host:port
    5. redis-trib.rb info host:port

集羣通信

  • 消息類型
    1. meet : 通知接受方節點加入當前集羣
    2. ping : 集羣內的每一個節點每秒向其餘節點發送ping,用於請求獲取其餘節點的狀態信息
    3. pong : 受到meet/ping後返回pong,內部封裝了節點的狀態數據,除了請求響應模式,也能夠廣播pong消息給其餘節點
    4. fail : 當節點判斷某個節點異常後,會廣播fail消息通知其餘節點
    5. 全部消息都包含head/body
      1. head包含發送方節點的自身信息:id,槽,主從角色,是否下線等
      2. body包含發送方節點發送的部分其餘節點的信息
  • 通信成本
    1. 節點每秒隨機選擇5個節點,選出未通信時間最長的進行ping通信,保證Gossip的隨機性
    2. 消息的發送頻率
      1. 節點每100毫秒(每秒10次)掃描本地列表,知足條件就會發送ping消息
      2. node.pong_received > cluster_node_timeout/2
      3. 因此cluster_node_timeout越大,通信頻率越低,默然15s
      4. 太大會影響故障轉移,槽信息更新,新節點加入
    3. 消息數據量
      1. head固定大小約2kb
      2. body的大小和節點數量成正比

集羣伸縮

  • 使用redis-trib.rb進行集羣擴容
    1. redis-trib.rb add-node host:port cluster_host:port
      1. 內部使用cluster meet實現添加master
      2. 內部會執行新節點狀態檢查,看是否已是另外一個集羣的成員,或者已經包含數據,若是是則放棄集羣操做報錯
      3. 手動cluster meet若是已是另外一個集羣的成員,那麼將原來集羣合併到如今的集羣,形成數據丟失和錯亂,避免使用
    2. redis-trib.rb reshard host:port --from --to --slots --yes --timeout --pipeline
      1. 手動流程解釋
        1. cluster setslot 4096 importing from_id : 讓目標節點準備導入某個節點的4096個槽
        2. cluster nodes : 確認目標節點開啓準備導入
        3. cluster setsolt 4096 migrating to_id : 讓源節點準備導出4096個槽到to_id節點
        4. cluster nodes : 確認源節點開啓準備導出
        5. cluster getkeysinslot 1 100 : 獲取100個源節點槽1的key
        6. mget key1 key2...key100 : 確認keys屬於這個節點
        7. migrate將全部keys進行遷移
        8. 使用mget/cluster nodes進行驗證,太他媽煩了
      2. 參數解釋
        1. host:port:這個是必傳參數,用來從一個節點獲取整個集羣信息,至關於獲取集羣信息的入口。
        2. --from :須要從哪些源節點上遷移slot,可從多個源節點完成遷移,以逗號隔開,傳遞的是節點的node id
          1. --from all 這樣源節點就是集羣的全部節點,不傳遞該參數的話,則會在遷移過程當中提示用戶輸入。
        3. --to :slot須要遷移的目的節點的node id,目的節點只能填寫一個,不傳遞該參數的話,則會在遷移過程當中提示用戶輸入。
        4. --slots :須要遷移的slot數量,不傳遞該參數的話,則會在遷移過程當中提示用戶輸入。
        5. --yes:設置該參數,能夠在打印執行reshard計劃的時候,提示用戶輸入yes確認後再執行reshard。
        6. --timeout :設置migrate命令的超時時間。
        7. --pipeline :定義cluster getkeysinslot命令一次取出的key數量,不傳的話使用默認值爲10。
    3. redis-trib.rb rebalance host:port
      1. 檢查數據分佈均衡性,若是不均衡會平衡集羣節點slot數量
    4. redis-trib.rb add-node host:port cluster_host:port --slave --master-id id
      1. 內部使用cluster replicaate添加slave
    5. redis-trib.rb check/info
      1. 檢查集羣
  • 使用redis-trib.rb進行集羣收縮
    1. redis-trib.rb reshard進行槽和數據的遷移
    2. redis-trib.rb del-node host:port downNodeId
      1. cluster forget忘記節點,有效期60s
      2. shutdown節點,若是有從節點,會將從節點指向其餘主節點
      3. 若是要把從節點下線,須要先下線從節點,以免全量複製帶來的開銷

故障轉移

  • 與Sentinel不一樣,Cluster的故障轉移由節點本身的相互通信機制完成
  • 整個故障轉移策略和Sentinel相似,包括主觀下線/客觀下線/選舉slave
  • 主觀下線:
    1. cluster-note-timeout時間內某個節點沒有ping通,則當前節點認爲此節點主觀下線
    2. 節點維護了一個有時限的下線報告列表,過時時間是cluster-note-timeout*2
  • 客觀下線
    1. 當節點發現下線列表的主觀下線數量大於槽節點(Master)總數的一半時,就會進行客觀下線廣播
    2. 廣播會通知全部master和salve,觸發故障轉移
  • 注意事項
    1. cluster-note-timeout過小會形成客觀下線判斷跟不上下線報告過時時間
    2. 不一樣區域的小集羣可能在必定時間沒法收到其餘區域的大集羣的下線報告,若是大集羣的slave在小集羣,就沒法完成轉移,因此儘可能master/slave在同區域
  • 故障恢復,選舉slave的過程
    1. 與master斷線時間超過cluster-note-timeout*cluster-slave-validity-factor(默認也是10)的沒有資格
    2. offset最大的slave優先,經過不一樣的延遲競選政策,好比offset大的延遲最小(1s)
    3. 競選slave更新配置紀元 configEpoch
      1. master configEpoch都不一樣,slave複製master
      2. 每次集羣有重大事件,都回更新配置紀元,configEpoch越大說明節點維護了最新的事件
      3. 集羣出現slots等關鍵信息不一致,以configEpoch大的爲準
      4. slave經過廣播競選來保證一個配置紀元內只能競選一次
    4. master進行投票,當N/2+1票後完成選舉
      1. master不要在同一臺物理機,不然服務器故障可能形成不夠票
  • 故障轉移的靈敏度
    1. failover-time <= cluster-note-timeout + cluster-note-timeout/2 +1
    2. cluster-note-timeout應該根據對故障轉移的容忍度設置,默認15s

集羣運維 : 見10.7

Java客戶端 Jedis

緩衝區

  • 輸入緩衝區
    1. 用於保存客戶端發送的命令
    2. 緩衝區大小動態調整,不能夠經過參數設定
    3. 每一個客戶端最大1G,超過會斷開鏈接
    4. 不受maxmemory限制,從而可能會超出限制
    5. 輸入緩衝區出現異常的狀況比較小
  • 輸出緩衝區
    1. 用於保存須要返回給客戶端的數據
    2. 能夠經過client-output-buffer-limit設置大小
      1. 分爲normal普通客戶/slave副本/pubsub訂閱客戶
      2. hard limit : 超出限制當即關閉鏈接
      3. soft limit/soft seconds : 超出必定時間關閉
    3. 分爲固定緩衝區(存放小的結果)和動態緩衝區(存放大的結果)
    4. 不受maxmemory限制,從而可能會超出限制
    5. 輸出緩衝區出現異常的狀況會比較大,可能因爲redis的處理能力比IO能力強大形成的
      1. 若是master節點輸入大,Slave的輸出壓力會比較大,應該適度增大
      2. 發現內存抖動頻繁,頗有多是輸出緩衝區過大形成

Jedis對象

  • Maven Dependency
    1. redis.clients : jedis
  • Jedis對API的使用與Redis Shell基本一致
    1. jedis.close() : 關閉或者歸還鏈接
  • Client
    1. jedis.getClient()
    2. setSoTimeout(soTimeout) : 設置讀寫超時
    3. setConnectionTimeout(connectionTimeout) : 設置鏈接超時

Pipeline對象

  • jedis.pipelined();
  • sync/syncAndReturnAll
  • Pipeline對API的使用與Redis Shell基本一致

Jedis鏈接池 JedisPool / GenericObjectPoolConfig

  • 鏈接池鏈接數量
    1. maxTotal : 最大鏈接數,默認8
    2. maxIdle : 最大空閒鏈接數, 默認8個,超出的會被移出
    3. minIdle : 最小空閒鏈接數, 默認0個,保持必定的最小空閒對性能可能有積極影響
  • 空閒檢查
    1. timeBetweenEvictionRunsMillis : 空閒檢測時間間隔(毫秒), 默認-1不開啓檢測
    2. numTestsPerEvictionRun :一次檢查幾個鏈接的空閒狀態, 默認3
    3. minEvictableIdleTimeMillis : 空閒的最小時間,超出的空閒鏈接將被移出,默認30分鐘
  • 有效性檢查
    1. testOnBorrow : 在獲取鏈接的時候檢查有效性, 無效會被移出,默認false
    2. testOnReturn : 向鏈接池歸還時檢查有效性, 無效會被移出,默認false
    3. testWhileIdle : 在獲取鏈接的時候作空閒檢測, 超時會被移出,默認false
  • 鏈接等待
    1. blockWhenExhausted : 是否等待鏈接池,默認true
    2. maxWaitMillis : 等待鏈接池資源的時間,默認-1,表示不超時,blockWhenExhausted=true才生效
  • jxmEnabled : 開啓JMX,用於監控鏈接池的使用狀況,默認true

Jedis使用Sentinel

  • JedisSentinelPool實現原理
    1. sentinels.add("host:port");將全部節點設置在sentinels集合裏Set
    2. 遍歷sentinel的host:port節點集合,選擇第一個可用sentinel
    3. 經過sentinel get-master-addr-by-name master-name獲取master節點
    4. 爲每一個sentinel節點啓動一個線程,用於訂閱sentinel節點的故障轉移頻道+switch-master
      1. pool.getResource();會返回故障轉移完成後新的master節點
      2. 故障轉移期間的操做會跑出異常,須要try/cache

Jedis使用Claster

  • JedisCluster使用細節
    1. HostAndPort能夠是所有,也能夠是部分,由於Jedis經過cluster slots發現全部槽
    2. JedisCluster內部包含了全部節點的JedisPool,因此應該是單例
    3. JedisCluster不須要關係鏈接池的獲取和歸還,由內部實現,因此它的close()方法不是歸還,而是銷燬全部JedisPool
    4. 多節點操做
      1. ...
    5. JedisCluster方法
      1. get/set
      2. getClusterNodes : 返回JedisPool的Map
        1. Jedis j = jedisPool.getValue().getResource() : 獲取到的多是master也多是slave節點
    6. JedisClusterCRC16.getSlot(hashtag)
  • JedisCluster實現原理
    1. Dummy客戶端
      1. 客戶端能夠隨機鏈接任意節點請求Cache數據,若是數據的槽不在當前節點,就會返回Moved信息
      2. 客戶端經過Moved信息進行重定向訪問正確的節點請求Cache數據
      3. JedisCluster避免了這種帶來額外IO開銷的傀儡客戶端,而使用了Smart客戶端
    2. Smart客戶端
      1. JedisCluster初始化時發送cluster slots從任一節點獲取全部槽的分佈狀況
      2. 槽映射信息存儲在JedisClusterInfoCache對象中,實現任意客戶端都維護了全部槽的映射關係
      3. 這樣就有效的避免了Redis Moved重定向問題帶來的IO消耗,偶爾的重定向會觸發cluster slots更新客戶端維護的槽映射關係
    3. JedisCluster請求數據
      1. 計算key的sort並根據槽映射關係找到對應節點發送請求
      2. 若是鏈接出錯(指拋出JedisConnectionException),返回第一步重試,attempts-1, 默認5
      3. 若是attempts=1或者任意一次重試捕獲到Moved重定向(MovedDataException),使用renewSlotCache方法發送cluster slots更新槽映射緩存
        1. 更新槽映射緩存會加鎖
        2. 同時只會有一個線程進行cluster slots更新槽映射緩存,減小併發調用和鎖等待
      4. 而後繼續1,2,3知道正確返回或者redirections<=0拋出異常
    4. Ask重定向
      1. 槽遷移期間發送請求不會獲得Moved重定向,而是Ask重定向
      2. 客戶端會發送Ask請求打開新節點的鏈接,來獲取數據,Ask鏈接是一次性的,每次都要這個過程
      3. Ask重定向不會更新槽映射關係,因此知道遷移完成,均可能發生Ask
      4. 源節點和目標節點維護槽信息來支持客戶端Ask
      5. 不支持批量操做的Ask重定向
      6. 不支持Pipeline的自動Ask,可是能夠經過手動分析Ask返回進行手動Ask重定向
  • 集羣對性能的消耗
    1. 大規模集羣
      1. 因爲Jedis爲每一個節點建立一個獨立的JedisPool,會維護很是多的鏈接
      2. 每一個客戶端維護的槽與節點的映射帶來內存消耗
      3. 客戶端發送cluster slots時帶來更多的數據傳輸
    2. 異常與重試機制
      1. 拋出JedisConnectionException的狀況
        1. Jedis與節點發生socket錯誤
        2. Read Time Out
        3. JedisPool獲取對象超時拋出JedisException,不會引發重試
      2. 能夠看出節點故障轉移期間,全部請求都回拋出JedisConnectionException異常
        1. 每5次重試會有一次cluster slots操做,並加鎖,會阻塞全部請求,形成請求積壓
    3. 高併發
      1. 當高併發遇到異常重試,會形成大規模請求積壓在客戶端
      2. 集羣規模大也會使這個問題更加凸顯
      3. 因此高併發不只要作好Redis集羣數量的平衡,也要作要客戶端集羣和負載均衡

Jedis使用Lua腳本

Redis配置 redis.conf

  • 啓動相關配置
    1. port 9961
    2. bind 127.0.0.1 : 註釋bind,將redis公開到網絡
      1. bind將redis邦定到指定網卡
    3. daemonize yes
    4. logfile "/opt/citimkts/rates/redis/logs/9961/redis.log"
    5. dir "/opt/citimkts/rates/redis/dir/9961"
  • 安全配置
    1. protected-mode no:
      1. no : 非保護模式建議設置密碼
      2. yes : 若是沒有設置密碼和bind,默認只能經過迴環地址(127.0.0.1)訪問,也就是本機
    2. requirepass pwd
  • 內存配置
    1. maxmemory byte : 設置數據使用的最大內存
    2. maxmemory-policy : 內存溢出策略
  • 慢查詢配置
    1. slowlog-log-slower-than 2000
    2. slowlog-max-len 128
  • client相關配置
    1. maxclients : 最大client數量,默認10000
    2. timeout : client空閒多久關閉鏈接,默認0,表示不限制
    3. tcp-keepalive : tcp鏈接有效性檢測週期,默認300
    4. tcp-backlog : tcp鏈接握手後放入隊列的大小,鏈接成功後會從隊列移出

性能分析與優化

阻塞

  • 客戶端輸出緩衝區出現問題的概率比較大,發現內存抖動頻繁,頗有多是輸出緩衝區過大形成
  • 集羣規模
    1. 當高併發遇到異常重試,會形成大規模請求積壓在客戶端
    2. 集羣規模大也會使這個問題更加凸顯
    3. 因此高併發不只要作好Redis集羣數量的平衡,也要作要客戶端集羣和負載均衡
  • 慢查詢
    1. Redis的問題可能會出在客戶端使用不當上面,形成阻塞, slowlog發現慢查詢
    2. 見可能會形成阻塞的命令
    3. 避免大對象 : --bigkeys
  • 持久化
    1. Redis的瓶頸可能會在硬盤IO方面,避免與存儲服務,消息隊列一同部署,部署多個實例時能夠作分盤,減輕磁盤IO
    2. AOF追加阻塞 :
      1. AOF的always絕對要慎用,即便everysec也是高併發下的Redis住線程阻塞元兇,磁盤IO能力不行啊
      2. info persistence的aof_delayed_fsync是全部AOF追加阻塞的時間
    3. fock阻塞:
      1. fock的耗時與數據量相關
      2. info stats察看latest_fork_usec,超過1s就得注意
    4. HugePage寫操做阻塞
  • CPU飽和
    1. Redis是CPU密集型服務,避免與計算密集服務公用
    2. 若是沒有開啓持久化,建議邦定CPU減小CPU切換,可是若是開啓了持久化,fork的子進程消耗90%以上CPU,影響主進程,全部不能邦定
    3. --stat察看OPS,若是在5W+基本就會飽和了,top,sar等察看CPU
    4. 單機多實例的部署方式能夠發揮多核CPU的優點,彌補單線程的不足
  • 內存交換
    1. cat /proc/皮帶/samps | grep Swap
    2. 若是內存交換過大,會使得Redis被磁盤速度拖累
    3. 防止
      1. maxmemory設置最大可用內存,並保證服務器內存充足
      2. 下降系統swap優先級: echo 10 > /proc/sys/vm/swappiness
  • 網絡問題
    1. 鏈接拒絕
      1. 網絡閃段:sar -n DEV查看歷史流量狀況/Ganglia等監控工具
      2. Redis鏈接拒絕,maxclient 10000 : info Stats | grep rejected_connections
      3. 鏈接溢出:
        1. 操做系統文件句柄個數,ulimit -n,默認1024
        2. 操做系統backlog,默認128: echo 511 > /proc/sys/net/core/somaxconn
        3. tcp-backlog,默認511
    2. 網絡延遲
      1. 同物理機>同機架>跨機架>同機房>同城機房>異地機房
      2. 帶寬瓶頸:機器網卡帶寬,機架交換機帶寬,機房專線帶寬
      3. redis-cli -h host -p port : --latency/--latency-history/--latency-dist
    3. 網卡軟中斷

內存優化

  • info memory
    1. used_memory_human: 數據佔用內存
    2. used_memory_rss_human: 進程佔用內存
    3. used_memory_peak_human: 數據佔用內存的峯值
    4. mem_fragmentation_ratio:
      1. used_memory_rss/used_memory : 表示內存碎片率
      2. 若是小於1,說明出現內存交換Swap
      3. 若是大於1比較多,說明碎片率嚴重
  • 緩衝區
    1. 輸入緩衝區和AOF緩衝區通常不會有問題
    2. 輸出緩衝區
      1. client-output-buffer-limit設置大小和策略
      2. 當客戶端數量過大,網絡傳輸有問題的時候,可能形成輸出緩衝區過大,默認不限制大小
      3. 當從節點數量過大,網絡傳輸有問題的時候,可能形成輸出緩衝區溢出,默認256mb
      4. 當訂閱客戶端的消費能力差的時候,可能形成輸出緩衝區溢出,默認32mb
    3. 複製積壓緩衝區
      1. 全部從節點公用一個緩衝區
      2. 默認1M過小了,能夠設置100MB,減小全量複製的發生
  • 內存碎片
    1. 頻繁的對字符串的修改操做,過時健的刪除會提升碎片率
    2. 能夠經過定時安全重啓作內存從新分配
    3. 更加高成本的優化是作數據對齊
  • 子進程內存消耗
    1. 子進程內存消耗通常比父進程小,實際消耗根據寫入命令量決定
    2. sysctl vm.overcommit_memory=1容許內核分配全部內存
    3. 建議關閉THP
  • 內存溢出消耗
    1. 建議Redis一直工做在maxmemory>used_memory的狀態下(也就是不太適合做爲緩存?),避免內存回收帶來的開銷
    2. 設置過時會帶來必定的額外CPU開銷
  • value對象長度
    1. 能夠採用更高效的序列化工具,好比protostuff,kryo
    2. 能夠對json等進行壓縮,好比GZIP算法,或者更快速的Snappy
  • 開啓整數共享對象池
  • 字符串優化
    1. 頻繁的對字符串的修改操做不但提升碎片率,還增長字符串的預分配大小,要避免大量append,setrange等操做,用set代替
    2. 用hash代替json能減小內存開銷
  • 內部編碼優化 : 見8.3.5
    1. intset儘可能作數據對齊,防止個別大整數使得整個set觸發升級操做
  • hash+ziplist優化:見8.3.6

Linux優化

  • vm.overcommit_memory
    1. 0 : 表示若是有足夠內存,申請內存經過,不然申請失敗
    2. 1 : 表示容許超量申請,由於申請後並不會立刻使用,直到用完內存
    3. 2 : 決不過量
    4. Redis建議設置1,保證fork操做能在低內存下也能執行成功
  • swappiness
    1. 1-100,數字越大,用swap的機率越高
    2. 分佈式redis,寧願死掉也不要swap
  • THP
    1. Redis建議關閉THP功能
  • OOM killer
    1. 當服務器內存不足時,優先殺死oom_adj大的進程
    2. 分佈式redis,寧願死掉
  • ulimit
    1. 客戶端與Redis的tcp鏈接都是文件句柄,建議open files和maxclients吻合
  • tcp-backlog
    1. Redis和服務器的設置建議吻合

熱點key優化

如何用好系列

策略選擇

  • 持久化策略 :數據安全性考慮
    1. RDB
      1. 全量數據存儲,服務故障可能會有幾分鐘的數據沒有持久化
      2. 對性能影響小,數據加載快速,支持文件壓縮
    2. AOF
      1. 更安全的持久化策略,最低級別也就30s左右的數據丟失
        1. everysec 數據最多丟失2s,安全性也性能的綜合使用方法,推薦
      2. 通常涉及到客戶操做的非再生數據都要用AOF,RDB會有BUG的
      3. no-appendfsync-on-rewrite:
        1. yes : 數據不安全,不阻塞
        2. no : 數據安全,阻塞
    3. 能夠主節點使用RDB,從節點使用AOF
  • 主從複製策略 :數據安全性考慮
    1. repl-disable-tcp-nodelay
      1. 數據安全性高的使用默認no
      2. 不然yes進行合併40毫秒左右的tcp數據包下降網絡帶寬壓力,增長吞吐量
  • 故障轉移的靈敏度
    1. sentinel down-after-milliseconds master-9961
      1. 超時時間越小,哨兵工做越及時,可是誤判率越高,默認30s
    2. cluster-note-timeout
      1. 應該根據對故障轉移的容忍度設置,默認15s
      2. failover-time <= cluster-note-timeout + cluster-note-timeout/2 +1
  • 當Redis做爲數據庫
    1. 數據安全性
    2. 持久化文件安全性
    3. 主從複製安全性
    4. 會形成持久化文件重寫的狀況

運維數據

  • RDB持久化建議每一個Redis實例控制在10GB
  • sentinel 部署至少3個奇數個節點
  • 從節點通常不要多於2個
  • 複製積壓緩衝區設置爲100MB,減小全量複製
  • 正常的碎片率在1.03左右
  • 相同業務線的redis用一套sentinel,不一樣的業務線用多套
  • slowlog-log-slower-than
    1. 默認10000,注意是10毫秒,建議設置成1毫秒左右,以便發現慢查詢,保證OPS至少1000
  • 值的長度若是能控制在39個字節內,能夠減小內存分配次數
  • ziplist建議長度不超過1000,每一個元素大小控制在512字節
  • 1M以上就能夠認爲是bigkey

數據丟失

  • 可以形成持久化文件丟失的狀況
    1. flushdb/flushall清楚緩存後,產生了RDB bgsave/save覆蓋持久化文件,AOF重寫覆蓋持久化文件
    2. AOF重寫失敗
    3. 從節點複製了有問題的主節點
  • 措施
    1. 使用預約義腳本恢復flushdb/flushall後的AOF文件
    2. 按期備份數據
    3. 使用複雜密碼(64位)/使用非root權限啓動:防止暴力破解進行攻擊
相關文章
相關標籤/搜索