超详细的搭建压测平台笔记

0、前言

最近重新回来学习熊哥的极客教程,结合自己学习的shell编程和Docker的指令学习,对熊哥的一些操作做bash脚本自动化,将搭建压测平台的步骤做记录,目的是分享搭建过程。

过程中会安装docker,mysql,redis,influxdb,grafana,promethues,jmeter,node-exporter等内容。

中间用于压测应用的服务Jar包属于课程的内容,这里不便提供,请原谅。

可以将应用程序jar换成自己标准的spring boot项目。

1、前置条件

  • 首先需要在阿里云创建四台按量计费,4C8G,25Mbps的机器
  • 账户充值至少100RMB
  • 自己机器下载FinalShel软件类似的连接云端服务器的软件,以便进行连接阿里云服务器。

1.1 搭建结构

服务架构如下:
image.png
搭建的监控架构如下所示:
image.png

1.2 云主机选择

选择阿里云 ecs.c7a.xlarge 类型,选择这个类型的原因是相对便宜,而且熊哥当初展示是也是使用这个规格类型,避免发生问题。
image.png
版本选择 CentOs 7.6 64位,硬盘选择默认即可。
image.png
选择分配公网地址,且流量为25Mbpsimage.png

定义自己的实例名称和主机名称。 image.png

目前定义四台机器,实例名称如下列表所示:

实例名主机名密码
hero01-ci-nginx-JMeterhero01A9405kk@01
hero02-mysql-redishero02A9405kk@02
hero03-applicationhero03A9405kk@03
hero04-grafana-influxDB-Prometheushero04A9405kk@04

实例创建完后如下所示:

image.png
为了节省资源消耗,首先先搭建hero02,先把基础中间件搭建完毕。

1.2 搭建环境步骤

1.2.1 搭建hero02-mysql-redis

这里安装Mysql和Redis,采用Docker安装的方式。

1.2.1.1 公网绑定

由于是数据库连接,建议采取弹性公网绑定的方式,以便外部访问。
image.png

image.png

image.png

接下来打开Final-Shell,进行后续操作。
image.png
image.png
image.png

1.2.1.1 安装Docker

创建一个脚本,install-docker.sh,内容如下所示:

#!/bin/bash

# 该脚本用于在CentOS 7.6上自动安装Docker并设置为开机自启

# 更新YUM包索引
sudo yum check-update

# 卸载旧版本的Docker(如果安装了)
sudo yum remove docker \
                docker-client \
                docker-client-latest \
                docker-common \
                docker-latest \
                docker-latest-logrotate \
                docker-logrotate \
                docker-engine

# 安装必要的YUM依赖项
sudo yum install -y yum-utils

# 设置Docker的稳定版仓库
sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo

# 安装Docker Engine(社区版)
sudo yum install -y docker-ce docker-ce-cli containerd.io

# 启动Docker服务
sudo systemctl start docker

# 将当前用户加入docker组,避免每次调用docker命令都需要sudo(需要重新登录以生效)
sudo usermod -aG docker $(whoami)

# 设置Docker服务开机自启
sudo systemctl enable docker

sudo yum install -y docker-compose

# 验证Docker是否安装成功
sudo docker run hello-world

# 脚本结束
echo "Docker has been installed and set to start on boot."

然后执行下面命令:

[root@hero02 ~]# vim install-docker.sh
[root@hero02 ~]# bash install-docker.sh 

image.png

1.2.1.2 安装Mysql+Redis+Adminer

建议参考博客:
Mysql: 【Docker-Dev】Mac M2 搭建docker mysql-CSDN博客
Redis: 【Docker-Dev】Mac M2 搭建docker的redis环境-CSDN博客

执行下面脚本,这个会设置docker启动后,会自动启动这两个中间件,而且脚本会帮忙创建对应的一些文件和目录。

创建一个脚本,名称为 install-mysql-redis-adminer.sh,内容如下所示:

#!/bin/bash

# 创建MySQL和Redis的数据存储与日志文件夹和配置文件,并启动服务

# 定义MySQL和Redis的数据和日志目录路径
MYSQL_DATA_DIR="./mysql/data"
MYSQL_CONF_DIR="./mysql/conf"
MYSQL_LOG_DIR="./mysql/logs"
REDIS_DATA_DIR="./redis/data"
REDIS_CONF_DIR="./redis/conf"

# 为MySQL和Redis创建数据和日志目录以及配置文件
mkdir -p "${MYSQL_DATA_DIR}" "${MYSQL_CONF_DIR}" "${MYSQL_LOG_DIR}"
mkdir -p "${REDIS_DATA_DIR}" "${REDIS_CONF_DIR}"


# 创建MySQL配置文件
cat > "${MYSQL_CONF_DIR}/my.cnf" << EOF
[mysqld]
user = mysql
pid-file = /var/run/mysqld/mysqld.pid
datadir = /var/lib/mysql
socket = /var/run/mysqld/mysqld.sock
log-error = /var/log/mysql/mysql_error.log
character-set-server = utf8mb4
collation-server = utf8mb4_unicode_ci
EOF

# 创建Redis配置文件
cat > "${REDIS_CONF_DIR}/redis.conf" << EOF
bind 0.0.0.0
protected-mode no
port 6379
timeout 0
tcp-keepalive 300
daemonize no
pidfile /var/run/redis_6379.pid
loglevel notice
logfile /data/redis.log
databases 16
always-show-logo no
save 900 1
save 300 10
save 60 10000
stop-writes-on-bgsave-error yes
rdbcompression yes
rdbchecksum yes
dbfilename dump.rdb
dir /data
slave-serve-stale-data yes
slave-read-only yes
repl-diskless-sync no
repl-diskless-sync-delay 5
repl-disable-tcp-nodelay no
slave-priority 100
requirepass rootpassword
appendonly no
EOF

