Hadoop之Hbase從入門到精通_第1頁
Hadoop之Hbase從入門到精通_第2頁
Hadoop之Hbase從入門到精通_第3頁
Hadoop之Hbase從入門到精通_第4頁
Hadoop之Hbase從入門到精通_第5頁
已閱讀5頁,還剩72頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡介

1、一、 HBase性能調(diào)優(yōu)我們經(jīng)??吹揭恍┪恼麓祰u某產(chǎn)品如何如何快,如何如何強(qiáng),而自己測試時(shí)卻不如描述的一些數(shù)據(jù)。其實(shí)原因可能在于你還不是真正理解其內(nèi)部結(jié)構(gòu),對于其性能調(diào)優(yōu)方法不夠了解。本文轉(zhuǎn)自TaoBao的Ken Wu同學(xué)的博客,是目前看到比較完整的HBase調(diào)優(yōu)文章。原文鏈接:HBase性能調(diào)優(yōu)因官方Book Performance Tuning部分章節(jié)沒有按配置項(xiàng)進(jìn)行索引,不能達(dá)到快速查閱的效果。所以我以配置項(xiàng)驅(qū)動,重新整理了原文,并補(bǔ)充一些自己的理解,如有錯誤,歡迎指正。配置優(yōu)化默認(rèn)值:3分鐘(180000ms)說明:RegionServer與Zookeeper間的連接超時(shí)時(shí)間。當(dāng)超時(shí)時(shí)

2、間到后,ReigonServer會被Zookeeper從RS集群清單中移除,HMaster收到移除通知后,會對這臺server負(fù)責(zé)的regions重新balance,讓其他存活的RegionServer接管.調(diào)優(yōu):這個(gè)timeout決定了RegionServer是否能夠及時(shí)的failover。設(shè)置成1分鐘或更低,可以減少因等待超時(shí)而被延長的failover時(shí)間。不過需要注意的是,對于一些Online應(yīng)用,RegionServer從宕機(jī)到恢復(fù)時(shí)間本身就很短的(網(wǎng)絡(luò)閃斷,crash等故障,運(yùn)維可快速介入),如果調(diào)低timeout時(shí)間,反而會得不償失。因?yàn)楫?dāng)ReigonServer被正式從RS集群中

3、移除時(shí),HMaster就開始做balance了(讓其他RS根據(jù)故障機(jī)器記錄的WAL日志進(jìn)行恢復(fù))。當(dāng)故障的RS在人工介入恢復(fù)后,這個(gè)balance動作是毫無意義的,反而會使負(fù)載不均勻,給RS帶來更多負(fù)擔(dān)。特別是那些固定分配regions的場景。hbase默認(rèn)值:10說明:RegionServer的請求處理IO線程數(shù)。調(diào)優(yōu):這個(gè)參數(shù)的調(diào)優(yōu)與內(nèi)存息息相關(guān)。較少的IO線程,適用于處理單次請求內(nèi)存消耗較高的Big PUT場景(大容量單次PUT或設(shè)置了較大cache的scan,均屬于Big PUT)或ReigonServer的內(nèi)存比較緊張的場景。較多的IO線程,適用于單次請求內(nèi)存消耗低,TPS要求非常高

4、的場景。設(shè)置該值的時(shí)候,以監(jiān)控內(nèi)存為主要參考。這里需要注意的是如果server的region數(shù)量很少,大量的請求都落在一個(gè)region上,因快速充滿memstore觸發(fā)flush導(dǎo)致的讀寫鎖會影響全局TPS,不是IO線程數(shù)越高越好。壓測時(shí),開啟Enabling RPC-level logging,可以同時(shí)監(jiān)控每次請求的內(nèi)存消耗和GC的狀況,最后通過多次壓測結(jié)果來合理調(diào)節(jié)IO線程數(shù)。這里是一個(gè)案例 Hadoop and HBase Optimization for Read Intensive Search Applications,作者在SSD的機(jī)器上設(shè)置IO線程數(shù)為100,僅供參考

5、。默認(rèn)值:256M說明:在當(dāng)前ReigonServer上單個(gè)Reigon的最大存儲空間,單個(gè)Region超過該值時(shí),這個(gè)Region會被自動split成更小的region。調(diào)優(yōu):小region對split和compaction友好,因?yàn)椴鸱謗egion或compact小region里的storefile速度很快,內(nèi)存占用低。缺點(diǎn)是split和compaction會很頻繁。特別是數(shù)量較多的小region不停地split, compaction,會導(dǎo)致集群響應(yīng)時(shí)間波動很大,region數(shù)量太多不僅給管理上帶來麻煩,甚至?xí)l(fā)一些Hbase的bug。一般512以下的都算小region。大region

