许经伟,李公平,王文学,郝 睿,李 夏
(中国电信股份有限公司安徽分公司,安徽 合肥 230000)
HBase 作为一种可扩展的NOSQL 数据库,能够部署到上千台机器上,存储数十亿行,在PB 级别数据量上提供根据Rowkey 的低延迟接口查询[1]。HBase 自身已经实现了一定程度的容错性高可用性。但要想稳定的使用HBase 提供实时接口查询,需要建立对HBase 应用的一整套监控和分析方法。这需要建立对整个接口查询链路上各种组件的监控,这些组件包括了调用HBase 服务的Tomcat、WebLogic 等常见Web 容器,以及HBase和HDFS 实例。并且还要引入一些开源工具对Web 容器实例、HBase 实例、HDFS 实例进行性能分析和故障分析。客户端访问HBase 应用的整个链路涉及到若干个部分,包括HBase 客户端、HBase 服务、HDFS 服务和操作系统。分析HBase 应用需要监控以上服务或基础设施的关键指标。
服务端监控指标包括Kerberos 服务、HBase 服务、HDFS 服务和服务端主机监控指标。
Kerberos 认证服务监控指标包括KDC 的服务状态、KDC 的认证时长。
HBase 服务监控指标包括HBase Master 监控、Region Server 监控、Table 监控、Region 监控几部分。
(1)HBase Master 监控指标包括Region Assign 指标、Server 指标。Region Assign 监控指标包括RIT 时长、RIT 数量、Assign 次数、批量Assign 次数;Server指标包括平均负载、Active RegionServer 数量、Dead RegionServer 数量、总请求数。
(2)RegionServer 监控指标包括JVM 指标、线程指标、Server 指标、IPC 指标。JVM 指标包括堆内存使用率、GC 时长、GC 次数、阻塞线程数、可运行线程数、等待线程数、定时等待线程数;线程指标包括当前线程数量、线程数量峰值;Server 指标包括Region 数量、Store 数量、读取请求数、写入请求数、分裂队列长度、刷新队列长度、压缩队列长度、hedge 读取次数;IPC 指标包括队列长度、打开连接数、P75处理时长、P90处理时长、P95处理时长、P98处理时长、P99处理时长、P999处理时长、P75队列时长、P90队列时长、P95队列时长、P98队列时长、P99队列时长、P999队列时长。
(3)Region 监控指标包括Store 数量、Store 文件数量、MemStore 大小、Store 文件大小、读取请求数、写入请求数、Append 次数、Delete 次数、Get 次数、Mutate 次数、Scan 次数、Increment 次数。HDFS 监控包括NameNode监控、DataNode 监控。
(4)NameNode 监控指标包括JVM 指标、文件系统指标、RPC 指标、RPC 活动详情指标、文件系统状态指标。JVM 指标包括堆内存使用率、GC 时长、GC 次数、阻塞线程数、可运行线程数、等待线程数、定时等待线程数;文件系统指标包括总块数、总文件数、丢失块数量、损坏块数量、副本不足块数量、待定删除块数量、待复制块数量、总负载、容量使用率、锁队列长度;RPC 指标包括用户打开连接数、RPC 入队列次数、RPC 队列平均时长、RPC 处理次数、RPC 处理平均时长、RPC 认证失败次数、RPC 认证成功次数、RPC 授权成功次数、RPC授权失败次数、打开连接数、调用队列长度、缓慢RPC次数;RPC 活动详情指标包括获取块位置次数、获取块位置平均时长、获取块次数、获取块平均时长、创建文件次数、创建文件平均时长、创建目录次数、创建目录平均时长、获取文件信息次数、获取文件信息平均时长、删除文件次数、删除文件平均时长、fsync 次数、fsync平均时长、complete 操作次数、compete 操作平均时长、追加写次数、追加写平均时长;文件系统状态指标包括文件系统状态、活动DataNode 数量、死亡DataNode 数量、卷损坏数量、过期的DataNode 数量、过期的卷数量、TopUser 及操作数量、维护状态的DataNode 数量。
(5)DataNode 监控指标包括DataNode 活动指标、JVM 指标、RPC 活动指标。DataNode 活动指标包括损坏卷数量、读取块平均响应时长、写入块平均响应时长、块汇报次数、块汇报平均时长、增量块汇报次数、增量块汇报平均时长、flush 平均时长、fsync 平均时长;JVM 指标包括堆内存使用率、GC 时长、GC 次数、阻塞线程数、可运行线程数、等待线程数、定时等待线程数。
基础设施监控包括主机CPU 监控、主机内存监控、主机磁盘监控。主机CPU 监控指标包括CPU 使用率、平均负载;主机内存监控指标包括内存使用率、交换区使用率、脏页字节数、物理内存写回磁盘字节数;主机磁盘监控指标包括读取字节数、写入字节数、读取次数、写入次数、磁盘使用率、磁盘队列时间、磁盘队列长度、磁盘服务时间;主机网络监控指标包括接收字节数、发送字节数、接收包数量、发送包数量、接收丢包数、发送丢包数、TCP 连接数、DNS 解析时长。
在IT 服务监控领域,存在着大量的开源监控软件,包括Zabbix、Nagios、OpenTSDB、Prometheus 等。Prometheus 是由Google 开源的监控报警系统和时序列数据库(TSDB)。Prometheus 使用Go 语言开发,是Google 公司BorgMon 监控系统的开源版本,性能足够支撑上万台规模的集群。
近几年兴起的监控系统大部分都选择了将数据存储在时序型数据库中,Prometheus 用的就是自研的TSDB,时序数据库在高并发的情况下,读写性能远高于传统的关系数据库,另外Prometheus 还提供了很多内置的基于时间的处理函数,简化数据聚合的难度。
Prometheus 在收集数据时,采用的Pull 模型(服务端主动去客户端拉取数据),Pull 模型在云环境中有着比较大的优势,原因是分布式系统中,一定是有中心节点知道整个集群信息的,那么通过中心节点就可以完成所有要监控节点的服务发现和数据拉取。
Zabbix 适合监控对象增减不频繁的情况,如基础设施监控,而Prometheus 适合集群环境下,监控对象频繁增减的情况。
Prometheus 的基本原理是通过HTTP 协议周期性抓取被监控组件的状态,任意组件只要提供对应的HTTP接口就可以接入监控。输出被监控组件信息的HTTP 接口叫做exporter。目前常用的开源组件大部分都有自带的exporter 可用,如haproxy、nginx、mysql、linux 操作系统,但是Hadoop 生态圈的组件并没有自带的exporter可用,所以需要针对HBase、hdfs 开发对应的exporter软件Prometheus 中的AlertManager 负责将Prometheus产生的报警信息发送到各种通知的渠道,如邮件、短信、微信等。在实际操作中,一般会配置一个通知脚本完成后续的短信通知。
客户端监控指标包括Web 容器监控指标、应用响应指标。Web 容器监控指标包括堆内存使用率、GC 时长、GC 次数、阻塞线程数、可运行线程数、等待线程数、定时等待线程数;应用响应指标包括调用成功率、调用响应时长、应用负载。
应用侧一般是Java Web 应用程序,部署在Tomcat或其他Web 容器中。对于这些实例的监控,我们采用Prometheus 监控JVM 相关的性能信息,采用Pinpoint 监控客户端调用HBase 服务的响应时长、异常信息和远程调用方法栈,采用阿里巴巴的Arthas 监控实时的JVM方法调用耗时。
Pinpoint 是基于Google Dapper 论文的一款全链路分析工具实现,提供了无侵入式的调用链监控等。
在由HBase 客户端、HBase 服务、HDFS 服务构成的复杂环境下,HBase 客户端发生报错或者响应缓慢的情况应该按照HBase 客户端、HBase 服务端、HDFS 服务的调用顺序依次进行分析。
HBase 客户端一般运行在Web 容器中,对外提供实时查询服务。当对外的实时查询服务出现异常时,需要分析主机和Web 容器相关的问题。
3.1.1 主机相关问题分析
主机相关的问题中,主要关注主机宕机、操作系统资源耗尽这几种情况。
(1)主机宕机
如果Web 容器所在的主机宕机,那么主机上部署的Web 容器也不能正常提供服务。主机宕机一般可能因为硬件故障、人为关机和交换区耗尽造成。一是硬件故障引起的主机宕机,通过ping 监控很容易发现。这种情况需要更换故障硬件处理。二是认为关机造成的主机宕机,也可以通过ping 监控发现。将主机启动即可,启动后在系统操作日志中可以看到关机的操作记录。三是当交换区耗尽时,一般物理内存也会耗尽。这时主机可以ping通,但主机上运行的Web 容器和监控程序都会不响应。这种情况需要通过SSH 登陆监控来探测,重启主机即可解决问题。
(2)操作系统资源耗尽
Web 容器在运行时,需要向操作系统申请CPU、文件句柄、进程等资源。当Web 容器申请的此类资源达到操作系统当前用户的限制,就会导致调用失败。一是主机CPU 使用率持续100%,程序运行缓慢。这种情况通过监控可以提前发现。二是文件句柄耗尽,通常由应用未释放资源引起,通过监控可以提前发现。三是进程数达到限制,通常由应用未释放资源引起,通过监控可以提前发现。四是文件系统满,通过df 可以查看文件系统空间限制,通过监控可以提前发现。
3.1.2 Web 容器相关问题分析
(1)服务进程退出
如果Web 容器进程因为某些异常或者其他情况造成进程退出,那么服务端口也不会监听。如果客户端调用服务返回端口不存在的异常,那么可以断定是Web 容器退出导致调用失败。在Web 容器的日志中会记录退出的原因,可能的原因有:一是被用户用kill 命令杀死,在应用日志和操作系统日志中会看到kill 操作记录;二是主机操作系统崩溃或者维护重启后Web 容器没有自动拉起,通过linux 主机的/var/log/message 日志可以看到重启发生的时间和异常信息;三是JVM 内存溢出导致进程退出,在日志中会看到OutOfMemory 的异常;四是JVM 缺陷导致进程退出,在web 容器目录下会看到hs_err_pid**.log 的日志。
(2)分配的资源耗尽
一是数据库连接池满造成服务响应缓慢,在日志中会看到连接池满的异常。这种情况需要排查数据库连接使用完毕后有没有合理地关闭。二是内存溢出造成服务响应缓慢,在日志中会看到OutOfMemory 的异常。这种情况需要用jmap 工具导出Java 堆,离线分析堆中是否分配了大量对象,这些对象在短期内不能被垃圾回收机制清理。三是线程池满造成服务响应缓慢。这种情况需要使用jstack 导出threaddump 文件,分析线程等待的对象,找出引起线程池满的原因。也可以使用arthus 工具,在线对线程池进行诊断,
(3)依赖服务问题
Web 容器依赖的关系数据库、HBase 等服务性能下降,造成服务响应缓慢。这种情况需要部署pinpoint、skywalker 等apm 工具,监控相关的外部服务异常率、响应时长、方法栈,进一步找出Web 容器响应缓慢的直接原因。一是关系数据库性能差。如果是Oracle 数据库,需要结合Oracle 数据库的AWR、ASH、ADDM 报表,优化性能差的SQL 语句;如果是MySQL 数据库,需要结合慢日志分析,找出并优化性能差的SQL 语句。二是HBase 性能差。这种情况放在下面分析。
HBase 服务相关的问题中,主要关注资源竞争、负载不均衡、配置错误、Region 状态异常这几种情况。
3.2.1 资源竞争
HBase 单个Region Server 的负载上限约为8000 个请求/秒,当某个Region Server 上发生批处理作业查询HBase 的情况,批处理作业的批量scan 请求就会占满请求队列,其他的少量scan 或get 操作就会在队列中超时。使用hive 批处理写入Hbase 也是类似的情况。
为了解决此问题,HBase 引入了Region Server 分组的机制。每个分组包括若干个RegionServer,不同业务下的表通过配置RSGroup 属性的方式部署在不同分组。Hbase 通过RSGroup 实现了不同业务的物理隔离,解决了资源竞争的问题。
3.2.2 负载不均衡
负载均衡,英文名称为Load Balance,其意思就是分摊到多个操作单元上进行执行,例如Web 服务器、FTP 服务器、企业关键应用服务器和其他关键任务服务器等,从而共同完成工作任务。
正常情况下,对HBase 的访问请求是按照RowKey平均分布到若干个Region 上的,而这若干个Region 是平均分布在若干个Region Server 上的。
在负载不均衡的情况下,大部分的访问请求都落在某几个Region 上。这样会造成处理效率降低,也会造成Region 所在的RegionServer 的handler、内存等资源耗尽,部署在该Region Server 上的其他业务也会受到很大的影响。
(1)rowkey 设计不合理
HBase 中RowKey 可以惟一标识一行记录,在HBase 中检索数据有三种方式:一是通过get 方式,指定RowKey 获取惟一一条记录;二是通过scan 方式,设置startRow 和stopRow 参数进行范围匹配;三是全表扫描,即直接扫描整张表中所有行记录。
通常在关系数据库中,主键是以序列形式递增的。如果将这种方式照搬到HBase 数据库,在插入的场景下,数据永远会插入到最新的一个Region 中,这样就造成了数据热点。通过RowKey 设计避免数据热点有三种方法。一是反转。如果RowKey 在数据分布上不均匀,但RowKey 尾部的数据却呈现出了良好的随机性,可以考虑将RowKey 的信息反转。反转可以有效的使RowKey随机分布,但是牺牲了RowKey 的有序性。二是加盐。加盐的原理是在原RowKey 的前面添加固定长度的随机数,也就是给RowKey 分配一个随机前缀使它和之间的RowKey 的开头不同。随机数能保障数据在所有Regions间的负载均衡。三是哈希。基于RowKey 的完整或部分数据进行Hash,而后将Hash 后的值完整替换或部分替换原RowKey 的前缀部分。这里说的hash 包含MD5、sha1、sha256或sha512等算法。
(2)region 分布不均
HBase Master 有一个内置的叫做均衡器的特性。在默认的情况下,HBase Master 会每五分钟运行一次。一旦均衡器启动,它将尝试均匀分配region 到所有region服务器。
当均衡器没有正常工作时,部分RegionServer 会部署大量的Region,而部分RegionServer 会部署少量的Region,这样也会导致负载不均衡。有两种情况会导致均衡器没有正常工作:一是均衡器没有开启;二是HBase 集群中存在长期处于迁移状态的Region。如果均衡器没有开启,手动开启均衡器就可以解决问题。如果因为存在长期处于迁移状态的Region 造成均衡器不工作,需要先解决长期处于迁移状态的Region,才能开启均衡器。
(3)小region 过热
HBase 设计出来是为了存储数十亿行、TB 级存储的海量数据,但实践中也会用来存储一些100 M 左右的数据。按照HBase 默认的配置,10 G 大小一个Region,所以这些数据都会存储到一个Region 里面。当此类Region遇到大量查询时,负载会落到1个RegionServer 上,造成RegionServer 过载。以上问题有两种解决办法:一是按照负载情况,将小Region 继续拆分,用于分担负载;二是将此类小表迁移到Redis 内存数据库中提供查询。
3.2.3 配置错误
(1)客户端配置
①表Region 大小配置。为了避免HBase 运行时分裂影响读写性能,一般会在集群级别设置最大文件大小为一个较大的值,在建表前根据表大小预估分区数,将HBase 表分为若干个分区。在客户端建表语句中也可以指定MAX_FILESIZE 参数,这样客户端配置会覆盖服务端的配置。以Hbase 批量导入为例,在批量导入后会遇到Region 持续分裂的合并的问题,严重影响Hbase 表的访问。
②客户端重试配置。为了避免瞬时的网络抖动影响HBase 客户端的查询,一般会在Hbase 客户端配置hbase.client.retries.number 参数和hbase.client.pause 参数。这两个参数含义分别为重试次数和重试间隔,重试间隔单位为毫秒。正常情况下,客户端在放弃本次操作之前,会在几秒内进行若干次重试,每次间隔为几十毫秒。但是经常存在客户端将重试间隔配置为秒级,这样客户端就会一直卡住,造成故障。
(2)服务端配置
大合并配置。HBase 是一种Log-Structured Merge Tree 架构模式,用户数据写入先写WAL,再写缓存,满足一定条件后缓存数据会执行flush 操作真正落盘,形成一个数据文件HFile。随着数据写入不断增多,flush次数也会不断增多,进而HFile 数据文件就会越来越多。然而,太多数据文件会导致数据查询IO 次数增多,因此HBase 尝试着不断对这些文件进行合并,这个合并过程称为Compaction。HBase 配置了hbase.hregion.majorcompaction 用于控制major compaction 的间隔,这个设置默认为7 天。对于存在大量Region 的HBase 集群,一般倾向于在闲时进行major compaction。无论这个设置为什么数值,均无法保证在闲时进行major compation。所以这个配置一般配置为0[2],即禁用自动的major compaction,并且部署定时任务,在闲时触发major compaction。
3.2.4 Region 异常
(1)Region 下线
HBase 集群在读写过程中,可能由于Region 分裂 或Region均衡等导致Region的短暂下线,此时客户端与HBase 集群进行RPC 操作时会抛出NotServingRegionException 异常,从而导致读写操作失败。从服务端考虑,应尽量预分区,避免Region 自动分裂。对于Region 均衡,应在忙时关闭均衡,在每天读写压力较小时闲时打开,触发均衡操作。从客户端考虑,要保证region 下线期间,读写请求能在region 上线后恢复。对于写操作,应将未写入成功的记录,放到缓存中,每隔一段时间交给一个后台线程重新提交。对于读操作,可以合理设置重试次数。
(2)长期RIT 状态
RIT 是Region In Transition 的缩写,是指在一次操作中Region 处于迁移状态。迁移状态本来是HBase 操作中的正常状态,但是因为各种原因,有些Region 会处于长时间的RIT 状态,必须人为干预才能解决。
如果Region 长时间处在PENDING_CLOSE 状态,一般重启Hbase Master 就可以解决;如果Region 长时间处在FAILED_OPEN 状态,一般是是HBase Meta 表与HDFS 文件中的元数据信息不一致,通过查看Region Server 日志可以定位到问题,后续使用hbck 工具使Hbase Meta 表中元数据与HDFS 文件中的元数据信息一致即可。
3.3.1 NameNode 异常
NameNode 管理着文件系统树和所有文件、目录的元数据。Name Node 记录着每个文件中各个块所在的数据节点的位置信息。
在生产环境下,NameNode 一般会采用高可用架构。在高可用架构中,会同时启动两个NameNode,一个处于active 状态,另一个处于standby 状态。这样,当一个NameNode 所在的服务器宕机时,可以在数据不丢失的情况下,切换到另一个NameNode 提供服务。
两个NameNode 同时宕机的情况极少发生,当一个NameNode 发生宕机,通过Prometheus 监控系统就可以及时得到通知。更容易遇到的情况是NameNode 性能下降,这需要查看NameNode 进程自带的JMX 信息,采集平均响应时长、平均队列时长、负载、RPC 队列等指标进一步的分析问题。
3.3.2 DataNode 异常
HBase 数据在写入缓存(MemStore)前首先把数据顺序写入HLog 中,这种设计在遇到RegionServer 宕机时,可以从HLog 中回放日志,保证数据不丢失。
HLog 会同时写入三个副本到DataNode。当某个DataNode 响应速度慢,HLog 的写入速度也会变慢,相应的HBase 写入操作就会变慢。一般在RegionServer中会打印出“slow sync cost:230 ms current pipeline DataNode IP 地址”类似的日志。
这种情况需要检查DataNode 是否有坏盘,或者DataNode 的磁盘是否存在写入竞争,导致响应速度变慢。如果有坏盘,需要及时更换损坏的磁盘;如果磁盘存在写入竞争,需要根据业务决定是否将HBase 集群单独部署。
通过实际案例的研究发现,在使用Web 应用访问HBase 集群的整个调用过程中会遇到很多异常情况。将这些异常情况进行了分类,并且按照分类详细分析了每一种异常情况,针对可能发生异常的对象制定了详细的监控指标,并给出了监控方案,用于及时发现异常情况。最后,针对文中提出各种的异常情况,提出了可行的解决方案。