Redis爲什麼快???

一、 Redis有多快?

Redis不是一般地快!

Redis和Memcached同爲內存數據庫,且都支持分佈式,近年來,Redis憑藉着優秀的架構設計,不斷蠶食Memcached領地,大有一統天下的趨勢。

感受一下redis高端配置的吞吐量,橫軸爲連接數,縱軸爲吞吐量,圖片來源於官方文檔

Requests per second

基於epoll/kqueue,Redis事件循環具有很強的可擴展性。Redis已經在60000多個連接上進行了基準測試,並且在這些條件下仍能夠維持50000q/s。根據經驗,具有30000個連接的實例只能處理100個連接可實現的吞吐量的一半。

二、Redis爲什麼快?

2.1 採用單線程

單線程意味着,Redis不再考慮鎖和進程的上下文切換及資源競爭問題。

Redis的單線程是指,網絡請求處理模塊使用了一個線程,Redis是線程安全的,不考慮併發安全性,也就是說,一個線程處理所有網絡請求。

需要注意的是,Redis其他模塊仍然使用了多個線程,如,文件的定時備份和恢復,執行數據清理策略等。

2.2 絕大部分請求是內存操作

  • 內存操作:
    • 內存數據讀寫
  • 磁盤持久化操作:
    • 文件備份與恢復

這裏可以簡單理解爲,Redis處理網絡請求的單個線程涉及到的操作都是內存操作,其他與磁盤相關的操作是其他線程來完成的。

2.3 採用IO多路複用策略epoll

IO多路複用的策略有select、pselect、poll和epoll,其中pselect與select大同小異,epoll是select和poll的改進版本。

epoll與select和poll相比,具有如下優點:

  1. 沒有最大併發連接的限制。select和poll有系統FD_SETSIZE限制的問題,32位機器默認1024,64位機器默認是2048,epoll解決了select和poll只能監聽有限數量FD(文件描述符)的問題,1G內存能監聽10萬左右的端口;
  2. 只遍歷活躍的Socket,輪詢效率高。select和poll不管Socket是否活躍,會遍歷所有Socket,包括idle-connection和dead-connection,而epoll最大的優點就在於只管“活躍”的連接,與連接總數無關,因此,epoll效率更高;
  3. 內核空間和用戶空間共享內存來減少FD複製的開銷。利用mmap()文件映射內存加速與內核空間的消息傳遞來實現。epoll使用一個文件描述符管理多個描述符,將用戶關係的文件描述符的事件存放到內核的一個事件表中,這樣在用戶空間和內核空間的copy只需一次,而select和poll需要將消息從內核傳遞到用戶空間,都需要多次內核拷貝動作。

2.4 其他優化

2.4.1 壓縮存儲

Redis的數據類型都可能有2種或者多種內部編碼實現,這使得Redis可以根據不同的場景選擇最優的編碼方式。

閱讀源碼會發現,當數據量較小時,Redis會使用ziplist實現list,使用zipmap實現HashTable,ziplist和zipmap是經過精心設計的數據編碼方式,ziplist和zipmap在內存中的存儲都是連續內存空間。ziplist列表兩端push和pop操作都是O(1),zmap的key查詢爲O(n),爲string-> string結構,節省了空間。

具體可參考源碼:redis/src/ziplist.credis/src/zipmap.c

2.4.2 數據淘汰策略的優化

最新版本Redis v5.4具有8種Eviction策略,其中,LFU爲最近版本加入。

值得一提的是,Redis實現的LRU是經典LRU的一種近似,簡單說就是有一個專用的eviction poll,當執行evict時,採樣N個樣本,並非經典LRU算法的所有樣本,加入到eviction poll,eviction poll的大小由EVPOOL_SIZE來定義。正是由於選取有限個值(一般是5)使用LRU算法,這大大提高了效率。

所有的策略如下:

Policy Description
noeviction 如果在嘗試插入更多數據時達到內存限制,則返回錯誤
allkeys-lru 從所有key中刪除最近最少使用的key
allkeys-lfu 從所有key中刪除最不常用的key
allkeys-random 隨機刪除所有key中的key
volatile-lru 使用“expire”字段從所有key中刪除最近最少使用的key
volatile-lfu 使用“expire”字段從所有key中刪除最不常用的key
volatile-random 使用“expire”字段隨機刪除key
volatile-ttl 使用“expire”字段,從所有key中刪除最短的生存時間和最近最少使用的key

LRU和LFU具體算法可參考源碼:redis/src/evict.c

2.4.3 數據結構及架構設計

這部分內容較爲繁雜,專用的數據結構都有很多巧妙的設計,如,sds、redisobj等,有興趣的可以讀讀源碼。

總結

早期Memcached強調Cache,而如今Redis強調DB,大多時候Redis可以替代Memached。
單線程情況下,Redis往往比Memcached快,但Memcached本身基於多線程,這是它的優勢所在,多線程情況下,Memcached往往比Redis快。具體的快慢總是相對的,需要根據自己的業務場景,適配合適的工具,除非性能是整個技術架構中的瓶頸,否則,應該長遠考慮架構的穩定性和拓展性。

參考文獻

  1. 聊聊IO多路複用之select、poll、epoll詳解
  2. select和pselect區別
  3. How fast is Redis?
  4. 爲什麼Redis是單線程?
  5. Redis Eviction Policies
  6. Redis源碼

能力有限,歡迎指錯交流~

個人微信公衆號WaltSmithML
主要方向爲NLP和推薦系統。非常歡迎交流學習

數學與機器學習

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章