概述
本次分析的源码版本为hadoop-2.6.0。HDFS源码分析思路:HDFS服务的每个角色都存在一个进程,即有一个主类存在一个man方法,这就是角色的入口。这里以NameNode分析方法举例:分析NameNode源码时切忌深入到每一个类、每一个方法,应该先对NameNode源码主干进行分析,对该源码有一个宏观认识,然后再进行详细分析。这里我们应该理清楚NamoNode启动的大体步骤,对NameNode 所做的工作,每一个角色提供什么样的服务,可以通过分析该角色的每一个线程。然后分析线程的run()方法来了解该角色实现的具体业务。这样分析源码的思路就比较清晰了。本文主要分析NameNode启动,NameNode的入口:org.apache.hadoop.hdfs.server.namenode.NameNode.main()。
NameNode启动步骤
NameNode启动的大多数步骤都在initialize()方法中完成。
1、初始化度量器系统,会启动Timer for ’NameNode‘ metrics system线程。
2、pauseMonitor.start():启动Jvm暂停监控,此功能由JvmPauseMonitor 线程完成。
3、startHttpServer():判断是否为NameNode角色,如果为NameNode则启动HttpServer服务器.接收外部发过来的请求,默认监听50070。
4、loadNamesystem():载入FSNamesystem,从磁盘加载fsimage和edits进行内存合并。
5、createRpcServer():创建RpcServer 包括ClientRpcServer和ServerRpcServer。ClientRpcServer用于接收客户端请求,ServerRpcServer用于接收DataNode、SecondaryNameNode等内部节点之间的通信请求。
6、startCommonServices():启动公共服务,包含FSNamesystem服务启动、检查磁盘是否有100m来写入edits log、检查是否进入安全模式、BlockManager激活、RpcServer启动。
7、NameNode.join():等待rcp server停止。
到此NameNode启动工作已经完成。接下来NameNode的各项服务个工作就由已经启动的线程承担。下文讲剖析NameNode启动后的各个具体的线程、每个线程主要的作用是做什么。
NameNode启动步骤详细分析
初始化度量器系统
调用流程:DefaultMetricsSystem.initialize()
--->MetricsSystemImpl.init()
--->MetricsSystemImpl.start()
--->MetricsSystemImpl.startTimer()
--->MetricsSystemImpl.onTimerEvent()
DefaultMetricsSystem通过枚举实现单例模式,startTimer()方法启动一个定时器,每隔10秒执行一次onTimerEvent()方法。onTimeEvent方法通过sampleMetrics()方法获取指标信息,并通过publishMetrics()方法发送至每个sink。
Jvm暂停监控
调用流程:pauseMonitor.start()
--->monitorThread.start()
--->Monitor.run()
HttpServer启动
载入FSNamesystem
RpcServer创建
公共服务启动
NameNode启动后的线程概览
1、main:程序主线程。
2、Finalizer:在main线程之后创建的,其优先级为10,主要用于在垃圾收集前,调用对象的finalize()方法。详细解释可以参考 JVM运行基本线程解析。
3、Reference Handler:它主要用于处理引用对象本身(软引用、弱引用、虚引用)的垃圾回收问题。
4、Signal Dispatcher:接收外部参数然后分发到各个不同的模块处理命令,并且返回处理结果。signal dispather线程是在第一次接收外部jvm命令时,进行初始化工作。
5、Timer for ’NameNode‘ metrics system:NameNode度量器系统线程。执行DefaultMetricsSystem.initialize("NameNode") 时启动。
6、JvmPauseMonitor$Monitor:Jvm暂停监控线程,执行pauseMonitor.start()时启动。
7、pool-1-thread-1: jetty内部线程,启动http server时创建 。执行startHttpServer(final Configuration conf) 代码时创建,最终在httpServer = builder.build();时创建并启动。
8、时间戳@qtp-932257672-0@2406: jetty内部线程,启动http server时创建 jetty内部线程 执行startHttpServer(final Configuration conf) 代码创建。
9、时间戳@qtp-932257672-1 - Acceptor0 HttpServer2$SelectChannelConnectorWithSafeStartup@account.jetbrains.com:50070@2407: jetty内部线程,启动http server时创建 执行startHttpServer(final Configuration conf) 代码创建。
10、Time-0:Jetty内部线程,启动Http Server时创建。执行startHttpServer(final Configuration conf) 代码时创建 最终在httpServer.start()时创建。
11、IPC Server idle connection scanner for port 9000@3804:RPC线程,会监听9000端口,执行createRpcServer时启动。
12、Socket Reader #1 for port 9000@3802:执行createRpcServer时启动。
13、BlockManager$ReplicationMonitor@70a36a66@4009:startCommonServices()---->blockManager.activate()时启动。
14、HeartbeatManager$Monitor@42f8285e@4008:执行startCommonServices()---->blockManager.activate()启动。
15、PendingReplicationBlocks$PendingReplicationMonitor@3bc735b3@4004:执行startCommonServices()---->blockManager.activate()启动。
16、DecommissionManager$Monitor@757529a4@4007:执行startCommonServices()---->blockManager.activate()启动。
17、process reaper@3930:执行startCommonServices()---->blockManager.activate()启动(后面会消失)
18、StorageInfoMonitor@4010:执行startCommonServices()---->blockManager.activate()启动。
19~28、IPC Server handler (0-9) on 9000:RPC 处理任务线程,执行startCommonServices()--->rpcServer.start();时启动。
29、IPC Server listener on 9000:RPC监听线程,执行startCommonServices()--->rpcServer.start();时启动。
30、IPC Server Responder:RPC请求响应线程,执行startCommonServices()--->rpcServer.start();时启动。
31、FSNamesystem$NameNodeEditLogRoller@14bae047@4174:在NameNode()--->state.enterState(haContext);启动。
32、FSNamesystem$NameNodeResourceMonitor@5c089b2f@4172:在NameNode()--->state.enterState(haContext);启动。
33、FSNamesystem$LazyPersistFileScrubber@66908383@4176:在NameNode()--->state.enterState(haContext);启动。
34、LeaseManager$Monitor@6ef7623@4170:在NameNode()--->state.enterState(haContext);启动。
35、CacheReplicationMonitor(221551064)@4178:在NameNode()--->state.enterState(haContext);启动。
到此NameNode 所有线程已经启动完成,接下来分析每个线程的具体业务逻辑
网友评论