前言 .................................................................................................................................................. 3 第一部分 数据结构 ......................................................................................................................... 3
表定义....................................................................................................................................... 3 数据结构定义 ........................................................................................................................... 3 主键........................................................................................................................................... 3 初始化....................................................................................................................................... 4 第二部分 表的初始化 ..................................................................................................................... 4
初始化策略 ............................................................................................................................... 4
保留最新版本 ................................................................................................................... 4 压缩策略 ........................................................................................................................... 4 自动过期 ........................................................................................................................... 4 预分区 ............................................................................................................................... 4 写入内存 ........................................................................................................................... 4
第三部分 代码开发 ......................................................................................................................... 5
CRUD操作 .............................................................................................................................. 5
新增操作 ........................................................................................................................... 5 更新操作 ........................................................................................................................... 5 查询操作 ........................................................................................................................... 5 删除操作 ........................................................................................................................... 5 表实例池 ................................................................................................................................... 6 获取总数 ................................................................................................................................... 6 列表分页 ................................................................................................................................... 7 列表排序 ................................................................................................................................... 8 第四部分 Hbase查询 ...................................................................................................................... 8
比较运算符 ............................................................................................................................... 8 比较器介绍 ............................................................................................................................... 9
BinaryComparator ............................................................................................................. 9 NullComparator ................................................................................................................ 9 RegexStringComparator .................................................................................................... 9 常用过滤器介绍 ..................................................................................................................... 10 过滤器应用实例 ..................................................................................................................... 10 过滤器集合的使用 ................................................................................................................. 10 复杂查询过滤 ......................................................................................................................... 10 第五部分 HBase性能优化 ........................................................................................................... 11
查询缓存 ................................................................................................................................. 11 多线程配置 ............................................................................................................................. 11 预分区..................................................................................................................................... 12 附录:代码..................................................................................................................................... 12
InitHBaseTable ....................................................................................................................... 12 InitHBaseTable.properties ...................................................................................................... 15 table=PK_YCONTROL/BASEINFO/ /false/false/false ............................................ 15 HBaseRowKeyUtil HBase主键生成工具 .......................................................................... 15 PKXControlDaoHBaseImpl .................................................................................................... 17
public void addXControlFK(String PK) throws Exception{ .......................................... 17
1
public void deleteXControlFK(String PK) throws Exception{ ....................................... 18 public String getXControlFK(String PK) throws Exception{ ......................................... 18 public List public void savePut(String tableName,Put put) throws IOException { .......................... 22 public void savePut(String tableName, List public static Filter getLESS_EQUAL_GREATERFilter(String startField, String endField, String fieldValue, boolean isFilterNull){ ........................................................ 36 public static Filter getLESS_OR_EQUALFilter(String field, String fieldValue, boolean isFilterNull){ ................................................................................................................... 37 public static Filter getGREATER_OR_EQUALFilter(String field, String fieldValue, boolean isFilterNull){ ..................................................................................................... 37 public static Filter getNOT_LESS_EQUAL_GREATERFilter(String startField, String endField, String fieldValue){ .......................................................................................... 38 public static Filter getRegexStringFilterContainsNull(String Colume,String value){ .... 38 public static Filter getRegexStringFilter(String Colume,String value){ ......................... 39 public static Filter getNotRegexStringFilter(String Colume,String value){ ................... 39 public static Filter getEqualFilter(String Colume,String value){ .................................... 40 public static Filter getNotEqualFilter(String Colume,String value){ .............................. 40 2 public static Filter getNullFilter(String Colume){ .......................................................... 40 public static Filter getNotNullFilter(String Colume){ .................................................... 41 前言 HBase是一个分布式的、面向列的开源数据库.HBase不同于一般的关系数据库,它是一个适合于非结构化数据存储的数据库。另一个不同的是HBase基于列的而不是基于行的模式。HBase – Hadoop Database,是一个高可靠性、高性能、面向列、可伸缩的分布式存储系统,利用HBase技术可在廉价PC Server上搭建起大规模结构化存储集群。 在调控层的开发过程中,调控文件可以录入多个子规则,因此系统拆分出多个调控子规则,用于运价匹配查询时用。由于预先设计的不完善,调控文件和调控子规则都保存到hbase中,因此才会涉及到hbase分页和hbase排序问题,虽然解决了这个问题,但是觉得调控文件确实没必要放在hbase中,因为它不参与运价的匹配查询。 提示:关系型数据操作尽量不要用hbase作为数据库。 第一部分 数据结构 表定义 表名:目前表名定义”T_”+实体名大写 列族:列族定义不超过三个。目前只定义了一个列族”BASEINFO” 数据结构定义 属性类型:推荐使用string。在传统的数据库中因为数据的大小不同,所以会用int、short、long、String、double来保存,定义数据格式的时候需要给定一个大小,但是在Hbase中,并不需要定义数据存储空间大小。 属性名:大写 主键 主键:表名前缀+yyyyMMdd+4位序列号 备注:序号列从自增表中获取,每天定义重置为0. 3 初始化 表名和列族必须先初始化,该表才能使用。示例:create 'T_XCONTROL','BASEINFO' 第二部分 表的初始化 代码参考:InitHBaseTable.properties InitHBaseTable 初始化策略 保留最新版本 只需要保存最新版本的数据HColumnDescriptor.setMaxVersions(1) 压缩策略 是否使用压缩策略 自动过期 数据自动过期,通过HColumnDescriptor.setTimeToLive(inttimeToLive)设置表中数据的存储生命期 预分区 介绍:hbase region split策略 是否使用预分区策略 写入内存 是否需要写入内存 4 第三部分 代码开发 CRUD操作 简单的CRUD操作,参考HBase权威指南(中文版).pdf,下面的是对HBase基本操作进行面向对象封装后的CRUD操作。所有以HBase作为存储数据库的DAO层,都继承 HBaseDaoImpl类,下列是使用示例。 新增操作 public String add(XControl control) throws Exception { String id = HBaseRowKeyUtil.getRowKey(controlTableName); control.setId(id); control.setStatus(Status.ADD.getValue()); PutDelete pd=HBaseConvetorUtil.convetor(control,id); super.savePutDelete(controlTableName, pd); return id; 更新操作 public String update(XControl control) throws Exception { String id = control.getId(); PutDelete pd=HBaseConvetorUtil.convetor(control,id); super.savePutDelete(controlTableName, pd); return id; } 查询操作 public XControl getXControl(String id) throws Exception { return super.get(XControl.class,controlTableName, id); } 删除操作 public void delete(String id) throws IOException { delete(controlTableName, id); } 5 表实例池 创建HTable实例是一项非常耗时的操作,通常耗时数秒才能完成。在资源高度紧张的环境下,每秒都有几千个请求,为每个请求单独创建HTable实例根本行不通。用户应当在一开始创建实例,然后再客户端生命周期内不断复用他们。 但是,在多线程环境中重用HTable实例会出现其他问题。 客户端可以通过HTablePool类来解决这个问题。它只有一个目的,那就是为HBase集群提供客户端连接池。 HTablePool类的使用参考HTablePoolUtil 表实例池 获取实例:HTablePoolUtil.getHTablePoolUtil().getHTable(tableName); 关闭实例:HTablePoolUtil.getHTablePoolUtil().putHTable(tableName); 获取总数 获取总数利用了HBase协处理器功能 1.配置 在$HBASE_HOME/conf/hbase-site.xml添加一个配置项。我用的0.94版本自带的实现为AggregateImplementation,具体如下 若之前未配置此项,则配置完后,需要重启hbase方能生效。 2.客户端使用代码示例 //获得符合条件结果总数 public Long getTotal(String tableName, Filter valueFilter){ Scan scan=new Scan(); if(null!=valueFilter){ scan.setFilter(valueFilter); } AggregationClient aggregationClient = new AggregationClient(conf); long rowCount = 0; try { scan.addColumn(Bytes.toBytes(\"BASEINFO\"), null);//必 6 须有此句,或者用addFamily(),否则出错,异常包含 ci **** rowCount aggregationClient.rowCount(Bytes.toBytes(tableName), scan); } catch (Throwable e) { e.printStackTrace(); } return rowCount; } = null, 列表分页 HBase的分页实现相对复杂一些。核心思想是结合分页过滤器 PageFilter(pageSize)和查询设置开始行scan.setStartRow(lastRow),lastRow为上一次查询rowkey,需要注意的是该rowkey是一个数组,对应多字段的存储位置; 不同用户登录会产生不同lastRow,因此我们把lastRow存储到session中,参考PageLastRowCache 。 为了解耦,我们又把对lastRow操作封装到HBaseDaoImpl ,以便开发写代码的时候不需要关心lastRow的操作。 public PageInfo searchXControl(QueryControlRuleQO qo,Integer pageSize,Integer currteIndex) throws Exception { //条件过滤器 FilterList filterList = new QueryControlRuleFilterList(qo).getFilterList(); //获得符合条件结果总数 Long total = getTotal(controlTableName, filterList); //过滤器集合 FilterList fl=new FilterList(); //分页过滤器 Filter filter = new PageFilter(pageSize); fl.addFilter(filterList); fl.addFilter(filter); //封装结果集 List log.info(\"--------------------- total : \" + list.size()); //返回结果集 PageInfo page = new PageInfo(total, list); return page; 7 } 列表排序 hbase都是按照字典序进行排序的,也就是降序,在页面的表现就是最早的数据(rowkey最小的)排在前面。 目前的解决方案是:给主键增加一个外键关联表,外键的生成规则是 400000000000-主键号,比如主键是X201401110001,对应外键则是X198598889999,为了实现升序排序功能,保存实体的时候用X198598889999作为主键,页面查询的时候再从关联表中根据X198598889999获取X201401110001。 备注:需要对新增、删除、查询进行关联操作。 示例: public String add(XControl control) throws Exception { pkControlDao.addXControlFK(id); } public void delete(String id) throws Exception { pkControlDao.deleteXControlFK(id); } public PageInfo searchXControl(QueryControlRuleQO qo,Integer pageSize,Integer currteIndex) throws Exception { //根据外键查询出匹配主键 if(StringUtils.isNotBlank(qo.getId())){ qo.setPKs(pkControlDao.getXControlPKs(qo.getId())); } 代码参考:HBaseRowKeyUtil PKXControlDaoHBaseImpl 第四部分 Hbase查询 比较运算符 注意:所有比较运算符匹配的时候都是拿数据库的数据值跟设定值比较,而不是拿设定值去跟数据库的数据值比较 LESS LESS_OR_EQUAL EQUAL NOT_EQUAL GREATER_OR_EQUAL GREATER NO_OP 8 匹配小于设定值的值 匹配小于等于设定值的值 匹配等于设定值的值 匹配与设定值不相等的值 匹配大于或等于设定值的值 匹配大于设定值的值 排除一切值 比较器介绍 BinaryComparator BinaryPrefixComparator NullComparator BitComparator RegexStringComparator SubstringComparator 使用Bytes.compareTo()比较当前值与阀值 与上面的相似,使用Bytes.compareTo()进行匹配,但是是从左端开始前缀匹配 不做匹配,只判断当前值是不是null 通过BitwiseOp类提供的按位与(AND)、或(OR)、异或(XOR)操作执行位级比较 根据一个正则表达式,在实例化这个比较器的时候去匹配表中的数据 把阀值和表中数据当String实例,同时通过contains()操作匹配字符串 上表示HBase对基于CompareFilter的过滤器提供的比较器,在调控项目中我们用到是BinaryComparator、NullComparator、RegexStringComparator,下面详细说明下BinaryComparator、NullComparator使用情况 BinaryComparator 对于所有的比较运算符都可以使用,因此在等于、不等于、范围匹配的时候用它就可以了。 NullComparator 在判断为空或者不为空的时候会用到比较器。 在使用NullComparator需要注意的是,HBase对空的定义。举例说明: row1的endarea是没有值的,但是在HBase中,它并表示空。 row2的endarea不存在该列,在HBase中,它表示空。 RegexStringComparator 跟SubstringComparator比较器作用差不多,常用来做字符串匹配,与等于、不等于比较运算符结合使用,不能与范围(LESS、GREATER……)比较运算使用。 9 常用过滤器介绍 HBase提供的过滤器有很多,详细参考HBase权威指南(中文版).pdf,在这次项目中用到的过滤器,我们主要用了SingleColumnValueFilter以及分页的时候用到PageFilter。 过滤器应用实例 注意:这里提供的过滤器实例都是针对单列值进行过滤的。 范围过滤:小于、小于或等于、大于、大于或等于、大于等于或小于、小于或大于 值过滤:等于、不等于 字符串过滤:匹配、不匹配 空过滤:空、非空 代码参考FilterHelper 过滤帮助类 过滤器集合的使用 在传统数据库查询中,经常会用到where A like ? and B=?,或者是where A like ? or B=?。 HBase实现这个功能,需要用到FilterList,示例: where A like ? and B=?可以这样写 FilterList andlist = new FilterList(Operator.MUST_PASS_ALL); andlist.addFilter(FilterHelper.getRegexStringFilter(field_A, field_A_Value)); andlist.addFilter(FilterHelper.getEqualFilter(field_B, field_A_Value)); where A like ? or B=?可以这样写 FilterList andlist = new FilterList(Operator.MUST_PASS_ONE); andlist.addFilter(FilterHelper.getRegexStringFilter(field_A, field_A_Value)); andlist.addFilter(FilterHelper.getEqualFilter(field_B, field_A_Value)); 复杂查询过滤 在上面查询比较简单,但实际业务中经常遇到更复杂的查询。例如:where (A like ? and B=?)or(where A like ? Or B=?),与上面示例相比,其实是多了一层嵌套。 在HBase中我们也可以嵌套FilterList来实现这种复杂的查询: FilterList andlist = new FilterList(Operator.MUST_PASS_ALL); andlist.addFilter(FilterHelper.getRegexStringFilter(field_A, 10 field_A_Value)); andlist.addFilter(FilterHelper.getEqualFilter(field_B, field_A_Value)); FilterList orlist = new FilterList(Operator.MUST_PASS_ONE); orlist.addFilter(FilterHelper.getRegexStringFilter(field_A, field_A_Value)); orlist.addFilter(FilterHelper.getEqualFilter(field_B, field_A_Value)); FilterList list = new FilterList(Operator.MUST_PASS_ONE); list.addFilter(andlist); list.addFilter(orlist); 在调控项目中我们用到很多这种FilterList嵌套,根据业务逻辑不同,嵌套的层级不同。 第五部分 HBase性能优化 查询缓存 Scan的caching属性默认值是1,意味着扫描器每次从region服务器抓取1条记录进行匹配。我们可以设置caching为比1大得多的值。例如,设置为500,则一次可以抓取500条,需要注意的是该值设得越大服务器的内存开销会越多。 HTableInterface hTable=getHTable(tableName); Scan scan=new Scan(); /*设置缓存*/ scan.setCaching(StaticConfig.getIControl_hbase_cache()); ResultScanner scanner= hTable.getScanner(scan); 多线程配置 Hbase.regionser.handler.count RegionServer中RPC监听器实例的数量。对于master来说,这个属性是master受理的处理线程(handler)数量。默认值是10。 根据调控层的业务场景,1条运价的匹配查询就会产生4条hbase并发查询。如果有20条,就可能有80条并发,这个并发量是相当的。除了将该参数适当调大可以增加并发处理能力外,还跟集群的数量和服务器的配置有直接的关系,预计集群数量越多,服务器CPU核数越高,并发处理能力越强。 11 预分区 HRegion是Hbase中分布式存储和负载均衡的最小单元。最小单元就表示不同的Hregion可以分布在不同的HRegion server上。但一个Hregion是不会拆分到多个server上的。 Hbase.hregion.max.filesize HstoreFile的最大值。Region中任何一个列族的存储文件如果超过了这个上限,就会被拆分成两个region。默认:268435456(256x1024x1024),即256M。 我们的调控文件比较小,要达到分区最大上限256M需要较多的调控文件。为了提高并发量,我们需要在没有达到分区上限的情况下,产生多个hregion来保存和处理数据,这里就用hbase的预分区功能。 示例: Configuration conf = HBaseConfiguration.create() HBaseAdmin admin = new HBaseAdmin(conf); HTableDescriptor desc = new HTableDescriptor( Bytes.toBytes(tablename)); HColumnDescriptor coldef = new HColumnDescriptor( Bytes.toBytes(colfamily)); admin.createTable(desc, Bytes.toBytes(1L), Bytes.toBytes(10L), 10); //以第一位字符不同划分区 desc.setValue(HTableDescriptor.SPLIT_POLICY, KeyPrefixRegionSplitPolicy.class.getName()); desc.setValue(\"prefix_split_key_policy.prefix_length\ 附录:代码 InitHBaseTable public class InitHBaseTable { private static Logger log Logger.getLogger(InitHBaseTable.class); private static Configuration conf HBaseConfiguration.create(); private static PropertiesConfiguration config = null; static{ Configuration conf = HBaseConfiguration.create(); try { config = new PropertiesConfiguration( 12 = = \"InitHBaseTable.properties\"); } catch (ConfigurationException e) { log.error(\"配置加载错误:\" + e.getMessage(), e); } } public void init() { try { List