摘要:協(xié)作方式在高并發(fā)場(chǎng)景中,必須要讓服務(wù)器同時(shí)維護(hù)大量請(qǐng)求連接,可能是一個(gè)服務(wù)進(jìn)程創(chuàng)建另一個(gè)進(jìn)程,也可能是一個(gè)服務(wù)線程去創(chuàng)建另一個(gè)線程,但連接結(jié)束后進(jìn)程或線程就銷毀了,這是一個(gè)巨大的浪費(fèi)一個(gè)自然的想法就是通過創(chuàng)建一個(gè)進(jìn)程線程池從而達(dá)到資源復(fù)用,
協(xié)作方式
在高并發(fā)場(chǎng)景中,必須要讓服務(wù)器同時(shí)維護(hù)大量請(qǐng)求連接,可能是一個(gè)服務(wù)進(jìn)程創(chuàng)建另一個(gè)進(jìn)程,也可能是一個(gè)服務(wù)線程去創(chuàng)建另一個(gè)線程,但連接結(jié)束后進(jìn)程或線程就銷毀了,這是一個(gè)巨大的浪費(fèi)
一個(gè)自然的想法就是通過創(chuàng)建一個(gè)進(jìn)程/線程池從而達(dá)到資源復(fù)用,一個(gè)進(jìn)程/線程可以處理多個(gè)連接
那么如何處理多個(gè)連接?
同步阻塞
一個(gè)請(qǐng)求占用一個(gè)進(jìn)程處理,先等待數(shù)據(jù)準(zhǔn)備好,然后從內(nèi)核向進(jìn)程復(fù)制數(shù)據(jù),最后處理完數(shù)據(jù)后返回
如果一個(gè)進(jìn)程處理一個(gè)請(qǐng)求,再來請(qǐng)求再開進(jìn)程,雖然會(huì)有CPU在等待IO時(shí)的浪費(fèi)和進(jìn)程數(shù)量限制,但還是可以做到一定的高性能。如果一個(gè)進(jìn)程處理多個(gè)連接,那么其他連接會(huì)在第一個(gè)連接導(dǎo)致的IO操作時(shí)被阻塞,這樣無法做到高性能,所以不會(huì)選擇該模式實(shí)現(xiàn)高性能
同步非阻塞
進(jìn)程先將一個(gè)套接字在內(nèi)核中設(shè)置成非阻塞再等待數(shù)據(jù)準(zhǔn)備好,在這個(gè)過程中反復(fù)輪詢內(nèi)核數(shù)據(jù)是否準(zhǔn)備好,準(zhǔn)備好之后最后處理數(shù)據(jù)返回
一個(gè)進(jìn)程處理一個(gè)請(qǐng)求不太實(shí)際,一個(gè)進(jìn)程處理多個(gè)請(qǐng)求的性能上限會(huì)更高,所以簡(jiǎn)單的處理同步阻塞中的阻塞問題的方式就是一個(gè)進(jìn)程輪詢多個(gè)連接,但輪詢是有CPU開銷的,且如果一個(gè)進(jìn)程有成千上萬的連接時(shí)效率很低,也不會(huì)選擇該模式實(shí)現(xiàn)高性能
I/O多路復(fù)用
相當(dāng)于對(duì)同步非阻塞的優(yōu)化版本,區(qū)別在于I/O多路復(fù)用阻塞在select,epoll這樣的系統(tǒng)調(diào)用之上,而沒有阻塞在真正的I/O系統(tǒng)調(diào)用如recvfrom之上。換句話說,輪詢機(jī)制被優(yōu)化成通知機(jī)制,多個(gè)連接公用一個(gè)阻塞對(duì)象,進(jìn)程只需要在一個(gè)阻塞對(duì)象上等待,無需再輪詢所有連接
當(dāng)某條連接有新的數(shù)據(jù)可以處理時(shí),操作系統(tǒng)會(huì)通知進(jìn)程,進(jìn)程從阻塞狀態(tài)返回,開始處理業(yè)務(wù),這是高性能的基礎(chǔ),但仍不算高效,因?yàn)樽屢粋€(gè)進(jìn)程/線程進(jìn)行select是不夠的,還需要某種機(jī)制來分配進(jìn)程/線程去負(fù)責(zé)監(jiān)聽、處理數(shù)據(jù)這個(gè)兩個(gè)過程才能實(shí)現(xiàn)高性能
Reactor
I/O多路復(fù)用結(jié)合線程池就是Reactor
Reactor的核心包括Reactor(監(jiān)聽和分配事件)和處理資源池(負(fù)責(zé)處理事件),具體實(shí)現(xiàn)可以多變,體現(xiàn)在:
Reactor的數(shù)量可以變化
處理資源池的數(shù)量可以變化,可以是單個(gè)進(jìn)程/線程,也可以是多個(gè)進(jìn)程/線程
單Reactor單進(jìn)程/線程
Reactor對(duì)象通過select監(jiān)控連接事件,收到事件后通過dispatch分發(fā)
如果是建立連接,交給Acceptor處理,通過accept接收連接,創(chuàng)建一個(gè)Handler來處理連接后續(xù)的事件
如果是不是建立連接事件,交給之前建立連接階段創(chuàng)建的對(duì)應(yīng)的Handler處理
優(yōu)點(diǎn)是簡(jiǎn)單,沒有進(jìn)程間通信、競(jìng)爭(zhēng),缺點(diǎn)是只有一個(gè)進(jìn)程,無法發(fā)揮多核CPU性能,且Handler上處理某個(gè)連接的業(yè)務(wù)時(shí),整個(gè)進(jìn)程無法處理任何其他事件
所以適用場(chǎng)景不多,適合于業(yè)務(wù)處理非??斓膱?chǎng)景,如Redis
單Reactor多線程
與單Reactor單進(jìn)程/線程在于Handler只負(fù)責(zé)響應(yīng)事件,業(yè)務(wù)處理交給Processor,且Processor會(huì)在獨(dú)立的子線程中處理,然后將結(jié)果發(fā)給主進(jìn)程的Handler處理
優(yōu)點(diǎn)是充分發(fā)揮了多核CPU的能力,缺點(diǎn)是多線程數(shù)據(jù)共享復(fù)雜,且Reactor承擔(dān)所有事件的監(jiān)聽和響應(yīng),高并發(fā)會(huì)成為瓶頸
多Reactor多進(jìn)程/線程
為了解決單Reactor多線程的問題,這個(gè)模式的區(qū)別:
父進(jìn)程的select監(jiān)聽到連接建立事件后通過Acceptor將新的連接分配給子進(jìn)程
子進(jìn)程的Reactor將新的連接加入自己的連接隊(duì)列進(jìn)行監(jiān)聽,并創(chuàng)建一個(gè)Handler用于處理連接的事件
當(dāng)有新的事件發(fā)生,子Reactor會(huì)調(diào)用連接的Handler
Handler完成read->業(yè)務(wù)處理->send的業(yè)務(wù)流程
看起來比單Reactor多線程更復(fù)雜,但實(shí)現(xiàn)更簡(jiǎn)單,因?yàn)椋?/p>
父進(jìn)程只負(fù)責(zé)接收并建立新連接,子進(jìn)程只負(fù)責(zé)業(yè)務(wù)處理
父子進(jìn)程之間的交互只有父進(jìn)程把連接交給子進(jìn)程,子進(jìn)程不需要把結(jié)果返回給父進(jìn)程
Nginx、Memcache、Netty使用的就是該模式
Proactor
Reactor是同步非阻塞的網(wǎng)絡(luò)模型,因?yàn)檎嬲膔ead和send這樣的IO操作都需要用戶進(jìn)程同步操作,如果把IO操作改為異步就能進(jìn)一步提升性能,這就是Proactor
初始化器Initiator負(fù)責(zé)創(chuàng)建通知組件Proactor和處理器Handler,并且都注冊(cè)到內(nèi)核
內(nèi)核負(fù)責(zé)處理注冊(cè)請(qǐng)求,并完成IO操作
內(nèi)核完成IO操作后通知Proactor
Proactor回調(diào)到Handler
Handler完成業(yè)務(wù)處理,Handler也可以注冊(cè)新的Handler到內(nèi)核
理論上Proactor的效率高于Reactor,讓IO操作與計(jì)算重疊,但要實(shí)現(xiàn)真正的異步IO,需要操作系統(tǒng)支持,Windows支持而Linux不完善
實(shí)踐方式
以上是操作系統(tǒng)或Nginx或高性能服務(wù)器軟件已經(jīng)幫我們解決了,我們?cè)诰幋a的時(shí)候除非達(dá)到了代碼的性能極限,一般不需要擔(dān)心這方面
所以下面談到的是一些作為開發(fā)人員,為了提升單體服務(wù)的性能而需要注意的地方
高性能的代碼
性能
選用高性能的框架。比如Java方面考慮用Netty,Go方面考慮用Gin
代碼細(xì)節(jié)。這塊是與我們最息息相關(guān)的了,如何寫出高性能代碼,每種語言都有自己的最佳實(shí)踐,反而這里沒辦法講到,需要日常學(xué)習(xí)積累。比如字符串拼接效率如何最高?哪個(gè)數(shù)據(jù)結(jié)構(gòu)適合在某個(gè)業(yè)務(wù)場(chǎng)景使用?
IO細(xì)節(jié)。由于磁盤的讀寫速度遠(yuǎn)低于CPU、內(nèi)存,所以對(duì)磁盤的讀寫往往會(huì)嚴(yán)重拖慢性能,比如寫日志,不注意的話可能本地寫了一份日志文件,控制臺(tái)也在輸出日志信息,另外一個(gè)文件上傳流也在寫入信息,那么log會(huì)成倍地拖慢速度,所以需要統(tǒng)一日志輸出方式,比如只往日志收集流中寫入到EFK系統(tǒng)中查看
單體服務(wù)器壓測(cè)
寫出了自認(rèn)為高性能的代碼?趕緊來壓測(cè)試一遍,壓測(cè)就一個(gè)目的:尋找瓶頸
在接近于生產(chǎn)環(huán)境下的機(jī)器做壓測(cè)才是最真實(shí)的,還需要使用專門的壓測(cè)機(jī)來避免環(huán)境的影響,最簡(jiǎn)單的方式是通過ab工具測(cè)試QPS是多少,同時(shí)檢測(cè)CPU、內(nèi)存、網(wǎng)絡(luò)流量是否達(dá)到了瓶頸,然后再根據(jù)瓶頸,尋找解決方案,這就是大體壓測(cè)以及優(yōu)化的思路,單體應(yīng)用的壓測(cè)還挺簡(jiǎn)單,至于集群的壓測(cè)就需要考慮更多,日后再說
最近我對(duì)一個(gè)服務(wù)進(jìn)行了壓測(cè),QPS是1200,并且是跑在3臺(tái)虛擬機(jī)上的,瓶頸在于CPU,所以很明顯單體服務(wù)的性能太低或者是總路由出現(xiàn)了轉(zhuǎn)發(fā)問題,這里不考慮后者,我們先分析這個(gè)服務(wù)的接口是拿來干什么的,這個(gè)接口僅僅做了一件事,從Redis獲取數(shù)據(jù),轉(zhuǎn)發(fā)給前端,這里也不考慮Redis的性能問題,那么就可能是在處理數(shù)據(jù)的時(shí)候性能太低。所以同事將返回的json壓縮了一下,從40kb壓縮到了20kb,QPS直接提升到2500。這就是一個(gè)簡(jiǎn)單的壓測(cè)后調(diào)優(yōu)的例子,還可以參考這里。
合適的服務(wù)器
規(guī)格
如果你用過云服務(wù),那么肯定會(huì)在啟動(dòng)實(shí)例的時(shí)候被強(qiáng)迫去選擇一個(gè)規(guī)格的實(shí)例,如下
那么請(qǐng)根據(jù)你的服務(wù)是哪種性能需要,選擇對(duì)應(yīng)的服務(wù)器呢,當(dāng)然還要考慮你滴錢包夠不夠
配置
在Linux平臺(tái)上,在進(jìn)行高并發(fā)TCP連接處理時(shí),最高的并發(fā)數(shù)量都要受到系統(tǒng)對(duì)用戶單一進(jìn)程同時(shí)可打開文件數(shù)量的限制(這是因?yàn)橄到y(tǒng)為每個(gè)TCP連接都要?jiǎng)?chuàng)建一個(gè)socket句柄,每個(gè)socket句柄同時(shí)也是一個(gè)文件句柄)??墒褂胾limit命令查看系統(tǒng)允許當(dāng)前用戶進(jìn)程打開的文件數(shù)限制
類似的,對(duì)Linux系統(tǒng)配置也會(huì)影響到性能的參數(shù)需要格外注意,但也需要遵從一個(gè)方式:按需調(diào)整
感謝您耐心看完的文章
順便給大家推薦一個(gè)Java技術(shù)交流群:710373545里面會(huì)分享一些資深架構(gòu)師錄制的視頻資料:有Spring,MyBatis,Netty源碼分析,高并發(fā)、高性能、分布式、微服務(wù)架構(gòu)的原理,JVM性能優(yōu)化、分布式架構(gòu)等這些成為架構(gòu)師必備的知識(shí)體系。還能領(lǐng)取免費(fèi)的學(xué)習(xí)資源,目前受益良多!
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/74694.html
摘要:作為面試官,我是如何甄別應(yīng)聘者的包裝程度語言和等其他語言的對(duì)比分析和主從復(fù)制的原理詳解和持久化的原理是什么面試中經(jīng)常被問到的持久化與恢復(fù)實(shí)現(xiàn)故障恢復(fù)自動(dòng)化詳解哨兵技術(shù)查漏補(bǔ)缺最易錯(cuò)過的技術(shù)要點(diǎn)大掃盲意外宕機(jī)不難解決,但你真的懂?dāng)?shù)據(jù)恢復(fù)嗎每秒 作為面試官,我是如何甄別應(yīng)聘者的包裝程度Go語言和Java、python等其他語言的對(duì)比分析 Redis和MySQL Redis:主從復(fù)制的原理詳...
摘要:作為面試官,我是如何甄別應(yīng)聘者的包裝程度語言和等其他語言的對(duì)比分析和主從復(fù)制的原理詳解和持久化的原理是什么面試中經(jīng)常被問到的持久化與恢復(fù)實(shí)現(xiàn)故障恢復(fù)自動(dòng)化詳解哨兵技術(shù)查漏補(bǔ)缺最易錯(cuò)過的技術(shù)要點(diǎn)大掃盲意外宕機(jī)不難解決,但你真的懂?dāng)?shù)據(jù)恢復(fù)嗎每秒 作為面試官,我是如何甄別應(yīng)聘者的包裝程度Go語言和Java、python等其他語言的對(duì)比分析 Redis和MySQL Redis:主從復(fù)制的原理詳...
摘要:表示的是兩個(gè),當(dāng)其中任意一個(gè)計(jì)算完并發(fā)編程之是線程安全并且高效的,在并發(fā)編程中經(jīng)??梢娝氖褂?,在開始分析它的高并發(fā)實(shí)現(xiàn)機(jī)制前,先講講廢話,看看它是如何被引入的。電商秒殺和搶購,是兩個(gè)比較典型的互聯(lián)網(wǎng)高并發(fā)場(chǎng)景。 干貨:深度剖析分布式搜索引擎設(shè)計(jì) 分布式,高可用,和機(jī)器學(xué)習(xí)一樣,最近幾年被提及得最多的名詞,聽名字多牛逼,來,我們一步一步來擊破前兩個(gè)名詞,今天我們首先來說說分布式。 探究...
閱讀 2960·2021-10-14 09:42
閱讀 3238·2019-08-30 15:52
閱讀 3392·2019-08-30 14:02
閱讀 1148·2019-08-29 15:42
閱讀 592·2019-08-29 13:20
閱讀 1208·2019-08-29 12:24
閱讀 528·2019-08-26 10:20
閱讀 720·2019-08-23 18:31