Ambari Alert告警服务梳理

目录

  1. Ambari 告警的基础概念
    1.1. Ambari 中 Alert 的类型
    1.1.1. Script
    1.1.2. Port
    1.1.3. Web
    1.2. Alert 相关的Rest API
    1.2.1. Create
    1.2.2. Update
    1.2.3. Delete
    1.2.4. Query
    1.2.5. Alert立即执行
    1.3. 告警通知
    1.3.1. Alert notification 模版XML结构
    1.3.2. 告警通知示例
  2. Ambari Agent对Alert的处理
    2.1. Ambari Agent获取Alert definition
    2.2. 执行Alert
    2.3. Ambari Agent上报alert信息
    2.4. AlertSchedulerHandler.py
    2.4.1. AlertSchedulerHandler启动流程
    2.4.2. AlertSchedulerHandler更新Alert definition
    2.4.3. AlertSchedulerHandler立刻执行Alert definition
    2.5. Alert调度器
    2.5.1. Python APScheduler
    2.5.2. Alert Scheduler
    2.6. AlertCollector
    2.7. Ambari agent对Alert的处理总结
    2.8. BaseAlert的collect函数执行过程
    2.9. Agent执行WebAlert过程
    2.10. Agent执行Port Alert过程
    2.11. Agent执行Script Alert过程
  3. Ambari Alert实践

1.Ambari 告警的基础概念

Ambari 为了帮助用户鉴别以及定位集群的问题,实现了告警(Alert)机制。在 Ambari 中预定了很多的告警,这些告警被用于监测集群的各个模块以及机器的状态。

对于告警来说,主要有两个概念,一个是 Alert Definition,一个是 Alert Instance。

(1)Alert Definition: 告警的定义,Server使用Alert Definition来将alert分配到合适的Ambari Agent中并创建Alert instance。在Alert Definition中会定义alert的检测时间间隔(interval)、类型(type)、以及阈值(threshold)等。

(2)Alert Instance:Ambari 会读取alert definition,然后创建对应的实例(instance)去定期执行这个告警。

终端用户可以在 WEB 中 Alert 的页面,浏览以及组织管理这些告警。如果告警名称太多,用户可以用过滤器筛选想要查找的告警。其实这些 WEB 中的显示,都是 Alert Definition。用户可以点击具体的 Alert name 去查看或者修改 Alert 属性(例如 interval 和阈值)。在详细的告警页面里,可以看到该告警所有的 instance。每个 instance 都会严格的报告该 instance 的检查结果。Alert 的检查结果会以五种级别呈现,分别是 OK、WARNING,CRITICAL、UNKNOW 和 NONE。其中最常见的是前三种。

1.1.Ambari 中 Alert 的类型
Ambari 中的 Alert 分为 5 种类型,分为 WEB、Port、Metric、Aggregate 和 Script。具体的区别见下面的表格。
这里写图片描述

每种类型的alert都具有如下公共属性:
a.id
b.name
c.label
d.cluster_name
e.service_name
f.component_name
g.source
除了一些公共属性外,每种类型的alert还会有一些特殊的属性,下面主要将alert的核心属性:Source及每种类型的alert的source属性应该如何配置。

1.1.1.Script

Script类型的alert的将所有的功能都有其指定的python脚本来说明。Script类型的alert,除了公共属性外,只需要在source属性中指定其python脚本路径。

"source" : {
      "path" : "HDFS/2.1.0.2.0/package/alerts/alert_ha_namenode_health.py",
      "type" : "SCRIPT" }

1.1.2.Port

返回值通过web请求的响应时间确定,不检查response的返回码。

"source" : {
      "default_port" : 2181, #当uri中不包含port时,使用该值
      "reporting" : {
        "ok" : {#状态码必须小写
          "text" : "TCP OK - {0:.3f}s response on port {1}"
        },
        "warning" : { #text:指定返回显示的文本
          "text" : "TCP OK - {0:.3f}s response on port {1}",
          "value" : 1.5#指定waring_timeout,如果大于30,则使用默认值
        },
        "critical" : {
          "text" : "Connection failed: {0} to {1}:{2}",
          "value" : 5.0
        }
      },
      "type" : "PORT",
      "uri" : "{{core-site/ha.zookeeper.quorum}}", #url必须为{{foo-bar/baz}}的形式,可为常量或是变量,如果变量值不存在,则agent会使用当前localhost代替
    }
  }

1.1.3.Web

