爲何單線程的redis那麼快

這是我參與8月更文挑戰的第4天,活動詳情查看:8月更文挑戰redis

redis單機QPS

./redis-benchmark -t set,lpush -n 100000 -q
SET: 82101.80 requests per second
LPUSH: 82440.23 requests per second
複製代碼

在本身的電腦上測試SET和LPUSH10萬次,能夠發現每秒SET和LPUSH大概在8w多,接近官方說的單機10w qps的寫。數據庫

爲何這麼快

內存型數據庫

redis徹底是基於內存的,絕大部分請求是純粹的內存操做,因此很是快速。markdown

簡單的數據結構

redis目前支持5種數據類型(string、list、hash、set、zset),數據結構相對簡單,操做起來也相對快速。網絡

sds數據結構數據結構

對於string來講,redis採用SDS方式來組織數據:多線程

截屏2021-08-01 下午12.53.33.png 這種數據的核心思想就是空間換時間併發

  1. 空間預分配:當空間擴展時,不只分配所需空間,還會分配額外的空間
  • 分配後sds長度小於1M,那麼也分配一樣大小的額外空間,假設一個key修改後 len=13,那麼也分配free=13,最後buf=13+13+1=27
  • 若是分配後len大於等於1M,那麼額外固定分配1M,假設修改後len=30M,分配free=1M,最後buf=30M+1M+1byte
  1. 惰性空間釋放
  • 假設有個len=13free=13的字符串,這時候若是字符變短了len=10,那麼額外的3個byte的空間也不會回收,先放在free裏面,這時候free=16

經過這種分配方式,某些場景下能夠減小內存申請的次數,從而達到必定的快速socket

跳躍表svn

redis的有序集合,採用的跳躍表的數據結構,經過層來加快訪問其餘節點oop

截屏2021-08-01 下午1.20.18.png 每一個節點會隨機一個層高,好比o1節點能夠經過L4層直接跳到o3,跨度是2,redis的有序集合就是經過這種方式來加快節點之間的訪問的。

單線程

redis採用單線程模型,單線程的好處在於避免了多線程對數據競爭的問題,加鎖的問題,上下文切換的問題。
據官方解釋,redis的瓶頸不在cpu,而在內存或者網絡的帶寬,綜合考慮而後就採用了單線程。這裏說的單線程是指處理網絡請求時只是用一個線程,redis自己在持久化的時候仍是會用到額外的線程的。

redis4.0的多線程

redis4.0開始也支持了多線程,固然只是針對部分命令採用的是多線程,例如:UNLINKFLUSHALLASYNCFLUSHDB。引入這些的目的是:在某些狀況下,儘量的提高效率,假設有一個key大到幾十M,這時DEL這個key的時候,可能會短暫的阻塞,這時若是用unlink來刪除,剛開始只是刪除這個key,真正的value是後臺線程去刪除的。

IO多路複用

redis採用了非阻塞的IO多路複用技術。redis自己就是一個事件驅動程序,redis把socket抽象成文件事件。這裏說的IO多路複用就是文件事件處理器以單線程的方式,來監聽相關的套接字(accept、read、write、close)。

截屏2021-08-01 上午11.19.41.png 因爲IO多路複用程序是一個單線程,那麼當多個socket到來時,確定要排隊,它們老是以隊列的方式順序地處理。

C10K問題

在沒有IO多路複用的時候,假設如今有10000個客戶端鏈接(fd1-10000),可是隻有1個客戶端有發數據,然而計算機並不知道哪一個fd有數據,只能遍歷10000次,每次都要陷入內核,開銷比較大,並且實際上9999次都是浪費的。

IO多路複用

IO多路複用的意思就是多個網路IO即爲多個TCP鏈接 複用一個進程或者線程,這種模型最大的好處就是不用爲每一個鏈接建立一個進程或者線程。比較經典的模型就是 selectpollepoll

  1. select:select(fds),一次性把fds交給內核,而後內核告訴哪些fd可讀可寫(內核本身遍歷,而不用用戶遍歷,將屢次的系統調用變成1次系統調用)。fds最大是1024,這也決定了select模型最大併發是1024。
  2. poll:和select差很少,只不過併發不止1024了,能夠更多
  3. epoll: select和poll的缺點是內核遍歷的時間複雜度是O(n),雖然用戶態不用遍歷了,減小了陷入內核的次數,可是內核仍是要遍歷的。epoll的優勢就是內核也不須要遍歷了,當用戶把fds傳給內核時,而後依賴硬件中斷,好比當網卡有數據到來時,就會中斷告訴cpu,cpu就知道哪一個fd有數據到達了。

redis默認採用epoll,除非系統不支持。

總結

  1. redis是內存型數據庫
  2. redis特殊的數據結構
  3. 單線程避免鎖的競爭
  4. io多路複用

以上4點是單線程redis快的主要緣由。

相關文章
相關標籤/搜索