Redis資料操作長延遲分析

FeelTouch發表於2019-03-20

1.  長耗時命令引起延遲

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

針對長耗時的最佳實踐:

  • 不要把List當做列表使用,僅當做佇列來使用
  • 通過機制嚴格控制Hash、Set、Sorted Set的大小
  • 可能的話,將排序、並集、交集等操作放在客戶端執行
  • 絕對禁止使用KEYS命令
  • 避免一次性遍歷集合型別的所有成員,而應使用SCAN類的命令進行分批的,遊標式的遍歷
  • 使用SUNION對兩個Set執行Union操作,或使用SORT對List/Set執行排序操作等時,都應該嚴加註意。
  • Redis提供了SCAN命令,可以對Redis中儲存的所有key進行遊標式的遍歷,避免使用KEYS命令帶來的效能問題
  • Redis提供了SSCAN/HSCAN/ZSCAN等命令,分別用於對Set/Hash/Sorted Set中的元素進行遊標式遍歷
  • 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

2.  網路引發的延遲

  • 儘可能使用長連線或連線池,避免頻繁建立銷燬連線
  • 客戶端進行的批量資料操作,考慮使用Pipeline特性在一次互動中完成。
  • 客戶端進行迴圈同型別操作,考慮用MGET,MSET,HMGET,HMSET來完成

3. 資料持久化引發的延遲

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操作的耗時(微秒)

4. Swap引發的延遲

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

/proc//smaps檔案中會儲存程式的swap記錄,通過檢視這個檔案,能夠判斷Redis的延遲是否由Swap產生。如果這個檔案中記錄了較大的Swap size,則說明延遲很有可能是Swap造成的。

5. 資料淘汰引發的延遲

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

參考:http://www.ttlsa.com/redis/redis-advanced-features-and-performance-tuning/

相關文章