HDFS实践文章背景趣头条数据量达到了百PB级别,本文分享一下趣头条的HDFS相关实践。 NameNode负载和扩展性问题拆RPC端口以及拆NameSpace组成Federation针对NameNode单点瓶颈,在把NameNode拆分成Client RPC端口和Service RPC端口后,推进了HDFS Federation的架构,原因是NameNode单点存在元数据量激增的问题,也存在NameNode RPC负载激增的问题。 针对Federation之间的数据迁移引入FastCopy: Balancer负载转移和搬迁优化拆分成Federation架构之后,HDFS Balancer 操作对Active NameNode造成了很大对负载,为此我们把Balancer操作的负载转移到了standby上面,从而降低了Active NameNode的RPC负载。 拆分日志相关的NameSpace降低负载有了HDFS Federation架构以后,日志还是会和业务的NameSpace互相产生影响,为此我们把defaultFs修改成系统单独的NameSpace。我们也向Hadoop YARN社区贡献了针对提交目录,日志聚合目录可以负载均衡到各个NameSpace的设想,具体Issue见:YARN-9634。 NameNode用户的拥塞控制
目前我们使用了FairCallQueue RPC Backoff, 能满足我们拥塞控制的需求。有效限制了异常高负载的用户对整体RPC可用性的影响。 针对用户较多的NameSpace我们正准备进行用户优先级分更多层级,进行多层的Qos保障。 异步化各种操作提高NameNode的吞吐量editlog和auditlog的异步化 块汇报的优化数据量越来越大以后,对NameNode的堆栈信息统计后发现,块汇报的压力对用户的影响较大,为此我们考虑对块汇报进行了优化。首先全量块汇报的时候加盐,分散整体汇报对NameNode的压力。然后增量汇报的时候进行如下优化: 首先把NameNode端的块汇报异步进行聚合,有效的缓解了RPC的压力,对应的Issue为:HDFS-9198。 然后相应的DataNode端的块汇报也进行了批量聚合,对应Issue为:HDFS-9710。 NameNode锁时间追踪HDFS-10872 添加了NameNode锁住时间对应的Metrics。NameNode的锁队列长度堆积过高的时候,我们增加了全局锁对应的锁住时间,对某些锁占用时间过长的情况,进行分析,对很多锁优化对细节很有帮助。 Decommission的改进大集群的Decommission操作非常常见,如机器迁移下线,机器故障需要下线等。而旧的Decommssion代码存在如下的问题:
Qos保障,业务控制,限流以及作业追踪软限制和作业追踪针对访问过高的用户,进行审计增强,目前的审计日志无法获取用户的作业信息。某些异常作业对某些治理不够完善的大表的疯狂访问等等行为,会对集群造成很大的稳定性和性能影响。为此我们引入了审计增强。 硬限制:NameNode源码改动另外一种硬的方式,不做事后分析,做事前强限制: 用户体验和运维便利性自研 HDFS Proxy由于历史原因导致,很多算法等业务需要独立的客户端进行管理,而业务的激增导致了客户端配置的频繁更新造成了很大的人力运维成本。且客户端的种类过于繁多,例如调度客户机,容器化的调度客户机,普通gateway等等。为了实现配置转移到了服务端进行控制,我们开发了HDFS Proxy,客户端无需配置,Hdfs Client 将请求转发到对应的HDFS Proxy Server。Proxy 可以横向扩展,上面挂了一层负载均衡器。非常轻量级,已经使用了将近半年,由于viewFs客户端维护方式很不利于运维管理,且我们当前版本比较老,且Router不够成熟,主要用于和Router进行过渡。 HDFS Router 改进和二次开发随着Router的成熟,和我们对Router进行了一些定制化的改进,我们慢慢从我们轻量级的HDFS Proxy切换到Router,毕竟开源的力量是伟大的,我们也要站在巨人的肩膀上。 Router审计日志的完善和作业追踪Router本身对AuditLog支持对不好,为此我们增加了定制对AuitLog,并且准备继续在Router这一层对任务进行追踪。在Router层实现软限制和作业追踪。 Router Trash重构和RPC优化针对数据成本优化,我们做了Hive生命周期的项目,每天都有大量的Trash操作。 Router 支持全局Quota管控如果单个目录挂载了多个NameSpace,Router目前也支持了全局的Quota管控,但还有部分细节需要完善。 Router rename across Federation针对Federation的各个NameSpace之间的FastCopy上述有做了介绍,Router有个功能可以实现类似FastMove的功能,针对跨NameSpace的已挂载的目录,可以进行rename到其他NameSpace。 HDFS目录实时解析HDFS的目录信息解析,需要从FSImage进行解析,集群大了以后,我们FSImage有100多G,解析过程相当缓慢,只能以 T 1的方式进行解析。 服务的稳定性和性能由于Federation架构8组业务的NameSpace共享同一个DataNode底层服务,加上本身我们的机型磁盘块很多,且业务的复杂性多样性对DataNode的访问,NameNode的压力转移到了DataNode上面。 DataNode DU导致IO重和重启Uncached问题存储从DU改为内存计算DataNode默认使用DU对存储总量进行汇总给 NameNode,DU操作对DataNode的IO压力比较大,且DataNode的IO没有和全局锁进行分离,IO也会占用锁的时间。DU对IO压力大的解决方案有多种,分散DU的时间加个随机数然后分布到各个节点,减缓整体的IO,但是无法避免还是需要DU操作。 针对磁盘的DU,我们把存储总量的计算放到了内存里,因为内存里本身有磁盘块的信息,通过内存数据结果进行定期计算。具体最新的Issue:HDFS-9710。 解决重启Uncached问题DataNode滚动的时候,经常会有ungraceful shutdown的情况,会导致存储量的缓存没有缓存到本地,那么启动的时候就会重复去计算,针对DU的场景会导致重启时间变得很长,为此我们加了定时线程对缓存进行更新,重启的时候就不用去重新计算存储总量了。具体Issue见:HDFS-15171。 慢节点和读写长尾优化当集群节点日益增长当时候,很容易产生DataNode节点老化导致磁盘或者网络IO慢等其他问题,这就会造成用户的读写长尾等问题。 除了DataNode的慢节点监控,以及NameNode汇总慢节点信息,也能从客户端去监控读写速度以及读写长尾的DataNode节点,这一块社区也有对应的实现,有待完善:HDFS-12861。 开启客户端并发读: 写慢节点: DataNode锁优化之旅业务量激增导致8组NameNode的负载都打到了DataNode,突然出现DataNode心跳时间陡增到数分钟,导致心跳没有即时收到,DataNode经常在高峰期批量Dead,对业务造成了很严重的影响。 Synchronized非公平锁改为ReentrantLock公平锁首先,我们把DataNode的Synchronized非公平锁改成了,ReentrantLock默认为公平锁。 ReentrantLock公平锁拆成公平的读写锁针对全局的可重入ReentrantLock,拆成了读写锁,效果很好,堵住几千个线程缓解了很多。 拆分成以BlockPool为单位的细粒度读写锁继续拆锁,拆分成以BlockPool为单位的读写锁,意味着,如果你有8组NameSpace的话,一个DataNode全局锁,可以拆分成8把锁。 最终目标,最小单位的锁最终目标,一个Volume中对应的BlockPool单位拆成一把锁。如下图所示,如果HDFS Federation有4组NameSpace,每个DataNode有3个磁盘块。那么就对应了4个BlockPool(BP),和3个Volume,原生的DataNode全局锁是一把锁,理想的情况下,在这个例子情况下是可以拆分成为4*3 = 12 把读写锁,对应锁住的范围就是两个椭圆的交接重合部分。 DataNode 接受指令异步化我们查看日志的时候发现,DataNode接受指令的时候,会把心跳线程给阻塞住,为此把阻塞的线程改成异步的线程池去处理这个指令操作,这样不会把心跳线程给堵住。 DataNode IO和锁分离DataNode的IO操作,有时候会占用很长的锁时间,为此我们正准备把IO和锁进行分离。 进行中的和未来规划
欢迎业内交流: |
|