最近重新回来学习熊哥的极客教程,结合自己学习的shell编程和Docker的指令学习,对熊哥的一些操作做bash脚本自动化,将搭建压测平台的步骤做记录,目的是分享搭建过程。
过程中会安装docker,mysql,redis,influxdb,grafana,promethues,jmeter,node-exporter等内容。
中间用于压测应用的服务Jar包属于课程的内容,这里不便提供,请原谅。
可以将应用程序jar换成自己标准的spring boot项目。
服务架构如下:
搭建的监控架构如下所示:
选择阿里云 ecs.c7a.xlarge 类型,选择这个类型的原因是相对便宜,而且熊哥当初展示是也是使用这个规格类型,避免发生问题。
版本选择 CentOs 7.6 64位,硬盘选择默认即可。
选择分配公网地址,且流量为25Mbps
定义自己的实例名称和主机名称。
目前定义四台机器,实例名称如下列表所示:
实例名 | 主机名 | 密码 |
---|---|---|
hero01-ci-nginx-JMeter | hero01 | A9405kk@01 |
hero02-mysql-redis | hero02 | A9405kk@02 |
hero03-application | hero03 | A9405kk@03 |
hero04-grafana-influxDB-Prometheus | hero04 | A9405kk@04 |
实例创建完后如下所示:
为了节省资源消耗,首先先搭建hero02,先把基础中间件搭建完毕。
这里安装Mysql和Redis,采用Docker安装的方式。
由于是数据库连接,建议采取弹性公网绑定的方式,以便外部访问。
接下来打开Final-Shell,进行后续操作。
创建一个脚本,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
建议参考博客:
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."
执行完毕后,可以看见服务启动成功。
为了确保服务重启后,能重新启动,需要重启云服务实例,然后查看是否OK。
目前测试过重启是OK的。
为了能够外部访问端口,需要设置安全组策略。
新建安全组并创建者几个规则
接下来,让实例绑定刚刚创建的安全组。
接下来输入如下地址,下面ip地址,是这台服务器的弹性公网ip地址。
http://<yourIpAddress>:8901
可以发现是可以打开成功的。
接下来进行登录。
操作也是正常的。
然后打开redis客户端进行访问。
ip地址敏感,进行了模糊化
直到现在为止,redis和mysql已经搭建完成。
这里我不是采用熊哥的逐步脚本操作,采用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端口。
然后访问
http://<yourIpAddress>:9100/metrics
然后服务重启后,发现重启后,服务都可以重新恢复。
为了验证后续1.2.2的应用程序运行后,可以验证性能效果。这里需要导入sql的初始化脚本。
这里决定采用Adminer进行导入,这里数据库导入的方式因人而已,可以采用自己本身机器连接去导入,我这里只是图省事,后续我还把这个hero_all删掉,再试了一遍sql文件的导入,完全是ok的。只是验证过程。
首先需要先创建一个数据库,这里命名为hero_all
否则脚本中存在乱码而导致导入异常。
接下来用导入的方式进行导入。
导入可能需要较长时间,需要等待一段时间。
因为保密性,应用的jar包不会提供,可以部署自己应用的jar包去进行后续操作。
用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的状态并没有变更。
返回上级目录,并创建子目录,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
然后查看一下java进程,是否启动成功
然后对接口进行访问,测试一下是否成功?
curl http://localhost:9001/spu/goods/10000005620800
到现在项目jar包已经启动完成。
然后在安全组需要开放9001端口,否则无法外部访问。
回到用户目录,创建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输出。
现在为止已经说明可以执行成功。
然后还需要开放端口。
打开jmeter工具,运行一下看效果
主要是看CPU/内存/磁盘读写的效果。
注意测试前需要运行应用程序。
然后结果如下所示:
可以看出来,目前是安装成功的,且可以被jmeter收集。
这台机器也需要安装node exporter,以便监控。
需要先参照 1.2.1.1 安装Docker。
然后再安装 1.2.1.5 安装node_exporter。
这里过程不再演示,只展示最终结果。
访问 http://< yourIpAddress >:9100/metrics
到现在,hero-application的机器环境已经完全搭建完成。
这个是为了后续课程学习nginx所需要的。
为了安装OpenResty,推荐采用Docker-Compose的做法,熊哥写的脚本操作最后服务重启还得写脚本,相对麻烦,这里是其官方的Docker Hub链接。
参照 1.2.1.1 安装Docker。
首先,创建一个目录,名称为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
。
然后将实例加入之前设置好的安全组,使用公网看看能不能访问。
访问地址是
http://<ip-address>
这个部分是为了后续搭建分布式压测做准备。
和nginx不同,jmeter不是一个需要实时启动的应用程序,所以jmeter不采用docker方式部署,采用脚本方式。
根据熊哥描述,采用5.4.1的版本方式进行。
为了安装JMeter,首先需要安装JDK,需要按照 1.2.2.1我写的操作步骤安装JDK环境,这里不再重复撰写。
然后把熊哥提供的插件就就绪版的jmeter上传。所谓的插件就绪,是在plugin页面对应插件。然后把下载的文件放入/lib/ext
目录下,然后打开测试计划,jui会提示要下哪些插件。下完后压缩上传到linux服务端。
这里创建/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
这台机器也需要安装node exporter,以便监控。
按照1.2.1.5 安装node_exporter。
这里过程不再演示,只展示最终结果。
值得注意的是,记得修改docker-compose.yaml中的hostname,否则会以容器id,后续展示到grafana中。
访问 http://<yourIpAddress>:9100/metrics
课程中是需要grafana和promethues面板查看程序的状态信息,另外influxDB时序数据库记录结果。
so,这个部分就是搭建这个。
首先需要安装Docker环境,参照1.2.1.1的内容。
创建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
命令。
然后登录进去看看jmeter数据库是否有了,通过docker ps
命令,可以看见启动的容器名为influxdb-influxdb-1。
docker exec -it influxdb-influxdb-1 influx
然后输入show databases;看见jmeter即算成功。
然后设置安全组,开放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。
新建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
命令即可
然后设置开放9090安全组:
接下来就是通过机器的IP地址访问:
http://<ip>:9090
接下来是重头戏,安装可视化工具,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
命令即可
然后设置开放端口3000安全组:
接下来就是通过机器的IP地址访问:
http://<ip>:3000
输入docker-compose配置的用户名和密码,登录进去后配置promethues数据源。
然后这个地方输入promethues的内网地址即可。
然后导入grafana的一些公共模板:
导入Linux系统dashboard
11074
16098
另一个面板也如此配置。
到现在为止,通过grafana和promethues的联合监控已经完毕。
这里首先,我们需要执行jmeter,在influxDB中加入数据。
我修改了测试计划,在前面加上了用户定义变量,因为阿里云主机,不绑定弹性公网的情况下,主机的公网ip地址是会被随机分配的。
接下来加压大概是这样的。
点击执行运行,压测结束后,需要看看influxdb是否有数据
搭建grafana的influxDB的数据源。
因为安装的时候特意选的是1.8版本,所以不用选择用户名和密码。
在Grafana的官网找到我们需要的展示模板
5496
3351
到此已经做好了grafana+influxdb+jmeter的搭建。
后续如果有时间,会考虑更新一下搭建多集群机器进行分布式压测的笔记,我还需要整理一下。
主要是需要一台window server主机和3-4台的jmeter小型压力机。
这样可以做梯度压测,由Windows汇总,也不需要我在mac电脑上压测,可以采用windows server,然后避免ip地址因为云主机启动而不得不变更ip的问题。
本次的搭建过程,其实适用于绝大多数的spring boot项目,主要是环境搭建和监控平台的构建。希望对大家有帮助。