【性能優化】秒殺系統性能優化初體驗
秒殺系統性能優化
優化之前的準備
在吞吐量、延遲和記憶體這三點中選擇我們業務的著重點。
例如本次這個系統,我認為應該更加註重吞吐量。(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。