這篇文章要跟大家介紹的內容是關於淺談node.js中高並發與分散式集群的內容,有一定的參考價值,有需要的朋友可以參考一下,希望對你有所幫助。
在解釋node為什麼能夠做到高並發之前,不妨先了解node的其他幾個特性:
我們先來明確一個概念,即:node是單執行緒
的,這一點與JavaScript在瀏覽器中的特性相同,並且在node中JavaScript主執行緒與其他執行緒(例如I/O執行緒)是無法共享狀態的。
單一執行緒的好處就是:
#不需要像多執行緒一樣去關注執行緒之間的狀態同步問題
沒有執行緒切換所帶來的開銷
沒有死鎖存在
當然單執行緒也有許多壞處:
無法充分利用多核心CPU
大量運算佔用CPU會導致應用程式阻塞(即不適用CPU密集型)
錯誤會引起整個應用的退出
不過在今天看來,這些壞處都已經不再是問題或得到了適當的解決:
(1) 創建進程or 細分實例
關於第一個問題,最直白解決方案就是使用child_process核心模組或cluster:child_process 和net 組合應用程式。我們可以透過在一台多核心伺服器上建立多個進程(通常使用fork操作)來充分利用每個核心,不過要處理好進程間通訊問題。
另一個方案是,我們可以將實體機器分割成多台單核心的虛擬機,並透過pm2等工具,管理多台虛擬機形成一個叢集架構,高效運作所需服務,至於每台機器間的通訊(狀態同步)我這裡先按下不表,在下文的Node分散式架構中再做詳細說明。
(2) 時間片輪轉
關於第二點,我跟小夥伴討論過後認為可以透過時間片輪轉方式,在單線程上模擬多線程,適當減少應用阻塞的感覺(雖然這種方法不會真的像多執行緒那樣節約時間)
(3) 負載平衡、壞點監控/隔離
至於第三點,我跟小夥伴們也討論過,認為主要的痛點就在於node不同於JAVA,它所實現的邏輯是以非同步為主的。
這就導致了node無法像JAVA一樣方便地使用 try/catch 來捕獲並繞過錯誤,因為無法確定非同步任務會何時傳回異常。而在單線程環境下,繞不過錯誤意味著導致應用程式退出,重啟恢復的間隙會導致服務中斷,這是我們不願意看到的。
當然,在伺服器資源豐富的當下,我們可以透過 pm2 或 nginx 這些工具,動態的判斷服務狀態。在服務出錯時隔離壞點伺服器,將請求轉送到正常伺服器上,並重新啟動壞點伺服器以繼續提供服務。這也是Node分散式架構的一部分。
你可能會問,既然node是單執行緒的,事件全部在一個執行緒上處理,那不是應該效率很低、與高並發相悖嗎?
恰恰相反,node的效能很高。原因之一是node具有非同步I/O
特性,每當有I/O請求發生時,node會提供給該請求一個I/O執行緒。然後node就不管這個I/O的操作過程了,而是繼續執行主執行緒上的事件,只需要在該請求返回回呼時在處理即可。也就是node省去了許多等待請求的時間。
這也是node支援高並發的重要原因之一
實際上不光是I/O操作,node的絕大多數操作都是以這種非同步的方式進行的。它就像是組織者,無需事必躬親,只需要告訴成員們如何正確的進行操作並接受反饋、處理關鍵步驟,就能使得整個團隊高效運作。
你可能又要問了,node怎麼知道請求回傳了回調,又應該何時去處理這些回調呢?
答案是node的另一個特性:事務驅動
,也就是主執行緒透過event loop事件循環觸發的方式來執行程式
##這是node支持高並發的另一個重要原因
圖解node環境下的Event loop:┌───────────────────────┐ ┌─>│ timers │<p>poll階段:<strong></strong></p>當進入poll階段,並且沒有timers被呼叫的時候,會發生下面的情況:<p></p>(1)如果poll隊列不為空:<p></p>
當進入到poll階段,並且呼叫了timers的話,會發生下面的情況:
一旦poll queue是空的話,Event Loop會檢查是否timers, 如果有1個或多個timers時間已經到達,Event Loop將會回到timer階段並執行那些timer的callback(即進入到下一次tick)。
優先:
Next Tick Queue > MicroTask Queue
setTimeout、setInterval > setImmediate
#由於timer需要從紅黑樹中取出定時器來判斷時間是否到了,時間複雜度為O(lg(n)),故如果想立即非同步執行一個事件,最好不要用setTimeout(func, 0) 。而是使用 process.nextTick() 來完成。
按我的理解整理了一副圖:
這對伺服器的記憶體負荷是相當高的,所以通常我們還是會在架構中加入Mysql,如下圖:
當用戶資料到來時,先將資料寫入Mysql,Node 需要資料時再去Redis 讀取,若沒有找到再去Mysql 裡面查詢想要的數據,並寫入Redis,下次使用時就可以直接去Redis 裡面查詢了。
(1)避免了短期內無用的資料寫入Redis,佔用內存,減輕Redis 負擔
流量接入層所做的就是對所有接受的流量進行處理,提供了以下服務:
讀取後端回應頭逾時
寫入回應逾時
與使用者長連線逾時
##叢集健康檢查/隔離壞點伺服器
連線池/會話保持機制
(2)編寫高效能查詢語句,與Redis、Mysql 交互,提高查詢效率
(3)透過Redis 同步叢集裡各個Node 服務的狀態
(4)透過硬體管理平台,管理/監控實體機器的狀態、管理IP位址等(其實這部分工作放在這一層感覺不妥,但我也不知道應該放在哪一層。。。)
(當然這部分我只是粗淺地列列條目,還是需要時間來累積、深入理解)
這一層主要的工作是:
# (1)建立Mysql 並設計相關頁、表格;建立必要的索引、外鍵,提升查詢便利性
(2)部署redis 並向Node 層提供對應介面
相關推薦:
以上是淺談node.js中高並發與分散式叢集的內容的詳細內容。更多資訊請關注PHP中文網其他相關文章!