黎子晨
摘 要:企業(yè)開發(fā)中常用到對(duì)象關(guān)系映射,隨著技術(shù)和業(yè)務(wù)的發(fā)展,應(yīng)用系統(tǒng)常需要集群部署來減輕每一臺(tái)服務(wù)器的壓力。對(duì)象關(guān)系映射中的緩存技術(shù)對(duì)于提升性能有較大益處,但在集群環(huán)境中常導(dǎo)致緩存不一致,從而影響業(yè)務(wù)處理的正確性。文中設(shè)計(jì)了緩存同步的設(shè)計(jì)方案,試圖解決同步問題,為在集群環(huán)境中部署使用ORM緩存技術(shù)提供借鑒意義。
關(guān)鍵詞:對(duì)象關(guān)系映射;緩存;集群;同步方案
中圖分類號(hào):TP393 文獻(xiàn)標(biāo)識(shí)碼:A 文章編號(hào):2095-1302(2017)08-00-03
0 引 言
隨著信息化技術(shù)的快速發(fā)展,人們依賴于使用軟件解決日常工作中碰到的問題。軟件的規(guī)模隨著技術(shù)及業(yè)務(wù)的發(fā)展變得越來越龐大和復(fù)雜。從過去個(gè)人桌面軟件的普及,到現(xiàn)在的分布式軟件架構(gòu),軟件系統(tǒng)已經(jīng)和企業(yè)現(xiàn)有的業(yè)務(wù)模式緊密結(jié)合在一起。對(duì)于企業(yè)級(jí)系統(tǒng),其最為核心的部分是與業(yè)務(wù)緊密關(guān)聯(lián)的各類數(shù)據(jù)。在數(shù)據(jù)存儲(chǔ)方面,企業(yè)使用最多的還是關(guān)系型數(shù)據(jù)庫(kù)系統(tǒng)。關(guān)系型數(shù)據(jù)庫(kù)從數(shù)學(xué)理論發(fā)展而來,和目前主流的軟件開發(fā)方式,即面向?qū)ο蟮能浖_發(fā)方式不匹配。對(duì)象關(guān)系映射(Object Relational Mapping,ORM)技術(shù)的出現(xiàn)從很大程度上解決了兩者的不匹配問題,即以系統(tǒng)開發(fā)程序員的角度來看,數(shù)據(jù)是面向?qū)ο蟮?,而?shù)據(jù)依然存儲(chǔ)于關(guān)系型數(shù)據(jù)庫(kù),即數(shù)據(jù)邏輯面向?qū)ο?,物理關(guān)系存在于關(guān)系模型中。
使用對(duì)象關(guān)系映射可通過減輕對(duì)底層數(shù)據(jù)庫(kù)的訪問頻率來提高系統(tǒng)性能。該性能提升功能通過啟用緩存來實(shí)現(xiàn),即數(shù)據(jù)的獲取可以通過緩存而非訪問數(shù)據(jù)庫(kù)來滿足。緩存通常存在于內(nèi)存中(也可能存在于本地磁盤中),相對(duì)于數(shù)據(jù)庫(kù)存取數(shù)據(jù)需要訪問磁盤尋找數(shù)據(jù),再將數(shù)據(jù)通過網(wǎng)絡(luò)傳輸給請(qǐng)求者,當(dāng)緩存命中時(shí)所帶來的性能提升十分明顯。依據(jù)局部性原理,設(shè)置一個(gè)合理的緩存將會(huì)有一個(gè)可觀的緩存命中率,可明顯提升系統(tǒng)的存取性能。
在ORM中開啟緩存存在一個(gè)嚴(yán)重的問題,即在集群環(huán)境中會(huì)產(chǎn)生數(shù)據(jù)不一致的現(xiàn)象。以B/S模式為例:當(dāng)一個(gè)應(yīng)用只部署在一個(gè)Web站點(diǎn)上時(shí),不存在上述問題;但當(dāng)該應(yīng)用采取集群方式部署在多個(gè)不同的Web站點(diǎn)上時(shí),極有可能出現(xiàn)相同的對(duì)象。在不同站點(diǎn)中存在不同緩存項(xiàng)會(huì)導(dǎo)致生產(chǎn)環(huán)境中的業(yè)務(wù)數(shù)據(jù)出現(xiàn)錯(cuò)誤。目前主流的ORM框架均不建議采用集群方式來部署,但隨著業(yè)務(wù)的發(fā)展,逐漸增多的業(yè)務(wù)會(huì)對(duì)系統(tǒng)產(chǎn)生更大的壓力,采用集群方式部署以減小單臺(tái)設(shè)備的壓力乃大勢(shì)所趨。本文通過提出幾種設(shè)計(jì)方案來解決集群部署采用ORM技術(shù)系統(tǒng)時(shí)存在的緩存不一致問題。
1 集群環(huán)境中ORM緩存不一致性分析
在企業(yè)應(yīng)用系統(tǒng)中,目前使用最為廣泛的架構(gòu)為瀏覽器-服務(wù)器架構(gòu),即B/S模式[1]。如圖1所示,在B/S模式中,客戶端使用瀏覽器,通過HTTP協(xié)議訪問部署于應(yīng)用系統(tǒng)的Web服務(wù)器[2]??蛻粝騑eb服務(wù)器請(qǐng)求或提交數(shù)據(jù),服務(wù)器對(duì)客戶的訪問進(jìn)行處理,將結(jié)果返回給客戶,產(chǎn)生的數(shù)據(jù)存儲(chǔ)在數(shù)據(jù)庫(kù)中。
當(dāng)Web服務(wù)器中使用了ORM技術(shù)后,Web服務(wù)器同數(shù)據(jù)庫(kù)服務(wù)器交換數(shù)據(jù)的方式將有所變化,如圖2所示。Web服務(wù)器不再直接通過SQL或存儲(chǔ)過程和數(shù)據(jù)庫(kù)服務(wù)器進(jìn)行交互,而是將數(shù)據(jù)對(duì)象提交給對(duì)象關(guān)系映射的框架,該框架再依據(jù)系統(tǒng)操作使用SQL或存儲(chǔ)過程完成數(shù)據(jù)存取,將數(shù)據(jù)存儲(chǔ)于數(shù)據(jù)庫(kù)或從中獲取數(shù)據(jù)。使用了ORM框架后,為取數(shù)方式增添了靈活性,易于開發(fā)且具有理想的訪問性能[3]。啟用ORM緩存,當(dāng)框架從數(shù)據(jù)庫(kù)中成功取數(shù)后,獲取的數(shù)據(jù)將會(huì)在框架中留有副本,稱之為緩存項(xiàng),所有的緩存項(xiàng)構(gòu)成了ORM的數(shù)據(jù)緩存。當(dāng)進(jìn)行下一次取數(shù)操作時(shí),應(yīng)用系統(tǒng)向ORM框架提出取數(shù)請(qǐng)求,ORM框架首先查找緩存項(xiàng),試圖找出能滿足請(qǐng)求的數(shù)據(jù)對(duì)象,并將結(jié)果返回給應(yīng)用系統(tǒng),如果不存在滿足條件的對(duì)象則會(huì)進(jìn)行一次數(shù)據(jù)庫(kù)訪問請(qǐng)求以獲取所需數(shù)據(jù)。根據(jù)局部性原理,一個(gè)適當(dāng)大小的緩存能明顯提高緩存的命中率,從而減少對(duì)數(shù)據(jù)庫(kù)的訪問,提升系統(tǒng)性能[4]。
以目前最流行的ORM框架Hibernate為例:在Hibernate中,所有的Session都由同一個(gè)SessionFactory實(shí)例產(chǎn)生。一級(jí)緩存的作用范圍為Session,二級(jí)緩存就是Session.Factory級(jí)別的緩存。二級(jí)緩存可在不同Session對(duì)象間共享,它屬于進(jìn)程范圍的緩存。二級(jí)緩存可進(jìn)行配置和更改,并且可以動(dòng)態(tài)加載和卸載。當(dāng)Hibernate發(fā)現(xiàn)緩存中已有該條數(shù)據(jù),便會(huì)直接使用,而不必去數(shù)據(jù)庫(kù)查詢,當(dāng)緩存中沒有找到對(duì)應(yīng)項(xiàng)時(shí)才會(huì)到數(shù)據(jù)庫(kù)中查找[5]。
ORM框架使用緩存的方式在單點(diǎn)部署方面不存在任何問題,但在集群環(huán)境下部署會(huì)產(chǎn)生數(shù)據(jù)不一致的問題[6]。如圖3所示,在一個(gè)網(wǎng)絡(luò)中將若干臺(tái)客戶端及部署了相同應(yīng)用系統(tǒng)的兩臺(tái)Web服務(wù)器作為集群,這兩臺(tái)Web服務(wù)器會(huì)訪問同一個(gè)數(shù)據(jù)庫(kù)服務(wù)器,所有客戶端都可以通過瀏覽器訪問Web服務(wù)器1或Web服務(wù)器2,并完成相同的工作。若兩臺(tái)Web服務(wù)器上所受理的業(yè)務(wù)為只讀,則不存在上述問題。如果業(yè)務(wù)存在讀寫的情況,當(dāng)不同客戶端通過不同Web服務(wù)器讀寫同一數(shù)據(jù)時(shí),則極有可能出現(xiàn)不一致的狀態(tài)。
以銀行轉(zhuǎn)賬業(yè)務(wù)為例:存在兩個(gè)用戶Tom和Jerry,當(dāng)Tom收到來自Jerry的匯款后,Tom打算將自己賬戶中所有的金錢全部取出。在數(shù)據(jù)庫(kù)中存在關(guān)系account(id,money)用于存儲(chǔ)用戶賬戶的金額,其中id作為主鍵用于標(biāo)識(shí)用戶身份,money用于存儲(chǔ)用戶帳戶的金額,Tom的id為1,Jerry的id為2。表1說明了兩個(gè)用戶的轉(zhuǎn)賬取款過程。假設(shè)Tom賬戶余額為300元,Jerry賬戶余額為400元,Jerry的轉(zhuǎn)賬金額為100元。在關(guān)系account中存在兩個(gè)元組,分別存儲(chǔ)Tom和Jerry的賬戶金額。正常情況下,時(shí)間1時(shí)Tom看到自己的余額為300元,時(shí)間3的余額為400元,時(shí)間4時(shí)將400元從自己的賬戶中取出。
表2顯示了在集群環(huán)境中使用ORM緩存后的執(zhí)行過程,Tom取出的金額為300元,但卻不是理想的結(jié)果,其問題出現(xiàn)的關(guān)鍵在時(shí)間序號(hào)2和3,即兩個(gè)Web服務(wù)器中的緩存不一致,沒有客觀反映現(xiàn)實(shí)世界的狀態(tài)。解決該問題的關(guān)鍵在于如何使數(shù)據(jù)庫(kù)和所有啟用ORM緩存的應(yīng)用服務(wù)器對(duì)于相同的元組反映一致的狀態(tài)。endprint
2 集群環(huán)境中ORM緩存同步方案設(shè)計(jì)
為解決在集群環(huán)境中使用ORM帶來的數(shù)據(jù)不一致問題,主要采取以下幾種解決措施:
(1)禁用ORM緩存,使所有數(shù)據(jù)訪問請(qǐng)求都產(chǎn)生一個(gè)數(shù)據(jù)庫(kù)訪問;
(2)采用某種方式使得對(duì)于數(shù)據(jù)庫(kù)中記錄的修改都能夠及時(shí)反映到所有存儲(chǔ)了該記錄的ORM緩存中。
第一種方案最簡(jiǎn)單直接,但會(huì)明顯降低系統(tǒng)數(shù)據(jù)存取的性能。對(duì)于第二種方案,采用合理的設(shè)計(jì)方案可以使得在不影響系統(tǒng)性能的前提下使緩存中的數(shù)據(jù)同步,從而得到一致性的狀態(tài)。但在開發(fā)和部署方面會(huì)相對(duì)復(fù)雜,也可能產(chǎn)生一些新的問題。本文將著重探討集群環(huán)境中的ORM緩存同步方案。
2.1 集中式ORM緩存同步方案設(shè)計(jì)
通常看來,ORM框架負(fù)責(zé)ORM緩存的管理工作,即緩存項(xiàng)的創(chuàng)建,更新,讀取,刪除。ORM緩存和框架運(yùn)行在同一臺(tái)服務(wù)器中,對(duì)緩存的操作都在本地完成。使用集中式ORM緩存同步方案,其基本思路是將ORM緩存和管理與緩存數(shù)據(jù)的使用分離開來,ORM集群中部署一臺(tái)專用的計(jì)算機(jī)用于數(shù)據(jù)緩存以及對(duì)緩存的管理,應(yīng)用服務(wù)器不在本地保存數(shù)據(jù)的緩存。圖4簡(jiǎn)要說明了該設(shè)計(jì)方案。所有服務(wù)器連接到緩存服務(wù)器,緩存服務(wù)器再連接到數(shù)據(jù)庫(kù)服務(wù)器。所有的Web服務(wù)器對(duì)于數(shù)據(jù)的請(qǐng)求,都必須經(jīng)由緩存服務(wù)器處理,緩存服務(wù)器還起到了代理作用。
對(duì)于應(yīng)用系統(tǒng)數(shù)據(jù)操作來說(以讀取數(shù)據(jù)為例),Web服務(wù)器首先向緩存服務(wù)器請(qǐng)求數(shù)據(jù),緩存服務(wù)器在ORM緩存中執(zhí)行數(shù)據(jù)查找,試圖找到滿足條件的數(shù)據(jù)項(xiàng);如果能從緩存中找到滿足要求的數(shù)據(jù)項(xiàng)則返回給提出請(qǐng)求的應(yīng)用服務(wù)器,否則向數(shù)據(jù)庫(kù)提交一個(gè)數(shù)據(jù)查詢請(qǐng)求,將獲取的數(shù)據(jù)添加到緩存中并交付給提出請(qǐng)求的應(yīng)用系統(tǒng)。所有應(yīng)用所看到的數(shù)據(jù)緩存是一份唯一的副本,完全可以滿足一致性要求。與直接訪問數(shù)據(jù)庫(kù)相比,集中式訪問緩存管理只需網(wǎng)絡(luò)IO,無需訪問數(shù)據(jù)庫(kù)時(shí)產(chǎn)生的磁盤IO,可以明顯提升性能。但集中式管理也存在一些問題。
所有應(yīng)用連接到緩存服務(wù)器,當(dāng)應(yīng)用系統(tǒng)集群中服務(wù)器有較大數(shù)量時(shí),必然會(huì)對(duì)緩存服務(wù)器產(chǎn)生極大的負(fù)載,緩存服務(wù)器可能會(huì)成為集群系統(tǒng)的IO瓶頸,從而影響整個(gè)系統(tǒng)的性能。緩存服務(wù)器也必須保證具有高可用性,該服務(wù)器的故障會(huì)導(dǎo)致整個(gè)集群系統(tǒng)癱瘓。當(dāng)多個(gè)應(yīng)用同時(shí)請(qǐng)求同一數(shù)據(jù)時(shí),也會(huì)存在現(xiàn)在、潛在的不一致風(fēng)險(xiǎn)。為解決上述問題,可在緩存中引入鎖的概念。對(duì)于每一個(gè)緩存數(shù)據(jù)項(xiàng)的請(qǐng)求都必須加鎖。鎖分為兩種,即共享鎖和排他鎖。其中共享鎖之間相容,排他鎖與共享鎖,排他鎖和排他鎖之間不相容[7]。對(duì)于緩存數(shù)據(jù)的請(qǐng)求,必須被授予鎖之后才能被滿足。只讀請(qǐng)求建議申請(qǐng)共享鎖,而對(duì)數(shù)據(jù)的修改必須申請(qǐng)排他鎖。數(shù)據(jù)使用完畢后必須要及時(shí)釋放占有的鎖,以便對(duì)該緩存項(xiàng)的后續(xù)請(qǐng)求予以滿足。由于鎖的沖突,不同應(yīng)用服務(wù)器對(duì)于同一緩存項(xiàng)的大量讀寫請(qǐng)求也會(huì)成為潛在的性能瓶頸,大量的鎖請(qǐng)求對(duì)于集群中不同的服務(wù)器來說可能會(huì)造成死鎖[8],使系統(tǒng)無法正常運(yùn)行。由于對(duì)緩存項(xiàng)鎖的管理由緩存服務(wù)器進(jìn)行,可以采用各種死鎖預(yù)防和死鎖檢測(cè)及恢復(fù)算法進(jìn)行處理[9]。
2.2 分布式ORM緩存同步方案設(shè)計(jì)
與集中式ORM緩存同步方案不同,分布式方案不存在一個(gè)專門用于管理緩存的服務(wù)器。分布式部署方案同圖3中的部署方式類似,不同之處在于每臺(tái)Web服務(wù)器之間緩存的同步方式。對(duì)于每一臺(tái)應(yīng)用服務(wù)器而言,其ORM緩存都存儲(chǔ)在本地,通過本地管理來滿足對(duì)緩存的需求,同時(shí)緩存管理也可以同時(shí)與其他集群中的應(yīng)用服務(wù)器協(xié)調(diào)以實(shí)現(xiàn)緩存同步。緩存同步方案如下所示:
監(jiān)視數(shù)據(jù)庫(kù)元組改動(dòng):該方案的基本原理是所有應(yīng)用服務(wù)器監(jiān)視對(duì)數(shù)據(jù)庫(kù)的操作。數(shù)據(jù)庫(kù)操作分為查詢,刪除,增加和修改。查詢操作不會(huì)改動(dòng)關(guān)系中的元組,故不會(huì)使ORM緩存數(shù)據(jù)與數(shù)據(jù)庫(kù)中的數(shù)據(jù)不一致。增加操作雖然會(huì)更新數(shù)據(jù)庫(kù)的狀態(tài),但增加的記錄必然只存在于數(shù)據(jù)庫(kù)中和執(zhí)行增加操作的應(yīng)用服務(wù)器緩存中,且兩者同步,其他服務(wù)器不會(huì)緩存該新增數(shù)據(jù)。修改和刪除操作會(huì)影響到緩存了該元組的其他應(yīng)用服務(wù)器,導(dǎo)致緩存和數(shù)據(jù)庫(kù)中的記錄不一致。這時(shí)數(shù)據(jù)庫(kù)應(yīng)當(dāng)通知所有集群中的應(yīng)用服務(wù)器,使該緩存中的數(shù)據(jù)無效。將數(shù)據(jù)的改動(dòng)通知給應(yīng)用服務(wù)器,以O(shè)racle數(shù)據(jù)庫(kù)為例,可以使用如下方案,其基本思想用到了觀察者模式。觀察者模式定義了對(duì)象間的一對(duì)多依賴關(guān)系,當(dāng)一個(gè)對(duì)象的狀態(tài)發(fā)生改變時(shí),所有依賴它的對(duì)象都會(huì)得到通知并被自動(dòng)更新[10]。可以針對(duì)Oracle數(shù)據(jù)庫(kù)中涉及的表編寫觸發(fā)器,當(dāng)更新和刪除操作發(fā)生時(shí)通知所有Web服務(wù)器,以將涉及修改或刪除的元組從緩存中移除。發(fā)送通知的消息中可以包含所有涉及元組的主鍵。Oracle數(shù)據(jù)庫(kù)可以掛接Java程序并被PLSQL調(diào)用[11],掛接的Java程序通過網(wǎng)絡(luò)完成后續(xù)的消息發(fā)送。
更新操作通知所有應(yīng)用系統(tǒng):針對(duì)系統(tǒng)的修改和刪除操作,發(fā)起操作的服務(wù)器在完成數(shù)據(jù)庫(kù)操作后,立即將消息發(fā)送給所有集群中的應(yīng)用系統(tǒng),收到消息的應(yīng)用系統(tǒng)從緩存中移除指定的緩存對(duì)象,使得緩存中不存在與數(shù)據(jù)庫(kù)不一致的對(duì)象。該方案與前一方案相比,前者對(duì)數(shù)據(jù)庫(kù)的負(fù)載較小,所有消息的發(fā)送路徑均建立在應(yīng)用服務(wù)器之間,數(shù)據(jù)庫(kù)不參與同步過程。但當(dāng)應(yīng)用服務(wù)器之間由于網(wǎng)絡(luò)或安全策略而無法相互通信時(shí),該方案則無法實(shí)現(xiàn)同步信息的交互。
2.3 ORM緩存同步方案設(shè)計(jì)對(duì)比
對(duì)于系統(tǒng)部署來說,集中式方案需要額外部署一臺(tái)緩存服務(wù)器,且所有數(shù)據(jù)訪問都需經(jīng)由該服務(wù)器來完成,對(duì)該服務(wù)器壓力較大,但便于系統(tǒng)的開發(fā)和管理。分布式方案中監(jiān)視數(shù)據(jù)庫(kù)的方案對(duì)于數(shù)據(jù)庫(kù)服務(wù)器會(huì)產(chǎn)生額外的負(fù)載,使得本來在性能上捉襟見肘的數(shù)據(jù)庫(kù)擁有更大的壓力,雖然如此,但其卻具有良好的可靠性。通知所有系統(tǒng)的方案可以將同步工作分?jǐn)偟剿袘?yīng)用系統(tǒng)服務(wù)器上,但對(duì)于網(wǎng)絡(luò)帶寬及穩(wěn)定性有著較高的要求,由于網(wǎng)絡(luò)而未收到消息會(huì)導(dǎo)致數(shù)據(jù)出現(xiàn)不一致的可能。
3 結(jié) 語
在應(yīng)用系統(tǒng)集群中使用ORM技術(shù)并開啟緩存,通過分析緩存不一致現(xiàn)象找出產(chǎn)生該問題的原因。筆者提出了集中式和分布式緩存兩種設(shè)計(jì)方案,試圖解決該問題。通過對(duì)比各種方案的特點(diǎn)及其適用環(huán)境,為實(shí)現(xiàn)緩存一致性提供了思路和方法。
參考文獻(xiàn)
[1]查修齊,吳榮泉,高元鈞. C/S到B/S模式轉(zhuǎn)換的技術(shù)研究[J].計(jì)算機(jī)工程, 2014, 40(1):263-267.
[2]張鳳娟,冉寶才,劉麗.基于B_S模式的醫(yī)院運(yùn)維管理系統(tǒng)設(shè)計(jì)與實(shí)現(xiàn)[J].醫(yī)學(xué)信息學(xué)雜志,2016,37 (7):26-30.
[3]陳正舉.基于HIBERNATE的數(shù)據(jù)庫(kù)訪問優(yōu)化[J].計(jì)算機(jī)應(yīng)用與軟件, 2012, 29(7):144-149.
[4]朱保鋒, 蔡艷.計(jì)算機(jī)系統(tǒng)中不同組織方式的Cache性能分析[J].河南教育學(xué)院學(xué)報(bào)(自然科學(xué)版), 2012, 21(1):38-39.
[5]曹偉,應(yīng)君,董黎剛. Hibernate的緩存機(jī)制及其應(yīng)用的研究[J].杭州電子科技大學(xué)學(xué)報(bào),2013,33(5):158-161.
[6]張吉良, 陳德宗.服務(wù)器集群環(huán)境下Hibernate使用問題和解決方案[J].科技資訊, 2011(23):14.
[7] Abraham Silberschatz, Henry F.Korth, S.Sudrashan. Database System Concepts[M].New York: McGraw-Hill, 2011: 661.
[8]孫國(guó)營(yíng).計(jì)算機(jī)中的死鎖問題[J].科技傳播, 2010(12).
[9]塔嫩鮑姆.現(xiàn)代操作系統(tǒng)[M].北京:機(jī)械工業(yè)出版社,2009: 248.
[10] Erich Gamma, Richard Helm, Ralph Johnson, et al.設(shè)計(jì)模式-可復(fù)用面向?qū)ο筌浖幕A(chǔ)[M].北京:機(jī)械工業(yè)出版社,2012.
[11]全立新.使用Java編寫Oracle存儲(chǔ)過程[J].計(jì)算機(jī)時(shí)代,2004 (6):35-36.endprint