【性能优化】秒杀系统性能优化初体验
秒杀系统性能优化
优化之前的准备
在吞吐量、延迟和内存这三点中选择我们业务的着重点。
例如本次这个系统,我认为应该更加注重吞吐量。(PS:我也是第一次,凭感觉来的……)
为什么更加注重吞吐量?
延迟:像我们大家平时去进行商品抢购的时候,应该都会觉得现在人太多了,卡一卡没什么问题(但是也不能太久,你给我直接来个10s,肯定给你差评),只关心的是最后我有没有抢到商品。所以我认为延迟这方面应该是其次,主要的是系统处理请求的数量。
内存占用:一般秒杀活动都会有时间限制,这段时间也不会占用太大的内存。我电脑16G也不用担心,如果真的内存很缺少,可以考虑考虑。
代码优化
将写入Redis缓存代码与数据库事务分开
防止网络抖动可能导致写缓存响应时间较慢,阻塞数据库事务。
原始代码:
/**
* 下订单、减库存事务(原始代码)
*/
@Transactional
public void seckillTransaction(SeckillDto seckillDto, GoodDto goodDto){
//添加订单操作......
//减库存操作......
//写入缓存,不用再调用数据库判断是否还能继续抢购
if (goodDto.getSurplusCount() <= 0){
redisTemplate.delete(seckillDto.getGoodId().toString());
redisTemplate.opsForValue().set(seckillDto.getGoodId().toString(), JSONObject.toJSONString(goodDto), 320, TimeUnit.SECONDS);
}
}
修改后:
public boolean seckillGood(SeckillDto seckillDto) {
// ......
if (goodDto.getSurplusCount()>0){
//执行下单 、 减库存事务
seckillTransaction(seckillDto, goodDto);
//写入缓存,不用再调用数据库判断是否还能继续抢购
if (goodDto.getSurplusCount() - 1 <= 0){
redisTemplate.delete(seckillDto.getGoodId().toString());
redisTemplate.opsForValue().set(seckillDto.getGoodId().toString(), JSONObject.toJSONString(goodDto), 320, TimeUnit.SECONDS);
}
}
// ......
}
/**
* 下订单、减库存事务(修改后)
*/
@Transactional
public void seckillTransaction(SeckillDto seckillDto, GoodDto goodDto){
log.info("seckillTransaction已调用");
//添加订单操作......
//减库存操作......
}
数据库相关优化
因为没弄很多数据,SQL语句也挺简单的,就不考虑那么多了。重点考虑连接池的参数设置。
连接池优化
我的电脑CPU是8核的。因为数据库连接算IO操作,所以我们将连接数在16左右进行调节。
使用的是dbcp2连接池:
max-wait-millis:最大等待时间
initial-size:连接池启动时创建的初始化连接数量
max-total:最大连接数
min-idle:最小空闲连接
max-idle:最大空闲连接
场景:100个请求同时对数据库进行抢购(下订单、减库存)操作,10个商品。开启了事务。
默认情况下,不配置连接参数。initialSize = 0,minIdle = 0。
连接数为16。initialSize = 16,minIdle = 16。
连接数为10。initialSize = 10,minIdle = 10。
连接数12。initialSize = 12,minIdle = 12。
连接数13。initialSize = 13,minIdle = 13。
TP95 | TP99 | 吞吐量 | |
---|---|---|---|
默认 | 2671 | 2694 | 104.2 |
连接数12 | 2408 | 2431 | 114.5 |
上面的数据可以测试数据可以看出:配置了连接数之后整体操作TP99下降了260ms,吞吐量也增加了10/s。