秒杀项目04-JMeter压测
- 1. JMeter入门
- 2. 自定义变量模拟多用户
- 编写程序生成多用户
- 3. JMeter命令行使用
- 4. Redis压测工具redis-benchmark
- 4.1 redis-benchmark -h 127.0.0.1 -p 6379 -c 100 -n 100000 -a 123456 100个并发请求,100000个请求, 密码为123456
- 4.2 redis-benchmark -h 127.0.0.1 -p 6379 -q -d 100 -a 123456 存取大小为100字节的数据包
- 4.3 redis-benchmark -t set,lpush -q -n 100000 -a 123456 测试set,lpush命令的QPS
- 4.4 redis-benchmark -n 100000 -q -a 123456 script load "redis.call('set','foo','bar')" 测试脚本的QPS
- 5. SpringBoot打war包
1. JMeter入门
1.1 JMeter安装
- 官网: http://jmeter.apache.org
- 下载: http://jmeter.apache.org/download_jmeter.cgi
- 用户手册 http://jmeter.apache.org/usermanual/index.html
1.2 JMeter使用
-
首先创建一个线程组
-
然后在线程组下创建HTTP请求默认值
-
然后创建HTTP请求
-
然后创建监听器
1.3 解决一个BUG
UserArgumentResolver.java
private String getCookieValue(HttpServletRequest request, String cookieName) {
Cookie[] cookies = request.getCookies();
if (cookies == null || cookies.length <= 0) {
return null;
}
for (Cookie cookie : cookies) {
if (cookie.getName().equals(cookieName)) {
return cookie.getValue();
}
}
return null;
}
查看linux下程序的负载情况,通过top命令
2. 自定义变量模拟多用户
新增UserController
@Controller
@RequestMapping("/user")
public class UserController {
@RequestMapping("/info")
@ResponseBody
public Result<MiaoshaUser> info(Model model, MiaoshaUser user) {
return Result.success(user);
}
}
2.1 创建配置文件,里面放userId,userToken的用户信息
config.txt
18936095619,0699ace44abf4611b2b1b2989ada8296
2.2添加配置原件CSV DATA SET CONFIG
2.3 添加我们刚才编写的配置文件,并完善相关设置
2.4 在HTTP请求的参数设置中,使用上面定义的变量userToken
编写程序生成多用户
DBUtil.java
public class DBUtil {
private static Properties props;
static {
try {
InputStream in = DBUtil.class.getClassLoader().getResourceAsStream("application.properties");
props = new Properties();
props.load(in);
in.close();
}catch(Exception e) {
e.printStackTrace();
}
}
public static Connection getConn() throws Exception{
String url = props.getProperty("spring.datasource.url");
String username = props.getProperty("spring.datasource.username");
String password = props.getProperty("spring.datasource.password");
String driver = props.getProperty("spring.datasource.driver-class-name");
Class.forName(driver);
return DriverManager.getConnection(url,username, password);
}
}
UserUtil.java
public class UserUtil {
private static void createUser(int count) throws Exception{
List<MiaoshaUser> users = new ArrayList<MiaoshaUser>(count);
//生成用户
for(int i=0;i<count;i++) {
MiaoshaUser user = new MiaoshaUser();
user.setId(13000000000L+i);
user.setLoginCount(1);
user.setNickname("user"+i);
user.setRegisterDate(new Date());
user.setSalt("hmxP@ssw0rd");
user.setPassword(MD5Util.inputPassToDBPass("123456", user.getSalt()));
users.add(user);
}
System.out.println("create user");
//插入数据库
/*Connection conn = DBUtil.getConn();
String sql = "insert into miaosha_user(login_count, nickname, register_date, salt, password, id)values(?,?,?,?,?,?)";
PreparedStatement pstmt = conn.prepareStatement(sql);
for(int i=0;i<users.size();i++) {
MiaoshaUser user = users.get(i);
pstmt.setInt(1, user.getLoginCount());
pstmt.setString(2, user.getNickname());
pstmt.setTimestamp(3, new Timestamp(user.getRegisterDate().getTime()));
pstmt.setString(4, user.getSalt());
pstmt.setString(5, user.getPassword());
pstmt.setLong(6, user.getId());
pstmt.addBatch();
}
pstmt.executeBatch();
pstmt.close();
conn.close();
System.out.println("insert to db");*/
//登录,生成token
String urlString = "http://localhost:8080/login/do_login";
File file = new File("D:/tokens.txt");
if(file.exists()) {
file.delete();
}
RandomAccessFile raf = new RandomAccessFile(file, "rw");
file.createNewFile();
raf.seek(0);
for(int i=0;i<users.size();i++) {
MiaoshaUser user = users.get(i);
URL url = new URL(urlString);
HttpURLConnection co = (HttpURLConnection)url.openConnection();
co.setRequestMethod("POST");
co.setDoOutput(true);
OutputStream out = co.getOutputStream();
String params = "mobile="+user.getId()+"&password="+MD5Util.inputPassToFormPass("123456");
out.write(params.getBytes());
out.flush();
InputStream inputStream = co.getInputStream();
ByteArrayOutputStream bout = new ByteArrayOutputStream();
byte buff[] = new byte[1024];
int len = 0;
while((len = inputStream.read(buff)) >= 0) {
bout.write(buff, 0 ,len);
}
inputStream.close();
bout.close();
String response = bout.toString();
JSONObject jo = JSON.parseObject(response);
String token = jo.getString("data");
System.out.println("create token : " + user.getId());
String row = user.getId()+","+token;
raf.seek(raf.length());
raf.write(row.getBytes());
raf.write("\r\n".getBytes());
System.out.println("write to file : " + user.getId());
}
raf.close();
System.out.println("over");
}
public static void main(String[] args)throws Exception {
createUser(5000);
}
}
MiaoshaUserService的login方法修改返回值
@Service
public class MiaoshaUserService {
public static final String COOKIE_NAME_TOKEN = "token";
@Autowired
private MiaoshaUserMapper miaoshaUserMapper;
@Autowired
private RedisService redisService;
public MiaoshaUser getByToken(HttpServletResponse response, String token) {
if (StringUtils.isBlank(token)) {
return null;
}
MiaoshaUser user = redisService.get(MiaoshaUserKey.token, token, MiaoshaUser.class);
if (user == null) {
throw new GlobalException(CodeMsg.TOKEN_ERROR);
}
//延长token有效期
addCookie(response,token,user);
return user;
}
public Result<String> login(HttpServletResponse response, LoginVo loginVo) {
if (loginVo == null) {
int i = 1;
throw new GlobalException(CodeMsg.SERVER_ERROR) ;
}
String mobile = loginVo.getMobile();
String formPass = loginVo.getPassword();
//判断手机号是否存在
MiaoshaUser user = miaoshaUserMapper.selectById(mobile);
if (user == null) {
throw new GlobalException(CodeMsg.MOBILE_NOT_EXIST);
}
//验证密码
String dbPass = user.getPassword();
String dbSalt = user.getSalt();
String pwd = MD5Util.formPassToDBPass(formPass, dbSalt);
if (!StringUtils.equals(pwd, dbPass)) {
throw new GlobalException(CodeMsg.PASSWORD_ERROR);
}
String token = UUIDUtil.uuid();
addCookie(response, token, user);
return Result.success(token);
}
//将token返回给浏览器并在redis中添加一份
private void addCookie(HttpServletResponse response, String token, MiaoshaUser user) {
//生成token
//设置redis中token的生存时间与cookie中的一致
redisService.set(MiaoshaUserKey.token, token, user);
Cookie cookie = new Cookie(COOKIE_NAME_TOKEN,token);
cookie.setMaxAge(MiaoshaUserKey.token.expireSeconds());
cookie.setPath("/");
response.addCookie(cookie);
}
}
修改/login/do_login接口的返回值
@RequestMapping("/do_login")
@ResponseBody
public Result<String> doLogin(HttpServletResponse response, @Valid LoginVo loginVo) {
log.info(loginVo.toString());
//登录
return miaoshaUserService.login(response, loginVo);
}
运行在启动应用程序后,启动UserUtil中的主方法生成包含UserId,UserToken的文件。
3. JMeter命令行使用
添加打jar包插件并修改packaging为jar
<packaging>jar</packaging>
<build>
<finalName>${project.artifactId}</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
java -jar ***.jar执行流程
首先找到jar包下META-INF目录下的MANIFEST.MF文件
先走spring提供的main函数再回调我们自己程序的main函数
将jar包放到linux中并运行nohup java -jar miaosha04.jar &命令,会将日志输出到nohup.out文件中
3.1 在windows上录好jmx
3.2 上传jmx和jmeter到linux中
3.2 命令行:
运行命令
./apache-jmeter-5.4.1/bin/jmeter.sh -n -t XXX.jmx -l result.jtl
-bash: ./apache-jmeter-5.4.1/bin/jmeter.sh: 权限不够
chmod 777./apache-jmeter-5.4.1/bin/ jmeter.sh
-bash: ./apache-jmeter-5.4.1/bin/jmeter: 权限不够
chmod 777 ./apache-jmeter-5.4.1/bin/jmeter
通过top命令查看linux负载情况
查看CPU信息
由于是虚拟机,只分配了一个处理器
cat /proc/cpuinfo | grep processor
3.3 把result.jtl导入到jmeter
通过命令将linux中的文件下载到windows
sz result.jtl
3.4 配置秒杀请求的压测文件
将token.txt和压测文件上传到linux中
并且修改压测文件中的token.txt的路径信息
3.5 压测秒杀请求
./apache-jmeter-5.4.1/bin/jmeter.sh -n -t miaosha.jmx -l result.jtl
将result.jtl下载到windows上,通过jmeter聚合函数查看压测报告
4. Redis压测工具redis-benchmark
4.1 redis-benchmark -h 127.0.0.1 -p 6379 -c 100 -n 100000 -a 123456 100个并发请求,100000个请求, 密码为123456
4.2 redis-benchmark -h 127.0.0.1 -p 6379 -q -d 100 -a 123456 存取大小为100字节的数据包
4.3 redis-benchmark -t set,lpush -q -n 100000 -a 123456 测试set,lpush命令的QPS
4.4 redis-benchmark -n 100000 -q -a 123456 script load “redis.call(‘set’,‘foo’,‘bar’)” 测试脚本的QPS
5. SpringBoot打war包
5.1 添加spring-boot-starter-tomcat的provided依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<!--编译时依赖-->
<scope>provided</scope>
</dependency>
5.2 添加maven-war-plugin插件
<build>
<finalName>${project.artifactId}</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<configuration>
<failOnMissingWebXml>false</failOnMissingWebXml>
</configuration>
</plugin>
</plugins>
</build>
5.3 修改打包方式为war包
<packaging>war</packaging>
5.4 修改启动类
@SpringBootApplication
@MapperScan("com.hmx.miaosha.mapper")
public class MainApplication extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplication.run(MainApplication.class,args);
}
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
return builder.sources(MainApplication.class);
}
}
5.5 在当前文件夹下的cmd窗口中,运行mvn clean package命令
5.6 将war包放到本地tomcat的webapps目录中中并启动tomcat
可以通过localhost:8080/miaosha04/login/to_login访问到登录页面