天天看點

「資料庫」兩萬字 redis.conf 7.0 配置和原理全解,生産王者必備

作者:架構思考

我是 Redis, 當程式員用指令 ./redis-server /path/to/redis.conf 把我啟動的時候,第一個參數必須是redis.conf 檔案的路徑。

這個檔案很重要,就好像是你們的 DNA,它能控制我的運作情況,不同的配置會有不同的特性和人生,它掌握我的人生命運,控制着我如何完成高可用、高性能。合理的配置能讓我更快、更省記憶體,并發揮我最大的優勢讓我更安全運作。

以下這些配置大家必知必會,需要大家掌握每個配置背後的技術原理,學會融合貫通并在生産中正确配置,解決問題。避免出現技術懸浮,原理說的叭叭叭,配置像個大傻瓜。

本文配置檔案版本是 Redis 7.0。

一、正常通用配置

這些是我的正常配置,每個 Redis 啟動必備參數,你一定要掌握,涉及到網絡、子產品插件、運作模式、日志等。

1、MODULES

這個配置可以加載子產品插件增強我的功能,常見的子產品有 RedisSearch、RedisBloom 等。關于子產品加載可以參考【5.6 布隆過濾器原理與實戰】章節內建布隆過濾器便是通過以下配置實作加載布隆過濾器插件。

loadmodule /opt/app/RedisBloom-2.2.14/redisbloom.so           

2、NETWORK

這部分都是與網絡相關的配置,很重要滴,配置不當将會有安全和性能問題。

bind

bind用于綁定本機的網絡接口(網卡),注意是本機。

每台機器可能有多個網卡,每個網卡都有一個 IP 位址。配置了 bind,則表示我隻允許來自本機指定網卡的 Redis 請求。

MySQL:“bind 是用于限制通路你的機器 IP 麼?”

非也,注意,這個配置指的并不是隻有 bind 指定的 IP 位址的計算機才能通路我。如果想限制指定的主機連接配接我,隻能通過防火牆來控制,bind 參數不也能起到這個作用。

舉個例子:如果我所在的伺服器有兩個網卡,每個網卡有一個 IP 位址, IP1,IP2。

配置 bind IP1,則表示隻能通過這個網卡位址來的網絡請求通路我,也可以使用空格分割綁定多個網卡 IP。

我的預設配置是bind 127.0.0.1 -::1 表示綁定本地回環位址 IPv4 和 Ipv6。- 表示當 ip 不存在也能啟動成功。

protected-mode

MySQL:網絡世界很危險滴,你如何保證安全?

預設開啟保護模式,如果沒有設定密碼或者沒有 bind 配置,我隻允許在本機連接配接我,其它機器無法連接配接。

如果想讓其它機器連接配接我,有以下三種方式。

  1. 配置為 protected-mode no(不建議,地球很危險滴,防人之心不可無)。
  2. protected-mode yes,配置 bind 綁定本機的 IP。
  3. protected-mode yes,除了設定 bind 以外,還可以通過 requirepass magebyte設定密碼為 magebyte, 讓其他機器的用戶端能使用密碼通路我。

bind、protected-mode、requirepass 之間的關系

  • bind:指定的是我所在伺服器網卡的 IP,不是指定某個可以通路我的機器。
  • protected-mode:保護模式,預設開啟,如果沒有設定密碼或者 bind IP,我隻接受本機通路(沒密碼+保護模式啟動=本地通路)。
  • requirepass,Redis 用戶端連接配接我通行的密碼。

如果參數設定為bind 127.0.0.1 -::1,不管 protected-mode是否開啟,隻能本機用 127.0.0.1 連接配接,其他外機無法連接配接。

在生産環境中,為了安全,不要關閉 protected-mode,并設定 requirepass 參數配置密碼和 bind 綁定機器的網卡 IP。

port 6379

用于指定我監聽的用戶端 socket 端口号,預設 6379。設定為 0 則不會監聽 TCP 連接配接,我想沒人設定為 0 吧。

tcp-backlog 511

用于在 Linux 系統中控制 TCP 三次握手已完成連接配接隊列(完成三次握手後)的長度,如果已完成連接配接隊列已經滿則無法放入,用戶端會報read timeout或者connection reset by peer的錯。

MySQL:“在高并發系統中這玩意需要調大些吧?”

是的,我的預設配置是 511,這個配置的值不能大于 Linux 系統定義的

/proc/sys/net/core/somaxconn 值,Linux 預設的是 128。

是以我在啟動的時候你會看到這樣的警告:WARNING: The TCP backlog setting of 511 cannot be enforced because kern.ipc.somaxconn is set to the lower value of 128.

當系統并發量大并且用戶端速度緩慢的時候,在高并發系統中,需要設定一個較高的值來避免用戶端連接配接速度慢的問題。

需要分别調整 Linux 和 Redis 的配置。

建議修改為 2048 或者更大,Linux 則在 /etc/sysctl.conf中添加net.core.somaxconn = 2048配置,并且在終端執行 sysctl -p即可。

碼哥使用 macOS 系統,使用 sudo sysctl -w kern.ipc.somaxconn=2048即可。

timeout

timeout 60 機關是秒,如果在 timout 時間内用戶端跟我沒有資料互動(用戶端不再向我發送任何資料),我将關閉該用戶端連接配接。

注意事項

  • 0 表示永不斷開。
  • timeout 對應源碼 server.maxidletime

tcp-keepalive

tcp-keepalive 300 機關是秒,官方建議值是 300。這是一個很有用的配置,實作 TCP 連接配接複用。

用途

用于用戶端與服務端的長連接配接,如果設定為非 0,則使用 SO_KEEPALIVE 周期性發送 ACK 給用戶端,俗話就是用來定時向用戶端發送 tcp_ack 包來探測用戶端是否存活,并保持該連接配接。不用每次請求都建立 TCP 連接配接,畢竟建立連接配接是比較慢的。

3、正常配置

這些都是我的正常配置,比較通用,你必須了解。你可以把這些配置寫到一個特有檔案中,其他節點可以使用 include /path/to/other.conf 配置來加載并複用該配置檔案的配置。

daemonize

配置daemonize yes表示使用守護程序的模式運作,預設情況下我是以非守護線程的模式運作(daemonize no),開啟守護程序模式,會生成一個 .pid檔案存儲程序号。

你也可以配置 pidfile /var/run/redis_6379.pid 參數來指定檔案的生成目錄,當關閉服務的時候我會自動删除該檔案。

loglevel

指定我在運作時的日志記錄級别。預設是 loglevel notice。有以下幾個選項可以配置。

  • debug:會記錄很多資訊,主要用于開發和測試。
  • verbose:許多用處不大的資訊,但是比 debug 少,如果發現生産出現一些問題無從下手,可使用該級别來輔助定位。
  • notice:生産一般配置這個級别。
  • warning:隻會記錄非常重要/關鍵的的日志。

logfile

指定日志檔案目錄,預設是 logfile "",表示隻在标準控制台輸出。

需要注意的是,如果使用标準控制台輸出,并且使用守護程序的模式運作,日志會發送到 /dev/null。

databases

