当前位置:   article > 正文

Hbase查询性能优化_hbase跨列族查询会影响性能?

hbase跨列族查询会影响性能?

Hbase虽然能提供海量数据的实时读写,但是一旦数据量非常大,查询延迟也会非常高,所以要做好优化工作。

一、表结构设计

1、列族越少越好

(1)列族(cf)数量,在内存结构中一个cf对应一个store区域,一个store中又存在多个storefile小文件,小storefile是不断合并新的大的storefile,数据量大了,storefile自然会多,合并任务也自然增多,会降低性能,增加列族性能会更有甚之。

(2)由于数据的备份、迁移、合并等操作都是基于列族层面进行的。列族少,也会减少数据备份、迁移、合并过程中内存、磁盘IO的耗时。

(3)每个列族读写次数不一样,假设A列族数据量很大,B列族数据量较小, 当A列族,memstore数据达到阀值时候,就会flush到磁盘中,这时会带动B列族的memstore刷新到内存中,导致B列族频繁flush,增加不必要的磁盘IO操作。

2、参数设置

把IN_MEMORY 设置为true,开启内存缓存,默认为false

二、rowKey的设计

rowKey即行健,相当于一级索引,根据业务需要,设计合理可以大大提高hbase查询效率

1、均匀分布

rowKey尽量要短,写入要分散,分布均匀,根据业务合理设置预分区,避免热点写

常见的有加随机数、hash计算、反转

(1)随机数俗称加salt,就是在rowkey前加随机数,如下,在前边添加a、b、c....之类的随机数。

rowkeysalt_rowkey
15738862581a_15738862581
15837456185b_15837456185
15837456189c_15837456189

这种rowkey设计可以均匀分布在各个Region中,但是它打乱了自然的字典排序,是不利于scan的

(2)hash计算  计算rowkey的hash值,并取前N位与原rowkey拼接

rowkeyhash_rowkey
157388625812f5f2eb_15738862581
15837456175cb4ght_15837456175
15837456159eh4kj3_15837456159

 这种rowkey一定程度均匀分布rowkey,对单个随机查询效率较高,但是也是不利于我们scan的

(3)反转就是将一段长度或者全部长度的rowkey进行倒序,如下将后四位反转后拼接

rowkeyreverse_rowkey
157388625811852_573886
158374561755716_583745
158374561599516_1583745

 这种打乱了rowkey,牺牲了行排序

2、存储设计

场景:查询用户所有订单,用户查询每个月的订单按时间由近及远排序,及时间倒序

这是我们就要利用hbase rowkey的字典排序特性来合理设计rowkey,以提高查询速度。由于每个查询都是基于某个用户的时间倒序。所以这里rowkey的设计用户id+时间戳timestamp来作为rowkey,这样一个用户的订单信息就会连续存储在一起,查询效率自然提高。如id=10000001,timestamp=1536425757188,rowkey=10000001_1536425757188。这样rowkey是使一个用户的订单连续分布一起了,但是时间正序,不符合倒序要求。因此要进一步优化,这时我们只需timestamp倒序就行了,用一个大数减去timestamp,timestamp=9223370500429018619=long.max-1536425757188 ,rowkey=10000001_9223370500429018619 如这样时间同一个用户最近的订单就排在最前面了。

rowkey:uid_(long.max-timestamp),防止热点也可以加salt,salt_uid_(long.max-timestamp)
存储主要代码如下:

  1. public static void addOneRecord()throws Exception{
  2. Table table = null;
  3. table = connection.getTable(TableName.valueOf(tableName));
  4. SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
  5. //rowKey id+时间倒序
  6. String rowKey= "100001"+(Long.MAX_VALUE - sdf.parse(new Date()).getTime());
  7. Put put = new Put(Bytes.toBytes(rowKey));
  8. put.addColumn(Bytes.toBytes(family), Bytes.toBytes(qualifier),Bytes.toBytes(value));
  9. table.put(put);
  10. }

查询主要代码如下:

  1. public void queryAll throws Exception {
  2. // 查询 100001 8月份 所有的订单
  3. Scan scan = new Scan();
  4. SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
  5. String startRow = "100001" + (Long.MAX_VALUE - sdf.parse("20180901000000").getTime());
  6. String stopRow = "100001_" + (Long.MAX_VALUE - sdf.parse("20180801000000").getTime());
  7. scan.setStartRow(startRow.getBytes());
  8. scan.setStopRow(stopRow.getBytes());
  9. ResultScanner rss = hTable.getScanner(scan);
  10. for(Result rs : rss) {
  11. System.out.print(new String(CellUtil.cloneValue(rs.getColumnLatestCell("cf".getBytes(), "dnum".getBytes()))));
  12. System.out.print(" " + new String(CellUtil.cloneValue(rs.getColumnLatestCell("cf".getBytes(), "date".getBytes()))));
  13. System.out.println(" " + new String(CellUtil.cloneValue(rs.getColumnLatestCell("cf".getBytes(), "type".getBytes()))));
  14. }
  15. }

3、巧用过滤器

假设用户的订单有四个状态,1 待支付、2代发货、3待收货、 4已完成,用户要查询待发货的订单,这时要用到过滤器,减少查询量,提高查询速度

  1. public void query() throws Exception {
  2. FilterList list = new FilterList(FilterList.Operator.MUST_PASS_ALL);
  3. // 过滤器1、前缀过滤,用户过滤
  4. String id=100001;
  5. PrefixFilter filter1 = new PrefixFilter(id.getBytes());
  6. list.addFilter(filter1);
  7. String type=3;//待收货
  8. // 过滤器2、过滤type=3的用户
  9. SingleColumnValueFilter filter2 = new SingleColumnValueFilter("cf".getBytes(), "type".getBytes(), CompareOp.EQUAL, type.getBytes());
  10. list.addFilter(filter2);
  11. Scan scan = new Scan();
  12. scan.setFilter(list);
  13. ResultScanner rss = hTable.getScanner(scan);
  14. for(Result rs : rss) {
  15. System.out.print(new String(CellUtil.cloneValue(rs.getColumnLatestCell("cf".getBytes(), "num".getBytes()))));
  16. System.out.print(" " + new String(CellUtil.cloneValue(rs.getColumnLatestCell("cf".getBytes(), "date".getBytes()))));
  17. System.out.println(" " + new String(CellUtil.cloneValue(rs.getColumnLatestCell("cf".getBytes(), "type".getBytes()))));
  18. }
  19. }

 

三、服务端调优

1、参数调优  暂不了解待完成

2、JVM调优  暂不了解待完成

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Li_阴宅/article/detail/745270
推荐阅读
相关标签
  

闽ICP备14008679号