童 敏,張文盛,錢立三
?
基于Node.js的高性能站群系統(tǒng)設(shè)計(jì)與實(shí)現(xiàn)
童 敏,張文盛,錢立三
(安徽廣播電視大學(xué) 信息技術(shù)與網(wǎng)絡(luò)管理中心,安徽 合肥 230022)
站群系統(tǒng)是統(tǒng)一數(shù)據(jù)、標(biāo)準(zhǔn)和管理的建站模式,可以輕松建立多個(gè)站點(diǎn),并在各站點(diǎn)間共享信息,從而顯著減少信息孤島現(xiàn)象。Node.js是javascript語言在服務(wù)器端的實(shí)現(xiàn),采用V8高性能引擎,結(jié)合語言本身獨(dú)特的異步特性,可以構(gòu)建高性能網(wǎng)站。提出一種基于Node.js的網(wǎng)站架構(gòu),采用MVC、Widgets和SOA進(jìn)行解耦,增加并行性,提高系統(tǒng)性能。在此架構(gòu)上,設(shè)計(jì)和實(shí)現(xiàn)一套高性能站群系統(tǒng),該系統(tǒng)結(jié)構(gòu)清晰簡單,可擴(kuò)展性好,穩(wěn)定性高,性能優(yōu)越,適合高校使用。
Node.js;站群系統(tǒng);MVC;Widgets;SOA
隨著信息技術(shù)的不斷發(fā)展,技術(shù)驅(qū)動和需求驅(qū)動讓我們在許多領(lǐng)域開發(fā)軟件,隨之軟件之間的關(guān)聯(lián)又成為新的問題,形成信息孤島。信息孤島是指信息系統(tǒng)之間相互不關(guān)聯(lián),信息不能共享,數(shù)據(jù)不能交換,以及信息與業(yè)務(wù)流程和應(yīng)用相互脫節(jié)。信息孤島是信息化進(jìn)程中的必然產(chǎn)物。人們嘗試著從數(shù)據(jù)庫、集成總線的方向努力把各個(gè)信息系統(tǒng)進(jìn)行關(guān)聯(lián),但是總是不能如愿,孤島依然普遍存在。具體到高校,由于每個(gè)部門和院系普遍都有網(wǎng)站,各個(gè)網(wǎng)站之間互相獨(dú)立,自成一體,因此高校網(wǎng)站信息孤島現(xiàn)象最為典型。網(wǎng)站信息孤島有如下特點(diǎn):技術(shù)架構(gòu)千差萬別,界面風(fēng)格各顯神通,安全防護(hù)形同虛設(shè),穩(wěn)定性無法保證,性能參差不齊,管理隨意分散。
針對網(wǎng)站信息孤島問題,目前通用的解決方案是采用站群系統(tǒng)。站群系統(tǒng)是指在統(tǒng)一規(guī)劃、統(tǒng)一標(biāo)準(zhǔn)和統(tǒng)一技術(shù)構(gòu)架基礎(chǔ)之上,實(shí)現(xiàn)分級管理、分級維護(hù)、耦合程度高和基于特定權(quán)限共享呈送信息的網(wǎng)站集合[1]。站群系統(tǒng)中的所有站點(diǎn)遵從相對一致的網(wǎng)站運(yùn)行和服務(wù)規(guī)范,能夠互聯(lián)互通,實(shí)行集群化管理。站群系統(tǒng)并不是多個(gè)網(wǎng)站的簡單堆砌,站群系統(tǒng)的特點(diǎn)是統(tǒng)一建設(shè)、分級管理、信息共享和單點(diǎn)登錄,此外站群系統(tǒng)還具有界面風(fēng)格一致,安全防護(hù)可控,運(yùn)行穩(wěn)定,性能卓越,輕松建站,建設(shè)成本低等諸多優(yōu)點(diǎn)[2]。
站群系統(tǒng)已經(jīng)有很多成熟產(chǎn)品面世,功能豐富,可以定制。各高校正在不遺余力進(jìn)采購和建設(shè)站群系統(tǒng),逐步將分散的網(wǎng)站遷移到站群系統(tǒng)中。站群系統(tǒng)采用的技術(shù)架構(gòu)主要有PHP,ASP.net和JSP,相比較而言,Node.js算后起之秀[3]。Node.js是javascript語言在服務(wù)器端的實(shí)現(xiàn),解決了javascript只能應(yīng)用在客戶端的缺點(diǎn)。Node.js采用Chrome V8高性能引擎,能夠?qū)⒛_本直接編譯成機(jī)器碼運(yùn)行,性能優(yōu)異。Node.js 使用了一個(gè)事件驅(qū)動、非阻塞式I/O的模型,使其輕量又高效[4]。javascript是異步編程語言,單進(jìn)程就可以承載大負(fù)荷處理任務(wù)。因此Node.js可以構(gòu)建高性能網(wǎng)站,新的應(yīng)用層出不窮[5]。本文采用Node.js構(gòu)建高性能網(wǎng)站群系統(tǒng),探討設(shè)計(jì)和實(shí)現(xiàn)問題。
本架構(gòu)采用MVC設(shè)計(jì)。MVC的全名是Model View Controller,是模型(model)-視圖(view)-控制器(controller)的縮寫,是一種軟件設(shè)計(jì)規(guī)范[6]。它是用一種業(yè)務(wù)邏輯、數(shù)據(jù)與界面顯示分離的方法來組織代碼,將眾多的業(yè)務(wù)邏輯聚集到一個(gè)部件里面,在需要改進(jìn)和個(gè)性化定制界面及用戶交互的同時(shí),不需要重新編寫業(yè)務(wù)邏輯,達(dá)到減少編碼的時(shí)間[7]。
本架構(gòu)還采用SOA(Service-Oriented Architecture,面向服務(wù)架構(gòu))技術(shù)。SOA是一種使用松耦合的黑盒子服務(wù)構(gòu)建業(yè)務(wù)應(yīng)用的體系架構(gòu),這些服務(wù)可以通過編排連接在一起以實(shí)現(xiàn)特定的功能。SOA具有更易維護(hù)、更高的可用性和更好的伸縮性等優(yōu)點(diǎn)。
本架構(gòu)包括兩層:前端和后端。前端和客戶端直接交互,提供業(yè)務(wù)邏輯處理和html靜態(tài)資源訪問,采用Node.js實(shí)現(xiàn)。后端向前端提供數(shù)據(jù)存儲和檢索服務(wù),采用ASP.net+SQL server 2005實(shí)現(xiàn)。系統(tǒng)結(jié)構(gòu)如圖1所示。
圖1中,服務(wù)器端使用兩臺服務(wù)器,一臺負(fù)責(zé)前端功能,一臺負(fù)責(zé)后端功能。前端服務(wù)器安裝Linux CentOS 7.2操作系統(tǒng),運(yùn)行Node.js。后端服務(wù)器安裝Winows 2008 R2操作系統(tǒng),運(yùn)行II7(ASP.net)和SQL server 2005。客戶端使用瀏覽器訪問Node.js。Node.js接受用戶請求,執(zhí)行路由,定位視圖模版,向后端請求數(shù)據(jù),處理數(shù)據(jù),渲染模版,返回最終結(jié)果給客戶端。ASP.net提供Web接口管理數(shù)據(jù),數(shù)據(jù)存儲在SQL server 2005數(shù)據(jù)庫中。Node.js訪問Web接口獲取數(shù)據(jù),Web接口使用JSON(JavaScript Object Notation)返回操作結(jié)果。本架構(gòu)中,前端負(fù)責(zé)View和Controller,后端負(fù)責(zé)Model。
圖1 Node.js網(wǎng)站系統(tǒng)結(jié)構(gòu)
Node.js采用Express框架提供前端服務(wù)。Express 是一個(gè)簡潔而靈活的Node.js Web應(yīng)用框架, 提供了一系列強(qiáng)大特性幫助創(chuàng)建各種Web應(yīng)用和豐富的HTTP工具。使用 Express可以快速地搭建一個(gè)完整功能的網(wǎng)站。Express框架核心特性有:可以設(shè)置中間件來響應(yīng)HTTP請求,定義路由表用于執(zhí)行不同的HTTP請求動作,可以通過向模板傳遞參數(shù)來動態(tài)渲染HTML頁面。
本架構(gòu)設(shè)計(jì)小部件(Widgets)技術(shù),使用中間件方式處理Widgets。Widgets是在視圖中使用的可重用單元,使用面向?qū)ο蠓绞絼?chuàng)建復(fù)雜和可配置用戶界面單元。傳統(tǒng)的MVC和基于Widgets的MVC工作原理比較如圖2所示。
傳統(tǒng)MVC中一個(gè)頁面對應(yīng)一個(gè)Controller和一個(gè)View文件,Controller從多個(gè)Model獲取數(shù)據(jù),然后渲染View文件,并輸出最終結(jié)果。基于Widgets的MVC,一個(gè)頁面可以對應(yīng)多個(gè)皮膚(Skin)文件。不同的Skin有不同的布局和風(fēng)格,可以根據(jù)用戶喜好選擇,使網(wǎng)站表現(xiàn)豐富多彩[8]。Skin將不同的功能區(qū)域封裝成不同的Widget。Widget只有一個(gè)Controller和一個(gè)View,通常只調(diào)用一個(gè)Model,功能單一,方便重用。
圖2 傳統(tǒng)MVC和基于Widgets的MVC比較
一個(gè)Skin通常有多個(gè)Widget占位符,一個(gè)Widget占位符代表一個(gè)Widget。Widgets中間件采用并行方法進(jìn)行處理,同時(shí)處理所有Widget,等到所有Widget處理完成,再將Skin中的Widget占位符全部替換成對應(yīng)結(jié)果,形成最終頁面。
后端負(fù)責(zé)業(yè)務(wù)邏輯和數(shù)據(jù)存儲,以Web接口對方式對外提供服務(wù),采用JSON標(biāo)準(zhǔn)交換數(shù)據(jù)。JSON是一種輕量級的數(shù)據(jù)交換格式,易于閱讀和編寫,同時(shí)也易于機(jī)器解析和生成。本架構(gòu)定義的JSON格式如下:
{
code=1,//成功代碼
msg=’錯(cuò)誤消息’,//出錯(cuò)消息,可選
data1=’’,//數(shù)據(jù)部分
data2=’’,//更多的數(shù)據(jù)
}
其中code指示操作是否成功,1表示成功,0表示失敗。msg指出錯(cuò)誤信息,code為1時(shí)可選,code為0時(shí)必須有。根據(jù)具體業(yè)務(wù)的不同,后面附上相應(yīng)的業(yè)務(wù)數(shù)據(jù)。
現(xiàn)代網(wǎng)站通常采用cookie+session的方式執(zhí)行狀態(tài)控制,包括記錄用戶登錄狀態(tài)和對用戶操作進(jìn)行權(quán)限檢查[9]。本架構(gòu)中,狀態(tài)控制主要由后端處理,包括session的生成、存儲和檢索,并使用cookie跟蹤session ID。前端負(fù)責(zé)在客戶端和后端之前傳遞cookie。當(dāng)調(diào)用后端服務(wù)返回cookie信息時(shí),前端將cookie再傳給瀏覽器。當(dāng)瀏覽器的請求中包含cookie時(shí),前端就將cookie傳給后端服務(wù)。
基于node.js的站群系統(tǒng)結(jié)構(gòu)如圖3所示。
圖3 站群系統(tǒng)結(jié)構(gòu)
圖3中,站群系統(tǒng)由一個(gè)主站、多個(gè)子站和一個(gè)管理后臺站點(diǎn)組成。在結(jié)構(gòu)上各個(gè)站點(diǎn)是平行關(guān)系。在邏輯上,主站是所有子站和管理后臺的入口,子站可以推送信息到主站,管理后臺執(zhí)行賬戶管理,配置主站和子站,發(fā)布和推送信息。
站群系統(tǒng)通常只配置一個(gè)域名,需要為各個(gè)站點(diǎn)規(guī)劃URL。本系統(tǒng)中,在站點(diǎn)名稱和URL之間建立直接映射。例如主站命名為portal,則訪問http://域名/portal/就是訪問主站。管理后臺命名為manger。根據(jù)規(guī)則,主站URL是http://域名/portal,而不是 http://域名/。因此當(dāng)訪問http://域名/時(shí),需要重定向到主站URL。
每個(gè)站點(diǎn)都需要?jiǎng)?chuàng)建一個(gè)路由文件,建立站點(diǎn)下所有頁面到各自Skin的映射規(guī)則。例如訪問http://域名/portal/search,實(shí)際上訪問的皮膚文件是/var/wwwroot/themes/portal/skins/search.html。路由文件以站點(diǎn)名稱命名,例如portal.js。
本系統(tǒng)中,為了減少表的數(shù)量,將所有的展示類信息歸一化存儲到單個(gè)表中,命名為文章表,可以存儲多條信息如新聞和公告,也可以存儲單條信息如學(xué)校簡介、辦公電話和校歷等。除此之外還有站點(diǎn)表,欄目表,用戶表和權(quán)限表。ER圖如圖4所示。
圖4 ER圖
圖4中,站點(diǎn)表存儲站點(diǎn)信息,一個(gè)站點(diǎn)表示為一條記錄。一個(gè)站點(diǎn)可有擁有多個(gè)欄目。一個(gè)欄目可以擁有多個(gè)文章。一個(gè)用戶有權(quán)維護(hù)多個(gè)欄目,一個(gè)欄目也可以有多個(gè)用戶維護(hù),是多對多關(guān)系。
站群系統(tǒng)維護(hù)多個(gè)站點(diǎn),更容易遭受攻擊,因此安全設(shè)計(jì)更要仔細(xì)[10]。本系統(tǒng)主要防范注入攻擊,跨站腳本攻擊,跨站請求偽造和枚舉攻擊,此外還進(jìn)行數(shù)據(jù)庫安全加固。
針對目前比較流行的腳本注入攻擊,最有效方法是采用參數(shù)化查詢,先編譯SQL語句,將執(zhí)行計(jì)劃固定,再傳參,確保最終執(zhí)行邏輯沒有偏差。微軟推出LINQ語言,不但是ORM(Object Relational Mapping,對象關(guān)系映射)框架,而且也是參數(shù)化查詢技術(shù),只要使用得當(dāng),不存在注入漏洞。本系統(tǒng)后端采用ASP.net,使用LINQ操縱數(shù)據(jù)庫。
跨站腳本攻擊是一種極難防范的攻擊[11]。針對跨站腳本攻擊,通常對用戶的輸入執(zhí)行嚴(yán)格檢查,轉(zhuǎn)義非法字符。文章表是防范重點(diǎn),主要是內(nèi)容字段。為了方便排版允許內(nèi)容字段帶有html代碼,因此內(nèi)容字段處理比較復(fù)雜。考慮到本系統(tǒng)中可以發(fā)表文章的地方只有后臺站點(diǎn),且只有授權(quán)用戶才有權(quán)發(fā)表,合法用戶執(zhí)行跨站攻擊的可能性很小。即使執(zhí)行了跨站腳本攻擊,如果將最后一道防線session保護(hù)好,就可以阻止權(quán)限竊取。本系統(tǒng)采用最小化保護(hù)策略,將包含session ID的cookie設(shè)置http only和path=/manager屬性。
針對跨站請求偽造,為關(guān)鍵操作設(shè)置驗(yàn)證碼,例如刪除文章時(shí),彈出驗(yàn)證碼窗口,提示正在刪除文章,要求輸入驗(yàn)證碼,驗(yàn)證碼正確才允許刪除。
枚舉攻擊是指當(dāng)文章的ID采用自增整數(shù)時(shí),如果顯示文章頁面URL是show?id=x,通過不斷自增id的值,即可將所有文章枚舉出來。本系統(tǒng)中文章ID采用隨機(jī)生成的字符串,不可預(yù)測,沒有枚舉的可能。
數(shù)據(jù)庫安全加固包括使用普通賬戶和執(zhí)行邏輯刪除。使用普通賬戶而不是超級用戶連接數(shù)據(jù)庫,該普通賬戶只能操作站群數(shù)據(jù)庫,且只能select,create和update。采用邏輯刪除策略,當(dāng)刪除數(shù)據(jù)時(shí)將deleted字段從0改成1。
重點(diǎn)給出widget的實(shí)現(xiàn)代碼。以portal的默認(rèn)文檔index.html為例,其路由規(guī)則如下:
router.get('/', function (req, res, next) {// 對/ GET的路由規(guī)則
res.context = {};
res.context._r_widget = true;//有widget
res.context._r_widget_skin = 'index.html';//皮膚文件
next();
});
index.html前兩行如下:
定義了兩個(gè)widget:header和banner。
處理widget的中間件代碼如下:
const reg = new RegExp(/
function widget(req, res, next) {
var skin = path.join(req.site.paths.skins, res. context ._r_widget_skin); //取skin路徑
fs.readFile(skin, 'utf8', (err, data) => { /讀skin文件
var widgets = [],temp = {},runs = [],widget_ids = [];
while ((temp = reg.exec(data)) !== null) {//解析出所有的widget
widgets.push({holder: temp[0],id: temp[1]});
widget_ids.push(temp[1]);}
//執(zhí)行widget的data.js腳本從后端獲取數(shù)據(jù),用數(shù)據(jù)渲染模版
widgets.forEach(function (e) {//對于每個(gè)widget
runs.push(function (callback) {//定義渲染過程,后面同時(shí)發(fā)射
var _w_path = path.join(req.site.paths. widget, e.id),
_w_js = path.join(_w_path, 'data.js'), //data.js
_w_html = path.join(_w_path, 'view'); //view.html
//準(zhǔn)備結(jié)果對象
var result = {site: req.site, _widget_name: _w_real.name, _widget_path: util.format('widgets/%s', _w_real.name) };
fs.accessSync(_w_js, fs.R_OK); //data.js存在
//執(zhí)行data.js
require(_w_js)(req, res, utils). then(function (r) {
r.site = req.site;
r._widget_name = result._widget_name;
r._widget_path = result._widget_path;
//用數(shù)據(jù)渲染模版
var content = template.renderFile (_w_html, r);
callback(null, {js: _w_js, holder: e.holder, content: content}); //渲染結(jié)果傳遞給回調(diào)函數(shù),替換占位符
});
});
}, this);
//并發(fā)執(zhí)行前面的渲染過程,傳入回調(diào)函數(shù)。全部執(zhí)行完成,才回調(diào)。
async.parallel(runs, function (err, result) {
result.forEach(function (e) {//用渲染結(jié)果替換占位符
data = data.replace(e.holder, e.content);});
res.send(data);
next();
});
});
}
子站可以將新聞推送到主站,實(shí)現(xiàn)信息共享。根據(jù)ER圖,一條新聞只能對應(yīng)一個(gè)站點(diǎn)[12]。因此新聞推送將創(chuàng)建兩條文章記錄,一條是子站點(diǎn)所有,一條是主站點(diǎn)所有。兩條記錄通過PID(party ID,對方ID)字段指向?qū)Ψ?,即主站新聞的PID字段設(shè)置為子站新聞ID,主站新聞的PID字段設(shè)置為子站新聞ID。主站新聞重要性高于子站。當(dāng)主站新聞未通過審核時(shí),修改子站新聞將同步到主站新聞。當(dāng)主站新聞通過審核后(審核標(biāo)志為1),修改子站新聞將無法同步到主站新聞。反過來,主站新聞修改總是同步到子站新聞。
站群系統(tǒng)建設(shè)不但是解決信息孤島現(xiàn)象的重要手段,也是推進(jìn)高校信息化向前發(fā)展的一個(gè)抓手。本文通過Node.js構(gòu)建高性能站群系統(tǒng),采用了諸多熱門技術(shù),包括MVC,Widget和SOA等,結(jié)構(gòu)輕量,穩(wěn)定可靠,給出站群系統(tǒng)建設(shè)的新模式。實(shí)際部署表明系統(tǒng)支持高并發(fā)請求,用戶體驗(yàn)良好,完全滿足需求。
[1] 陳潔, 雷萌. 基于脈沖耦合神經(jīng)網(wǎng)絡(luò)的乳鼠心肌細(xì)胞圖像增強(qiáng)[J]. 軟件, 2018, 39(02): 41-43.
[2] 李軍. 高并發(fā)Web系統(tǒng)的設(shè)計(jì)與優(yōu)化[D]. 北京交通大學(xué), 2009.
[3] 郭家寶. Node. js開發(fā)指南[M]. 人民郵電出版社, 2012.
[4] 閆曉甜, 李玉斌. 微信平臺支持下的高校微課程設(shè)計(jì)與應(yīng)用研究[J]. 中國遠(yuǎn)程教育, 2015(07): 52-57+80.
[5] 冼學(xué)輝. 基于Web的實(shí)時(shí)信息推送技術(shù)的研究[D]. 華北電力大學(xué), 2013.
[6] 劉欣. 基于MVC模式的Web軟件系統(tǒng)開發(fā)框架設(shè)計(jì)與實(shí)現(xiàn)[D]. 山東大學(xué), 2013.
[7] 宋婷婷, 徐世許. 基于全采樣和L1范數(shù)降采樣的卷積神經(jīng)網(wǎng)絡(luò)圖像分類方法[J]. 軟件, 2018, 39(02): 75-80.
[8] 付向東, 孫寧, 何長鵬. 高等院校站群系統(tǒng)建設(shè)與實(shí)踐[J]. 中國教育信息化, 2014(05): 82-84.
[9] 賀盈. 重慶文理學(xué)院站群系統(tǒng)開發(fā)研究與實(shí)現(xiàn)[D]. 電子科技大學(xué), 2012.
[10] 楊盾, 王小鵬. 應(yīng)對DDoS攻擊的SDN網(wǎng)絡(luò)安全特性研究[J]. 軟件, 2018, 39(03): 175-180.
[11] 羅淑元. Android系統(tǒng)中Widget的設(shè)計(jì)與實(shí)現(xiàn)[D]. 北京交通大學(xué), 2012.
[12] 陳培君. 基于SOA的數(shù)字校園綜合信息服務(wù)平臺的研究與設(shè)計(jì)[D]. 電子科技大學(xué), 2013.
Design and Implementation of High Performance Station Cluster System Based on Node.js
TONG Min, ZHANG Wen-sheng, QIAN Li-san
(Anhui Radio and TV University Information Technology and Network Management Center, Hefei, Anhui, 230022)
Station cluster system is station model with unified data, standard and management, which can establish a number of sites easily and share information between sites, and reduce information island phenomenon significantly. Node.js is implementation of JavaScript language on server side, with V8 high performance engine, combined with unique asynchronous features of language, it can build high performance web site. The article proposes a website architecture based on Node.js, to decouple with MVC, Widgets and SOA, increase parallelism and improve system performance. Under the framework, the article discusses design and implemention of a set of high performance station cluster system, which has advantages of clear and simple structure, good scalability, high stability and superior performance, and is suitable for colleges and universities.
Node.js; Station cluster system; MVC; Widgets; SOA
TN711
A
10.3969/j.issn.1003-6970.2018.08.003
安徽廣播電視大學(xué)軟件開發(fā)項(xiàng)目“電大移動服務(wù)平臺”(編號RJ17-01)
童敏(1992-),女,助理工程師,碩士,研究方向:計(jì)算機(jī)網(wǎng)絡(luò)應(yīng)用;張文盛(1980-),男,高級工程師,本科,研究方向:計(jì)算機(jī)網(wǎng)絡(luò)應(yīng)用;錢立三(1970-),男,高級工程師,本科,研究方向:計(jì)算機(jī)網(wǎng)絡(luò)應(yīng)用。
本文著錄格式:童敏,張文盛,錢立三. 基于Node.js的高性能站群系統(tǒng)設(shè)計(jì)與實(shí)現(xiàn)[J]. 軟件,2018,39(8):09-13