木讷大叔爱运维

漏了监控:Zabbix对Eureka instance状态监控

点击上方 蓝色字体 ,关注我们 预计阅读时间4分钟

背景

在正式开始介绍监控之前,我们先来了解下我们微服务架构使用的两个组件,这两个组件是我们本次监控需求的来源。

Eureka

Eureka作为Spring Cloud的注册中心,主要提供服务注册与发现的能力。

Eureka 采用 CS(Client/Server,客户端/服务器) 架构,它包括以下两大组件:

  • Eureka Server :Eureka服务注册中心,主要用于提供服务注册功能。当微服务启动时,会将自己的服务注册到 Eureka Server。Eureka Server 维护了一个可用服务列表,存储了所有注册到 Eureka Server 的可用服务的信息,这些可用服务可以在 Eureka Server 的管理界面中直观看到。

  • Eureka Client :Eureka 客户端,通常指的是微服务系统中各个微服务,主要用于和 Eureka Server 进行交互。在微服务应用启动后,Eureka Client 会向 Eureka Server 发送心跳(默认周期为 30 秒)。若 Eureka Server 在多个心跳周期内没有接收到某个 Eureka Client 的心跳,Eureka Server 将它从可用服务列表中移除(默认 90 秒)。

Apollo

Apollo(阿波罗)是一款可靠的分布式配置管理中心,诞生于携程框架研发部,能够集中化管理应用不同环境、不同集群的配置,配置修改后能够实时推送到应用端,并且具备规范的权限、流程治理等特性,适用于微服务配置管理场景。

而Spring Cloud配置中心集成git仓库、svn仓库等配置源统一获取系统配置参数,由Spring Cloud Config Client消费。其配置文件必须遵循严格的语法格式,即使多余的空格都会造成Client 无法读取相应的配置参数,一旦出问题很容易被忽视。

基于Spring Cloud配置中心这种缺陷,我们使用Apollo进行了逐步的替换,使运维、开发对于不同环境之间的配置文件管理更加方便。

问题

借助Apollo可以实现 配置修改实时生效(热发布) ,即用户在Apollo修改完配置并发布后,客户端能实时(1秒)接收到最新的配置,并通知到应用程序。

Apollo热发布功能满足了我们在更改配置属性需求时,应用可以实时感知。但在使用过程中,如果Eureka Client 自动更新配置时,进行全量更新,则会导致Eureka Server在心跳周期内的健康检查状态如下:

  • client服务发现状态为“UNKNOWN”
  • client后台仍然正常运行,无法向Eureka Server发送正常心跳

由于Eureka Server服务发现状态异常,此时是无法正常对外提供服务的。如果运维不及时检查Eureka管理界面每个client状态时,那么就会差生一起生产事故。

注意:每个client对应一个instance,下面我们统一将其称为instance。

需求

针对以上情况,虽然我们已经对instance接入了健康检查,但由于instance正常运行并没有产生告警,此时看来我们的监控还是有漏洞,因此我们需要通过Zabbix对Eureka instance状态监控来实现应用监控的全覆盖。

思路

Eureka Server注册的服务以application维度进行分组,每个application下有多个instance。因此我们借助Zabbix的自动发现,通过Eureka API 可以获取所有的分组信息,而不必每次都手动再次添加监控项。

由于Zabbix监控项是不能重复的,因此我们通过 application名/Instance ip地址 进行命名,区分不同的instance,这就要求我们的应用不能在一台服务器上部署多个应用,否则会导致监控项重复。 「注意:」 其实我们可以通过 InstanceId 作为区分更合理,但是InstanceId的使用往往不规范,如包含ip、主机名等等,由于字符过长可能导致不必要的麻烦。

Eureka API

# 获取Eureka 所有的applicationhttp://192.168.3.123:1180/eureka/apps# 获取某个application下所有的instancehttp://192.168.3.123:1180/eureka/apps/application名/

具体实现

因为需要解析Eureka API返回的数据,所以我们使用python来解析json数据。

instance自动发现