6、,則不太適合經(jīng)常split和compaction,因?yàn)樽鲆淮蝐ompact和split會產(chǎn)生較長時(shí)間的停頓,對應(yīng)用的讀寫性能沖擊非常大。此外,大region意味著較大的storefile,compaction時(shí)對內(nèi)存也是一個(gè)挑戰(zhàn)。當(dāng)然,大region也有其用武之地。如果你的應(yīng)用場景中,某個(gè)時(shí)間點(diǎn)的訪問量較低,那么在此時(shí)做compact和split,既能順利完成split和compaction,又能保證絕大多數(shù)時(shí)間平穩(wěn)的讀寫性能。既然split和compaction如此影響性能,有沒有辦法去掉?compaction是無法避免的,split倒是可以從自動調(diào)整為手動。只要通過將這個(gè)參數(shù)值調(diào)大到某個(gè)很

7、難達(dá)到的值,比如100G,就可以間接禁用自動split(RegionServer不會對未到達(dá)100G的region做split)。再配合RegionSplitter這個(gè)工具,在需要split時(shí),手動split。手動split在靈活性和穩(wěn)定性上比起自動split要高很多,相反,管理成本增加不多,比較推薦online實(shí)時(shí)系統(tǒng)使用。內(nèi)存方面,小region在設(shè)置memstore的大小值上比較靈活,大region則過大過小都不行,過大會導(dǎo)致flush時(shí)app的IO wait增高,過小則因store file過多影響讀性能。默認(rèn)值:0.4/0.35upperlimit說明:hbase.hregion.m

8、emstore.flush.size 這個(gè)參數(shù)的作用是 當(dāng)單個(gè)memstore達(dá)到指定值時(shí),flush該memstore。但是,一臺ReigonServer可能有成百上千個(gè)memstore,每個(gè)memstore也許未達(dá)到flush.size,jvm的heap就不夠用了。該參數(shù)就是為了限制memstores占用的總內(nèi)存。當(dāng)ReigonServer內(nèi)所有的memstore所占用的內(nèi)存總和達(dá)到heap的40%時(shí),HBase會強(qiáng)制block所有的更新并flush這些memstore以釋放所有memstore占用的內(nèi)存。lowerLimit說明: 同upperLimit,只不過當(dāng)全局memstore的內(nèi)

9、存達(dá)到35%時(shí),它不會flush所有的memstore,它會找一些內(nèi)存占用較大的memstore,做個(gè)別flush,當(dāng)然更新還是會被block。lowerLimit算是一個(gè)在全局flush導(dǎo)致性能暴跌前的補(bǔ)救措施。為什么說是性能暴跌?可以想象一下,如果memstore需要在一段較長的時(shí)間內(nèi)做全量flush,且這段時(shí)間內(nèi)無法接受任何讀寫請求,對HBase集群的性能影響是很大的。調(diào)優(yōu):這是一個(gè)Heap內(nèi)存保護(hù)參數(shù),默認(rèn)值已經(jīng)能適用大多數(shù)場景。它的調(diào)整一般是為了配合某些專屬優(yōu)化,比如讀密集型應(yīng)用,將讀緩存開大,降低該值,騰出更多內(nèi)存給其他模塊使用。這個(gè)參數(shù)會給使用者帶來什么影響?比如,10G內(nèi)存,1

10、00個(gè)region,每個(gè)memstore 64M,假設(shè)每個(gè)region只有一個(gè)memstore,那么當(dāng)100個(gè)memstore平均占用到50%左右時(shí),就會達(dá)到lowerLimit的限制。假設(shè)此時(shí),其他memstore同樣有很多的寫請求進(jìn)來。在那些大的region未flush完,就可能又超過了upperlimit,則所有region都會被block,開始觸發(fā)全局flush。不過,除了你的內(nèi)存非常小或你的應(yīng)用場景里大多數(shù)都是讀,我覺得不需要去調(diào)這個(gè)參數(shù)。默認(rèn)值:0.2說明:storefile的讀緩存占用Heap的大小百分比,0.2表示20%。該值直接影響數(shù)據(jù)讀的性能。調(diào)優(yōu):當(dāng)然是越大越好,如果讀比

