当前位置: 首页 > 科技观察

P0故障导致“线上业务”HBase参数应该如何调优?

时间:2023-03-15 17:20:24 科技观察

1。背景由于种种原因,最近将核心业务生产使用的HBase迁移到了云端的弹性MapReduce(EMR)集群,并使用了EMR的HBase组件的默认参数配置。结果在流量高峰期出现主机故障,两个核心节点(部署了regionserver和datanode)挂掉了。大量regionrits需要15分钟自动恢复,强制P0故障。在查看磁盘时发现由于云端EMR默认设置了hdfssockettimeout参数为900000(15min),导致region再次上线读取时等待15分钟才重试下一个节点故障节点的WAL日志。.这种自愈时间显然不符合“线上业务”的需求。需要将这个超时时间调整为60000(1min),以达到快速自愈的目的。因此,结合HBase自身组件的特点和“线上业务”的高可用、低抖动需求,全面梳理出HBase参数调优的最佳实践。2.首先回顾一下HBase的基础设施。这里只是简单回顾一下整体架构,这样我们就可以把需要优化的参数与各个组件进行对比。2.1总体架构在物理结构上,HBase包括zookeeper、HMaster、RegionServer三类服务器,形成主从结构。RegionServer主要用于服务读写操作。当用户通过客户端访问数据时,客户端直接与HBaseRegionServer通信。HMaster主要进行RegionServer管理、DDL(创建、删除表)操作等。Zookeeper是HDFS(Hadoop分布式文件系统)的一部分,主要用于维护整个集群的生存,保证HA和自动故障转移。底层存储仍然依赖于HDFS。Hadoop的DataNode存储的是RegionServer管理的数据,HBase的数据全部存储在HDFS中。Hadoop的NameNode维护着所有物理数据块的元数据。2.2RegionServer组成一个RegionServer运行在一个HDFSDataNode上,有如下组件:WAL:全称WriteAheadLog,属于分布式系统上的文件。主要用于存储尚未持久化到磁盘的新数据。如果新数据还没有持久化,节点挂了,那么可以用WAL恢复数据。BlockCache:是读缓存。它存储经常访问的数据。当缓存已满时,清除最近最少访问的数据。MenStore:是写缓存。它存储尚未写入磁盘的数据。它会在写入磁盘之前对自己的数据进行排序,以保证数据的顺序写入。每个区域的每个columfamily都会有一个对应的memstore。HFiles:按字典顺序存储每一行??的键值。3、读取优化3.1优化读写内存比例一个RegionServer上有一个BlockCache和N个Memstores,它们的大小之和必须小于HeapSize*0.8,否则HBase无法启动,因为还有一些内存留给保证其他任务的执行。BlockCache作为读缓存,更看重的是读性能。如果读取较多,建议使用1:4内存的机器,如:8cpu32g或16pu64g的机器。在读多写少的场景下,可以通过增大BlockCache的值,减小Memstore的值来提升读场景的性能。核心调整参数如下:-hfile.block.cache.size=0.5-hbase.regionserver.global.memstore.size=0.33.2减少HFile的个数因为HBase在读取的时候没有命中缓存,所以需要打开H文件。如果HFile文件越多,IO次数越多,读延迟就越高。因此,HBase通过compaction机制合并HFiles。但是对于“线上业务”来说,在白天流量高峰的时候做compact会严重影响磁盘IO,造成读写毛刺,所以需要限制compact的速度。3.3启用“短路读取”功能。HBase数据存储在HDFS中。从HDFS读取数据需要经过DataNode。开启Short-CircuitLocalRead后,客户端可以直接读取本地数据。假设有两个用户User1和User2。User1有权限访问HDFS目录下的/appdata/hbase1文件,而User2没有这个权限,但是User2需要访问这个文件。然后就可以在UNIX中使用“文件描述符传输”了。”该机制让User1打开一个文件得到一个文件描述符,然后把文件描述符传递给User2,然后User2就可以读取文件的内容,即使User2没有权限。这个关系映射到HDFS。DataNode可以可以看作是User1,客户端DFSClient可以看作是User2,要读取的文件是DataNode目录下的/appdata/hbase1文件,实现如下图:核心参数如下:-dfs.client.read.shortcircuit=true3.4启用“HedgeRead”功能(需要评估磁盘IO)当我们启用“Short-CircuitRead”功能时,会优先通过Short-CircuitLocalRead功能尝试本地读,但是在某些特殊情况下,可能会因为磁盘问题或者网络问题,导致本地读短时间失败,为了应对此类问题,HBase实现了“对冲读”特性HedgedRead基本工作原理该机制的主要内容是:客户端发起一个l本地读取,一旦一段时间后没有返回,客户端就会向其他DataNode发送相同数据的请求。无论哪个请求先返回,另一个都将被丢弃。当然这个特性会明显放大磁盘IO的压力,需要慎重评估和使用。核心参数如下:(根据实际环境调整参数)。-dfs.client.hedged.read.threadpool.size=10//指定使用多少线程来服务对冲读取。如果此值设置为0(默认值),则禁用对冲读取-dfs.client.hedged.read.threshold.millis:默认值为500(0.5秒):产生第二个线程之前等待的时间。4.写入优化4.1增加MemStore的内存面对“多写少读”的场景,可以考虑增加MemStore的内存配比,降低BlockCache的内存配比,这和BlockCache的思路正好相反阅读优化3.1。具体可以根据读写的比例来评价。4.2适当增加HFile的生成本文与3.2不冲突,需要权衡。在数据写入过程中,MemStore会在满足一定条件时刷入磁盘,并生成一个HFile文件。当一个Store下的HFile数量大于一定的阈值时,会导致写入或更新阻塞。RS日志中将出现类似“存储文件太多...”的内容。当这种情况发生时,你需要等待Compaction来减少HFiles的数量。这里,主要是MinorCompaction,也就是小型合并。所以我们尽量提高这个阈值来减少压缩。核心参数:-hbase.hstore.blockingStoreFiles=100如果写入速度快,很容易带来大量的HFile,因为HFile合并的速度没有写入速度快。Majorcompaction需要在业务低峰期进行,以充分利用系统资源。如果HFile无法缩减,则需要添加节点。4.3适当增加Memstore的阻塞因子当MemStore的大小达到刷新阈值(hbase.hregion.memstore.flush.size,默认128M)时,就会被刷新到磁盘,这个操作基本不会被阻塞。但是,当一个Region中所有MemStore的大小达到一个blockingmultiplier(hbase.hregion.memstore.block.multiplier,默认值为4,即4倍刷新阈值默认为4*128=512M),所有Region中的MemStore会被阻塞。更新请求和强制刷新。客户端可能会抛出RegionTooBusyException。为了尽可能避免写阻塞,可以适当调整这两个参数。核心参数包括:-hbase.hregion.memstore.flush.size=128-hbase.hregion.memstore.block.multiplier=45IO优化HBase使用compaction机制换取大量读延迟毛刺和一定的写阻塞总体读取延迟是平坦的。为了综合平衡性能和稳定性,需要限制compation的速度。核心调整参数如下:-hbase.offpeak.end.hour=6//不限速compact结束时间-hbase.offpeak.start.hour=22//不限速compact开始时间-hbase.hstore.compaction.throughput.higher.bound=15728640//最大限速compact为15M-hbase.hstore.compaction.throughput.lower.bound=10485760//最小限速compact为10M-hbase.hregion.majorcompactio=0//OFFTimingmajorcompaction-hbase.regionserver.thread.compaction.large=1//Compationthread-hbase.regionserver.thread.compaction.small=1//Compactionthread-hbase.hstore.compaction.max=3//AMinorCompaction合并HFile文件的最大数量需要注意的是,白天compaction限速,关闭scheduledmajorcompaction后,可能会导致HFile合并不足。所以可以考虑通过外部控制(比如javaapi)在晚上做majorcompaction来减少HFiles的数量。6、故障恢复优化导致RegionServer由于各种原因宕机,包括FullGC、网络异常、官方bug(关闭等待端口未关闭)、DataNode异常等。在这些场景下,一旦RegionServer宕机,HBase会检测立即宕机,检测到宕机后,会将宕机的RegionServer上的所有Region重新分配给集群中其他正常的RegionServer,然后根据HLog丢失数据恢复,恢复完成后即可对外提供服务。整个过程自动完成,不需要人工干预。基本原理如下图所示:当datanode异常时,如果读取超时设置(dfs.client.socket-timeout和dfs.socket.timeout)过大,region无法正常读取WAL日志,这会导致恢复时间的增加。核心参数如下:-dfs.client.socket-timeout=60000-dfs.datanode.socket.write.timeout=480000-dfs.socket.timeout=600007其他优化7.1拆分策略HBase2.0采用的拆分策略.0及以上是SteppingSplitPolicy。SteppingSplitPolicy前期region数量少时,分裂阈值低,会更频繁地触发分裂。我们已经对表进行了预分区,所以拆分策略可以设置为固定大小(大小由参数hbase.hregion.max.filesize决定)。核心参数:-hbase.regionserver.region.split.policy=org.apache.hadoop.hbase.regionserver.ConstantSizeRegionSplitPolicy7.2开启rsgrouprsgroup对扩缩容等运维操作很有帮助,可以很好的控制移动的地区影响。move_servers_rsgroup命令的for循环将区域一个接一个地移动。-hbase.coprocessor.master.classes=org.apache.hadoop.hbase.rsgroup.RSGroupAdminEndpointhbase.master.loadbalancer.class=org.apache.hadoop.hbase.rsgroup.RSGroupBasedLoadBalancer另外,为了避免元表“Retrystorm”,regiondriftfails(开启状态异常),可以为meta表设置一个独立的rsgroup,与业务rsgroup隔离。同时,增加元表中的处理程序数量。-hbase.regionserver.metahandler.count=400//建议根据客户端数量评估设置。8.小结本文从HBase“基础设施”出发,梳理各组件参数调优及读写流程,希望能满足“线上业务”的高可用、低抖动需求。