在《HDFS源码分析心跳汇报之数据结构初始化》一文中,我们了解到HDFS心跳相关的BlockPoolManager、BPOfferService、BPServiceActor三者之间的关系,并且知道最终HDFS的心跳是通过BPServiceActor线程实现的。那么,这个BPServiceActor线程到底是如何工作的呢?本文,我们将继续HDFS心跳分析之BPServiceActor工作线程运行流程。

首先,我们先看下

那么,BPServiceActor线程是通过什么样的流程来实现心跳的呢?我们来看下它正常工作的run()方法,代码如下:

  1. /**
  2. * No matter what kind of exception we get, keep retrying to offerService().
  3. * That's the loop that connects to the NameNode and provides basic DataNode
  4. * functionality.
  5. *
  6. * Only stop when "shouldRun" or "shouldServiceRun" is turned off, which can
  7. * happen either at shutdown or due to refreshNamenodes.
  8. */
  9. @Override
  10. public void run() {
  11. // 记录日志信息:starting to offer service
  12. LOG.info(this + " starting to offer service");
  13. try {
  14. // 在一个while循环内,完成连接NameNode并握手操作,即初始化
  15. while (true) {
  16. // init stuff
  17. try {
  18. // setup storage
  19. // 连接NameNode并握手
  20. connectToNNAndHandshake();
  21. break;
  22. } catch (IOException ioe) {
  23. // 如果存在异常
  24. // Initial handshake, storage recovery or registration failed
  25. // 现将运行状态runningState设置为初始化失败INIT_FAILED
  26. runningState = RunningState.INIT_FAILED;
  27. // 调用shouldRetryInit()方法判断初始化失败时是否可以重试
  28. if (shouldRetryInit()) {
  29. // Retry until all namenode's of BPOS failed initialization
  30. // 记录error日志信息
  31. LOG.error("Initialization failed for " + this + " "
  32. + ioe.getLocalizedMessage());
  33. // 线程休眠5s,并记录info日志信息,之后再进入循环重复执行之前的操作
  34. sleepAndLogInterrupts(5000, "initializing");
  35. } else {
  36. // 不允许重试的情况下,将运行状态runningState设置为失败FAILED,退出循环,并返回
  37. runningState = RunningState.FAILED;
  38. LOG.fatal("Initialization failed for " + this + ". Exiting. ", ioe);
  39. return;
  40. }
  41. }
  42. }
  43. // 设置运行状态runningState为正在运行RUNNING
  44. runningState = RunningState.RUNNING;
  45. // 进入另一个while循环,不停的调用offerService()方法,
  46. // 发送心跳给NameNode并接收来自NameNode,然后根据命令交给不同的组件去处理
  47. // 循环的条件就是该线程的标志位shouldServiceRun为true,且dataNode的shouldRun()返回true
  48. while (shouldRun()) {
  49. try {
  50. offerService();
  51. } catch (Exception ex) {
  52. // 存在异常的话,记录error日志,并休眠5s
  53. LOG.error("Exception in BPOfferService for " + this, ex);
  54. sleepAndLogInterrupts(5000, "offering service");
  55. }
  56. }
  57. // 设置运行状态runningState为已退出EXITED
  58. runningState = RunningState.EXITED;
  59. } catch (Throwable ex) {
  60. LOG.warn("Unexpected exception in block pool " + this, ex);
  61. runningState = RunningState.FAILED;
  62. } finally {
  63. LOG.warn("Ending block pool service for: " + this);
  64. // 清空,释放占用的资源
  65. cleanUp();
  66. }
  67. }

在run()方法的开始,也就是BPServiceActor线程刚启动时,会在一个while循环内,完成连接NameNode并握手操作,即初始化。这里,是通过调用connectToNNAndHandshake()方法完成与NameNode的连接并进行两次握手的。值得一提的是,如果出现了IOException异常,会先将运行状态runningState设置为初始化失败INIT_FAILED,然后调用shouldRetryInit()方法判断初始化失败时是否可以重试:

