編者按:高可用架構分享及傳播在架構領域具有典型意義的文章,本文由桑世龍在高可用架構群分享。轉載請註明來自高可用架構公眾號「 ArchNotes 」。
桑世龍,天津空弦科技 CTO,開源項目 Moajs 作者,Node.js 技術傳道者。曾就職在新浪、網秦,曾做過前端、後端、數據分析、移動端負責人、做過首席架構師、技術總監,全棧技術實踐者。目前主要關注技術架構和團隊梯隊建設方向。
「JavaScript 是世界上使用最廣泛的語言,沒有之一,包括後端開發工程師也更愛使用 JavaScript。」 ——stackoverflow
Node.js 全球現狀雖然 Node.js 在國內沒有盛行,但據 StackOverflow 2016 年開發者調查,其中 Node.js 、全棧、JavaScript 相關的技術在多個領域(包括全棧、後端)都有排名領先。
(http://stackoverflow.com/research/developer-survey-2016)
後端分布
(http://stackoverflow.com/research/developer-survey-2016)
Node.js 與生俱來的 2 個特性:
event-driven
non-blocking I/O
以前總強調的異步特性,到今天異步已經不是明顯優勢。因此除了性能,其他都是病(不足)?
1、Callback hell 問題
目前已經很好的解決了。promise / generator / async 後面會講。
2、包管理
npm 已經是開源世界裡最大的包管理器了,模塊非常豐富(25.6萬 )。
Node.js』 package ecosystem, npm, is the largest ecosystem of open source libraries in the world.
以前我們總是喜歡拿異步說事兒,現在我們拿 Node.js 的強大的生態來炫耀。
為什麼選擇 Node.js?空弦科技做的是基於雲倉儲的 SaaS 服務,給中小賣家提供服務,核心系統是進銷存、訂單池、WMS。
先看一下我們的瓶頸在哪裡
人(天津不好招人)。Node.js 招不到,好多都是從 Java 轉的,前端也不好找,好多也是從 Java 轉的,我們相當於從 0 開始組建團隊
開發速度。創業公司 5 分鐘要造火箭,大家都懂。所以讓開發快速進入狀態,提高開發速度,對我們來說至關重要。
穩定。在沒有專業運維人員的情況下,如何保證系統可用、穩定。
於是就引出了我認為的 Node.js 好處
Node.js 給了我們足夠的選擇工具
甚至可以用各種編譯器 coffee、typescript、babel(es)等。對於從 0 開始的團隊來講,可以先面向過程、然後隨著團隊的成熟度,一點一點增加難度。
提供好的基礎和包管理工具
以上這些都做大型軟體的基礎,Node.js 在這方面做得非常好
特定場景的快速
很多人把 MEAN 組合(比如 mean.io)起來,這樣做的好處是如果熟悉,開發速度確實會非常快,但是難度太大,很少有人能搞的定。metetor 模糊了服務端和客戶端,是同構的典型應用,對於實時場景是非常高效的。這種東西都算特定場景的快速,一般不敢輕易上,調優難度非常大,如果有人能 cover 的住,在初期是非常高效的。
總結需求:可以簡單,可以難;可以快、也可以慢;可以開發大型軟體
如果以上不滿足咋辦?這時就需要架構平衡了。
架構平衡在架構中各自做各自合適的事兒就好,我們很坦然的面對 Node.js 的優點和缺點,做好架構平衡。
1、在語言層面可以做,那語言層面做
已有大量 npm 上的模塊 ( 目前在 25.6 萬個以上 )
自己造輪子 ( 站在海量包上 簡單語法 npm = 快速 )
使用 Node.js 裡的 (nan https://github.com/nodejs/nan)自己包裝 C/C++ 輪子
從上面看,絕大部分需求都可以滿足了
2、如果語言層面搞不定,那就架構層面做
業務邊界、模塊拆分、面向服務
MQ、RPC、cache
運維、監控、自動化
稍微解釋一下,首先,架構與 Node.js 沒直接關係。其次,架構師常用的東東有足夠的 Node.js 模塊支持,比如 MQ,像 Rabbitmq 有比較好的 Node 模塊支持,RPC 裡 Thrift、Grpc、Tchannel 支持的都不錯,我們使用的 senecajs,Redis,ioredis 等軟體,後面做 HA 都是一樣的。
3、如果架構層面也解決不了……
合適的場景用合適的東西。有很多東西是 Node.js 不擅長,又不在架構範疇裡的,咋辦?如實在不夠,Java 補(嚴格點,應該叫其他語言補)
但凡是 Java 或其他語言裡比較成熟的庫,可以作為獨立服務使用的,都可以做 Node.js 的支持。避免過多的時間用在造輪子上,影響開發進度。
4、Node.js 優劣分析
Node.js 的 Web 開發框架 Express、Koa 等,簡單,小巧,精緻,缺點是集成度不夠,目前已有的 MEAN 或 yo 或 sails 等總有某種方面的不滿意
團隊 Node.js 使用現狀選擇 Node.js 我們需要做的包括:固化項目結構;限定 ORM;自定義腳手架。
由於 Node.js 已經提供以下特性,因此你可以在 30 分鐘完成一個腳手架。
我們用Node.js做什麼?
API 服務
前端(moa-frontend)
SDK(OAuth Provider)
輔助開發 cli 工具
目前進度
使用 0.10.38,開發 Moajs 框架,Express / MongoDB
pm2 部署, 前後端分離,阿里雲的 slb 負載,alinode 監控
moa-api, moa-frontend, moa-h5 (未能用)
使用 Redis 緩存,Rabbitmq,senaca 作為 RPC
一些正在建設的方面
打算進行技術棧更新,包括Nodejs 4.x(預計今年 6 月份;Koa(generator/co);es6/es7 ( babel )。
4.x 在內存和性能上都有非常大的提升,新的語言特性上,異步流程和語法上都需要學習,故不急於升級,待人才梯隊完善。
目前的做法是小步快走,一次只上一樣新技術;另外形成梯隊,即可準備上新東西;善用 npm,實現 3 化:模塊化、最小化、服務化
為什麼選擇 MEAN 架構MEAN 架構
MEAN 是目前最潮的全棧 JavaScript 架構。MEAN 是一個 JavaScript 平臺的現代 Web 開發框架總稱,它是 MongoDB Express AngularJS Node.js 四個框架的第一個字母組合。它與傳統 LAMP 一樣是一種全套開發工具的簡稱。
從我的角度看
MySQL 用 MongoDB 替換,NoSQL 裡最像 rdbms 的,從開發和性能都是有優勢的(參看老畢在高可用架構群分享文章:MongoDB 2015回顧:全新裡程碑式的WiredTiger存儲引擎 )。
Angular 的出現是一個時代,IoC,雙向綁定,指令等都曾讓無數熱血沸騰。
Node.js 提供了完全的生態和工具鏈,你要的它基本都有,感謝 npm,早些年 Node.js 的性能甩 php 幾條街的。
Express 作為 Node.js 示範項目,它非常精簡,是比較合適的 Web 框架
我為什麼選擇 MEAN 架構?
成熟、穩定,簡單,有問題我們能 cover 住,所以我們選了 Node.js。
把握趨勢,以後 Node.js 的前景非常看好,尤其前後端統一,全棧方向。
在架構上可以屏蔽可能風險,不孤注一擲,也不會一葉障目,合理的使用其他語言,只要每個功能都以服務出現,至於它是什麼語言寫的,並不重要。
招人成本的性價比相對較高,技術棧新,容易吸引人才。
最重要的一件事兒,是當有問題的時候,有人能 cover 住,在創業初期這是最最重要的事兒。
Node.js最新Web技術棧
https://cnodejs.org/topic/55651bf07d4c64752effb4b1
Node.js 異步流程異步流程控制
JavaScript 流程控制的演進過程,分以下 5 部分:
目前所有版本都支持 Promise / a+ 規範
目前 Node.js 4.0 支持 Generators/ yield
目前不支持 es7 裡的 Async/await,但可以通過 babel 實現
整體來說,對異步流程控制解決的還是比較好的。
Node.js 最新技術棧之 Promise 篇
https://cnodejs.org/topic/560dbc826a1ed28204a1e7de
快速開發實踐業務邊界優化
創業公司有很多可變性,要做的系統也無數,如何保證業務系統的邊界是非常難的,我們其實走了很多彎路。
靜態 API 理論
當需求和 UE 定下來之後,就開始編寫靜態 API,這樣 APP、H5、前端就可以使用靜態 API 完成功能,而後端也可以以靜態 API 為標準來實現,整體效率還是比較高的。
API 的最佳實踐
http://developer.github.com/v3/ (嚴格的restful)
微博 API (可讀性強,相對比較傳統),我們採用的微博 API 類似的,約定結構也是類似的。
res.api is an express middleware for render json api , it convention over api format like this :
{
data : {},
status: {
code : x,
msg : 『some message』
}
}
客戶端 API 開發總結
https://cnodejs.org/topic/552b3b9382388cec50cf6d95
約定結構
和 Java 開發裡的目錄結構類似,該分層的分層,適當的按照 Express/Koa 增加中間件、路由等目錄,便於開發。
使用 npm 模塊化
編寫生成器
在 Web 開發裡,寫了 Moajs 生成器,類似於 rails
moag order name:string password:string
其他開發,如 iOS 開發裡模型校驗非常煩,於是寫了一個 json2objc 命令行工具,讀取 json,生成 oc 代碼,可以節省不少時間
Moajs 框架和前後端分離
前端 (moa-frontend https://github.com/moajs/moa-frontend)
public下面的採用 Nginx 做反向代理
其他的採用 Express Jade 精簡代碼(ajax與後端交互)
後端(moa-api https://github.com/moajs/moa-api)
moa 生成器,即上面講的生成器 scaffold。
moa-frontend 技術棧:Express / Jade / bootstrap、bootstrap-table / jQuery / gulp / Nginx
moa-api 技術棧:
base2(mirco kernel) https://github.com/base-n/base2-core
mongoose https://github.com/Automattic/mongoose
bluebird https://github.com/petkaantonov/bluebird
res.api https://github.com/moajs/res.api
Features
自動加載路由,自帶用戶管理,使用 jsonwebtoken 做用戶鑑權
支持 MongoDB 配置,集成 mongoosedao,快速寫 CRUD 等 dao 接口
支持 migrate 測試,Mocha 測試
默認集成 res.api,便於寫接口
集成 supervisor,代碼變動,自動重載,gulp 自動監控文件變動,跑測試
gulp routes 生成路由說明
使用 log4js 記錄日誌
從開發效果上看,還是非常快的,非常穩定的。
Moajs框架演進之路
https://cnodejs.org/topic/567e2388aacb6923221de469
全棧 or 全爛 ?Node.js 相關工具
grunt/gulp/fis/webpack
bower/spm/npm
tdd/bdd cucumber/mocha
standard
babel/typescript/coffee
前端開發四階段
Vuejs 綜合 Angular 和 React 的優點,應該是下一個流行趨勢。
Hybrid 開發
Hybrid 混搭開發是指使用 H5 技術開發的跨瀏覽器應用,並最終可以將 html5/js/css 等打包成 apk 和 ipa 包的開發方式。它也可以上傳到應用商店,提供給行動裝置進行安裝。它最大的好處是通過 H5 開發一次,就可以在多個平臺上安裝。
未來將會是 JavaScript 一統天下(Node.js 做後端,傳統 Web 和 H5 使用 Javasctipt,更智能的工具如 gulp,更簡單的寫法如 coffeescript 等)。H5 大行其道(網速變快,硬體內存增長)。
跨平臺
C/S 架構到 B/S 架構,這個大部分都清楚,不多說。
移動端加殼,在瀏覽器上做文章,把頁面生成各個移動端的 app 文件。
PC 端加殼,一樣是延續瀏覽器做文章,不過這次把頁面生成各個 PC 平臺的可執行文件。
目前比較火的編輯器都是基於 Electron 打包:
組件化:統一用法
React 的出現影響最大的是 JSX 的出現,解決了長久以來組件化的問題:
單純的 React 只是 view 層面的,還不足以應用,於是又有 Redux。核心概念:Actions、Reducers 和 Store,簡單點說就是狀態控制,然後再結合打包加殼,變成 app 或可執行文件。iOS、Android 上用 Cordova,PC 上使用 Electron。
總結
這部分其實組件化了前端,那麼能否用這樣的思想來組件化移動端呢?
react-native
https://github.com/facebook/react-native)
A framework for building native apps with React.
http://facebook.github.io/react-native/
簡單點說,就是用 React 的語法來組件化 iOS 或 Android SDK。它們都在告訴我們,你們以後就玩這些組件就好了,你不需要知道複雜的 SDK 是什麼。
當下流行玩法
Medis is a beautiful, easy-to-use Redis management application built on the modern web with Electron, React, and Redux. It’s powered by many awesome Node.js modules, especially ioredis and ssh2.
https://github.com/luin/medis
技術點
使用 Node.js 模塊
使用 Webpack 構建
使用 React(視圖) Redux(控制邏輯)
使用 Electron 加殼打包
親,你看到未來了麼?
如何全棧?講了 Node 工具,前端 4 階段,hybrid,各種跨平臺,目前就是為了介紹 Node 全棧的各種可能,下面講一下如何能做到 Node 全棧?
全棧核心,後端不會的 UI(界面相關),前端不會的 DB(業務相關),只要打通這 2 個要點,其他就比較容易了。
1、從後端轉
做後端的人對資料庫是比較熟悉,無論 MongoDB,還是 Mysql、Postgres,對前端理解比較弱,會基本的Html,Css,模板引擎等比較熟悉。
4 階段循序漸進,build 與工具齊飛,前端開發 4 階段,我的感覺是按照順序,循序漸進。
Html / Css / JavaScript(基礎)
jQuery、jQuery-ui,Extjs(曾經流行)
Backbone,Angularjs(當前流行)、Vuejs
React(未來趨勢)、Vuejs
Vuejs 綜合 Angular 和 React 的優點,應該是下一個流行趨勢
2、從前端轉
從前端往後端轉,API 接口非常容易學會,像 Express、Koa 這類框架大部分人一周就能學會,最難的是對 DB、ER 模型的理解,說直白點,還是業務需求落地的理解
我們來想想一般的前端有什麼技能?
那麼他們如果想在前端領域做的更深有哪些難點呢?
基礎:OO,設計模式,命令,Shell,構建等
編程思想上的理解(MVC、IoC,規約等)
區分概念
外圍驗收,如 H5 和 hybird 等
追趕趨勢,如何學習新東西
以上皆是痛點。所以比較好的辦法:
玩轉 npm、gulp 這樣的前端工具類(此時還是前端)
使用 Node 做前後端分離(此時還是前端)
Express、Koa 這類框架
Jade、ejs 等模板引擎
Nginx
玩轉【後端】異步流程處理 promise / es6 的 ( generator | yield) / es7 ( async|await )
玩轉【後端】MongoDB、Mysql 對應的 Node 模塊
從我們的經驗看,這樣是比較靠譜的。https://github.com/moajs/moa-frontend 就是最簡單前後端分離,裡面沒有任何和 DB 相關。
技術棧
一般的前端都非常容易學會,基本 2 周就已經非常熟練了,我的計劃是半年後,讓他們接觸【異步流程處理】和【資料庫】相關內容,學習後端代碼,就可以全棧了
3、從移動端轉
移動端分:native 原生開發,hybrid 混搭式開發。原生開發就是 iOS 用 oc/swift,Android 用 Java 或 Scala 等,就算偶爾嵌入 webview,能玩 JavaScript 的機會也非常好少。所以移動端轉全棧的方法,最好是從 cordova(以前叫 phonegap)開始做 hybrid開發。只要關注 www 目錄裡的 H5 即可,比較簡單。如果 H5 不足以完成的情況下,可以編寫 cordova 插件,即通過插件讓 JavaScript 調用原生s dk 裡功能。cordova 的 cli 可以通過 npm 安裝,學習 npm 的好方法,學習 gulp 構建工具。
只要入了 H5 的坑,其實就非常好辦了。
然後 H5、Zeptojs、iScroll、fastclick 等
然後微信常用的,如weui、vux(vue weui)、jmui(react weui)
然後可以玩點框架,比如 jQuery mobile,Sencha touch
然後可以玩點高級貨,ionicframework(基於Angularjs、cordova)
然後前端 4 階段,依次打怪升級
然後 Node.js
這個基本上是我走的路,從 2010 年寫 IOS、做 phonegap(當時是0.9.3)一路走到現在的總結吧。
展望 Node.js 技術未來Node.js 可能是一場春夢,
也可能一個變革機遇;
我們更相信它是變革機遇,
請拭目以待!
附:Node.js 2015 發展歷史Q1 第一季度
Q2 第二季度
npm 支持私有模塊
Node 項目領導人 TJ Fontaine 逐步解除核心身份並離開 Joyent 公司
A changing of the guard in Nodeland
Node.js 和 IO.js 在 Node 基金會下合併情況
Q3 第三季度
Q4 第四季度
Node v4.2.0,首個長期支持版本(LTS)
Apigee,RisingStack 和 Yahoo 加入 Node.js 基金會
Node Interactive
The first annual Node.js conference by the Node.js Foundation
版本帝?去年從 v0.10.35 開始
2015-01-14 發布了 v1.0.0 版本(IO.js)
2.x(IO.js)
3.x(IO.js)
2015 年 09 月 Node.js 基金會已發布 Node.js v4.0 版 與 IO.js 合併後的第一個版本
2015 年 10 月 Node.js v4.2.0 將是首個 LTS 長期支持版本
年底發布到 4.2.4 && 5.4.0
目前(2016 年 3 月 20 日)的 2 個版本
v4.4.0 LTS(長期支持版本)
v5.9.0 Stable(穩定版本)
整體來說趨於穩定。
(參考連結:http://i5ting.github.io/history-of-node-js/)
Node.js 企業級大事記Node.js 的企業級大事兒記
2014年 nearform (NODE.JS 為什麼會成為企業中的首選技術?http://www.nearform.com/nodecrunch/node-js-becoming-go-technology-enterprise/)
2015年 IBM (收購 StrongLoop,拓展雲服務業務 http://www-03.ibm.com/press/us/en/pressrelease/47577.wss)
Node.js 基金會的創始成員包括 Joyent、IBM、Paypal、微軟、Fidelity 和 Linux 基金會。
對於企業級開發,Node.js 是足夠的,無論從性能、安全、穩定性等都是非常棒的。
空弦科技做的是基於雲倉儲的 SaaS 服務,給中小賣家提供服務,核心系統是進銷存、訂單池、WMS。目前來看不存在任何問題,
es && babel
2015 年 ECMA 國際大會宣布正式批准 ECMA-262 第 6 版,亦即 ECMAScript 2015(曾用名:ECMAScript 6、ES6)的語言規範。
babel (http://babeljs.io/)作為 es 編譯器,已經大量開始使用了,模塊做的非常棒,還有人用babel寫其他語言編譯器。Node.js 裡在 0.12 之後才增加 es6 特性,es7 的目前還不支持。所以在 Node.js 裡使用 es 裡比較高級的特性,是需要 babel 去編譯處理的。這是 Node 追逐的標準。
2016 年 01 月 22 日,(微軟請求 Node.js 支持 ChakraCore https://github.com/nodejs/node/pull/4765)
未來 Node.js 不只是基於 chrome v8 內核,它還可以支持更多其他瀏覽器內核,對生態、效率提升等非常有好處。
蔡偉小兄弟的查克拉 benchmark 的對比(https://github.com/DavidCai1993/ES6-benchmark)基本結論是 V8 ES5 > 查克拉 ES6 > 查克拉 ES5 > V8 ES6
Q & A1. 在全棧的語言選擇上,除了 Node.js,是否還考慮過其他語言?
桑世龍:有的,未來 swift 和 Lua 是有可能的。swift 的語法和性能上有很大優勢,Lua 在 openresty 的推動下也有機會,不過沒有 swift 大。像 WebAssembly 之類的就不太看好了。
2. 請教桑老師:剛才你說的並發開發流程中靜態 API 指的是 API 文檔?如果是的話誰負責編寫?你們目前已經是一個人分模塊從前端寫到後端了嗎?
桑世龍:目前沒做到文檔即靜態 API,所以目前是直接提供 json 和部分(json-server https://github.com/typicode/json-server),負責是後端開發的 leader 在寫,他的進度會比正常開發要早一周左右。目前不是一個人寫所有的前後端,團隊成立不久,天津 Node.js 會的不多,所以還是前後端分離。但是通過 moa-frontend 可以讓前端了解 Express 等後端知識,適當的時候會給予機會,前端轉後端。
3. 貴司在開發協作中提到了靜態 API,請問是不是有什麼比較好的工具可以推薦?
桑世龍:Node.js 裡(json-server https://github.com/typicode/json-server) 比較好
我其實很想圍繞靜態 API,寫各種請求的生成器,只要 API 出來,文檔和各平臺的 HTTP 請求代碼就生成出來,同時可以對正式 API 進行壓測,可惜目前還沒精力寫。
4. 做 hybrid app 在移動端會遇到性能問題吧,有沒有什麼優化經驗可以分享?
桑世龍:足夠輕量級,少選大框架,做好前端該有的優化。注意 touch 和 click 的區別,比如 fastclick 或 Zeptojs 的 tap 手勢。Chrome profile(css3動畫)。使用 weinre 真機測試。參考:(我的 H5 實踐 http://mp.weixin.qq.com/s?__biz=MzAxMTU0NTc4Nw==&mid=222892082&idx=1&sn=ba1cdb42b43fbec08e4328c5080774e5#rd)。
5. 如果都全棧了,當前你們團隊是如何分工的?
桑世龍:我們團隊還是傾向於分工專業化,各個服務粒度非常小,便於輪崗、還有就是可以為以後像 Google 那樣代碼開放做準備。但是有很多情況下,是需要有機動的突擊隊的(尤其是創業時期),這樣可以隨便組合,另外就是全棧為 remote 提供了更多便利性。
6. H5 在手機上用 iScroll 坑比較多啊 尤其三星打開硬體加速的時候 render 頁面,桑老師怎麼看?
桑世龍:可以嘗試一下淘寶系的 H5 虛擬化,鬼道曾經在 as 大會上講過的,我們目前還沒能力做這麼深層次的優化。
7. Node.js 做業務金額計算的金額性能和精度夠嗎
桑世龍:你問的不是 Node.js,而是 Node.js 要操作的資料庫。耗性能的計算可以在架構上平衡的,如果可以延時,MQ 就可以了。如果是非延時情況,可以採用其他語言編寫對應服務,沒必要非要一定要 Node.js。我們目前的場景,還沒有在計算遇到瓶頸。
8. 關於 API 返回格式那裡,對於 status 為什麼不打平了把 code 和 message 放出來?這麼設定有什麼好處麼?
桑世龍:語義上更加清晰。整個返回的 json 就只有 data 和 status,如果 status.code != 0,我取 msg 就好了,如果等於 0,處理 data 數據這種設計不見得多好,不過結構清晰,對於開發者來說,是比較容易接受的。
最後桑老師還要補充最重要的一句,大家別忘了互相轉告。
空弦科技招聘全棧相關架構師、高級程式設計師,語言不限,坐標天津,郵箱:sang@aircos.com
本文策劃李慶豐,編輯王傑,審校 Tim Yang,想討論更多 NodeJS 全棧開發,請關注公眾號獲取進群機會。轉載請註明來自高可用架構「ArchNotes」微信公眾號及包含以下二維碼。
高可用架構
改變網際網路的構建方式
長按二維碼 訂閱「高可用架構」公眾號