11、寫少,開到0.4-0.5也沒問題。如果讀寫較均衡,0.3左右。如果寫比讀多,果斷默認(rèn)吧。設(shè)置這個(gè)值的時(shí)候,你同時(shí)要參考 hbase.regionserver.global.memstore.upperLimit ,該值是memstore占heap的最大百分比,兩個(gè)參數(shù)一個(gè)影響讀,一個(gè)影響寫。如果兩值加起來超過80-90%,會有OOM的風(fēng)險(xiǎn),謹(jǐn)慎設(shè)置。默認(rèn)值:7說明:在compaction時(shí),如果一個(gè)Store(Coulmn Family)內(nèi)有超過7個(gè)storefile需要合并,則block所有的寫請求,進(jìn)行flush,限制storefile數(shù)量增長過快。調(diào)優(yōu):block寫請求會影響當(dāng)前regi

12、on的性能,將值設(shè)為單個(gè)region可以支撐的最大store file數(shù)量會是個(gè)不錯的選擇,即允許comapction時(shí),memstore繼續(xù)生成storefile。最大storefile數(shù)量可通過region size/memstore size來計(jì)算。如果你將region size設(shè)為無限大,那么你需要預(yù)估一個(gè)region可能產(chǎn)生的最大storefile數(shù)。默認(rèn)值:2說明:當(dāng)一個(gè)region里的memstore超過單個(gè)memstore.size兩倍的大小時(shí),block該region的所有請求,進(jìn)行flush,釋放內(nèi)存。雖然我們設(shè)置了memstore的總大小,比如64M,但想象一下,在最后6

13、3.9M的時(shí)候,我Put了一個(gè)100M的數(shù)據(jù),此時(shí)memstore的大小會瞬間暴漲到超過預(yù)期的memstore.size。這個(gè)參數(shù)的作用是當(dāng)memstore的大小增至超過memstore.size時(shí),block所有請求,遏制風(fēng)險(xiǎn)進(jìn)一步擴(kuò)大。調(diào)優(yōu): 這個(gè)參數(shù)的默認(rèn)值還是比較靠譜的。如果你預(yù)估你的正常應(yīng)用場景(不包括異常)不會出現(xiàn)突發(fā)寫或?qū)懙牧靠煽?,那么保持默認(rèn)值即可。如果正常情況下,你的寫請求量就會經(jīng)常暴長到正常的幾倍,那么你應(yīng)該調(diào)大這個(gè)倍數(shù)并調(diào)整其他參數(shù)值,比如hfile.block.cache.size和hbase.regionserver.global.memstore.upperLimi

14、t/lowerLimit,以預(yù)留更多內(nèi)存,防止HBase server OOM。其他啟用LZO壓縮LZO對比Hbase默認(rèn)的GZip,前者性能較高,后者壓縮比較高,具體參見 Using LZO Compression。對于想提高HBase讀寫性能的開發(fā)者,采用LZO是比較好的選擇。對于非常在乎存儲空間的開發(fā)者,則建議保持默認(rèn)。不要在一張表里定義太多的Column FamilyHbase目前不能良好的處理超過包含2-3個(gè)CF的表。因?yàn)槟硞€(gè)CF在flush發(fā)生時(shí),它鄰近的CF也會因關(guān)聯(lián)效應(yīng)被觸發(fā)flush,最終導(dǎo)致系統(tǒng)產(chǎn)生更多IO。批量導(dǎo)入在批量導(dǎo)入數(shù)據(jù)到Hbase前,你可以通過預(yù)先創(chuàng)建

15、regions,來平衡數(shù)據(jù)的負(fù)載。詳見 Table Creation: Pre-Creating Regions避免CMS concurrent mode failureHBase使用CMS GC。默認(rèn)觸發(fā)GC的時(shí)機(jī)是當(dāng)年老代內(nèi)存達(dá)到90%的時(shí)候,這個(gè)百分比由 -XX:CMSInitiatingOccupancyFraction=N 這個(gè)參數(shù)來設(shè)置。concurrent mode failed發(fā)生在這樣一個(gè)場景:當(dāng)年老代內(nèi)存達(dá)到90%的時(shí)候,CMS開始進(jìn)行并發(fā)垃圾收集,于此同時(shí),新生代還在迅速不斷地晉升對象到年老代。當(dāng)年老代CMS還未完成并發(fā)標(biāo)記時(shí),年老代滿了,悲劇就發(fā)生了。CMS因

16、為沒內(nèi)存可用不得不暫停mark,并觸發(fā)一次全jvm的stop the world(掛起所有線程),然后采用單線程拷貝方式清理所有垃圾對象。這個(gè)過程會非常漫長。為了避免出現(xiàn)concurrent mode failed,我們應(yīng)該讓GC在未到90%時(shí),就觸發(fā)。通過設(shè)置 -XX:CMSInitiatingOccupancyFraction=N這個(gè)百分比, 可以簡單的這么計(jì)算。如果你的 hfile.block.cache.size 和 hbase.regionserver.global.memstore.upperLimit 加起來有60%(默認(rèn)),那么你可以設(shè)置 70-8

