redis全面解析(六)

redis全面解析(六)

Redis性能調優

儘管Redis是一個非常快速的內存數據存儲媒介,也並不代表Redis不會產生性能問題。

前文中提到過,Redis採用單線程模型,所有的命令都是由一個線程串行執行的,所以當某個命令執行耗時較長時,會拖慢其後的所有命令,這使得Redis對每個任務的執行效率更加敏感。

針對Redis的性能優化,主要從下面幾個層面入手:

  • 最初的也是最重要的,確保沒有讓Redis執行耗時長的命令
  • 使用pipelining將連續執行的命令組合執行
  • 操作系統的Transparent huge pages功能必須關閉:

echo never > /sys/kernel/mm/transparent_hugepage/enabled

  • 如果在虛擬機中運行Redis,可能天然就有虛擬機環境帶來的固有延遲。可以通過./redis-cli --intrinsic-latency 100命令查看固有延遲。同時如果對Redis的性能有較高要求的話,應儘可能在物理機上直接部署Redis。
  • 檢查數據持久化策略
  • 考慮引入讀寫分離機制

長耗時命令

Redis絕大多數讀寫命令的時間複雜度都在O(1)到O(N)之間,在文本和官方文檔中均對每個命令的時間複雜度有說明。

通常來說,O(1)的命令是安全的,O(N)命令在使用時需要注意,如果N的數量級不可預知,則應避免使用。例如對一個field數未知的Hash數據執行HGETALL/HKEYS/HVALS命令,通常來說這些命令執行的很快,但如果這個Hash中的field數量極多,耗時就會成倍增長。

又如使用SUNION對兩個Set執行Union操作,或使用SORT對List/Set執行排序操作等時,都應該嚴加註意。

避免在使用這些O(N)命令時發生問題主要有幾個辦法:

  • 不要把List當做列表使用,僅當做隊列來使用
  • 通過機制嚴格控制Hash、Set、Sorted Set的大小
  • 可能的話,將排序、並集、交集等操作放在客戶端執行
  • 絕對禁止使用KEYS命令
  • 避免一次性遍歷集合類型的所有成員,而應使用SCAN類的命令進行分批的,遊標式的遍歷

Redis提供了SCAN命令,可以對Redis中存儲的所有key進行遊標式的遍歷,避免使用KEYS命令帶來的性能問題。同時還有SSCAN/HSCAN/ZSCAN等命令,分別用於對Set/Hash/Sorted Set中的元素進行遊標式遍歷。SCAN類命令的使用請參考官方文檔:https://redis.io/commands/scan

Redis提供了Slow Log功能,可以自動記錄耗時較長的命令。相關的配置參數有兩個:

slowlog-log-slower-than xxxms #執行時間慢於xxx毫秒的命令計入Slow Log

slowlog-max-len xxx #Slow Log的長度,即最大紀錄多少條Slow Log

使用SLOWLOG GET [number]命令,可以輸出最近進入Slow Log的number條命令。

使用SLOWLOG RESET命令,可以重置Slow Log

網絡引發的延遲

  • 儘可能使用長連接或連接池,避免頻繁創建銷燬連接
  • 客戶端進行的批量數據操作,應使用Pipeline特性在一次交互中完成。具體請參照本文的Pipelining章節

數據持久化引發的延遲

Redis的數據持久化工作本身就會帶來延遲,需要根據數據的安全級別和性能要求制定合理的持久化策略:

  • AOF + fsync always的設置雖然能夠絕對確保數據安全,但每個操作都會觸發一次fsync,會對Redis的性能有比較明顯的影響
  • AOF + fsync every second是比較好的折中方案,每秒fsync一次
  • AOF + fsync never會提供AOF持久化方案下的最優性能
  • 使用RDB持久化通常會提供比使用AOF更高的性能,但需要注意RDB的策略配置
  • 每一次RDB快照和AOF Rewrite都需要Redis主進程進行fork操作。fork操作本身可能會產生較高的耗時,與CPU和Redis佔用的內存大小有關。根據具體的情況合理配置RDB快照和AOF Rewrite時機,避免過於頻繁的fork帶來的延遲

Redis在fork子進程時需要將內存分頁表拷貝至子進程,以佔用了24GB內存的Redis實例為例,共需要拷貝24GB / 4kB * 8 = 48MB的數據。在使用單Xeon 2.27Ghz的物理機上,這一fork操作耗時216ms。

可以通過INFO命令返回的latest_fork_usec字段查看上一次fork操作的耗時(微秒)

Swap引發的延遲

當Linux將Redis所用的內存分頁移至swap空間時,將會阻塞Redis進程,導致Redis出現不正常的延遲。Swap通常在物理內存不足或一些進程在進行大量I/O操作時發生,應儘可能避免上述兩種情況的出現。

/proc//smaps文件中會保存進程的swap記錄,通過查看這個文件,能夠判斷Redis的延遲是否由Swap產生。如果這個文件中記錄了較大的Swap size,則說明延遲很有可能是Swap造成的。

數據淘汰引發的延遲

當同一秒內有大量key過期時,也會引發Redis的延遲。在使用時應儘量將key的失效時間錯開。

引入讀寫分離機制

Redis的主從複製能力可以實現一主多從的多節點架構,在這一架構下,主節點接收所有寫請求,並將數據同步給多個從節點。

在這一基礎上,我們可以讓從節點提供對實時性要求不高的讀請求服務,以減小主節點的壓力。

尤其是針對一些使用了長耗時命令的統計類任務,完全可以指定在一個或多個從節點上執行,避免這些長耗時命令影響其他請求的響應。

關於讀寫分離的具體說明,請參見後續章節


分享到:


相關文章: