【問底】夏俊:深刻站點服務端技術(一)——站點併發的問題

摘要:本文來自擁有十年IT從業經驗、擅長站點架構設計、Web前端技術以及Java企業級開發的夏俊,此文也是《關於大型站點技術演進的思考》系列文章的最新出爐內容。首發於CSDN,各位技術人員不容錯過。

注:本文首發於CSDN,轉載請標明出處。javascript

【編者按】 本文來自擁有十年IT從業經驗、擅長站點架構設計、Web前端技術以及Java企業級開發的夏俊。此文也是《關於大型站點技術演進的思考》系列文章的最新出爐內容。首發於CSDN。各位技術人員不容錯過。php

下面爲正文:html

1、 引子

《關於大型站點技術演進的思考》已經連載完了兩個系列,它們各自是《存儲的瓶頸》和《站點靜態化的處理》。這兩個系列相應到站點裏的組件就是存儲端和瀏覽器端。站點除了這兩端外,另外一端那就是服務端了,服務端上接瀏覽器端。下承存儲端,因此當咱們想讓站點的瀏覽器端或存儲端性能更加優秀的時候,就不得不去考慮服務端的問題,因爲服務端和它們永遠都是剪不斷理還亂的關聯性。前端

現在我要開啓《關於大型站點技術演進的思考》這個主題下最後一個系列,這個系列就是 討論站點組件裏最後一端服務端了,因爲服務端和瀏覽器端以及存儲端存在着一種永遠都剪不斷的關係。因此本系列還會解說和其它兩端相關聯的技術,只是本系列的講述的深度會更高些,但願經過這樣的深刻的研究讓咱們更加深刻的理解那些能做用於瀏覽器端和存儲端的服務端技術。固然服務端除了上接瀏覽器端,下承存儲端做用外。它自身還有本身的技術範疇,那就是怎樣使用服務端技術實現站點的業務邏輯了,以上這些就是本系列將要討論的主題了。java

本系列大概會按下面思路進行討論:react

  • 首先是從和瀏覽器端相連的服務端技術講起,這塊知識映射到MVC模式那就是控制層的相關技術,這裏主要包括:併發性。併發和集羣的問題。HTTP協議的轉化問題等等,最後我將以MVC裏C層即控制層的做用來總結下這塊的技術;
  • 接下來就是解說服務端實現業務邏輯層的技術,這個映射到MVC模式就是M層即模型層的問題了。這裏面我不會去討論怎樣使用服務端技術寫業務邏輯,而是以模型層和控制層關係的角度、模型層和存儲層關係的角度以及模型層的服務治理的角度來討論模型層架構設計的問題。
  • 而後就是服務端和存儲端相關的技術了,這裏面主要就是我在存儲瓶頸系列裏提到的數據訪問層。該層的做用是爲了遷移存儲層的計算功能,從而達到減輕存儲層系統壓力的目的。上面內容講完之後我會參照以上的技術總結下大型站點分佈式系統和站點SOA應用的特色。

固然上面的知識都是我本身多年經驗和本身所掌握知識的總結,現在尚未完整的知識雛形,因此在寫的過程裏很是有可能會依據實際狀況進行調整。不管最後結果怎樣,上面的列舉的慷慨向我都會盡力講到的。redis

2、關於站點併發的問題

如下就我開始講服務端和瀏覽器端相關部分的技術了,首先從站點的併發性開始講起吧。算法

1)《關於大型站點技術演進的思考》前兩系列的內容數據庫

存儲的瓶頸和站點靜態化處理參見本人的 博客編程

2)站點併發問題概述

什麼是站點的併發?這個問題答案很是easy,站點的併發就是指站點在同一個時間可以同一時候處理多個用戶請求。談到站點的併發,很是多朋友很是天然的會想到多線程技術。多線程可以使得一個應用程序並行處理多個計算任務,這個技術的做用類推到Web應用裏那就是多線程技術可以讓站點並行處理多個請求,所以多線程技術是可以用來處理站點的併發問題的。

因此當咱們要去理解站點的併發問題時候,首先要解決的問題就是怎樣使用多線程技術。

當咱們學好了多線程技術。是否是就可以解決站點的併發問題了?回答固然是可以的,只是一個站點對併發的要求絕對不是隻要求咱們會使用多線程技術那麼簡單了,當站點併發的問題解決後。咱們當即就要面臨一個相同迫切的問題了,那就是怎樣提高站點的併發能力。這個問題落到實處就是怎樣讓站點在有限的系統資源下併發能力變得更強,換句話說就是怎樣讓有限的系統資源下。站點的併發數更大,當站點併發數變大之後,咱們又要考慮怎樣讓單個請求處理效率更高。這兩個內容就是本篇文章的主題了。

本篇文章主要是談論如何提高單臺server的併發能力問題,下一篇文章談論的是當站點處理用戶請求的服務端使用了集羣技術後,針對併發的處理會發生如何的變化呢。

3)多線程技術

併發技術相應的是多線程技術,而多線程技術又是創建在線程技術上。那麼咱們這裏首先談談線程技術的問題。

第一步我要作的是明白什麼是線程,如下是百度百科裏對線程的解釋。詳細例如如下:

線程,有時被稱爲輕量級進程(Lightweight Process。LWP),是程序執行流的最小單元。

一個標準的線程由線程ID,當前指令指針(PC),寄存器集合和堆棧組成。另外,線程是進程中的一個實體。是被系統獨立調度和分派的基本單位,線程本身不擁有系統資源。僅僅擁有一點兒在執行中不可缺乏的資源,但它可與同屬一個進程的其餘線程共享進程所擁有的全部資源。

從這個定義裏咱們知道線程有例如如下特色:

  • 特色一:線程是進程的一個實體,也就是說線程的母體是進程,這是線程的範疇問題。
  • 特色二:線程是輕量級的,它本身不擁有系統資源。但是咱們知道線程運行時候是可以操做硬盤的文件。也可以操做內存的數據,那麼這些被線程操做的資源從哪裏來的呢?上面的解釋裏回答了這個問題。那就是線程可以共享進程的資源。換句話說線程操做的資源是進程的資源。

  • 特色三:線程本身也有寄存器和堆棧。這些東西自己也是可以存儲數據的,數據也是要佔用系統的部分資源,那麼這個解釋也就說明,線程自己也是可以佔必定系統資源了,僅僅只是這個資源比較少而已,因此這個解釋就補充了特色二的場景:線程操做的資源除了它所在進程的資源外還有它自身能控制的資源,這一點比較重要。我會在後面講線程安全問題裏提到線程自有資源的使用問題的。

單個線程就是一個獨立的程序運行流。咱們在學習計算機語言,寫的練習代碼都是在一個單線程的場景下進行的,單個線程放到站點併發處理的範疇裏,它有個問題是咱們必定要注意的,那就是怎樣提高單個線程的運行效率問題,也就是說咱們怎樣讓一個線程運行的更快同一時候還要讓一個線程運行時候所消耗的系統資源更低。爲了解決問題,咱們就要分析下單個線程的運做特色,看看線程運做流程裏那些方面會影響到線程的運行效率問題。

線程運做流程很是easy。咱們使用線程時候首先是建立一個線程,線程建立好之後就是使用它了,線程使用完成之後就要銷燬它了。把這個流程放到請求處理場景裏,咱們就會發現線程的建立過程和線程的銷燬過程事實上是和處理請求的邏輯無關。但是一個線程又必須經歷這三個階段,所以線程建立的時間和線程銷燬的時間也會被統計到請求處理時間裏,那麼咱們就會想有沒有辦法可以消除線程建立和銷燬所花的時間對請求處理的影響呢?