Web 和port功能相似,区别是Web不仅检测TCP连接性,还检查HTTP响应状态码。

 "source" : {
      "reporting" : {
        "ok" : {
          "text" : "HTTP {0} response in {2:.3f} seconds"
        },
        "warning" : {
          "text" : "HTTP {0} response in {2:.3f} seconds"
        },
        "critical" : {
          "text" : "Connection failed to {1}: {3}"
        }
      },
      "type" : "WEB",
      "uri" : {
        "http" : "{{hdfs-site/dfs.namenode.http-address}}",
        "https" : "{{hdfs-site/dfs.namenode.https-address}}",
        "https_property" : "{{hdfs-site/dfs.http.policy}}",
        "https_property_value" : "HTTPS_ONLY",
        "kerberos_keytab" : "{{hdfs-site/dfs.web.authentication.kerberos.keytab}}",
        "kerberos_principal" : "{{hdfs-site/dfs.web.authentication.kerberos.principal}}",
        "default_port" : 0.0,
        "high_availability" : {
          "nameservice" : "{{hdfs-site/dfs.nameservices}}",
          "alias_key" : "{{hdfs-site/dfs.ha.namenodes.{{ha-nameservice}}}}",
          "http_pattern" : "{{hdfs-site/dfs.namenode.http-address.{{ha-nameservice}}.{{alias}}}}",
          "https_pattern" : "{{hdfs-site/dfs.namenode.https-address.{{ha-nameservice}}.{{alias}}}}"
        }
      }
    }

1.2.Alert 相关的Rest API

1.2.1.Create

POST api/v1/clusters/<cluster>/alert_definitions “ Alert defintion data in json format

1.2.2.Update

更新时,不需要传入所有的属性,只需要传入需要修改的属性,其他属性使用之前的值。

PUT api/v1/clusters/<cluster>/alert_definitions/<definition-id>

{
  "AlertDefinition" : {
    "interval" : 10,
      "uri" : "{{yarn-site/yarn.resourcemanager.address.foo}}"
    }
  }
}

只更新Alert(具体Alert由Alert id指定)的uri和interval值

1.2.3.Delete

DELETE api/v1/clusters/<cluster>/alert_definitions/<definition-id>

1.2.4.Query

查询时也可传入参数,限定某些alert

GET api/v1/clusters/<cluster>/alert_definitions    

1.2.5.Alert立即执行

PUT http://<server>/api/v1/clusters/<cluster>/alert_definitions/<definition-id>?run_now=true

1.3.告警通知

Ambari中的Notification是用来将集群告警信息发布出去。通知模版的内容是和notification类型强耦合的。Email和SNMP 都可以通过模版配置notification内容。
下面主要讲述如何进行自定义notification模版。自定义notification只能通过修改 ambari.properties配置文件,不提供Rest 或是其他方式进行修改。具体步骤:
① 编辑/etc/ambari-server/conf/ambari.properties文件,增加自定义的notification条目,例如:alerts.template.file=/foo/var/alert-templates-custom.xml
实际ambari在启动时,如果没有找到对应的自定义配置文件,则还是使用默认的(在ambari的jar包中)。

② 保存文件,然后重启ambari server.

1.3.1. Alert notification 模版XML结构

<alert-templates>
    <alert-template type="EMAIL">
         <subject>
             Subject Content
            </subject>
            <body>
                Body Content
        </body>
    </alert-template>

    <alert-template type="SNMP">
         <subject>
                Subject Content
            </subject>
            <body>
             Body Content
         </body>
    </alert-template>
</alert-templates>

在XML模版中,可以使用模版变量。部分模版变量如下表所示。(详细完整的模版变量见:https://cwiki.apache.org//confluence/display/AMBARI/Customizing+the+Alert+Template

这里写图片描述

1.3.2.告警通知示例
① 下载alert-templates.xml文件,作为模版(地址:https://github.com/apache/ambari/blob/trunk/ambari-server/src/main/resources/alert-templates.xml
② 将模版保存到某个目录,例如: /var/lib/ambari-server/resources/alert-templates-custom.xml .
③ 编辑模版文件中的标签的subject域,改成:

<subject>
  <![CDATA[Petstore Ambari has $summary.getTotalCount() alerts!]]>
</subject>

④ 保存文件
⑤ 编辑/etc/ambari-server/conf/ambari.properties文件,增加一个条目,指向刚才编辑的temple文件

alerts.template.file=/var/lib/ambari-server/resources/alert-templates-custom.xml

⑥ 保存文件,重启Ambari Server

2.Ambari Agent对Alert的处理

2.1.Ambari Agent获取Alert definition

           Ambar agent获取Alert definition有两个方式:1)在向server注册时,注册成功时,会调用AlertSchedulerHandler进行Alert definitions更新;

Controller.py
def registerWithServer(self):
          ................
    # always update alert definitions on registration
    self.alert_scheduler_handler.update_definitions(ret)
    ............. 

2)在收到Server的HeartBeat响应时,server可能会发送alertDefinitionCommands指令,则Agent需要处理该指令;

