dashboard、thread、jvm
docker pull influxdb:1.8.6 # 拉取influxdb镜像
docker run -d -p 8086:8086 --name=jmeterdb influxdb:1.8.6 # 启动influxdb,并命名为jmeterdb
docker exec -it jmeterdb bash # 进入容器
influx # 进入influxdb数据库
create database jmeter; # 创建jmeter库
show databases; # 显示所有数据库,显示jmeter库就创建成功
use jmeter; # 进入jmeter库
select * from jmeter; # 查询库里面的数据,这时数据是空的正常
在jmeter线程组下添加后端监听器
线程组 > 监听器 > 后端监听器
Thread Group > Listener > Backend Listener
Backend Listener implementation: org.apache.jmeter.visualizers.backend.influxdb.InfluxdbBackendListenerClient
influxdbUrl: http://influxdb.host:8086/write?db=jmeter # 这里的IP输自己主机的
application: mx-app # 这里的名字自己随意定义即可
measurement: jmeter # 数据库的名字,jmeter为上面在influxdb中创建的jmeter库
testTitle: Jmeter # 这个名字也自己随意定义即可
配置完之后执行一次压测脚本,看influxdb中jmeter库里面有没有数据,有数据就配置成功了。
在grafana添加influxdb数据源,点击按钮Add data source
找到 influxdb,单击选择该db,配置influxdb数据源
拉到页面最下面点击 Save&Test 按钮
点击左侧加号,选择Import
将json文本复制/粘贴到paste JSON 文本框中,单机Load按钮导入(json文件下载地址:https://grafana.com/api/dashboards/5496/revisions/1/download)
在DB name 中选择我们上面创建的数据源mx-mall,单机 Import 按钮完成 Dashboard 导入
show create table pms_product;
CREATE TABLE `pms_product` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`brand_id` bigint(20) DEFAULT NULL,
`product_category_id` bigint(20) DEFAULT NULL,
`feight_template_id` bigint(20) DEFAULT NULL,
`product_attribute_category_id` bigint(20) DEFAULT NULL,
`name` varchar(64) NOT NULL,
`pic` varchar(255) DEFAULT NULL,
`product_sn` varchar(64) NOT NULL COMMENT '货号',
`delete_status` int(11) DEFAULT NULL COMMENT '删除状态:0->未删除;1->已删除',
`publish_status` int(11) DEFAULT NULL COMMENT '上架状态:0->下架;1->上架',
`new_status` int(11) DEFAULT NULL COMMENT '新品状态:0->不是新品;1->新品',
`recommand_status` int(11) DEFAULT NULL COMMENT '推荐状态;0->不推荐;1->推荐',
`verify_status` int(11) DEFAULT NULL COMMENT '审核状态:0->未审核;1->审核通过',
`sort` int(11) DEFAULT NULL COMMENT '排序',
`sale` int(11) DEFAULT NULL COMMENT '销量',
`price` decimal(10,2) DEFAULT NULL,
`promotion_price` decimal(10,2) DEFAULT NULL COMMENT '促销价格',
`gift_growth` int(11) DEFAULT '0' COMMENT '赠送的成长值',
`gift_point` int(11) DEFAULT '0' COMMENT '赠送的积分',
`use_point_limit` int(11) DEFAULT NULL COMMENT '限制使用的积分数',
`sub_title` varchar(255) DEFAULT NULL COMMENT '副标题',
`description` text COMMENT '商品描述',
`original_price` decimal(10,2) DEFAULT NULL COMMENT '市场价',
`stock` int(11) DEFAULT NULL COMMENT '库存',
`low_stock` int(11) DEFAULT NULL COMMENT '库存预警值',
`unit` varchar(16) DEFAULT NULL COMMENT '单位',
`weight` decimal(10,2) DEFAULT NULL COMMENT '商品重量,默认为克',
`preview_status` int(11) DEFAULT NULL COMMENT '是否为预告商品:0->不是;1->是',
`service_ids` varchar(64) DEFAULT NULL COMMENT '以逗号分割的产品服务:1->无忧退货;2->快速退款;3->免费包邮',
`keywords` varchar(255) DEFAULT NULL,
`note` varchar(255) DEFAULT NULL,
`album_pics` varchar(800) DEFAULT NULL COMMENT '画册图片,连产品图片限制为5张,以逗号分割',
`detail_title` varchar(255) DEFAULT NULL,
`detail_desc` text,
`detail_html` text COMMENT '产品详情网页内容',
`detail_mobile_html` text COMMENT '移动端网页详情',
`promotion_start_time` datetime DEFAULT NULL COMMENT '促销开始时间',
`promotion_end_time` datetime DEFAULT NULL COMMENT '促销结束时间',
`promotion_per_limit` int(11) DEFAULT NULL COMMENT '活动限购数量',
`promotion_type` int(11) DEFAULT NULL COMMENT '促销类型:0->没有促销使用原价;1->使用促销价;2->使用会员价;3->使用阶梯价格;4->使用满减价格;5->限时购',
`brand_name` varchar(255) DEFAULT NULL COMMENT '品牌名称',
`product_category_name` varchar(255) DEFAULT NULL COMMENT '商品分类名称',
`gmt_create` datetime(6) DEFAULT CURRENT_TIMESTAMP(6),
`gmt_modified` datetime(6) DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=43 DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='商品信息'
show create table pms_sku_stock;
CREATE TABLE `pms_sku_stock` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`product_id` bigint(20) DEFAULT NULL,
`sku_code` varchar(64) NOT NULL COMMENT 'sku编码',
`price` decimal(10,2) DEFAULT NULL,
`stock` int(11) DEFAULT '0' COMMENT '库存',
`lock_stock` int(11) DEFAULT '0' COMMENT '锁定库存',
`low_stock` int(11) DEFAULT NULL COMMENT '预警库存',
`sp1` varchar(64) DEFAULT NULL COMMENT '销售属性1',
`sp2` varchar(64) DEFAULT NULL,
`sp3` varchar(64) DEFAULT NULL,
`pic` varchar(255) DEFAULT NULL COMMENT '展示图片',
`sale` int(11) DEFAULT NULL COMMENT '销量',
`promotion_price` decimal(10,2) DEFAULT NULL COMMENT '单品促销价格',
`gmt_create` datetime(6) DEFAULT CURRENT_TIMESTAMP(6),
`gmt_modified` datetime(6) DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE,
KEY `idx_product_id` (`product_id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=147 DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='sku的库存'
BEGIN
DECLARE sku_id INT DEFAULT 110001;
WHILE sku_id < 1000000 DO
INSERT INTO `micromall`.`pms_product` (
`brand_id`,
`product_category_id`,
`feight_template_id`,
`product_attribute_category_id`,
`name`,
`pic`,
`product_sn`,
`delete_status`,
`publish_status`,
`new_status`,
`recommand_status`,
`verify_status`,
`sort`,
`sale`,
`price`,
`promotion_price`,
`gift_growth`,
`gift_point`,
`use_point_limit`,
`sub_title`,
`description`,
`original_price`,
`stock`,
`low_stock`,
`unit`,
`weight`,
`preview_status`,
`service_ids`,
`keywords`,
`note`,
`album_pics`,
`detail_title`,
`detail_desc`,
`detail_html`,
`detail_mobile_html`,
`promotion_start_time`,
`promotion_end_time`,
`promotion_per_limit`,
`promotion_type`,
`brand_name`,
`product_category_name`
)
VALUES
(
'58',
'29',
'0',
'1',
'耐克NIKE 男子 气垫 休闲鞋 AIR MAX 90 ESSENTIAL 运动鞋 AJ1285-101白色41码',
'http://macro-oss.oss-cn-shenzhen.aliyuncs.com/mall/images/20180615/5b19403eN9f0b3cb8.jpg',
'6799345',
'0',
'1',
'1',
'1',
'0',
'0',
'0',
'499.00',
NULL,
'0',
'0',
'0',
'耐克NIKE 男子 气垫 休闲鞋 AIR MAX 90 ESSENTIAL 运动鞋 AJ1285-101白色41码',
'',
'499.00',
'100',
'0',
'',
'0.00',
'0',
'',
'',
'',
'',
'',
'',
'',
'',
NULL,
NULL,
'0',
'0',
'NIKE',
'男鞋'
);
INSERT INTO `micromall`.`pms_sku_stock` (
`product_id`,
`sku_code`,
`price`,
`stock`,
`lock_stock`,
`low_stock`,
`sp1`,
`sp2`,
`sp3`,
`pic`,
`sale`,
`promotion_price`
)
VALUES
(
sku_id,
sku_id,
'3000.00',
'100000000',
'10',
'5',
'黑色',
'16g',
NULL,
NULL,
'0',
NULL
);
SET sku_id = sku_id + 1;
END
WHILE;
END
mx-mall压测.jmx
https://download.csdn.net/download/menxu_work/87361222
线程组 > 监听器 > 后端监听器
Thread Group > Listener > Backend Listener
线程组 > 配置元件 > CSV数据文件设置
Thread Group > Config Element > CSV Data Set Config
线程组 > 配置元件 > HTTP 信息头管理
Thread Group > Config Element > HTTP Header Manager
线程组 > 断言 > 简单控制器
Thread Group > Assertions > Simple Controller
{
"productId": ${productId},
"productSkuId": ${productId},
"quantity": 1
}
线程组 > 后置处理器 > JSON Extractor
Thread Group > Post Processors > JSON Extractor
{
"itemIds":[${itemIds}]
}
线程组 > 前置处理器 > BeanShell PreProcessor
Thread Group > Pre Processors > BeanShell PreProcessor
//log.info("调试是否获取长度id:"+vars.get("cartId_matchNr"));
int num=Integer.valueOf("${cartId_matchNr}");
//log.info("数据为:"+num);
StringBuilder stringBuilder = new StringBuilder();
for(i = 1;i<=num;i++){
stringBuilder.append(vars.get("cartId_"+i)+",");
}
String itemIds = stringBuilder.substring(0, stringBuilder.length() - 1);
//log.info("结果:"+itemIds);
vars.put("itemIds",itemIds);
线程组 > 监听器 > 聚合报告
Thread Group > Listener > Aggregate Report
线程组 > 监听器 > 察看结果树
Thread Group > Listener > View Results Tree
追求目标:
启动100个线程数,循环执行次数为10000,那么每个线程发送10000次请求,总请求数为 100*10000 =1000000
定位问题:
解决问题:
效果:
QPS超过了两百多,最高的时候有四五百多,好像优化有效果,继续一直压测下去,会发现qps一直在慢慢往下掉,这是为什么了?
定位问题:
解决问题:
效果:
5. QPS 稳定在两千多,mysql的cpu占用也下降了很多,优化效果相当明显,提升了一个数量级,可见平时工作中对数据库的sql优化是非常重要的,一条慢sql在高并发场景下甚至可以拖垮整个数据库
6. skywalking这条sql的执行时间也到了几毫秒了,对应的post请求的总执行时间也下降了很多,当然还有100多毫秒,这个应该算正常,在高并发情况下,请求之间争用系统资源会有等待,导致链路调用过程中会有损耗
启动100个线程数,循环执行次数为10000,那么每个线程发送10000次请求,总请求数为 100*10000 =1000000
一个查询操作QPS只有40左右?
定位问题:
解决问题:
效果:
购物车查询比添加购物车时间慢?
定位问题:
解决问题:
上了网关比不上网关QPS相差2倍?
dashboard、thread
在容器里下载arthas, 通过arthas的一些常用命令来分析下jvm情况
wget https://arthas.gitee.io/arthas-boot.jar
java -jar arthas-boot.jar
定位问题:
thread -n 3
最繁忙的3个线程(占用cpu最多的前3个),输出栈信息
4. thread -b
输出阻塞的线程栈信息,如果响应慢,阻塞状态的线程比较多,我们需要重点关注
gateway内部的线程池很繁忙,占用cpu很高
解决问题:
reactor.netty.ioWorkerCount
,但是一般不建议调整,因为这个线程池的内部就是按照cpu核数(我这个gateway部署的机器是8核的)来确定的,调大意义也不是很大,当然我们可以试着来调试下,在gateway的deployment文件里加上这个 -Dreactor.netty.ioWorkerCount=16
效果: 作用不大
, 需要调整回去
jstat -gcutil 7 1000 100
FGC还算正常,但是YGC几乎每秒1次,感觉有点频繁,可能是年轻代太小了,我们看下堆内存情况,当然如果FGC比较频繁我们可以通过jmap查看下对象占用内存的情况
jmap -histo 7 | head -20
jinfo -flags 1
定位:
解决:
-Xms1G -Xmx1G -Xmn512M -Xss512K -XX:MetaspaceSize=256M -XX:MaxMetaspaceSize=256M
效果:
因为网关gateway对cpu性能要求较高,把gateway部署调整下机器,再压测差别已经不大了。有的时候压测结果跟机器性能会有较大关系
创建订单接口的qps不到100,凭经验来说应该是有优化余地的,注意这里grafana里展示的是3个接口的总QPS
查看skywalking的创建订单接口的链路,发现有一部分请求链路非常长,里面包含上百条查询商品的执行sql
例如:购物车添加500件商品,没查询一件商品更新一条购物车状态
解决:
进入order服务后台用arthas来分析下,然后看了下应用和mysql的机器使用率,我们发现order和gateway服务占用cpu较高,因为现在主要就在测order服务
执行下thread命令看下线程整体情况,发现waiting的线程好像有点多,关键占用cpu还比较高
thread thread-id
thread -n 6
我们发现里面大多数线程都是在等待获取数据库的连接
调整Order数据库连接池大小
spring:
datasource:
url: jdbc:mysql://mysql.localhost.com:3306/micromall?serverTimezone=UTC&useSSL=false&useUnicode=true&characterEncoding=UTF-8
username: root
password: root
druid:
initial-size: 10 #连接池初始化大小
min-idle: 20 #最小空闲连接数
max-active: 100 #最大连接数
web-stat-filter:
exclusions: "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*" #不统计这些请求数据
stat-view-servlet: #访问监控网页的登录用户名和密码
login-username: druid
login-password: druid
数据库连接倒是用上来了,不过mysql连接已经用满了
调整tmysql服务端的总连接数
set global max_connections=500; # 这样修改mysql重启后会恢复之前值,要彻底修改需要修改mysql的配置文件并重启
server:
port: 8844
tomcat:
accept-count: 200 # accept队列的长度,当accept队列中连接的个数达到acceptCount时,新进来的请求一律被拒绝。默认值是100
threads:
max: 300 # 线程池中最大活跃线程数,默认值200
min-spare: 20 # 线程池中保持的最小线程数
max-connections: 1000 # Tomcat最多能并发处理的请求(连接)
重启order服务后再次压测发现下单qps几乎没什么变化,注意,线程数并不是越大越好的,太大了会导致cpu争用,让线程响应时间变长,所以线程数具体设置多少合适,需要通过压测具体的项目不断调整到较合理的值,比如,如果我们期望系统单台机器下单达到300并发,最大线程数设置为100或300都能达到,那我们就可以设置为100会更合适点。
既然加大tomcat线程数不行,我们再回到skywalking看下下单接口的执行链路
我们发现在我们调整完各种连接池之后,虽然qps没有增加,
查看mysql的慢查询有没有我们没有注意到的sql
-- 慢查询
show variables like '%slow_query_log%'; -- 查看是否开启慢查询
set global slow_query_log=1; -- 开启慢查询
show variables like 'long_query_time%'; -- 查看慢查询阈值
set global long_query_time=0.1; -- 设置慢查询阈值(单位s),设置完需要重新开启session才能查看生效
show global variables like 'long_query_time'; -- 查看慢查询阈值
show variables like '%log_output%'; -- 查看慢查询写入文件还是数据表
set global log_output='TABLE'; -- 设置慢查询写入数据表,默认是写入文件
select sleep(1); -- 执行一条慢查询
select * from mysql.slow_log; -- 查看慢查询记录表
TRUNCATE mysql.slow_log;
通过慢查询我们发现竟然还有不少sql执行时间超过100ms的
分析问题:
目前系统里实现的生成订单业务:
效果:
目前购物车与订单相关表里的数据都已经过百万了,对于这种复杂的接口在这个数据量级和目前这个配置的机器上差不多也就这个水平了
如果内存不大,比如
-Xms3072M -Xmx3072M -Xmn1536M -Xss1M
-XX:MetaspaceSize=256M
-XX:MaxMetaspaceSize=256M
-XX:SurvivorRatio=6
-XX:MaxTenuringThreshold=5
-XX:PretenureSizeThreshold=1M
-XX:+UseParNewGC -XX:+UseConcMarkSweepGC
-XX:CMSInitiatingOccupancyFaction=92
-XX:+UseCMSCompactAtFullCollection
-XX:CMSFullGCsBeforeCompaction=0