之前有人在Linux上作過一個測試。這個測試結果就是一個線程建立和消耗至少要消耗2MB的內存。依照這個結論。假設咱們在Linux上建立1000個線程那麼系統至少要消耗2G以上的內存。這個消耗是很是驚人,假設咱們每次使用一個線程就來個建立銷燬,那麼請求處理時候就會要新增很是多無謂的系統資源消耗。假如碰到server系統資源很是緊張時候,線程的頻繁建立和銷燬的過程就會侵佔不少其它系統資源從而影響到線程的運行,這個問題咱們又該怎樣來攻克了?

要解決問題咱們首先要回想下線程的運做流程,這個結果例如如下圖所看到的:

 

這張圖不是咱們但願看到的,咱們但願看到如下這種流程圖。例如如下圖所看到的:

 

咱們但願請求處理流程僅僅是做用在線程運行這塊。那麼在實際的生產實踐裏咱們又是怎樣來解決問題了?解決方式就是使用線程池技術,線程池技術就是基於線程建立和銷燬操做影響性能的角度來設計的。只是線程池技術並非簡單的事先建立好一批線程,而後統一銷燬一批線程那麼簡單,這裏我以Java的JDK裏自帶的線程池技術爲例來說講關於線程池技術的使用,內容詳細例如如下:

JDK裏的線程池對線程池大小的設定使用了兩個參數,一個是核心線程個數,一個是最大線程個數。核心線程在系統啓動時候就會被建立,假設用戶請求沒有超過核心線程處理能力,那麼線程池不會再建立新線程,假設核心線程個數已經處理只是來了,線程池就會開啓新線程,新線程第一次建立後,使用完成後也不是立刻對其銷燬,也是被會收到線程池裏,當線程池裏的線程總數超過了最大線程個數,線程池將不會再建立新線程,這樣的作法讓線程數量依據實際請求的狀況進行調整,這樣既達到了充分利用計算機資源的目的。同一時候也避免了系統資源的浪費,JDK的線程池還有個超時時間。當超出核心線程的線程在必定時間內一直未被使用,那麼這些線程將會被銷燬,資源就會被釋放,這樣就讓線程池的線程的數量老是處在一個合理的範圍裏;假設請求實在太多了,線程池裏的線程臨時處理只是來了。JDK的線程池還提供一個隊列機制,讓這些請求排隊等待,當某個線程處理完成,該線程又會從這個隊列裏取出一個請求進行處理,這樣就避免請求的丟失,jdk的線程池對隊列的管理有很是多策略,有興趣的童鞋可以查查百度,這裏我還要說的是jdk線程池的安全策略作的很是好,假設隊列的容量超出了計算機的處理能力,隊列會拋棄沒法處理的請求,這個也叫作線程池的拒絕策略。

由上面對JDK自帶線程池的介紹,咱們發現使用線程池咱們要考慮例如如下的問題。詳細例如如下:

  • 問題一:線程池初始化的時候咱們究竟要事先建立多少個線程放在池子裏比較合適。

  • 問題二:線程池初始化時候假設建立的線程過多會有什麼問題。
  • 問題三:一臺server由於受限於自身能力的限制好比CPU的能力。內存的能力等等,那麼一臺server可以建立多少個有效線程的數量事實上是有個臨界值的。那麼當業務方要求建立超出臨界值的線程時候咱們的處理策略是如何的呢。

問題三的我在介紹JDK裏線程池的設計方案時候已經提到了,解決方法就是當業務方要求超出臨界值時候。詳細就是超出線程池最大線程數的時候,咱們用一個隊列先緩存這些請求,等線程池裏的線程空暇出來後,再去從隊列裏取出業務請求交付給線程進行處理。

至於問題一和問題二。這個就和多線程的技術相關了,爲了更好的解答它,我這裏先來介紹下多線程技術。

多線程技術的核心就是讓多個線程同一時候被運行。用戶的感覺就是計算機可以並行運行計算任務,那麼咱們首先要理解下多個線程是怎樣進行併發操做的。詳細例如如下:

一個程序包括兩個部分,它們就是計算和存儲了,好的程序就和一個活生生的人同樣,存儲至關於人的臭皮囊也就是身體了,而計算就是人的大腦了,而程序的計算是經過CPU來完畢的,因此線程的並行運行效果就是看CPU是怎樣並行處理多個線程的機制了。那麼CPU怎樣作到並行處理呢?事實上CPU並不能作到並行處理,CPU僅僅能一次運行一個計算指令。聽到這個回答,咱們的頭是否是一會兒變大了,CPU無法作到並行處理,那咱們看到活生生的並行操做到底是怎麼回事呢?

線程技術裏有個概念叫作時間片,要解釋時間片咱們就要從進程提及了,當一個進程被操做系統運行時候,CPU會給這個進程分配一段運行時間,當進程裏面建立了線程之後,操做系統會把進程分配到的運行時間分紅片斷賦予給線程,假如進程裏僅僅有一個線程,那麼這個線程的時間片的長度就和進程的時間段基本一致,假設進程裏開啓的線程有多個。假設這些線程沒有設置什麼優先級策略。那麼每個線程就會平分到一樣的時間片,時間片就是線程被CPU運行的單位時間,當CPU依照時間片規定的時間運行了某個線程後。假設線程的CPU計算沒有全部運行完成,那麼CPU就會讓線程先掛起來等因而讓線程處於一個等待狀態。CPU的調度機制找到下一個線程。當下一個線程時間片所規定的時間運行完成後,CPU就會讓這個線程掛起來。再去找第三個線程,這個過程依次進行下去。等進程裏開啓的線程都運行完成後。第一個線程纔會又一次開始運行。這個機制就是線程的輪詢機制了,也是咱們常說的線程切換機制背後的原理了。

該機制可以保障在一個固定時間範圍內,全部線程都能獲得運行,由於線程的運行速度很快,因此給用戶的感受就是多個線程是可以並行運行的。

由上面的原理咱們來看看這個實例,詳細例如如下:

有一個線程被分配到的時間片長度是10毫秒。假設這個線程沒有其它干擾。它運行完成需要花費50毫秒,那就等於要運行5次時間片。假如咱們再新增了一個線程,該線程時間片也是10毫秒。也要運行50毫秒才幹運行完成,那麼當中一個線程運行完一次時間片。依照輪詢機制另一個線程也要被運行。最後咱們就會發現第一個線程運行時間就變成了100毫秒,假設咱們再加上CPU的調度所花的時間,該線程的運行時間就會遠遠大於100毫秒。儘管100多毫秒人的感官是很是難覺察到,但是這個作法畢竟讓單個線程的運行效率大幅度減小了,假設咱們線程開啓的不少其它,那麼單個線程運行效率也就會變得更低。

有了這個結論咱們再去看看線程池問題一和問題二,假設咱們一開始建立了太多線程。而且這些線程大部分都會被閒置,那麼這些閒置的線程就會讓有效線程的運行效率大大下降。同一時候閒置的線程還會消耗系統資源。而這些被消耗的系統資源都沒實用到業務處理上,因此成熟的線程池方案就會設計核心線程和最大線程的概念。它們可以讓線程池依據實際業務需求和系統負載能力作到動態調節。這樣就可以下降開啓不少其它線程影響線程運行效率的問題,也可以讓計算機的系統資源獲得更加有效的利用。

4)站點的併發與多線程技術

多線程技術可以實現併發操做。站點的併發場景很適合使用多線程技術,那麼咱們就先來談談怎樣使用多線程技術來實現站點併發,首先咱們從單個站點請求處理場景開始提及吧。

單個網絡請求是從瀏覽器端發送,經過網絡傳輸到服務端,服務端接收到數據後進行處理,處理完畢後服務端再把響應經過網絡發送給瀏覽器端。而這個過程都是使用服務端一個線程全程陪同的完畢,這個作法彷佛沒什麼問題,這裏我先給你們看一個表格,這個表格是Node.js 的做者 Ryan Dahl 爲 JSConf 大會所做的演講裏提供的,詳細例如如下所看到的:

I/O設備

CPU 調用週期

