<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    Jack Jiang

    我的最新工程MobileIMSDK:http://git.oschina.net/jackjiang/MobileIMSDK
    posts - 494, comments - 13, trackbacks - 0, articles - 1

    本文原題“高并發高性能服務器是如何實現的”,轉載請聯系作者。

    1、系列文章引言

    1.1 文章目的

    作為即時通訊技術的開發者來說,高性能、高并發相關的技術概念早就了然與胸,什么線程池、零拷貝、多路復用、事件驅動、epoll等等名詞信手拈來,又或許你對具有這些技術特征的技術框架比如:Java的Netty、Php的workman、Go的gnet等熟練掌握。但真正到了面視或者技術實踐過程中遇到無法釋懷的疑惑時,方知自已所掌握的不過是皮毛。

    返璞歸真、回歸本質,這些技術特征背后的底層原理到底是什么?如何能通俗易懂、毫不費力真正透徹理解這些技術背后的原理,正是《從根上理解高性能、高并發》系列文章所要分享的。

    1.2 文章源起

    我整理了相當多有關IM、消息推送等即時通訊技術相關的資源和文章,從最開始的開源IM框架MobileIMSDK,到網絡編程經典巨著《TCP/IP詳解》的在線版本,再到IM開發綱領性文章《新手入門一篇就夠:從零開發移動端IM》,以及網絡編程由淺到深的《網絡編程懶人入門》、《腦殘式網絡編程入門》、《高性能網絡編程》、《不為人知的網絡編程》系列文章。

    越往知識的深處走,越覺得對即時通訊技術了解的太少。于是后來,為了讓開發者門更好地從基礎電信技術的角度理解網絡(尤其移動網絡)特性,我跨專業收集整理了《IM開發者的零基礎通信技術入門》系列高階文章。這系列文章已然是普通即時通訊開發者的網絡通信技術知識邊界,加上之前這些網絡編程資料,解決網絡通信方面的知識盲點基本夠用了。

    對于即時通訊IM這種系統的開發來說,網絡通信知識確實非常重要,但回歸到技術本質,實現網絡通信本身的這些技術特征:包括上面提到的線程池、零拷貝、多路復用、事件驅動等等,它們的本質是什么?底層原理又是怎樣?這就是整理本系列文章的目的,希望對你有用。

    1.3 文章目錄

    從根上理解高性能、高并發(一):深入計算機底層,理解線程與線程池

    從根上理解高性能、高并發(二):深入操作系統,理解I/O與零拷貝技術

    從根上理解高性能、高并發(三):深入操作系統,徹底理解I/O多路復用

    從根上理解高性能、高并發(四):深入操作系統,徹底理解同步與異步

    從根上理解高性能、高并發(五):深入操作系統,理解高并發中的協程

    從根上理解高性能、高并發(六):通俗易懂,高性能服務器到底是如何實現的》(* 本文

    1.4 本篇概述

    接上篇《從根上理解高性能、高并發(五):深入操作系統,理解高并發中的協程》,本篇是高性能、高并發系列的第6篇文章(也是完結篇)。

    本篇是本系列文章的完結篇,你將能了解到,一個典型的服務器端是如何利用前5篇中講解的各單項技術從而實現高性能高并發的。

    本文已同步發布于“即時通訊技術圈”公眾號,歡迎關注。公眾號上的鏈接是:點此進入

    2、本文作者

    應作者要求,不提供真名,也不提供個人照片。

    本文作者主要技術方向為互聯網后端、高并發高性能服務器、檢索引擎技術,網名是“碼農的荒島求生”。感謝作者的無私分享。

    3、正文引言

    當你在閱讀本篇文章的時候,有沒有想過,服務器是怎么把這篇文章發送給你的呢?

    說起來很簡單:不就是一個用戶請求嗎?服務器根據請求從數據庫中撈出這篇文章,然后通過網絡發回去嗎。

    其實有點復雜:服務器端到底是如何并行處理成千上萬個用戶請求的呢?這里面又涉及到哪些技術呢?

    這篇文章就是來為你解答這個問題的。

    4、多進程

    歷史上最早出現也是最簡單的一種并行處理多個請求的方法就是利用多進程

    比如在Linux世界中,我們可以使用fork、exec等系統調用創建多個進程,我們可以在父進程中接收用戶的連接請求,然后創建子進程去處理用戶請求。

    就像這樣:

    這種方法的優點就在于:

    • 1)編程簡單,非常容易理解;
    • 2)由于各個進程的地址空間是相互隔離的,因此一個進程崩潰后并不會影響其它進程;
    • 3)充分利用多核資源。

    多進程并行處理的優點很明顯,但是缺點同樣明顯:

    • 1)各個進程地址空間相互隔離,這一優點也會變成缺點,那就是進程間要想通信就會變得比較困難,你需要借助進程間通信(IPC,interprocess communications)機制,想一想你現在知道哪些進程間通信機制,然后讓你用代碼實現呢?顯然,進程間通信編程相對復雜,而且性能也是一大問題;
    • 2)我們知道創建進程開銷是比線程要大的,頻繁的創建銷毀進程無疑會加重系統負擔。

    幸好,除了進程,我們還有線程。

    5、多線程

    不是創建進程開銷大嗎?不是進程間通信困難嗎?這些對于線程來說統統不是問題。

    什么?你還不了解線程,趕緊看看這篇《深入計算機底層,理解線程與線程池》,這里詳細講解了線程這個概念是怎么來的。

    由于線程共享進程地址空間,因此線程間通信天然不需要借助任何通信機制,直接讀取內存就好了。

    線程創建銷毀的開銷也變小了,要知道線程就像寄居蟹一樣,房子(地址空間)都是進程的,自己只是一個租客,因此非常的輕量級,創建銷毀的開銷也非常小。

    我們可以為每個請求創建一個線程,即使一個線程因執行I/O操作——比如讀取數據庫等——被阻塞暫停運行也不會影響到其它線程。

    就像這樣:

    但線程就是完美的、包治百病的嗎,顯然,計算機世界從來沒有那么簡單。

    由于線程共享進程地址空間,這在為線程間通信帶來便利的同時也帶來了無盡的麻煩。

    正是由于線程間共享地址空間,因此一個線程崩潰會導致整個進程崩潰退出,同時線程間通信簡直太簡單了,簡單到線程間通信只需要直接讀取內存就可以了,也簡單到出現問題也極其容易,死鎖、線程間的同步互斥、等等,這些極容易產生bug,無數程序員寶貴的時間就有相當一部分用來解決多線程帶來的無盡問題。

    雖然線程也有缺點,但是相比多進程來說,線程更有優勢,但想單純的利用多線程就能解決高并發問題也是不切實際的。

    因為雖然線程創建開銷相比進程小,但依然也是有開銷的,對于動輒數萬數十萬的鏈接的高并發服務器來說,創建數萬個線程會有性能問題,這包括內存占用、線程間切換,也就是調度的開銷。

    因此,我們需要進一步思考。

    6、事件驅動:Event Loop

    到目前為止,我們提到“并行”二字就會想到進程、線程。

    但是:并行編程只能依賴這兩項技術嗎?并不是這樣的!

    還有另一項并行技術廣泛應用在GUI編程以及服務器編程中,這就是近幾年非常流行的事件驅動編程:event-based concurrency。

    PS:搞IM服務端開發的程序員肯定不陌生,著名的Java NIO高性能網絡編程框架Netty中EvenLoop 這個接口意味著什么(有關Netty框架的高性能原理可以讀這篇《新手入門:目前為止最透徹的的Netty高性能原理和框架架構解析》)。

    大家不要覺得這是一項很難懂的技術,實際上事件驅動編程原理上非常簡單。

    這一技術需要兩種原料:

    • 1)event;
    • 2)處理event的函數,這一函數通常被稱為event handler;

    剩下的就簡單了:你只需要安靜的等待event到來就好,當event到來之后,檢查一下event的類型,并根據該類型找到對應的event處理函數,也就是event handler,然后直接調用該event handler就好了。

    That's it !

    以上就是事件驅動編程的全部內容,是不是很簡單!

    從上面的討論可以看到:我們需要不斷的接收event然后處理event,因此我們需要一個循環(用while或者for循環都可以),這個循環被稱為Event loop。

    使用偽代碼表示就是這樣:

    while(true) {

        event = getEvent();

        handler(event);

    }

    Event loop中要做的事情其實是非常簡單的,只需要等待event的帶來,然后調用相應的event處理函數即可。

    注意:這段代碼只需要運行在一個線程或者進程中,只需要這一個event loop就可以同時處理多個用戶請求。

    有的同學可以依然不明白:為什么這樣一個event loop可以同時處理多個請求呢?

    原因很簡單:對于網絡通信服務器來說,處理一個用戶請求時大部分時間其實都用在了I/O操作上,像數據庫讀寫、文件讀寫、網絡讀寫等。當一個請求到來,簡單處理之后可能就需要查詢數據庫等I/O操作,我們知道I/O是非常慢的,當發起I/O后我們大可以不用等待該I/O操作完成就可以繼續處理接下來的用戶請求。

    現在你應該明白了吧:雖然上一個用戶請求還沒有處理完我們其實就可以處理下一個用戶請求了,這也是并行,這種并行就可以用事件驅動編程來處理。

    這就好比餐廳服務員一樣:一個服務員不可能一直等上一個顧客下單、上菜、吃飯、買單之后才接待下一個顧客,服務員是怎么做的呢?當一個顧客下完單后直接處理下一個顧客,當顧客吃完飯后會自己回來買單結賬的。

    看到了吧:同樣是一個服務員也可以同時處理多個顧客,這個服務員就相當于這里的Event loop,即使這個event loop只運行在一個線程(進程)中也可以同時處理多個用戶請求。

    相信你已經對事件驅動編程有一個清晰的認知了,那么接下來的問題就是,這個事件也就是event該怎么獲取呢?

    7、事件來源:IO多路復用

    在《深入操作系統,徹底理解I/O多路復用》這篇文章中我們知道,在Linux/Unix世界中一切皆文件,而我們的程序都是通過文件描述符來進行I/O操作的,當然對于網絡編程中的socket也不例外。

    那我們該如何同時處理多個文件描述符呢?

    IO多路復用技術正是用來解決這一問題的:通過IO多路復用技術,我們一次可以監控多個文件描述,當某個“文件”(實際可能是im網絡通信中socket)可讀或者可寫的時候我們就能得到通知啦。

    這樣IO多路復用技術就成了event loop的原材料供應商,源源不斷的給我們提供各種event,這樣關于event來源的問題就解決了。

    當然:關于IO多路復用技術的詳細講解請參見《深入操作系統,徹底理解I/O多路復用》,本文作為綱領性文章,就不再贅述了。

    至此:關于利用事件驅動來實現并發編程的所有問題都解決了嗎?event的來源問題解決了,當得到event后調用相應的handler,看上去大功告成了。

    想一想還有沒有其它問題?

    8、問題:阻塞式IO

    現在:我們可以使用一個線程(進程)就能基于事件驅動進行并行編程,再也沒有了多線程中讓人惱火的各種鎖、同步互斥、死鎖等問題了。

    但是:計算機科學中從來沒有出現過一種能解決所有問題的技術,現在沒有,在可預期的將來也不會有。

    那上述方法有什么問題嗎?

    不要忘了,我們event loop是運行在一個線程(進程),這雖然解決了多線程問題,但是如果在處理某個event時需要進行IO操作會怎么樣呢?

    在《深入操作系統,理解I/O與零拷貝技術》一文中,我們講解了最常用的文件讀取在底層是如何實現的,程序員最常用的這種IO方式被稱為阻塞式IO。

    也就是說:當我們進行IO操作,比如讀取文件時,如果文件沒有讀取完成,那么我們的程序(線程)會被阻塞而暫停執行,這在多線程中不是問題,因為操作系統還可以調度其它線程。

    但是:在單線程的event loop中是有問題的,原因就在于當我們在event loop中執行阻塞式IO操作時整個線程(event loop)會被暫停運行,這時操作系統將沒有其它線程可以調度,因為系統中只有一個event loop在處理用戶請求,這樣當event loop線程被阻塞暫停運行時所有用戶請求都沒有辦法被處理。你能想象當服務器在處理其它用戶請求讀取數據庫導致你的請求被暫停嗎?

    因此:在基于事件驅動編程時有一條注意事項,那就是不允許發起阻塞式IO。

    有的同學可能會問,如果不能發起阻塞式IO的話,那么該怎樣進行IO操作呢?

    PS:有阻塞式IO,就有非阻塞式IO。我們繼續往下討論。

    9、解決方法:非阻塞式IO

    為克服阻塞式IO所帶來的問題,現代操作系統開始提供一種新的發起IO請求的方法,這種方法就是異步IO。對應的,阻塞式IO就是同步IO,關于同步和異步這兩個概念可以參考《從根上理解高性能、高并發(四):深入操作系統,徹底理解同步與異步》。

    異步IO時,假設調用aio_read函數(具體的異步IO API請參考具體的操作系統平臺),也就是異步讀取,當我們調用該函數后可以立即返回,并繼續其它事情,雖然此時該文件可能還沒有被讀取,這樣就不會阻塞調用線程了。此外,操作系統還會提供其它方法供調用線程來檢測IO操作是否完成。

    就這樣,在操作系統的幫助下IO的阻塞調用問題也解決了。

    10、基于事件驅動并行編程的難點

    雖然有異步IO來解決event loop可能被阻塞的問題,但是基于事件編程依然是困難的。

    首先:我們提到,event loop是運行在一個線程中的,顯然一個線程是沒有辦法充分利用多核資源的,有的同學可能會說那就創建多個event loop實例不就可以了,這樣就有多個event loop線程了,但是這樣一來多線程問題又會出現。

    另一點在于編程方面,在《從根上理解高性能、高并發(四):深入操作系統,徹底理解同步與異步》這篇文章中我們講到過,異步編程需要結合回調函數(這種編程方式需要把處理邏輯分為兩部分:一部分調用方自己處理,另一部分在回調函數中處理),這一編程方式的改變加重了程序員在理解上的負擔,基于事件編程的項目后期會很難擴展以及維護。

    那么有沒有更好的方法呢?

    要找到更好的方法,我們需要解決問題的本質,那么這個本質問題是什么呢?

    11、更好的方法

    為什么我們要使用異步這種難以理解的方式編程呢?

    是因為:阻塞式編程雖然容易理解但會導致線程被阻塞而暫停運行。

    那么聰明的你一定會問了:有沒有一種方法既能結合同步IO的簡單理解又不會因同步調用導致線程被阻塞呢?

    答案是肯定的:這就是用戶態線程(user level thread),也就是大名鼎鼎的協程(關于協程請詳讀本系列的上篇《從根上理解高性能、高并發(五):深入操作系統,理解高并發中的協程》,本文就不再贅述了)。

    雖然基于事件編程有這樣那樣的缺點,但是在當今的高性能高并發服務器上基于事件編程方式依然非常流行,但已經不是純粹的基于單一線程的事件驅動了,而是 event loop + multi thread + user level thread。

    關于這一組合,同樣值得拿出一篇文章來講解,我們將在后續文章中詳細討論。

    12、本文小結

    高并發技術從最開始的多進程一路演進到當前的事件驅動,計算機技術就像生物一樣也在不斷演變進化,但不管怎樣,了解歷史才能更深刻的理解當下。希望這篇文章能對大家理解高并發服務器有所幫助。

    附錄:更多高性能、高并發文章精選

    高性能網絡編程(一):單臺服務器并發TCP連接數到底可以有多少

    高性能網絡編程(二):上一個10年,著名的C10K并發連接問題

    高性能網絡編程(三):下一個10年,是時候考慮C10M并發問題了

    高性能網絡編程(四):從C10K到C10M高性能網絡應用的理論探索

    高性能網絡編程(五):一文讀懂高性能網絡編程中的I/O模型

    高性能網絡編程(六):一文讀懂高性能網絡編程中的線程模型

    高性能網絡編程(七):到底什么是高并發?一文即懂!

    以網游服務端的網絡接入層設計為例,理解實時通信的技術挑戰

    知乎技術分享:知乎千萬級并發的高性能長連接網關技術實踐

    淘寶技術分享:手淘億級移動端接入層網關的技術演進之路

    一套海量在線用戶的移動端IM架構設計實踐分享(含詳細圖文)

    一套原創分布式即時通訊(IM)系統理論架構方案

    微信后臺基于時間序的海量數據冷熱分級架構設計實踐

    微信技術總監談架構:微信之道——大道至簡(演講全文)

    如何解讀《微信技術總監談架構:微信之道——大道至簡》

    快速裂變:見證微信強大后臺架構從0到1的演進歷程(一)

    17年的實踐:騰訊海量產品的技術方法論

    騰訊資深架構師干貨總結:一文讀懂大型分布式系統設計的方方面面

    以微博類應用場景為例,總結海量社交系統的架構設計步驟

    新手入門:零基礎理解大型分布式架構的演進歷史、技術原理、最佳實踐

    從新手到架構師,一篇就夠:從100到1000萬高并發的架構演進之路

    本文已同步發布于“即時通訊技術圈”公眾號。

    ▲ 本文在公眾號上的鏈接是:點此進入。同步發布鏈接是:http://www.52im.net/thread-3315-1-1.html



    作者:Jack Jiang (點擊作者姓名進入Github)
    出處:http://www.52im.net/space-uid-1.html
    交流:歡迎加入即時通訊開發交流群 215891622
    討論:http://www.52im.net/
    Jack Jiang同時是【原創Java Swing外觀工程BeautyEye】【輕量級移動端即時通訊框架MobileIMSDK】的作者,可前往下載交流。
    本博文 歡迎轉載,轉載請注明出處(也可前往 我的52im.net 找到我)。


    只有注冊用戶登錄后才能發表評論。


    網站導航:
     
    Jack Jiang的 Mail: jb2011@163.com, 聯系QQ: 413980957, 微信: hellojackjiang
    主站蜘蛛池模板: 国产国产人免费视频成69大陆| 亚洲成在人线aⅴ免费毛片| 国产免费av一区二区三区| 亚洲综合国产成人丁香五月激情 | 四虎永久成人免费| 亚洲国产精品美女久久久久| 18禁超污无遮挡无码免费网站国产| 亚洲国产成人久久三区| 免费AA片少妇人AA片直播| 亚洲va久久久久| 日韩人妻无码免费视频一区二区三区| 亚洲啪AV永久无码精品放毛片| 免费被黄网站在观看| 国产精品日本亚洲777| 亚洲国产成人久久笫一页| 毛片基地看看成人免费| 国产成人亚洲综合无码精品 | 亚洲va久久久噜噜噜久久狠狠 | 免费a级毛片大学生免费观看 | 最新黄色免费网站| 亚洲欧洲日本在线观看| 国产99视频精品免费视频7| 国产精品1024在线永久免费| 亚洲av色影在线| 国产麻豆视频免费观看| 国产天堂亚洲国产碰碰| 国精无码欧精品亚洲一区| 国产成人精品免费视频网页大全 | 黑人粗长大战亚洲女2021国产精品成人免费视频 | 女人18毛片水真多免费看| 美女啪啪网站又黄又免费| 亚洲精品无码永久中文字幕| 18女人腿打开无遮掩免费| 亚洲一久久久久久久久| 亚洲伊人成无码综合网| 免费无码中文字幕A级毛片| 亚洲国产精品无码久久98| 亚洲成AV人片在线观看| 18禁成年无码免费网站无遮挡| 一级一看免费完整版毛片| 亚洲欧洲精品久久|