Controller.py
def heartbeatWithServer(self):
          ................
    if 'alertDefinitionCommands' in response_keys:
         logger.log(logging_level, "Updating alert definitions")
               self.alert_scheduler_handler.update_definitions(response)
    ..................

    ............. 

2.2.执行Alert

Alert任务的执行触发条件分为两种:
1)在Server的heartbeat响应中收到了alertExecutionCommands命令(如通过rest api发送了立刻执行的请求),在agent中则会立刻执行该alert;

Controller.py
def heartbeatWithServer(self):
          ................
if 'alertExecutionCommands' in response_keys:
        logger.log(logging_level, "Executing alert commands")
        self.alert_scheduler_handler.execute_alert(response['alertExecutionCommands'])
    ..................

    ............. 

2)Alert定时到了。Alert在Agent中作为间隔定时作业进行调度。关于该部分下面几节会进行详细说明。

2.3.Ambari Agent上报alert信息

Agent会在heartbeat请求中加上alert信息

Heartbeat.py
def build(self, id='-1', add_state=False, componentsMapped=False):
        ................
if self.collector is not None:
      heartbeat['alerts'] = self.collector.alerts()
    ..................

下面主要对Alert涉及的核心类进行详细分析,包括AlertSchedulerHandler,HeartBeat,APScheduler.Scheduler,Job,AlertCollector。

2.4.AlertSchedulerHandler.py

AlertSchedulerHandler属于Alert控制器,作用包括:
① 为controller提供接口,更新本机alert defintion
② 为controller提供接口,立刻执行Alert
③ 加载本机的Alert definition
④ 管理、启动Alert调度器,并负责在更新Alert definition时,对Alert 调度器中的任务进行管理(如删除任务、添加新任务)。

2.4.1.AlertSchedulerHandler启动流程

当Controller线程在初始化时,就会创建AlertSchedulerHandler对象,然后调用AlertSchedulerHandler的start方法。首先从start方法开始看看该类的处理过程。
Start方法处理过程:
① 如果没有创建调度器,则直接返回(该调度器会在AlertSchedulerHandler初始化函数中进行创建);
② 判定调度器的运行状态;如果调度器已经运行了,则停止注销该调度器,重新创建初始化调度器;
③ 调用__load_defintions函数,解析本机上的defintions.json文件(文件目录:/var/lib/ambari-agent/cache/alerts/defintions.json),找到其中定义的所有的Alert定义;
④ 调用schedule_defintion函数,将Alert加入到调度器中;
调用调度器的start方法,启动Alert调度器。
过程的流程图如下所示:
这里写图片描述

__load_defintions函数解析加载Alert过程如下所示:
这里写图片描述

在根据json元素创建Alert对象时,会根据json中的type,source创建不同的Alert对象,包括MetricAlert,AmsAlert,PortAlert,ScriptAlert,WebAlert,RecoveryAlert。不同的Alert对象的类继承关系如下图所示:
这里写图片描述

BaseAlert的collect函数为Alert的具体执行逻辑,在BaseAlert函数的collect函数中会调用具体子类的_collect函数。子类必须实现_collect函数,实现特定类型的Alert信息收集工作。

2.4.2.AlertSchedulerHandler更新Alert definition

AlertSchedulerHandler调用update_definitioons函数更新本机alert definiton,过程如下图所示:
这里写图片描述

关于为什么需要判定:alertDefinitions中指定的clusterName在AlertSchedulerHandler的集群名列表中?如果alertDefinitions中指定的clusterName在AlertSchedulerHandler的集群列表中(该列表保存上次从definition.json中解析出的alert的clustername),则表示此处是更新某些Alert defintion,而不需要将之前存在与alert 调度器中的alert任务清理掉。如果不在的化,则说明之前从definiton.json中加载的alert defintion完全不同,则需要将alert 调度器中的alert任务清理掉,重新生成任务,加入到调度器中。

reschedule和reschedule_all函数的差别也就在于是否需要将之前存在与alert 调度器中的alert任务清理掉。