CPU一級緩存

3

CPU二級緩存

14

內存

250

硬盤

41000000

網絡

240000000

從這個表格裏咱們發現,網絡IO的處理時間是CPU一級緩存處理時間的一億倍。假如咱們把CPU一級緩存的處理速度等同於CPU的計算速度。這裏我若是CPU運行時間是1毫秒。那麼當一個線程裏有網絡操做時候,CPU要等待將近1億毫秒的時間才被運行,這1億毫秒時間裏CPU不知道可以作多少事情啊。

咱們再以Java的網絡編程爲例進一步說明這個問題。站點的網絡傳輸協議是HTTP協議,HTTP協議使用的是TCP協議進行網絡通信的。java裏使用socket技術來編寫TCP通信程序,最主要的socket編程裏當client有數據傳遞到服務端後,服務端的ServerSocket就會開啓一個線程處理這個請求了。但是服務端的處理需要client把全部傳輸數據完成後才幹作興許處理,因此當client數據還沒傳輸完成,處理線程就要在哪裏等待傳輸數據完成,咱們由上表可以知道線程的等待時間相對於CPU運行時間是何等長了,等待的線程什麼都沒有作的時候還要參入線程的輪詢處理裏。所以它還會影響其它線程的運行效率。

單個server自己所能承載的線程數量是有限的,假如某個線程就這種被閒置起來就會致使線程的利用率十分低下。這些問題咱們究竟該怎樣來攻克了?

5)怎樣提高線程的使用效率?

要解答標題的問題,咱們首先要分析下站點請求的特色,站點的請求事實上包括兩個操做步奏,這兩個步奏各自是IO操做和CPU操做,而線程的做用主要是體現在CPU的操做上,假設咱們在一個線程裏包括IO操做和CPU操做,特別是使用到很是慢的網絡IO操做時候,那麼IO操做的效率就會影響到CPU操做的運行效率,假設咱們能把這兩個操做分解開來,讓線程僅僅去關心CPU操做,這樣單個線程就能被更加充分的利用起來,可是IO操做畢竟是請求操做裏不可切割的操做,那麼咱們究竟該怎樣破這個局了?

破這個局的方法就是使用赫赫有名的reactor設計模式,咱們來看看reactor模式的設計圖。例如如下圖所看到的:

 

reactor模式裏有一個組件就是reactor組件。它事實上是一個單獨的線程。client的請求首先是發送到服務端的reactor線程進行處理,reactor線程採取輪詢的方式輪詢client的請求,當它發現某一個請求的傳輸數據完成後,reactor就以事件通知的方式從線程池裏取出一個線程進行興許處理。這樣線程池裏的每個線程都能被充分的使用。

咱們再細緻分析下reactor模式,咱們發現啊,reactor模式事實上並無提高一個請求的整體運行效率,而是把請求裏效率最低的IO操做和CPU計算操做分紅兩步進行運行,這個方式就等因而把同步請求操做成了一個異步運行操做,儘管該方式沒有提高請求整體的處理效率,但是它能讓服務端的線程利用率更高,這也就變相的讓站點的併發處理能力加強了,而且該方式可以避免線程被閒置在那裏空轉的問題。假如咱們能有效的控制好線程的合理數量,那麼該方式仍是有可能提高單個請求的運行效率的。

Reactor模式處理請求的模式和上節裏講到請求處理模式。它們的核心問題都是發生在請求的IO處理問題上,因此上節的IO處理場景在java技術領域裏有個專有名詞表述那就是BIO。中文解釋就是堵塞的IO,這個堵塞的含義就是指當一個IO操做運行時候它會獨佔IO處理的線程。其它IO操做就被此IO操做堵塞起來,而Reactor模式下的IO操做在java技術裏也有個專有名詞那就是NIO,NIO最先出現在JDK1.4版。當時官方解釋是New IO。經過咱們上面的論述咱們發現NIO事實上是針對BIO的堵塞問題設計的。因此咱們習慣把NIO稱之爲非堵塞IO,非堵塞IO操做不會堵塞線程的操做。