# 创建docker-compose.yml文件
cat > docker-compose.yml << EOF
version: '3.1'

services:
  mysql:
    image: mysql:5.7
    container_name: mysql
    restart: always
    environment:
      MYSQL_DATABASE: 'db'
      MYSQL_USER: 'user'
      MYSQL_PASSWORD: 'password'
      MYSQL_ROOT_PASSWORD: 'root'
    volumes:
      - ${MYSQL_DATA_DIR}:/var/lib/mysql
      - ${MYSQL_CONF_DIR}:/etc/mysql/conf.d
      - ${MYSQL_LOG_DIR}:/var/log/mysql
    ports:
      - "3306:3306"

  redis:
    image: redis:5.0
    container_name: redis
    restart: always
    command: redis-server /usr/local/etc/redis/redis.conf
    volumes:
      - ${REDIS_DATA_DIR}:/data
      - ${REDIS_CONF_DIR}:/usr/local/etc/redis
    ports:
      - "6379:6379"

  adminer:
    image: adminer
    container_name: adminer
    restart: always
    ports:
      - "8901:8080"
    environment:
      ADMINER_DEFAULT_SERVER: mysql
    depends_on:
      - mysql
EOF

# 启动服务
docker-compose up -d

# 输出成功消息
echo "MySQL, Redis, and Adminer services have been started."

image.png
执行完毕后,可以看见服务启动成功。
image.png
为了确保服务重启后,能重新启动,需要重启云服务实例,然后查看是否OK。
目前测试过重启是OK的。

1.2.1.3 设置安全组

为了能够外部访问端口,需要设置安全组策略。
新建安全组并创建者几个规则
image.png
image.png

image.png

接下来,让实例绑定刚刚创建的安全组。
image.png

1.2.1.4 验证是否完成

接下来输入如下地址,下面ip地址,是这台服务器的弹性公网ip地址。

http://<yourIpAddress>:8901

image.png
可以发现是可以打开成功的。
接下来进行登录。
image.png
操作也是正常的。
然后打开redis客户端进行访问。
image.png

ip地址敏感,进行了模糊化

image.png

直到现在为止,redis和mysql已经搭建完成。

1.2.1.5 安装node_exporter

这里我不是采用熊哥的逐步脚本操作,采用docker 文件运行。
创建目录文件 node-export,然后在这个目录下,创建docker-compose.yaml文件,内容如下所示:

这里尤其注意, hostname,和当前你机器的hostname或者你实例的名称一致,否则在后续搭建grafana+promethues面板看见的只是容器的id。看不出是啥。

version: '3.1'

services:
  node-exporter:
    image: prom/node-exporter:latest
    hostname: hero02-mysql-redis
    ports:
      - '9100:9100'
    volumes:
      - '/proc:/host/proc:ro'
      - '/sys:/host/sys:ro'
      - '/:/rootfs:ro'
    command:
      - '--path.procfs=/host/proc'
      - '--path.sysfs=/host/sys'
      - '--collector.filesystem.ignored-mount-points'
      - '^/(sys|proc|dev|host|etc)($$|/)'
    restart: always

然后开放安全组9100端口。
image.png
然后访问

http://<yourIpAddress>:9100/metrics

image.png
然后服务重启后,发现重启后,服务都可以重新恢复。
在这里插入图片描述

1.2.1.6 数据导入

为了验证后续1.2.2的应用程序运行后,可以验证性能效果。这里需要导入sql的初始化脚本。
这里决定采用Adminer进行导入,这里数据库导入的方式因人而已,可以采用自己本身机器连接去导入,我这里只是图省事,后续我还把这个hero_all删掉,再试了一遍sql文件的导入,完全是ok的。只是验证过程。
image.png
首先需要先创建一个数据库,这里命名为hero_all
image.png
否则脚本中存在乱码而导致导入异常。
接下来用导入的方式进行导入。
image.png
导入可能需要较长时间,需要等待一段时间。

1.2.2 搭建hero03-application

因为保密性,应用的jar包不会提供,可以部署自己应用的jar包去进行后续操作。

1.2.2.1 创建JDK环境

用FinalShell登录对应的hero03-application服务器,然后上传jar包到对应目录文件中。

编写下面脚本,以便执行JDK安装,下面脚本可以在任意处执行,会计算上传的jdk文件路径,如果确定自己在哪个路径了,可以修改find命令,改成自己的上传jar包路径地址。

下面的脚本的jdk-8u261-linux-x64.tar.gz,事实上是提前下好了的。Oracle并没有提供不进行用户鉴权后的下载url

#!/bin/bash

# JDK包名称
JDK_TAR_GZ_FILENAME='jdk-8u261-linux-x64.tar.gz'
# JDK版本信息
JDK_VERSION="1.8.0_261"
# 安装目录
JAVA_INSTALL_DIR='/usr/local/java'

# 在整个文件系统中搜索JDK包
echo "正在搜索JDK安装包 ${JDK_TAR_GZ_FILENAME} ..."
JDK_TAR_GZ_PATH=$(find / -type f -name "$JDK_TAR_GZ_FILENAME" 2>/dev/null | head -n 1)