2.4.3.AlertSchedulerHandler立刻执行Alert definition

当Controller直接调用AlertSchedulerHandler的execute_alert函数时,AlertSchedulerHandler会立马执行该Alert Defintion任务,但是任务不会加入到调度器中,即任务之后执行一次。该接口主要用于测试目的(当任务的运行周期比较长,则需要等待很长时间才会运行)。
execute_alert函数逻辑比较简单,执行步骤如下:
① 解析heartbeat中的execution_commands数据;
② 对于execution_commands中的每条alert defintion,创建相应的Alert对象,绑定alert信息collector,然后直接执行Alert的collect方法,执行Alert。
注意,直接走execute_alert函数的化,execution_commands数据是不刷新到本机definitions.json文件中的

2.5.Alert调度器

2.5.1.Python APScheduler

APScheduler:强大的任务调度工具,可以完成定时任务,周期任务等,它是跨平台的,用于取代Linux下的cron daemon或者Windows下的task scheduler。

特点:
(1)内置三种调度调度系统:Cron风格、间隔性执行、仅在某个时间执行一次
(2)作业存储的backends支持:Memory、SQLAlchemy (any RDBMS supported by SQLAlchemy works)、MongoDB、Redis、RethinkDB、ZooKeeper

APScheduler中的基本组件:
① triggers: 描述一个任务何时被触发,有按日期、按时间间隔、按cronjob描述式三种触发方式
② job stores: 任务持久化仓库,默认保存任务在内存中,也可将任务保存都各种数据库中,任务中的数据序列化后保存到持久化数据库,从数据库加载后又反序列化。
③ executors: 执行任务模块,当任务完成时executors通知schedulers,schedulers收到后会发出一个适当的事件
④ schedulers: 任务调度器,控制器角色,通过它配置job stores和executors,添加、修改和删除任务。
运行逻辑:scheduler的主循环(main_loop),其实就是反复检查是不是有到时需要执行的任务,完成一次检查的函数是_process_jobs, 这个函数做这么几件事:
① 询问自己的每一个jobstore,有没有到期需要执行的任务(jobstore.get_due_jobs())
② 如果有,计算这些job中每个job需要运行的时间点(run_times = job._get_run_times(now))如果run_times有多个,这种情况我们上面讨论过,有coalesce检查。提交给executor排期运行(executor.submit_job(job, run_times))
③ 那么在这个_process_jobs的逻辑,什么时候调用合适呢?如果不间断地调用,而实际上没有要执行的job,是一种浪费。每次掉用_process_jobs后,其实可以预先判断一下,下一次要执行的job(离现在最近的)还要多长时间,作为返回值告诉main_loop, 这时主循环就可以去睡一觉,等大约这么长时间后再唤醒,执行下一次_process_jobs。这里唤醒的机制就会有IO模型的区别了。

根据Scheduler采用的IO模型,Scheduler具体实现有多种。内置scheduler有:
① BlockingScheduler: scheduler在当前进程的主线程中运行,所以调用start函数会阻塞当前线程,不能立即返回。
② BackgroundScheduler: 放到后台线程中运行,所以调用start后主线程不会阻塞
③ AsyncIOScheduler: 使用asyncio模块
④ GeventScheduler: 使用gevent作为IO模型,和GeventExecutor配合使用
⑤ TornadoScheduler: 配合TwistedExecutor,用reactor.callLater完成定时唤醒
⑥ TwistedScheduler: 使用tornado的IO模型,用ioloop.add_timeout完成定时唤醒
⑦ QtScheduler: 使用QTimer完成定时唤醒

2.5.2.Alert Scheduler

Alert调度器实现在apscheduler/scheduler中。Scheduler实现策略和Python的APscheduler类似。在Agent中的Scheduler采用的IO模型为Event模型,在调用_process_jobs处理任务时,会计算下次wakeup时间,执行完_process_jobs任务后,通过Event模型,睡眠一段时间,然后再次调用_process_jobs任务。

需要注意的是Scheduler在提交Alert任务时,直接将任务提交到线程池,但是任务绑定的运行函数为Scheduler._run_job函数。该函数负责调用Alert任务的collect函数,获取处理返回结果、结果做日志处理,并发出相关事件(Alert任务执行失败事件、任务执行成功事件等),通知Scheduler事件的监听者(默认情况下,Scheduler并没有注册任何事件监听者)。

2.6.AlertCollector

