性能工程之中级系列之四

2021-04-01 11:21:28 浏览数 (1)

erp登录接口之mysql调优

一、前言

为了方便跟踪系统tps变动,这次采用 Grafana 展示结果,而且采用 docker 安装部署 influxdb 与 grafana ,参考命令如:

代码语言:javascript复制
mkdir -p /home/influxdb/data /home/influxdb/conf /home/influxdb/meta /home/influxdb/wal
docker pull influxdb
docker search grafana
docker pull docker.io/grafana/grafana
docker run -d -p 8083:8083 -p 8086:8086 --name influxdb influxdb

docker run -d -p 3000:3000 --name=grafana -v /data/grafana:/var/lib/grafana grafana/grafana

docker exec -it 219f8baad500 bash
root@219f8baad500:/# influx
Connected to http://localhost:8086 version 1.8.3
InfluxDB shell version: 1.8.3
> CREATE database jmeter;
> SHOW DATABASES;
name: databases
name
----
_internal
jmeter
>

其他部署安装略也可以参考性能工具之Jmeter小白入门系列之六,目前该数据库配置结果为:

Grafana展示结果如:

一、登录代码分析

在上一讲中已经发现sql没有建立索引问题,这一节一起从代码层去分析为什么没有建立索引,打开idea找到登录请求资源路径位置如:

代码语言:javascript复制
@PostMapping(value = "/login")
public BaseResponseInfo login(@RequestParam(value = "loginName", required = false) String loginName,
                    @RequestParam(value = "password", required = false) String password,
                    HttpServletRequest request)throws Exception {

1、找到登录 Controller 调 service 位置

2、找到方法实现层:

解释:从上面代码可以看出,用户登录传入用户名密码,代码根据用户去DAO层去查询是否有该用户;

说明:Dao层就是常规写法,没有什么特别地方,再跳转xml文件查看sql是怎么写的:

说明:根据条件查询全部数据,既然这是登录接口传入的是用户名,那么应该在用户名处增加用户索引,这样查询能加快速度;

索引类似于字典目录,通过索引能快速找到响应数据;

解释:如果查询为空或者查询结果为0表示数据库么有数据直接返回用户不存在,如果存在在往下走走;

解释:如果上面都通过,这里又根据用户名密码查询数据库,这里作者为什么要查询两次数据库,既然上面已经查询完全可以在内存做判断;假如数据库有1000千用户数,每个用户登录都需要查询两次数据,也是一笔不小的开支;

二、索引优化

上节课已经发现索引有问题,但是发现用户表数据很少,第一步先增加用户数据,再通过Jmeter进行压测,造数据在性能测试中是常见的事件,这次造数据直接通过 java for 循环造数据代码参考如下:

代码语言:javascript复制
/**
 * @description: 注册用户
 * @author: 李文
 * @create: 2021-03-19 21:03
 **/
@RunWith(SpringRunner.class)
@SpringBootTest
public class LoginRegTest {

    @Resource
    private UserMapper userMapper;

    @Test
    public void contextLoads() {


        try {
            for (int j = 0; j < 100; j  ) {
                for (int i = 0; i < 1000; i  ) {
                    UserEx userEx = new UserEx();
                    userEx.setLoginName(RandomUtil.randomString(10));
                    userEx.setUsername(RandomUtil.randomString(8));
                    userEx.setEmail(RandomUtil.randomInt(1, 1100)   "@7DGroup.com");
                    userEx.setPassword(Tools.md5Encryp(BusinessConstants.USER_DEFAULT_PASSWORD));
                    userEx.setIsystem(BusinessConstants.USER_NOT_SYSTEM);
                    userEx.setIsmanager(BusinessConstants.USER_NOT_MANAGER);
                    userEx.setStatus(BusinessConstants.USER_STATUS_NORMAL);
                    userMapper.insert(userEx);
                }
            }
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
    }
}

再次打开mysql客户端输入如下sql语句:

代码语言:javascript复制
mysql> SELECT count(*) from `jsh_user`;
 ---------- 
| count(*) |
 ---------- 
| 333724   |
 ---------- 
1 行于数据集 (0.07 秒)

mysql> SELECT count(*) from `jsh_user`;

EXPLAIN SELECT id,username,login_name, PASSWORD,position, department, email, phonenum, ismanager, isystem, STATUS, description, remark, tenant_id
FROM
  jsh_user
WHERE
  (
    login_name = "admin"
    AND PASSWORD = "e10adc3949ba59abbe56e057f20f883e"
    AND STATUS = 0
  );
 ---------- 
| count(*) |
 ---------- 
| 333724   |
 ---------- 
1 行于数据集 (0.05 秒)

 ---- ------------- ---------- ------------ ------ --------------- ------ --------- ------ -------- ---------- ------------- 
| id | select_type | table    | partitions | type | possible_keys | key  | key_len | ref  | rows   | filtered | Extra       |
 ---- ------------- ---------- ------------ ------ --------------- ------ --------- ------ -------- ---------- ------------- 
| 1  | SIMPLE      | jsh_user | NULL       | ALL  | NULL          | NULL | NULL    | NULL | 331551 | 0.10     | Using where |
 ---- ------------- ---------- ------------ ------ --------------- ------ --------- ------ -------- ---------- ------------- 
1 行于数据集 (0.06 秒)

mysql> 
 

图片如下:

为了减少性能消耗,这次都采用后台运行,把项目跑起来显现如下:

Jmeter运行结果如下:

代码语言:javascript复制
liwen@liwen123 hunhe % jmeter -n -t he1.jmx
Creating summariser <summary>
Created the tree successfully using he1.jmx
Starting standalone test @ Fri Mar 19 22:01:53 CST 2021 (1616162513949)
Waiting for possible Shutdown/StopTestNow/HeapDump/ThreadDump message on port 4445
summary       44 in 00:00:06 =    7.8/s Avg:   534 Min:   472 Max:   910 Err:     0 (0.00%) Active: 9 Started: 9 Finished: 0
summary      336 in 00:00:30 =   11.2/s Avg:  2129 Min:   537 Max:  3626 Err:     0 (0.00%) Active: 30 Started: 30 Finished: 0
summary =    380 in 00:00:36 =   10.7/s Avg:  1944 Min:   472 Max:  3626 Err:     0 (0.00%)

运行几分钟结果如下:

增加索引语句:

代码语言:javascript复制
ALTER TABLE `jsh_user` ADD INDEX index_name ( `login_name` )

增加索引结果如下:

调优结果:

jmeter后台数据如下:

说明:通过直接增加索引TPS明显增加;

三、复习Mysql索引

Mysql索引分为:

(1)主键索引 PRIMARY KEY:它是一种特殊的唯一索引,不允许有空值。一般是在建表的时候同时创建主键索引。

(2) 唯一索引 UNIQUE:

代码语言:javascript复制
ALTER TABLE table_name ADD UNIQUE (column)

(3) 普通索引 INDEX

代码语言:javascript复制
ALTER TABLE table_name ADD INDEX index_name (column)

(4) 组合索引 INDEX

代码语言:javascript复制
ALTER TABLE table_name ADD INDEX index_name(column1, column2, column3)

(5) 全文索引 FULLTEXT

代码语言:javascript复制
ALTER TABLE table_name ADD FULLTEXT (column)

查看索引:

代码语言:javascript复制
mysql> show index from  jsh_user;
 ---------- ------------ ------------ -------------- ------------- ----------- ------------- ---------- -------- ------ ------------ --------- --------------- --------- 
| Table    | Non_unique | Key_name   | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | Visible |
 ---------- ------------ ------------ -------------- ------------- ----------- ------------- ---------- -------- ------ ------------ --------- --------------- --------- 
| jsh_user | 0          | PRIMARY    | 1            | id          | A         | 3           | NULL     | NULL   |      | BTREE      |         |               | YES     |
| jsh_user | 1          | index_name | 1            | login_name  | A         | 331551      | NULL     | NULL   |      | BTREE      |         |               | YES     |
 ---------- ------------ ------------ -------------- ------------- ----------- ------------- ---------- -------- ------ ------------ --------- --------------- --------- 
2 行于数据集 (0.02 秒)

mysql>

删除索引:

代码语言:javascript复制
ALTER TABLE  jsh_user DROP INDEX  index_name;

更多mysql调优请参考《性能测试实战30讲》中的:

https://time.geekbang.org/column/article/196791《22丨MySQL:数据库级监控及常用计数器解析(上)》

https://time.geekbang.org/column/article/197432 《23丨MySQL:数据库级监控及常用计数器解析(下)》

四、总结

性能调优是一个反复验证尝试的过程,但调优步骤是固定。在这一节中通过观察代码步骤来跟踪并理解为什么在用户名上面增加索引,通过边压测边增加索引看到调优结果;

0 人点赞