17、0,一般高10%左右差不多。Hbase客戶端優(yōu)化AutoFlush將HTable的setAutoFlush設(shè)為false,可以支持客戶端批量更新。即當(dāng)Put填滿客戶端flush緩存時(shí),才發(fā)送到服務(wù)端。默認(rèn)是true。Scan Cachingscanner一次緩存多少數(shù)據(jù)來scan(從服務(wù)端一次抓多少數(shù)據(jù)回來scan)。默認(rèn)值是 1,一次只取一條。Scan Attribute Selectionscan時(shí)建議指定需要的Column Family,減少通信量,否則scan操作默認(rèn)會返回整個(gè)row的所有數(shù)據(jù)(所有Coulmn Family)。Close ResultScanners通過scan取完數(shù)

18、據(jù)后,記得要關(guān)閉ResultScanner,否則RegionServer可能會出現(xiàn)問題(對應(yīng)的Server資源無法釋放)。Optimal Loading of Row Keys當(dāng)你scan一張表的時(shí)候,返回結(jié)果只需要row key(不需要CF, qualifier,values,timestaps)時(shí),你可以在scan實(shí)例中添加一個(gè)filterList,并設(shè)置 MUST_PASS_ALL操作,filterList中add FirstKeyOnlyFilter或KeyOnlyFilter。這樣可以減少網(wǎng)絡(luò)通信量。Turn off WAL on Puts當(dāng)Put某些非重要數(shù)據(jù)時(shí),你可以設(shè)

19、置writeToWAL(false),來進(jìn)一步提高寫性能。writeToWAL(false)會在Put時(shí)放棄寫WAL log。風(fēng)險(xiǎn)是,當(dāng)RegionServer宕機(jī)時(shí),可能你剛才Put的那些數(shù)據(jù)會丟失,且無法恢復(fù)。啟用Bloom FilterBloom Filter通過空間換時(shí)間,提高讀操作性能二、 關(guān)于HFile的思考本文是一篇轉(zhuǎn)載文章,原文作者郭鵬(逖靖寒),國內(nèi)Cassandra領(lǐng)域的先驅(qū)者和實(shí)踐者。資深軟件開發(fā)工程師,擅長分布式應(yīng)用程序的開發(fā)和使用,實(shí)踐經(jīng)驗(yàn)極其豐富。在本文中,作者推薦了HFile文件格式的經(jīng)典論文,并對HFile的block size的應(yīng)用進(jìn)行了實(shí)例探討。0.90.x

20、版本的HBase中的文件是存儲在HFile中的。關(guān)于HFile文件的詳細(xì)介紹,可以查看這篇文章:hfile.pdf這篇文章中介紹了以下五點(diǎn)內(nèi)容:· HFile的作用。· HFile的格式。· HFile的性能。· HFile的使用注意事項(xiàng)。· HFile的編程接口。HFile中有一個(gè)很重要的參數(shù),那就是block size。如果我們寫入hfile中的某一個(gè)value的值大于block size會怎么樣?于是有如下的測試代碼:/ create local file systemFileSystem fs = new RawLocalFileSys