古老的Apacheserver和java裏的tomcat容器新版本號都採取了NIO技術。但是Apache和它同類型的ngnixserver相比,所能承載的併發能力實在差太多了,實際場景下Apache能支持5000個併發就要驚爲天人了,而ngnix官方文檔裏就說它可以支持5萬併發,而實際場景裏支持3萬併發那是一點問題都沒有的。爲何ngnix可以達到如此高的性能呢?它有什麼獨門絕技呢?

6)C10K的目標

業界有一個C10K的目標。所謂c10k問題,指的是server同一時候支持成千上萬個client的問題,也就是concurrent 10 000 connection(這也是c10k這個名字的由來)。

咱們想讓Apache同一時候支持上萬併發這個在實際場景下是一件基本沒法完畢的事情。聽到個人說法不知道會不會有朋友不服氣。我要是把server的配置搞得高高的。我就不信Apache不能支持上萬併發,假設咱們這麼作了咱們就會發現server硬件的提高並不能致使Apache併發能力的線性提高。假如咱們設定Apache在5000併發下咱們經過添加硬件性能可以近似的提高Apache的併發能力,當Apache併發達到5000後。咱們再把硬件性能提高一倍,終於咱們必定會發現Apache的併發數並不會變成1萬,它能支持到7000以上就謝天謝地了。而且Apache的併發越高。其單個鏈接的處理性能降低的也很厲害。而這個場景遷移到ngnix上。結果就大不一樣樣了,ngnix基本可以作到硬件性能提高,其併發性能也能達到線性提高的目的。

因而可知ngnix實在太優秀了。它究竟用什麼獨門祕籍了?你們是否是很是急迫的想知道了,如下我就來說講ngnix的設計思想了。

首先咱們要分析下多線程作併發的問題,線程自己是要消耗系統資源的,假設咱們開啓線程很是多,計算機就得抽取不少其它資源維護這些線程,因此線程越多浪費掉的系統資源也就不少其它,這是多線程作併發的第一個問題。

多線程作併發第二個問題就是多線程的並行處理機制了。線程的併發要經過線程輪詢或者說線程切換來保證,而線程的切換會影響單個線程的運行效率。而且CPU管理線程切換也會消耗CPU的計算能力,因此當咱們線程開啓的越多,單個線程的運行效率也會隨之降低。

這也就是Apache容器在高併發下表現出來的問題。

明白了問題。解決方法就出來了。咱們假設想讓線程運行效率更高咱們就不要建立太多線程,這樣就可以下降維護線程的開銷,同一時候也能下降線程切換的開銷。最理想的方案是咱們僅僅使用一個線程來處理所有併發,假設一個線程可以處理好所有併發,那麼線程的開銷問題就基本可以忽略不計了。

依照這個思路咱們就要拋棄多線程處理併發的思路了,這種想法咋一看是否是有點毀人三觀了。那麼一個線程究竟可不可以處理併發了?問題的答案是確定的。

這裏我先不解說ngnix的設計,咱們先講講Node.js技術,Node.js做者之因此要建立Node.js,源自於他對怎樣設計一個高效的Web容器的思考,他以爲高效的Web容器要採取異步機制,事件驅動機制和非堵塞的IO處理。看到這個描寫敘述咱們發現這個和我前面講到reactor模式是何其的類似,但是Node.js在異步機制和事件驅動作的比上面的reactor模式方案更加優秀,在網絡IO處理上。Node.js和reactor模式基本一致,在Node.js有一個專門的模塊異步處理IO操做,只是Node.js對IO操做已經完畢的請求的興許處理就和reactor模式大不一樣樣了,Node.js僅僅用一個線程完畢這個請求的興許處理。這個線程處理請求的方式借鑑了多線程裏並行處理的原理,因爲請求最耗時的IO操做被抽取出來異步處理,因此處理興許請求的單線程僅僅需要運行請求環節裏效率最高的部分,這就讓每個請求的處理速度變得很是快了,人眼基本感受不出這個順序性操做,只是Node.js單線程處理請求的方式和多線程的輪詢機制是不太同樣的。首先輪詢自己的效率是很是低下的,爲了輪詢,操做系統把線程拆分紅若干個步奏運行,這個作法就添加了咱們對多線程處理的難度,假設碰到不一樣線程操做一個共享資源。因爲步奏的拆分就很是有可能產生錯誤的操做共享資源的行爲,這也就是線程安全問題的源頭了。這個問題我後面會將具體討論,這裏就不展開論述了。