設定資料庫數量,我的預設配置是 databases 16 。預設的資料庫是 DB 0,使用叢集模式的時候, database 隻有一個,就是 DB 0。

二、RDB 快照持久化

MySQL:“要怎麼開啟 RDB 記憶體快照檔案實作持久化呢?”

RDB 快照持久化相關的配置,必須掌握,合理配置能我實作當機快速恢複實作高可用。

1、save

使用 save <seconds> <changes> 開啟持久化,比如 save 60 100 表示 60 秒内,至少執行了 100 個寫操作,則執行 RDB 記憶體快照儲存。

不關心是否丢失資料,你也可以通過配置 save "" 來禁用 RDB 快照儲存,讓我性能起飛,沖出三界外。

預設情況的我會按照如下規則來儲存 RDB 記憶體快照。

  • 在 3600 秒 (一個小時) 内,至少執行了一次更改。
  • 在 300 秒(5 分鐘)内,至少執行了 100 個更改。
  • 在 60 秒後,至少執行了 10000 個更改。

也可以通過 save 3600 1 300 100 60 10000 配置來顯示設定。

2、

stop-writes-on-bgsave-error

MySQL:“bgsave 失敗的話,停止接收寫請求要怎麼配置?”

預設配置為

stop-writes-on-bgsave-error yes,它的作用是如果 RDB 記憶體快照持久化開啟并且最後一次 bgsave 失敗的話就停止接收寫請求。

我通過這種強硬的方式來告知程式員資料持久化不正常了,否則可能沒人知道 RDB 快照持久化出問題了。

當 bgsave 背景程序能正常工作,我會自動允許寫請求。如果你對此已經有相關的監控,即使磁盤出問題(磁盤空間不足、沒有權限等)的情況下依舊處理寫請求,那麼設定成 no 即可。

3、rdbcompression

MySQL:“RDB 記憶體快照檔案比較大,可以壓縮麼?”

我的預設配置是 rdbcompression yes,意味着對 RDB 記憶體快照檔案中的 String 對象使用 LZF 算法做壓縮。這個非常有用,能大大減少檔案大小,受益匪淺呀,建議你開啟。

如果你不想損失因為壓縮 RDB 記憶體快照檔案的 CPU 資源,那就設定成 no,帶來的後果就是檔案比較大,傳輸占用更大的帶寬(要三思啊,老夥計)。

4、rdbchecksum

預設配置是 rdbchecksum yes,從 5.0 版本開始,RDB 檔案末尾會寫入一個 CRC64 檢驗碼,能起到一定的糾錯作用,但是要丢失大約 10% 的性能損失,你可以設定成功 no 關閉這個功能來獲得更快的性能。

關閉了這個功能, RDB 記憶體快照檔案的校驗就是 0 ,代碼會自動跳過檢查。

推薦你關閉,讓我快到令人發指。

你還可以通過 dbfilename 參數來指定 RDB 記憶體快照檔案名,預設是 dbfilename dump.rdb。

5、rdb-del-sync-files

預設配置是 rdb-del-sync-files no,主從進行全量同步時,通過傳輸 RDB 記憶體快照檔案實作,沒有開啟 RDB 持久化的執行個體在同步完成後會删除該檔案,通常情況下保持預設即可。

6、dir

我的工作目錄,注意這是目錄而不是檔案, 預設配置是dir ./。比如存放 RDB 記憶體快照檔案、AOF 檔案。

三、主從複制

這部配置設定置很重要,涉及到主從複制的方方面面,是高可用的基石,重點對待啊夥計們。

1、replicaof

主從複制,使用replicaof <masterip> <masterport> 配置将目前執行個體成為其他 Redis 服務的從節點。

  • masterip,就是 master 的 IP。
  • masterport,master 的端口。

有以下幾點需要注意。

  • 我使用異步實作主從複制,當 Master 節點的 slave 節點數量小于指定的數量時,你可以設定 Master 節點停止處理寫請求。
  • 主從複制如果斷開的時間較短,slave 節點可以執行部分重新同步,需要合理設定 backlog size,保證這個緩存區能完整儲存斷連期間 Master 接受寫請求的資料,防止出現全量複制,具體配置後面會細說。
  • 主從複制是自動的,不需要使用者幹預。

2、masterauth

如果目前節點是 slave,且 master 節點配置了 requirepass 參數設定了密碼,那麼 slave 節點必須使用該參數配置為 master 的密碼,否則 master 節點将拒絕該 slave 節點的請求。

配置方式為 masterauth <master-password>。

3、masteruser

在 6.0 以上版本,如果使用了我的 ACL 安全功能,隻配置 masterauth 還不夠。因為預設使用者不能運作 PSYNC 指令或者主從複制所需要的其他指令。

這時候,最好配置一個專門用于主從複制的特殊使用者,配置方式為 masteruser <username>。

4、replica-serve-stale-data

MySQL:“當 slave 節點與 master 失去連接配接,導緻主從同步失敗的時候,還能處理用戶端請求麼?”

slave 節點可以有以下兩種行為來決定是否處理用戶端請求。

  • 配置為 yes,slave 節點可以繼續處理用戶端請求,但是資料可能是舊的,因為新的沒同步過來。也可能是空的,如果是第一次同步的話。
  • 配置為 no,slave 節點将傳回錯誤 MASTERDOWN Link with MASTER is down and replica-serve-stale-data is set to no給用戶端。但是以下的指令還是可以執行:INFO, REPLICAOF, AUTH, SHUTDOWN, REPLCONF, ROLE, CONFIG, SUBSCRIBE,UNSUBSCRIBE, PSUBSCRIBE, PUNSUBSCRIBE, PUBLISH, PUBSUB, COMMAND, POST,HOST and LATENCY。

我的預設配置是 replica-serve-stale-data yes。

5、replica-read-only

這個配置用于控制 slave 執行個體能否接收寫指令,在 2.6 版本後預設配置為 yes,表示 slave 節點隻處理讀請求,如果為 no 則可讀可寫。

我建議保持預設配置,讓 slave 節點隻作為副本實作高可用。想要提高寫性能,使用叢集模式橫向拓展更好。

6、repl-diskless-sync

主從複制過程中,新加入的 slave 節點和 slave 節點重連後無法進行增量同步,需要進行一次全量同步,master 節點會生成 RDB 記憶體快照檔案傳輸給 slave 節點。

是以這個配置是用于控制傳輸方式的,傳輸方式有兩種。

  • Disk-backed(磁盤備份):master 節點建立新程序将 RDB 記憶體快照檔案寫到磁盤,主程序逐漸将這個檔案傳輸到不同 slave 節點。
  • Diskless(無盤備份):master 節點建立一個新程序直接把 RDB 記憶體快照内容寫到 Socket,不會将 RDB 記憶體快照檔案持久化到磁盤。

使用磁盤備份的方式,master 儲存在磁盤的 RDB 記憶體快照檔案可以讓多個 slave 複用。

使用無盤備份的話,當 RDB 記憶體快照檔案傳輸開始,如果目前有多個slave 節點與 master 建立連接配接,我會使用并行傳輸的方式将 RDB 内容傳輸給多個節點。