# 执行脚本自动发现application名和Instance ip地址python eureka-instance.py discovery{    "data":[        {            "{#APP}":"TEST1",            "{#HOSTNAME}":"192.168.3.10"        },        {            "{#APP}":"TEST1",            "{#HOSTNAME}":"192.168.3.11"        }    ]}
通过获取 {#APP} 和 {#HOSTNAME} ,我们就可以组合成对应命名规则的监控项。
# 监控项组合TEST1/192.168.3.10TEST1/192.168.3.11

获取监控项状态

经过自动发现后的数据,我们可以进一步获取监控项的状态。

# 1.获取instance 10状态python eureka-instance.py status TEST1 192.168.3.10# 执行结果UP# 2.获取instance 11状态python eureka-instance.py status TEST1 192.168.3.11# 执行结果UP

根据不同Instance的状态,只要结果非“UP”则进行告警。

最终脚本

#!/usr/local/miniconda/bin/python#-*- coding:utf-8 -*-#comment:#1.zabbix自动发现eureka instance#2.对instance的状态进行监控告警import requestsimport jsonimport sysfrom copy import deepcopy# 返回json格式数据,否则返回xml格式数据headers = {'Accept':'text/html, application/xhtml+xml, application/json;q=0.9, */*;q=0.8'}def instance_discovery():    app_list = []    url="http://192.168.3.123:1180/eureka/apps/"     try:       response=requests.get(url, headers=headers)       if response.status_code == 200:           instance_dic = {}           #for app in response.json()["applications"]["application"][1:2]:           for app in response.json()["applications"]["application"]:               for instance in app['instance']:                   instance_dic['{#APP}'] = instance['app']                   instance_dic['{#HOSTNAME}'] = instance['hostName']                   # 深copy                   app_list.append(deepcopy(instance_dic))           #print(app_list)           #json序列化           discovery_app_info = {"data":app_list}           print(json.dumps(discovery_app_info, sort_keys=True, indent=4, separators=(',', ':')))    except Exception as e:       print(e)def instance_status():    if len(sys.argv) == 4:        try:            url="http://192.168.3.123:1180/eureka/apps/%s/" % (sys.argv[2])            response=requests.get(url, headers=headers)            if response.status_code == 200:                instance_dic = {}                for instance in response.json()["application"]["instance"]:                    if sys.argv[3] == instance["hostName"]:                        print(instance["status"])        except Exception as e:            print(e)    else:        print("Usage: python eureka-instance.py status app hostName")if __name__ == '__main__':    if sys.argv[1] == 'discovery':        instance_discovery()    elif sys.argv[1] == 'status':        instance_status()    else:        print("Usage: python eureka-instance.py [discovery]|[status app hostName]")

接入Zabbix

1.配置文件

vim eureka.confUserParameter=instance_discovery,/usr/local/miniconda/bin/python /etc/zabbix/monitor_scripts/eureka-instance.py discoveryUserParameter=instance_status[*],/usr/local/miniconda/bin/python /etc/zabbix/monitor_scripts/eureka-instance.py status "$1" "$2"

2.自动发现


注意:自动发现instance的检查时间我们设置为半小时,避免过于频繁的调用Eureka API。

3.监控项配置


注意: instance状态的检查 时间我们设 置为15分钟, 避免过于频繁 的调用Eureka API 。
4.告警信息
# 1.状态为DOWN,发生告警告警主机:中间件_eureka_192.168.3.123主机IP:192.168.3.123主机组:中间件_eureka告警时间:2022.06.01 14:58:23恢复时间:2022.06.01 15:13:24告警等级:High告警信息:Eureka/TEST1/192.168.3.10:状态为DOWN告警项目:instance_status[TEST1,192.168.3.10]问题详情:TEST1/192.168.3.10: DOWN当前状态:发生告警# 2.状态为UP,恢复告警告警主机:中间件_eureka_192.168.3.123主机IP:192.168.3.123主机组:中间件_eureka告警时间:2022.06.01 14:58:23恢复时间:2022.06.01 15:13:24告警等级:High告警信息:Eureka/TEST1/192.168.3.10:状态为DOWN告警项目:instance_status[TEST1,192.168.3.10]问题详情:TEST1/192.168.3.10: UP当前状态:告警恢复: UP


1.Bug:Zabbix对Kafka topic积压数据监控
2. 运维:CMDB好用和用好,差别还是挺大的!
3.基于等级保护梳理服务器安全合规基线
4.Linux高危命令,运维人手一份
5.后话:PipeLine支撑运维自动化
6.Kwok:开源的 IT 管理系统
7.蓝鲸实现多环境vsphere虚拟机交付



札记:弱小和无知,不是生存的障碍,傲慢才是。 --《三体》 喜欢这篇文章,记得 点赞+在看 哦~