关于C10K、异步回调、协程、同步阻塞
2019獨(dú)角獸企業(yè)重金招聘Python工程師標(biāo)準(zhǔn)>>>
最近到處在爭論這些話題,發(fā)現(xiàn)很多人對一些基礎(chǔ)的常識并不了解,在此發(fā)表一文做一下解釋。此文未必能解答所有問題,各位能有一個(gè)大致的了解就好。
C10K的由來
大家都知道互聯(lián)網(wǎng)的基礎(chǔ)就是網(wǎng)絡(luò)通信,早期的互聯(lián)網(wǎng)可以說是一個(gè)小群體的集合。互聯(lián)網(wǎng)還不夠普及,用戶也不多。一臺服務(wù)器同時(shí)在線100個(gè)用戶估計(jì)在當(dāng)時(shí)已經(jīng)算是大型應(yīng)用了。所以并不存在什么C10K的難題。互聯(lián)網(wǎng)的爆發(fā)期應(yīng)該是在www網(wǎng)站,瀏覽器,雅虎出現(xiàn)后。最早的互聯(lián)網(wǎng)稱之為Web1.0,互聯(lián)網(wǎng)大部分的使用場景是下載一個(gè)Html頁面,用戶在瀏覽器中查看網(wǎng)頁上的信息。這個(gè)時(shí)期也不存在C10K問題。
Web2.0時(shí)代到來后就不同了,1方面是普及率大大提高了,用戶群體幾何倍增長。2是互聯(lián)網(wǎng)不再是單純的瀏覽萬維網(wǎng)網(wǎng)頁,逐漸開始進(jìn)行交互,而且應(yīng)用程序的邏輯也變的更復(fù)雜,從簡單的表單提交,到即時(shí)通信和在線實(shí)時(shí)互動(dòng)。C10K的問題才體現(xiàn)出來了。每一個(gè)用戶都必須與服務(wù)器保持TCP連接才能進(jìn)行實(shí)時(shí)的數(shù)據(jù)交互。Facebook這樣的網(wǎng)站同一時(shí)間的并發(fā)TCP連接可能會過億。
騰訊QQ也是有C10K問題的,只不過他們是用了UDP這種原始的包交換協(xié)議來實(shí)現(xiàn)的,繞開了這個(gè)難題。當(dāng)然過程肯定是痛苦的。如果當(dāng)時(shí)有epoll技術(shù),他們肯定會用TCP。后來的手機(jī)QQ,微信都采用TCP協(xié)議。這時(shí)候問題就來了,最初的服務(wù)器都是基于進(jìn)程/線程模型的,新到來一個(gè)TCP連接,就需要分配1個(gè)進(jìn)程(或者線程)。而進(jìn)程又是操作系統(tǒng)最昂貴的資源,一臺機(jī)器無法創(chuàng)建很多進(jìn)程。如果是C10K就要?jiǎng)?chuàng)建1萬個(gè)進(jìn)程,那么操作系統(tǒng)是無法承受的。如果是采用分布式系統(tǒng),維持1億用戶在線需要10萬臺服務(wù)器,成本巨大,也只有Facebook,Google,雅虎才有財(cái)力購買如此多的服務(wù)器。這就是C10K問題的本質(zhì)。
實(shí)際上當(dāng)時(shí)也有異步模式,如:select/poll模型,這些技術(shù)都有一定的缺點(diǎn),如selelct最大不能超過1024,poll沒有限制,但每次收到數(shù)據(jù)需要遍歷每一個(gè)連接查看哪個(gè)連接有數(shù)據(jù)請求。Epoll異步非阻塞
既然有了C10K問題,程序員們就開始行動(dòng)去解決它。于是FreeBSD推出了kqueue,Linux推出了epoll,Windows推出了IOCP。這些操作系統(tǒng)提供的功能就是為了解決C10K問題。因?yàn)長inux是互聯(lián)網(wǎng)企業(yè)中使用率最高的操作系統(tǒng),Epoll就成為C10K killer、高并發(fā)、高性能、異步非阻塞這些技術(shù)的代名詞了。
epoll技術(shù)的編程模型就是異步非阻塞回調(diào),也可以叫做Reactor,事件驅(qū)動(dòng),事件輪循(EventLoop)。Epoll就是為了解決C10K問題而生。使用Epoll技術(shù),使得小公司也可以玩高并發(fā)。不需要購買很多服務(wù)器,有幾臺服務(wù)器就可以服務(wù)大量用戶。Nginx,libevent,node.js這些就是Epoll時(shí)代的產(chǎn)物。
C100K,C1M,C10M,C100M …
C10K問題解決后,程序員又提出了更高的挑戰(zhàn),也就是最近在火熱爭論的C100K,C1M等。Epoll既然能解決C10K,解決什么C100K,C1M也是可以的。只不過這個(gè)已經(jīng)沒有意義了。一個(gè)公司有1億用戶難道他買不起1萬臺服務(wù)器嘛。WhatsApp有2億用戶,賣了150億美元。1萬臺服務(wù)器最多花費(fèi)5000萬美元。
看到阿里技術(shù)保障部的人也在談C10K話題,我要補(bǔ)充一下,搞路由器、交換機(jī)、網(wǎng)關(guān)、防火墻之類基礎(chǔ)網(wǎng)絡(luò)設(shè)備的人,就不要參與C10K話題了。我們說的是應(yīng)用層程序。協(xié)程,coroutine
當(dāng)程序員還沉浸在解決C10K問題帶來的成就感時(shí),一個(gè)新的問題被拋出了。異步嵌套回調(diào)太TM難寫了。尤其是Node.js層層回調(diào),縮進(jìn)了幾十層,要把程序員逼瘋了。于是一個(gè)新的技術(shù)被提出來了,那就是協(xié)程(coroutine)。這個(gè)技術(shù)本質(zhì)上也是異步非阻塞技術(shù),它是將事件回調(diào)進(jìn)行了包裝,讓程序員看不到里面的事件循環(huán)。程序員就像寫阻塞代碼一樣簡單。比如調(diào)用 client->recv() 等待接收數(shù)據(jù)時(shí),就像阻塞代碼一樣寫。實(shí)際上是底層庫在執(zhí)行recv時(shí)悄悄保存了一個(gè)狀態(tài),比如代碼行數(shù),局部變量的值。然后就跳回到EventLoop中了。什么時(shí)候真的數(shù)據(jù)到來時(shí),它再把剛才保存的代碼行數(shù),局部變量值取出來,又開始繼續(xù)執(zhí)行。
這個(gè)就像時(shí)間禁止的游戲一樣,國王對巫師說“我必須馬上得到寶物,不然就砍了你的腦袋”,巫師念了一句時(shí)間停止的咒語,直到過了1年后勇士們才把寶物送來。這時(shí)候巫師解開咒語,把寶物交給國王。這里國王就可以理解成協(xié)程,他根本沒感覺到時(shí)間停止,在他停止到醒來期間發(fā)生了什么他不知道,也不關(guān)心。
這就是協(xié)程的本質(zhì)。協(xié)程是異步非阻塞的另外一種展現(xiàn)形式。Golang,Erlang,Lua協(xié)程都是這個(gè)模型。
同步阻塞
再回到同步阻塞這個(gè)話題,不知道大家看完協(xié)程是否感覺得到,實(shí)際上協(xié)程和同步阻塞是一樣的。答案是的。所以協(xié)程也叫做用戶態(tài)進(jìn)/用戶態(tài)線程。區(qū)別就在于進(jìn)程/線程是操作系統(tǒng)充當(dāng)了EventLoop調(diào)度,而協(xié)程是自己用Epoll進(jìn)行調(diào)度。
協(xié)程的優(yōu)點(diǎn)是它比系統(tǒng)線程開銷小,缺點(diǎn)是如果其中一個(gè)協(xié)程中有密集計(jì)算,其他的協(xié)程就不運(yùn)行了。操作系統(tǒng)進(jìn)程的缺點(diǎn)是開銷大,優(yōu)點(diǎn)是無論代碼怎么寫,所有進(jìn)程都可以并發(fā)運(yùn)行。
Erlang解決了協(xié)程密集計(jì)算的問題,它基于自行開發(fā)VM,并不執(zhí)行機(jī)器碼。即使存在密集計(jì)算的場景,VM發(fā)現(xiàn)某個(gè)協(xié)程執(zhí)行時(shí)間過長,也可以進(jìn)行中止切換。Golang由于是直接執(zhí)行機(jī)器碼的,所以無法解決此問題。所以Golang要求用戶必須在密集計(jì)算的代碼中,自行Yield。實(shí)際上同步阻塞程序的性能并不差,它的效率很高,不會浪費(fèi)資源。當(dāng)進(jìn)程發(fā)生阻塞后,操作系統(tǒng)會將它掛起,不會分配CPU。直到數(shù)據(jù)到達(dá)才會分配CPU。多進(jìn)程只是開多了之后副作用太大,因?yàn)檫M(jìn)程多了互相切換有開銷。所以如果一個(gè)服務(wù)器程序只有1000左右的并發(fā)連接,同步阻塞模式是最好的。
異步回調(diào)和協(xié)程哪個(gè)性能好
協(xié)程雖然是用戶態(tài)調(diào)度,實(shí)際上還是需要調(diào)度的,既然調(diào)度就會存在上下文切換。所以協(xié)程雖然比操作系統(tǒng)進(jìn)程性能要好,但總還是有額外消耗的。而異步回調(diào)是沒有切換開銷的,它等同于順序執(zhí)行代碼。所以異步回調(diào)程序的性能是要優(yōu)于協(xié)程模型的。
這里是指Nginx這種多進(jìn)程異步非阻塞程序。Node.js/Redis此類程序如果不開多個(gè)進(jìn)程,由于無法利用多核計(jì)算優(yōu)勢,所以性能并不好。在Node.js中可以使用childprocess/cluster等擴(kuò)展開啟多進(jìn)程以解決此問題。轉(zhuǎn)載于:https://my.oschina.net/wdyoschina/blog/681395
總結(jié)
以上是生活随笔為你收集整理的关于C10K、异步回调、协程、同步阻塞的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 中班社会教案《尊重他人的劳动》
- 下一篇: E-MapReduce结合DataV进行