H5活動抽獎

本文講解內容

針對兩類發獎需求的四種抽獎邏輯及細節redis

通常H5抽獎活動的發獎需求分爲

1.必定中獎(獎品庫存不空的狀況下)
2.不必定中獎sql

發獎接口的最終實現要求

1.獎品不超發
2.惟一獎品單次發放
3.對併發有必定的限制併發

接口實戰

1.根據獎品開放時間進行抽獎app

public function award($openid)
    {
        $award = Award::find()->where(['openid' => ''])
            ->andWhere(['>', 'open_at', 0])->andWhere(['<', 'open_at', time()])
            ->orderBy('open_at ASC')->limit(1)->one();
        if (!empty($award)) {
            $res = Award::updateAll(
                [
                    'openid' => $openid
                ],
                'code = :code AND openid = :openid',
                [
                    ':code' => $award['code'],
                    ':openid' => ''
                ]
            );
            if ($res) {
                return ArrayHelper::toArray($award);
            }
        }
        return [];
    }

這種方式,多用戶併發狀況下,會出現多個用戶相同獎品,因爲update語句限制,拿到相同獎品碼的用戶中只有一人能中得獎品。this

2.在開放時間的基礎上加上類型機率code

public function randAward($openid)
    {
        $number = rand(0, 100);
        $type = 5;
        if ($number < 10) {
            $type = 1;
        } else if ($number < 30) {
            $type = 2;
        } else if ($number < 70) {
            $type = 3;
        } else if ($number < 80) {
            $type = 4;
        }
        $award = Award::find()->where(['openid' => ''])
            ->andWhere(['>', 'open_at', 0])->andWhere(['<', 'open_at', time()])
            ->andWhere(['type' => $type])
            ->orderBy('open_at ASC')->limit(1)->one();
        if (!empty($award)) {
            $res = Award::updateAll(
                [
                    'openid' => $openid
                ],
                'code = :code AND openid = :openid',
                [
                    ':code' => $award['code'],
                    ':openid' => ''
                ]
            );
            if ($res) {
                return ArrayHelper::toArray($award);
            }
        }
        return [];
    }

這種方式,也會出現多個用戶相同獎品,但加上type限制後,用戶被分散在各個類型中,未中獎機率會比上面的例子低。索引

3.利用Redis獎品池的概念進行發獎接口

public function redisAward($openid)
    {
        try {
            $redis = \Yii::$app->redis->client();
            $code = $redis->LPop(self::AWARD_LIST_KEY);
        } catch (Exception $err) {
            return [];
        }
        $res = Award::updateAll(
            [
                'openid' => $openid
            ],
            'code = :code AND openid = :openid',
            [
                ':code' => $code,
                ':openid' => ''
            ]
        );
        if ($res) {
            $award = Award::find()->where(['code' => $code])->limit(1)->one();
            return ArrayHelper::toArray($award);
        }
        return [];
    }

這種利用預先生成獎品池的方式,獎品池不空的狀況下,每一個用戶都會取走不一樣獎品碼,要注意的是 前期生成獎品池及後期操做獎品池時,防止獎品碼複用it

4.根據獎品開放時間(類型)進行抽獎,換成用sql語句進行發獎io

public function sqlAward($openid)
    {
        $sql = "UPDATE award SET openid = :openid 
                WHERE open_at > 0 AND openid = '' AND open_at < :time
                ORDER BY open_at ASC LIMIT 1";
        $res = \Yii::$app->db->createCommand($sql, [':time' => time(), ':openid' => $openid])->execute();
        if ($res) {
            return Award::find()->where(['openid' => $openid])->limit(1)->asArray()->one();
        }
        return [];
    }

必定中獎需求下,建議採用Redis獎品池或者sql語句進行update
以上四種方式在多用戶併發的狀況下帶來不同的結果

除了多用戶併發,還會出現惡刷狀況,就是同一用戶併發請求
這種狀況應該在真正進入抽獎邏輯以前進行限制

能夠根據實際需求搭配如下方式進行限制

public function actionAward()
    {
        $openid = 'okjkLj7-UL4gXknY9bDkFn0O6Jos';
        $redis = \Yii::$app->redis->client();
//            用戶單次數
        if (!$redis->sAdd(self::USER_LIST_KEY, $openid)) {
            return [];
        }
        return $this->sqlAward($openid);
    }

也能夠限制抽獎人數

public function actionAward()
    {
        $openid = CommonTool::randString(32);
        try {
            $redis = \Yii::$app->redis->client();
//            抽獎用戶數量
            $list = $redis->sMembers(self::USER_LIST_KEY);
            if (count($list) > 1000) {
                return ;
            }
        } catch (Exception $err) {

        }
        $award = $this->sqlAward($openid);
    }

寫在最後的最後

H5活動抽獎接口須要注意幾點1.檢查用戶有效性2.限制單用戶訪問次數3.使用機率讓用戶分流,從而控制真正進入抽獎邏輯的請求4.記錄抽獎領獎等相關操做的時間設備IP等..5.控制獎品的分佈(時間,插空,機率等)6.作好索引關係

相關文章
相關標籤/搜索