总结《HBase原理与实践》集群修复、调优、故障原因
目录
Hbase集群修复
HBase集群一致性主要包括两个方面
- HBase Region一致性 集群中所有Region都被assign,而且deploy到唯一一台RegionServer上,并且该Region的状态在内存中、hbase:meta表中以及ZooKeeper这三个地方需要保持一致。
- Hbase 表完整性 : 每个rowkey都仅能存在于一个Region区间。
详细信息:
hbase hbck -details
只对某张表:
hbase hbck TableA TableB
集群修复的基本原则是首先修复低风险的region一致性问题(以及部分表完整性问题),在修复部分高风险表完整性问题.
Hbase的低风险修复
低风险的Region一致性问题修复是指,这类修复仅仅涉及Master内存中Region状态、ZooKeeper临时节点中Region状态以及hbase:meta元数据表中Region状态的修改,并不实际修改任何HDFS文件。修复成功之后,Region的状态在.regioninfo文件、Master内存、ZooKeeper临时节点和hbase:meta元数据表中保持一致。
-fixAssignments
-fixMeta
除了Region一致性问题是低风险问题之外,部分表完整性问题的风险也不高。最典型的就是HDFS Region空洞(HDFSRegion holes)。这个命令会在空洞形成的地方填充一个空Region。
-fixMeta -fixAssignments -fixHdfsHoles // 一般是组合命令
-repairHoles // 或者直接用这个
HBCK的高危修复
Region区间overlap相关问题的修复属于高危修复操作,因为这类修复通常需要修改HDFS上的文件,有时甚至需要人工介入。建议先执行hbck -details命令,执行相应的修复命令。建议在overlap分析的基础上使用merge命令,强制将存在overlap的相关Region全部合并到一起。
需要注意的是,对于多个Region,需要两两合并,之后对合并后的Region执行MajorCompaction,再两两合并。
常见案例:
(1)Region没有部署到任何RegionServer上 先执行-fixAssignments命令,再执行hbck命令,看看是否还输出这样的信息。
(2)Region没有部署到任何RegionServer上且元数据表中对应记录为空, -fixMeta -fixAssignments.
(3)HBase version file丢失, HBase集群启动时会加载HDFS上的version file(/hbase-root/hbase.version)来确定HBase的版本信息,如果该文件丢失或损坏,则系统无法正常启动。
hbase hbck -fixVersionFile
Hbase调优
1. 操作系统级别调优
关闭selinux vim /etc/selinux/config disabled
做好时钟同步,关闭防火墙
vm.min_free_kbytes,代表系统所保留空闲内存的最低限watermark[min],达到就开始内存回收,HBase官方推荐别小于1G.
vm.swappiness=0 , 对于数据库来说,swap是尽量需要避免的,所以需要将其设置为0。此处需要注意,设置为0并不代表不执行swap。
关闭THP THP是一种动态管理策略,会在运行期分配管理大页,因此会有一定程度的分配延时
echo never/always >/sys/kernel/mm/transparent_hugepage/enabled
2. Hbase相关组件调优
- HDFS
- 开启短路度 当前HDFS读取数据都需要经过DataNode,客户端会向DataNode发送读取数据的请求,DataNode接收到请求后从磁盘中将数据读出来,再通过TCP发送给客户端。对于本地数据,Short Circuit Local Read策略允许客户端绕过DataNode直接从磁盘上读取本地数据,因为不需要经过DataNode而减少了多次网络传输开销,因此数据读取的效率会更高。
- Hedged Read 通常情况下HBase会根据一定算法优先选择一个DataNode进行数据读取。然而在某些情况下,有可能因为磁盘问题或者网络问题等引起读取超时,根据Hedged Read策略,如果在指定时间内读取请求没有返回,HDFS客户端将会向第二个副本发送第二次数据请求,并且谁先返回就使用谁,之后返回的将会被丢弃。
- 通过执行Major_compact提升数据本地率,major_compact本质上是将Region中的所有文件读取出来然后写到一个大文件,写大文件必然会在本地DataNode生成一个副本,这样Region的数据本地率就会提升到100%。
- zookeeper
- zookeeper.session.timeout 表示ZooKeeper客户端与服务器端session超时时间,超时之后RegionServer将会被踢出集群。
- 最大连接数
3. HBase参数优化
- region的默认大小,默认为10G,Region中最大的Store中所有文件大小一旦大于该值整个Region就会执行分裂。太大影响compaction,太小频繁分裂,消耗资源.
- BlockCache相关参数 RegionServer内存在20G以内的就选择LRUBlockCache,大于20G的就选择BucketCache中的offheap模式。采用combinedBlockCache,即两种缓存的搭配使用,L1采用LRUBlockCache,主要存储HFile中的元数据Block,L2采用BucketCache,主要存储业务数据Block。因为只用来存储元数据Block.
- memory flush 大小默认128M,适当调整256M.
- compact 相关参数, store中文件数, 参与合并文件数,增加合并线程数.
-
队列资源隔离 RegionServer可以同时提供写队列、get请求队列和scan请求队列,这样就将写请求、get请求和scan请求分发到不同的队列,不同队列使用不同的工作线程进行处理,有效隔离了不同请求类型的相互影响。
4. Hbase业务调优
- 表名强烈建议生产线创建表时不要单独使用表名,而应该使用命名空间加表名的形式。
- 列簇设置
- 设置合适的布隆过滤器 无, row, rowcol 默认是row
- TTL设置数据失效时间 , 数据会自动删除,是根据compact来实现的.
- 压缩算法 snappy, lz4, 推荐snappy压缩.
- 设置合理的列簇,
- 设置合理的版本
- BlockSize, 文件块大小,默认64k,是时间和空间的权衡选择.
- Hash散列rowkey, 这个能解决热点region问题,但是对scan操作不友好.
- 对rowkey进行加盐
- 表属性
- 合理预分区, 如果之前的预分区发现不合理,将数据导出,重新建表在预分区.
- HLog持久化级别
- 是否开启compact
5. JVM调优
每种应用都会有自己的内存对象特性,通常可分为两种:一种是短寿对象(指存活时间相对较短的对象,比如临时变量等)居多的工程,比如大多数纯HTTP请求处理工程,短寿对象可能占到所有对象的70%左右;另一种是长寿对象(指存活对象较长的对象,比如TTL设置较长的缓存对象)居多的工程,比如类似于HBase、Spark等这类大内存工程。
分析Hbase中的内存对象:
- RPC请求对象:随着rpc的销毁而消失,比如Request对象和Response对象,这些对象可以认为是短寿对象。
- MemStore对象: HBase的MemStore中对象一般会持续存活较长时间,用户写入数据到MemStore中之后对象就一直存在,直至MemStore写满之后flush到HDFS。这类对象属于长寿对象。
- BlockCache对象,和MemStore对象一样,BlockCache对象一般也会在内存中存活较长时间,属于长寿对象。
HBase系统属于长寿对象居多的工程,一方面,GC的时候要将RPC这类短寿对象在Young区淘汰掉;另一方面,要减少Old区的对象总量。
两种垃圾算法: CMS(并发标记清除算法) G1(并发标记整理算法)
调优点:增大-Xmn(新生代大小) 和 -XX:SurvivorRatio(新生代Eden和survivor区的比例)
G1的年轻代是由分散的多个Region组成,而且Region的个数会随着前面多次young GC的STW时间动态调整。若之前的young GC耗时比较长,则G1会调小young区大小,反之则调大,因为更大的young区明显会导致更长的STW耗时。
CMS老年代GC并不会挪动对象,只有在做full GC的时候才会挪动对象,处理碎片问题。理论上使用CMS无法避免STW的full GC。而G1可以通过多次mixed GC增量地处理内存碎片,所以,G1有能力完全避免STW的fullGC。•由于G1的老年代回收是增量式的,所以G1更加适合大堆。
G1 GC的调优思路包括以下几点:
- IHOP需要考虑常驻内存对象的总大小。
- 通过G1NewSizePercent和MaxGCPauseMillis来控制Young GC的耗时和触发mixed GC的时间间隔。
- 通过MixedGCCountTarget和OldCSetRegionThreshold来控制每次Mixed GC周期内执行mixed GC的次数以及单次mixed GC的耗时。
- 注意选择正确的SurvivorRatio。
HBase故障原因
1.长时间GC导致RegionServer宕机
排查关键:排查日志可以直接搜索两类关键字—— a long garbage collectingpause或者ABORTING region server。或者以在GC日志中搜索相应的关键字进行确认:concurrent mode failure或者promotion failed。
解决方案: JVM提供了参数XX:CMSInitiatingOccupancyFraction=N来设置CMS回收的时机,其中N表示当前老年代已使用内存占总内存的比例,可以将该值修改得更小使回收更早进行,比如改为60。
2. 大字段scan导致RegionServer宕机
排查关键:查看日志找到可疑日志"java.lang. OutOfMemoryError: Requested array sizeexceeds VM limit"在某些场景下scan结果数据太大导致JVM在申请array时抛出OutOfMemoryError,造成RegionServer宕机。
解决方案:要求客户端访问的时候对返回结果大小做限制(scan.setMaxResultSize (210241024)),并且对列数量做限制(scan. setBatch(100))。当然,0.98.13版本以后也可以在服务器端对返回结果大小进行限制,只需设置参数hbase.server.scanner.max.result.size即可。
3.MemStore占用内存大小超过设定阈值导致写入阻塞
排查关键:在日志中首先搜索关键字"Blockingupdates on"
排查方向:需要确定时MemStore内存超过默认配置,或者Hfile太多flush刷写阻塞。
一般原因:集群中有一张表使用了PREFIX_TREE编码,该功能在某些场景下会导致执行Compaction的线程阻塞,进而耗尽Compaction线程池中的所有工作线程。其他表的Compaction请求只能在队列中排队。•集群中所有Compaction操作都无法执行,这使不断flush生成的小文件无法合并,HFile的数量随着时间不断增长。
解决方案:1.强烈建议在生产环境中不使用PREFIX_TREE这种实验性质的编码格式.
2.生产环境对集群中HFile相关指标(store file数量、文件大小等)以及Compaction队列长度等进行监控,有助于问题的提前发现以及排查。
3.合理设置Compaction的相关参数。
HBase2.x核心功能:
- 基于Procedure v2重新设计了HBase的AssignmentManager和核心管理流程。通过Procedure v2,HBase能保证各核心步骤的原子性,从设计上解决了分布式场景下多状态不一致的问题。
- 实现了In Memory Compaction功能。该功能将MemStore分成若干小数据块,将多个数据块在MemStore内部做Compaction,一方面缓解了写放大的问题,另一方面降低了写路径的GC压力。
- 存储MOB数据。2.0.0版本之前对大于1MB的数据支持并不友好,因为大value场景下Compaction会加剧写放大问题,同时容易挤占HBase的BucketCache。而新版本通过把大value存储到独立的HFile中来解决这个问题,更好地满足了多样化的存储需求。
- 读写路径全链路Offheap化。在2.0版本之前,HBase只有读路径上的BucketCache可以存放Offheap,而在2.0版本中,社区实现了从RPC读请求到完成处理,最后到返回数据至客户端的全链路内存的Offheap化,从而进一步控制了GC的影响。
- 异步化设计。异步的好处是在相同线程数的情况下,提升系统的吞吐量。2.0版本中做了大量的异步化设计,例如提供了异步的客户端,采用Netty实现异步RPC,实现asyncFsWAL等