佳木斯湛栽影视文化发展公司

主頁 > 知識庫 > 美團酒店服務(wù)使用Node.js實現(xiàn)JavaScript全棧開發(fā)的經(jīng)驗分享

美團酒店服務(wù)使用Node.js實現(xiàn)JavaScript全棧開發(fā)的經(jīng)驗分享

熱門標(biāo)簽:服務(wù)外包 網(wǎng)站排名優(yōu)化 AI電銷 呼叫中心市場需求 百度競價排名 鐵路電話系統(tǒng) 地方門戶網(wǎng)站 Linux服務(wù)器

前后端分離的背景
“前后端分離”顯然已不是什么新鮮的話題,Zakas在2013年10月份就曾發(fā)表過一篇博客《Node.js and the new web front-end》討論Node背景下新時代的前端。毫無疑問,Node的出現(xiàn)給JavaScript語言帶來了新的生機,也使得前端開發(fā)者有了更多的可能性。

前后端分離表面上看似乎是一場“圈地運動”,但實質(zhì)上前后端分離是為了解決以往開發(fā)模式的一些詬病和痛點,同時也是迎合大的行業(yè)趨勢的明智之舉。我所在的美團酒店事業(yè)部去年7月份成立,新的業(yè)務(wù)、新的開發(fā)團隊,這一切使得我們的前后端分離推進的很徹底。截至目前,前端承載的所有業(yè)務(wù)和線上服務(wù)都是基于Node,生產(chǎn)環(huán)境已經(jīng)有近20臺服務(wù)器。如此帶來的全新前后端協(xié)作方式能夠讓專業(yè)的人做專業(yè)的事,無論前端后端都能較之前更專注在自己擅長的方面。

開發(fā)模式、技術(shù)棧

傳統(tǒng)的開發(fā)模式只需要專注在多終端的呈現(xiàn)上(瀏覽器、WebView)。而現(xiàn)在,瀏覽器只是前端的其中一環(huán),延伸出來的還有Node端的架構(gòu)、服務(wù)的運維能力等。上圖是我們目前的服務(wù)架構(gòu):Nginx位于Node服務(wù)之前,用做負載均衡、服務(wù)調(diào)度、Gzip壓縮等。之后便是Node服務(wù),我們通過PM2.5進行Node服務(wù)的Cluster部署和負載均衡(充分利用多核優(yōu)勢),同時作為輕量的中間層,負責(zé)路由、Controllers、Views、以及視圖的渲染,數(shù)據(jù)的獲取通過RESTful的API接口使用JSON格式交互。而后端則只需要負責(zé)業(yè)務(wù)邏輯、數(shù)據(jù)存儲、Models,并為前端提供JSON數(shù)據(jù)即可。

這樣改變之后,Node端可以進行首屏渲染等頁面加載方面的優(yōu)化,頁面渲染出來之后后續(xù)的交互、渲染都交由瀏覽器端的JavaScript代碼來完成,Node端的模板和瀏覽器端的模板大部分情況下都是相同的,所以我們需要考慮模板重用的問題。我們用Juicer替換了Express框架默認的模板引擎,Juicer是一個高效、輕量的前端 (Javascript) 模板引擎,效率和易用是它追求的目標(biāo)。除此之外,它還可以運行在 Node.js 環(huán)境中。通過Juicer,可以解決Node端和瀏覽器端的模板、Helper復(fù)用問題。而且基于前后端分離的工程架構(gòu)下,前端的代碼倉庫和后端隔離,前端獨立負責(zé)前端靜態(tài)資源文件、模板文件、Controller的維護和發(fā)布。

按照這樣重新定義前后端分工之后,前端可以做的事情較以往更多了,比如微信SDK的接入,因為微信JS SDK的使用需要在服務(wù)端進行簽名,所以現(xiàn)在我們不需要后端介入,前端完全可以獨立完成微信SDK的接入。此外像我們內(nèi)部和商家端SSO登錄邏輯的接入都完全由前端獨立完成。

技術(shù)選型的思考
對于前端的技術(shù)選型,我們始終保持理性、擁抱的態(tài)度。我們不會為了盲目求新而引入新的技術(shù),技術(shù)選型是針對我們目前大團隊的場景,為了解決以往協(xié)作過程中發(fā)現(xiàn)的一些痛點和不足。比如引入Node是為了改進前后端的工作流和效率,提升前后端的開發(fā)體驗。再比如目前我們項目中采用的Angular、React也是針對特定的業(yè)務(wù)場景,為了提升開發(fā)效率、增強代碼的可維護性。在我們的業(yè)務(wù)應(yīng)用中,面向商家、后臺的一些增刪改查系統(tǒng),Angular能夠顯著的提升開發(fā)效率,而React我們目前只是在面向用戶的PC端項目中在做一些嘗試和實踐。

