redisserver是什么问题_面试官老是问:为什么采用单线程的Redis也会如此之快?...
Java面試筆試面經(jīng)、Java技術每天學習一點
公眾號Java面試
關注我不迷路
作者:kaito
來源:http://kaito-kidd.com/2020/06/28/why-redis-so-fast/
眾所周知,Redis在內存庫數(shù)據(jù)庫領域非常地火熱,它極高的性能和豐富的數(shù)據(jù)結構為我們的開發(fā)提供了極大的便利。
但我們也聽說了,Redis是單線程的,為什么采用單線程的Redis也會如此之快呢?這篇文章我們來分析一下其中的緣由。
其實,嚴格來說,Redis Server是多線程的,只是它的請求處理整個流程是單線程處理的。?這一點我們一定要清楚了解到,不要單純地認為Redis Server是單線程的!
我們平時說的Redis單線程快是指它的請求處理過程非常地快!
下面我們就來分下一下為什么請求處理使用單線程,依舊可以達到這么高的性能。
Redis的性能非常之高,每秒可以承受10W+的QPS,它如此優(yōu)秀的性能主要取決于以下幾個方面:
- 純內存操作
- 使用IO多路復用技術
- 非CPU密集型任務
- 單線程的優(yōu)勢
純內存操作
Redis是一個內存數(shù)據(jù)庫,它的數(shù)據(jù)都存儲在內存中,這意味著我們讀寫數(shù)據(jù)都是在內存中完成,這個速度是非??斓摹?/p>
Redis是一個KV內存數(shù)據(jù)庫,它內部構建了一個哈希表,根據(jù)指定的KEY訪問時,只需要O(1)的時間復雜度就可以找到對應的數(shù)據(jù)。同時,Redis提供了豐富的數(shù)據(jù)類型,并使用高效的操作方式進行操作,這些操作都在內存中進行,并不會大量消耗CPU資源,所以速度極快。
使用IO多路復用技術
Redis采用單線程,那么它是如何處理多個客戶端連接請求呢?
Redis采用了IO多路復用技術和非阻塞IO,這個技術由操作系統(tǒng)實現(xiàn)提供,Redis可以方便地操作系統(tǒng)的API即可。Redis可以在單線程中監(jiān)聽多個Socket的請求,在任意一個Socket可讀/可寫時,Redis去讀取客戶端請求,在內存中操作對應的數(shù)據(jù),然后再寫回到Socket中。
整個過程非常高效,Redis利用了IO多路復用技術的事件驅動模型,保證在監(jiān)聽多個Socket連接的情況下,只針對有活動的Socket采取反應。
非CPU密集型任務
采用單線程的缺點很明顯,無法使用多核CPU。Redis作者提到,由于Redis的大部分操作并不是CPU密集型任務,而Redis的瓶頸在于內存和網(wǎng)絡帶寬。
在高并發(fā)請求下,Redis需要更多的內存和更高的網(wǎng)絡帶寬,否則瓶頸很容易出現(xiàn)在內存不夠用和網(wǎng)絡延遲等待的情況。
當然,如果你覺得單個Redis實例的性能不足以支撐業(yè)務,Redis作者推薦部署多個Redis節(jié)點,組成集群的方式來利用多核CPU的能力,而不是在單個實例上使用多線程來處理。
單線程的優(yōu)勢
基于以上特性,Redis采用單線程已足夠達到非常高的性能,所以Redis沒有采用多線程模型。
另外,單線程模型還帶了以下好處:
- 沒有了多線程上下文切換的性能損耗
- 沒有了訪問共享資源加鎖的性能損耗
- 開發(fā)和調試非常友好,可維護性高
所以Redis正是基于以上這些方面,所以采用了單線程模型來完成請求處理的工作。
多線程優(yōu)化
在文章開頭已經(jīng)特別說明,Redis Server本身是多線程的,除了請求處理流程是單線程處理之外,Redis內部還有其他工作線程在后臺執(zhí)行,它負責異步執(zhí)行某些比較耗時的任務,例如AOF每秒刷盤、AOF文件重寫都是在另一個線程中完成的。
而在Redis 4.0之后,Redis引入了lazyfree的機制,提供了unlink、flushall aysc、flushdb async等命令和lazyfree-lazy-eviction、lazyfree-lazy-expire等機制來異步釋放內存,它主要是為了解決在釋放大內存數(shù)據(jù)導致整個redis阻塞的性能問題。
在刪除大key時,釋放內存往往都比較耗時,所以Redis提供異步釋放內存的方式,讓這些耗時的操作放到另一個線程中異步去處理,從而不影響主線程的執(zhí)行,提高性能。
到了Redis 6.0,Redis又引入了多線程來完成請求數(shù)據(jù)的協(xié)議解析,進一步提升性能。它主要是解決高并發(fā)場景下,單線程解析請求數(shù)據(jù)協(xié)議帶來的壓力。請求數(shù)據(jù)的協(xié)議解析由多線程完成之后,后面的請求處理階段依舊還是單線程排隊處理。
可見,Redis并不是保守地認為單線程有多好,也不是為了使用多線程而引入多線程。Redis作者很清楚單線程和多線程的使用場景,針對性地優(yōu)化,這是非常值得我們學習的。
缺點
上面介紹了單線程可以達到如此高的性能,并不是說它就沒有缺點了。
單線程處理最大的缺點就是,如果前一個請求發(fā)生耗時比較久的操作,那么整個Redis就會阻塞住,其他請求也無法進來,直到這個耗時久的操作處理完成并返回,其他請求才能被處理到。
我們平時遇到Redis變慢或長時間阻塞的問題,90%也都是因為Redis處理請求是單線程這個原因導致的。
所以,我們在使用Redis時,一定要避免非常耗時的操作,例如使用時間復雜度過高的方式獲取數(shù)據(jù)、一次性獲取過多的數(shù)據(jù)、大量key集中過期導致Redis淘汰key壓力變大等等,這些場景都會阻塞住整個處理線程,直到它們處理完成,勢必會影響業(yè)務的訪問。
我會在后期的文章中專門介紹具體有哪些場景會引發(fā)Redis阻塞的問題,并提供規(guī)避問題的方法和優(yōu)化方案。
總結
Redis使用單線程,配合IO多路復用技術,可以完成多個連接的請求處理。而且正是由于它的使用定位是內存數(shù)據(jù)庫,這樣幾乎所有的操作都在內存中完成,它的性能可以達到非常之高。
同時,單線程沒有了線程上下文切換和訪問共享資源加鎖的性能損耗,而且單線程模型對程序的開發(fā)和調試非常友好,因此Redis使用單線程模型也就在情理之中了。
Redis在最近的版本也對多線程進行了優(yōu)化,用于解決釋放大內存數(shù)據(jù)和請求數(shù)據(jù)協(xié)議解析對Redis產生的性能影響,進一步提升了Redis的性能。
單線程結合上述場景可以達到非常高的性能,同時也存在耗時操作阻塞整個線程的問題,我們在使用Redis時要避免耗時過長的操作,才能更好地發(fā)揮Redis的性能。
總結
以上是生活随笔為你收集整理的redisserver是什么问题_面试官老是问:为什么采用单线程的Redis也会如此之快?...的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java 昵称1到32位字符_Java期
- 下一篇: urlconnection java_j