关于hadoop:数据库‖超万亿规模的Hadoop-NameNode性能故障排查过程分享

37次阅读

共计 5262 个字符,预计需要花费 14 分钟才能阅读完成。

随着国内互联网行业的倒退,万亿规模的超大集群尽管已不像几年前那么百里挑一,然而也并不多见,尤其是波及超万亿规模的超大集群性能故障排查的机会就更加稀少。

而这次我所进行的超万亿规模的 Hadoop NameNode 性能故障排查也是在我守业几年以来所遇到的集群规模最大,耗时最长,排查工作量最大,头发掉的最多,最终都不得不求助于大牛的一次经验。

因而在问题解决之后,我也第一工夫将这次的整个排查过程记录下来进行总结,心愿能给看到的各位同学有所帮忙。上面,enjoy:


起 因

事件的起因是因为近日客户反馈应用咱们数据库的成果忽然变差,之前秒级响应的数据查问与检索,当初却总是在“转圈”,卡住不动了。因为是忽然产生的景象,曾经在现场的同当时排除了业务变动,然而并未发现问题。作为本人创建公司后第一个接到的万亿数据体量的大我的项目,我本身也非常重视,马上第一工夫奔赴现场。

这里先容介绍一下该平台架构,底层采纳 hadoop 进行分布式存储,两头数据库采纳的录信 LSQL,数据实时导入采纳 kafka 进行。每天的数据规模是 500 亿,数据存储周期为 90 天,一共有 4000 多张数据表,其中最大的单表数据规模近 2 万亿条记录,总数据规模将近 5 万亿,存储空间占 8PB。

数据平台撑持的根本应用次要包含数据的全文检索、多维查问,以及地理位置检索、数据碰撞等操作。也会有局部业务波及数据的统计和剖析,会有极少量的数据导出与多表关联操作。


经 过

Before the day:初步定位问题

话说我在守业之前在腾讯做 Hermes 零碎,每日接入的实时数据量就曾经达到了 3600 亿 / 天,之后更是达到了每日近万亿条数据的实时导入。为了不显得那么凡尔赛,我只想说,我和梁启超在北大演讲时的情绪一样:我对超大集群没什么理解,然而还是有那么一点喽!面对以后每日 500-1000 亿规模的零碎,我在思考是不是买票的时候把当天的回程票也买了 ……

为了疾速定位问题,还没登程之前我就跟现场要了一些日志和 jstack,初步定位是 hadoop NameNode 的瓶颈,而 NN 的优化咱们此前也做了很屡次,别无其他,唯手熟尔。

下图为过后堆栈的剖析状况,预计在座诸位看了都会信念满满,这很显著就是 hadoop 卡顿。

②First Day:尝试调整 log4j

到现场的第一天,仍然是风和日丽,情绪持续放弃漂亮。

我到现场后第一件事件就是一直的抓 hadoop Namenode 的堆栈 Jstack。从中失去的论断是 问题的确是卡顿在 NN 上。此处 NN 是一个全局锁,所有的读写操作都在排序期待,详情如下图所示:

1. 卡在哪里

这个锁的期待个数居然长达 1000 多个,不卡才怪呢,咱们再细看一下,以后领有这个锁的线程在做什么?

2. 问题剖析

很显著,在记录 log 上存在瓶颈,阻塞的工夫太久。

1) 记录的 log4j 不应该加【%L】,它会创立 Throwable 对象,而这个在 java 里是一个重对象。

2) 日志记录太频繁,刷盘刷不动。

3) log4j 有全局锁,会影响吞吐量。

3. 调整计划

1) 客户的 hadoop 版本采纳的是 2.6.0 版本,该版本的 hadoop,在日志解决上存在诸多问题,故咱们将官网明确示意存在问题的 patch 打了进来

https://issues.apache.org/jir… 因日志起因导致 nn 慢

https://issues.apache.org/jir… 将日志记录到锁外,防止卡锁

https://issues.apache.org/jir… processIncrementalBlockReport 导致的记录日志问题,重大影响 NN 性能

2) 禁用 namenode 所有 info 级别的日志

察看发现当有大量日志输入的时候,全局锁会阻塞 NN。

目前批改形式是屏蔽到 log4j 的日志输入,禁用 namenode 所有 info 级别的日志。

3) log4j 的日志输入去掉【%L】参数

这个参数会为了失去行号而创立 new Throwable 对象,这个对象对性能影响很大,大量创立会影响吞吐量。

4) 启用异步审计日志

dfs.namenode.audit.log.async 设置为 true,将审计日志改为异步。

4. 优化成果

