找回密码
 立即注册
首页 业界区 业界 彩笔运维勇闯机器学习--cpu与qps的线性关系 ...

彩笔运维勇闯机器学习--cpu与qps的线性关系

葛雅隽 2025-9-28 16:36:57
前言

书接上文,上一小节简单介绍了一元回归的基本原理、使用方式,作为运维,实践才是最重要的,那本小节就来实践一下我们之前的话题:探索cpu与qps的关系
获取数据

1. cpu数据

由于我的监控数据在阿里云的prometheus上面,并且阿里云也提供了一种查询方式,通过本地搭建的prometheus的remote_read功能,读取远端阿里云的数据

  • 搭建本地的prometheus

    • 准备配置文件
      1. ▶ cat ~/workspace/prometheus/docker/prometheus.yml
      2. # my global config
      3. global:
      4.    scrape_interval: 15s # Set the scrape interval to every 15 seconds. Default is every 1 minute.
      5.    evaluation_interval: 15s # Evaluate rules every 15 seconds. The default is every 1 minute.
      6.    # scrape_timeout is set to the global default (10s).
      7. # Alertmanager configuration
      8. alerting:
      9.    alertmanagers:
      10.      - static_configs:
      11.          - targets:
      12.            # - alertmanager:9093
      13. # Load rules once and periodically evaluate them according to the global 'evaluation_interval'.
      14. rule_files:
      15.    # - "first_rules.yml"
      16.    # - "second_rules.yml"
      17. # A scrape configuration containing exactly one endpoint to scrape:
      18. # Here it's Prometheus itself.
      19. scrape_configs:
      20.    # The job name is added as a label `job=<job_name>` to any timeseries scraped from this config.
      21.    - job_name: "prometheus"
      22.      # metrics_path defaults to '/metrics'
      23.      # scheme defaults to 'http'.
      24.      static_configs:
      25.        - targets: ["localhost:9090"]
      26. remote_read:
      27.    - url: "https://cn-beijing.arms.aliyuncs.com:9443/api/v1/prometheus/***/***/***/cn-beijing/api/v1/read"
      28.      read_recent: true
      复制代码
      remote_read 可以参考 阿里云prometheus文档
    • docker启动
      1. docker run --name=prometheus -d \
      2.     -v ./prometheus.yml:/etc/prometheus/prometheus.yml \
      3.     -p 9090:9090 \
      4.     -v /usr/share/zoneinfo/Asia/Shanghai:/etc/localtime \
      5.     prom/prometheus
      复制代码

  • 搭建好之后通过prometheus接口来获取数据
    1. def get_container_cpu_usage_seconds_total(start_time, end_time, step):
    2.     url = "http://localhost:9090/api/v1/query_range"
    3.     query = f'sum(rate(container_cpu_usage_seconds_total{{image!="",pod_name=~"^helloworld-[a-z0-9].+-[a-z0-9].+",namespace="default"}}[{step}s]))'
    4.     params = {
    5.         "query": query,
    6.         "start": start_time,
    7.         "end": end_time,
    8.         "step": step
    9.     }
    10.     response = requests.get(url, params=params)
    11.     data = response.json()
    12.     return data
    复制代码
    我们获取了helloworld这组pod在某个时间段所使用的cpu之和
2. qps数据

由于我的日志是托管在阿里云的sls,这里依然使用阿里云sls接口,直接把数据拉下来
阿里云sls文档
训练模型

由于sls日志与prometheus涉及到一些敏感内容,我这里直接调用方法,就不展示具体代码了,prometheus的代码可以参考上述,sls日志的代码可以直接去阿里云文档里面模拟接口copy
  1. from flow import get_cpu_data, get_query_data
  2. from datetime import datetime
  3. import pandas as pd
  4. start_time = datetime.strptime('2025-03-21 00:00:00', '%Y-%m-%d %H:%M:%S').timestamp()
  5. end_time = datetime.strptime('2025-03-21 23:59:59', '%Y-%m-%d %H:%M:%S').timestamp()
  6. step = 60
  7. sls_step = 3600
  8. query = get_query_data(start_time, end_time, sls_step)
  9. cpu = get_cpu_data(start_time, end_time, step)
  10. print('cpu: ', len(cpu), cpu)
  11. print('query: ', len(query), query)
复制代码
运行看一下
1.png

