最近接到的項目是在公司年會將有一個搖紅包的環節,公司共有一千人,每人可以領取十個紅包。這對於程序來說是一個不小的壓力吧,活動已經結束,效果很好。下面我來分享下我們Java後端採用的基本設計。
總體設計思路是: 多線程 + 併發隊列 + 數據庫(儘可能與微信少交互)
@WesApi
@RequestMapping(value = "/pay/bonusThread", method = RequestMethod.POST)
public String BonusAsync(@RequestBody String wxBody) throws Exception {
long time1 = System.currentTimeMillis();
logger.info("**********1*****************get body current time***************" + time1);
queue.offer(wxBody);
long time2 = System.currentTimeMillis();
WesBonusController.writeTime = time2;
logger.info("**********2*****************offer queue time ******************" + (time2-time1));
return "{\"return_code\":\"SUCCESS\"}";
}
真正的API 只有上面一個,原因很簡單,在各位打開企業號開始搖紅包那個過程,前端的訪問壓力非常的大,所以後端不可能進行同步代碼執行,因此我們的設計理念是每當前端post數據給後端時,API只做兩件事情 1、放入隊列 2、返回JSON字符串。
前面說到我們會採用多線程來開發,那麼很顯然需要一個線程來處理隊列中的數據。所以我們在Spring boot開啓時就會注入線程。
@Bean
public BonusThread returnBonusThread(){
thread.start();
return thread;
}
線程中的處理代碼如下:
public void run() {
while(true){
if(!WesBonusController.queue.isEmpty()){
logger.info("**************** queue size**********" +WesBonusController.queue.size());
String wxBody = WesBonusController.queue.poll();
try {
wxBody = URLDecoder.decode(wxBody);
WxBonus bonus = JsonUtils.jsonStr2Model(wxBody.trim(), WxBonus.class);
//get current time
long currentTime = System.currentTimeMillis();
// check from map time by userId
String userIdTime = WesBonusController.recodeUserTimeMap.get(bonus.getUserId());
if("".equals(userIdTime) || null == userIdTime){
// first
long getSuccessTime = sendBonus(bonus, wxBody);
// save time to success current time
WesBonusController.recodeUserTimeMap.put(bonus.getUserId(), String.valueOf(getSuccessTime));
}else if((Long.valueOf(userIdTime)+1000*60) < currentTime){
// can send bonus
long getSuccessTime = sendBonus(bonus, wxBody);
// update time to success current time
WesBonusController.recodeUserTimeMap.remove(bonus.getUserId());
WesBonusController.recodeUserTimeMap.put(bonus.getUserId(), String.valueOf(getSuccessTime));
}else if((Long.valueOf(userIdTime)+1000*60) >= currentTime){
// poll data to queue
WesBonusController.queue.offer(wxBody);
}
} catch (Exception e) {
e.printStackTrace();
}
}else{
try {
BonusThread.sleep(100);
sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
至於怎樣發送紅包的代碼可以參考我之前的微博。需要提下的是,在很大的訪問量壓力下,切記能將微信返回數據存入數據庫的一定要存入數據庫(建議Redis), 否則會很大程度影響用戶體驗。
需要轉載此文章需要徵得同意。謝謝!
上海地區有合適的開發工作可以加我。
微信ID: wangyan199366