优化之后,的确因 log4j 导致的卡顿问题不存在了,但 hadoop 的吞吐量仍然卡,仍旧卡在 lock 上。

③Second Day:优化 du,排查解决所有卡顿

接着昨天的工作:

1. 在解决了 log4j 的问题后,持续抓 jstack,抓到如下地位:

2. 通过代码进行剖析,发现的确此处有锁,证实此处会引起所有拜访阻塞:

3. 持续深刻研读代码,发现受如下参数管制:

(2.6.5 版本这个默认值是 5000,曾经不存在这个问题了)

这个参数的外围逻辑是,如果配置上大于零的值,它会距离肯定文件数量,开释锁,让别的程序得以继续执行,该问题只会在 hadoop2.6.0 的版本里存在,之后的版本里曾经对此做了修复。

4. 解决办法

1) 打上官网 patch:

https://issues.apache.org/jir…

2) lsql 外部移除所有对于 hadoop du 的应用

5. 为什么要打 patch

2.6.5 版本中,能够本人定义休眠工夫,默认休眠工夫为 500ms,而 2.6.0 休眠工夫为 1ms, 我放心太短,会呈现问题。

持续依照原先思路,排查所有的 jstack。将所有波及卡顿的中央都一一解决掉,至此 hadoop 通过 jstack 曾经抓不到任何的流动线程,然而仍然卡顿在读写锁的切换上,这阐明:

1.namenode 外部的每个函数曾经最优,jstack 根本抓不到了;

2. 堆栈调用只能看到近 1000 个读写锁在一直切换,阐明 nn 的申请并发十分高,多线程之间锁的上下文切换曾经成为了次要瓶颈。

所以 当下次要思路应该落在如何缩小 NN 的调用频率下面。

④Third Day:尽可能减少 NN 申请频率

为了缩小 NN 的申请频率,尝试了多个办法:

1. 启用录信数据库 lsql 的不同表不同分片性能

思考到现场有 4000 多张表,每张表有 1000 多个并发写入分片,有可能是同时写入的文件数太多,导致的 nn 申请频率太高,故思考将那些小表,进行分片合并,写入的文件数量少了,申请频率自然而然就升高了。

2. 与现场人员配合,清理不必要的数据,缩小 hadoop 集群的压力。清理后 hadoop 集群的文件块数由将近 2 亿,升高到 1.3 亿,清理力度足够大。

3. 调整一系列与 NN 无关交互的心跳的频率:如 blockmanager 等相干参数。

4. 调整 NN 外部锁的类型:由偏心锁调整为非偏心锁。

本次调整波及的参数有:

  • dfs.blockreport.intervalMsec 由 21600000L 调整为 259200000L (3 天),全量心跳
  • dfs.blockreport.incremental.intervalMsec 增量数据心跳由 0 改为 300,尽量批量一次上报(老版本无该参数)
  • dfs.namenode.replication.interval 由 3 秒调整为 60 秒,缩小心跳频率
  • dfs.heartbeat.interval 心跳工夫由默认 3 秒调整为 60 秒,缩小心跳频率
  • dfs.namenode.invalidate.work.pct.per.iteration 由 0.32 调整为 0.15 (15% 个节点),缩小扫描节点数量

本次调整波及的堆栈:

最终后果卡顿问题仍然存在。自己曾经江郎才尽,人曾经懵了,不晓得该如何解决。

⑤Fourth Day:机关用尽,思考建设分流机制

拖着曾经间断熬了三个早晨的疲乏身躯,第四天一早就跟公司和客户汇报排查具体情况,也间接说了曾经没有任何的思路。心愿能启用 B 计划:

1. 启用 hadoop 联邦计划,靠多个 namenode 解决当下问题;

2. 立刻批改录信 lsql 数据库,在一个 lsql 数据库内适配 hadoop 多集群计划,也就是搭建两个齐全一样的集群,录信数据库启动 600 个过程,300 个过程申请旧集群,300 个过程分流到新集群,以达到加重压力的目标。

家里(公司)的意见是先回去睡觉,头脑清醒时再做决定。

客户这边倡议持续排查,因为零碎曾经稳固运行一年多了,没道理忽然就不行了,还是心愿深入研究一下。

就像是系统故障大部分一次重启就能解决,我决定先睡会,期待醒了之后问题可能迎刃而解。
睡醒之后,穷途末路的我只好求助于老同事高高,高高是我以前在腾讯时专门负责 HDFS 的大牛,他对 hadoop 的精通水平堪比我熟知各类防脱发诀窍,而且上万台大集群的优化教训,可遇而不可求,我想如果他也不能点播一二,恐怕就没人搞得定了,我也不用白费力气。

