HBase建表高级属性,hbase应用案例看行键设计,HBase和mapreduce结合,从Hbase中读取数据、分析,写入hdfs,从hdfs中读取数据写入Hbase,协处理器和二级索引
1. Hbase高級(jí)應(yīng)用
1.1建表高級(jí)屬性
下面幾個(gè)shell 命令在hbase操作中可以起到很到的作用,且主要體現(xiàn)在建表的過(guò)程中,看下面幾個(gè)create 屬性
1、 BLOOMFILTER 默認(rèn)是NONE 是否使用布隆過(guò)慮及使用何種方式
布隆過(guò)濾可以每列族單獨(dú)啟用。
使用 HColumnDescriptor.setBloomFilterType(NONE | ROW | ROWCOL) 對(duì)列族單獨(dú)啟用布隆。
? Default = ROW 對(duì)行進(jìn)行布隆過(guò)濾。
? 對(duì) ROW,行鍵的哈希在每次插入行時(shí)將被添加到布隆。
? 對(duì) ROWCOL,行鍵 + 列族 + 列族修飾的哈希將在每次插入行時(shí)添加到布隆
使用方法: create ‘table’,{BLOOMFILTER =>’ROW’}
啟用布隆過(guò)濾可以節(jié)省讀磁盤(pán)過(guò)程,可以有助于降低讀取延遲
2、 VERSIONS 默認(rèn)是1 這個(gè)參數(shù)的意思是數(shù)據(jù)保留1個(gè) 版本,如果我們認(rèn)為我們的數(shù)據(jù)沒(méi)有這么大的必要保留這么多,隨時(shí)都在更新,而老版本的數(shù)據(jù)對(duì)我們毫無(wú)價(jià)值,那將此參數(shù)設(shè)為1 能節(jié)約2/3的空間
使用方法: create ‘table’,{VERSIONS=>’2’}
附:MIN_VERSIONS => ‘0’是說(shuō)在compact操作執(zhí)行之后,至少要保留的版本
3、 COMPRESSION 默認(rèn)值是NONE 即不使用壓縮
這個(gè)參數(shù)意思是該列族是否采用壓縮,采用什么壓縮算法
使用方法: create ‘table’,{NAME=>’info’,COMPRESSION=>’SNAPPY’}
建議采用SNAPPY壓縮算法
HBase中,在Snappy發(fā)布之前(Google 2011年對(duì)外發(fā)布Snappy),采用的LZO算法,目標(biāo)是達(dá)到盡可能快的壓縮和解壓速度,同時(shí)減少對(duì)CPU的消耗;
在Snappy發(fā)布之后,建議采用Snappy算法(參考《HBase: The Definitive Guide》),具體可以根據(jù)實(shí)際情況對(duì)LZO和Snappy做過(guò)更詳細(xì)的對(duì)比測(cè)試后再做選擇。
| GZIP | 13.4% | 21 MB/s | 118 MB/s |
| LZO | 20.5% | 135 MB/s | 410 MB/s |
| Zippy/Snappy | 22.2% | 172 MB/s | 409 MB/s |
如果建表之初沒(méi)有壓縮,后來(lái)想要加入壓縮算法,可以通過(guò)alter修改schema
4. alter
使用方法:
如 修改壓縮算法
disable ‘table’
alter ‘table’,{NAME=>’info’,COMPRESSION=>’snappy’}
enable ‘table’
但是需要執(zhí)行major_compact ‘table’ 命令之后 才會(huì)做實(shí)際的操作。
5. TTL
默認(rèn)是 2147483647 即:Integer.MAX_VALUE 值大概是68年
這個(gè)參數(shù)是說(shuō)明該列族數(shù)據(jù)的存活時(shí)間,單位是s
這個(gè)參數(shù)可以根據(jù)具體的需求對(duì)數(shù)據(jù)設(shè)定存活時(shí)間,超過(guò)存過(guò)時(shí)間的數(shù)據(jù)將在表中不在顯示,待下次major compact的時(shí)候再?gòu)氐讋h除數(shù)據(jù)
注意的是TTL設(shè)定之后 MIN_VERSIONS=>’0’ 這樣設(shè)置之后,TTL時(shí)間戳過(guò)期后,將全部徹底刪除該family下所有的數(shù)據(jù),如果MIN_VERSIONS 不等于0那將保留最新的MIN_VERSIONS個(gè)版本的數(shù)據(jù),其它的全部刪除,比如MIN_VERSIONS=>’1’ 屆時(shí)將保留一個(gè)最新版本的數(shù)據(jù),其它版本的數(shù)據(jù)將不再保存。
6. describe ‘table’ 這個(gè)命令查看了create table 的各項(xiàng)參數(shù)或者是默認(rèn)值。
7. disable_all ‘toplist.*’ disable_all 支持正則表達(dá)式,并列出當(dāng)前匹配的表的如下:
toplist_a_total_1001
toplist_a_total_1002
toplist_a_total_1008
toplist_a_total_1009
toplist_a_total_1019
toplist_a_total_1035
…
Disable the above 25 tables (y/n)? 并給出確認(rèn)提示
8. drop_all 這個(gè)命令和disable_all的使用方式是一樣的
9. hbase 表預(yù)分區(qū)—-手動(dòng)分區(qū)
默認(rèn)情況下,在創(chuàng)建HBase表的時(shí)候會(huì)自動(dòng)創(chuàng)建一個(gè)region分區(qū),當(dāng)導(dǎo)入數(shù)據(jù)的時(shí)候,所有的HBase客戶端都向這一個(gè)region寫(xiě)數(shù)據(jù),直到這個(gè)region足夠大了才進(jìn)行切分。一種可以加快批量寫(xiě)入速度的方法是通過(guò)預(yù)先創(chuàng)建一些空的regions,這樣當(dāng)數(shù)據(jù)寫(xiě)入HBase時(shí),會(huì)按照region分區(qū)情況,在集群內(nèi)做數(shù)據(jù)的負(fù)載均衡。
命令方式:
create ‘t1’, ‘f1’, {NUMREGIONS => 15, SPLITALGO => ‘HexStringSplit’}
也可以使用api的方式:
bin/hbase org.apache.hadoop.hbase.util.RegionSplitter test_table HexStringSplit -c 10 -f info
參數(shù):
test_table是表名
HexStringSplit 是split 方式
-c 是分10個(gè)region
-f 是family
可在UI上查看結(jié)果,如圖:
這樣就可以將表預(yù)先分為15個(gè)區(qū),減少數(shù)據(jù)達(dá)到storefile 大小的時(shí)候自動(dòng)分區(qū)的時(shí)間消耗,并且還有以一個(gè)優(yōu)勢(shì),就是合理設(shè)計(jì)rowkey 能讓各個(gè)region 的并發(fā)請(qǐng)求平均分配(趨于均勻) 使IO 效率達(dá)到最高,但是預(yù)分區(qū)需要將filesize 設(shè)置一個(gè)較大的值,設(shè)置哪個(gè)參數(shù)呢 hbase.hregion.max.filesize 這個(gè)值默認(rèn)是10G 也就是說(shuō)單個(gè)region 默認(rèn)大小是10G
這個(gè)參數(shù)的默認(rèn)值在0.90 到0.92到0.94.3各版本的變化:256M–1G–10G
1.2 hbase應(yīng)用案例看行鍵設(shè)計(jì)
表結(jié)構(gòu)設(shè)計(jì)
1、列族數(shù)量的設(shè)定
以用戶信息為例,可以將必須的基本信息存放在一個(gè)列族,而一些附加的額外信息可以放在另一列族;
2、行鍵的設(shè)計(jì)
語(yǔ)音詳單:
13877889988-20150625
13877889988-20150625
13877889988-20150626
13877889988-20150626
13877889989
13877889989
13877889989
—-將需要批量查詢的數(shù)據(jù)盡可能連續(xù)存放
CMS系統(tǒng)—-多條件查詢
盡可能將查詢條件關(guān)鍵詞拼裝到rowkey中,查詢頻率最高的條件盡量往前靠
20150230-zhangsan-category…
20150230-lisi-category…
(每一個(gè)條件的值長(zhǎng)度不同,可以通過(guò)做定長(zhǎng)映射來(lái)提高效率)
參考:《hbase 實(shí)戰(zhàn)》—-詳細(xì)講述了facebook /GIS等系統(tǒng)的表結(jié)構(gòu)設(shè)計(jì)
1.3 Hbase和mapreduce結(jié)合
為什么需要用mapreduce去訪問(wèn)hbase的數(shù)據(jù)?
——加快分析速度和擴(kuò)展分析能力
Mapreduce訪問(wèn)hbase數(shù)據(jù)作分析一定是在離線分析的場(chǎng)景下應(yīng)用
1.3.1 從Hbase中讀取數(shù)據(jù)、分析,寫(xiě)入hdfs
/** public abstract class TableMapper<KEYOUT, VALUEOUT> extends Mapper<ImmutableBytesWritable, Result, KEYOUT, VALUEOUT> { }* @author duanhaitao@itcast.cn**/ public class HbaseReader {public static String flow_fields_import = "flow_fields_import";static class HdfsSinkMapper extends TableMapper<Text, NullWritable>{@Overrideprotected void map(ImmutableBytesWritable key, Result value, Context context) throws IOException, InterruptedException {byte[] bytes = key.copyBytes();String phone = new String(bytes);byte[] urlbytes = value.getValue("f1".getBytes(), "url".getBytes());String url = new String(urlbytes);context.write(new Text(phone + "\t" + url), NullWritable.get());}}static class HdfsSinkReducer extends Reducer<Text, NullWritable, Text, NullWritable>{@Overrideprotected void reduce(Text key, Iterable<NullWritable> values, Context context) throws IOException, InterruptedException {context.write(key, NullWritable.get());}}public static void main(String[] args) throws Exception {Configuration conf = HBaseConfiguration.create();conf.set("hbase.zookeeper.quorum", "spark01");Job job = Job.getInstance(conf);job.setJarByClass(HbaseReader.class);// job.setMapperClass(HdfsSinkMapper.class);Scan scan = new Scan();TableMapReduceUtil.initTableMapperJob(flow_fields_import, scan, HdfsSinkMapper.class, Text.class, NullWritable.class, job);job.setReducerClass(HdfsSinkReducer.class);FileOutputFormat.setOutputPath(job, new Path("c:/hbasetest/output"));job.setOutputKeyClass(Text.class);job.setOutputValueClass(NullWritable.class);job.waitForCompletion(true);}}1.3.2 從hdfs中讀取數(shù)據(jù)寫(xiě)入Hbase
/** public abstract class TableReducer<KEYIN, VALUEIN, KEYOUT> extends Reducer<KEYIN, VALUEIN, KEYOUT, Writable> { }* @author duanhaitao@itcast.cn**/ public class HbaseSinker {public static String flow_fields_import = "flow_fields_import";static class HbaseSinkMrMapper extends Mapper<LongWritable, Text, FlowBean, NullWritable>{@Overrideprotected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {String line = value.toString();String[] fields = line.split("\t");String phone = fields[0];String url = fields[1];FlowBean bean = new FlowBean(phone,url);context.write(bean, NullWritable.get());}}static class HbaseSinkMrReducer extends TableReducer<FlowBean, NullWritable, ImmutableBytesWritable>{@Overrideprotected void reduce(FlowBean key, Iterable<NullWritable> values, Context context) throws IOException, InterruptedException {Put put = new Put(key.getPhone().getBytes());put.add("f1".getBytes(), "url".getBytes(), key.getUrl().getBytes());context.write(new ImmutableBytesWritable(key.getPhone().getBytes()), put);}}public static void main(String[] args) throws Exception {Configuration conf = HBaseConfiguration.create();conf.set("hbase.zookeeper.quorum", "spark01");HBaseAdmin hBaseAdmin = new HBaseAdmin(conf);boolean tableExists = hBaseAdmin.tableExists(flow_fields_import);if(tableExists){hBaseAdmin.disableTable(flow_fields_import);hBaseAdmin.deleteTable(flow_fields_import);}HTableDescriptor desc = new HTableDescriptor(TableName.valueOf(flow_fields_import));HColumnDescriptor hColumnDescriptor = new HColumnDescriptor ("f1".getBytes());desc.addFamily(hColumnDescriptor);hBaseAdmin.createTable(desc);Job job = Job.getInstance(conf);job.setJarByClass(HbaseSinker.class);job.setMapperClass(HbaseSinkMrMapper.class);TableMapReduceUtil.initTableReducerJob(flow_fields_import, HbaseSinkMrReducer.class, job);FileInputFormat.setInputPaths(job, new Path("c:/hbasetest/data"));job.setMapOutputKeyClass(FlowBean.class);job.setMapOutputValueClass(NullWritable.class);job.setOutputKeyClass(ImmutableBytesWritable.class);job.setOutputValueClass(Mutation.class);job.waitForCompletion(true); } }1.3 hbase高級(jí)編程
1.3.1 協(xié)處理器—- Coprocessor
協(xié)處理器有兩種:observer和endpoint
Observer允許集群在正常的客戶端操作過(guò)程中可以有不同的行為表現(xiàn)
Endpoint允許擴(kuò)展集群的能力,對(duì)客戶端應(yīng)用開(kāi)放新的運(yùn)算命令
? Observer協(xié)處理器
? 正常put請(qǐng)求的流程:
? 加入Observer協(xié)處理后的put流程:
1 客戶端發(fā)出put請(qǐng)求
2 該請(qǐng)求被分派給合適的RegionServer和region
3 coprocessorHost攔截該請(qǐng)求,然后在該表上登記的每個(gè)RegionObserver上調(diào)用prePut()
4 如果沒(méi)有被prePut()攔截,該請(qǐng)求繼續(xù)送到region,然后進(jìn)行處理
5 region產(chǎn)生的結(jié)果再次被CoprocessorHost攔截,調(diào)用postPut()
6 假如沒(méi)有postPut()攔截該響應(yīng),最終結(jié)果被返回給客戶端
? Observer的類(lèi)型
1.RegionObs——這種Observer鉤在數(shù)據(jù)訪問(wèn)和操作階段,所有標(biāo)準(zhǔn)的數(shù)據(jù)操作命令都可以被pre-hooks和post-hooks攔截
**2.WALObserver——**WAL所支持的Observer;可用的鉤子是pre-WAL和post-WAL
3.MasterObserver——鉤住DDL事件,如表創(chuàng)建或模式修改
? Observer應(yīng)用場(chǎng)景示例
見(jiàn)下節(jié);
? Endpoint—參考《Hbase 權(quán)威指南》
1.3.2 二級(jí)索引
row key在HBase中是以B+ tree結(jié)構(gòu)化有序存儲(chǔ)的,所以scan起來(lái)會(huì)比較效率。單表以row key存儲(chǔ)索引,column value存儲(chǔ)id值或其他數(shù)據(jù) ,這就是Hbase索引表的結(jié)構(gòu)。
由于HBase本身沒(méi)有二級(jí)索引(Secondary Index)機(jī)制,基于索引檢索數(shù)據(jù)只能單純地依靠RowKey,為了能支持多條件查詢,開(kāi)發(fā)者需要將所有可能作為查詢條件的字段一一拼接到RowKey中,這是HBase開(kāi)發(fā)中極為常見(jiàn)的做法
比如,現(xiàn)在有一張1億的用戶信息表,建有出生地和年齡兩個(gè)索引,我想得到一個(gè)條件是在杭州出生,年齡為20歲的按用戶id正序排列前10個(gè)的用戶列表。
有一種方案是,系統(tǒng)先掃描出生地為杭州的索引,得到一個(gè)用戶id結(jié)果集,這個(gè)集合的規(guī)模假設(shè)是10萬(wàn)。然后掃描年齡,規(guī)模是5萬(wàn),最后merge這些用戶id,去重,排序得到結(jié)果。
這明顯有問(wèn)題,如何改良?
保證出生地和年齡的結(jié)果是排過(guò)序的,可以減少merge的數(shù)據(jù)量?但Hbase是按row key排序,value是不能排序的。
變通一下——將用戶id冗余到row key里?OK,這是一種解決方案了,這個(gè)方案的圖示如下:
merge時(shí)提取交集就是所需要的列表,順序是靠索引增加了_id,以字典序保證的。
2, 按索引查詢種類(lèi)建立組合索引。
在方案1的場(chǎng)景中,想象一下,如果單索引數(shù)量多達(dá)10個(gè)會(huì)怎么樣?10個(gè)索引,就要merge 10次,性能可想而知。
解決這個(gè)問(wèn)題需要參考RDBMS的組合索引實(shí)現(xiàn)。
比如出生地和年齡需要同時(shí)查詢,此時(shí)如果建立一個(gè)出生地和年齡的組合索引,查詢時(shí)效率會(huì)高出merge很多。
當(dāng)然,這個(gè)索引也需要冗余用戶id,目的是讓結(jié)果自然有序。結(jié)構(gòu)圖示如下:
這個(gè)方案的優(yōu)點(diǎn)是查詢速度非常快,根據(jù)查詢條件,只需要到一張表中檢索即可得到結(jié)果list。缺點(diǎn)是如果有多個(gè)索引,就要建立多個(gè)與查詢條件一一對(duì)應(yīng)的組合索引
而索引表的維護(hù)如果交給應(yīng)用客戶端,則無(wú)疑增加了應(yīng)用端開(kāi)發(fā)的負(fù)擔(dān)
通過(guò)協(xié)處理器可以將索引表維護(hù)的工作從應(yīng)用端剝離
? 利用Observer自動(dòng)維護(hù)索引表示例
在社交類(lèi)應(yīng)用中,經(jīng)常需要快速檢索各用戶的關(guān)注列表t_guanzhu,同時(shí),又需要反向檢索各種戶的粉絲列表t_fensi,為了實(shí)現(xiàn)這個(gè)需求,最佳實(shí)踐是建立兩張互為反向的表:
? 一個(gè)表為正向索引關(guān)注表 “t_guanzhu”:
Rowkey: A-B
f1:From
f1:To
? 另一個(gè)表為反向索引粉絲表:“t_fensi”:
Rowkey: B—A
f1:From
f1:To
插入一條關(guān)注信息時(shí),為了減輕應(yīng)用端維護(hù)反向索引表的負(fù)擔(dān),可用Observer協(xié)處理器實(shí)現(xiàn):
1、編寫(xiě)自定義RegionServer
public class InverIndexCoprocessor extends BaseRegionObserver {@Overridepublic void prePut(ObserverContext<RegionCoprocessorEnvironment> e, Put put, WALEdit edit, Durability durability) throws IOException {// set configurationConfiguration conf = HBaseConfiguration.create();// need conf.set...HTable table = new HTable(conf, "t_fensi");Cell fromCell = put.get("f1".getBytes(), "From".getBytes()).get(0);Cell toCell = put.get("f1".getBytes(), "To".getBytes()).get(0);byte[] valueArray = fromCell.getValue();String from = new String(valueArray);valueArray = toCell.getValue();String to = new String(valueArray);Put putIndex = new Put((to+"-"+from).getBytes());putIndex.add("f1".getBytes(), "From".getBytes(),from.getBytes());putIndex.add("f1".getBytes(), "To".getBytes(),to.getBytes());table.put(putIndex);table.close();} }2、打成jar包“fensiguanzhu.jar”上傳hdfs
hadoop fs -put fensiguanzhu.jar /demo/
3、修改t_fensi的schema,注冊(cè)協(xié)處理器
hbase(main):017:0> alter ' t_fensi ',METHOD => 'table_att','coprocessor'=>'hdfs://spark01:9000/demo/ fensiguanzhu.jar|cn.itcast.bigdata.hbasecoprocessor. InverIndexCoprocessor|1001|' Updating all regions with the new schema... 0/1 regions updated. 1/1 regions updated. Done.4、檢查是否注冊(cè)成功
hbase(main):018:0> describe ‘ff’
DESCRIPTION ENABLED
‘ff’, {TABLE_ATTRIBUTES => {coprocessor$1 => ‘hdfs://spark01:9000/demo/fensiguanzhu.jar|cn.itcast.bi true
gdata.hbasecoprocessor.TestCoprocessor|1001|’}, {NAME => ‘f1’, DATA_BLOCK_ENCODING => ‘NONE’, BLOOMF
ILTER => ‘ROW’, REPLICATION_SCOPE => ‘0’, VERSIONS => ‘1’, COMPRESSION => ‘NONE’, MIN_VERSIONS => ‘0
‘, TTL => ‘2147483647’, KEEP_DELETED_CELLS => ‘false’, BLOCKSIZE => ‘65536’, IN_MEMORY => ‘false’, B
LOCKCACHE => ‘true’}, {NAME => ‘f2’, DATA_BLOCK_ENCODING => ‘NONE’, BLOOMFILTER => ‘ROW’, REPLICATIO
N_SCOPE => ‘0’, VERSIONS => ‘1’, COMPRESSION => ‘NONE’, MIN_VERSIONS => ‘0’, TTL => ‘2147483647’, KE
EP_DELETED_CELLS => ‘false’, BLOCKSIZE => ‘65536’, IN_MEMORY => ‘false’, BLOCKCACHE => ‘true’}
1 row(s) in 0.0250 seconds
5、向正向索引表中插入數(shù)據(jù)進(jìn)行驗(yàn)證
總結(jié)
以上是生活随笔為你收集整理的HBase建表高级属性,hbase应用案例看行键设计,HBase和mapreduce结合,从Hbase中读取数据、分析,写入hdfs,从hdfs中读取数据写入Hbase,协处理器和二级索引的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 成都部队文职管理岗跟技能岗哪个好考
- 下一篇: 自定义Flume拦截器,并将收集的日志存