帶來的挑戰(zhàn)
這樣的分工和架構(gòu)模式在給前端帶來更多可能性、更多便利的同時,也帶來了不小的挑戰(zhàn),相比傳統(tǒng)的前端角色而言,我們需要更多的關(guān)注線上服務(wù)的狀態(tài),進程內(nèi)存占用、CPU占用的詳細狀況,以及線上異常的監(jiān)控等。在我們擁抱Node的同時,對前端的能力要求是更上一階的。一段看起來正常的JS代碼,在瀏覽器端和在Node端兩種不同的運行環(huán)境下,就可能會暴露出一些以往關(guān)注不到的問題,比如內(nèi)存泄露:一個閉包或者一個用于緩存數(shù)據(jù)的對象,跟瀏覽器不同,Node對內(nèi)存泄露十分敏感,因為線上應(yīng)用有成千上萬甚至百萬計的流量,所以哪怕是一個字節(jié)的內(nèi)存泄露也會造成內(nèi)存堆積,從而導(dǎo)致垃圾回收過程耗時增加,應(yīng)用響應(yīng)緩慢,知道進程內(nèi)存溢出,應(yīng)用重啟或崩潰。

內(nèi)存泄露問題的定位
以下是我們在生產(chǎn)環(huán)境遭遇的一個案例:最近發(fā)現(xiàn)線上服務(wù)的內(nèi)存占用在服務(wù)重啟后會呈線性的增長,進程啟動18小時后,內(nèi)存就已經(jīng)占用接近1.6G左右,之后不久便會超過V8的內(nèi)存限制導(dǎo)致服務(wù)重啟。從圖中可以看出,在修復(fù)之前內(nèi)存使用情況一直在隨時間進行周期性的波動,波動的原因就是線上Node進程不斷的重啟導(dǎo)致的。

眾所周知,在V8的垃圾回收機制下,一般的代碼很少出現(xiàn)內(nèi)存泄露的情況,但是一旦出現(xiàn)內(nèi)存泄露往往較難排查。但造成內(nèi)存泄露的本質(zhì)原因只有一個,就是應(yīng)當(dāng)回收的對象沒有正常被回收,變成了老生代中的常駐對象。好在借助一些常見的排查工具可以幫助我們定位內(nèi)存泄露的具體原因:

- v8-profiler
- node-heapdump
- node-mtrace
- dtrace
- node-memwatch
這里我們使用node-heapdump來在模擬訪問的條件下生成堆內(nèi)存的snapshot,并通過Chrome的開發(fā)者調(diào)試工具對生成的snapshot文件進行分析。通過對比服務(wù)剛啟動時以及使用AB模擬并發(fā)訪問一段時間后的heapdump信息可以比較容易的定位到內(nèi)存泄露的問題點:是因為Juicer默認開啟了cache,會默認對編譯后的模板進行緩存,因此隨著訪問的增長和并發(fā)請求,cache對象會持續(xù)增長且不被回收,于是關(guān)閉cache并重新部署上線后線上恢復(fù)正常。

由于在瀏覽器的場景中運行時間短,且運行在用戶的機器上,即便內(nèi)存使用過多或者內(nèi)存泄露,也只會影響到用戶的終端。而且運行時間短,隨著進程的退出,內(nèi)存也會隨之釋放,幾乎沒有太多內(nèi)存管理的必要。但在Node端同樣的代碼就可能會暴露出問題。

線上服務(wù)的運維和監(jiān)控
前后端分離除了意味著代碼倉庫的分離、開發(fā)協(xié)作的分離之外,還涉及到線上服務(wù)的獨立發(fā)布和單獨部署。與之俱來的當(dāng)然是前端如何更好地對線上服務(wù)進行更細粒度的運維和監(jiān)控,我們的SA會更多的關(guān)注線上服務(wù)的整體指標(biāo)和可用性,而前端更希望能夠細粒度的了解線上Node的進程狀態(tài)以及異常情況。

PM2是一款優(yōu)秀且開源的Node進程管理工具。我們在PM2的基礎(chǔ)上做了一些改造,同時在云端部署了數(shù)據(jù)收集、數(shù)據(jù)實時獲取的服務(wù),從而形成了我們目前已經(jīng)應(yīng)用到線上的Node部署監(jiān)控平臺PM2.5,它可以將線上Node服務(wù)進程級別的細粒度信息聚合在云端進行處理和可視化展現(xiàn),PM2.5能夠監(jiān)控Node Server和進程的各項指標(biāo)狀態(tài),且可以配置報警并在各終端(Web、iPhone、Apple Watch)展示。

PM2.5的服務(wù)架構(gòu)

簡單介紹下PM2.5的服務(wù)架構(gòu):生產(chǎn)環(huán)境的Node服務(wù)通過PM2.5 CLI進行部署,PM2.5 CLI會持續(xù)不斷的將Node進程的各項數(shù)據(jù)上報到PM2.5的云端。云端收到上報的數(shù)據(jù)后會對原始數(shù)據(jù)進行處理并存儲至MongoDB。而Web端和iOS應(yīng)用都會通過WebSocket服務(wù)從服務(wù)端獲得實時的數(shù)據(jù)流,然后通過前端進行可視化的信息展示。

PM2.5的內(nèi)部實現(xiàn)