21、tem();fs.setConf(new Configuration();/ block size = 1kbHFile.Writer hwriter = new HFile.Writer(fs, new Path("hfile"), 1, (Compression.Algorithm) null, null);/ create key & value, the value is 8kb, larger than 1kbbyte key = "".getBytes();byte value = new byte

22、8 * 1024;for (int i = 0; i < 8 * 1024; i+) valuei = '0'/ add values to hfilefor (int i = 0; i < 10; i+) hwriter.append(key, value);/ close hfilehwriter.close();上面的代碼可以看出來,每一個(gè)value的值都是8kb,已經(jīng)超過了hfile預(yù)設(shè)的1kb的block size。實(shí)際的寫入情況是如果value大于block size,那么就按照實(shí)際的情況來寫。上面的測試用例執(zhí)行完畢以后,整個(gè)hile文件只有1個(gè)data

23、 block。這個(gè)hfile的讀取代碼如下:/ create local file systemFileSystem fs = new RawLocalFileSystem();fs.initialize(URI.create("file:/"), new Configuration();fs.setConf(new Configuration();HFile.Reader hreader = new HFile.Reader(fs,new Path("hfile"), null, false);/ loadFileInfohreader.loadFil

24、eInfo();HFileScanner hscanner = hreader.getScanner(false, false);/ seek to the start position of the hfile.hscanner.seekTo();/ print index = 1;while (hscanner.next() System.out.println("index: " + index+);System.out.println("key: " + hscanner.getKeyString();System.out.

25、println("value: " + hscanner.getValueString();/ close hfile.hreader.close();上面的代碼將讀取hfile,并將這個(gè)文件中的所有kv打印出來。通過上面的測試可以看出:如果某一個(gè)key有非常非常多的value,那么查找這些value就無法通過索引去快速查找,而是需要通過遍歷進(jìn)行。另外,JIRA上面的HBASE-3857也提出了一種新的HFile格式,HFile v2他主要是針對現(xiàn)有HFile的兩個(gè)主要缺陷提出來的:· 暫用過多內(nèi)存· 啟動加載時(shí)間緩慢有興趣的朋友可以詳細(xì)了解一下。三、

26、HBase性能優(yōu)化方法總結(jié)1. 表的設(shè)計(jì)1.1 Pre-Creating Regions默認(rèn)情況下,在創(chuàng)建HBase表的時(shí)候會自動創(chuàng)建一個(gè)region分區(qū),當(dāng)導(dǎo)入數(shù)據(jù)的時(shí)候,所有的HBase客戶端都向這一個(gè)region寫數(shù)據(jù),直到這個(gè)region足夠大了才進(jìn)行切分。一種可以加快批量寫入速度的方法是通過預(yù)先創(chuàng)建一些空的regions,這樣當(dāng)數(shù)據(jù)寫入HBase時(shí),會按照region分區(qū)情況,在集群內(nèi)做數(shù)據(jù)的負(fù)載均衡。有關(guān)預(yù)分區(qū),詳情參見:Table Creation: Pre-Creating Regions,下面是一個(gè)例子:123456789101112131415161718192021222

27、3242526public static boolean createTable(HBaseAdmin admin, HTableDescriptor table, byte splits) throws IOException   try     admin.createTable(table, splits);     return true;    catch (TableExistsException e)     logger

28、.info("table " + table.getNameAsString() + " already exists");     / the table already exists.     return false;      public static byte getHexSplits(String startKey, String endKey, int numRegions)   byte split

29、s = new bytenumRegions-1;   BigInteger lowestKey = new BigInteger(startKey, 16);   BigInteger highestKey = new BigInteger(endKey, 16);   BigInteger range = highestKey.subtract(lowestKey);   BigInteger regionIncrement = range.divide(BigInteger.valueOf(numRegion

30、s);   lowestKey = lowestKey.add(regionIncrement);   for(int i=0; i < numRegions-1;i+)     BigInteger key = lowestKey.add(regionIncrement.multiply(BigInteger.valueOf(i);     byte b = String.format("%016x", key).getBytes();  

31、;   splitsi = b;      return splits; 1.2 Row KeyHBase中row key用來檢索表中的記錄,支持以下三種方式:· 通過單個(gè)row key訪問:即按照某個(gè)row key鍵值進(jìn)行g(shù)et操作;· 通過row key的range進(jìn)行scan:即通過設(shè)置startRowKey和endRowKey,在這個(gè)范圍內(nèi)進(jìn)行掃描;· 全表掃描:即直接掃描整張表中所有行記錄。在HBase中,row key可以是任意字符串,最大長度64KB,實(shí)際應(yīng)用中一般為10100by

32、tes,存為byte字節(jié)數(shù)組,一般設(shè)計(jì)成定長的。row key是按照字典序存儲,因此,設(shè)計(jì)row key時(shí),要充分利用這個(gè)排序特點(diǎn),將經(jīng)常一起讀取的數(shù)據(jù)存儲到一塊,將最近可能會被訪問的數(shù)據(jù)放在一塊。舉個(gè)例子:如果最近寫入HBase表中的數(shù)據(jù)是最可能被訪問的,可以考慮將時(shí)間戳作為row key的一部分,由于是字典序排序,所以可以使用Long.MAX_VALUE timestamp作為row key,這樣能保證新寫入的數(shù)據(jù)在讀取時(shí)可以被快速命中。1.3 Column Family不要在一張表里定義太多的column family。目前Hbase并不能很好的處理超過23個(gè)column family的

33、表。因?yàn)槟硞€(gè)column family在flush的時(shí)候,它鄰近的column family也會因關(guān)聯(lián)效應(yīng)被觸發(fā)flush,最終導(dǎo)致系統(tǒng)產(chǎn)生更多的I/O。感興趣的同學(xué)可以對自己的HBase集群進(jìn)行實(shí)際測試,從得到的測試結(jié)果數(shù)據(jù)驗(yàn)證一下。1.4 In Memory創(chuàng)建表的時(shí)候,可以通過HColumnDescriptor.setInMemory(true)將表放到RegionServer的緩存中,保證在讀取的時(shí)候被cache命中。1.5 Max Version創(chuàng)建表的時(shí)候,可以通過HColumnDescriptor.setMaxVersions(int maxVersions)設(shè)置表中數(shù)

34、據(jù)的最大版本,如果只需要保存最新版本的數(shù)據(jù),那么可以設(shè)置setMaxVersions(1)。1.6 Time To Live創(chuàng)建表的時(shí)候,可以通過HColumnDescriptor.setTimeToLive(int timeToLive)設(shè)置表中數(shù)據(jù)的存儲生命期,過期數(shù)據(jù)將自動被刪除,例如如果只需要存儲最近兩天的數(shù)據(jù),那么可以設(shè)置setTimeToLive(2 * 24 * 60 * 60)。1.7 Compact & Split在HBase中,數(shù)據(jù)在更新時(shí)首先寫入WAL 日志(HLog)和內(nèi)存(MemStore)中,MemStore中的數(shù)據(jù)是排序的,當(dāng)MemStore累計(jì)到一定閾值

35、時(shí),就會創(chuàng)建一個(gè)新的MemStore,并且將老的MemStore添加到flush隊(duì)列,由單獨(dú)的線程flush到磁盤上,成為一個(gè)StoreFile。于此同時(shí), 系統(tǒng)會在zookeeper中記錄一個(gè)redo point,表示這個(gè)時(shí)刻之前的變更已經(jīng)持久化了(minor compact)。StoreFile是只讀的,一旦創(chuàng)建后就不可以再修改。因此Hbase的更新其實(shí)是不斷追加的操作。當(dāng)一個(gè)Store中的StoreFile達(dá)到一定的閾值后,就會進(jìn)行一次合并(major compact),將對同一個(gè)key的修改合并到一起,形成一個(gè)大的StoreFile,當(dāng)StoreFile的大小達(dá)到一定閾值后,又會對 S

36、toreFile進(jìn)行分割(split),等分為兩個(gè)StoreFile。由于對表的更新是不斷追加的,處理讀請求時(shí),需要訪問Store中全部的StoreFile和MemStore,將它們按照row key進(jìn)行合并,由于StoreFile和MemStore都是經(jīng)過排序的,并且StoreFile帶有內(nèi)存中索引,通常合并過程還是比較快的。實(shí)際應(yīng)用中,可以考慮必要時(shí)手動進(jìn)行major compact,將同一個(gè)row key的修改進(jìn)行合并形成一個(gè)大的StoreFile。同時(shí),可以將StoreFile設(shè)置大些,減少split的發(fā)生。2. 寫表操作2.1 多HTable并發(fā)寫創(chuàng)建多個(gè)HTable客戶端用于寫操作

37、,提高寫數(shù)據(jù)的吞吐量,一個(gè)例子:12345678static final Configuration conf = HBaseConfiguration.create(); static final String table_log_name = “user_log”; wTableLog = new HTabletableN; for (int i = 0; i < tableN; i+)     wTableLogi = new HTable(conf, table_log_name);     wTab

38、leLogi.setWriteBufferSize(5 * 1024 * 1024); /5MB     wTableLogi.setAutoFlush(false); 2.2 HTable參數(shù)設(shè)置2.2.1 Auto Flush通過調(diào)用HTable.setAutoFlush(false)方法可以將HTable寫客戶端的自動flush關(guān)閉,這樣可以批量寫入數(shù)據(jù)到HBase,而不是有一條put就執(zhí)行一次更新,只有當(dāng)put填滿客戶端寫緩存時(shí),才實(shí)際向HBase服務(wù)端發(fā)起寫請求。默認(rèn)情況下auto flush是開啟的。 Write Buffer通過調(diào)用HTab

39、le.setWriteBufferSize(writeBufferSize)方法可以設(shè)置HTable客戶端的寫buffer大小,如果新設(shè)置的buffer小于當(dāng)前寫buffer中的數(shù)據(jù)時(shí),buffer將會被flush到服務(wù)端。其中,writeBufferSize的單位是byte字節(jié)數(shù),可以根據(jù)實(shí)際寫入數(shù)據(jù)量的多少來設(shè)置該值。 WAL Flag在HBae中,客戶端向集群中的RegionServer提交數(shù)據(jù)時(shí)(Put/Delete操作),首先會先寫WAL(Write Ahead Log)日志(即HLog,一個(gè)RegionServer上的所有Region共享一個(gè)HLog),只有當(dāng)WAL日志寫成功后,再

40、接著寫MemStore,然后客戶端被通知提交數(shù)據(jù)成功;如果寫WAL日志失敗,客戶端則被通知提交失敗。這樣做的好處是可以做到RegionServer宕機(jī)后的數(shù)據(jù)恢復(fù)。因此,對于相對不太重要的數(shù)據(jù),可以在Put/Delete操作時(shí),通過調(diào)用Put.setWriteToWAL(false)或Delete.setWriteToWAL(false)函數(shù),放棄寫WAL日志,從而提高數(shù)據(jù)寫入的性能。值得注意的是:謹(jǐn)慎選擇關(guān)閉WAL日志,因?yàn)檫@樣的話,一旦RegionServer宕機(jī),Put/Delete的數(shù)據(jù)將會無法根據(jù)WAL日志進(jìn)行恢復(fù)。2.3 批量寫通過調(diào)用HTable.put(Put)方法可以將一個(gè)指

41、定的row key記錄寫入HBase,同樣HBase提供了另一個(gè)方法:通過調(diào)用HTable.put(List<Put>)方法可以將指定的row key列表,批量寫入多行記錄,這樣做的好處是批量執(zhí)行,只需要一次網(wǎng)絡(luò)I/O開銷,這對于對數(shù)據(jù)實(shí)時(shí)性要求高,網(wǎng)絡(luò)傳輸RTT高的情景下可能帶來明顯的性能提升。2.4 多線程并發(fā)寫在客戶端開啟多個(gè)HTable寫線程,每個(gè)寫線程負(fù)責(zé)一個(gè)HTable對象的flush操作,這樣結(jié)合定時(shí)flush和寫buffer(writeBufferSize),可以既保證在數(shù)據(jù)量小的時(shí)候,數(shù)據(jù)可以在較短時(shí)間內(nèi)被flush(如1秒內(nèi)),同時(shí)又保證在數(shù)據(jù)量大的時(shí)候,寫bu

42、ffer一滿就及時(shí)進(jìn)行flush。下面給個(gè)具體的例子:12345678910111213141516171819202122for (int i = 0; i < threadN; i+)     Thread th = new Thread()         public void run()             while (true) &#

43、160;               try                     sleep(1000); /1 second           

44、;       catch (InterruptedException e)                     e.printStackTrace();                

45、                                  synchronized (wTableLogi)             

46、60;       try                         wTableLogi.flushCommits();              &#

47、160;       catch (IOException e)                         e.printStackTrace();             

48、                                                    

49、60;            th.setDaemon(true);     th.start(); 3. 讀表操作3.1 多HTable并發(fā)讀創(chuàng)建多個(gè)HTable客戶端用于讀操作,提高讀數(shù)據(jù)的吞吐量,一個(gè)例子:1234567static final Configuration conf = HBaseConfiguration.create(); static final String table_log_name = “user_log”; rTabl

50、eLog = new HTabletableN; for (int i = 0; i < tableN; i+)     rTableLogi = new HTable(conf, table_log_name);     rTableLogi.setScannerCaching(50); 3.2 HTable參數(shù)設(shè)置 Scanner Caching通過調(diào)用HTable.setScannerCaching(int scannerCaching)可以設(shè)置HBase scanner一次從服務(wù)端抓取的數(shù)據(jù)條數(shù),默認(rèn)

51、情況下一次一條。通過將此值設(shè)置成一個(gè)合理的值,可以減少scan過程中next()的時(shí)間開銷,代價(jià)是scanner需要通過客戶端的內(nèi)存來維持這些被cache的行記錄。 Scan Attribute Selectionscan時(shí)指定需要的Column Family,可以減少網(wǎng)絡(luò)傳輸數(shù)據(jù)量,否則默認(rèn)scan操作會返回整行所有Column Family的數(shù)據(jù)。 Close ResultScanner通過scan取完數(shù)據(jù)后,記得要關(guān)閉ResultScanner,否則RegionServer可能會出現(xiàn)問題(對應(yīng)的Server資源無法釋放)。3.3 批量讀通過調(diào)用HTable.get(Get)方法可以根據(jù)一

52、個(gè)指定的row key獲取一行記錄,同樣HBase提供了另一個(gè)方法:通過調(diào)用HTable.get(List)方法可以根據(jù)一個(gè)指定的row key列表,批量獲取多行記錄,這樣做的好處是批量執(zhí)行,只需要一次網(wǎng)絡(luò)I/O開銷,這對于對數(shù)據(jù)實(shí)時(shí)性要求高而且網(wǎng)絡(luò)傳輸RTT高的情景下可能帶來明顯的性能提升。3.4 多線程并發(fā)讀在客戶端開啟多個(gè)HTable讀線程,每個(gè)讀線程負(fù)責(zé)通過HTable對象進(jìn)行g(shù)et操作。下面是一個(gè)多線程并發(fā)讀取HBase,獲取店鋪一天內(nèi)各分鐘PV值的例子:12345678910111213141516171819202122232425262728293031323334353637

53、3839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146public class DataReaderServer  

54、;    /獲取店鋪一天內(nèi)各分鐘PV值的入口函數(shù)      public static ConcurrentHashMap getUnitMinutePV(long uid, long startStamp, long endStamp)          long min = startStamp;          int

55、count = (int)(endStamp - startStamp) / (60*1000);          List lst = new ArrayList();          for (int i = 0; i <= count; i+)             min = s

56、tartStamp + i * 60 * 1000;             lst.add(uid + "_" + min);                    return parallelBatchMinutePV(lst);    

57、60;        /多線程并發(fā)查詢,獲取分鐘PV值 private static ConcurrentHashMap parallelBatchMinutePV(List lstKeys)         ConcurrentHashMap hashRet = new ConcurrentHashMap();         int parallel = 3; &

58、#160;       List<List<String>> lstBatchKeys  = null;         if (lstKeys.size() < parallel )             lstBatchKeys  = new ArrayList<Li

59、st<String>>(1);             lstBatchKeys.add(lstKeys);                  else             ls

60、tBatchKeys  = new ArrayList<List<String>>(parallel);             for(int i = 0; i < parallel; i+  )                 List lst = new Arra

61、yList();                 lstBatchKeys.add(lst);                            for(int i = 0 ;

62、 i < lstKeys.size() ; i + )                 lstBatchKeys.get(i%parallel).add(lstKeys.get(i);                       &#

63、160;         List >> futures = new ArrayList >>(5);           ThreadFactoryBuilder builder = new ThreadFactoryBuilder();         builder.setNameFormat(&q

64、uot;ParallelBatchQuery");         ThreadFactory factory = builder.build();         ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.newFixedThreadPool(lstBatchKeys.size(), factory);    

65、60;      for(List keys : lstBatchKeys)             Callable< ConcurrentHashMap > callable = new BatchMinutePVCallable(keys);             FutureT

66、ask< ConcurrentHashMap > future = (FutureTask< ConcurrentHashMap >) executor.submit(callable);             futures.add(future);                  exe

67、cutor.shutdown();           / Wait for all the tasks to finish         try           boolean stillRunning = !executor.awaitTermination(     

68、          5000000, TimeUnit.MILLISECONDS);           if (stillRunning)             try          

69、;       executor.shutdownNow();              catch (Exception e)                 / TODO Auto-generated catch block  

70、0;              e.printStackTrace();                                  catch (Int

71、erruptedException e)           try               Thread.currentThread().interrupt();            catch (Exception e1)   &

72、#160;         / TODO Auto-generated catch block             e1.printStackTrace();                     

73、60;         / Look for any exception         for (Future f : futures)           try              

74、60;if(f.get() != null)                                  hashRet.putAll(ConcurrentHashMap)f.get();        

75、                   catch (InterruptedException e)             try                

76、;  Thread.currentThread().interrupt();              catch (Exception e1)                 / TODO Auto-generated catch block     

77、60;           e1.printStackTrace();                         catch (ExecutionException e)        

78、0;    e.printStackTrace();                               return hashRet;           /一個(gè)線程批量查詢,獲取

79、分鐘PV值     protected static ConcurrentHashMap getBatchMinutePV(List lstKeys)         ConcurrentHashMap hashRet = null;         List lstGet = new ArrayList();        &

80、#160;String splitValue = null;         for (String s : lstKeys)             splitValue = s.split("_");             long uid = Long

81、.parseLong(splitValue0);             long min = Long.parseLong(splitValue1);             byte key = new byte16;            &#

82、160;Bytes.putLong(key, 0, uid);             Bytes.putLong(key, 8, min);             Get g = new Get(key);             g.

83、addFamily(fp);             lstGet.add(g);                  Result res = null;         try      

84、       res = tableMinutePVrand.nextInt(tableN).get(lstGet);          catch (IOException e1)             logger.error("tableMinutePV exception, e=" + e1.getStackTrace();             

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論