最近接到的项目是在公司年会将有一个摇红包的环节,公司共有一千人,每人可以领取十个红包。这对于程序来说是一个不小的压力吧,活动已经结束,效果很好。下面我来分享下我们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