每分钟获取一次数据,cpu与qps的数据分别打印出来,1440个(只显示了前10个,看下数据长什么样子就行了),这里一定要注意数量对齐
开始训练
  1. from sklearn.linear_model import LinearRegression
  2. from sklearn.model_selection import train_test_split
  3. from sklearn.metrics import mean_squared_error, r2_score
  4. from flow import get_cpu_data, get_query_data
  5. from datetime import datetime
  6. import pandas as pd
  7. start_time = datetime.strptime('2025-03-23 00:00:00', '%Y-%m-%d %H:%M:%S').timestamp()
  8. end_time = datetime.strptime('2025-03-25 23:59:59', '%Y-%m-%d %H:%M:%S').timestamp()
  9. step = 60
  10. sls_step = 3600
  11. query = get_query_data(start_time, end_time, sls_step)
  12. cpu = get_cpu_data(start_time, end_time, step)
  13. print('cpu 数据个数为{} ,前10数据为{}'.format(len(cpu), cpu[:10]))
  14. print('query 数据个数为{} ,前10数据为{}'.format(len(query), query[:10]))
  15. # 准备数据
  16. data = {
  17.     'cpu': cpu,
  18.     'query': query
  19. }
  20. df = pd.DataFrame(data)
  21. X = df[['query']]
  22. y = df['cpu']
  23. # 划分训练集和测试集
  24. X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=88)
  25. # 创建模型并训练
  26. model = LinearRegression()
  27. model.fit(X_train, y_train)
  28. # 模型评估
  29. y_pred = model.predict(X_test)
  30. mse = mean_squared_error(y_test, y_pred)
  31. r2 = r2_score(y_test, y_pred)
  32. print(f"MSE: {mse}, R²: {r2}")
复制代码
脚本!启动
2.png

训练是训练出来的,但是模型好烂啊!

  • 我们获取的数据为3天的,3.23 -- 3.25
  • MSE高达0.04,我们之前说过,MSE有平方的计算,那实际误差是0.2,基本是20%--30%的水平了
  • R²才0.48,该模型只能解释48%的数据
我训练了个寂寞啊,这模型太烂,必须要修正一下
修正模型

修正模型从检查数据开始,看下数据是否有异常。画图是最直观的检查方式,那就找一个开源的库来画图,用matplotlib来完成,安装也非常简单,pip3 install matplotlib
先拿一天的数据来看看,3.23
  1. import matplotlib.pyplot as plt
  2. from datetime import datetime
  3. from flow import get_cpu_data
  4. step = 60
  5. sls_step = 3600
  6. l = [
  7.     {
  8.         'name': '3-23',
  9.         'start_time': datetime.strptime('2025-03-23 00:00:00', '%Y-%m-%d %H:%M:%S').timestamp(),
  10.         'end_time': datetime.strptime('2025-03-23 23:59:59', '%Y-%m-%d %H:%M:%S').timestamp()
  11.     },
  12. ]
  13. # 画多条线
  14. for piece in l:
  15.     cpu = get_cpu_data(piece['start_time'], piece['end_time'], step)
  16.     plt.plot(cpu, marker='o', linestyle='-', label=piece['name'])
  17. # 图例
  18. plt.legend()
  19. # 显示
  20. plt.show()
复制代码
脚本!启动
3.png

看起来数据很多,并且杂乱,并且cpu数据有个特性,会有激凸的特点,这对于数据收敛是不利的,所以,尝试把间隔时间调长一点,5分钟
  1. step = 600
复制代码
脚本!启动
4.png

看起来数据少了很多,并且离群激凸点没有了,尝试带入到训练脚本去试一试
  1. from sklearn.linear_model import LinearRegression
  2. from sklearn.model_selection import train_test_split
  3. from sklearn.metrics import mean_squared_error, r2_score
  4. from flow import get_cpu_data, get_query_data
  5. from datetime import datetime
  6. import pandas as pd
  7. start_time = datetime.strptime('2025-03-23 00:00:00', '%Y-%m-%d %H:%M:%S').timestamp()
  8. end_time = datetime.strptime('2025-03-25 23:59:59', '%Y-%m-%d %H:%M:%S').timestamp()
  9. step = 600
  10. sls_step = 3600*6
  11. query = get_query_data(start_time, end_time, sls_step)
  12. cpu = get_cpu_data(start_time, end_time, step)
  13. print('cpu 数据个数为{} ,前10数据为{}'.format(len(cpu), cpu[:10]))
  14. print('query 数据个数为{} ,前10数据为{}'.format(len(query), query[:10]))
  15. # 准备数据
  16. data = {
  17.     'cpu': cpu,
  18.     'query': query
  19. }
  20. df = pd.DataFrame(data)
  21. X = df[['query']]
  22. y = df['cpu']
  23. # 划分训练集和测试集
  24. X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=88)
  25. # 创建模型并训练
  26. model = LinearRegression()
  27. model.fit(X_train, y_train)
  28. # 模型评估
  29. y_pred = model.predict(X_test)
  30. mse = mean_squared_error(y_test, y_pred)
  31. r2 = r2_score(y_test, y_pred)
  32. print(f"MSE: {mse}, R²: {r2}")
复制代码
脚本!启动
5.png

哇哦,模型提升了

  • MSE来到了0.004,误差为0.063左右,大约在5%--10%之间
  • R²来到了0.89,解释了将近90%的数据,模型性能极大提升
