1.前情总结本文将讲述Hadoop部署在大规模集群场景下,大量客户端并发写入数据时的文件契约监控算法。性能优化。要理解本文,您需要一些Hadoop的基础知识背景。不太了解的可以先看之前的文章:《?干掉几百行的大SQL,我用Hadoop?》2。背景介绍在HadoopHDFS上并发写一个文件,你觉得可以吗?显然不能接受,兄弟,HDFS上的文件是不允许并发写入的,比如并发追加一些数据。因此HDFS中有一种机制叫做文件契约机制。也就是说,同一时刻只能有一个client获取到NameNode上的一个文件的contract,然后才能写入数据。此时如果其他客户端尝试获取文件合约,将获取不到,只能等待。通过这种机制,可以保证一次只有一个客户端在写一个文件。获取到文件契约后,在写文件的过程中,客户端需要开启一个线程,不断的向NameNode发送更新文件的请求,并告诉NameNode:NameNode兄弟,我还在写文件,你给我一直遵守那个合同,好吗?NameNode内部有一个专门的后台线程,负责监控每个合约的续约时间。如果长期没有续签合同,此时合同自动失效,让其他客户代写。说了这么多,老规矩,这里放一张图让大家直观感受整个过程。3.问题突出。现在问题来了。如果我们大规模部署一个Hadoop集群,可能同时有上万个客户端。这时候NameNode内部维护的文件合约列表会非常非常大,监控合约的后台线程需要经常定时检查所有合约是否已经过期。比如每隔几秒就遍历大量的合约,势必会导致性能不佳,那么这种合约监控机制显然不适合hadoop集群的大规模部署。4、Hadoop优化方案那么Hadoop是如何优化文件契约监控算法的呢?下面我们一步步来看他的实现逻辑。首先我们来看看下面这张手绘图:其实谜男很简单。客户端每次发送续约请求时,都会设置这个合约的最晚续约时间。然后基于一个TreeSet数据结构,将合约按照最晚续约时间排序,每次续约时间最早的合约排在第一位。这种排序后的合约数据结构非常重要。TreeSet是一种可排序的数据结构,其底层实现基于TreeMap。TreeMap底层是基于红黑树实现的,可以保证元素不重复,也可以在每次插入元素时按照我们自己定义的排序规则进行自定义排序。所以这里是我们的排序规则:按照合约的最新续约时间排序。其实这个优化就是这么简单,就是维护这样一个排序好的数据结构。现在来看一下Hadoop中合约监控的源码实现:每次检查一个合约是否过期,不想遍历几千个合约,当然遍历效率会很低。我们可以从TreeSet中获取最旧续约时间的合同。如果续约时间最早的合约还没有到期,那么就不用继续查了!这意味着那些续约时间较近的合同永远不会过期!例如:最老续约时间的合约上次续约是在10分钟前,但我们判断合约到期时限为15分钟内未续约到期的合约。这个时候连10分钟前续约的合约都还没有到期,所以那些8分钟前、5分钟前续约的合约肯定也不会到期!这种机制的优化对于性能的提升还是很有帮助的,因为正常情况下,过期的合约肯定还是占了一小部分,所以不需要每次都遍历所有的合约来检查是否过期。我们只需要检查续订时间最早的合同。如果合同到期,删除该合同,然后检查第二旧的合同。等等。通过这种TreeSet排序+最老合约优先级检查的机制,可以有效提升大规模集群下合约监控机制的性能至少10倍。这个理念值得学习和借鉴。稍微扩展一下,在SpringCloud微服务架构中,作为注册中心的Eureka其实有一个合约续签检查机制,这个机制和Hadoop类似。如果你想了解Eureka注册中心相关的技术,建议你看一下:《SpringCloud精妙的设计,你还不知道?》但是Eureka中并没有实现类似的更新优化机制,而是每一轮暴力遍历所有服务的更新时间实例。如果你面对的是大规模部署微服务系统,情况就不好了!在部署了数十万台机器的大型系统中,数十万个服务实例的更新信息驻留在Eureka的内存中。每隔几秒就要遍历几十万个服务实例的更新信息吗??最后想跟大家提一下,优秀的开源项目中包含着很多优秀的设计思想。看各种优秀的开源项目的源代码,是一种在短时间内快速大幅度提高自己的技术水平和技术水平的方法。你不妨试一试。
