微服務(wù)架構(gòu)是一種構(gòu)造應(yīng)用程序的替代性方法。應(yīng)用程序被分解為更小、完全獨(dú)立的組件,這使得它們擁有更高的敏捷性、可伸縮性和可用性。
一個(gè)復(fù)雜的應(yīng)用被拆分為若干微服務(wù),微服務(wù)更需要一種成熟的交付能力。持續(xù)集成、部署和全自動(dòng)測(cè)試都必不可少。編寫(xiě)代碼的開(kāi)發(fā)人員必須負(fù)責(zé)代碼的生產(chǎn)部署。構(gòu)建和部署鏈需要重大更改,以便為微服務(wù)環(huán)境提供正確的關(guān)注點(diǎn)分離。
后續(xù)我們會(huì)聊一下如何在時(shí)速云平臺(tái)上集成 DevOps。

Node.js 是構(gòu)建微服務(wù)的利器,為什么這么說(shuō)呢,我們先看下 Node.js 有哪些優(yōu)勢(shì):
Node.js 采用事件驅(qū)動(dòng)、異步編程,為網(wǎng)絡(luò)服務(wù)而設(shè)計(jì)
Node.js 非阻塞模式的IO處理給 Node.js 帶來(lái)在相對(duì)低系統(tǒng)資源耗用下的高性能與出眾的負(fù)載能力,非常適合用作依賴(lài)其它IO資源的中間層服務(wù)
Node.js輕量高效,可以認(rèn)為是數(shù)據(jù)密集型分布式部署環(huán)境下的實(shí)時(shí)應(yīng)用系統(tǒng)的完美解決方案。
這些優(yōu)勢(shì)正好與微服務(wù)的優(yōu)勢(shì):敏捷性、可伸縮性和可用性相契合(捂臉笑),再看下Node.js 的缺點(diǎn):
單進(jìn)程,單線(xiàn)程,只支持單核CPU,不能充分的利用多核CPU服務(wù)器。一旦這個(gè)進(jìn)程 down 了,那么整個(gè) web 服務(wù)就 down 了
異步編程,callback 回調(diào)地獄
第一個(gè)缺點(diǎn)可以通過(guò)啟動(dòng)多個(gè)實(shí)例來(lái)實(shí)現(xiàn)CPU充分利用以及負(fù)載均衡,話(huà)說(shuō)這不是 K8s 的原生功能嗎。
第二個(gè)缺點(diǎn)更不是事兒,現(xiàn)在可以通過(guò) generator 、 promise 等來(lái)寫(xiě)同步代碼,爽的不要不要的。
下面我們主要從 Docker 和 Node.js 出發(fā)聊一下高質(zhì)量Node.js微服務(wù)的編寫(xiě)和部署:
Node.js 異步流程控制:generator 與 promise
Express、Koa 的異常處理
如何編寫(xiě) Dockerfile
微服務(wù)部署及 DevOps 集成
1. Node.js 異步流程控制:Generator 與 Promise
Node.js 的設(shè)計(jì)初衷為了性能而異步,現(xiàn)在已經(jīng)可以寫(xiě)同步的代碼了,你造嗎?
目前 Node.js 的 LTS 版本早就支持了 Generator , Promise 這兩個(gè)特性,也有許多優(yōu)秀的第三方庫(kù)bluebird、q 這樣的模塊支持的也非常好,性能甚至比原生的還好,可以用 bluebird 替換Node.js 原生的 Promise:
global.Promise = require('bluebird')
blurbird 的性能是 V8 里內(nèi)置的 Promise 3 倍左右(bluebird 的優(yōu)化方式見(jiàn) https://github.com/petkaantonov/bluebird/wiki/Optimization-killers )。
1.1 ES2015 Generator
generator 就像一個(gè)取號(hào)機(jī),你可以通過(guò)取一張票來(lái)向機(jī)器請(qǐng)求一個(gè)號(hào)碼。你接收了你的號(hào)碼,但是機(jī)器不會(huì)自動(dòng)為你提供下一個(gè)。
換句話(huà)說(shuō),取票機(jī)“暫停”直到有人請(qǐng)求另一個(gè)號(hào)碼( next() ),此時(shí)它才會(huì)向后運(yùn)行。下面我們看一個(gè)簡(jiǎn)單的示例:


從上面的代碼的輸出可以看出:
generator 函數(shù)的定義,是通過(guò) function *(){} 實(shí)現(xiàn)的
對(duì) generator 函數(shù)的調(diào)用返回的實(shí)際是一個(gè)遍歷器,隨后代碼通過(guò)使用遍歷器的 next() 方法來(lái)獲得函數(shù)的輸出
通過(guò)使用 yield 語(yǔ)句來(lái)中斷 generator 函數(shù)的運(yùn)行,并且可以返回一個(gè)中間結(jié)果
每次調(diào)用 next() 方法,generator 函數(shù)將執(zhí)行到下一個(gè) yield 語(yǔ)句或者是 return 語(yǔ)句。
下面我們就對(duì)上面代碼的每次next調(diào)用進(jìn)行一個(gè)詳細(xì)的解釋?zhuān)?/p>
第1次調(diào)用 next() 方法的時(shí)候,函數(shù)執(zhí)行到第一次循環(huán)的 yield index++ 語(yǔ)句停了下來(lái),并且返回了 0 這個(gè) value ,隨同 value 返回的 done 屬性表明 generator 函數(shù)的運(yùn)行還沒(méi)有結(jié)束
第2次調(diào)用 next() 方法的時(shí)候,函數(shù)執(zhí)行到第二循環(huán)的 yield index++ 語(yǔ)句停了下來(lái),并且返回了 1 這個(gè) value ,隨同 value 返回的 done 屬性表明 generator 函數(shù)的運(yùn)行還沒(méi)有結(jié)束
… …
第4次調(diào)用 next() 方法的時(shí)候,由于循環(huán)已經(jīng)結(jié)束了,所以函數(shù)調(diào)用立即返回,done 屬性表明 generator 函數(shù)已經(jīng)結(jié)束運(yùn)行, value 是 undefined 的,因?yàn)檫@次調(diào)用并沒(méi)有執(zhí)行任何語(yǔ)句
PS: 如果在 generator 函數(shù)內(nèi)部需要調(diào)用另外一個(gè) generator 函數(shù),那么對(duì)目標(biāo)函數(shù)的調(diào)用就需要使用 yield* 。