孫杜靖,李玲娟
(南京郵電大學(xué) 計(jì)算機(jī)學(xué)院,江蘇 南京 210003)
面向Redis的數(shù)據(jù)序列化算法研究
孫杜靖,李玲娟
(南京郵電大學(xué) 計(jì)算機(jī)學(xué)院,江蘇 南京 210003)
為了解決實(shí)時(shí)計(jì)算中半結(jié)構(gòu)化和非結(jié)構(gòu)化數(shù)據(jù)的存儲(chǔ)問(wèn)題,借助內(nèi)存數(shù)據(jù)庫(kù)Redis可以存儲(chǔ)鍵值型數(shù)據(jù)和支持全內(nèi)存運(yùn)算的優(yōu)勢(shì),結(jié)合文件序列化、圖像序列化、JSON序列化和Java對(duì)象序列化技術(shù),設(shè)計(jì)了面向Redis的半結(jié)構(gòu)化和非結(jié)構(gòu)化數(shù)據(jù)的序列化算法。該序列化算法不僅解決了半結(jié)構(gòu)化和非結(jié)構(gòu)化數(shù)據(jù)無(wú)法直接存入Redis的問(wèn)題,而且由于在序列化過(guò)程中實(shí)現(xiàn)了對(duì)這些數(shù)據(jù)的深拷貝,使得反序列化可以完美地還原初始數(shù)據(jù)。此外,序列化過(guò)程還支持通過(guò)加解密來(lái)保障數(shù)據(jù)安全?;赟torm平臺(tái)的實(shí)驗(yàn)結(jié)果表明,所設(shè)計(jì)的序列化算法快速、有效且性能穩(wěn)定。在海量數(shù)據(jù)實(shí)時(shí)計(jì)算中,無(wú)論使用哪種開(kāi)發(fā)語(yǔ)言,將該算法與Redis數(shù)據(jù)庫(kù)結(jié)合,既能利用Redis帶來(lái)的高讀寫(xiě)效率,又能存儲(chǔ)任何半結(jié)構(gòu)化和非結(jié)構(gòu)化數(shù)據(jù)對(duì)象而無(wú)需重復(fù)開(kāi)發(fā)代碼。
Redis;序列化;半結(jié)構(gòu)化;非結(jié)構(gòu)化;Storm
大數(shù)據(jù)時(shí)代的到來(lái)使得半結(jié)構(gòu)化數(shù)據(jù)、非結(jié)構(gòu)化數(shù)據(jù)迅猛增長(zhǎng),而處理和存儲(chǔ)這些數(shù)據(jù)的需求也日益增長(zhǎng)。傳統(tǒng)的關(guān)系型數(shù)據(jù)庫(kù)只能存儲(chǔ)結(jié)構(gòu)化數(shù)據(jù),并且對(duì)于高并發(fā)的數(shù)據(jù)寫(xiě)操作、海量數(shù)據(jù)的存儲(chǔ)和快速查詢(xún)以及服務(wù)器的橫向擴(kuò)展[1]顯得無(wú)能為力。為了解決這些問(wèn)題,NoSQL[2](Not Only SQL)技術(shù)應(yīng)運(yùn)而生。NoSQL主要分為四類(lèi):鍵值(Key-Value)存儲(chǔ)數(shù)據(jù)庫(kù)、列存儲(chǔ)數(shù)據(jù)庫(kù)、文檔型數(shù)據(jù)庫(kù)和圖形數(shù)據(jù)庫(kù)。鍵值存儲(chǔ)數(shù)據(jù)庫(kù)使用哈希來(lái)構(gòu)建數(shù)據(jù)庫(kù),列存儲(chǔ)數(shù)據(jù)庫(kù)善于分布式存儲(chǔ),文檔型、圖形數(shù)據(jù)庫(kù)顧名思義在文檔型、圖數(shù)據(jù)處理方面優(yōu)勢(shì)明顯。
Redis(Remote Dictionary Server)[3]就是NoSQL中屬于鍵值存儲(chǔ)數(shù)據(jù)庫(kù)的一個(gè)產(chǎn)品,并且是一個(gè)內(nèi)存型數(shù)據(jù)庫(kù),全內(nèi)存運(yùn)算和存儲(chǔ)使其在高并發(fā)的操作下仍能保持高性能讀寫(xiě),是已知性能最快的Key-Value數(shù)據(jù)庫(kù)[4]。Key-Value模型的內(nèi)存數(shù)據(jù)庫(kù),支持多種語(yǔ)言接口,如C++、C#、Java、JavaScript、Python等。Key-Value數(shù)據(jù)庫(kù)利用哈希表維護(hù)Key值到具體數(shù)據(jù)(Value)的映射,通過(guò)Key值可以方便高效地查詢(xún)數(shù)據(jù)[5]。Redis通過(guò)緩存數(shù)據(jù)庫(kù)查詢(xún)結(jié)果,減少對(duì)硬盤(pán)的訪(fǎng)問(wèn)次數(shù),其緩存數(shù)據(jù)庫(kù)全部加載在內(nèi)存中進(jìn)行操作,定期通過(guò)異步快照或者日志操作將數(shù)據(jù)庫(kù)數(shù)據(jù)flush到硬盤(pán)上進(jìn)行保存。因采用純內(nèi)存操作,每秒可以處理超過(guò)10萬(wàn)次讀寫(xiě)操作,Redis性能非常高。Redis還有其他一些優(yōu)勢(shì),比如提供了豐富的數(shù)據(jù)結(jié)構(gòu)、支持主從復(fù)制、完善的持久化機(jī)制等等。
實(shí)時(shí)計(jì)算中需要頻繁讀取數(shù)據(jù),Redis通過(guò)訪(fǎng)問(wèn)緩存數(shù)據(jù)庫(kù)讀取數(shù)據(jù),可以保證計(jì)算過(guò)程中讀取需求的實(shí)時(shí)響應(yīng)、數(shù)據(jù)庫(kù)數(shù)據(jù)的實(shí)時(shí)更新,因此Storm[6]等實(shí)時(shí)計(jì)算平臺(tái)借助Redis鍵值存儲(chǔ)和內(nèi)存操作的優(yōu)勢(shì)將能夠更好地完成流數(shù)據(jù)的實(shí)時(shí)處理任務(wù)。但是,采用全內(nèi)存的Key-Value存儲(chǔ)形式,Redis雖然能滿(mǎn)足實(shí)時(shí)處理的需求,卻不能直接存儲(chǔ)和處理大量半結(jié)構(gòu)化及非結(jié)構(gòu)化數(shù)據(jù),而這些數(shù)據(jù)是Storm等流式實(shí)時(shí)計(jì)算平臺(tái)必須面對(duì)的。
為此,設(shè)計(jì)了面向Redis的序列化算法,并通過(guò)在Storm平臺(tái)上的實(shí)現(xiàn)結(jié)果,證明了該算法在保證Redis高性能讀寫(xiě)的前提下,解決實(shí)時(shí)計(jì)算中半結(jié)構(gòu)和非結(jié)構(gòu)化數(shù)據(jù)的存儲(chǔ)問(wèn)題。
如上所述,要充分利用Redis的優(yōu)勢(shì),需要解決Redis作為鍵值型數(shù)據(jù)庫(kù)不能直接存儲(chǔ)和處理Storm等流式實(shí)時(shí)計(jì)算平臺(tái)必須面對(duì)的半結(jié)構(gòu)化及非結(jié)構(gòu)化數(shù)據(jù)的問(wèn)題。為解決這一問(wèn)題,可以利用Redis能夠存儲(chǔ)二進(jìn)制流的特性,先將半結(jié)構(gòu)化及非結(jié)構(gòu)化數(shù)據(jù)進(jìn)行序列化,然后存入Redis中,讀取后再進(jìn)行反序列化,使Redis存儲(chǔ)各種數(shù)據(jù)成為可能?;诖怂悸?,設(shè)計(jì)了面向Redis的序列化算法,該算法考慮了半結(jié)構(gòu)化數(shù)據(jù)、非結(jié)構(gòu)化數(shù)據(jù)和需要保密的數(shù)據(jù)。非結(jié)構(gòu)化數(shù)據(jù)的序列化包括:采用文件流的序列化和圖數(shù)據(jù)序列化;半結(jié)構(gòu)化數(shù)據(jù)的序列化包括:采用JSON[7]的序列化和采用Java對(duì)象的序列化。
圖1給出了算法的總體思想。
圖1 面向Redis的半結(jié)構(gòu)化及非結(jié)構(gòu)化數(shù)據(jù)序列化
數(shù)據(jù)發(fā)送端將半結(jié)構(gòu)化或非結(jié)構(gòu)化數(shù)據(jù)先序列化成二進(jìn)制流或JSON字符串,如有敏感數(shù)據(jù),可以將其加密,然后存入Redis數(shù)據(jù)庫(kù);數(shù)據(jù)更新時(shí),以半結(jié)構(gòu)化數(shù)據(jù)為例,Value1值會(huì)隨之改變,但是存入的鍵Key1值不變,即Redis數(shù)據(jù)庫(kù)中存入的Value1值也是實(shí)時(shí)更新的,如果數(shù)據(jù)消費(fèi)者想要查看此半結(jié)構(gòu)化數(shù)據(jù),可通過(guò)事先約定好的鍵Key1值來(lái)獲取數(shù)據(jù),如曾經(jīng)加密過(guò),則需解密;然后將獲得的二進(jìn)制流或JSON字符串進(jìn)行反序列化,得到原始數(shù)據(jù)。由于Redis數(shù)據(jù)庫(kù)中存入的數(shù)據(jù)是實(shí)時(shí)更新的,數(shù)據(jù)消費(fèi)者獲取的數(shù)據(jù)也是最近存入的數(shù)據(jù),對(duì)于實(shí)時(shí)更新的半結(jié)構(gòu)化數(shù)據(jù)只采用一個(gè)KEY值進(jìn)行存儲(chǔ)的原因有三:一是通信雙方可以事先規(guī)定好KEY值,無(wú)需頻繁修改;二是Redis為內(nèi)存型數(shù)據(jù)庫(kù),讀寫(xiě)速率快,完全可以支持?jǐn)?shù)據(jù)的實(shí)時(shí)更新和實(shí)時(shí)讀??;三是若采用不同時(shí)刻不同KEY值,在實(shí)時(shí)計(jì)算中,會(huì)迅速占滿(mǎn)內(nèi)存,使Redis可能無(wú)法再存入新的數(shù)據(jù)。
2.1 非結(jié)構(gòu)化數(shù)據(jù)的序列化
非結(jié)構(gòu)化數(shù)據(jù)即為不方便用傳統(tǒng)數(shù)據(jù)庫(kù)二維邏輯表來(lái)存儲(chǔ)的數(shù)據(jù),包括文檔、文本、圖像、音頻、視頻等等。傳統(tǒng)數(shù)據(jù)庫(kù)通過(guò)創(chuàng)建一個(gè)三字段(編號(hào)number、內(nèi)容描述varchar(1024)、內(nèi)容blog)的表來(lái)對(duì)其進(jìn)行索引,需要的人工參與量比較大,面對(duì)海量非結(jié)構(gòu)化數(shù)據(jù)的存儲(chǔ)與檢索時(shí),該方法顯然不可能在較短時(shí)間內(nèi)將其整理入庫(kù),數(shù)據(jù)的價(jià)值也無(wú)法很好地發(fā)揮。所設(shè)計(jì)的基于Redis的數(shù)據(jù)序列化算法采用將非結(jié)構(gòu)化數(shù)據(jù)進(jìn)行序列化后存入內(nèi)存數(shù)據(jù)庫(kù)Redis中的方案,能很好地解決此類(lèi)問(wèn)題,具體包括采用文件流的序列化和圖數(shù)據(jù)序列化。
1)采用文件流序列化非結(jié)構(gòu)數(shù)據(jù)。
對(duì)非結(jié)構(gòu)化數(shù)據(jù)序列化分為兩個(gè)過(guò)程:序列化和反序列化,對(duì)應(yīng)的方法分別是writeObject()和readObject()。
(1)writeObject():將非結(jié)構(gòu)化數(shù)據(jù)A序列化(序列化過(guò)程)。
輸入:非結(jié)構(gòu)化數(shù)據(jù)A,可以是文檔、圖像、音頻、視頻等等,路徑P
輸出:字節(jié)數(shù)組
步驟為:
①while(A更新一次)
②將A寫(xiě)入到底層輸入流A';
③通過(guò)文件輸出流將A'以字節(jié)流的方式保存到指定路徑P;
④endwhile
(2)readObject():將指定路徑中的對(duì)象轉(zhuǎn)化為原始非結(jié)構(gòu)化數(shù)據(jù)(反序列化過(guò)程)。
輸入:路徑P
輸出:原始非結(jié)構(gòu)化數(shù)據(jù)A
步驟為:
①將路徑P中的對(duì)象讀入原始字節(jié)流A';
②從輸入流中讀取數(shù)據(jù)對(duì)象類(lèi)數(shù)據(jù)A';
③將A'轉(zhuǎn)換成抽象Object類(lèi)A;
④returnA
數(shù)據(jù)發(fā)送方通過(guò)writeObject()函數(shù)將非結(jié)構(gòu)化數(shù)據(jù)序列化,然后將序列化的結(jié)果作為value存入Redis的某一路徑下,數(shù)據(jù)接收方先根據(jù)數(shù)據(jù)發(fā)送方存入的key取出相應(yīng)的字節(jié)流,然后通過(guò)readObject()方法,將字節(jié)流反序列化為抽象類(lèi),而原始數(shù)據(jù)類(lèi)型可能是文檔、圖像、音頻或視頻,反序列化后格式不變,可將其下載到某個(gè)路徑下查看,如若知道其為文檔,可以將其向下轉(zhuǎn)型成文件類(lèi),直接進(jìn)行其他數(shù)據(jù)處理。
2)對(duì)圖數(shù)據(jù)的序列化。
圖像是非結(jié)構(gòu)化數(shù)據(jù)的一種,視頻、圖像的實(shí)時(shí)計(jì)算處理過(guò)程中需要對(duì)大量照片進(jìn)行存儲(chǔ)、計(jì)算。在線(xiàn)系統(tǒng)中,在線(xiàn)數(shù)據(jù)的備份和恢復(fù)和對(duì)原始數(shù)據(jù)進(jìn)行測(cè)試需要使用到快照[7-8],而快照由于其實(shí)時(shí)更新,并且需要被不斷讀取和計(jì)算,對(duì)其進(jìn)行存儲(chǔ)并保證其能被快速讀取顯得尤為重要。由于圖數(shù)據(jù)使用頻繁,頻繁的文件讀寫(xiě)會(huì)增加時(shí)間開(kāi)銷(xiāo);另一方面,圖數(shù)據(jù)占用內(nèi)存過(guò)大時(shí),所涉及的內(nèi)存消耗和網(wǎng)絡(luò)傳輸會(huì)很大,為了避免文件讀寫(xiě)以減少時(shí)間開(kāi)銷(xiāo)、內(nèi)存消耗和網(wǎng)絡(luò)傳輸,采用如下的圖像序列化方案。該方案分為兩個(gè)過(guò)程:序列化和反序列化,對(duì)應(yīng)的方法分別是writeImage()和byte2image()。
(1)writeObjectwriteImage():將圖像轉(zhuǎn)化成字節(jié)數(shù)組(序列化過(guò)程)。
輸入:實(shí)時(shí)更新的某張圖像A
輸出:字節(jié)數(shù)組
步驟為:
①while(A更新一次)
②將圖像A以某種格式(如png)寫(xiě)入內(nèi)存;
③字節(jié)輸出流捕獲內(nèi)存緩沖區(qū)的數(shù)據(jù)A',轉(zhuǎn)換成字節(jié)數(shù)組B;
④endwhile
⑤returnB
(2)byte2image():將從Redis讀取的字節(jié)數(shù)組B轉(zhuǎn)化為圖像(反序列化過(guò)程)。
輸入:字節(jié)數(shù)組B
輸出:原始圖像A
步驟為:
①將字節(jié)數(shù)組B寫(xiě)入圖像文件輸出流中;
②輸出流探測(cè)圖像格式,并調(diào)用對(duì)應(yīng)的插件進(jìn)行解碼,得到原始圖像A;
③eturnA
數(shù)據(jù)發(fā)送方通過(guò)writeImage()方法將圖像序列化,然后將序列化的結(jié)果作為value存入Redis,數(shù)據(jù)接收方先根據(jù)數(shù)據(jù)發(fā)送方存入的key取出相應(yīng)的二進(jìn)制流,然后通過(guò)byte2image()方法,將二進(jìn)制流反序列化為圖像,直接進(jìn)行數(shù)據(jù)處理。
2.2 半結(jié)構(gòu)化數(shù)據(jù)的序列化算法
半結(jié)構(gòu)化的數(shù)據(jù)有一定的結(jié)構(gòu)性,但結(jié)構(gòu)變化很大,OEM[9](Object Exchange Model)是它的典型代表。由于其結(jié)構(gòu)性,需要了解數(shù)據(jù)內(nèi)部細(xì)節(jié),因而不能將其看成非結(jié)構(gòu)化數(shù)據(jù),像2.1節(jié)那樣將數(shù)據(jù)簡(jiǎn)單組織成一個(gè)文件;又因其數(shù)據(jù)結(jié)構(gòu)變化大,也不能將其按照結(jié)構(gòu)化數(shù)據(jù)處理方式存入二維表。設(shè)計(jì)了兩種方法將其序列化后存入Redis數(shù)據(jù)庫(kù),一種是采用JSON(JavaScript Object Notation)數(shù)據(jù)交換格式,另一種是利用Java對(duì)象序列化技術(shù)。
1)采用JSON序列化半結(jié)構(gòu)化數(shù)據(jù)。
JSON是一種輕量級(jí)的數(shù)據(jù)交換格式,是基于JavaScript Programming Language,Standard ECMA-262 3rd Edition-December 1999的一個(gè)子集。它易于機(jī)器解析和生成,因而用于在不同的編程語(yǔ)言之間交換數(shù)據(jù),比如JavaScript和Java、C#間交互。
JSON主要有兩種結(jié)構(gòu):對(duì)象和數(shù)組。
對(duì)象:用“{}”括起來(lái)的內(nèi)容,數(shù)據(jù)結(jié)構(gòu)為{key:value,key:value…}的鍵值對(duì),key為對(duì)象屬性,value為對(duì)應(yīng)的屬性值,通過(guò)“對(duì)象.key”來(lái)獲取屬性值,而屬性值的類(lèi)型可以是數(shù)字、字符串、數(shù)組或者對(duì)象。
數(shù)組:用“[]”括起來(lái)的內(nèi)容,數(shù)據(jù)結(jié)構(gòu)為[“java”,“c#”,“javascript”,“redis”…],通過(guò)索引進(jìn)行取值,字段值的類(lèi)型同樣可以是數(shù)字、字符串、數(shù)組或者對(duì)象。
將半結(jié)構(gòu)化的數(shù)據(jù)序列化為JSON字符串的方法是object2json(),具體的序列化過(guò)程如下:
object2json():將半結(jié)構(gòu)化數(shù)據(jù)序列化,轉(zhuǎn)換成JSON字符串。
輸入:實(shí)時(shí)更新的半結(jié)構(gòu)化數(shù)據(jù)A
輸出:JSON字符串S
步驟為:
①while(A更新一次)
②if(A為空)
③S.append(“”);
④else if(A是String、Integer、Boolean、Byte等基本類(lèi)型)
⑤S.append(“A”);
⑥else if(A是Object[]、List、Map、Set類(lèi)型數(shù)據(jù))
⑦調(diào)用類(lèi)似于S.append(array2json((Object[]) A))的方法進(jìn)行解析;
⑧else S.append(bean2json)格式化輸出;
⑨return S.toString()
在Redis中,數(shù)據(jù)發(fā)送方先將半結(jié)構(gòu)化數(shù)據(jù)通過(guò)object2json方法進(jìn)行序列化,轉(zhuǎn)換成JSON字符串,然后將該JSON字符串作為值寫(xiě)入特定的鍵中,即以(key,value)的形式寫(xiě)入Redis。數(shù)據(jù)接收方通過(guò)key取出相應(yīng)的value-JSON字符串,再將JSON字符串通過(guò)fromObject方法轉(zhuǎn)換成JSONObject,將對(duì)原始數(shù)據(jù)的解析轉(zhuǎn)換成對(duì)JSONObject的解析。
將半結(jié)構(gòu)化的數(shù)據(jù)序列化為JSON數(shù)據(jù),優(yōu)點(diǎn)是可以支持多種編程語(yǔ)言,并且被序列化的對(duì)象可以繼續(xù)添加或者刪除成員變量而不用變更object2json方法。但是,被序列化的對(duì)象必須要有無(wú)參數(shù)的構(gòu)造方法和所有變量的getter和setter方法。數(shù)據(jù)接收方須知道被序列化的對(duì)象的“key”和該對(duì)象所有的成員變量,才能完全地解析JSONString。
2)采用Java對(duì)象序列化技術(shù)序列化半結(jié)構(gòu)化數(shù)據(jù)。
利用Java對(duì)象序列化技術(shù)將半結(jié)構(gòu)化數(shù)據(jù)序列轉(zhuǎn)化為二進(jìn)制字符串的方法是:writeObject()和readObject()。
(1)writeObject():由于Java中所有的對(duì)象都繼承自O(shè)bject類(lèi),考慮到代碼的可重用性,可以利用父類(lèi)Object的writeObject方法將所有不同類(lèi)型的對(duì)象轉(zhuǎn)換成字節(jié)數(shù)組,具體的序列化過(guò)程如下:
輸入:實(shí)時(shí)更新的半結(jié)構(gòu)化數(shù)據(jù)A
輸出:字節(jié)數(shù)組
步驟為:
①while(A更新一次)
②A向上轉(zhuǎn)型成Object類(lèi)A';
③從對(duì)象流中讀取對(duì)象A',寫(xiě)入內(nèi)存;
④捕獲內(nèi)存緩沖區(qū)數(shù)據(jù)A',轉(zhuǎn)換成字節(jié)數(shù)組B;
⑤endwhile
⑥r(nóng)eturnB
(2)readObject()方法:利用抽象類(lèi)Object類(lèi)的readObject方法將字節(jié)數(shù)組轉(zhuǎn)化為Object類(lèi),具體的反序列化過(guò)程如下:
輸入:字節(jié)數(shù)組
輸出:原始數(shù)據(jù)A'
步驟為:
①將字節(jié)數(shù)組B轉(zhuǎn)化為輸入流B';
②將輸入流中的數(shù)據(jù)B'輸入對(duì)象輸入流B'';
③從流中讀取對(duì)象,恢復(fù)對(duì)象狀態(tài),得到A';
④returnA'
數(shù)據(jù)發(fā)送方通過(guò)Java對(duì)象序列化技術(shù),先將對(duì)象向上轉(zhuǎn)型成父類(lèi)Object類(lèi),然后通過(guò)writeObject()方法將對(duì)象序列化成二進(jìn)制流,數(shù)據(jù)接收方經(jīng)由readObject()方法將接收到的二進(jìn)制流反序列化為抽象類(lèi)Object類(lèi),然后再向下轉(zhuǎn)型為原始數(shù)據(jù)類(lèi)型。
2.3 對(duì)敏感數(shù)據(jù)字段進(jìn)行加密
一些數(shù)據(jù)中可能存在敏感字段,比如年齡、性別、電話(huà)號(hào)碼、密碼等等,圖像也可能涉及機(jī)密或隱私,序列化的優(yōu)點(diǎn)是序列化之后的數(shù)據(jù)格式比較簡(jiǎn)單且統(tǒng)一,可以對(duì)其運(yùn)用DES[10]、AES[11]、RSA[12]、MD5[13]等經(jīng)典加密算法或者自定義加密算法進(jìn)行加密。數(shù)據(jù)發(fā)送方將加密后的二進(jìn)制流寫(xiě)入Redis,數(shù)據(jù)接收方需先將接收到的二進(jìn)制流進(jìn)行解密,再進(jìn)行反序列化。即使key值被泄露,value值還需先解密才能被成功的反序列化,對(duì)于無(wú)密鑰的數(shù)據(jù)攔截者而言無(wú)法獲取原始數(shù)據(jù),從而保證了數(shù)據(jù)的安全。
3.1 實(shí)驗(yàn)環(huán)境
設(shè)計(jì)了基于流計(jì)算平臺(tái)Storm的實(shí)驗(yàn)來(lái)測(cè)試所設(shè)計(jì)的序列化算法的性能。
Storm是Twitter支持開(kāi)發(fā)的一款分布式的、實(shí)時(shí)的、主從式大數(shù)據(jù)流式計(jì)算系統(tǒng)[14]。實(shí)時(shí)性主要體現(xiàn)在其可以處理流數(shù)據(jù)而非靜態(tài)數(shù)據(jù),并實(shí)時(shí)更新計(jì)算結(jié)果[6],主從架構(gòu)由一個(gè)主節(jié)點(diǎn)Nimbus和多個(gè)工作節(jié)點(diǎn)Supervisor組成。Nimbus負(fù)責(zé)在集群中分發(fā)代碼,分配計(jì)算任務(wù)給機(jī)器,并且監(jiān)控集群狀態(tài)。Supervisor負(fù)責(zé)監(jiān)聽(tīng)分配給它的機(jī)器的工作,根據(jù)需要啟動(dòng)或關(guān)閉工作進(jìn)程。
實(shí)驗(yàn)的硬件環(huán)境:內(nèi)存8 GB,CPU為主頻2.7 GHz的i7處理器,1個(gè)Nimbus節(jié)點(diǎn)、2個(gè)Supervisor節(jié)點(diǎn)的Storm集群。
軟件環(huán)境:Storm0.9.1,JRE1.7,Zookeeper-3.4.6、redis-2.4.5。
操作系統(tǒng):Centos6.4。
編程語(yǔ)言:Java。
3.2 序列化算法的正確性測(cè)試
(1)采用文件流序列化非結(jié)構(gòu)化數(shù)據(jù)的測(cè)試結(jié)果。
將需要測(cè)試的商品號(hào)(1417,2227,3967,7237,8467,10477,10777…)序列化后存入Redis,然后反序列化寫(xiě)入路徑Pubic/sundujing下的test_items.txt中,如圖2(a)所示,文件內(nèi)容如圖2(b)所示,與原始數(shù)據(jù)一致。
圖2 采用文件流序列化非結(jié)構(gòu)化數(shù)據(jù)
(2)圖數(shù)據(jù)序列化測(cè)試結(jié)果。
圖數(shù)據(jù)序列化的測(cè)試情況如圖3所示。對(duì)圖3(a)的序列化結(jié)果為[B@17ee8b8,反序列化結(jié)果為圖3(b)。
圖3 圖數(shù)據(jù)序列化
(3)半結(jié)構(gòu)化數(shù)據(jù)序列化測(cè)試結(jié)果。
半結(jié)構(gòu)化數(shù)據(jù)的序列化與反序列化以簡(jiǎn)單的商品信息ITEM為例,ITEM有商品號(hào)item_id、商品所屬類(lèi)目號(hào)cat_id、商品標(biāo)題分詞后的結(jié)果terms這三個(gè)屬性。一個(gè)簡(jiǎn)單的實(shí)例item:商品號(hào)29、商品所屬類(lèi)目號(hào)155、商品標(biāo)題分詞為123950,53517,106068,59598,7503,171811,25618,147905。JSON序列化結(jié)果為item----{"item_id":"29","cat_id":"155" , "terms":"123950,53517,106068,59598,7503,171811,25618,147905"};Java對(duì)象序列化結(jié)果為[B@fa3ac1,經(jīng)過(guò)反序列化后,能得到原始數(shù)據(jù)實(shí)例item。
3.3 序列化算法的效率測(cè)試
以下通過(guò)Redis存取序列化數(shù)據(jù)的性能來(lái)體現(xiàn)序列化算法的效率。采用用戶(hù)購(gòu)買(mǎi)記錄作為數(shù)據(jù)集,如圖4所示,三個(gè)字段分別為用戶(hù)id、商品id、用戶(hù)購(gòu)買(mǎi)時(shí)間。將用戶(hù)id作為key值,將用戶(hù)購(gòu)買(mǎi)的商品id作為value值存入對(duì)應(yīng)的用戶(hù)id中,用50萬(wàn)、100萬(wàn)、150萬(wàn)條購(gòu)買(mǎi)記錄進(jìn)行測(cè)試,Redis測(cè)試所需時(shí)間如圖5所示。
Redis官方聲明過(guò),Redis在極佳的情況下能達(dá)到每秒10萬(wàn)次讀寫(xiě),而在該次實(shí)驗(yàn)中50萬(wàn)條數(shù)據(jù)序列化后存入只需40 s,并且隨著需處理的數(shù)據(jù)條數(shù)的增長(zhǎng),時(shí)間呈線(xiàn)性增長(zhǎng),不會(huì)因此導(dǎo)致內(nèi)存激增而影響其他線(xiàn)程的執(zhí)行,由此可以看出Redis存取序列化后的數(shù)據(jù)的性能很高且穩(wěn)定。
圖4 測(cè)試數(shù)據(jù)集截圖
圖5 Redis時(shí)效測(cè)試結(jié)果
基于Redis的特點(diǎn)和流式實(shí)時(shí)計(jì)算平臺(tái)對(duì)半結(jié)構(gòu)化和非結(jié)構(gòu)化數(shù)據(jù)的處理需求,設(shè)計(jì)了面向Redis的數(shù)據(jù)序列化算法,借助文件序列化、圖像序列化、JSON序列化和Java對(duì)象序列化技術(shù),解決了Redis無(wú)法直接存儲(chǔ)半結(jié)構(gòu)化與非結(jié)構(gòu)化數(shù)據(jù)的問(wèn)題,并在流數(shù)據(jù)處理平臺(tái)Storm上通過(guò)實(shí)驗(yàn)證明了該算法能有效解決實(shí)時(shí)計(jì)算中半結(jié)構(gòu)化與非結(jié)構(gòu)化數(shù)據(jù)的存儲(chǔ)和實(shí)時(shí)讀取問(wèn)題。
在海量數(shù)據(jù)實(shí)時(shí)計(jì)算中,無(wú)論使用哪種開(kāi)發(fā)語(yǔ)言,使用Redis作為數(shù)據(jù)庫(kù)并采用設(shè)計(jì)的序列化算法,一方面,當(dāng)需要被處理的數(shù)據(jù)很大時(shí),能有效降低系統(tǒng)的內(nèi)存消耗和網(wǎng)絡(luò)傳輸;另一方面,不僅可以利用Redis帶來(lái)的高性能讀寫(xiě)效率,而且可以存儲(chǔ)任何半結(jié)構(gòu)化數(shù)據(jù)甚至非結(jié)構(gòu)化數(shù)據(jù)對(duì)象而無(wú)須重復(fù)開(kāi)發(fā)代碼,所設(shè)計(jì)的序列化算法能高效地解決半結(jié)構(gòu)化和非結(jié)構(gòu)化數(shù)據(jù)的存儲(chǔ)問(wèn)題。
[1] 蔡金花.淺析NOSQL及使用[J].電腦知識(shí)與技術(shù),2011,7(12):2757-2758.
[2] 宗 平,吳秀娟.基于NoSQL系統(tǒng)的組合索引技術(shù)研究[J].計(jì)算機(jī)技術(shù)與發(fā)展,2014,24(12):53-56.
[3] 曾泉?jiǎng)?基于Redis的分布式消息服務(wù)的設(shè)計(jì)與實(shí)現(xiàn)[D].北京:北京郵電大學(xué),2014.
[4] 蘇翔宇.Key-Value數(shù)據(jù)庫(kù)及其應(yīng)用研究[C]//中國(guó)職協(xié)2013年度優(yōu)秀科研成果獲獎(jiǎng)?wù)撐募?下冊(cè)).出版地不詳:出版者不詳,2013.
[5] 羅 軍,陳席林,李文生.高效Key-Value持久化緩存系統(tǒng)的實(shí)現(xiàn)[J].計(jì)算機(jī)工程,2014,40(3):33-38.
[6] Anderson Q.Storm real-time processing cookbook[M].Birmingham:Packt Publishing,2013.
[7] 張 濤,黃 強(qiáng),毛磊雅,等.一個(gè)基于JSON的對(duì)象序列化算法[J].計(jì)算機(jī)工程與應(yīng)用,2007,43(15):98-100.
[8] 袁曉銘,林 安.幾種主流快照技術(shù)的分析比較[J].微處理機(jī),2008,29(1):127-130.
[9] Surhone L M,Tennoe M T,Henssonow S F,et al.Object exchange model[M].[s.l.]:Betascript Publishing,2010.
[10] 李少芳.DES算法加密過(guò)程的探討[J].計(jì)算機(jī)與現(xiàn)代化,2006(8):102-104.
[11] 何明星,林 昊.AES算法原理及其實(shí)現(xiàn)[J].計(jì)算機(jī)應(yīng)用研究,2002,19(12):61-63.
[12] 陳傳波,祝中濤.RSA算法應(yīng)用及實(shí)現(xiàn)細(xì)節(jié)[J].計(jì)算機(jī)工程與科學(xué),2006,28(9):13-14.
[13] 張裔智,趙 毅,湯小斌.MD5算法研究[J].計(jì)算機(jī)科學(xué),2008,35(7):295-297.
[14] 李 浩,羅云彬,王志軍,等.基于分布式流式計(jì)算系統(tǒng)的任務(wù)處理方法、系統(tǒng)及節(jié)點(diǎn):CN,CN 103763378A[P].2014.
Investigation on Data Serialization Algorithm for Redis
SUN Du-jing,LI Ling-juan
(School of Computer,Nanjing University of Posts and Telecommunications,Nanjing 210003,China)
In order to deal with the problem of storing semi-structured and unstructured data in real-time calculation,a data serialization algorithm for Redis is designed.It takes advantage of Redis which can store key-value data and support full memory operation and uses the technologies of file serialization,image serialization,JSON serialization and Java object serialization.The algorithm can not only solve the problem that the semi-structured and unstructured data cannot be directly stored into Redis,but also enable the deserialization to restore the original data perfectly by keeping a deep copy of the data.In addition,encrypting and decrypting can be added to the serialization process to ensure the security of data.The experimental results on Storm platform show that the proposed algorithm is fast,effective and stable.In the real-time processing of massive data integration,this algorithm with Redis can not only make reading and writing highly efficient,but also store any semi-structured and unstructured data without rewriting code no matter which programming language is employed.
Redis;serialization;semi-structured;unstructured;Storm
2016-06-20
2016-09-22 網(wǎng)絡(luò)出版時(shí)間:2017-03-07
國(guó)家自然科學(xué)基金資助項(xiàng)目(61302158,61571238)
孫杜靖(1992-),女,碩士研究生,CCF會(huì)員,研究方向?yàn)榱鲾?shù)據(jù)挖掘;李玲娟,教授,CCF會(huì)員,研究方向?yàn)閿?shù)據(jù)挖掘、信息安全、分布式計(jì)算。
http://kns.cnki.net/kcms/detail/61.1450.TP.20170307.0922.086.html
TP391
A
1673-629X(2017)05-0077-05
10.3969/j.issn.1673-629X.2017.05.017