背景

由于后端微服务架构,于是各种业务被拆分为多个服务,服务之间的调用采用RPC接口,而Nacos作为注册中心,可以监听多个服务的状态,比如某个服务是否down掉了、某个服务的访问地址是否改变、以及流量分配降级等等。(nacos注册中心的由来及原理

运维架构用的是K8S,由于之前没有做服务高可用的特性,K8S上服务挂掉后不会自动重启。

所以测试过程中,某个接口有问题,可能最先需要排查该服务或依赖服务是否正常可用。

问题

上面说到,测试过程中还需要查看服务是否正常,这是很浪费时间的,特别是环境不稳定的情况下,也许今天下班前测得好好的,明天或者后天就会发现部分服务就挂掉了(毕竟六七十个服务人工筛查太麻烦了)。能否把这个问题前置解决?

解决方案

我的解决方法就是,利用python爬虫思路,每天获取当前nacos注册的服务与nacos配置的服务列表对比,如果注册的服务小于Nacos的服务,就说明部分服务不可用,这时就可以先解决后再介入测试,再搭配Jenkins,可以早晚巡查服务是否正常。(当然我们后面K8S已经实现了服务的自动重启,所以该脚本也算服务检查的补充方案了)

设计如下

首先定义一个测试类checkJob。

第一步,登录nacos

1     # 登录nocas
2 def con_nacos(self):
3 data = {"username":"nacos","password":"Billion123!@#"}
4 res = requests.post(url = self.urlLogin, headers = self.headers, data=data).json()['accessToken']
5 return res

第二步,获取当前namespace服务配置文件

1     # 获取目前环境服务配置列表
2 def get_job_config(self):
3 self.joblist = []
4 params = self.config_params
5 res = requests.get(url= self.urlGetConfig, headers = self.headers, params = params).json()["pageItems"]
6 for i in res:
7 self.joblist.append(i.get("dataId"))
8 print("-------目前的服务配置有:", len(self.joblist))
9 return self.joblist

第三步,获取当前正常注册的服务

1     # 获取目前所有服务列表
2 def get_job(self):
3 self.getjoblist = []
4 res = requests.get(url = self.urlGetJob,headers = self.headers, params = self.params).json()['serviceList']
5 for i in res:
6 self.getjoblist.append(i.get("name"))
7 return self.getjoblist

第四步,比对实际注册的服务与配置的服务并打印输出

 1     #迭代比对当前服务列表
2 def check_job(self):
3 tmp = set(self.joblist).difference(self.getjoblist)
4 if tmp:
5 return tmp
6 else:
7 return ""
8
9 #对未存在的服务通知告警
10 def msg(self,tmp):
11 for i in self.ignore:
12 if i in tmp:
13 tmp.remove(i)
14 # print(i)
15 if tmp:
16 print(f"缺少{len(tmp)}个服务,如下:", tmp)
17 else:
18 print(f"{len(self.joblist)}个服务正常:", self.joblist)

当然可能有多个环境,优化一下代码,全部代码如下:

  1 import requests
2
3 class CheckJob():
4 #定义所有服务列表
5 joblist = []
6 urlLogin = "http://xxx.xxx.xxx.xxx:10086/nacos/v1/auth/users/login"
7 urlGetConfig = "http://xxx.xxx.xxx.xxx:10086/nacos/v1/cs/configs"
8 urlGetJob = "http://xxx.xxx.xxx.xxx:10086/nacos/v1/ns/catalog/services"
9 headers = {
10 'Accept': 'application/json, text/plain, */*',
11 'Accept-Encoding': 'gzip, deflate',
12 'Accept-Language': 'zh-CN,zh;q=0.9',
13 'Connection': 'keep-alive',
14 "Host": "nacos.bb.local",
15 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.77 Safari/537.36',
16 }
17 # 忽略部分服务列表
18 ignore = ["member", "zuul", "order", "b-shop"]
19 def __init__(self):
20 self.accessToken = self.con_nacos()
21 for str in ["d","t","p","pro"]:
22 if str.strip() == "p":
23 # 预发环境
24 self.params = "hasIpCount=true&withInstances=false&pageNo=1&pageSize=100&serviceNameParam=&groupNameParam=&namespaceId=4dcd1ab3-9c07-4f2b-9ed9-9c1f67f4de9e&accessToken=$accessToken"
25 self.config_params = "dataId=&group=&appName=&config_tags=&pageNo=1&pageSize=100&tenant=4dcd1ab3-9c07-4f2b-9ed9-9c1f67f4de9e&search=accurate&accessToken=$accessToken"
26 print("预发环境",end="")
27 elif str.strip() == "t":
28 # 测试环境
29 self.params = "hasIpCount=true&withInstances=false&pageNo=1&pageSize=100&serviceNameParam=&groupNameParam=&namespaceId=0f4106a4-acad-4327-a1f5-54ee78b342ea&accessToken=$accessToken"
30 self.config_params = "dataId=&group=&appName=&config_tags=&pageNo=1&pageSize=100&tenant=0f4106a4-acad-4327-a1f5-54ee78b342ea&search=accurate&accessToken=&accessToken"
31 print("测试环境", end="")
32 elif str.strip() == "d":
33 # 开发环境
34 self.params = "hasIpCount=true&withInstances=false&pageNo=1&pageSize=100&serviceNameParam=&groupNameParam=&accessToken=$accessToken&namespaceId=ddd4b051-5a76-417d-bef8-09f7ff941bbd"
35 self.config_params = "dataId=&group=&appName=&config_tags=&pageNo=1&pageSize=100&tenant=ddd4b051-5a76-417d-bef8-09f7ff941bbd&search=accurate&accessToken=&accessToken"
36 print("开发环境",end="")
37 elif str.strip() == "pro":
38 # 线上环境
39 self.params = "hasIpCount=true&withInstances=false&pageNo=1&pageSize=100&serviceNameParam=&groupNameParam=&accessToken=&accessToken&namespaceId=1b1a6ba8-2d21-4cd6-b7b2-ecd3b838c387"
40 self.config_params = "dataId=&group=&appName=&config_tags=&pageNo=1&pageSize=100&tenant=1b1a6ba8-2d21-4cd6-b7b2-ecd3b838c387&search=accurate&accessToken=&accessToken"
41 print("线上",end="")
42 else:
43 print("输入不合法")
44 if self.params:
45 self.params = self.params.replace("$accessToken", self.accessToken)
46 if self.get_job_config():
47 if self.get_job():
48 self.msg(self.check_job())
49 else:
50 print("获取nacos服务失败")
51 else:
52 print("获取nacos服务配置失败")
53 else:
54 print("nacos登录失败")
55
56
57 # 登录nocas
58 def con_nacos(self):
59 data = {"username":"naco登录名","password":"nacos登录密码"}
60 res = requests.post(url = self.urlLogin, headers = self.headers, data=data).json()['accessToken']
61 return res
62
63 # 获取目前环境服务配置列表
64 def get_job_config(self):
65 self.joblist = []
66 params = self.config_params
67 res = requests.get(url= self.urlGetConfig, headers = self.headers, params = params).json()["pageItems"]
68 for i in res:
69 self.joblist.append(i.get("dataId"))
70 print("-------目前的服务配置有:", len(self.joblist))
71 return self.joblist
72
73 # 获取目前所有服务列表
74 def get_job(self):
75 self.getjoblist = []
76 res = requests.get(url = self.urlGetJob,headers = self.headers, params = self.params).json()['serviceList']
77 for i in res:
78 self.getjoblist.append(i.get("name"))
79 return self.getjoblist
80
81 #迭代比对当前服务列表
82 def check_job(self):
83 tmp = set(self.joblist).difference(self.getjoblist)
84 if tmp:
85 return tmp
86 else:
87 return ""
88
89 #对未存在的服务通知告警
90 def msg(self,tmp):
91 for i in self.ignore:
92 if i in tmp:
93 tmp.remove(i)
94 # print(i)
95 if tmp:
96 print(f"缺少{len(tmp)}个服务,如下:", tmp)
97 else:
98 print(f"{len(self.joblist)}个服务正常:", self.joblist)
99
100 if __name__ == '__main__':
101 cj= CheckJob()

Jenkins持续集成

第一步,上传到gitlab

这一步就不说了,自行上传即可(记得拷贝git链接),没用gitlab的可以直接放到Jenkins的服务器上。

第二步,配置jenkins

新建一个任务,选择github项目,输入项目地址

在源码管理这里配置的git登录用户证书信息,分支直接选master即可

构建触发器这里填入cron定时任务,这里代表周一到周六每天早上8点和下午15点各执行一次。

构建命令这里输入python命令即可(注意Jenkins的服务器上得有python的运行环境)

最后,构建后自动发送邮件(需要安装Editable Email Notification插件)

以下收件人和回复人得邮件地址采用了变量方式,也可直接输入邮箱地址

Content Type选择HTML(text/html)作为邮箱格式,Default Subject输入模板标题,Default Content作为邮件内容模板,参考如下

 1 <!DOCTYPE html>
2 <html>
3 <head>
4 <meta charset="UTF-8">
5 <title>${ENV, var="JOB_NAME"}-第${BUILD_NUMBER}次构建日志</title>
6 </head>
7
8 <body leftmargin="8" marginwidth="0" topmargin="8" marginheight="4"
9 offset="0">
10 <table width="95%" cellpadding="0" cellspacing="0" style="font-size: 11pt; font-family: Tahoma, Arial, Helvetica, sans-serif">
11 <tr>
12 本邮件由系统自动发出,无需回复!<br/>
13 各位同事,大家好,以下为${PROJECT_NAME }项目构建信息</br>
14 <td><font color="#2D5900">构建结果 - ${BUILD_STATUS}</font></td>
15 </tr>
16 <tr>
17 <td><br />
18 <b><font color="#0B610B">构建信息</font></b>
19 <hr size="2" width="100%" align="center" /></td>
20 </tr>
21 <tr>
22 <td>
23 <ul>
24
25 <li>账 号 : admin</li>
26 <li>密 码 : admin123</li>
27 <li>项目名称 : ${PROJECT_NAME}</li>
28 <li>构建编号 : 第${BUILD_NUMBER}次构建</li>
29 <li>触发原因: ${CAUSE}</li>
30 <li>构建状态: ${BUILD_STATUS}</li>
31 <li>项目 Url : <a href="${PROJECT_URL}">${PROJECT_URL}</a></li>
32 <li>构建信息: ${BUILD_LOG, maxLines = 10, escapeHtml = false}</li>
33 </ul>
34
35 <h4><font color="#0B610B">失败用例</font></h4>
36 <hr size="2" width="100%" />
37 $FAILED_TESTS<br/>
38
39 <h4><font color="#0B610B">最近提交(#$SVN_REVISION)</font></h4>
40 <hr size="2" width="100%" />
41 <ul>
42 ${CHANGES_SINCE_LAST_SUCCESS, reverse=true, format="%c", changesFormat="<li>%d [%a] %m</li>"}
43 </ul>
44 </td>
45 </tr>
46 </table>
47 </body>
48 </html>

Attachments作为邮件附件,直接输入report/*.html,Attach Build Log这栏选择Attach Build Log选项

保存构建项目,查看结果如下,详细配置邮件可参考这个文章:https://zhuanlan.zhihu.com/p/161627231

微服务状态之python巡查脚本开发的更多相关文章

  1. 通过Dapr实现一个简单的基于.net的微服务电商系统(十四)——开发环境容器调试小技巧

    之前有很多同学提到如何做容器调试,特别是k8s环境下的容器调试,今天就讲讲我是如何调试的.大家都知道在vs自带的创建项目模板里勾选docker即可通过F5启动docker容器调试.但是对于启动在k8s ...

  2. zipkin微服务调用链分析(python)

    一,概述 zipkin的作用 在微服务架构下,一个http请求从发出到响应,中间可能经过了N多服务的调用,或者N多逻辑操作,如何监控某个服务,或者某个逻辑操作的执行情况,对分析耗时操作,性能瓶颈具有很 ...

  3. Spring cloud微服务安全实战-4-11Zuul网关安全开发(四)

    限流,有个现成的开源项目可以帮助我们来做网关上的限流 用最新的这个版本 在pom.xml加入引用. 在限流的过程中需要存一些信息,可以存在数据库里 也可以存在redis里.这里我们演示存到数据库里 比 ...

  4. Spring cloud微服务安全实战-4-9Zuul网关安全开发(二)

    把在微服务里面写的安全的相关逻辑挪到网关里面来.这样把安全逻辑和业务逻辑解耦开.那么这些问题就都解决了. 先来看下之前的安全的代码,首先在之类做了认证,认证服务器去认证,拿这个token去换用户信息. ...

  5. Spring cloud微服务安全实战-4-8Zuul网关安全开发(一)

    安全相关的代码和业务逻辑相关的代码实际上是在一个应用里面的,在这个应用里面,我们需要去,这个应用本身的处理逻辑里面需要去处理令牌和用户信息之间的转换. 然后我们需要去知道认证服务器的地址,这些都是耦合 ...

  6. Spring cloud微服务安全实战-4-10Zuul网关安全开发(三)

    首先把地址给它 发送post请求,请求的数据就是这个entity对象. 最后返回的值要封装到TokenInfo里面 如果一切正常的话就会拿到一个响应的实体,实体里面就包含了TokenInfo 打印实体 ...

  7. 基于DDD的微服务设计和开发实战

    你是否还在为微服务应该拆多小而争论不休?到底如何才能设计出收放自如的微服务?怎样才能保证业务领域模型与代码模型的一致性?或许本文能帮你找到答案. 本文是基于 DDD 的微服务设计和开发实战篇,通过借鉴 ...

  8. 驱动领域DDD的微服务设计和开发实战

    你是否还在为微服务应该拆多小而争论不休?到底如何才能设计出收放自如的微服务?怎样才能保证业务领域模型与代码模型的一致性?或许本文能帮你找到答案. 本文是基于 DDD 的微服务设计和开发实战篇,通过借鉴 ...

  9. 关于Python构建微服务的思考(一)

    一:什么是微服务? 微服务是一种架构风格,一个大型复杂软件应用由一个或多个微服务组成. 系统中的各个微服务可被独立部署,各个微服务之间是松耦合的. 每个微服务仅关注于完成一件任务并很好地完成该任务. ...

随机推荐

  1. vue学习过程总结(06) - vue的数据存储store

    这个不知道能怎么叫不?现在对这块很迷.以下为个人理解 store是状态管理,是一个对象,有其属性和方法. 常见的值有:state/mutations/actions/getters, 这几个值的意思: ...

  2. J20航模遥控器开源项目系列教程(四)PCB打印 | 嘉立创PCB下单教程,5元顺丰包邮解君愁!

    我们的开源宗旨:自由 协调 开放 合作 共享 拥抱开源,丰富国内开源生态,开展多人运动,欢迎加入我们哈~ 和一群志同道合的人,做自己所热爱的事! 项目开源地址:https://github.com/J ...

  3. 利用多个sem信号量在线程通讯

    直接上代码,主要用到sem_trywait & sem_post #include<stdio.h> #include<pthread.h> #include<s ...

  4. 羽夏看Win系统内核—— VT 入门番外篇

    写在前面   此系列是本人一个字一个字码出来的,包括示例和实验截图.由于系统内核的复杂性,故可能有错误或者不全面的地方,如有错误,欢迎批评指正,本教程将会长期更新. 如有好的建议,欢迎反馈.码字不易, ...

  5. C++ 文件加解密

    通过文件二进制数据 与密钥进行异或处理,可加密文件 #ifndef __ENCRYPT__HEAD__ #define __ENCRYPT__HEAD__ #include <fstream&g ...

  6. SpringMVC源码解读 - RequestMapping注解实现解读

    SpringMVC源码解读 - RequestMapping注解实现解读 - RequestCondition体系  https://www.cnblogs.com/leftthen/p/520840 ...

  7. 关于web以及浏览器处理预加载有哪些思考?

    图片等静态资源在使用之前就提前请求资源使用到的时候能从缓存中加载, 提升用户体验页面展示的依赖关系维护

  8. Eclipse创建Spring XML配置文件插件

    引用:https://www.cnblogs.com/lideqiang/p/9067219.html 第一步:在 Eclipse Marketplace仓库中,搜索sts 第二步:安装Spring ...

  9. 学习 MongoDB(一)

    1.介绍 MongoDB是C++语言编写,是一个基于分布式文件存储的开源数据库系统,MongoDB将数据存储为一个文档, 数据结构由键值对(key=>value)组成,MongoDB文档类似于 ...

  10. java集合类框架的基本接口有哪些

    集合类接口指定了一组叫做元素的对象.集合类接口的每一种具体的实现类都可以以他自己的方式对元素进行保存和排序.有的集合允许重复的键,有些不允许. java集合类里面最基本 的接口: Collection ...