背景
在正式开始介绍监控之前,我们先来了解下我们微服务架构使用的两个组件。
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 所有的application
http://192.168.3.123:1180/eureka/apps
# 获取某个application下所有的instance
http://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.10
TEST1/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 requests
import json
import sys
from 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.conf
UserParameter=instance_discovery,/usr/local/miniconda/bin/python /etc/zabbix/monitor_scripts/eureka-instance.py discovery
UserParameter=instance_status[*],/usr/local/miniconda/bin/python /etc/zabbix/monitor_scripts/eureka-instance.py status "$1" "$2"
2.自动发现
3.监控项配置
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
文章评论