微信企業號如何在十分鐘內發送一萬個紅包

最近接到的項目是在公司年會將有一個搖紅包的環節,公司共有一千人,每人可以領取十個紅包。這對於程序來說是一個不小的壓力吧,活動已經結束,效果很好。下面我來分享下我們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();
				}
			}
		}
	}


由於需要while(true)因此需要在隊列爲空的情況下釋放CPU壓力。


至於怎樣發送紅包的代碼可以參考我之前的微博。需要提下的是,在很大的訪問量壓力下,切記能將微信返回數據存入數據庫的一定要存入數據庫(建議Redis), 否則會很大程度影響用戶體驗。


需要轉載此文章需要徵得同意。謝謝! 

上海地區有合適的開發工作可以加我。

微信ID: wangyan199366

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章