为了再次提升性能,提高模型的泛化能力,需要继续内卷,卷起来!
再次分析数据,由于有3天的数据,尝试将3天的数据对比作图,看看有什么收获
  1. import matplotlib.pyplot as plt
  2. from datetime import datetime
  3. from flow import get_cpu_data
  4. step = 600
  5. l = [
  6.     {
  7.         'name': '3-23',
  8.         'start_time': datetime.strptime('2025-03-23 00:00:00', '%Y-%m-%d %H:%M:%S').timestamp(),
  9.         'end_time': datetime.strptime('2025-03-23 23:59:59', '%Y-%m-%d %H:%M:%S').timestamp()
  10.     },
  11.     {
  12.         'name': '3-24',
  13.         'start_time': datetime.strptime('2025-03-24 00:00:00', '%Y-%m-%d %H:%M:%S').timestamp(),
  14.         'end_time': datetime.strptime('2025-03-24 23:59:59', '%Y-%m-%d %H:%M:%S').timestamp()
  15.     },
  16.     {
  17.         'name': '3-25',
  18.         'start_time': datetime.strptime('2025-03-25 00:00:00', '%Y-%m-%d %H:%M:%S').timestamp(),
  19.         'end_time': datetime.strptime('2025-03-25 23:59:59', '%Y-%m-%d %H:%M:%S').timestamp()
  20.     }
  21. ]
  22. # 画多条线
  23. for piece in l:
  24.     cpu = get_cpu_data(piece['start_time'], piece['end_time'], step)
  25.     plt.plot(cpu, marker='o', linestyle='-', label=piece['name'])
  26. # 图例
  27. plt.legend()
  28. # 显示
  29. plt.show()
复制代码
脚本!启动
6.png

找到你了!25号的数据,你是怎么回事,怎么突然间高潮了。我去找业务的同事询问,原来那一天系统发红包,大量用户在那个时刻都去领红包去了,造成了cpu异常
哦~原来如此,那一天属于异常数据,有两种方法,第一种就是用异常检测算法将异常点全部踢掉,由于我还不会异常检测算法(比如什么均方差、箱型图、孤立森林之类的);所以我使用了第二种方法,放弃3.25的数据, =_=!
  1. from sklearn.linear_model import LinearRegression
  2. from sklearn.model_selection import train_test_split
  3. from sklearn.metrics import mean_squared_error, r2_score
  4. from flow import get_cpu_data, get_query_data
  5. from datetime import datetime
  6. import pandas as pd
  7. start_time = datetime.strptime('2025-03-23 00:00:00', '%Y-%m-%d %H:%M:%S').timestamp()
  8. end_time = datetime.strptime('2025-03-24 23:59:59', '%Y-%m-%d %H:%M:%S').timestamp()
  9. step = 600
  10. sls_step = 3600*6
  11. query = get_query_data(start_time, end_time, sls_step)
  12. cpu = get_cpu_data(start_time, end_time, step)
  13. print('cpu 数据个数为{} ,前10数据为{}'.format(len(cpu), cpu[:10]))
  14. print('query 数据个数为{} ,前10数据为{}'.format(len(query), query[:10]))
  15. # 准备数据
  16. data = {
  17.     'cpu': cpu,
  18.     'query': query
  19. }
  20. df = pd.DataFrame(data)
  21. X = df[['query']]
  22. y = df['cpu']
  23. # 划分训练集和测试集
  24. X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=88)
  25. # 创建模型并训练
  26. model = LinearRegression()
  27. model.fit(X_train, y_train)
  28. # 模型评估
  29. y_pred = model.predict(X_test)
  30. mse = mean_squared_error(y_test, y_pred)
  31. r2 = r2_score(y_test, y_pred)
  32. print(f"MSE: {mse}, R²: {r2}")
复制代码
7.png

真是一场酣畅淋漓的战斗

  • MSE来到了0.001,误差是0.03,大约在5%以内
  • R²来到了0.976,差不多98%的数据都能够被解释了
这个模型已经很优秀了,来预测一把
  1. # 预测
  2. predicted_query = [10000, 50000]
  3. new_data = pd.DataFrame({
  4.     "query": [x*300 for x in predicted_query]
  5. })
  6. predicted_qps = model.predict(new_data)
  7. print("预测的 qps:", predicted_query)
  8. print("预测的 cpu:", predicted_qps)
复制代码
这里要注意,query是5分钟内访问的总和,所以如果qps是1w,需要qps*300,才是5分钟的query
脚本!启动
8.png

装杯时刻


  • 老板:我们的系统能够承受什么样的压力?
  • 牛马:我们系统日常qps在5w左右,峰值qps在20w左右,消耗的cpu分别为42和172,按照我们4c8g的云服务器,分别需要11台和44台,现在我们使用的服务器为100台,可以缩减服务器成本大约50%
  • 老板:牛批,节约下来的钱请你吃一顿麻辣烫
  • 牛马:谢谢老板栽培
联系我


  • 联系我,做深入的交流
9.bmp

至此,本文结束
在下才疏学浅,有撒汤漏水的,请各位不吝赐教...

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

相关推荐

6 小时前

举报

感谢分享
您需要登录后才可以回帖 登录 | 立即注册