转载

一次Locust分布式压测实践

记录性能测试的相关知识与实践:测试指标,测试工具,性能调优点

一次Locust分布式压测实践

关于性能测试

性能测试是通过自动化的测试工具模拟多种 正常峰值 以及 异常 负载条件来对系统的各项性能指标进行测试。

负载测试和压力测试都属于性能测试,两者可以结合进行。

  • 通过 负载测试 ,确定在各种工作负载下系统的性能,目标是测试当 负载逐渐增加 时,系统各项性能指标的变化情况。
  • 压力测试 是通过确定一个系统的 瓶颈 或者不能接受的 性能点 ,来获得系统能提供的 最大服务级别 的测试。

测试指标

主要是从以下三个维度来衡量

  1. 响应时间:从用户角度
    • Average (ms):服务平均响应时长
    • Min (ms):服务最小响应时长
    • Max(ms):服务最大响应时长
  2. 服务器资源:从系统角度
    • 内存使用率:内存泄漏,内存溢出
    • CPU负载
    • 磁盘IO
    • 网络IO
  3. 吞吐量:从业务角度
    • Request:总请求数
    • RPS(并发数/平均响应时间):服务每秒处理请求数

测试准备工作

工欲善其事必先利其器

服务器监控工具

  • prometheus .node_exporter系统监控,或者 zabbix
  • grafana 可视化

监控指标

  • 可用内存
  • 可用磁盘
  • CPU负载
  • 网络流量

JVM监控工具

jps -lvm

查看java进程情况

Java VisualVM

在服务端启动j statd 后,在本地用jdk自带的 jvisualvm 连接:

  • 监控Heap使用情况
  • 监控线程情况

测试框架

一次Locust分布式压测实践
Locust

分布式性能测试框架

  • master:1个
  • slave:4个

Locust的关键配置

压测Web界面配置

  • Number of users to simulate:模拟的用户数,即压测的用户总数
  • Hatch rate:压测时,每秒并发/启动的用户数

TaskSet脚本配置

  • min_wait:模拟用户在执行任务之间等待的最小时间,单位是毫秒;
  • max_wait:模拟用户在执行任务之间等待的最大时间,单位是毫秒; 默认1000,即locust在执行每个任务之间总是会等待1秒

测试环境搭建

服务器准备

  • API服务器
  • 缓存服务器
  • 数据库服务器
  • Web服务器

服务部署

Jenkins编写服务部署脚本

测试数据准备

小样本数据采用Junit单元测试调用API接口生成, 大样本数据用locust脚本生成

  • 用户数据:100
  • 人员数据:10000
  • 设备数据:10000
  • 设备人员关系数据:100000000

参数化

  • 为尽量模拟压测的真实性,测试数据应从测试数据源中随机抽样生成;

    locust测试脚本中可采用python的random从list中抽样;

    或者用pandas的sample生成采样数据;

测试脚本

locust测试脚本示例

# coding:utf-8

import pandas as pd
import json
import random
import uuid

from locust import HttpLocust, TaskSet, task

class OpenPersonBackendApi(TaskSet):
    __PERSON_LIBS = None
    # @task(1)
    def person_query(self):
        """
        人员列表查询
        :return:
        """
        ysk_id, person_lib_id = self._get_person_lib()
        payload = {
            "ysk_id": ysk_id,
            "person_lib_id": person_lib_id,
            "limit": random.randint(10, 500)
        }
        headers = {'content-type': 'application/json'}
        r = self.client.post("/person_create", data=json.dumps(payload), headers=headers, verify=False)
        assert r.status_code == 200
        rData = json.loads(r.text, encoding="utf-8")
        if rData["success"]:
            print("person_lib_id {},time {},person_id:{}".format(person_lib_id, time, rData["data"]["person_id"]))
        else:
            print(rData)

    def _get_person_lib(self):
        if self.__PERSON_LIBS is None:
            self.__PERSON_LIBS = pd.read_csv("data/person_libs.txt").values.tolist()
        person_lib = random.choice(self.__PERSON_LIBS)
        ysk_id = person_lib[0]
        person_lib_id = person_lib[1]
        return ysk_id, person_lib_id

class OpenPersonLocust(HttpLocust):
    task_set = OpenPersonBackendApi
    host = "http://172.26.12.191:9881/backend/1.0"
    min_wait = 1000
    max_wait = 1000

if __name__ == "__main__":
    """
    master启动脚本:export node=master && python open_person_backend.py 
    slave启动脚本:export node=salve && python open_person_backend.py
    """
    import os

    # ps -ef|grep locust |grep -v grep|awk '{print $2}'|xargs kill
    node = os.environ.get("node", "slave")
    if node == "master":
        os.system("nohup locust -f open_person_backend.py --master -P 9090 >>master.log &")
    else:
        os.system("nohup locust -f open_person_backend.py --slave --master-host=172.26.12.128 >>slave.log &")
        os.system("nohup locust -f open_person_backend.py --slave --master-host=172.26.12.128 >>slave.log &")

复制代码
原文  https://juejin.im/post/5dff7a3df265da33942a8b4f
正文到此结束
Loading...