HBase应用 | HBase性能优化
一、Rowkey设计
1、Rowkey长度原则
Rowkey是一个二进制码流,Rowkey的长度建议设计在10-100个字节,最好不要超过16个字节。
原因有:
- 数据的持久化文件HFile中是按照KeyValue存储的,如果Rowkey过长,比如100个字节,1000万列数据光Rowkey就要占用100*1000万=10亿个字节,将近1G数据,这会极大影响HFile的存储效率。
- MemStore将缓存部分数据到内存,如果Rowkey字段过长内存的有效利用率会降低,系统将无法缓存更多的数据,这会降低检索效率。因此Rowkey的字节长度越短越好。
- 目前操作系统都是64位系统,内存8字节对齐。控制在16个字节,8字节的整数倍利用操作系统的最佳特性。
2、Rowkey散列原则
如果Rowkey是按照时间戳的方式递增,不要将时间放在二进制码的前面,建议将RowKey的高位作为散列字段,由程序循环生成,低位放时间字段,这样将提高数据均衡分布在每个RegionServer实现负载均衡的几率。如果没有散列字段,首字段直接是时间信息将产生所有新数据都在一个RegionServer上堆积的热点现象,这样在做数据检索的时候负载将会集中在个别RegionServer,降低查询效率。
3、Rowkey唯一原则
必须在设计上保证Rowkey的唯一性。
二、Region优化
1、预先分区
默认情况下,在创建HBase表的时候会自动创建一个Region分区,当导入数据的时候,所有的HBase客户端都向这一个Region写数据,直到这个Region足够大了才进行切分。一种可以加快批量写入速度的方法是通过预先创建一些空的Regions,这样当数据写入HBase时,会按照Region分区情况,在集群内做数据的负载均衡。
2、HFile大小设计
- Region过大会发生多次compaction,将数据读一遍并重写一遍到HDFS上,占用磁盘IO;
- Region过小会造成多次split,Region 会下线,影响访问服务。
最佳的解决方法是调整hbase.hregion. max.filesize 为256m。
3、RegionServer资源配置
1)磁盘资源
每台 RegionServer 管理 10~1000 个 Regions,每个 Region 在 1~2G,则每台 Server 最少要 10G,最大要1000*2G=2TB,考虑 3 备份,则要 6TB。方案一是用 3 块 2TB 硬盘,二是用 12 块 500G 硬盘,带宽足够时,后者能提供更大的吞吐率,更细粒度的冗余备份,更快速的单盘故障恢复。
2)内存资源
在不影响其他服务的情况下,越大越好。例如在 HBase 的 conf 目录下的 hbase-env.sh 的最后添加 export HBASE_REGIONSERVER_OPTS="-Xmx16000m$HBASE_REGIONSERVER_OPTS”
其中 16000m 为分配给 RegionServer 的内存大小。
3)RegionServer的请求处理I/O线程数
较少的 IO 线程适用于处理单次请求内存消耗较高的 Big Put 场景 (大容量单次 Put 或设置了较大 cache 的Scan,均属于 Big Put) 或 ReigonServer 的内存比较紧张的场景。
较多的 IO 线程,适用于单次请求内存消耗低,TPS 要求 (每秒事务处理量 (TransactionPerSecond)) 非常高的场景。设置该值的时候,以监控内存为主要参考。
在 hbase-site.xml 配置文件中配置项为 hbase.regionserver.handler.count。
三、数据热点问题
1、出现数据热点问题原因
出现数据热点问题的原因有:
- HBase中的数据是按照字典顺序排序的,当大量连续的Rowkey集中写在个别的region,各个region之间数据分布不均衡;
- 创建表时没有提前预分区。创建的表默认只有一个region,大量的数据写入当前region;
- 创建表已经以前预分区,但是设计的Rowkey没有规律可循,设计的Rowkey应该由regionNo + messageId组成。
2、如何解决热点问题
解决数据热点问题目前有两种方案:Hash和Partition。
1)hash方案
hash就是rowkey前面由一串随机字符串组成,随机字符串生成方式可以由SHA或者MD5方式生成,只要region所管理的start-end keys范围比较随机,那么就可以解决数据热点问题。
2)partition方案
partition顾名思义就是分区式,这种分区有点类似于MapReduce中的Partitioner,将区域用长整数作为分区号,每个region管理着相应的区域数据,在rowkey生成时,将ID取模后,然后拼上ID整体作为rowkey,这个比较简单,必须要取样,splitkeys也非常简单,直接是分区号即可。
四、数据读取
1、客户端一次从服务器拉取的数量
通过配置一次拉去的较大的数据量可以减少客户端获取数据的时间,但是它会占用客户端内存。有三个地方可进行配置:
- 在 HBase 的 conf 配置文件中进行配置 hbase.client.scanner.caching;
- 通过调用HTable.setScannerCaching(intscannerCaching) 进行配置;
- 通过调用Scan.setCaching(intcaching) 进行配置。三者的优先级越来越高。
五、数据写入
1、批量写
HBase 的 Put 支持单条插入,也支持批量插入,一般来说批量写更快,节省来回的网络开销。在客户端调用JavaAPI 时,先将批量的 Put 放入一个 Put 列表,然后调用 HTable 的 Put(Put 列表) 函数来批量写。
2、缓冲区大小
hbase.client.write.buffer
这个参数可以设置写入数据缓冲区的大小,当客户端和服务器端传输数据,服务器为了提高系统运行性能开辟一个写的缓冲区来处理它,这个参数设置如果设置的大了,将会对系统的内存有一定的要求,直接影响系统的性能。
3、写数据备份
备份数与读性能成正比,与写性能成反比,且备份数影响高可用性。有两种配置方式,一种是将 hdfs-site.xml拷贝到 hbase 的 conf 目录下,然后在其中添加或修改配置项 dfs.replication 的值为要设置的备份数,这种修改对所有的 HBase 用户表都生效,另外一种方式,是改写 HBase 代码,让 HBase 支持针对列族设置备份数,在创建表时,设置列族备份数,默认为 3,此种备份数只对设置的列族生效。
4、WAL(预写日志)
可设置开关,表示 HBase 在写数据前用不用先写日志,默认是打开,关掉会提高性能,但是如果系统出现故障(负责插入的 RegionServer 挂掉),数据可能会丢失。配置 WAL 在调用 JavaAPI 写入时,设置 Put 实例的WAL,调用 Put.setWriteToWAL(boolean)。