預設的配置是 repl-diskless-sync yes,表示使用無盤備份。在磁盤速度很慢,而網絡超快的情況下,無盤備份會更給力。如果網絡很慢,有可能會出現資料丢失,推薦你改成 no。

7、repl-diskless-sync-delay

使用無盤複制的話,如果此刻有新的 slave 發起全量同步,需要等待之前的傳輸完畢才能開啟傳輸。

是以可以使用配置 repl-diskless-sync-delay 5 參數指定一個延遲時間,這個機關是秒,讓 master 節點等待一會,讓更多 slave 節點連接配接再執行傳輸。

因為一旦開始傳輸,master 節點無法響應新的 slave 節點的全量複制請求,隻能在隊列中等待下一次 RDB 記憶體快照傳輸。

想要關閉這個功能,設定為 0 即可。

8、repl-diskless-load

mastar 節點有兩種方式傳輸 RDB,slave 節點也有兩種方式加載 master 傳輸過來的 RDB 資料。

  • 傳統方式:接受到資料後,先持久化到磁盤,再從磁盤加載 RDB 檔案恢複資料到記憶體中,這是傳統方式。
  • diskless-load:從 Socket 中一邊接受資料,一邊解析,實作無盤化。

一共有三個取值可配置。

  • disabled:不使用 diskless-load 方式,即采用磁盤化的傳統方式。
  • on-empty-db:安全模式下使用 diskless-load(也就 slave 節點資料庫為空的時候使用 diskless-load)。
  • swapdb:使用 diskless-load 方式加載,slave 節點會緩存一份目前資料庫的資料,再清空資料庫,接着進行 Socket 讀取實作加載。緩存一份資料的目的是防止讀取 Socket 失敗。

需要注意的是,diskless-load 目前在實驗階段,因為 RDB 記憶體快照資料并沒有持久化到磁盤,是以有可能造成資料丢失;

另外,該模式會占用更多記憶體,可能會導緻 OOM。

9、repl-ping-replica-period

預設配置repl-ping-replica-period 10 表示 slave 每 10 秒 PING 一次 master。

10、repl-timeout

很重要的一個參數,slave 與 master 之間的複制逾時時間,預設配置是repl-timeout 60,表示在 60 秒内 ping 不通,則判定逾時。

逾時包含以下三種情況。

  • slave 角度,全量同步期間,在 repl-timeout 時間内沒有收到 master 傳輸的 RDB 記憶體快照檔案。
  • slave 角度,在 repl-timeout 時間内沒有收到 master 發送的資料包或者 ping。
  • master 角度,在 repl-timeout 時間内沒有收到 REPCONF ACK (複制偏移量 offset)确認資訊。

當檢測到逾時,将會關閉 master 與 slave 之間的連接配接,slave 會發起重建立立主從連接配接的請求,對于記憶體資料比較大的系統,可以增大 repl-timeout 的值。

你需要注意的是,這個配置一定要大于 repl-ping-replica-period的值,否則每次心跳監測都逾時。

11、repl-disable-tcp-nodelay

當 slave 與 master 全量同步(slave 發送 psync/sync 指令給 master)完成後,後續的增量同步是否設定成 TCP_NODELAY。

如果設定成 yes,master 将合并小的 TCP 包進而節省帶寬,但是會增加同步延遲(40 ms),造成 master 與 slave 資料不一緻;設定成 no,則 master 會立即發送資料給 slave,沒有延遲。

預設配置 repl-disable-tcp-nodelay no。

12、repl-backlog-size

設定主從複制積壓緩沖區(backlog) 容量大小,這是一個環形數組,正常主從同步不涉及到 repl-backlog。當主從斷開重連,repl-backlog 的作用就出來了。

緩沖區用于存放斷連期間 master 接受的寫請求資料,當主從斷開重連,通常不需要執行全量同步,隻需要将斷連期間的部分資料傳遞到 slave 即可。

主從複制積壓緩沖區越大,slave 可以承受的斷連時間越長。

預設配置是 repl-backlog-size 1mb,建議根據每秒流量大小和斷開重連時間長,設定大一點,比如 128 mb。

13、repl-backlog-ttl

用于配置當 master 與 slave 斷連多少秒之後,master 清空主從複制積壓緩沖區(repl-backlog)。配置成 0 ,表示永遠不清空。預設配置repl-backlog-ttl 3600。

14、replica-priority

slave 優先級,這個配置是給哨兵使用的,當 master 節點挂掉,哨兵會選擇一個 priority 最小的 slave 節點作為新的 master,這個值越小沒接越優先選中。

如果是 0,那意味着這個 slave 将不能選中成為 master,預設配置是 replica-priority 100。

15、min-slaves-to-write 和 min-slaves-max-lag

這兩個配置要一起設定才有意義,如果有一個配置成 0,表示關閉該特性。

先看預設配置含義。

min-replicas-to-write 3
min-replicas-max-lag 10           

如果 master 發現超過 3 個 slave 節點連接配接 master 延遲大于 10 秒,那麼 master 就停止接收用戶端寫請求。這麼做的目的是為了盡可能保證主從資料一緻性。

master 會記錄每個 slave 最近一次發來 ping 的時間,掌握每個 slave 的運作情況。

16、tracking-table-max-keys

我在 Redis 6.0 版本,實作了服務端輔助實作用戶端緩存的特性,需要追蹤用戶端有哪些 key。當某個 key 被修改,我需要把這個失效資訊發送到對應的用戶端将本地緩存失效,這個配置就是用于指定追蹤表儲存的最大 key 數量,一旦超過這個數量,即使這個 key 沒有被修改,為了回收記憶體我也會強制這個 key 所在的用戶端緩存值失效。

設定 0 表示不限制,需要注意的是,如果使用廣播模式實作鍵追蹤,則不需要額外記憶體,忽略這個配置。

使用廣播模式的不足就是與這個 key 無關的用戶端也會收到失效消息。

四、安全

正是由于我快的一塌糊塗,攻擊者一秒鐘可以嘗試 100 萬個密碼,是以你應該使用非常健壯的密碼。

1、ACL

ACL 日志的最大長度,預設配置 acllog-max-len 128 表示最大 128 mb。

另外,使用 aclfile /etc/redis/users.acl 配置 ACL 檔案所在位置。

2、requirepass

目前 Redis 伺服器的通路密碼,預設是不需要密碼通路,網絡危險,必須設定,如 requirepass magebyte660設定密碼為 “magebyte666”。

3、maxclients

設定用戶端同時連接配接的最大數量,預設設定是 maxclients 10000。達到最大值,我将關閉用戶端新的連接配接,并發送一個 max number of clients reached 錯誤給用戶端。

五、記憶體管理

作為用記憶體儲存資料的我,這部分的配置也相當重要。

1、maxmemory

設定使用記憶體最大位元組,當記憶體達到限制,我将嘗試根據配置的記憶體淘汰政策(參見 maxmemory-policy)删除一些 key。建議你不要設定太大的記憶體,防止執行 RDB 記憶體快照檔案或者 AOF 重寫的時候因資料太大而阻塞過長時間。

推薦最大設定為 maxmemory 6GB。

如果淘汰政策是 noeviction,當收到寫請求,我将回複錯誤給用戶端,讀請求依然可以執行。

