刚开年,公司要扩大业务规模,准备接入新的渠道,预计系统处理的业务量要提升几倍,由此提出了性能优化需求。性能优化的技术,有很多,加缓存、分库分表,接入中间件,代码优化等等,但这些都是术,而性能优化之道,在于指标量化,要知道系统目前的状况,性能瓶颈在哪,才能做到有效的优化,性能优化同样遵循82原则,80%的性能瓶颈,在不到20%的模块中,由此,我开启了系统分析之路。
对于后端来讲,对外提供的主要是接口,接口最主要的评估数据,在于响应速度和并发量,我们的系统目前还没有遇到大规模并发的情况,所以主要分析响应速度,于是我在每个系统的服务器入口处,都加了代码用于统计接口时间,大致按controller, method, time的格式,单独写入日志记录下每次请求的响应时间,从业务低谷期到高峰期,收集了差不多一整天的数据。日志格式大概如下:
xxController xxMethod 0.052
xxController xxMethod 1.23
有了每个接口的响应时间,需要对响应数据进行统计,我大概整理了这么几个指标,按接口分类,统计最小请求时间,最大请求时间,请求总数,平均请求时间。请求总数用于分析系统频繁请求的api是哪些,平均请求时间用于反映哪些接口比较慢,影响用户体验,最小最大时间则用于分析接口是否有波动,结合平均时间,看是偶尔慢还是一直都慢
有了上述指标,也有了日志,要做统计就很方便了,甚至都不用自己写代码,我把需求描述给chatgpt,自动生成了下列python代码
import os
from collections import defaultdict
from openpyxl import Workbook
# 日志文件路径
log_file_path = "request_time.log"
# 定义一个存储所有数据的字典,接口名为键,值为每个接口的统计数据
stats = defaultdict(lambda: {"min_time": float("inf"), # 最小请求时间
"max_time": float("-inf"), # 最大请求时间
"total_time": 0, # 总请求时间
"count": 0}) # 请求次数
# 读取文件并统计
if os.path.exists(log_file_path):
with open(log_file_path, "r") as f:
for line in f:
# 去除首尾空白符
line = line.strip()
if not line:
continue # 跳过空行
# 假设日志格式为:<类名> <接口函数名> <请求时间>
parts = line.split() # 使用空格分割
if len(parts) != 3: # 如果一行不是三个部分,跳过
continue
class_name, api_name, request_time_str = parts
try:
# 转换请求时间为浮点数
request_time = float(request_time_str)
except ValueError:
# 如果请求时间无法转换为浮点数,跳过该行
continue
# 生成唯一的接口标识,如 "类名.接口名"
api_identifier = f"{class_name}.{api_name}"
# 更新统计信息
stats[api_identifier]["min_time"] = min(stats[api_identifier]["min_time"], request_time)
stats[api_identifier]["max_time"] = max(stats[api_identifier]["max_time"], request_time)
stats[api_identifier]["total_time"] += request_time
stats[api_identifier]["count"] += 1
else:
print(f"日志文件 {log_file_path} 不存在!")
exit(1)
sorted_data = []
for api_identifier, data in stats.items():
count = data["count"]
if count > 0:
avg_time = data["total_time"] / count # 计算平均时间
else:
avg_time = 0
sorted_data.append({
"api": api_identifier,
"min_time": data["min_time"],
"max_time": data["max_time"],
"count": count,
"avg_time": avg_time
})
# 提供排序选项:按平均时间排序或按次数排序
sort_by = "count" # 可选:"avg_time" 或 "count"
reverse_order = True # True 表示从大到小排序,False 表示从小到大排序
if sort_by == "avg_time":
sorted_data = sorted(sorted_data, key=lambda x: x["avg_time"], reverse=reverse_order)
elif sort_by == "count":
sorted_data = sorted(sorted_data, key=lambda x: x["count"], reverse=reverse_order)
# 输出排序结果
wb = Workbook()
ws = wb.active
ws.append(['接口', '最短时间', '最长时间', '次数', '平均时间'])
for data in sorted_data:
ws.append([data['api'], data['min_time'], data['max_time'], data['count'], f"{data['avg_time']:.3f}"])
wb.save('request_time.xlsx')
因为包含多个服务,我则把多个服务的日志分别处理,最后汇总excel就搞定了。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。