記錄可滿足10W人同時在線 1W併發的紅包雨活動實現過程

場景描述:

跨年紅包雨活動,分爲五場,2018-12-31 20:00以後每個整點一場,每場紅包雨持續1分鐘。

有以下幾個問題需要思考

 

思考一:10W人同時使用系統保證服務正常

從某雲購買負載均衡SLB 10臺 按量付費 規格是標準型2  按使用流量計費

nginx服務器,前端頁面一定要用靜態頁面實現

 

思考二:如何保證獎品發出數量<=總獎品數量。

把所有的獎品按照單個獎品的總數平均分配到10臺服務器,每臺服務器上的單個獎品在平均分爲5場

把以上分配好的獎品生成記錄插入數據庫。如某優惠券有100個:平均每臺服務器上分10個,平均每臺服務器上的每場分2個獎品,生成100條記錄插入數據庫,每條記錄有對應的服務器編號,場次編號,獎品id等信息。

後臺語言java實現,每場獎品數據隨機打亂放入隊列中。每來一個請求,若中獎,則從隊列中移除該獎品,同時把該用戶的中獎信息保存到redis。涉及到線程安全問題,一定要做好。保證一個機器上的某一場的某個獎品不會被多個人同時中獎。

負載均衡一定要設置ip進入的規則“輪詢”,把每個請求按順序逐一分配到不同的server,保證每臺服務器上的獎品都能被均勻領到。

 

思考三:程序的靈活性,如何控制每場開始時間、獎品數量、中獎機率等等。

機器編號如何生成?不應該打10個包,每個包配置一個服務器編號,假如有100個不是要瘋了?

可以用redis的自增方法,每啓動一臺服務獲取key的值後保存到內存中,並且對該key的value+1操作。

提供接口,可以隨時更改中獎機率和設置開始時間等等,每場間隔一個小時,有足夠時間執行下一場的操作。

......

抽獎方法的核心代碼:

public String init(@PathVariable(value = "openId") String openId) {
        // 本地緩存
        Repository repo = Repository.instance;

        // 一輪結束
        if (repo.endFlag > 0) {
            return ResultUtil.error(201, blessArr[(int) (Math.random() * blessArr.length)]);
        }
        // 查看當前獎勵是否開始
        if (System.currentTimeMillis() < repo.prizeStart) {
            return ResultUtil.error(201, blessArr[(int) (Math.random() * blessArr.length)]);
        }

        // 直接比較,不用任何變量,如果數值超過128不能用==比較
        if (repo.prizeNum != (int) (Math.random() * repo.prizeRate)) {
            // 不要使用Exception的機制,內存和時間消耗很大
            return ResultUtil.error(201, blessArr[(int) (Math.random() * blessArr.length)]);
        }

        // 將中獎信息保存到緩存(setNX排他) 獎品批次:openId : 獎品內容(需要序列化,這裏用toString代替)
        PeAcHbyPrize prize;
        if (redisUtil.incr("flag:" + repo.prizeGroup + openId, 1) <= repo.prizeCount) {
            // 取得獎品
            prize = repo.pollPrize();
            if (null == prize) {
                // 在本服務器上沒獎,可能在別的服務器還有,要回退中獎次數
                redisUtil.decr("flag:" + repo.prizeGroup + openId, 1);
                return ResultUtil.error(201, blessArr[(int) (Math.random() * blessArr.length)]);
            }
            redisUtil.lSet("prize:" + repo.prizeGroup + openId, JSONObject.toJSONString(prize));
        } else {
            return ResultUtil.error(201, blessArr[(int) (Math.random() * blessArr.length)]);
        }
        log.info("{}--{}", openId, prize.getId());
        return ResultUtil.success(prize);// 成功
    }

 

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