如果你把我當做一個 LRU 或 LFU 緩存系統的時候,那請用心關注以下配置。

2、maxmemory-policy

設定記憶體淘汰政策,定義當記憶體滿時如何淘汰 key,預設配置是 noeviction。

  • volatile-lru -> 在設定過期時間的 key 中使用近似 LRU 驅逐。
  • allkeys-lru -> 在所有 key 中使用近似 LRU 驅逐。
  • volatile-lfu -> 在過期 key 中使用近似 LFU 驅逐。
  • allkeys-lfu -> 在所有 key 中使用近似 LFU。
  • volatile-random -> 在設定了過期時間的 key 中随機删除一個。
  • allkeys-random -> 在所有的 key 中随機删除一個。
  • volatile-ttl -> 誰快過期就删誰。
  • noeviction -> 不删除任何 key,記憶體滿了直接傳回報錯。

3、maxmemory-samples

LRU, LFU and minimal TTL algorithms 不是精确的算法,是一個近似的算法(主要為了節省記憶體)。

是以需要你自己權衡速度和精确度。預設會抽取 5 個 key,選擇一個最近最少使用的 key 淘汰,你可以改變這個數量。

預設的 5 可以提供不錯的結果。配置 10 會非常接近真實的 LRU 但是會耗費更多的 CPU,配置 3 會更快,但是就不那麼精确了。

4、replica-ignore-maxmemory

從 Redis 5.0 開始,預設情況下 slave 節點會忽略 maxmemory 配置,除非在故障轉移後或手動将其提升為 master。這意味着隻有 master 才會執行記憶體淘汰政策,當 master 删除 key 後會發送 DEL指令給 slave。

預設配置replica-ignore-maxmemory yes。

5、active-expire-effort

我有兩種方式删除過期資料。

  • 背景周期性選取部分資料删除。
  • 惰性删除,當通路請求到某個 key 的時候,發現該 key 已經過期則删除。

這個配置用于指定過期 key 滞留在記憶體中的比例,預設值是 1,表示最多隻能有 10 % 的過期 key 駐留在記憶體中,值設定的越小,那麼一次淘汰周期内需需要消耗的 CPU 将會更多,因為需要删除更多的過期資料。

六、惰性釋放

MySQL:“ 可以使用非阻塞的方式删除 bigkey 麼?”

我提供了兩種删除 key 的基本指令用于删除資料。

  • DEL 指令:這是一個阻塞的删除,執行該指令會停止處理寫請求,使用同步的方式去回收 DEL 删除的對象的記憶體。如果這個 key 對應的 value 是一個非常小的對象, DEL 執行的時間非常短,時間複雜度為 O(1) 或者 O(log n)。如果 key 對應的 value 非常大,比如集合對象的資料包含百萬個元素,伺服器将阻塞很長時間(幾秒鐘)才能完成操作。
  • UNLINK(非阻塞删除)、(異步删除) FLUSHALL ASYNC/FLUSHDB ASYNC:背景回收記憶體,這些指令在常量級别時間内執行,會使用一個新的線程在背景漸進的删除并釋放記憶體(Lazy Free 機制)。

1、lazyfree-lazy-eviction

由于 maxmemory 和 maxmemory-policy 政策配置,我會删除一些資料,防止記憶體爆掉。使用lazyfree-lazy-eviction yes表示使用 lazy free 機制,該場景開啟 lazy free 可能會導緻淘汰資料的記憶體釋放不及時,出現記憶體超限。

2、lazyfree-lazy-expire

對于設定了 TTL 的鍵,過期後删除。如果想啟用 lazy free 機制删除,則配置 lazyfree-lazy-eviction yes。

3、lazyfree-lazy-server-del

針對有些指令在處理已存在的鍵時,會帶有一個隐式的 DEL 鍵的操作。

如 rename 指令,當目标鍵已存在,我會先删除目标鍵,如果這些目标鍵是一個 big key,那可能會出現阻塞删除的性能問題。 此參數設定就是解決這類問題,建議配置 lazyfree-lazy-server-del yes 開啟。

4、replica-lazy-flush

該配置針對 slave 進行全量資料同步,在加載 master 的 RDB 記憶體快照檔案之前,會先運作 flashall清理資料的時候是否采用異步 flush 機制。

推薦你使用 replica-lazy-flush yes配置,可減少全量同步耗時,進而減少 master 因輸出緩沖區暴漲引起的記憶體增長。

5、lazyfree-lazy-user-del

意思是是否将 DEL 指令的預設行為替換成 lazy free 機制删除,效果就跟 UNLINK 一樣,隻要配置成 lazyfree-lazy-user-del yes。

6、lazyfree-lazy-user-flush

FLUSHDB, FLUSHALL, SCRIPT FLUSH, FUNCTION FLUSH可以使用額外參數 ASYNC|SYNC 決定使用同步還是異步操作,當沒有指定這個可選項,可以通過 lazyfree-lazy-user-flush yes 表示使用異步删除。

7、IO 多線程

大家知道我是單線程模型處理讀寫請求,但是有一些操作可以使用其他線程處理,比如 UNLINK,I/O 讀寫操作。

在 6.0 版本,我提供了 I/O 多線程處理 Socket 讀寫,利用 I/O 多線程可以提高用戶端 Socket 讀寫性能。

預設配置是關閉的,我隻建議當你的機器至少是 4 核 CPU 或者更多的情況啟用,并且配置的線程數少于機器總 CPU 核數,配置超過 8 個線程對提升沒什麼幫助。

當你的機器是四核 CPU,那可以嘗試配置使用 2~3 個 I/O 線程,如果是 8 核 CPU,一般隻需要配置 6 個線程。

如下配置表示開啟 I/O 線程組,線程組的 I/O 線程數量為 3。

io-threads-do-reads yes
io-threads 3           

七、AOF 持久化

除了 RDB 記憶體快照檔案作為持久化手段以外,還能使用 AOF(Append only file) 實作持久化,AOF 是一種可選的持久化政策提供更好資料安全性。

預設配置下,我最多隻會丢失一秒的資料,你甚至可以配置更進階别,最多隻丢失一次 write 操作,但這樣會對損耗性能。

1、appendonly

appendonly yes 表示開啟 AOF 持久化,可以同時開啟 AOF 和 RDB 記憶體快照持久化,如果開啟了 AOF ,我會先加載 AOF 用于恢複記憶體資料。

2、appendfilename

指定 AOF 檔案名稱,預設名字是 appendonly.aof。為了友善,你可以配置 appenddirname 指定 AOF 檔案存儲目錄。

3、appendfsync

調用作業系統的 fsync()函數告訴作業系統把輸出緩沖區的資料持久化到磁盤, AOF 檔案刷寫的頻率有三種。

  • no:不去主動調用 fsync(),讓作業系統自己決定何時寫磁盤。
  • always:每次 write 操作之後都調用 fsync(),非常慢,但是資料安全性最高。
  • everysec:每秒調用一次 fsync(),一個折中的政策,最多丢失一秒的資料。

預設配置是 appendfsync everysec,推薦大家這麼設定,兼顧了速度和資料安全。

4、no-appendfsync-on-rewrite

