代码功能:
以多线程的方式一边读取容器占用cpu和内存资源,一边将获得的数据写入数据库
完整代码如下:
"""
******************************************************************************************
* 多线程写入数据库-最终版
*-----------------------------------------------------------------------------------------
* 注意:pymysql多线程读写数据库报错:Packet sequence number wrong
* 解决方法: 每个execute前加上互斥锁
* lock.acquire()
* cursor.execute(command,data)
* lock.release()
*
******************************************************************************************
"""
import pymysql.cursors
import threading
import time
import docker
# -------------------------- 初始化 -------------------------------
print('程序初始化...')
print('建立数据库连接...')
# 创建数据库连接
cnx = pymysql.connect(host='localhost', port=3306, user='root', password='123456', db='qt', charset='utf8mb4',connect_timeout=20)
cursor = cnx.cursor()
# 定义容器名列表
container_names = ['a','b','c','d','e','f','g']
# 创建锁
lock = threading.Lock()
# -------------------------- docker stats读取 -------------------------------
def get_container_stats(container_name):
client = docker.from_env() # 假设你已经初始化了 Docker 客户端
container = client.containers.get(container_name)
stats = container.stats(stream=False)
cpu_usage = 100 * stats['cpu_stats']['cpu_usage']['total_usage'] / stats['cpu_stats']['system_cpu_usage']
memory_used = 100 * stats['memory_stats']['usage'] / stats['memory_stats']['limit']
return cpu_usage, memory_used
# -------------------------- 数据库写入 -------------------------------
def mysql_data_update(container_name, cursor, cnx):
cpu_usage, memory_used = get_container_stats(container_name)
# 将容器状态写入数据库
# 执行更新数据的 SQL 语句
lock.acquire()
cursor.execute("UPDATE container_stats SET cpu_usage = %s, memory_used = %s WHERE container_name = %s", [cpu_usage, memory_used, container_name])
# 提交事务
cnx.commit()
lock.release()
print('容器:{} 成功写入数据库'.format(container_name))
# -------------------------- 多线程 ------------------------------------
def refresh_stats(container_names, interval=1):
while True:
start_time = time.time()
# 创建线程列表
threads = []
# 多线程1:读取容器cpu,mem
for container_name in container_names:
# 创建并启动线程
thread = threading.Thread(target=mysql_data_update, args=(container_name, cursor, cnx))
thread.start()
threads.append(thread)
# 等待所有线程结束
for thread in threads:
thread.join()
end_time = time.time()
total_time = end_time - start_time
print("总时间: {:.2f} 秒".format(total_time))
print("---------------------------------------------------------------------------------------------\n")
time.sleep(interval)
# 调用函数进行实时刷新
refresh_stats(container_names)
代码解释
-
引入所需的模块:
pymysql.cursors
用于数据库连接和操作,threading
用于多线程操作,time
用于时间相关的操作,docker
用于与 Docker 进行交互。 -
get_container_stats
函数:该函数通过 Docker 客户端获取指定容器的 CPU 和内存使用情况。 -
mysql_data_update
函数:该函数用于将容器的 CPU 和内存使用情况写入数据库。它首先调用get_container_stats
函数获取容器的使用情况,然后执行 SQL 语句将数据更新到数据库中。 -
refresh_stats
函数:该函数是多线程的核心部分。它使用一个无限循环来定期刷新容器的状态。在每次循环中,它创建多个线程来处理不同的容器,并调用mysql_data_update
函数将容器的使用情况写入数据库。每个线程负责一个容器的处理。线程创建后,它们被添加到线程列表中,并在循环结束时等待所有线程执行完毕。之后,程序会休眠一段时间(由interval
参数指定),然后再次开始新的循环。
注意:
for container_name in container_names
是一个循环语句,它用于遍历一个名为container_names
的列表(或可迭代对象)中的每个元素,并将每个元素赋值给变量container_name
。在这段代码中,
container_names
是一个包含容器名字的列表。通过使用循环语句,程序可以逐个遍历container_names
列表中的容器名字,并将每个容器名字赋值给变量container_name
。在循环的每次迭代中,程序可以对每个容器执行相应的操作或处理。换句话说,这个循环用于迭代处理
container_names
列表中的容器名字,以便在后续代码中使用这些容器名字执行相应的操作。
同时,代码中使用了互斥锁(
lock
)来确保在执行cursor.execute
语句时的线程安全性,以避免出现报错:"Packet sequence number wrong"。在执行cursor.execute
之前获取锁(lock.acquire()
),在执行完毕后释放锁(lock.release()
)。