Ambari深入学习(II)-实现细节
在第一节中,我们简单讲了一下Ambari的系统架构。我们这一节主要分析Ambari的源代码,总览Ambari的具体实现方式及其工作细节。
一、Ambari-Server启动
- // API handler加载的REST处理包
- ServletHolder sh = new ServletHolder(ServletContainer.class);
- //采用包结构的形式进行加载
- sh.setInitParameter("com.sun.jersey.config.property.resourceConfigClass",
- "com.sun.jersey.api.core.PackagesResourceConfig");
- // 下面是/api/v1/接受的请求由哪些包来处理
- sh.setInitParameter("com.sun.jersey.config.property.packages",
- "org.apache.ambari.server.api.rest;" +
- "org.apache.ambari.server.api.services;" +
- "org.apache.ambari.eventdb.webservice;" +
- "org.apache.ambari.server.api");
- sh.setInitParameter("com.sun.jersey.api.json.POJOMappingFeature",
- "true");
- root.addServlet(sh, "/api/v1/*");
- sh.setInitOrder(2);
- // Agent Handler加载的REST包,主要是org.apache.ambari.server.agent.rest.HeartBeatHandler来接受心跳请求
- ServletHolder agent = new ServletHolder(ServletContainer.class);
- agent.setInitParameter("com.sun.jersey.config.property.resourceConfigClass",
- "com.sun.jersey.api.core.PackagesResourceConfig");
- agent.setInitParameter("com.sun.jersey.config.property.packages",
- "org.apache.ambari.server.agent.rest;" + "org.apache.ambari.server.api");
- agent.setInitParameter("com.sun.jersey.api.json.POJOMappingFeature",
- "true");
- agentroot.addServlet(agent, "/agent/v1/*");
- agent.setInitOrder(3);
- // 对agent发过来的数据包进行证书签名所需要加载的包
- ServletHolder cert = new ServletHolder(ServletContainer.class);
- cert.setInitParameter("com.sun.jersey.config.property.resourceConfigClass",
- "com.sun.jersey.api.core.PackagesResourceConfig");
- cert.setInitParameter("com.sun.jersey.config.property.packages",
- "org.apache.ambari.server.security.unsecured.rest;" + "org.apache.ambari.server.api");
- cert.setInitParameter("com.sun.jersey.api.json.POJOMappingFeature",
- "true");
- agentroot.addServlet(cert, "/*");
- cert.setInitOrder(4);
- // WEB客户端提供的数据包
- ServletHolder resources = new ServletHolder(ServletContainer.class);
- resources.setInitParameter("com.sun.jersey.config.property.resourceConfigClass",
- "com.sun.jersey.api.core.PackagesResourceConfig");
- resources.setInitParameter("com.sun.jersey.config.property.packages",
- "org.apache.ambari.server.resources.api.rest;" + "org.apache.ambari.server.api");
- resources.setInitParameter("com.sun.jersey.api.json.POJOMappingFeature",
- "true");
- root.addServlet(resources, "/resources/*");
- resources.setInitOrder(6)
二、Ambari-Server处理Ambari-Agent请求
- public HeartBeatResponse handleHeartBeat(HeartBeat heartbeat)
- throws AmbariException {
- String hostname = heartbeat.getHostname();
- Long currentResponseId = hostResponseIds.get(hostname);
- HeartBeatResponse response;
- if (currentResponseId == null) {
- //Server restarted, or unknown host.
- LOG.error("CurrentResponseId unknown - send register command");
- return createRegisterCommand(); // 无responseId, 新请求,就进行注册, responseId =0
- }
- LOG.info("Received heartbeat from host"
- + ", hostname=" + hostname
- + ", currentResponseId=" + currentResponseId
- + ", receivedResponseId=" + heartbeat.getResponseId());
- if (heartbeat.getResponseId() == currentResponseId - 1) {
- LOG.warn("Old responseId received - response was lost - returning cached response");
- return hostResponses.get(hostname);
- } else if (heartbeat.getResponseId() != currentResponseId) {
- LOG.error("Error in responseId sequence - sending agent restart command");
- return createRestartCommand(currentResponseId); // 心跳是历史记录,那么就要求其重启,重新注册,
- // responseId 不变
- }
- response = new HeartBeatResponse();
- response.setResponseId(++currentResponseId); // responseId 加 1 , 返回一个新的responseId,下次心跳又要把这个responseId带回来。
- Host hostObject = clusterFsm.getHost(hostname);
- if (hostObject.getState().equals(HostState.HEARTBEAT_LOST)) { // 失去心跳
- // After loosing heartbeat agent should reregister
- LOG.warn("Host is in HEARTBEAT_LOST state - sending register command");
- return createRegisterCommand(); //失去连接,要求重新注册, responseId=0
- }
- hostResponseIds.put(hostname, currentResponseId);
- hostResponses.put(hostname, response);
- long now = System.currentTimeMillis();
- HostState hostState = hostObject.getState();
- // If the host is waiting for component status updates, notify it
- if (heartbeat.componentStatus.size() > 0
- && hostObject.getState().equals(HostState.WAITING_FOR_HOST_STATUS_UPDATES)) { // 节点已经进行了注册,但是该节点还没有汇报相关状态信息,等待服务状态更新
- try {
- LOG.debug("Got component status updates");
- hostObject.handleEvent(new HostStatusUpdatesReceivedEvent(hostname, now)); // 更新服务状态机
- } catch (InvalidStateTransitionException e) {
- LOG.warn("Failed to notify the host about component status updates", e);
- }
- }
- try {
- if (heartbeat.getNodeStatus().getStatus().equals(HostStatus.Status.HEALTHY)) {
- hostObject.handleEvent(new HostHealthyHeartbeatEvent(hostname, now,
- heartbeat.getAgentEnv())); // 向状态机发送更新事件,更新节点至正常状态
- } else {
- hostObject.handleEvent(new HostUnhealthyHeartbeatEvent(hostname, now,
- null)); // 把节点列入不健康
- }
- if (hostState != hostObject.getState()) scanner.updateHBaseMaster(hostObject); // 更新 hbase master状态,如果该节点上在master节点的话,
- } catch (InvalidStateTransitionException ex) {
- LOG.warn("Asking agent to reregister due to " + ex.getMessage(), ex);
- hostObject.setState(HostState.INIT); // 出错,重新注册
- return createRegisterCommand();
- }
- //Examine heartbeat for command reports
- processCommandReports(heartbeat, hostname, clusterFsm, now); // 处理状态更改的汇报信息,看进度到哪一点了。
- // Examine heartbeart for component live status reports
- processStatusReports(heartbeat, hostname, clusterFsm); // 处理该节点的服务状态信息(也称作为组件)
- // Send commands if node is active
- if (hostObject.getState().equals(HostState.HEALTHY)) {
- sendCommands(hostname, response); //把该节点的命令AgentCommand组装起来,统一返回给agent
- }
- return response;
- }
三、Ambari-Agent执行流程
- class Controller(threading.Thread):
- def __init__(self, config, range=30): // 在初始化Controller之前,ambari-agent就会在main.py里面进行判断:ambari-server是否正常,正常才会初始化Controller
- // 省略初始化代码
- def run(self):
- self.actionQueue = ActionQueue(self.config) // 初始化队列线程
- self.actionQueue.start()
- self.register = Register(self.config) // 初始化注册类
- self.heartbeat = Heartbeat(self.actionQueue) // 初始化心跳类
- opener = urllib2.build_opener()
- urllib2.install_opener(opener)
- while True:
- self.repeatRegistration = False
- self.registerAndHeartbeat() //开始注册 并且 定时发心跳
- if not self.repeatRegistration:
- break
- pass
CommandQueue队列主要有3类command:
- REGISTER_COMMAND:该类命令主要通知agent重新向server发送注册请求。
- STATUS_COMMAND:该类命令主要告诉agent需要向server发送某组件的状态信息。
- EXECUTION_COMMAND:要求agent执行puppet或者软件集升级任务
ActionQueue线程在执行STATUS_COMMAND时,会通过LiveStatus类构建一个StatusCheck检测器,并且通过ps命令来检测该组件是否是活着。
- def getIsLive(self, pidPath):
- // ....
- //检测该组件pid文件是否存在...
- res = self.sh.run(['ps -p', str(pid), '-f']) //运行shell命令,检测该进程是否存在
- lines = res['output'].strip().split(os.linesep)
- try:
- procInfo = lines[1]
- isLive = not procInfo == None
- except IndexError:
- logger.info('Process is dead')
- return isLive
ActionQueue线程在执行EXECUTION_COMMAND任务时,通常是用于执行相关Puppet任务,它会在[agent].prefix目录下产生一个puppet文件,然后执行puppet apply命令执行一批puppet module文件完成配置更改和节点管理任务。
- def runCommand(self, command, tmpoutfile, tmperrfile):
- taskId = 0
- if command.has_key("taskId"):
- taskId = command['taskId']
- siteppFileName = os.path.join(self.tmpDir, "site-" + str(taskId) + ".pp") // self.tmpdir是ambari-agent.ini里面配置的agent.prefix参数, site-{taskId:int}.pp文件里面主要是一组服务的配置参数
- generateManifest(command, siteppFileName, self.modulesdir, self.config) //生成一个puppet配置文件
- result = self.run_manifest(command, siteppFileName, tmpoutfile, tmperrfile) // 会根据command命令里repo_info参数值,执行相应的puppet命令
- return result
Ambari深入学习(II)-实现细节的更多相关文章
- Mybatis学习的一些细节
一.mybatis 基本配置 最近几天一直在学习mybatis,看了一些源码,本文讲述mybatis的一些基本配置和基本的用法和注意到一些细节.个人时间和精力有限,本文属于流水账类型,不成体系,算是自 ...
- Ambari深入学习(I)-系统架构
Ambari是hadoop分布式集群配置管理工具,是由hortonworks主导的开源项目.它已经成为apache基金会的孵化器项目,已经成为hadoop运维系统中的得力助手,引起了业界和学术界的关注 ...
- 03-spring学习-属性配置细节
配置bean的一些细节 字面值 如果包含特殊符号,直接写会报错.可以用这个<![CDATA[]]>包裹起来. 比如这里的配置属性里面的value值包含<>等特殊符号,直接写会报 ...
- Ambari深入学习(III)-开源使用及其改进思考
Ambari采用的不是一个新的思想和架构,也不是完成了软件的新的革命,而是充分利用了一些已有的优秀开源软件,巧妙地把它们结合起来,使其在分布式环境中做到了集群式服务管理能力.监控能力.展示能力.这些优 ...
- 近期Android学习II
一晃眼又过了5天,这几天的学习有些杂乱,半年在家没运动,返校了准备慢慢恢复运动,身体才是革命的本钱~ 四天跑了三回步,每次都死亡喘息= = 这几天的学习重点总归还是放在Android上了,前面31天连 ...
- jQuery学习易忘细节
1.类似于alert(""),但不会中断页面操作:console.log("last"); 2.javascript是HTML5以及所有现代浏览器中的默认脚本语 ...
- 【SQLSERVER学习笔记】细节记录
SQLSERVER 查询时,WHERE中使用<>时,不会把NULL值查出来. SQLSERVER子查询中不能使用 ORDER BY. SQLSERVER 使用DISTINCT时,必须把OR ...
- LWIP学习之一些细节
一 绑定端口后,开启监听,为何监听还要返回一个新的连接?:监听状态的连接只需要很小的内存,于是tcp_listen()就会收回原始连接的内存,而重新分配一个较小内存块供处于监听状态的连接使用. 二 t ...
- Ambari 自定义服务集成原理介绍
之前,在 github 上开源了 ambari-Kylin 项目,可离线部署,支持 hdp 2.6+ 及 hdp 3.0+ .github 地址为:https://github.com/8418090 ...
随机推荐
- 解决linux环境下nohup: redirecting stderr to stdout问题
在生产环境下启动Weblogic时,发现原来好好的nohup信息输出到指定文件中的功能,突然出问题了.现象是控制台输出的信息一部分输出到了我指定的文件,另一部分却输出到了nohup.out,而我是不想 ...
- IDE 问题及解决
目录 Eclipse 篇 1.MarketPlace 打不开,对话框闪退 2.使用 lombok ,预编译不通过 3.Eclipse + PyDev - > Unresolved import: ...
- 小程序使用npm安装第三方包
安装vant 小程序UI库 进到小程序目录,在地址栏中cmd 进入DOS界面 npm init -f 安装vant 小程序UI库 npm i vant-weapp -S --production ...
- GEO Gene Expression Omnibus
GEO Gene Expression Omnibus 基因表达数据库 网址:https://www.ncbi.nlm.nih.gov/geo/ GEO的数据存储方式 GEO数据库具体存放四类数据: ...
- Vs2017添加.NET Standard项目出现黄色未引用的SDK
项目打开文件夹位置,按住shift键,执行dotnet restore命令
- VS 点击页面自动定位到解决方案资源管理器目录位置
点击工具→选项→项目和解决方案:勾上“在解决方案资源管理器中跟踪活动项”.
- 1045-Access denied for user 'root'@'localhost'解决方法
1.出现这个问题的原因之一是权限的问题,也就是说你的电脑可能没有权限访问mysql数据库. 讲道理这种情况其实基本上不该遇到,因为我们在安装mysql之后,root其实是有最高权限的,而且很少会有人去 ...
- dubbo源码分析- 集群容错之Cluster(一)
1.集群容错的配置项 failover - 失败自动切换,当出现失败,重试其他服务器(缺省),通常用于读操作,但重试会带来更长的延时. failfast - 快速失效,只发起一次调用,失败立即报错.通 ...
- Java: Java终止线程的几种方式
首先说明,使用stop方法终止的方式已经在很久之前就被废弃了,在加锁的情况下有可能会造成死锁,这里不做讨论. 1. 使用标志位终止线程 在run()方法执行完毕后,该线程就终止了.但是在某些特殊的情况 ...
- 使用NPOI或EPPlus来导出Excel文件实例,可在Excel文件加密
使用NPOI.dll组件来导出Excel文件,并设置样式,Nuget引用即可. packages\NPOI.2.1.3.1\lib\net20\NPOI.dll #region Excel prote ...