Python 协程检测Kubernetes服务端口
一、需求分析
在上一篇文章,链接如下:
https://www.cnblogs.com/xiao987334176/p/10237551.html
已经得到了需要的数据,现在需要对这些端口做检测,判断端口是否正常!
实际情况是,有上百个端口需要检测。如果一个个检测,可能需要花费几分钟的时间,效率不够快!
那么首先想到的就是多进程,但是一个进程会消耗一个CPU。
在不影响性能的情况下,最快的办法,就是使用协程。它是异步的,遇到io会自动切换!
二、协程
介绍
协程是一种用户态的轻量级线程,协程的调度完全由用户控制。协程拥有自己的寄存器上下文和栈。协程调度切换时,将寄存器上下文和栈保存到其他地方,在切回来的时候,恢复先前保存的寄存器上下文和栈,直接操作栈则基本没有内核切换的开销,可以不加锁的访问全局变量,所以上下文的切换非常快。
关于 进程、线程和协程的理解,请参考链接:
https://www.cnblogs.com/guolei2570/p/8810536.html
这篇文章,有大量的图片解释,通俗易懂!
安装
使用协程,需要安装模块
pip3 install gevent
什么是猴子补丁(monkey patch)
monkey patch指的是在执行时动态替换,通常是在startup的时候.
用过gevent就会知道,会在最开头的地方gevent.monkey.patch_all();把标准库中的thread/socket等给替换掉.这样我们在后面使用socket的时候能够跟寻常一样使用,无需改动不论什么代码,可是它变成非堵塞的了.
使用
导入模块时,必须要导入猴子补丁
from gevent import monkey; monkey.patch_all()
import gevent
示例
from gevent import monkey;monkey.patch_all() # 它会把下面导入的所有的模块中的IO操作都打成一个包,gevent就能够认识这些IO了 import time import gevent def eat(): print('eating1') time.sleep(1) # 延时调用 print(time.time(),'eating2') def play(): print('playing1') time.sleep(1) # 延时调用 print(time.time(),'playing2') g1 = gevent.spawn(eat) # 创建一个协程对象g1 g2 = gevent.spawn(play) g1.join() # 等待g1结束 g2.join()
执行输出:
eating1 playing1 1546917759.6040378 eating2 1546917759.6040378 playing2
看时间戳,可以发现,即使睡眠了1秒,2个函数几乎是同时运行的
三、正式代码
#!/usr/bin/env python # coding: utf-8 import os import json import time import socket from gevent import monkey;monkey.patch_all() import gevent # data = "" # with open('test.json') as f: # data = json.loads(f.read()) # api整理好的json数据 data = {"voucher-center-master": [ {"server_port": 8012, "ip": "192.169.167.105", "pod_name": "voucher-center-rc-p20kk", "nodeName": "job-node149", "beejob_port": 3011}, {"server_port": 8012, "ip": "192.169.183.26", "pod_name": "voucher-center-rc-vknkt", "nodeName": "job-node137", "beejob_port": 3011}, {"server_port": 8012, "ip": "192.169.242.29", "pod_name": "voucher-center-rc-0x482", "nodeName": "job-node145", "beejob_port": 3011}, {"server_port": 8012, "ip": "192.169.76.159", "pod_name": "voucher-center-rc-xtxfb", "nodeName": "job-node151", "beejob_port": 3011}, {"server_port": 8012, "ip": "192.169.98.159", "pod_name": "voucher-center-rc-n9wkl", "nodeName": "job-node147", "beejob_port": 3011}]} class CheckServer(object): # 检查服务端口 def __init__(self): self.process_list = [] # 进程列表 def check_tcp(self, ip, port, timeout=1): """ 检测tcp端口 :param ip: ip地址 :param port: 端口号 :param timeout: 超时时间 :return: bool """ flag = False try: socket.setdefaulttimeout(timeout) # 整个socket层设置超时时间 cs = socket.socket(socket.AF_INET, socket.SOCK_STREAM) address = (str(ip), int(port)) status = cs.connect_ex((address)) # 开始连接 cs.settimeout(timeout) if not status: flag = True return flag except Exception as e: print("error:%s" % e) return flag def write_log(self, content): """ 写入日志文件 :param content: 写入内容 :return: """ path = "output.log" # 日志文件 with open(path, mode='a+', encoding='utf-8') as f: content = time.strftime('%Y-%m-%d %H:%M:%S') + ' ' + content + "\n" print(content) f.write(content) def run(self, name, ip, port, category): """ 运行程序 :param name: 名称 :param ip: ip :param port: 端口 :param category: 类别 :return: """ self.write_log("name:{} {}_ip:{} 检查端口: {} 状态:{}".format(name, category, ip, port, self.check_tcp(ip, port))) def main(self): for i in data: # 遍历字典 # print("name",i) for j in data[i]: # 遍历节点数据 if j.get('server_port'): # 获取server_port if j.get('ip'): ip = j['ip'] port = j['server_port'] # 添加到进程列表中 self.process_list.append(gevent.spawn(self.run, i, ip, port, 'server')) if j.get('beejob_port'): # 获取beejob_port if j.get('ip'): ip = j['ip'] port = j['beejob_port'] # 添加到进程列表中 self.process_list.append(gevent.spawn(self.run, i, ip, port, 'beejob')) return self.process_list if __name__ == '__main__': startime = time.time() # 开始时间 process_list = CheckServer().main() gevent.joinall(process_list) # 使用协程执行所有协程 endtime = time.time() take_time = endtime - startime if take_time < 1: # 判断不足1秒时 take_time = 1 # 设置为1秒 # 计算花费时间 m, s = divmod(take_time, 60) h, m = divmod(m, 60) print("本次花费时间 %02d:%02d:%02d" % (h, m, s))
执行输出:
2019-01-08 11:27:54 name:voucher-center-master server_ip:192.169.167.105 检查端口: 8012 状态:False 2019-01-08 11:27:54 name:voucher-center-master beejob_ip:192.169.167.105 检查端口: 3011 状态:False 2019-01-08 11:27:54 name:voucher-center-master server_ip:192.169.183.26 检查端口: 8012 状态:False 2019-01-08 11:27:54 name:voucher-center-master beejob_ip:192.169.183.26 检查端口: 3011 状态:False 2019-01-08 11:27:54 name:voucher-center-master server_ip:192.169.242.29 检查端口: 8012 状态:False 2019-01-08 11:27:54 name:voucher-center-master beejob_ip:192.169.242.29 检查端口: 3011 状态:False 2019-01-08 11:27:54 name:voucher-center-master server_ip:192.169.76.159 检查端口: 8012 状态:False 2019-01-08 11:27:54 name:voucher-center-master beejob_ip:192.169.76.159 检查端口: 3011 状态:False 2019-01-08 11:27:54 name:voucher-center-master server_ip:192.169.98.159 检查端口: 8012 状态:False 2019-01-08 11:27:54 name:voucher-center-master beejob_ip:192.169.98.159 检查端口: 3011 状态:False 本次花费时间 00:00:01
可以发现,即使有那么多端口,1秒钟就完成了,使用协程非常的高效!