歡迎關注
CSDN:程序員小羊
微信公眾號:程序員小羊
博客園:程序員小羊
一、什么是Redis
redis是一個高性能的key-value數據庫,它是完全開源免費的,而且redis是一個NOSQL類型數據庫,是為了解決高並發、高擴展,大數據存儲等一系列的問題而產生的數據庫解決方案,是一個非關系型的數據庫。但是,它也是不能替代關系型數據庫,只能作為特定環境下的擴充。
redis是一個以key-value存儲的數據庫結構型服務器,它支持的數據結構類型包括:字符串(String)、鏈表(lists)、哈希表(hash)、集合(set)、有序集合(Zset)等。為了保證讀取的效率,redis把數據對象都存儲在內存當中,它可以支持周期性的把更新的數據寫入磁盤文件中。而且它還提供了交集和並集,以及一些不同方式排序的操作。
二、Redis到底有多快
Redis采用的是基於內存的采用的是單進程單線程模型的 KV 數據庫,由C語言編寫,官方提供的數據是可以達到100000+的QPS(每秒內查詢次數)。這個數據不比采用單進程多線程的同樣基於內存的 KV 數據庫 Memcached 差!有興趣的可以參考官方的基准程序測試《How fast is Redis?》(https://redis.io/topics/benchmarks)
橫軸是連接數,縱軸是QPS。 此時,這張圖反映了一個數量級,希望大家在面試的時候可以正確的描述出來,不要問你的時候,你回答的數量級相差甚遠!
三、Redis為什么這么快
-
完全基於內存,絕大部分請求是純粹的內存操作,非常快速。數據存在內存中,類似於HashMap,HashMap的優勢就是查找和操作的時間復雜度都是O(1);
-
數據結構簡單,對數據操作也簡單,Redis中的數據結構是專門進行設計的;
-
采用單線程,避免了不必要的上下文切換和競爭條件,也不存在多進程或者多線程導致的切換而消耗 CPU,不用去考慮各種鎖的問題,不存在加鎖釋放鎖操作,沒有因為可能出現死鎖而導致的性能消耗;
-
使用多路I/O復用模型,非阻塞IO;
-
使用底層模型不同,它們之間底層實現方式以及與客戶端之間通信的應用協議不一樣,Redis直接自己構建了VM 機制 ,因為一般的系統調用系統函數的話,會浪費一定的時間去移動和請求;
以上幾點都比較好理解,下邊我們針對多路 I/O 復用模型進行簡單的探討:
多路 I/O 復用模型
多路I/O復用模型是利用 select、poll、epoll 可以同時監察多個流的 I/O 事件的能力,在空閑的時候,會把當前線程阻塞掉,當有一個或多個流有 I/O 事件時,就從阻塞態中喚醒,於是程序就會輪詢一遍所有的流(epoll 是只輪詢那些真正發出了事件的流),並且只依次順序的處理就緒的流,這種做法就避免了大量的無用操作。
這里“多路”指的是多個網絡連接,“復用”指的是復用同一個線程。 采用多路 I/O 復用技術可以讓單個線程高效的處理多個連接請求(盡量減少網絡 IO 的時間消耗),且 Redis 在內存中操作數據的速度非常快,也就是說內存內的操作不會成為影響Redis性能的瓶頸,主要由以上幾點造就了 Redis 具有很高的吞吐量。
四:那么為什么Redis是單線程的
原因如下:
1. CPU不是瓶頸:Redis的所有操作都是基於內存的,而CPU不是Redis的瓶頸。在大多數情況下,Redis的瓶頸很可能是機器內存或網絡帶寬的大小。如果我們想要更高的性能,可以使用單線程Redis,我們可以使用集群(多個進程)解決方案。
2. 並發性:並行性不是支持多個客戶端的唯一策略。Redis使用epoll和事件循環來實現並發策略並節省大量時間而無需上下文切換。
3. 易於實現:編寫多線程程序可能會更加困難。我們需要為線程添加鎖和同步機制。
4. 易於部署:單線程應用程序可以部署在至少具有單個CPU內核的任何計算機上。
並發與並行?
並發性和並行性之間的區別
1. 並發就是一次處理很多事情。並行是關於一次做很多事情。
2. 並發是關於結構;並行是關於執行的。
3. 並發提供了一種構造解決方案的方法,以解決可能(但不一定)可並行化的問題。
我們可以使用餐廳服務員的類比:
什么是並發
服務員可以為多個客戶提供服務,而一次只能為一個客戶准備菜。
由於廚房提供的菜餚之間會有一定的間隔,因此當顧客人數少於5人時,一位侍者通常可以處理。
什么是並行
假設廚房一次可以為20位顧客提供餐具。如果一位服務員的顧客數量太大,我們需要更多的服務員。在這種情況下,多個服務員同時工作。我們稱其為並行性。
五:多線程的Redis?
在 2019 年 12 月 20 號這天,眾所期待的 Redis 新版 6.0 rc1 發布了(Redis 6 RC1 is out today),肯定很多關注的同學都進行了試用,雖然因為引入了 c11 的 _Atomic 導致相當多的環境都無法直接編譯成功,但是對於想一探究竟的粉絲們來說,這是完全阻擋不了的熱情,
新版除了增加 ACLS 權限控制模塊、支持更為廣泛的新協議 RESP3、客戶端緩存、無磁盤同步、Cluster Proxy 等十來個相當實用的新特性外,還對 長久以來 社區筒子們 呼聲比較高的 多線程 進行了支持,當然也帶來 性能提升了一倍 的好處
這次我們的任務有兩個: - 剖析 Redis6 多線程的實現方式 - 與 Memcached 的多線程模型(個人認為這是一個極其經典的多線程網絡編程案例)進行對比
加入多線程 IO 之后,整體的讀流程如下:
- 主線程負責接收建連請求,讀事件到來(收到請求)則放到一個全局等待讀處理隊列
- 主線程處理完讀事件之后,通過 RR(Round Robin) 將這些連接分配給這些 IO 線程,然后主線程忙等待(spinlock 的效果)狀態
- IO 線程將請求數據讀取並解析完成(這里只是讀數據和解析並不執行)
- 主線程執行所有命令並清空整個請求等待讀處理隊列(執行部分串行)
上面的這個過程是完全無鎖的,因為在 IO 線程處理的時主線程會等待全部的 IO 線程完成,所以不會出現 data race 的場景。
參考鏈接:https://www.sohu.com/a/331991216_268033
歡迎關注
CSDN:程序員小羊
微信公眾號:程序員小羊
博客園:程序員小羊