當 appendfsync 的配置設定成 always或者 everysec ,現在有一個背景 save 程序(可能是生成 RDB 記憶體快照的 bgsave 程序,也有可能是 AOF rewrite 程序)正在進行大量的磁盤 I/O 操作,會造成調用 fsync()執行太長,後續其他想要調用 fsync() 的程序就會阻塞。

為了緩解這個問題,可以使用以下配置 no-appendfsync-on-rewrite yes 表示當已經有 bgsave和bgrewriteaof 背景程序在調用 fsync() 時,不再開啟新程序執行 AOF 檔案寫入。

這樣的話,就會出現目前有子程序在做 bgsave 或者其他的磁盤操作時,我就無法繼續寫 AOF 檔案,這意味着可能會丢失更多資料。

如果有延遲問題,請将此選項改為 yes。否則将其保留為 no。從持久化的角度來看,no是最安全的選擇。

5、AOF 重寫

為了防止 AOF 檔案過大,antirez 大佬給我搞了個 AOF 重寫機制。

auto-aof-rewrite-percentage 100 表示目前 AOF 檔案大小超過上一次重寫的 AOF 檔案大小的百分之多少(如果沒有執行過 AOF 重寫,那就參照原始 AOF 檔案大小),則執行 AOF 檔案重寫操作。

除了這個配置,你還要配置 auto-aof-rewrite-min-size 64mb 用于指定觸發 AOF 重寫操作的檔案大小。

如果該 AOF 檔案大小小于該值,即使檔案增長比例達到 100%,我也不會觸發 AOF 重寫操作,這是為了防止 AOF 檔案其實很小,但是滿足增長百分比時的多餘 AOF 重寫操作。

如果配置為

auto-aof-rewrite-percentage 0 ,表示禁用 AOF 重寫功能,建議大家開啟 AOF 重寫,防止檔案過大。

6、aof-load-truncated

MySQL:如果 AOF 檔案是損壞的,你還加載資料還原到記憶體中麼?

加載 AOF 檔案把資料還原到記憶體中,檔案可能是損壞的,比如檔案末尾是錯誤的。這種情況一般是由于當機導緻,尤其是使用 ext4 檔案系統挂載時沒配置 data=ordered 選項。

在這種情況下,我可以直接報錯,或者盡可能的讀取可讀的 AOF 内容。

如果配置成 aof-load-truncated yes,我依然會加載并讀取這個損壞的 AOF 檔案,并記錄一個錯誤日志通知程式員。

配置成 aof-load-truncated no,我就會報錯并拒絕啟動服務,你需要使用 redis-check-aof 工具修複 AOF 檔案,再啟動 Redis。如果修複後還是錯誤,我依然報錯并拒絕啟動。

7、aof-use-rdb-preamble

這就是大名鼎鼎的 RDB-AOF 混合持久化功能,配置成 aof-use-rdb-preamble yes(必須先開啟 AOF),AOF 重寫生成的檔案将同時包含 RDB 格式的内容和 AOF 格式内容。

混合持久化是在 AOF 重寫完成的,開啟混合持久化後,fork 出的子程序先将記憶體資料以 RDB 的方式寫入 AOF 檔案,接着把 RDB 格式資料寫入 AOF 檔案期間收到的增量指令從重寫緩沖區以 AOF 格式寫到檔案中。

寫入完成後通知主程序更新統計資訊,并把含有 RDB 格式和 AOF 格式的 AOF 檔案替換舊的 AOF 檔案。

這樣的好處是可以結合 RDB 和 AOF 的優點,實作快速加載同時避免丢失過多資料,缺點是 AOF 檔案的 RDB 部分内容不是 AOF 格式,可讀性差(都是程式解析讀取,哪個傻瓜程式員去讀這個呀),強烈推薦你使用這個來保證持久化。

8、aof-timestamp-enabled

我在 7.0 版本新增的特性,大體就是講 AOF 現在支援時間戳了,你可以做到基于時間點來恢複資料。

預設是 aof-timestamp-enabled no 表示關閉該特性,你可以按照實際需求選擇開啟。

八、Cluster 叢集

Redis Cluster 叢集相關配置,使用叢集方式的你必須重視和知曉。别嘴上原理說的頭頭是道,而叢集有哪些配置?如何配置讓叢集快到飛起,實作真正的高可用卻一頭霧水,通過下面這些配置詳解也讓你對叢集原理更加深刻。

1、cluster-enabled

普通的 Redis 執行個體是不能成為叢集的一員,想要将該節點加入 Redis Cluster,需要設定 cluster-enabled yes。

2、cluster-config-file

cluster-config-file nodes-6379.conf 指定叢集中的每個節點檔案。

叢集中的每個節點都有一個配置檔案,這個檔案并不是讓程式員編輯的,是我自己建立和更新的,每個節點都要使用不同的配置檔案,一定要確定同一個叢集中的不同節點使用的是不同的檔案。

3、cluster-node-timeout

設定叢集節點不可用的最大逾時時間,節點失效檢測。叢集中當一個節點向另一個節點發送 PING 指令,但是目标節點未在給定的時限内傳回 PING 指令的回複時,那麼發送指令的節點會将目标節點标記為 PFAIL(possible failuer,可能已失效);

如果 master 節點超過這個時間還是無響應,則用它的從節點将啟動故障遷移,更新成主節點。

預設配置是 cluster-node-timeout 15000,機關是毫秒數。

4、cluster-port

該端口是叢集總線監聽 TCP 連接配接的端口,預設配置為 cluster-port 0,我就會把端口綁定為用戶端指令端口 + 10000(用戶端端口預設 6379,是以綁定為 16379 作為叢集總線端口)。每個 Redis Cluster 節點都需要開放兩個端口:

  • 一個用于服務于用戶端的 TCP 端口,比如 6379.
  • 另一個稱為叢集總線端口,節點使用叢集總線進行故障監測、配置更新、故障轉移等。用戶端不要與叢集總線端口通信,另外請確定在防火牆打開這兩個端口,否則 Redis 叢集之間将無法通信。

5、

cluster-replica-validity-factor

該配置用于決定當 Redis Cluster 叢集中,一個 master 當機後,如何選擇一個 slave 節點完成故障轉移自動恢複(failover)。如果設定為 0 ,則不管 slave 與 master 之間斷開多久,都有資格成為 master。

下面提供了兩種方式來評估 slave 的資料是否太舊。

  • 如果有多個 slave 可以 failover,他們之間會通過交換資訊選出擁有擁有最大複制 offset 的 slave 節點。
  • 每個 slave 節點計算上次與 master 節點互動的時間,這個互動包含最後一次 ping 操作、master 節點傳輸過來的寫指令、上次與 master 斷開的時間等。如果上次互動的時間過去很久,那麼這個節點就不會發起 failover。

針對第二點,互動時間可以通過配置定義,如果 slave 與 master 上次互動的時間大于 (node-timeout *

cluster-replica-validity-factor) + repl-ping-replica-period,該 slave 就不會發生 failover。

