付晶晶,熊前興,趙江濱
(1.武漢理工大學(xué) 計算機科學(xué)與技術(shù)學(xué)院,湖北 武漢430063;2.武漢理工大學(xué) 能源與動力工程學(xué)院,湖北 武漢430074)
作為智能航道子系統(tǒng)之一的數(shù)字機務(wù)系統(tǒng),能夠?qū)C務(wù)設(shè)備實現(xiàn)智能化管理,是智能航道的重要組成部分,能夠?qū)Υ暗母B(tài)、航向航跡、主機、齒輪箱、發(fā)電機組、主配電板等設(shè)備的運行數(shù)據(jù)進(jìn)行遠(yuǎn)程監(jiān)測,其核心功能是實現(xiàn)船岸數(shù)據(jù)實時通信。系統(tǒng)能夠接收從船上傳來的實時數(shù)據(jù),能將動態(tài)數(shù)據(jù)實時顯示到系統(tǒng)中,工作人員通過計算機就能看到船舶的實時動態(tài)信息,進(jìn)而實現(xiàn)對船舶的遠(yuǎn)程控制。系統(tǒng)中數(shù)據(jù)來源有兩種,一種是船舶通過傳感器發(fā)送來的實時動態(tài)數(shù)據(jù),如船舶的實時航行方向、經(jīng)緯度等;另一種是靜態(tài)基礎(chǔ)數(shù)據(jù),如船舶的名稱、所屬機構(gòu)及編碼、航行的經(jīng)緯度、機構(gòu)的名稱及編碼等。該系統(tǒng)采用B/S模型,應(yīng)用當(dāng)前比較流行的Jsp +Servlet 技術(shù),服務(wù)器采用的是Tomcat 服務(wù)器。采用這一模型固然方便,但是如此大量數(shù)據(jù)的頻繁訪問必然造成網(wǎng)絡(luò)擁塞和服務(wù)器超載,導(dǎo)致客戶訪問延遲增大。為了系統(tǒng)能夠快速響應(yīng)客戶需求,一個快速有效的解決方案就是在網(wǎng)絡(luò)傳輸上利用緩存技術(shù)使得Web 服務(wù)數(shù)據(jù)流能就近訪問。經(jīng)過測試,該緩存策略能極大提高服務(wù)器端的響應(yīng)速度[1]。
通常情況下,數(shù)據(jù)是保存在數(shù)據(jù)庫或者硬盤文件中的,每次操作數(shù)據(jù)時都需要從數(shù)據(jù)庫或者硬盤上去獲取,速度很慢,會造成性能問題[2],如果先將數(shù)據(jù)庫或者硬盤文件中將會被頻繁使用到的數(shù)據(jù)或者資源緩存到緩存區(qū)中,當(dāng)應(yīng)用程序需要這些數(shù)據(jù)時,直接從緩存區(qū)中提取,就可以減少系統(tǒng)開銷。數(shù)據(jù)緩存的目的是減少網(wǎng)絡(luò)中冗余數(shù)據(jù)的重復(fù)傳輸,使之最小化,從而提高數(shù)據(jù)的讀取速度。因為服務(wù)器與應(yīng)用客戶端之間存在著流量的瓶頸,所以頻繁讀取大容量數(shù)據(jù)時,使用緩存來直接為客戶端服務(wù),就不必重復(fù)從數(shù)據(jù)庫中讀出,可以減少Web 服務(wù)器端與數(shù)據(jù)庫的數(shù)據(jù)交互,減少數(shù)據(jù)庫的訪問量,從而大大提高程序的性能[3]。Web 內(nèi)容可以緩存在客戶端、代理服務(wù)器以及服務(wù)器端。
一個簡單的數(shù)據(jù)緩存解決方法是把這些數(shù)據(jù)緩存到內(nèi)存里,每次操作時,先到內(nèi)存里面找,如果有就直接使用,如果沒有就獲取它,并設(shè)置到緩存中,下一次訪問時就直接從內(nèi)存中獲取,從而節(jié)省大量的時間。當(dāng)然,緩存是一種典型的空間換時間的方案[4]。在Java 中最常見的一種實現(xiàn)緩存的方式就是使用靜態(tài)Map[5]。
根據(jù)系統(tǒng)的特性以及可操作性,該系統(tǒng)將數(shù)據(jù)緩存在Web 服務(wù)器端,以內(nèi)存來換取速度(在數(shù)據(jù)容量不是特別大時是適合的)[6],數(shù)字機務(wù)管理系統(tǒng)緩存設(shè)計思路如圖1 所示。
該系統(tǒng)中緩存實現(xiàn)的基本步驟是:
圖1 數(shù)據(jù)緩存設(shè)計思路
(1)在程序啟動時,直接將頻繁使用的基礎(chǔ)信息從數(shù)據(jù)庫讀到服務(wù)器內(nèi)存中。
(2)當(dāng)用戶請求相應(yīng)數(shù)據(jù)時,服務(wù)器直接從這個內(nèi)存中讀取數(shù)據(jù)來響應(yīng)用戶,而不是從數(shù)據(jù)庫中去讀取。
(3)當(dāng)用戶更改了基礎(chǔ)信息后,直接將數(shù)據(jù)緩存的數(shù)據(jù)全部更新,以保證數(shù)據(jù)的一致性。
對于靜態(tài)基礎(chǔ)數(shù)據(jù),主要是機構(gòu)信息和船舶信息,需要在系統(tǒng)每個頁面左側(cè)導(dǎo)航以樹形結(jié)構(gòu)顯示出來,如圖2 所示。每當(dāng)頁面跳轉(zhuǎn)并刷新時,由于機構(gòu)和船舶信息量比較大,為了減少數(shù)據(jù)庫的訪問量并提高效率,并不希望樹形導(dǎo)航重新從數(shù)據(jù)庫里面讀取數(shù)據(jù)來顯示,于是設(shè)計了一種緩存策略,每當(dāng)程序啟動時,將船舶和機構(gòu)信息全部讀到內(nèi)存中,頁面刷新時,可以讀取這個內(nèi)存中的數(shù)據(jù)來顯示,以內(nèi)存換取速度。
圖2 系統(tǒng)頁面左側(cè)數(shù)據(jù)導(dǎo)航界面圖
具體實現(xiàn)過程如下:
首先設(shè)計了一個單例模式的類,即數(shù)據(jù)中心,它保存緩存的數(shù)據(jù),在應(yīng)用程序與數(shù)據(jù)庫之間,實現(xiàn)數(shù)據(jù)的緩存。設(shè)計單例模式的目的在于防止創(chuàng)建多個對象,每次讀取數(shù)據(jù)在一個對象中讀取,保證數(shù)據(jù)的同步性,同時還減少了系統(tǒng)因新建多個對象而產(chǎn)生的額外開銷[7]。根據(jù)數(shù)據(jù)模型,各設(shè)計了一個包含所有信息列表的靜態(tài)Map。機構(gòu)數(shù)據(jù)結(jié)構(gòu)比較復(fù)雜,一個機構(gòu)下會包含若干機構(gòu),最多達(dá)到4 級,機構(gòu)數(shù)據(jù)列表如下:
船舶數(shù)據(jù)列表如下:
船舶實時動態(tài)信息列表如下:
這3 個Map 對象是保存數(shù)據(jù)的中心,在系統(tǒng)啟動時將其實例化,實例化對象時會給Map 賦值,即從數(shù)據(jù)庫中讀取數(shù)據(jù)給其賦值,dataShipList數(shù)據(jù)不是從數(shù)據(jù)庫中讀取,由船舶動態(tài)返回,通過接口去獲取。
其次,設(shè)置了一個監(jiān)聽器Listener,監(jiān)聽Tomcat 的啟動,Tomcat 啟動時直接實例化這個對象,并將數(shù)據(jù)讀到內(nèi)存中。
在web.xml 文件中配置監(jiān)聽器:
監(jiān)聽器的實現(xiàn)如下:
在Tomcat 啟動后,通過監(jiān)聽器啟動了一個線程,在這個myThread 線程中,實例化了數(shù)據(jù)中心對象,同時對于保存船舶實時信息的dataShip-List,其數(shù)據(jù)來源是通過接口從其他系統(tǒng)讀取來的,以Json 格式文件保存,需要解析這個Json 來給dataShipList 賦值,由于數(shù)據(jù)是不斷更新的,因此必須每隔一個時間間隔通過接口去獲取Json數(shù)據(jù)。其主要代碼如下:
這樣數(shù)據(jù)中心的數(shù)據(jù)全部都讀到內(nèi)存中了,當(dāng)客戶端請求數(shù)據(jù)時,服務(wù)器不用從數(shù)據(jù)庫讀取而是從這個緩存里讀取,緩存的數(shù)據(jù)是個Map 列表,返回數(shù)據(jù)時將其轉(zhuǎn)換成Json 格式的數(shù)據(jù)。使用Json 格式傳輸數(shù)據(jù)不僅傳輸效率要比Map 對象高,而且易于Jquery 解析[8]。該系統(tǒng)采用的是Fastjson 庫,它將Map 對象轉(zhuǎn)換成Json 數(shù)據(jù)的速度提升到極致,超過所有Json 庫。在請求的Servlet 中的代碼如下:
動態(tài)的船舶信息dataShipList 是在一些特定頁面需要時才返回,而機構(gòu)和船舶信息是每個頁面都需要的,用戶每次刷新頁面都會重新請求。
從以上過程可以看出,建立數(shù)據(jù)緩存對于數(shù)據(jù)的訪問完全沒有問題,而對于數(shù)據(jù)的增刪改,需要保持?jǐn)?shù)據(jù)庫與這個數(shù)據(jù)中心類的數(shù)據(jù)一致性。
當(dāng)用戶增加、刪除、更改一個船舶或者機構(gòu)信息時,首先要更新數(shù)據(jù)庫,而對于這個數(shù)據(jù)緩存中心,有兩種方案來更新其數(shù)據(jù),第一種是在用戶進(jìn)行增刪改操作時,不僅對數(shù)據(jù)庫進(jìn)行相應(yīng)的操作,也要對這個數(shù)據(jù)中心的對象進(jìn)行操作,如圖3 所示;第二種是只進(jìn)行數(shù)據(jù)庫的操作,數(shù)據(jù)中心類的數(shù)據(jù)重新從數(shù)據(jù)庫中讀取,從而達(dá)到緩存中心里的數(shù)據(jù)與數(shù)據(jù)庫數(shù)據(jù)的一致性[9],如圖4 所示。兩種方式各有優(yōu)缺點。第一種方式在用戶進(jìn)行增刪改操作后,直接操作數(shù)據(jù)中心對象,這種方式不用重新從數(shù)據(jù)庫中查詢數(shù)據(jù),而且有針對性地對對象更改,只需更改數(shù)據(jù)變化的地方,這種方式無疑是最好的,但是航道系統(tǒng)Map 對象的數(shù)據(jù)結(jié)構(gòu)是非常復(fù)雜的,導(dǎo)致操作非常復(fù)雜,Map 對象最多可達(dá)到4 級結(jié)構(gòu),如果修改了一個機構(gòu),不僅要判斷它的下級是否有船舶和機構(gòu),還要判斷上級,如果有機構(gòu)還要判斷機構(gòu)的上下級是否有機構(gòu)或者船舶,有就進(jìn)行增加、修改或者刪除的操作,因為級聯(lián)操作很復(fù)雜,這種方式不適合,它一般適合數(shù)據(jù)結(jié)構(gòu)比較簡單的系統(tǒng)。第二種方式是重新刷新數(shù)據(jù)中心的數(shù)據(jù),這種方式?jīng)]有操作對象的復(fù)雜,實現(xiàn)方式很簡單,但是修改了一處數(shù)據(jù)要全部進(jìn)行刷新,由于系統(tǒng)對數(shù)據(jù)修改量很少,并發(fā)要求不是很大,因此這種方式是最好的選擇。添加一個船舶信息后,更新緩存數(shù)據(jù),代碼如下:
DBcon.sqlnoquery(sql);//添加船舶,先更新到數(shù)據(jù)庫
RTModelManager.getInstance().initRTModels();
更改數(shù)據(jù)以后,調(diào)用RTModelManager 單例模式類的initRTModels()方法,重新從數(shù)據(jù)庫中讀出數(shù)據(jù),將緩存數(shù)據(jù)全部更新,實現(xiàn)緩存數(shù)據(jù)與數(shù)據(jù)庫數(shù)據(jù)的一致性,頁面刷新時,即可得到更改后的最新數(shù)據(jù)[10]。
圖3 保持?jǐn)?shù)據(jù)一致性方法一
圖4 保持?jǐn)?shù)據(jù)一致性方法二
Java 的緩存還有很多實現(xiàn)方式,現(xiàn)在有很多專業(yè)的緩存框架,如OSCache、Ehcache、memcached 等,每種方式有自己的優(yōu)缺點,只有找到適合自己系統(tǒng)的方式,才能提高系統(tǒng)的訪問速度和吞吐量。該系統(tǒng)使用的這種緩存方式屬于單機緩存方案,讀寫訪問在所有緩存策略中的性能最高,代價最小,在數(shù)據(jù)量不大且在并發(fā)性能要求不是很高的情況下是非常合適的。經(jīng)過測試,把頁面中需要頻繁訪問的數(shù)據(jù)都緩存起來,定時進(jìn)行更新,大大提升了系統(tǒng)的性能,減少了數(shù)據(jù)庫的訪問量。
[1]周京暉. 數(shù)據(jù)緩存按需同步的設(shè)計與應(yīng)用[J]. 軟件,2013,34(5):6 -11.
[2]董黎剛.分布式系統(tǒng)中的調(diào)度與緩存技術(shù)[M]. 杭州:浙江工商大學(xué)出版社,2010:20 -70.
[3]顧榮慶,楊開杰,徐汀榮.分布式數(shù)據(jù)緩存技術(shù)研究[J].計算機應(yīng)用與軟件,2011,28(6):202 -204.
[4]倪高鵬. 基于Memcached 的緩存系統(tǒng)設(shè)計與實現(xiàn)[D].大連:大連理工大學(xué)圖書館,2012.
[5]鄭鈞.Web 應(yīng)用系統(tǒng)架構(gòu):緩存架構(gòu)策略[EB/OL].[2014 - 01 - 24]. http://zhengjunwei2007. blog.163.com/blog/static/.
[6]肖紅鳳.基于數(shù)據(jù)中心的數(shù)據(jù)訪問服務(wù)模型研究[D].大慶市:東北石油大學(xué)圖書館,2012.
[7]丁鯤,嚴(yán)浩,刁興春.分布式數(shù)據(jù)庫數(shù)據(jù)同步技術(shù)研究[J].海軍工程大學(xué)學(xué)報,2004,28(5):100 -104.
[8]陳懷亮. 分布式數(shù)據(jù)緩存技術(shù)的研究與應(yīng)用[D].大連:大連理工大學(xué)圖書館,2011.
[9]劉清.高性能分布式數(shù)據(jù)緩存系統(tǒng)的研究與實現(xiàn)[D].南京:南京郵電大學(xué)圖書館,2011.
[10]李棟.Pushlet 和數(shù)據(jù)緩存在船舶動態(tài)管理系統(tǒng)應(yīng)用的研究[D].大連:大連海事大學(xué)圖書館,2009.