基于Lua的TTLB內(nèi)Servlet批量查詢HBase數(shù)據(jù)方法
【技術(shù)領(lǐng)域】
[0001]本發(fā)明涉及一種數(shù)據(jù)處理方法,尤其涉及一種基于Lua的TTLB內(nèi)Servlet批量查詢HBase數(shù)據(jù)方法。
【背景技術(shù)】
[0002]HBase是一個(gè)支持非結(jié)構(gòu)化存儲(chǔ)的高可靠性、高性能、可伸縮的開源數(shù)據(jù)庫。采用Servlet訪問HBase可能發(fā)生兩個(gè)線程同時(shí)訪問同一資源,造成數(shù)據(jù)不一致,導(dǎo)致線程不安全。Servlet規(guī)范、Java教材、Internet和相關(guān)文獻(xiàn)指出:現(xiàn)有解決線程不安全的方法主要有:實(shí)現(xiàn)SingleThreadModel接口、同步共享數(shù)據(jù)、避免對象實(shí)例、增加延時(shí)。
[0003]1、實(shí)現(xiàn) SingleThreadModel 接口
[0004]實(shí)現(xiàn)了 SingleThreadModel接口,Servlet容器保證只有一個(gè)線程servlet實(shí)例在運(yùn)行,而其它請求排隊(duì)等待。
[0005]2、同步共享數(shù)據(jù)
[0006]synchronized防止異步調(diào)用,每次只有一個(gè)線程訪問同步代碼塊。
[0007]3、避免對象實(shí)例
[0008]全局變量或者共享變量造成了線程不安全;而局部變量保證了線程安全。
[0009]4、增加延時(shí)
[0010]采用sleep函數(shù)增加延時(shí),使得只有一個(gè)線程修改全局變量或者共享變量,而其它線程處于阻塞狀態(tài):還沒有將修改的數(shù)據(jù)刷新到內(nèi)存。
[0011]以上四種方法雖能設(shè)計(jì)出線程安全的Servlet,但存在系統(tǒng)開銷大、降低系統(tǒng)并發(fā)處理性能、難確定阻塞時(shí)間。對于實(shí)現(xiàn)SingleThreadModel接口方法,Servlet為每個(gè)請求創(chuàng)建一個(gè)單獨(dú)Servlet實(shí)例,大量Servlet實(shí)例將引起系統(tǒng)大量的開銷。對于避免使用實(shí)例對象方法,采用局部變量將增大每個(gè)線程的私有棧。對于同步共享數(shù)據(jù)方法,每一時(shí)刻只允許一個(gè)線程執(zhí)行同步代碼,其它線程處于同步阻塞狀態(tài),這將降低系統(tǒng)的并發(fā)處理性能。對于增加延時(shí)方法,如果延時(shí)太短,當(dāng)前線程還沒有處理完,而處于阻塞狀態(tài)的線程因睡眠時(shí)間結(jié)束開始運(yùn)行,可能造成線程不安全;如果延時(shí)過長(如超過10秒),則根據(jù)國際3/5/10原則,用戶很難接受長時(shí)間等待,增加延時(shí)方法很難確定:經(jīng)過多長延時(shí)線程才安全又讓等待在用戶可接受范圍內(nèi)?
[0012]HBase面向海量數(shù)據(jù)存儲(chǔ),當(dāng)大規(guī)模用戶采用Servlet訪問HBase時(shí),以上四種方法的問題在Servlet訪問HBase中更為突出。不僅存在系統(tǒng)開銷大、降低系統(tǒng)并發(fā)處理性能、難確定阻塞時(shí)間,而且還會(huì)引發(fā)更嚴(yán)重的問題:根據(jù)HBase規(guī)范,HTable.get (Get)和HTable.put (Put)方法在多線程環(huán)境下也是不安全的。一般對HBase表記錄的查詢和存儲(chǔ),需分開處理。
【發(fā)明內(nèi)容】
[0013]本發(fā)明旨在提供一種基于Lua的TTLB內(nèi)Tomcat批量查詢HBase數(shù)據(jù)方法,通過Lua表緩存TTLB內(nèi)查詢請求,該方法確保了 Servlet并發(fā)查詢HBase的線程安全,允許Tomcat能接納更大規(guī)模的用戶訪問,還減少了 HBase集群網(wǎng)絡(luò)I/O。
[0014]為達(dá)到上述目的,本發(fā)明是采用以下技術(shù)方案實(shí)現(xiàn)的:
[0015]本發(fā)明公開的基于Lua的TTLB內(nèi)Servlet批量查詢HBase表數(shù)據(jù)方法,包括以下步驟:
[0016]步驟1、建立 Wrapper 類、LuaScript 函數(shù)和 ReadHBase 類,
[0017]所述Wrapper類用于將查詢請求緩存在Lua表中,以及從Lua表中快速檢索查詢結(jié)果;
[0018]所述LuaScript函數(shù)用于打包TTLB內(nèi)所有線程并發(fā)查詢請求,調(diào)用ReadHBase類的Java API完成批量查詢HBase表記錄,解包返回結(jié)果并生成每個(gè)線程的返回結(jié)果;
[0019]所述ReadHBase類用于解包從LuaScript傳過來的參數(shù),調(diào)用Java API函數(shù)HTable.get (List〈Get>),打包該get函數(shù)的返回結(jié)果;
[0020]步驟2、獲取Wrapper類對象實(shí)例:包括獲取欲查詢HBase表和欲查詢表行,產(chǎn)生查詢請求標(biāo)識(shí);
[0021]步驟3、將欲查詢HBase表、欲查詢HBase表行和查詢請求標(biāo)識(shí)緩存在Lua表Readqueue 中;
[0022]步驟4、通過LuaScript打包TTLB內(nèi)批量查詢請求;
[0023]步驟5、通過ReadHBase解包TTLB內(nèi)批量查詢請求;
[0024]步驟6、調(diào)用 Java API 函數(shù) HTable.get (List〈Get>);
[0025]步驟7、通過ReadHBase打包批量查詢的結(jié)果;
[0026]步驟8、通過LuaScript解包批量查詢的結(jié)果;
[0027]步驟9、生成線程調(diào)用結(jié)果;
[0028]步驟10、獲取查詢結(jié)果。
[0029]進(jìn)一步的,在步驟3結(jié)束時(shí),檢測布爾型變量startscheduler,當(dāng)startscheduler為false時(shí),將startscheduler賦值為true并進(jìn)入步驟4,在步驟9結(jié)束時(shí)將startscheduler 賦值為 false ;當(dāng) startscheduler 為 true 時(shí),直接轉(zhuǎn)到步驟 10。
[0030]進(jìn)一步的,在步驟10完成后,還包括檢測查詢是否完成,當(dāng)檢測查詢完成為真時(shí),清空檢測查詢,然后結(jié)束;當(dāng)檢測查詢完成為假時(shí),直接結(jié)束。
[0031]優(yōu)選的,在步驟2中,通過查詢請求標(biāo)識(shí)作為下標(biāo)索引快速定位Lua表中的嵌套表元素。
[0032]優(yōu)選的,在步驟4中,所述打包是將欲查詢HBase表行關(guān)鍵字打包成字符串;
[0033]在步驟5中,所述解包是將所述字符串解包成HBase表行關(guān)鍵字。
[0034]本發(fā)明針對HBase表的查詢。HTable.get (Get)是單條記錄查詢,每次查詢都需要HBase集群網(wǎng)絡(luò)一次I/O ;HTable.get (List〈Get>)支持批量查詢,與單條查詢相比較,批量查詢的優(yōu)勢在于:完成一次批量查詢只需要一次HBase集群網(wǎng)絡(luò)1/0,節(jié)省了 HBase集群網(wǎng)絡(luò)帶寬,因此本發(fā)明針對HBase批量查詢。
[0035]要采用HTable.get (List〈Get>)實(shí)現(xiàn)批量查詢HBase數(shù)據(jù),需緩存Servlet批量查詢請求。通常方法是通過vector緩存批量查詢請求實(shí)現(xiàn)HBase表查詢,其原理(要點(diǎn))如下:
[0036]1、將HBase表的列族和列成員(標(biāo)簽)封裝為事件類;
[0037]2、將Tomcat批量查詢請求緩存在vector中;
[0038]3、注冊查詢事件;
[0039]4、查詢HBase表完成,觸發(fā)查詢事件。
[0040]利用vector緩存查詢請求存在以下3個(gè)問題:首先,對于每個(gè)HBase表都要設(shè)計(jì)一個(gè)事件類,一個(gè)事件類不適用于所有HBase表;其次,HBase表最大可以支持上百萬列數(shù)據(jù)的存儲(chǔ),事件類的數(shù)據(jù)成員數(shù)量非常龐大,運(yùn)行這種事件類要占用很大內(nèi)存,但很多記錄數(shù)據(jù)又是稀疏的,將造成內(nèi)存大量浪費(fèi);最后,在批量查詢結(jié)果中,很難檢測出HBase表沒有欲查詢記錄的空返回。Lua表支持key-value鍵值對存儲(chǔ)、表中元素類型異構(gòu)、表中嵌套表,可以采用Lua表緩存TTLB內(nèi)Servlet批量查詢請求。
[0041]本發(fā)明的有益效果如下:
[0042](I)采用Lua表緩存TTLB內(nèi)查詢請求,保證了 Servlet的多線程安全。
[0043](2)采用TTLB內(nèi)批量查詢,既在用戶可接受的請求響應(yīng)時(shí)間內(nèi)返回查詢結(jié)果,又減少了 HBase集群網(wǎng)絡(luò)I/O。
[0044](3)通過打包解包批量查詢請求和查詢結(jié)果,能夠查詢?nèi)我釮Base表記錄。
[0045](4) Lua表支持字符串作為嵌套表元素索引,能夠快速檢索查詢結(jié)果。
[0046](5)單實(shí)例類和僅僅處理HBase表有數(shù)據(jù)的列,減少了系統(tǒng)內(nèi)存開銷,使得Tomcat能接納更大規(guī)模的用戶訪問。
【附圖說明】
[0047]圖1為本發(fā)明的處理流程圖。
【具體實(shí)施方式】
[0048]為了使本發(fā)明的目的、技術(shù)方案及優(yōu)點(diǎn)更加清楚明白,以下結(jié)合附圖,對本發(fā)明進(jìn)行進(jìn)一步詳細(xì)說明。
[0049]如圖1所示,本發(fā)明公開的基于Lua的TTLB內(nèi)Servlet批量查詢HBase表數(shù)據(jù)方法,包括以下步驟:
[0050]步驟1、建立 Wrapper 類、LuaScript 函數(shù)和 ReadHBase 類,
[0051]所述Wrapper類用于將查詢請求緩存在Lua表中,以及從Lua表中快速檢索查詢結(jié)果;
[0052]所述LuaScript函數(shù)用于打包TTLB內(nèi)所有線程并發(fā)查詢請求,調(diào)用ReadHBase類的Java API完成批量查詢HBase表記錄,解包返回結(jié)果并生成每個(gè)線程的返回結(jié)果;
[0053]所述ReadHBase類用于解包從LuaScript傳過來的參數(shù),調(diào)用Java API函數(shù)HTable.get (List〈Get>),打包該get函數(shù)的返回結(jié)果;
[0054]步驟2、獲取Wrapper類對象實(shí)例:包括獲取欲查詢HBase表tabIename和欲查詢表行rowkey,產(chǎn)生查詢請求標(biāo)識(shí)uui ;由于Lua表支持key-value鍵值對緩存,所以可通過uuid作為下標(biāo)索引能快速定位Lua表中的嵌套表元素;
[0055]步驟3、將欲查詢HBase表tabIename、欲查詢HBase表行rowkey和查詢請求標(biāo)識(shí)uui 緩存在 Lua 表 Readqueue 中;檢測布爾型變量 startscheduler,當(dāng) startscheduler 為false時(shí),將startscheduler賦值為true并進(jìn)入步驟4,在步驟9結(jié)束時(shí)將startscheduler賦值為false ;當(dāng)startscheduler為true時(shí),直接轉(zhuǎn)到步驟10 ;
[0056]步驟4、通過LuaScript打包TTLB內(nèi)批量查詢請求;
[0057]步驟5、通過ReadHBase解包TTLB內(nèi)批量查詢請求;
[0058]步驟6、調(diào)用 Java API 函數(shù) HTable.get (List〈Get>);
[0059]步驟7、通過ReadHBase打包批量查詢的結(jié)果;
[0060]步驟8、通過LuaScript解包批量查詢的結(jié)果;
[0061]步驟9、生成線程調(diào)用結(jié)果;
[0062]步驟10、獲取查詢結(jié)果:檢測查詢是否完成,當(dāng)檢測查詢完成為真時(shí),清空檢測查詢,然后結(jié)束;當(dāng)檢測查詢完成為假時(shí),直接結(jié)束。
[0063]在LuaScript中,打包TTLB內(nèi)所有線程并發(fā)查詢請求,調(diào)用ReadHBase類的JavaAPI完成批量查詢HBase表記錄,解包返回結(jié)果并生成每個(gè)線程的返回結(jié)果。在ReadHBase類中,解包從LuaScript傳過來的參數(shù),調(diào)用Java API函數(shù)HTable.get (List〈Get>),打包該get函數(shù)的返回結(jié)果。在LuaScript中對欲查詢HBase表行關(guān)鍵字打包成字符串,在ReadHBase類中將該字符串解包成HBase表行關(guān)鍵字;同時(shí),在ReadHBase類中對get (List<Get>)的返回結(jié)果打包成字符串,在LuaScript中將返回結(jié)果解包,通過這種打包解包批量查詢請求和批量查詢結(jié)果,能實(shí)現(xiàn)對任意HBase表的批量查詢,增強(qiáng)了本發(fā)明的通用性和實(shí)用性。
[0064]本發(fā)明所涉及的類和函數(shù)及實(shí)施方式如下:
[0065]一'Wrapper 類
[0066]初始化ReadHBase 類,通過 Luajava 插件調(diào)用 LuaScript 的 Lua API 向 Servlet提供服務(wù):setReadParameter將查詢請求緩存到LuaScript的Readqueue表中;getResult從Readqueue中快速查找查詢結(jié)果。另外,由TTLB內(nèi)的第一個(gè)線程調(diào)用schedule完成批量查詢(其它線程返回,等待或者查找查詢結(jié)果)。
[0067]Wrapper類的數(shù)據(jù)成員:
[0068]K private Boolean startscheduler ;//是否已經(jīng)啟動(dòng)批量查詢請求執(zhí)行線程
[0069]private static W