例如,`node-timeout = 30秒,

cluster-replica-validity-factor=10,repl-ping-slave-period=10秒, 表示 slave 節點與 master 節點上次互動時間已經過去了 310 秒,那麼 slave 節點就不會做 failover。

調大

cluster-replica-validity-factor 則允許存儲過舊資料的 slave 節點提升為 master,調小的話可能會導緻沒有 slave 節點可以升為 master 節點。

考慮高可用,建議大家設定為

cluster-replica-validity-factor 0。

6、cluster-migration-barrier

沒有 slave 節點的 master 節點稱為孤兒 master 節點,這個配置就是用于防止出現孤兒 master。

當某個 master 的 slave 節點當機後,叢集會從其他 master 中選出一個富餘的 slave 節點遷移過來,確定每個 master 節點至少有一個 slave 節點,防止當孤立 master 節點當機時,沒有 slave 節點可以升為 master 導緻叢集不可用。

預設配置為 cluster-migration-barrier 1,是一個遷移臨界值。

含義是:被遷移的 master 節點至少還有 1 個 slave 節點才能做遷移操作。比如 master A 節點有 2 個以上 slave 節點 ,當叢集出現孤兒 master B 節點時,A 節點富餘的 slave 節點可以遷移到 master B 節點上。

生産環境建議維持預設值,最大可能保證高可用,設定為非常大的值或者配置

cluster-allow-replica-migration no 禁用自動遷移功能。

cluster-allow-replica-migration 預設配置為 yes,表示允許自動遷移。

7、

cluster-require-full-coverage

預設配置是 yes,表示為當 redis cluster 發現還有哈希槽沒有被配置設定時禁止查詢操作。

這就會導緻叢集部分當機,整個叢集就不可用了,當所有哈希槽都有配置設定,叢集會自動變為可用狀态。

如果你希望 cluster 的子集依然可用,配置成

cluster-require-full-coverage no。

8、

cluster-replica-no-failover

當配置成 yes,在 master 當機時,slave 不會做故障轉移升為 master。

這個配置在多資料中心的情況下會很有用,你可能希望某個資料中心永遠不要更新為 master 節點,否則 master 節點就漂移到其他資料中心了,正常情況設定成 no。

9、

cluster-allow-reads-when-down

預設是 no,表示當叢集因主節點數量達不到最小值或者哈希槽沒有完全配置設定而被标記為失效時,節點将停止所有用戶端請求。

設定成 yes,則允許叢集失效的情況下依然可從節點中讀取資料,保證了高可用。

10、

cluster-allow-pubsubshard-when-down

配置成 yes,表示當叢集因主節點數量達不到最小值或者哈希槽沒有完全配置設定而被标記為失效時,pub/sub 依然可以正常運作。

11、

cluster-link-sendbuf-limit

設定每個叢集總線連接配接的發送位元組緩沖區的記憶體使用限制,超過限制緩沖區将被清空(主要為了防止發送緩沖區發送給慢速連接配接時無限延長時間的問題)。

預設禁用,建議最小設定 1gb,這樣預設情況下叢集連接配接緩沖區可以容納至少一條 pubsub 消息(client-query-buffer-limit 預設是 1gb);

九、性能監控

1、慢查詢日志

慢查詢(Slow Log)日志是我用于記錄慢查詢執行時間的日志系統,隻要查詢超過配置的時間,都會記錄。slowlog 隻儲存在記憶體中,是以效率很高,大家不用擔心會影響到 Redis 的性能。

執行時間不包括 I/O 操作的時間,比如與用戶端建立連接配接、發送回複等,隻記錄執行指令執行階段所需要的時間。

你可以使用兩個參數配置慢查詢日志系統。

  • slowlog-log-slower-than:指定對執行時間大于多少微秒(microsecond,1 秒 = 1,000,000 微秒)的查詢進行記錄,預設是 10000 微妙,推薦你先執行基線測試得到一個基準時間,通常這個值可以設定為基線性能最大延遲的 3 倍。
  • slowlog-max-len:設定最多儲存多少條慢查詢的日志,slowlog 本身是一個 FIFO 隊列,當超過設定的最大值後,我會把最舊的一條日志删除。預設配置 128,如果設定太大會占用多大記憶體。

2、延遲監控

延遲監控(LATENCY MONITOR)系統會在運作時抽樣部分指令來幫助你分析 Redis 卡頓的原因。

通過 LATENCY指令,可以列印一些視圖和報告,系統隻會記錄大于等于指定值的指令。

預設配置 latency-monitor-threshold 0,設定 0 表示關閉這個功能。沒有延遲問題,沒必要開啟開啟監控,因為會對性能造成很大影響。

在運作過程中你懷疑有延遲性能問題,想要監控的話可以使用 CONFIG SET latency-monitor-threshold <milliseconds>開啟,機關是毫秒。

十、進階設定

這部配置設定置主要圍繞以下幾個方面。

  • 指定不同資料類型根據不同條數下使用不同的資料結構存儲,合理配置能做到更快和更省記憶體。
  • 用戶端緩沖區相關配置。
  • 漸進式 rehash 資源控制。
  • LFU 調優。
  • RDB 記憶體快照檔案、AOF 檔案同步政策。

1、Hashes(散清單)

在 Redis 7.0 版本散清單資料類型有兩種資料結構儲存資料,分别為散清單和 listpack。當資料量很小時,可以使用更高效的資料結構存儲,進而達到在不影響性能的情況下節省記憶體。

  • hash-max-listpack-entries 512:指定使用 listpack 存儲的最大條目數。
  • hash-max-listpack-value 64:listpack 中,條目 value 值最大位元組數,建議設定成 1024。

在 7.0 版本以前,使用的是 ziplist 資料結構,配置如下。

hash-max-ziplist-entries 512
hash-max-ziplist-value 64           

2、Lists(清單)

Lists 也可以使用一種特殊方式進行編碼來節省大量記憶體空間。在 Redis 7.0 之後,Lits 底層的資料結構使用 linkedlist 或者 listpack 。

Redis 3.2 版本,List 内部是通過 linkedlist 和 quicklist 實作,quicklist 是一個雙向連結清單, quicklist 的每個節點都是一個 ziplist,進而實作節省記憶體。

元素少時用 quicklist,元素多時用 linkedlist。listpack 的目的就是用于替代 ziplist 和 quicklist。listpack 也叫緊湊清單,它的特點就是用一塊連續的記憶體空間來緊湊地儲存資料,同時為了節省記憶體空間

list-max-ziplist-size

7.0 版本之前list-max-ziplist-size 用于配置 quicklist 中的每個節點的 ziplist 的大小。 當這個值配置為正數時表示 quicklist 每個節點的 ziplist 最多可存儲元素數量,超過該值就會使用 linkedlist 存儲。

當 list-max-ziplist-size 為負數時表示限制每個 quicklistNode 的 ziplist 的記憶體大小,超過這個大小就會使用 linkedlist 存儲資料,每個值有以下含義:

  • -5:每個 quicklist 節點上的 ziplist 大小最大 64 kb <--- 正常環境不推薦
  • -4:每個 quicklist 節點上的 ziplist 大小最大 32 kb <--- 不推薦
  • -3:每個 quicklist 節點上的 ziplist 大小最大 16 kb <--- 可能不推薦
  • -2:每個 quicklist 節點上的 ziplist 大小最大 8 kb <--- 不錯
  • -1:每個 quicklist 節點上的 ziplist 大小最大 4kb <--- 不錯

預設值為 -2,也是官方最推薦的值,當然你可以根據自己的實際情況進行修改。

list-max-listpack-size

7.0 之後,配置修改為list-max-listpack-size -2則表示限制每個 listpack 大小,不再贅述。

list-compress-depth

壓縮深度配置,用來配置壓縮 Lists 的,當 Lists 底層使用 linkedlist 也是可以壓縮的,預設是 list-compress-depth 0表示不壓縮。一般情況下,Lists 的兩端通路的頻率高一些,是以你可以考慮把中間的資料進行壓縮。

不同參數值的含義如下。

  • 0,關閉壓縮,預設值。
  • 1,兩端各有一個節點不壓縮。
  • 2,兩端各有兩個節點不壓縮。
  • N,依次類推,兩端各有 N 個節點不壓縮。

需要注意的是,head 和 tail 節點永遠都不會被壓縮。

3、Sets(無序集合)

Sets 底層的資料結構可以是 intset(整形數組)和 Hashtable(散清單),intset 你可以了解成數組,Hashtable 就是普通的散清單(key 存的是 Sets 的值,value 為 null)。有沒有覺得 Sets 使用散清單存儲是意想不到的事情?

set-max-intset-entries

當集合的元素都是 64 位以内的十進制整數時且長度不超過 set-max-intset-entries 配置的值(預設 512),Sets 的底層會使用 intset 存儲節省記憶體。添加的元素大于 set-max-intset-entries配置的值,底層實作由 intset 轉成散清單存儲。

4、SortedSets(有序集合)

在 Redis 7.0 版本之前,有序集合底層的資料結構有 ziplist 和 skipist,之後使用 listpack 代替了 ziplist。

7.0 版本之前,當集合元素個數小于 zset-max-ziplist-entries配置,同時且每個元素的值大小都小于zset-max-ziplist-value配置(預設 64 位元組,推薦調大到 128)時,我将使用 ziplist 資料結構存儲資料,有效減少記憶體使用。與此類似,7.0 版本之後我将使用 listpack 存儲。

## 7.0 之前的配置
zset-max-ziplist-entries 128
zset-max-ziplist-value 64
## 7.0 之後的配置
zset-max-listpack-entries 128
zset-max-listpack-value 64           

5、HyperLogLog

HyperLogLog 是一種進階資料結構,統計基數的利器。HyperLogLog 的存儲結構分為密集存儲結構和稀疏存儲結構兩種,預設為稀疏存儲結構,而我們常說的占用 12K 記憶體的則是密集存儲結構,稀疏結構占用的記憶體會更小。

hll-sparse-max-bytes

預設配置是 hll-sparse-max-bytes 3000,機關是 Byte,這個配置用于決定存儲資料使用稀疏資料結構(sparse)還是稠密資料結構(dense)。

如果 HyperLogLog 存儲内容大小大于 hll-sparse-max-bytes 配置的值将會轉換成稠密的資料結構(dense)。

推薦的值是 0~3000,這樣PFADD指令的并不會慢多少,還能節省空間。如果記憶體空間相對 cpu 資源更缺乏,可以将這個值提升到 10000。

6、Streams(流)

Stream 是 Redis 5.0 版本新增的資料類型。Redis Streams 是一些由基數樹(Radix Tree)連接配接在一起的節點經過 delta 壓縮後構成的,這些節點與 Stream 中的消息條目(Stream Entry)并非一一對應,而是每個節點中都存儲着若幹 Stream 條目,是以這些節點也被稱為宏節點或大節點。

stream-node-max-bytes 4096

機關為 Byte,預設值 4096,用于設定每個宏節點占用的記憶體上限為 4096,0 表示無限制。

stream-node-max-entries 100

用于設定每個宏節點存儲元素個數。 預設值 100,0 表示無限制。當一個宏節點存儲的 Stream 條目到達上限,新添加的條目會存儲到新的宏節點中。

7、rehash

我采用的是漸進式 rehash,這是一個惰性政策,不會一次性把所有資料遷移完,而是分散到每次請求中,這樣做的目的是防止資料太多要遷移阻塞主線程。

在漸進式 rehash 的同時,推薦你使用 activerehashing yes開啟定時輔助執行 rehash,預設情況下每一秒執行 10 次 rehash 加快遷移速度,盡可能釋放記憶體。

關閉該功能的話,如果這些 key 不再活躍不被被通路到,rehash 操作可能不再有機會完成,會導緻散清單占用更多記憶體。

8、用戶端輸出緩沖區限制

這三個配置是用來強制斷開用戶端連接配接的,當用戶端沒有及時把緩沖區的資料讀取完畢,我會認為這個用戶端可能完蛋了(一個常見的原因是 Pub/Sub 用戶端處理釋出者的消息不夠快),于是斷開連接配接。

一共分為三種不同類型的用戶端,分别設定不同的限制。

  • normal(普通),普通用戶端,包括 MONITOR 用戶端。
  • replica(副本用戶端),slave 節點的用戶端。
  • pubsub(釋出訂閱用戶端),至少訂閱了一個 pubsub 頻道或者模式的用戶端。

client-output-buffer-limit的文法如下。

client-output-buffer-limit <class> <hard limit> <soft limit> <soft seconds>           

<class> 表示不同類型的用戶端,當用戶端的緩沖區内容大小達到 <hard limit>後我就立馬斷開與這個用戶端的連接配接,或者達到 <soft limit> 并持續了 <soft seconds>秒後斷開。

預設情況下,普通用戶端不會限制,隻有後異步的用戶端才可能發送發送請求的速度比讀取響應速度快的問題。比如 pubsub 和 replica 用戶端會有預設的限制。

soft limit 或者 hard limit 設定為 0,表示不啟用此限制。預設配置如下。

client-output-buffer-limit normal 0 0 0
client-output-buffer-limit replica 256mb 64mb 60
client-output-buffer-limit pubsub 32mb 8mb 60           

9、client-query-buffer-limit

每個用戶端都有一個 query buffer(查詢緩沖區或輸入緩沖區),用于儲存用戶端發送指令,Redis Server 從 query buffer 擷取指令并執行。

如果程式的 Key 設計不合理,用戶端使用大量的 query buffer,導緻 Redis 很容易達到 maxmeory 限制。最好限制在一個固定的大小來避免占用過大記憶體的問題。

如果你需要發送巨大的 multi/exec 請求的時候,那可以适當修改這個值以滿足你的特殊需求。

預設配置為 client-query-buffer-limit 1gb。

10、maxmemory-clients

這是 7.0 版本特性,每個與服務端建立連接配接的用戶端都會占用記憶體(查詢緩沖區、輸出緩沖區和其他緩沖區),大量的用戶端可能會占用過大記憶體導緻 OOM,為了避免這個情況,我提供了一種叫做(Client Eviction)用戶端驅逐機制用于限制記憶體占用。

配置方式有兩種。

  • 具體記憶體值, maxmemory-clients 1g來限制所有用戶端占用記憶體總和。
  • 百分比,maxmemory-clients 5% 表示用戶端總和記憶體占用最多為 Redis 最大記憶體配置的 5%。

預設配置是 maxmemory-clients 0 表示無限制。

MySQL:“達到最大記憶體限制,你會把所有用戶端連接配接都釋放麼?”

不是的,一旦達到限制,我會優先嘗試斷開使用記憶體最多的用戶端。

11、proto-max-bulk-len

批量請求(單個字元串的元素)記憶體大小限制,預設是 proto-max-bulk-len 512mb,你可以修改限制,但必須大于等于 1mb。

12、hz

我會在背景調用一些函數來執行很多背景任務,比如關閉逾時連接配接,清理不再被請求的過期的 key,rehash、執行 RDB 記憶體快照和 AOF 持久化等。

并不是所有的背景任務都需要使用相同的頻率來執行,你可以使用 hz 參數來決定執行這些任務的頻率。

預設配置是 hz 10,表示每秒執行 10 次,更大的值會消耗更多的 CPU 來處理背景任務,帶來的效果就是更快的清理過期 key,清理的逾時連接配接更精确。

這個值的範圍是 1~500,不過并不推薦設定大于 100 的值。大家使用預設值就好,或者最多調高到 100。

13、dynamic-hz

預設配置是 dynamic-hz yes,啟用 dynamic-hz 後,将啟用自适應 HZ 值的能力。hz 的配置值将會作為基線,Redis 服務中的實際 hz 值會在基線值的基礎上根據已連接配接到 Redis 的用戶端數量自動調整,連接配接的用戶端越多,實際 hz 值越高,Redis 執行定期任務的頻率就越高。

14、

aof-rewrite-incremental-fsync

當子程序進行 AOF 重寫時,如果配置成

aof-rewrite-incremental-fsync yes,每生成 4 MB 資料就執行一次 fsync操作,分批送出到硬碟來避免高延遲峰值,推薦開啟。

15、

rdb-save-incremental-fsync

當我在儲存 RDB 記憶體快照檔案時,如果配置成 db-save-incremental-fsync yes,每生成 4MB 檔案就執行一次 fsync操作,分批送出到硬碟來避免高延遲峰值,推薦開啟。

16、LFU 調優

這個配置生效的前提是記憶體淘汰政策設定的是 volatile-lfu或allkeys-lfu。

  • lfu-log-factor 用于調整 Logistic Counter 的增長速度,lfu-log-factor 值越大,Logistic Counter 增長越慢。預設配置 10。
  • 以下是表格是官方不同 factor 配置下,計數器的改變頻率。注意:表格是通過如下指令獲得的: redis-benchmark -n 1000000 incr foo redis-cli object freq foo。
  • factor100 hits1000 hits100K hits1M hits10M hits01042552552552551184925525525510101814225525510081149143255
  • lfu-decay-time 用于調整 Logistic Counter 的衰減速度,它是一個以分鐘為機關的數值,預設值為 1;lfu-decay-time 值越大,衰減越慢。

十一、線上記憶體碎片整理

MySQL:“什麼是線上記憶體碎片整理?”

Active (online) defragmentation 線上記憶體碎片整理指的是自動壓縮記憶體配置設定器配置設定和 Redis 頻繁做更新操作、大量過期資料删除,釋放的空間(不夠連續)無法得到複用的記憶體空間。

通常來說當碎片化達到一定程度(檢視下面的配置)Redis 會使用 Jemalloc 的特性建立連續的記憶體空間, 并在此記憶體空間對現有的值進行拷貝,拷貝完成後會釋放掉舊的資料。 這個過程會對所有的導緻碎片化的 key 以增量的形式進行。

需要注意的是

  1. 這個功能預設是關閉的,并且隻有在編譯 Redis 時使用我們代碼中的 Jemalloc 版本才生效。(這是 Linux 下的預設行為)。
  2. 在實際使用中,建議是在 Redis 服務出現較多的記憶體碎片時啟用(記憶體碎片率大于 1.5),正常情況下盡量保持禁用狀态。
  3. 如果你需要試驗這項特性,可以通過指令 CONFIG SET activefrag yes來啟用。

清理的條件

activefrag yes:記憶體碎片整理總開關,預設為禁用狀态 no。

active-defrag-ignore-bytes 200mb:記憶體碎片占用的記憶體達到 200MB。

active-defrag-threshold-lower 20:記憶體碎片的空間占比超過系統配置設定給 Redis 空間的 20% 。

在同時滿足上面三項配置時,記憶體碎片自動整理功能才會啟用。

CPU 資源占用

MySQL:如何避免自動記憶體碎片整理對性能造成影響?

清理的條件有了,還需要配置設定清理碎片占用的 CPU 資源,保證既能正常清理碎片,又能避免對 Redis 處理請求的性能影響。

active-defrag-cycle-min 5:自動清理過程中,占用 CPU 時間的比例不低于 5%,進而保證能正常展開清理任務。

active-defrag-cycle-max 20:自動清理過程占用的 CPU 時間比例不能高于 20%,超過的話就立刻停止清理,避免對 Redis 的阻塞,造成高延遲。

整理力度

active-defrag-max-scan-fields 1000:碎片整理掃描到set/hash/zset/list 時,僅當 set/hash/zset/list的長度小于此閥值時,才會将此鍵值對加入碎片整理,大于這個值的鍵值對會放在一個清單中延遲處理。

active-defrag-threshold-upper 100:記憶體碎片空間占作業系統配置設定給 Redis 的總空間比例達此門檻值(預設 100%),我會盡最大努力整理碎片。建議你調整為 80。

1、jemalloc-bg-thread

預設配置為 jemalloc-bg-thread yes,表示啟用清除髒頁背景線程。

2、綁定 CPU

你可以将 Redis 的不同線程和程序綁定到特定的 CPU,減少上下文切換,提高 CPU L1、L2 Cache 命中率,實作最大化的性能。

你可以通過修改配置檔案或者taskset指令綁定。

可分為三個子產品。

  • 主線程和 I/O 線程:負責指令讀取、解析、結果傳回。指令執行由主線程完成。
  • bio 線程:負責執行耗時的異步任務,如 close fd、AOF fsync 等。
  • 背景程序:fork 子程序(RDB bgsave、AOF rewrite bgrewriteaof)來執行耗時的指令。

Redis 支援分别配置上述子產品的 CPU 親合度,預設情況是關閉的。

  • server_cpulist 0-7:2,I/O 線程(包含主線程)相關操作綁定到 CPU 0、2、4、6。
  • bio_cpulist 1,3,bio 線程相關的操作綁定到 CPU 1、3。
  • aof_rewrite_cpulist,aof rewrite 背景程序綁定到 CPU 8、9、10、11。
  • bgsave_cpulist 1,10-11,bgsave 背景程序綁定到 CPU 1、10、11。

注意事項

  1. Linux 下,使用 「numactl --hardware」 檢視硬體布局,確定支援并開啟 NUMA。
  2. 線程要盡可能分布在 不同的 CPU,相同的 node,設定 CPU 親和度才有效,否則會造成頻繁上下文切換。
  3. 你要熟悉 CPU 架構,做好充分的測試。否則可能适得其反,導緻 Redis 性能下降。

文章來源:

https://segmentfault.com/a/1190000043845458

繼續閱讀