# 如果JDK包不存在,则退出脚本
if [[ -z "$JDK_TAR_GZ_PATH" ]]; then
    echo "错误:未在系统中找到JDK安装包 ${JDK_TAR_GZ_FILENAME}."
    exit 1
fi
echo "找到JDK安装包:${JDK_TAR_GZ_PATH}"

# 检查是否已安装了JDK
if type -p java; then
    JAVA_VERSION=$(java -version 2>&1 | awk -F '"' '/version/ {print $2}')
    if [[ "$JAVA_VERSION" == "$JDK_VERSION" ]]; then
        echo "JDK $JDK_VERSION 已安装."
        exit 0
    else
        echo "发现其他版本的JDK:$JAVA_VERSION"
        exit 1
    fi
else
    echo "未发现JDK安装,继续..."
fi

# 检查Java安装目录是否存在,若不存在则创建
if [[ ! -d "$JAVA_INSTALL_DIR" ]]; then
    echo "创建安装目录..."
    sudo mkdir -p $JAVA_INSTALL_DIR
fi

# 解压JDK包到安装目录
echo "解压JDK到 ${JAVA_INSTALL_DIR}..."
sudo tar -xzf "$JDK_TAR_GZ_PATH" -C "$JAVA_INSTALL_DIR"

# 设置环境变量
JAVA_HOME_DIR=$(tar -tzf "$JDK_TAR_GZ_PATH" | grep "/$" | head -n 1 | tr -d '/')
echo "JAVA_HOME_DIR: ${JAVA_HOME_DIR}"
# 写入环境变量到/etc/profile
echo "设置环境变量..."
echo "export JAVA_HOME=${JAVA_INSTALL_DIR}/${JAVA_HOME_DIR}" | sudo tee -a /etc/profile
echo 'export PATH=$PATH:$JAVA_HOME/bin' | sudo tee -a /etc/profile

# 更新环境变量
source /etc/profile

# 验证安装
echo "验证安装..."
java -version
# 完成
echo "Oracle JDK 安装完成。"

执行完毕后,在command界面还是得输入 source /etc/profile,否则最终还是没生效,我认为可能是脚本的bash执行,terminal的状态并没有变更。
image.png

1.2.2.2 上传应用jar和执行脚本

返回上级目录,并创建子目录,hero_default,由于课程会有多次不同的hero,以及后续还需要测JVM的GC不同会有不同的。
然后在hero_default文件夹下,创建一个conf文件夹。
将熊哥的jar和两个启动脚本都上传上去。
原始的jar提供的start.sh的执行脚本如下所示:

#!/bin/sh
# Copyright 1999-2022 Geek NB Group Holding Ltd.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

export JAVA_HOME=/usr/local/hero/jdk1.8.0_261
export JRE_HOME=${JAVA_HOME}/jre
export CLASSPATH=.:${JAVA_HOME}/lib:${JRE_HOME}/lib
export PATH=${JAVA_HOME}/bin:$PATH

#===========================================================================================
# init
#===========================================================================================

export SERVER="hero_web"
export JAVA_HOME
export JAVA="$JAVA_HOME/bin/java"
# 获取当前目录
export BASE_DIR=`cd $(dirname $0)/.; pwd`
# 默认加载路径
export DEFAULT_SEARCH_LOCATIONS="classpath:/,classpath:/config/,file:./,file:./config/"
# 自定义默认加载配置文件路径
export CUSTOM_SEARCH_LOCATIONS=${DEFAULT_SEARCH_LOCATIONS},file:${BASE_DIR}/conf/


#===========================================================================================
# JVM Configuration
#===========================================================================================
JAVA_OPT="${JAVA_OPT} -server -Xms512m -Xmx512m -Xmn256 -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=320m"
JAVA_OPT="${JAVA_OPT} -XX:-OmitStackTraceInFastThrow -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=${BASE_DIR}/logs/java_heapdump.hprof"
JAVA_OPT="${JAVA_OPT} -XX:-UseLargePages"
JAVA_OPT="${JAVA_OPT} -jar ${BASE_DIR}/${SERVER}-*.jar"
JAVA_OPT="${JAVA_OPT} ${JAVA_OPT_EXT}"
JAVA_OPT="${JAVA_OPT} --spring.config.location=${CUSTOM_SEARCH_LOCATIONS}"
# 创建日志文件目录
if [ ! -d "${BASE_DIR}/logs" ]; then
  mkdir ${BASE_DIR}/logs
fi

# 输出变量
echo "$JAVA ${JAVA_OPT}"
# 检查start.out日志输出文件
if [ ! -f "${BASE_DIR}/logs/${SERVER}.out" ]; then
  touch "${BASE_DIR}/logs/${SERVER}.out"
fi
#===========================================================================================
# 启动服务
#===========================================================================================
# 启动服务
echo "$JAVA ${JAVA_OPT}" > ${BASE_DIR}/logs/${SERVER}.out 2>&1 &
nohup $JAVA ${JAVA_OPT} hero_web.hero_web >> ${BASE_DIR}/logs/${SERVER}.out 2>&1 &
echo "server is starting,you can check the ${BASE_DIR}/logs/${SERVER}.out"

我需要对文件路径进行修改,变动点如下所示:

# 修改JAVA_HOME地址
export JAVA_HOME=/usr/local/java/jdk1.8.0_261
# 修改CUSTOM_SEARCH_LOCATIONS路径
export CUSTOM_SEARCH_LOCATIONS=file:${BASE_DIR}/conf/

因为是标准的spring boot项目,所以执行下面命令,提取出jar包中的config文件。

