本文已参与「新人创作礼」活动,一起开启掘金创作之路。
前言
读写性能对于数据库来说是基准指标,如果读写性能无法达标的话,其余的功能是都浮云。HBase底层使用LSM tree理念实现的,注定了HBase都是重写轻读的特点。
在这种情况下,HBase读写性能的优化方向就应该是着重增加读写性能以及存储量;对于查询则是尽量在当前HBase支持的查询方式的基础上提高查询性能,至于查询的最终解决方案,可能需要借助第三方组件,如phoenix或者elasticsearch。
HBase 写入性能调优
HBase server端优化
Region数量控制
首先,在数据量大小可以预估,数据特点清楚明了的前提下,必须在建表时进行预分区,从而达到充分利用多server并行处理的能力。
其次,在预分区如果发现部分Region负载以及请求量不均匀,则需要切分部分请求负载高的Region,然后等待HBase自己负载均衡。但是如果想即时解决,则可以使用命令将部分Region迁移到其他 RegionServer 节点上,以达到充分利用服务器资源,负载均衡。
根据查询场景确定预分区策略
检查 RowKey 设计以及预分区策略,保证写入请求均衡。针对get查询为主的表,可以使用hash预分区策略;针对scan为主的表,建议使用分段预分区的策略。
使用 SSD 存储 WAL
将 WAL 文件写到SSD上,对于写性能会有非常大的提升。
使用该特性配置步骤:
使用 HDFS Archival Storage 机制,配置 HDFS 的部分文件目录为 SSD 介质
hbase-site.xml 添加配置
<property>
<name>hbase.wal.storage.policy</name>
<value>ONE_SSD</value>
</property>
hbase.wal.storage.policy 默认为 none,用户可以指定 ONESSD(WAL 一个副本写入 SSD 介质)或者 ALLSSD(WAL的三个副本全部写入 SSD 介质)。
HBase client端优化
离线导入使用 Bulkload 方案
Bulkload 是一个 MapReduce 程序,输出 HFile 文件。这种方式的业务场景是离线导入数据,优点是吞吐量大 ,效率高;缺点是实时性差。
是否需要写WAL?WAL是否需要同步写入
此处划重点:如果业务上能够忍受小部分数据丢失,且需要极限提高写入速度,可以考虑禁用WAL。这样做的缺点就是RegionServer宕机的时候会丢一部分数据,且无法做跨集群的replication。
数据写入流程可以理解为 一次顺序写WAL+一次写memstore,两者都写入成功后即可以返回client端写入成功。
WAL 的持久化分为四个等级:
- SKIP_WAL
- ASYNC_WAL
- SYNC_WAL
- FSYNC_WAL
默认为 SYNC_WAL 等级持久化数据。
根据业务关注点在 WAL 机制和写入吞吐量之间作出选择,用户可以选择异步写入WAL甚至可以忽略WAL。
Put使用批量提交
HBase 分别提供了单条 put 以及批量 put 的 API 接口,使用批量 put 接口可以减少客户端到 RegionServer 之间的 RPC 连接数,提高写入吞吐量。
另外,如果对数据实时性要求不是特别严格,可以考虑开启异步批量提交,用户可以设置 setAutoFlush(false),客户端缓存达到阈值(默认2M)后批量提交给 RegionServer。这样做的好处是能够减少RPC调用的次数,将数据从client端提交给server端的任务交给HBase来处理,提高吞吐量;缺点是如果客户端异常,缓存数据可能丢失。
写入HBase的单条数据不要太大
KeyValue 大小对写入性能影响巨大。如果太大,会对性能产生很大的影响。
RowKey的最大长度限制为64KB,但在实际应用中最多不会超过100B。这是由于HBase的rowkey会按照rowkey+columnFamily+qualifier+timestamp组成的cell被多次冗余存储,RowKey越大,浪费的内存和硬盘资源也会越多。
Value过大也会对性能产生很大的影响,也会影响到HBase的响应速度。如果Value过大,建议拆成多列存储,每次返回需要的值,或者将Value存储到HDFS上,在HBase中存储url
HBase 读取性能优化
HBase server端优化
读请求负载均衡
如果数据吞吐量较大,且一次查询返回的数据量较大,则Rowkey 必须进行散列化处理,同时建表必须进行预分区处理。
对于以get为主的查询场景,则将表进行hash预分区,均匀分布;如果以scan为主,则需要兼顾业务场景设计rowkey,在满足查询需求的前提下尽量对数据打散并进行负载均衡。
BlockCache策略设置
一个通用的规则就是:如果 JVM 内存配置量小于 20G,BlockCache 策略选择 LRUBlockCache;否则选择 BucketCache 策略的 offheap 模式。
如果是heap模式,也可以根据业务场景的读写比例来配置堆中读写heap的比例,默认堆中读写缓存均占heap的40%,即读写均衡。
HFile数量控制
一个 Store 中包含多个 HFile 文件,文件越多,检索所需的 IO 次数越多,读取延迟也越高。
文件数量通常取决于 minorCompaction 的执行策略,一般和两个配置参数有关: hbase.hstore.compactionThreshold 和 hbase.hstore.compaction.max.size ,前者表示一个 store 中的文件数超过阈值就应该进行合并;后者表示参与合并的文件大小最大是多少,超过此大小的文件不能参与合并。
可以查看 RegionServer 级别以及 Region 级别的HFile数量,确认 HFile 文件是否过多。
hbase.hstore.compactionThreshold 设置不能太大,默认为3个。
MajorCompaction的管理
MajorCompaction可以将一个store下的所有文件合并成一个,并在合并的过程中将修改和删除的数据一共处理完成,释放硬盘资源。
由于配置文件中默认的MajorCompaction是定时按表执行,且消耗资源很大,对系统性能影响同样很大,所以对于读取延迟以及系统性能波动敏感的业务通常不建议开启自动 MajorCompaction,而是利用脚本定时或者手动在业务低峰期触发;对于延迟不敏感的业务可以开启自动MajorCompaction,但建议限制流量。
数据本地化
尽量避免Region无故迁移。对于本地化率较低的节点,可以在业务低峰期执行MajorCompaction。
HBase client端优化
scan设置客户端缓存
在HBase总RPC次数调整到比较合理的前提下,可以考虑将大 scan 场景下将 scan 缓存从 100 增大到 500 或者 1000,用以减少 RPC 次数。
get使用批量请求
HBase分别提供了单条get以及批量get的 API 接口,使用批量 get 接口可以减少客户端到 RegionServer 之间的 RPC 连接数,提高读取吞吐量。
显式指定列簇或者列
在客户端查询时尽量指定列簇或者列进行精确查询,过滤不必要的列族或者列达到列裁剪的效果。
离线批量读取设置禁止缓存
离线批量读取请求设置禁用缓存,scan.setCacheBlocks(false),此种场景适用于离线的全表扫秒,如mapreduce。此时使用缓存不仅无法提升性能,可能还会适得其反。
布隆过滤器的使用
建议在任何业务都应该设置布隆过滤器,用空间换取时间。默认设置为 row,除非确定业务随机查询类型为 row + column,这是布隆过滤器设置为 rowcol(适合大量指定column的场景,这种场景下占用的缓存内存以及磁盘的量会增加)。
HBase的二级索引
HBase本身只支持三种查询方式,即单数据的get,范围数据的scan以及全表scan,这种情况下是没办法直接支持二级索引的,所以需要使用变通的方式支持二级索引,当前主流的方式有三种:
- HBase中创建二级索引表:rowkey是查询条件,value是原始数据的rowkey,这样的使用方式就是通过二级索引表查询到rowkey后再去主表查询原始数据。这种方式适合于有限的二级索引查询需求,过多可能会导致索引膨胀以及极其严重的写放大
- phoenix:可以在HBase上加一层phoenix,好处是可以使用phoenix管理HBase的二级索引,坏处是对HBase本身有侵入,且phoenix在稳定性以及性能上都会受到限制。这种方式适用于查询不算很复杂且对性能要求不是很严格的场景
- elasticsearch:最后一种则是HBase+elasticsearch方案,这种方案中使用HBase作为原始数据存储的介质,使用HBase的coprocessor协处理器来生成二级索引并存储在elasticsearch中,做到数据与索引分离,充分利用了elasticsearch搜索多样性以及数据聚合的优点以及HBase高吞吐量的优点。强强联合,除了需要维护两套组件外基本上可以面对所有的业务场景。由于elasticsearch扩展性极强,能支持多种插件,使得HBase具备了空间索引等高级属性。
结语
在大数据快速发展的今天,各种组件如雨后春笋般的出现,给了大数据更多的选择性。当前的大数据已经很少会有一个组件撑天下的场景了,更多的是相互配合,各取所长。而带来的好处也是很明显的,那就是一个组件过去很难办到或者成本很高的实现,换个组件可能很轻松愉快的就解决掉了。
所以当前阶段大数据的技术发展以及在纵向的基础上向横向发展了。而各个组件如何选型,组件之间如何配合,则成了架构师更多需要考虑的问题,也成为衡量一个架构师是否称职的基础了。