高高首先询问了集群的根本状况,并给我多项无效倡议。最让我振奋的是依据高高的剖析,咱们的集群相对没有达到性能的下限。

⑥The last day:对调用 NN 的锁的每个函数进行剖析

这次没有间接看 jmx 信息,放心后果不精确。采纳的是 btrace 这个工具,排查具体是哪个线程频繁给 NN 加锁,导致 NN 负载如此之高。

破费了 3 个小时剖析,最终令人惊喜的是发现 processIncrementalBlockReport 这个线程申请频率十分高,远远高于其余线程。而这个线程不是 datanode(dn)节点增量心跳的逻辑吗?为什么频率如此之高?心跳频率我不是都改掉了吗?难道都没失效么?

认真查看 hadoop 代码,发现这个逻辑的确有问题,每次写数据和删数据都会立刻调用,而我设置的那些心跳参数在客户的这个版本的 hadoop 集群里并没有这方面优化,设置了也没用,于是紧急在网上寻找 patch 的办法,最终找到了这个,它不仅仅解决了心跳频率的问题,还解决了加锁频率问题,通过缩小锁的应用次数,从而缩小上下文切换的次数,进而晋升 nn 的吞吐量。

迅速打上此 patch,  显著发现 NN 吞吐量上来了,而且不仅仅是拜访 NN 不卡了,实时 kafka 的生产速度也一下子由原先的每小时解决 40 亿,回升至每小时解决 100 亿,入库性能也跟着翻倍。打上 patch 后,此问题失去了基本的解决。

究其 根本原因在于 HDFS NameNode 外部的繁多锁设计,使得这个锁显得极为的“重”。持有这个锁须要付出的代价很高。每个申请须要拿到这个锁,而后让 NN 去解决这个申请,这外面就蕴含了很强烈的锁竞争。因而一旦 NN 的这个锁被一些大规模的导入 / 删除操作, 容易使 NameNode 一下子解决大量申请,其它用户的工作会马上受到影响。这次 patch 的次要作用就是增量汇报的锁批改为异步的锁——让删除、上报等操作不影响查问。

具体详细描述与改法参考这里:

https://blog.csdn.net/android…


总 结

最初,针对于这次性能故障的排查,我从问题成因和解决倡议两个方面总结一下:

①问题成因

零碎之前始终运行安稳,忽然呈现的问题的起因次要是因为以下几个:

1. 用户删除了大量文件,造成 hadoop 压力增大

  • 近期硬盘快要满了,集中清理了一批数据
  • 最近 hadoop 不稳固,集中开释了一大批文件

2. 近期显著的日常数据量暴增对 hadoop 调优后,重入数据,按日志进行数据条数统计,最近的数据规模减少很多

3. 生产数据积压

本次调优过程中,因为数据积压了很多天,导致 kafka 始终在满速生产数据。而在满速生产的状况下,会对 nn 造成较大的冲击。

4. 快照和 mover 对 hadoop 造成的冲击

  • 清理快照的时候,开释了大量的数据块,造成数据的删除
  • mover 新增了大量的数据块,以致零碎删除了大量的 ssd 上的文件块。且因节点数增多,心跳频繁,刹时都进行 processIncrementalBlockReport 对 nn 造成较大的压力

②我的几点倡议

1.Never give up easily!

在排查的第四天,在尝试过多种解决方案之后,我也想过要放弃,并且认为这次的性能故障是无解的。在这种时候咱们无妨多与共事,哪怕是以前的共事领导探讨探讨,兴许会带来不一样的思路和启发,要置信群体的智慧!

2. 肯定要理解的 hadoop 原理,这也是本次 hadoop 调优的关键点

(1)当咱们在 HDFS 中删除文件时:namenode 只是把目录入口删掉,而后把须要删除的数据块记录到 pending deletion blocks 列表。当下一次 datanode 向 namenode 发送心跳时,namenode 再把删除命令和这个列表发送到 datanode 端,所以这个 pending deletion blocks 列表很长很长,导致了 timeout。

(2)当咱们导入数据时:客户端会将数据写入到 datanode 里,而 datanode 在接到数据块后,会立刻调 processIncrementalBlockReport 给 NN 汇报,写入数据量越多,越频繁,机器数量越多,过程越多,调用 NN 就会越频繁。所以本次的异步锁 patch,在这里才会有成果。

3. 最要害的一点:千万不要应用 hadoop2.6.0 这个版本!!!

用 hadoop 官网的话来讲,别的版本都是存在 a few of bug,而这个版本存在 a lot of bug,所以回去后第一件事要督促客户尽快降级换版本。

正文完
 0