Node.js吸收了多線程方案的經驗教訓,它沒有採取輪詢方式處理請求。而是以隊列方式一個個運行請求,這樣就可以充分利用CPU的操做時間,同一時候也規避了線程安全的問題。而且採取這個方式,當一個請求到達服務端後服務端添加的系統資源消耗基本和請求自己的系統資源消耗一致,因此和Node.js機制相似的ngnixserver當併發上去後。請求處理性能也不會像Apache那樣陡降下去。

只是Node.js處理機制裏另外一個細節咱們要特別注意下,那就是異步IO操做怎樣和主線程處理協同起來的。也就是當IO處理完成後咱們怎樣把興許操做插入到主線程下,這個問題看起來很是easy,咱們直接把新的請求放到請求隊列的最後不便可了嗎,那麼問題來了。這個問題就和Ajax技術的問題相似。Ajax可以異步請求。但是因爲請求要經過網絡給服務端處理,因此Ajax從開始運行到最後獲取響應處理響應結果之間就存在很是大的時間差,而這個時間差是很是難把控的。或許有時是1秒,有時就變成了3秒,假設咱們簡單把結果代碼放在Ajax處理後面,那麼咱們僅僅能燒香拜佛但願響應能在代碼運行到結果處理位置時候到達。那麼Ajax技術是怎樣解決問題呢?Ajax使用回調函數機制來破這個題。當服務端響應全然返回到client後,javascript裏有相關的事件就會通知回調函數當即運行,這事實上就把請求發送和響應處理作成了一個異步模式,這也就是Node.js解釋裏提到的異步機制和事件驅動了,異步機制事實上就是指的是回調函數的使用,這個機制放到Node.js對主線程請求隊列的操做裏,那就是異步IO處理完成後。事件機制就會把請求興許操做以回調函數的方式放在請求隊列的後面,這樣就能有效的保證請求處理的時序性了。

Ngnix的設計思想和Node.js的設計思想相似,只是ngnix使用的不是谷歌的V8引擎完畢這個機制的,而是直接使用操做系統的相似機制完畢,因此ngnix的併發能力比Node.js會強很是多,它和Apache相比那就是質的飛越了。

好了。本篇內容講完了,下篇文章我開始再補充下單臺server併發處理的內容。以後我就要討論併發和集羣之間的問題了。

(責編/錢曙光) 

做者簡單介紹:夏俊,擁有十年的IT從業經驗,擅長的技術領域有站點的架構設計、Web前端技術以及java企業級開發。熱愛技術,喜歡分享本身的技術研究成果和經驗


由「2015 OpenStack技術大會」、「2015 Spark技術峯會」、「2015 Container技術峯會」 所組成的 OpenCloud 2015大會於4月17-18日在北京召開。 日程已經全部公開懂行的人都在這裏!(優惠票價期,速來)

不少其它《問底》內容:

《問底》是CSDN雲計算頻道新建欄目,以實踐爲本,分享我的對於新時代軟件架構與研發的深入看法。在含有「【問底】」字樣標題的文章中。你會看到某個國外IT巨頭的架構分享。會看到國內資深project師對某個技術的實踐總結,更會看到一系列關於某個新技術的探索。

 《問底》邀請對技術具備獨特/深入看法的你一塊兒打造一片僅僅屬於技術的天空。詳情可郵件至qianshg@csdn.net。 

相關文章
相關標籤/搜索