AlertCollector位于alerts/collector.py中,负责收集所有的Alert任务执行结果。
Cotroller线程会定时的向server发送Heartbeat信息。Heartbeat信息调用Heartbeat类的build方法进行构建,在构建heartbeat信息时,会调用collector的alerts()函数收集在此heartbeat期间执行的Alert任务的结果,然后将构建好的heartbeat信息发送给Server。
AlertCollector保存了一个map(key=集群,value={alert名字,执行结果})。当Alert执行完后,会将执行结果发送到绑定的AlertCollector中,放入到AlertCollector的map中。alerts函数的执行过程下图所示:
这里写图片描述

2.7.Ambari agent对Alert的处理总结

Ambari Agent中和Alert相关的各个组件之间的关系如下图所示:
这里写图片描述

默认情况下,只有一个AlertCollector,所有的Alert任务都绑定同一个AlertCollector,当Job完成后,将结果发送给AlertCollector。当Controller发送Heartbeat消息时,调用Heartbeat类的build方法。Heartbeat类在构造hearbeat消息数据时,会调用AlertCollector的alert的方法,将所有的alert执行结果放入到heartbeat消息体中。

2.8.BaseAlert的collect函数执行过程

如前所述,Alert注册的执行体为类的collect函数,该函数在父类BaseAlert中实现。BaseAlert的collect函数的处理过程如下图所示:
这里写图片描述

说明:在BaseAlert中实现的collect函数是一个基础执行框架,包括通用的异常处理和结果处理。在执行过程中,会调用子类的_collect函数,执行特定alert的业务逻辑。具体的Alert子类(如WebAlert,PortAlert)将自己的业务逻辑全部在_collect函数中定义。因此,下面讲述具体Alert执行过程时,就是描述该Alert的_collect的执行过程。

2.9.Agent执行WebAlert过程

WebAlert的_collect函数主要处理过程如下图所示:

这里写图片描述

比如HDFS中定义的namenode_webui Alert,默认配置下,在hdfs-site中并没有配置dfs.internal.nameservices,也无法解析{{hdfs-site/dfs.ha.namenodes.{{ha-nameservice}}}},则无法根据HA配置中获取到URI。但是在hdfs-site中配置了dfs.namenode.http-address,其值为node1:50070,则最后构建的URI为:node1:50070,最后构造的URL为http://node1:50070

这里写图片描述

2.10.Agent执行Port Alert过程

PortAlert的_collect函数主要处理过程如下图所示:

这里写图片描述

2.11.Agent执行Script Alert过程

这里写图片描述

3.Ambari Alert实践

(1)为Kibana增加一个port类型的alert,并通过rest api安装。Agent将本节点的alert定义从server端拉下来(通过heartbeat),保存到/var/lib/ambari-agent/cache/alerts/definition.json。

curl -u admin:admin   -i     -H 'X-Requested-By:ambari'  -X  POST  http://node1:8080/api/v1/clusters/mycluster/alert_definitions   -d   '{"AlertDefinition" : {
    "service_name" : "KIBANA",      
    "component_name" : "KibanaNode",
    "enabled" : true,
    "interval" : 1,
    "label" : "Kibana Port",
    "name" : "Kibana Port",
    "scope" : "ANY",
    "source": {
             "type": "PORT",
               "uri": "{{kibana-site/server.port}}",
              "default_port": 5601,
             "reporting": {
               "ok": {   
                    "text": "TCP OK - {0:.3f}s response on port {1}"                                                                                 
                     },
               "warning": { 
                      "text": "TCP OK - {0:.3f}s response on port {1}", 
                        "value": 2.5  
                         },
                "critical": {
                         "text": "Connection failed: {0} to {1}:{2}",
                          "value": 10.0
                          }
        } } }}'

(2)立即运行该alert,测试该alert是否能正确执行

curl -u admin:admin   -i     -H 'X-Requested-By:ambari'  -X  PUT    http://node1:8080/api/v1/clusters/mycluster/alert_definitions/1002?run_now=true

(3)删除该alert(在该例子中, url后面的后缀数字为alert的id号)

curl -u admin:admin   -i     -H 'X-Requested-By:ambari'  -X  DELETE       http://node1:8080/api/v1/clusters/mycluster/alert_definitions/1001

Alert的id号可通过ambari web端进行查看,如查看HDFS的名为Host Disk Usage的alert的id号的方式:在web中点击查看该alert,url中的后缀即为该alert的id号。
这里写图片描述

猜你喜欢

转载自blog.csdn.net/youyou1543724847/article/details/78377400