<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          面試時說Redis是單線程的,被噴慘了!

          共 2753字,需瀏覽 6分鐘

           ·

          2020-11-10 21:05

          Redis是單線程的,這話擱以前,是橫著走的,誰都知道的真理。現(xiàn)在不一樣,Redis 變了。再說這句話,多少得有質(zhì)疑的語氣來跟你辯駁一番。意志不堅定的,可能就繳械投降,順著別人走了。


          到底是什么樣的,各位看官請跟我一起往下看:


          - 思維導(dǎo)圖 -


          Reactor模式

          反應(yīng)器模式,你可能不太認識,如果看過上篇文章的話應(yīng)該會有點印象。涉及到 Redis 線程它是一個繞不過去的話題。

          1、傳統(tǒng)阻塞IO模型

          在講反應(yīng)器模式前,這里有必要提一下傳統(tǒng)阻塞IO模型的處理方式。

          在傳統(tǒng)阻塞IO模型中,由一個獨立的 Acceptor 線程來監(jiān)聽客戶端的連接,每當有客戶端請求過來時,它就會為客戶端分配一個新的線程來進行處理。當同時有多個請求過來,服務(wù)端對應(yīng)的就會分配相應(yīng)數(shù)量的線程。這就會導(dǎo)致CPU頻繁切換,浪費資源。

          有的連接請求過來不做任何事情,但服務(wù)端還會分配對應(yīng)的線程,這樣就會造成不必要的線程開銷。這就好比你去餐廳吃飯,你拿著菜單看了半天發(fā)現(xiàn)真他娘的貴,然后你就走人了。這段時間等你點菜的服務(wù)員就相當于一個對應(yīng)的線程,你要點菜可以看作一個連接請求。



          同時,每次建立連接后,當線程調(diào)用讀寫方法時,線程會被阻塞,直到有數(shù)據(jù)可讀可寫, 在此期間線程不能做其它事情。還是上邊餐廳吃飯的例子,你出去轉(zhuǎn)了一圈發(fā)現(xiàn)還是這家性價比最高?;氐竭@家餐廳又拿著菜單看了半天,服務(wù)員也在旁邊等你點完菜為止。這個過程中服務(wù)員什么也不能做,只能這么干等著,這個過程相當于阻塞。


          你看這樣的方式,每來一個請求就要分配一個線程,并且還得阻塞地等線程處理完。有的請求還只是過來連接下,什么操作也不干,還得為它分配一個線程,對服務(wù)器資源要求那得多高啊。遇到高并發(fā)場景,不敢想象。對于連接數(shù)目比較小的的固定架構(gòu)倒是可以考慮。

          2、偽異步IO模型

          你可能了解過一種通過線程池優(yōu)化的解決方案,采用線程池和任務(wù)隊列的方式。這種被稱作偽異步IO模型。

          當有客戶端接入時,將客戶端的請求封裝成一個 task 投遞到后端線程池中來處理。線程池維護一個消息隊列和多個活躍線程,對消息隊列中的任務(wù)進行處理。


          這種解決方案,避免了為每個請求創(chuàng)建一個線程導(dǎo)致的線程資源耗盡問題。但是底層仍然是同步阻塞模型。如果線程池內(nèi)的所有線程都阻塞了,那么對于更多請求就無法響應(yīng)了。因此這種模式會限制最大連接數(shù),并不能從根本上解決問題。

          我們繼續(xù)用上邊的餐廳來舉例,餐廳老板在經(jīng)營了一段時間后,顧客多了起來,原本店里的5個服務(wù)員一對一服務(wù)的話根本對付不過來。于是老板采用5個人線程池的方式。服務(wù)員服務(wù)完一個客人后立刻去服務(wù)另一個。

          這時問題出現(xiàn)了,有的客人點菜特別慢,服務(wù)員就得等待很長時間,直到客人點完為止。如果5個客人都點的特別慢的話,這5個服務(wù)員就得一直等下去,就會導(dǎo)致其余的顧客沒有人服務(wù)的狀態(tài)。這就是我們上邊所說的線程池所有線程都被阻塞的情況。

          那么這種問題該如何解決呢?別急, Reactor 模式就要出場了。

          3、Reactor設(shè)計模式

          Reactor 模式的基本設(shè)計思想是基于I/O復(fù)用模型來實現(xiàn)的。

          這里說下I/O復(fù)用模型。和傳統(tǒng)IO多線程阻塞不同,I/O復(fù)用模型中多個連接共用一個阻塞對象,應(yīng)用程序只需要在一個阻塞對象等待。當某個連接有新的數(shù)據(jù)可以處理時,操作系統(tǒng)通知應(yīng)用程序,線程從阻塞狀態(tài)返回,開始進行業(yè)務(wù)處理。

          什么意思呢?餐廳老板也發(fā)現(xiàn)了顧客點餐慢的問題,于是他采用了一種大膽的方式,只留了一個服務(wù)員。當客人點餐的時候,這個服務(wù)員就去招待別的客人,客人點好餐后直接喊服務(wù)員來進行服務(wù)。這里的顧客和服務(wù)員可以分別看作多個連接和一個線程。服務(wù)員阻塞在一個顧客那里,當有別的顧客點好餐后,她就立刻去服務(wù)其他的顧客。

          了解了 reactor 的設(shè)計思想后,我們再來看下今天的主角單 reactor 單線程的實現(xiàn)方案:

          Reactor 通過 I/O復(fù)用程序監(jiān)控客戶端請求事件,收到事件后通過任務(wù)分派器進行分發(fā)。

          針對建立連接請求事件,通過 Acceptor 處理,并建立對應(yīng)的 handler 負責后續(xù)業(yè)務(wù)處理。

          針對非連接事件,Reactor 會調(diào)用對應(yīng)的 handler 完成 read->業(yè)務(wù)處理->write 處理流程,并將結(jié)果返回給客戶端。

          整個過程都在一個線程里完成。

          ?

          單線程時代

          了解了 Reactor 模式后,你可能會有一個疑問,這個和我們今天的主題有什么關(guān)系呢??赡苣悴恢赖氖?,Redis 是基于 Reactor 單線程模式來實現(xiàn)的。

          IO多路復(fù)用程序接收到用戶的請求后,全部推送到一個隊列里,交給文件分派器。對于后續(xù)的操作,和在?reactor 單線程實現(xiàn)方案里看到的一樣,整個過程都在一個線程里完成,因此 Redis 被稱為是單線程的操作。


          對于單線程的 Redis 來說,基于內(nèi)存,且命令操作時間復(fù)雜度低,因此讀寫速率是非常快的。

          多線程時代

          Redis6 版本中引入了多線程。上邊已經(jīng)提到過 Redis 單線程處理有著很快的速度,那為什么還要引入多線程呢?單線程的瓶頸在什么地方?

          我們先來看第二個問題,在 Redis 中,單線程的性能瓶頸主要在網(wǎng)絡(luò)IO操作上。也就是在讀寫網(wǎng)絡(luò) read/write 系統(tǒng)調(diào)用執(zhí)行期間會占用大部分 CPU 時間。如果你要對一些大的鍵值對進行刪除操作的話,在短時間內(nèi)是刪不完的,那么對于單線程來說就會阻塞后邊的操作。

          回想下上邊講得 Reactor 模式中單線程的處理方式。針對非連接事件,Reactor 會調(diào)用對應(yīng)的 handler 完成 read->業(yè)務(wù)處理->write 處理流程,也就是說這一步會造成性能上的瓶頸。

          Redis 在設(shè)計上采用將網(wǎng)絡(luò)數(shù)據(jù)讀寫和協(xié)議解析通過多線程的方式來處理,對于命令執(zhí)行來說,仍然使用單線程操作。

          ?

          總結(jié)

          Reactor模式
          • 傳統(tǒng)阻塞IO模型客戶端與服務(wù)端線程1:1分配,不利于進行擴展。
          • 偽異步IO模型采用線程池方式,但是底層仍然使用同步阻塞方式,限制了最大連接數(shù)。
          • Reactor?通過?I/O復(fù)用程序監(jiān)控客戶端請求事件,通過任務(wù)分派器進行分發(fā)。

          單線程時代
          • 基于 Reactor 單線程模式實現(xiàn),通過IO多路復(fù)用程序接收到用戶的請求后,全部推送到一個隊列里,交給文件分派器進行處理。


          多線程時代
          • 單線程性能瓶頸主要在網(wǎng)絡(luò)IO上。
          • 將網(wǎng)絡(luò)數(shù)據(jù)讀寫和協(xié)議解析通過多線程的方式來處理?,對于命令執(zhí)行來說,仍然使用單線程操作。


          有道無術(shù),術(shù)可成;有術(shù)無道,止于術(shù)

          歡迎大家關(guān)注Java之道公眾號


          好文章,我在看??

          瀏覽 72
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  正在播放蜜臀av 正在播放做爱内射 | 亚洲成人网站视频 | 亚洲www啪成人一区二区麻豆 | 996热1 | 中文字幕不卡 |