jar xf hero_web-1.0-SNAPSHOT-default.jar BOOT-INF/classes/application.yml
jar xf hero_web-1.0-SNAPSHOT-default.jar BOOT-INF/classes/application-dev.yml

然后把这两个文件copy所创建的conf目录下

cp BOOT-INF/classes/* conf/

修改application-dev.yml文件做的mysql的ip地址172.17.187.78:3307,改成自己机器的内网地址:3306(需要确定能连通,用户名和密码是正确的):

server:
  port: 9001
spring:
  thymeleaf:
    cache: false
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://<your mysql ip>:3306/hero_all?useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2B8
    username: root
    password: root

# Tomcat的maxConnections、maxThreads、acceptCount三大配置,分别表示最大连接数,最大线程数、最大的等待数,可以通过application.yml配置文件来改变这个三个值,一个标准的示例如下:
server.tomcat.uri-encoding: UTF-8

由于熊哥提供的脚本文件是windows下的,需要进行windows的换行符变成linux换行符。
这里需要安装一个工具,然后执行命令,将脚本转换格式:

sudo yum install -y  dos2unix
dos2unix startup.sh 
dos2unix stop.sh

image.png
image.png
然后查看一下java进程,是否启动成功
image.png
然后对接口进行访问,测试一下是否成功?

curl http://localhost:9001/spu/goods/10000005620800

image.png

到现在项目jar包已经启动完成。
然后在安全组需要开放9001端口,否则无法外部访问。
image.png

1.2.2.3 启动jmeter的ServiceAgent

回到用户目录,创建serviceAgent文件夹,并cd进去。

为了让压测的时候,jmeter能够监听当前服务器的状态,所以需要下载配置服务端的ServerAgent。

关于ServerAgent的描述请点击这里,下载地址为https://github.com/undera/perfmon-agent/releases/download/2.2.3/ServerAgent-2.2.3.zip。

服务器硬件资源的监控,必须在服务端安装serverAgent代理服务,jmeter才能实现监控服务端的cpu、内存、io的使用情况

通过研究知道,这个下载解压后,内部会有个startAgent.sh的脚本,脚本的原始内容如下所示:

java -jar $(dirname $0)/CMDRunner.jar --tool PerfMonAgent "$@"

按照熊哥说法,为了让能正常对外开放,这里需要把脚本设置端口。

服务启动默认4444端口,根本连接不上,因此自己创建一个部署脚本文件对此进行部署,且把端口修改为7879

所以脚本需要变更如下所示:

nohup java -jar $(dirname $0)/CMDRunner.jar --tool PerfMonAgent --udp-port 7879 --tcp-port 7879 > log.log 2>&1 &

同时还需要赋予脚本可执行权限。

chmod 755 startAgent.sh

因此为了这个目的,我编写如下脚本:

#!/bin/bash

# 定义需要的文件和下载链接
FILE="ServerAgent-2.2.3.zip"
URL="https://github.com/undera/perfmon-agent/releases/download/2.2.3/ServerAgent-2.2.3.zip"
DIR="ServerAgent-2.2.3"
BASE_DIR=$(dirname $(realpath $0))/$DIR
echo "BASE DIR: $BASE_DIR"
# 检查文件是否存在
if [ ! -f "$FILE" ]; then
    echo "$FILE does not exist. Downloading..."
    wget "$URL"
else
    echo "$FILE already exists."
fi

# 检查unzip命令是否存在,如果不存在,则使用yum安装它
if ! command -v unzip &> /dev/null; then
    echo "Unzip not found. Installing it using yum..."
    sudo yum install unzip -y
fi

# 解压zip文件
unzip -o "$FILE"

# 删除旧的startAgent.sh文件(如果存在)
rm -f startAgent.sh

# 创建新的startAgent.sh文件,并添加shebang以及指定的命令
{
echo '#!/bin/bash'
echo ''
echo 'export JAVA_HOME=/usr/local/java/jdk1.8.0_261'
echo 'export JRE_HOME=${JAVA_HOME}/jre'
echo 'export CLASSPATH=.:${JAVA_HOME}/lib:${JRE_HOME}/lib'
echo 'export PATH=${JAVA_HOME}/bin:$PATH'
echo 'export JAVA_HOME'
echo 'export JAVA="$JAVA_HOME/bin/java"'
echo 'BASE_DIR=$(dirname $(realpath $0))'
echo 'nohup java -jar $BASE_DIR/CMDRunner.jar --tool PerfMonAgent --udp-port 7879 --tcp-port 7879 > $BASE_DIR/log.log 2>&1 &'
} > $BASE_DIR/startAgent.sh

# 给新的startAgent.sh文件添加执行权限
chmod 755 "$BASE_DIR/startAgent.sh"

# 检查/etc/rc.local是否已包含startAgent.sh启动命令
if ! grep -q "$BASE_DIR/startAgent.sh" /etc/rc.local; then
    echo "Adding startAgent.sh to /etc/rc.local"
    echo "$BASE_DIR/startAgent.sh" | sudo tee -a /etc/rc.local > /dev/null
else
    echo "startAgent.sh already added to /etc/rc.local"
fi

chmod +x /etc/rc.d/rc.local

然后重启服务,执行下面命令:

ps -ef|grep CMDRunner

同时前往ServerAgent-2.2.3的文件夹下,查看log.log输出。
image.png
现在为止已经说明可以执行成功。

然后还需要开放端口。
image.png

1.2.2.4 初步压测验证

打开jmeter工具,运行一下看效果
image.png
主要是看CPU/内存/磁盘读写的效果。
注意测试前需要运行应用程序。
image.png
然后结果如下所示:
image.png
可以看出来,目前是安装成功的,且可以被jmeter收集。

1.2.2.5 安装node_exporter

这台机器也需要安装node exporter,以便监控。
需要先参照 1.2.1.1 安装Docker。
然后再安装 1.2.1.5 安装node_exporter。
这里过程不再演示,只展示最终结果。
访问 http://< yourIpAddress >:9100/metrics
image.png
到现在,hero-application的机器环境已经完全搭建完成。

1.2.3 搭建hero01-ci-nginx-JMeter

这个是为了后续课程学习nginx所需要的。
为了安装OpenResty,推荐采用Docker-Compose的做法,熊哥写的脚本操作最后服务重启还得写脚本,相对麻烦,这里是其官方的Docker Hub链接。

1.2.3.1 安装docker和docker-compose

参照 1.2.1.1 安装Docker

1.2.3.2 下载安装OpenResty

首先,创建一个目录,名称为openResty,创建nginx.conf文件,内容所示:

events {
    # worker_connections 768;
    # 其他事件配置...
}

http {
    server {
        listen 80;
        server_name localhost;

        location / {
            root   /usr/local/openresty/nginx/html;
            index  index.html index.htm;
        }

        # 其他 location、upstream、等配置...
    }

    # 其他 http 配置...
}


然后创建docker-compose.yaml文件,内容如下所示:

version: '3.1'

services:
  openresty:
    image: openresty/openresty
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx.conf:/usr/local/openresty/nginx/conf/nginx.conf
    command: ["/usr/local/openresty/bin/openresty", "-g", "daemon off;"]

在这个docker-compose文件中,我使用command

command: ["/usr/local/openresty/bin/openresty", "-g", "daemon off;"]

这个命令的含义拆解如下:

  • /usr/local/openresty/bin/openresty”:这是在容器内部调用 OpenResty 可执行文件的完整路径。OpenResty 是建立在 Nginx 和 LuaJIT 上的一个全功能的 web 平台,通过该命令启动它。
  • -g”:这是一个指示 OpenResty 接下来的参数是全局指令的标志。
  • "daemon off;":这是一个 Nginx 的全局指令,告诉 Nginx 以前台模式运行而不是默认的守护进程模式。在 Docker 容器中运行服务时,通常希望主进程在前台运行。如果主进程作为守护进程在后台运行,那么 Docker 容器在启动后会立即退出,因为 Docker 认为主进程已经结束。

将整个命令合在一起,就是告诉 Docker 启动 OpenResty 并保持它在前台运行。这样,Docker 就可以管理 OpenResty 服务,如果服务终止,Docker 将能够检测到这一点,并根据容器的重启策略做出相应的操作。

编写完毕后,我选择执行docker compose up -d
image.png
然后将实例加入之前设置好的安全组,使用公网看看能不能访问。
image.png
访问地址是

http://<ip-address>

image.png

1.2.3.3 安装jmeter

这个部分是为了后续搭建分布式压测做准备。
和nginx不同,jmeter不是一个需要实时启动的应用程序,所以jmeter不采用docker方式部署,采用脚本方式。
根据熊哥描述,采用5.4.1的版本方式进行。
为了安装JMeter,首先需要安装JDK,需要按照 1.2.2.1我写的操作步骤安装JDK环境,这里不再重复撰写。

然后把熊哥提供的插件就就绪版的jmeter上传。所谓的插件就绪,是在plugin页面对应插件。然后把下载的文件放入/lib/ext目录下,然后打开测试计划,jui会提示要下哪些插件。下完后压缩上传到linux服务端。

image.png
这里创建/usr/local/apache-jmeter-5.4.1目录,然后把上传的zip。

这里注意,因为原文件zip包包含中文,需要去掉中文,目前我把“插件就绪版"几个字去掉了。

解压放到对应目录下,解压前,需要安装unzip。

yum install -y unzip

然后执行下面脚本:

#!/bin/bash

# 要解压的zip文件
ZIP_FILE="apache-jmeter-5.4.1.zip"

# 目标目录,解压后的文件将放在这里
TARGET_DIR="/usr/local/apache-jmeter-5.4.1"

# 临时目录,用于中转解压内容
TEMP_DIR=$(mktemp -d)

# 解压ZIP文件到临时目录
unzip -q "$ZIP_FILE" -d "$TEMP_DIR"

# 找到临时目录中的第一层目录(假设只有一个目录)
FIRST_DIR=$(find "$TEMP_DIR" -mindepth 1 -maxdepth 1 -type d)
echo "first DIR : $FIRST_DIR"
# 将第一层目录中的内容移动到目标目录
if [ -d "$FIRST_DIR" ]; then
    # 如果目标目录不存在,创建它
    mkdir -p "$TARGET_DIR"
    # 将文件复制到目标目录
    mv "$FIRST_DIR"/* "$TARGET_DIR"
fi

# 删除临时目录
rm -rf "$TEMP_DIR"


# 设置环境变量
echo "Setting environment variables..."

JMETER_HOME_VAR="JMETER_HOME=/usr/local/apache-jmeter-5.4.1"
PATH_VAR='PATH=$JMETER_HOME/bin:$PATH'

# 添加 JMETER_HOME 到 /etc/profile,如果它还没被添加
if ! grep -q "export $JMETER_HOME_VAR" /etc/profile; then
    echo "Adding JMETER_HOME to /etc/profile"
    echo "export $JMETER_HOME_VAR" | sudo tee -a /etc/profile
else
    echo "JMETER_HOME already added to /etc/profile"
fi

# 添加 JMETER_HOME/bin 到 PATH,在 /etc/profile,如果它还没被添加
if ! grep -q "export $PATH_VAR" /etc/profile; then
    echo "Adding JMETER_HOME/bin to PATH in /etc/profile"
    echo "export $PATH_VAR" | sudo tee -a /etc/profile
else
    echo "JMETER_HOME/bin already added to PATH in /etc/profile"
fi

# 提示
echo "Please log out and log back in to apply the environment variable changes, or open a new terminal session."
sudo chmod -R 755 /usr/local/apache-jmeter-5.4.1

为了验证这个是ok的,打算使用一个测试计划去验证。
通过熊哥给的文件,需要把测试计划修改一下,把ip地址切换成内网地址。

jmeter -n -t [jmx file] -l [results file] -e -o [Path to web report folder]
# 参数说明
-h 帮助:打印出有用的信息并退出
-n 非 GUI 模式:在非 GUI 模式下运行 JMeter
-t 测试文件:要运行的 JMeter 测试脚本文件
-l 日志文件:记录结果的文件
-r 远程执行:启动远程服务
-H 代理主机:设置 JMeter 使用的代理主机
-P 代理端口:设置 JMeter 使用的代理主机的端口号
-e:测试结束后,生成测试报告
-o:指定测试报告的存放位置

所以目前我们执行命令:

jmeter -n -t 01-stress-testing-example.jmx -l 01-stress-testing-example.jtl -e -o ./01-stress-testing-example-html

image.png

1.2.3.4 安装node exporter

这台机器也需要安装node exporter,以便监控。
按照1.2.1.5 安装node_exporter。
这里过程不再演示,只展示最终结果。
值得注意的是,记得修改docker-compose.yaml中的hostname,否则会以容器id,后续展示到grafana中。
访问 http://<yourIpAddress>:9100/metrics

1.2.4 搭建hero04-grafana-influxDB-Prometheus

课程中是需要grafana和promethues面板查看程序的状态信息,另外influxDB时序数据库记录结果。
so,这个部分就是搭建这个。
首先需要安装Docker环境,参照1.2.1.1的内容

1.2.4.1 安装influxDB

创建influxDB目录,在influxDB目录下,创建data目录。
data目录路径为:/root/influxDB/data。
在influx目录下创建docker-compose.yaml文件,内容如下所示:

version: '3.1'

services:
  influxdb:
    image: influxdb:1.8
    restart: always
    volumes:
      - /root/influxDB/data:/var/lib/influxdb
    environment:
      INFLUXDB_DB: jmeter  # 预先创建名为jmeter的数据库
    ports:
      - "8086:8086"
      - "8083:8083"

然后执行 docker compose up -d命令。
image.png
然后登录进去看看jmeter数据库是否有了,通过docker ps命令,可以看见启动的容器名为influxdb-influxdb-1。

docker exec -it influxdb-influxdb-1 influx

然后输入show databases;看见jmeter即算成功。
image.png
然后设置安全组,开放8086和8083两个端口。

InfluxDB 是一个开源时间序列数据库,它使用不同的端口来提供不同的功能:

  • 8086 是默认的HTTP API端口,用于客户端与 InfluxDB 服务器的交云通讯。这包括查询、写入时间序列数据,以及管理数据库的请求。自 InfluxDB 1.0 版本开始,8086 端口也支持 InfluxDB 的 HTTP服务。
  • 8083 曾经是 InfluxDB 的管理界面端口,用来访问 InfluxDB 提供的 Web UI(用户界面),可以在浏览器中对数据库进行操作。然而,从 InfluxDB 1.3 版本开始,这个 UI 和对应的端口8083已经被移除,所有的管理操作推荐通过 CLI(命令行界面)或者通过 InfluxDB 的 HTTP API 端口8086来完成。

对于现代的 InfluxDB 2.x 版本,它使用单一的端口(默认是8086)来处理所有的客户端交云通讯和用户界面访问。如果使用的是 InfluxDB 2.x,通常只需要关心8086端口。目前其实也是关心8086。

image.png
image.png

1.2.4.2 安装promethues

新建promethues目录,然后进入promthues目录新建data目录,data目录路径为:/root/promthues/data

然后在/root/promthues目录下新建prometheus.yml文件,内容如下所示:


global:
  scrape_interval: 15s
  evaluation_interval: 15s

scrape_configs:
  - job_name: 'hero-Linux'
    static_configs:
      - targets: ['172.17.121.201:9100','172.17.121.202:9100','172.17.121.203:9100']

注意一下,这里我配置了heror-linux的一个抓取任务job,配置的targets就是,之前前面几个实例,三台机器机器IP地址配置的node exporter的端口。地址是对应的实例机器的内网地址。

然后在promethues目录下,新建 docker-compose.yaml文件,内容如下所示:

version: '3.1'
services:
  prometheus:
    image: prom/prometheus:v2.15.1
    container_name: prometheus
    user: root
    ports:
      - "9090:9090"
    volumes:
      - /root/promthues/prometheus.yml:/etc/prometheus/prometheus.yml
      - /root/promthues/data:/prometheus
    restart: always

接下来执行 docker compose up -d 命令即可
image.png
image.png
然后设置开放9090安全组:
image.png
接下来就是通过机器的IP地址访问:

http://<ip>:9090

image.png
image.png

1.2.4.3 安装grafana

接下来是重头戏,安装可视化工具,grafana。这样就能把promethues的node_exporter还有influxDB中的数据读取出来。
首先在root目录下,创建 grafana文件夹,然后进入grafana文件夹下创建data目录,data目录路径为:/root/grafana/data。
然后grafana文件夹下,创建docker-compose.yaml文件,内容如下所示:

version: '3.1'

services:
  grafana:
    image: grafana/grafana:latest
    user: root
    ports:
      - '3000:3000'
    environment:
      - GF_SECURITY_ADMIN_PASSWORD=admin
      - GF_SECURITY_ADMIN_USER=admin
    volumes:
      - /root/grafana/data:/var/lib/grafana
    restart: always

接下来执行 docker compose up -d 命令即可
image.png
image.png
然后设置开放端口3000安全组:
image.png
接下来就是通过机器的IP地址访问:

http://<ip>:3000

image.png
输入docker-compose配置的用户名和密码,登录进去后配置promethues数据源。
image.png
然后这个地方输入promethues的内网地址即可。
image.png

image.png

然后导入grafana的一些公共模板:
导入Linux系统dashboard

  • Node Exporter for Prometheus Dashboard EN 20201010
    • dashboard-ID: 11074
  • Node Exporter Dashboard
    • dashboard-ID: 16098

image.png
image.png
image.png
image.png
另一个面板也如此配置。
image.png

到现在为止,通过grafana和promethues的联合监控已经完毕。

1.2.4.4 设置jmeter的influxDB监控

这里首先,我们需要执行jmeter,在influxDB中加入数据。
我修改了测试计划,在前面加上了用户定义变量,因为阿里云主机,不绑定弹性公网的情况下,主机的公网ip地址是会被随机分配的。
image.png

image.png
接下来加压大概是这样的。
image.png
点击执行运行,压测结束后,需要看看influxdb是否有数据
image.png
搭建grafana的influxDB的数据源。
image.png
image.png
image.png

因为安装的时候特意选的是1.8版本,所以不用选择用户名和密码。
image.png
image.png
在Grafana的官网找到我们需要的展示模板

  • Apache JMeter Dashboard
    • dashboad-ID:5496
  • JMeter Dashboard(3.2 and up)
    • dashboad-ID:3351

image.png
image.png

到此已经做好了grafana+influxdb+jmeter的搭建。

1.3 结语

后续如果有时间,会考虑更新一下搭建多集群机器进行分布式压测的笔记,我还需要整理一下。

主要是需要一台window server主机和3-4台的jmeter小型压力机。

这样可以做梯度压测,由Windows汇总,也不需要我在mac电脑上压测,可以采用windows server,然后避免ip地址因为云主机启动而不得不变更ip的问题。

本次的搭建过程,其实适用于绝大多数的spring boot项目,主要是环境搭建和监控平台的构建。希望对大家有帮助。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/320814.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

python 通过定时任务执行pytest case

这段Python代码使用了schedule库来安排一个任务&#xff0c;在每天的22:50时运行。这个任务执行一个命令来运行pytest&#xff0c;并生成一个报告。 代码开始时将job_done变量设为False&#xff0c;然后运行预定的任务。一旦任务完成&#xff0c;将job_done设置为True并跳出循…

基于Java SSM框架实现学生成绩管理系统项目【项目源码+论文说明】

基于java的SSM框架实现学生成绩管理系统演示 摘要 学生成绩是高校人才培养计划的重要组成部分&#xff0c;是实现人才培养目标、培养学生科研能力与创新思维、检验学生综合素质与实践能力的重要手段与综合性实践教学环节。而学生所在学院多采用半手工管理学生成绩的方式&#…

【PyTorch简介】3.Loading and normalizing datasets 加载和规范化数据集

Loading and normalizing datasets 加载和规范化数据集 文章目录 Loading and normalizing datasets 加载和规范化数据集Datasets & DataLoaders 数据集和数据加载器Loading a Dataset 加载数据集Iterating and Visualizing the Dataset 迭代和可视化数据集Creating a Cust…

如何使用csdn中的c知道进行学习?

1.c知道 猜测是通过chatgpt训练链接到CSDN内部的文章内容等&#xff0c;进行生成的一款应用。 2.如何使用呢 打比方说&#xff0c;我想学习下多目标跟踪中的ukf&#xff0c;那么就可以输入这个关键字。 那既然是学习&#xff0c;就要进一步深究&#xff0c;有三种方式&#…

LV.13 D11 Linux驱动移植及内核深化 学习笔记

一、设备树 1.1 设备树 设备树是一种描述硬件信息的数据结构&#xff0c;Linux内核运行时可以通过设备树将硬件信息直接传递给Linux内核&#xff0c;而不再需要在Linux内核中包含大量的冗余编码 举例&#xff1a;让LED2闪烁的代码中&#xff0c;有逻辑代码和设备代码。Li…

Django数据库选移的preserve_default=False是什么意思?

有下面的迁移命令&#xff1a; migrations.AddField(model_namemovie,namemov_group,fieldmodels.CharField(defaultdjango.utils.timezone.now, max_length30),preserve_defaultFalse,),迁移命令中的preserve_defaultFalse是什么意思呢&#xff1f; 答&#xff1a;如果模型定…

点击随机红点的简单游戏(pygame)

import pygame import sys import random# 初始化 Pygame pygame.init()# 设置窗口大小 width, height 800, 600 screen pygame.display.set_mode((width, height)) pygame.display.set_caption("Click the Red Dot")# 定义颜色 black (0, 0, 0) red (255, 0, 0)…

Spring来了,春天还会远吗?

结束了JVM的学习后&#xff0c;要进入的是JavaEE进阶的学习了。JavaEE进阶学习内容很多很丰富&#xff0c;并且也很有难度。今天我们就从Spring开始讲起。 目录 框架的好处 怎么学框架 Spring核心与设计思想 容器 IoC Spring IoC DI&#xff08;Dependency Injection&a…

Android 通知

通知 通知是指 Android 在应用界面之外显示的消息&#xff0c;旨在向用户提供提醒、来自他人的通信或应用中的其他实时信息。用户可以点按通知以打开您的应用&#xff0c;或直接从通知中执行操作。 通知在状态栏中显示为图标&#xff0c;在抽屉式通知栏中显示更详细的条目&…

【书生·浦语】大模型实战营——第五课作业

教程文档&#xff1a;https://github.com/InternLM/tutorial/blob/vansin-patch-4/lmdeploy/lmdeploy.md#tritonserver-%E6%9C%8D%E5%8A%A1%E4%BD%9C%E4%B8%BA%E5%90%8E%E7%AB%AF 视频链接&#xff1a; 作业&#xff1a; 基础作业 使用如下命令创建conda环境 conda create…

【期末考试】数据库综合复习宝典

目录 第一章 数据库系统概述 第二章 关系代数 第四章 关系数据库理论 第五章 数据库设计 第六章 数据库管理系统 第八章 事务管理 第一章 数据库系统概述 1.1三级模式 ①外模式&#xff1a;它为特定的应用程序或用户群体提供了一个数据视图&#xff0c;这个视图是独立于…

评估LLM在细胞数据上的实用性(2)-细胞层面的评估

本文衔接上一篇&#xff1a;评估LLM在细胞数据上的实用性(1)-基本概述 目录 定义参数和任务批次整合多模态整合细胞类型注释 细胞层面的评估批次整合多模态整合细胞类型注释 定义 我们考虑一个预训练LLM表示为 M ( x , θ ) M(x,\theta) M(x,θ)&#xff0c;其基于单细胞数据…

设计模式-传输对象模式

设计模式专栏 模式介绍模式特点应用场景传输对象模式和序列化的区别代码示例Java实现传输对象模式Python实现传输对象模式 传输对象模式在spring中的应用 模式介绍 传输对象模式&#xff08;Transfer Object Pattern&#xff09;是一种设计模式&#xff0c;用于从客户端向服务…

【redis基础1】基础数据类型详解和应用案例

博客计划 &#xff0c;我们从redis开始&#xff0c;主要是因为这一块内容的重要性不亚于数据库&#xff0c;但是很多人往往对redis的问题感到陌生&#xff0c;所以我们先来研究一下。 本篇&#xff0c;我们先看一下redis的基础数据类型详解和应用案例。 1.redis概述 以mysql为…

某mps政务网站jsl加速乐cookie逆向解析

本文针对的目标网站如下&#xff0c;使用base64解密获得 aHR0cHM6Ly93d3cubXBzLmdvdi5jbi8 开篇&#xff1a;加速乐其实算是比较好处理的逆向问题了&#xff0c;了解过的朋友都知道&#xff0c;其本身跟瑞数相似&#xff0c;都是设置cookie后才能成功&#xff0c;设置cookie的过…

配置CentOS系统以支持静态HTTP服务

CentOS是一个流行的Linux发行版&#xff0c;广泛应用于服务器环境。要配置CentOS系统以支持静态HTTP服务&#xff0c;您可以按照以下步骤进行操作&#xff1a; 安装Web服务器软件&#xff1a;CentOS自带了Apache HTTP服务器软件&#xff0c;您可以使用以下命令安装它&#xff1…

计算机找不到vcomp140.dll怎样修复?马上教会你修复dll问题

在计算机系统运行过程中&#xff0c;遭遇“vcomp140.dll丢失”的场景并不少见&#xff0c;这一问题的出现往往伴随着软件无法正常启动、运行时错误提示或者系统性能下降等现象。具体场景可能包括但不限于&#xff1a;用户在尝试打开某个依赖于Visual C Redistributable库的应用…

机器学习入门知识

一、引言 机器学习是当前信息技术中最令人振奋的领域之一。在这门课程中&#xff0c;我们将探索该技术的前沿&#xff0c;并能够亲自实现机器学习的算法。 或许你每天都在不知不觉中使用了机器学习的算法。每次你打开谷歌或必应搜索你需要的内容&#xff0c;正是因为它们拥有出…

FFmpeg技术详解

FFmpeg技术详解 本文概不介绍相关安装配置&#xff0c;详情请入官方或者其他大佬博客&#xff0c;此处做出推荐&#xff1a; https://ffmpeg.org/ FFmpeg官网 https://ffmpeg.github.net.cn/developer.html FFmpeg中文文档 https://blog.csdn.net/m0_47449768/article/details/…

以太网抓包软件Wireshake应用介绍( SMART PLC MODBUSTCP通信)

首先介绍下常看到的字符ACK,ACK是确认字符,在数据通信中,接收站发给发送站的一种传输类控制字符,表示发来的数据已确认接收无误。在TCP/IP协议中,如果接收方成功的接收到数据,会回复一个ACK数据。通常ACK信号有自己固定的格式,长度大小,由接收方回复给发送方。ACK在TCP的…