1、如果可以重试的话,记录error日志信息,线程休眠5s,并记录info日志信息,之后再进入循环重复执行之前的操作;

2、不允许重试的情况下,将运行状态runningState设置为失败FAILED,退出循环,并返回。

接下来,设置运行状态runningState为正在运行RUNNING,进入另一个while循环,不停的调用offerService()方法,发送心跳给NameNode并接收来自NameNode的命令,然后根据命令交给不同的组件去处理,循环的条件就是该线程的标志位shouldServiceRun为true,且dataNode的shouldRun()返回true;

而当循环过程中存在异常Exception的话,记录error日志,并休眠5s,然后继续循环,只有当shouldRun()方法返回false,才退出循环,设置运行状态runningState为已退出EXITED,最终调用cleanUp()方法释放占用的资源等。

上述就是BPServiceActor线程正常工作进行周期性心跳的主流程。下面,我们针对其中的某些细节进行详细描述。

首先,完成与NameNode的连接并进行两次握手的connectToNNAndHandshake()方法,实现如下:

  1. /**
  2. * 连接NameNode并握手
  3. */
  4. private void connectToNNAndHandshake() throws IOException {
  5. // get NN proxy
  6. // 利用DataNode实例dn的connectToNN()方法和NameNode地址nnAddr获得NameNode的代理bpNamenode
  7. bpNamenode = dn.connectToNN(nnAddr);
  8. // First phase of the handshake with NN - get the namespace
  9. // info.
  10. // 与NameNode握手第一阶段:获取命名空间信息
  11. NamespaceInfo nsInfo = retrieveNamespaceInfo();
  12. // Verify that this matches the other NN in this HA pair.
  13. // This also initializes our block pool in the DN if we are
  14. // the first NN connection for this BP.
  15. // 验证,并设置命名空间信息()
  16. bpos.verifyAndSetNamespaceInfo(nsInfo);
  17. // Second phase of the handshake with the NN.
  18. // 与NameNode握手第二阶段,注册
  19. register();
  20. }

它的主要处理流程如下:

1、利用DataNode实例dn的connectToNN()方法和NameNode地址nnAddr获得NameNode的代理bpNamenode
        2、与NameNode握手第一阶段:调用retrieveNamespaceInfo()方法获取命名空间信息nsInfo;

3、通过bpos的verifyAndSetNamespaceInfo()方法进行验证,并设置命名空间信息nsInfo;

4、与NameNode握手第二阶段,调用register()方法进行注册。

接着,我们再看下实现周期性心跳的offerService()方法,代码如下:

HDFS源码分析心跳汇报之BPServiceActor工作线程运行流程的更多相关文章

  1. HDFS源码分析心跳汇报之数据块增量汇报

    在<HDFS源码分析心跳汇报之BPServiceActor工作线程运行流程>一文中,我们详细了解了数据节点DataNode周期性发送心跳给名字节点NameNode的BPServiceAct ...

  2. HDFS源码分析心跳汇报之数据块汇报

    在<HDFS源码分析心跳汇报之数据块增量汇报>一文中,我们详细介绍了数据块增量汇报的内容,了解到它是时间间隔更长的正常数据块汇报周期内一个smaller的数据块汇报,它负责将DataNod ...

  3. HDFS源码分析心跳汇报之数据结构初始化

    在<HDFS源码分析心跳汇报之整体结构>一文中,我们详细了解了HDFS中关于心跳的整体结构,知道了BlockPoolManager.BPOfferService和BPServiceActo ...

  4. HDFS源码分析心跳汇报之周期性心跳

    HDFS源码分析心跳汇报之周期性心跳,近期推出!

  5. HDFS源码分析心跳汇报之DataNode注册

    HDFS源码分析心跳汇报之DataNode注册,近期推出!

  6. HDFS源码分析心跳汇报之整体结构

    我们知道,HDFS全称是Hadoop Distribute FileSystem,即Hadoop分布式文件系统.既然它是一个分布式文件系统,那么肯定存在很多物理节点,而这其中,就会有主从节点之分.在H ...

  7. HDFS源码分析数据块汇报之损坏数据块检测checkReplicaCorrupt()

    无论是第一次,还是之后的每次数据块汇报,名字名字节点都会对汇报上来的数据块进行检测,看看其是否为损坏的数据块.那么,损坏数据块是如何被检测的呢?本文,我们将研究下损坏数据块检测的checkReplic ...

  8. HDFS源码分析数据块校验之DataBlockScanner

    DataBlockScanner是运行在数据节点DataNode上的一个后台线程.它为所有的块池管理块扫描.针对每个块池,一个BlockPoolSliceScanner对象将会被创建,其运行在一个单独 ...

  9. HDFS源码分析数据块复制监控线程ReplicationMonitor(一)

    ReplicationMonitor是HDFS中关于数据块复制的监控线程,它的主要作用就是计算DataNode工作,并将复制请求超时的块重新加入到待调度队列.其定义及作为线程核心的run()方法如下: ...

随机推荐

  1. 17.2.10 NOIP模拟赛 藏妹子之处(excel)

    藏妹子之处(excel) 问题描述: 今天CZY又找到了三个妹子,有着收藏爱好的他想要找三个地方将妹子们藏起来,将一片空地抽象成一个R行C列的表格,CZY要选出3个单元格.但要满足如下的两个条件: ( ...

  2. duilib入门简明教程 -- 完整的自绘标题栏(8) (转)

    原文转自:http://www.cnblogs.com/Alberl/p/3343763.html     看了前面那么多教程,相信对duilib已有基本映像了,我们就快马加鞭,做出一个完整的自绘标题 ...

  3. linux下轻松修改pdf文件

    前几天使用firefox打印了一个网页,后来查看有很多页面都是评论,对我来说,实在没有什么用处,就想把多余的内容给删除了,后来,终于找到了一个工具:pdf mod非常不错的工具,直接打开文件,选择要删 ...

  4. Scrapy学习-23-分布式爬虫

    scrapy-redis分布式爬虫 分布式需要解决的问题 request队列集中管理 去重集中管理 存储管理   使用scrapy-redis实现分布式爬虫 github开源项目: https://g ...

  5. java实现udp发送端和接收端

    发送端: package demo02; import java.io.IOException; import java.net.DatagramPacket; import java.net.Dat ...

  6. Action 和 Func 的用法以及区别

    Action 无返回值 Func 有返回值,且最后一个参数为返回值 Action用法 public static void test(string s) { Console.WriteLine(&qu ...

  7. RadioGroup动态添加RadioButton,并且获得事件

    由于有许多的RadioButton是动态的,不是固定的一些,所以需要在代码中,动态的添加到RadioGroup中,下面是我的实现方法. 1.添加RadioButton到RadioGroup中 Radi ...

  8. Android进阶之Fragment与Activity之间的数据交互

    1 为什么 因为Fragment和Activity一样是具有生命周期,不是一般的bean通过构造函数传值,会造成异常. 2 Activity把值传递给Fragment 2.1 第一种方式,也是最常用的 ...

  9. Ticket Lock, CLH Lock, MCS Lock

    如果不用OS提供的mutex,我们该如何实现互斥锁?(不考虑重入的情况) 1. naive lock 最简单的想法是,搞一个volatile类型的共享变量flag,值可以是flase(无锁)或者tru ...

  10. Codeforces Round #466 (Div. 2) A. Points on the line[数轴上有n个点,问最少去掉多少个点才能使剩下的点的最大距离为不超过k。]

    A. Points on the line time limit per test 1 second memory limit per test 256 megabytes input standar ...