當(dāng)Node進程通過PM2.5啟動時,PM2.5 CLI會同云端服務(wù)進行握手,握手成功后才會源源不斷的進行數(shù)據(jù)的上報。上報時首先會將數(shù)據(jù)進行AES256加密,然后使用TCP通信將數(shù)據(jù)上報到服務(wù)器,這里用到了開源的Axon,云端服務(wù)器收到數(shù)據(jù)后會將數(shù)據(jù)入庫存儲到MongoDB中,同時會進行監(jiān)控報警的掃描,如果當(dāng)前數(shù)據(jù)符合用戶訂閱的監(jiān)控報警條件,則會通過云端的Push服務(wù)向iOS客戶端推送報警信息。云端同時運行WebSocket服務(wù),為多個終端(Web平臺、iOS應(yīng)用)提供實時數(shù)據(jù)的推送。

這里值得一提的是,PM2.5的客戶端是基于React-Native開發(fā),目前已經(jīng)提交Apple Store正在審核,審核通過后就可以從Apple Store中下載到了,客戶端提供了服務(wù)和進程基本指標(biāo)的查看,同時可以配合Web平臺的監(jiān)控報警設(shè)置實現(xiàn)7x24小時對服務(wù)的監(jiān)控。

其它監(jiān)控設(shè)施的接入
為了確保線上服務(wù)的可靠、穩(wěn)定,我們還接入了其它一些監(jiān)控設(shè)施和日志平臺,便于對線上的錯誤和訪問日志進行追蹤、分析和定位處理。

Zabbix
Zabbix是一種分布式系統(tǒng)監(jiān)控以及網(wǎng)絡(luò)監(jiān)控功能的企業(yè)級開源中間件,主要是被運維使用。Zabbix主要用于對服務(wù)進行心跳檢測、監(jiān)控服務(wù)的各項指標(biāo),當(dāng)某些指標(biāo)異?;虺^設(shè)定的閾值時進行短信、大象、郵件的報警。

Sentry 錯誤日志收集
Sentry是一個錯誤日志服務(wù)器,可以將程序錯誤的詳細情況集中捕獲。而且提供各種常見語言的SDK供業(yè)務(wù)接入。但Sentry在服務(wù)器端會有采樣,一般不能替代實時錯誤日志報警的監(jiān)控。

日志監(jiān)控平臺
日志監(jiān)控平臺是美團內(nèi)部的一個日志收集系統(tǒng),目前美團統(tǒng)一使用flume收集日志,flume具有接收scribe格式日志的能力,而日志監(jiān)控平臺也是以scibe格式日志來收集。日志在整個收集流程中以兩種形式存在,分別是原始日志和解析后的日志。目前我們使用日志監(jiān)控平臺主要用于將訪問日志的格式化數(shù)據(jù)上報,之后就可以通過Hive/Presto對訪問數(shù)據(jù)進行查詢了。

性能監(jiān)控平臺
性能監(jiān)控平臺為美團各平臺和產(chǎn)品線提供簡單易用的、端到端的性能數(shù)據(jù)服務(wù)。同時也提供了各種常見語言的SDK供業(yè)務(wù)接入。主要用于分析Node端的接口響應(yīng),以及瀏覽器端的頁面載入性能。

小結(jié)
以上是美團酒店前端在應(yīng)用Node進行全棧開發(fā)的過程中摸索前行的一些心得,也是引子,主要介紹了我們酒店事業(yè)部的前后端分離架構(gòu),線上內(nèi)存泄露問題的排查,和所使用的Node服務(wù)監(jiān)控平臺PM2.5,后續(xù)我會分享更多我們的Node方面的一些實踐,以及PM2.5監(jiān)控平臺的背后實現(xiàn),希望能對你有所幫助,也歡迎大家能夠參與進來共同交流前后端分離和Node相關(guān)的技術(shù)點。

標(biāo)簽:仙桃 崇左 黃山 湖南 衡水 湘潭 銅川 蘭州

巨人網(wǎng)絡(luò)通訊聲明:本文標(biāo)題《美團酒店服務(wù)使用Node.js實現(xiàn)JavaScript全棧開發(fā)的經(jīng)驗分享》,本文關(guān)鍵詞  ;如發(fā)現(xiàn)本文內(nèi)容存在版權(quán)問題,煩請?zhí)峁┫嚓P(guān)信息告之我們,我們將及時溝通與處理。本站內(nèi)容系統(tǒng)采集于網(wǎng)絡(luò),涉及言論、版權(quán)與本站無關(guān)。
  • 相關(guān)文章
  • 收縮
    • 微信客服
    • 微信二維碼
    • 電話咨詢

    • 400-1100-266
    绥江县| 且末县| 田东县| 苍溪县| 浙江省| 合山市| 西丰县| 江陵县| 宜兴市| 封开县| 女性| 阿拉善盟| 丹巴县| 高要市| 宝兴县| 休宁县| 宣武区| 肃宁县| 竹溪县| 清水县| 信宜市| 平远县| 双柏县| 武山县| 新巴尔虎左旗| 绥芬河市| 博爱县| 巴彦县| 昌邑市| 得荣县| 惠安县| 江山市| 易门县| 庄浪县| 砚山县| 乌鲁木齐市| 霞浦县| 湖南省| 清流县| 颍上县| 龙胜|