成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

高并發(fā)紅包整體設(shè)計(jì)方案

shenhualong / 2320人閱讀

摘要:記錄下整體的設(shè)計(jì)思路以及運(yùn)營(yíng)過(guò)程中的各種問(wèn)題。如果錢是負(fù)數(shù)了,還得從已生成的小紅包中抽取回來(lái)將紅包放入隊(duì)列之中創(chuàng)建紅包失敗,請(qǐng)檢查參數(shù)生產(chǎn)和之間的隨機(jī)數(shù),但是概率不是平均的,從到方向概率逐漸加大。

公司前段時(shí)間根據(jù)業(yè)務(wù)方需求需要做一個(gè)搶紅包的活動(dòng),網(wǎng)上也搜索了很多資料。記錄下整體的設(shè)計(jì)思路以及運(yùn)營(yíng)過(guò)程中的各種問(wèn)題。

產(chǎn)品需求:

1.紅包支持配置開始時(shí)間、結(jié)束時(shí)間、類型(隨機(jī)金額或固定金額)、單個(gè)最小紅包金額、單個(gè)最大紅包金額

2.可領(lǐng)取紅包的業(yè)務(wù)條件(根據(jù)業(yè)務(wù)信息指定某些滿足條件的人可以搶)

設(shè)計(jì)思路:

難點(diǎn)1:紅包算法(根據(jù)紅包配置最大、最小金額、數(shù)量生成符合條件的紅包集合)

因?yàn)榧t包有配置單個(gè)紅包的最大和最小金額,所以不能完全使用隨機(jī)分配的方式。

所以要求:

? ? * 單個(gè)紅包金額既要大于最小金額,又要小于最大金額
? ? * 根據(jù)紅包總金額和個(gè)數(shù)要正好將錢分完

* 單個(gè)紅包精確到分,也就是小數(shù)點(diǎn)后兩位

實(shí)現(xiàn)代碼:

    /*
    * @todo 設(shè)置隨機(jī)紅包金額
    * return array
    */
    public function setRandMoney()
    {
        $result = [];
        //取小數(shù)點(diǎn)后兩位將金額乘100
        $this->total = $this->total * 100;//紅包總金額
        $this->min = $this->min * 100;//單個(gè)紅包最小金額
        $this->max = $this->max * 100;//單個(gè)紅包最大金額
        //獲取紅包平均金額
        $average = $this->total / $this->num;

        for ($i = 0; $i < $this->num; $i++) {
        //因?yàn)樾〖t包的數(shù)量通常是要比大紅包的數(shù)量要多的,因?yàn)檫@里的概率要調(diào)換過(guò)來(lái)。
        //當(dāng)隨機(jī)數(shù)>平均值,則產(chǎn)生小紅包
        //當(dāng)隨機(jī)數(shù)<平均值,則產(chǎn)生大紅包
            if (rand($this->min, $this->max) > $average) {
        // 在平均線上減錢
                $temp = $this->min + $this->xRandom($this->min, $average);
                $result[$i] = $temp;
                $this->total -= $temp;
            } else {
        // 在平均線上加錢
                $temp = $this->max - $this->xRandom($average, $this->max);
                $result[$i] = $temp;
                $this->total -= $temp;
            }
        }
        // 如果還有余錢,則嘗試加到小紅包里,如果加不進(jìn)去,則嘗試下一個(gè)。
        while ($this->total > 0) {
            for ($i = 0; $i < $this->num; $i++) {
                if ($this->total > 0 && $result[$i] < $this->max) {
                    $result[$i]++;
                    $this->total--;
                }
            }
        }
      // 如果錢是負(fù)數(shù)了,還得從已生成的小紅包中抽取回來(lái)
        while ($this->total < 0) {
            for ($i = 0; $i < $this->num; $i++) {
                if ($this->total < 0 && $result[$i] > $this->min) {
                    $result[$i]--;
                    $this->total++;
                }
            }
        }
        if (!empty($result)) {
            //將紅包放入隊(duì)列之中
            foreach ($result as $val) {
                $this->redis->lPush($this->redpack_money_queue . $this->act_id, $val / 100);
            }
            return ["code" => "0", "msg" => "success"];
        }
        return ["code" => "1", "msg" => "創(chuàng)建紅包失敗,請(qǐng)檢查參數(shù)"];

    }


    /**
     * 生產(chǎn)min和max之間的隨機(jī)數(shù),但是概率不是平均的,從min到max方向概率逐漸加大。
     * 先平方,然后產(chǎn)生一個(gè)平方值范圍內(nèi)的隨機(jī)數(shù),再開方,這樣就產(chǎn)生了一種“膨脹”再“收縮”的效果。
     */
    private function xRandom($bonus_min, $bonus_max)
    {
        $sqr = intval($this->sqr($bonus_max - $bonus_min));
        $rand_num = rand(0, ($sqr - 1));
        return intval(sqrt($rand_num));
    }

    private function sqr($n)
    {
        return $n * $n;
    }

因?yàn)槿∽钚『妥畲蠼痤~之間隨機(jī)數(shù)的時(shí)候使用了intval()函數(shù)導(dǎo)致該算法只能處理整數(shù),故在處理的時(shí)候?qū)⒔痤~乘100 ,在最后入隊(duì)列的時(shí)候再將其 除100,這樣就將其精確到小數(shù)點(diǎn)后兩位。

難點(diǎn)2:高并發(fā)時(shí)對(duì)服務(wù)器的訪問(wèn)壓力
類似搶紅包、1元搶購(gòu),秒殺等業(yè)務(wù)場(chǎng)景都是在同一時(shí)間大量請(qǐng)求堆積到服務(wù)器,從而導(dǎo)致服務(wù)器資源緊張,程序處理不過(guò)來(lái)。那么我們要做的就是將流量控制住,不讓大量的請(qǐng)求透過(guò)web服務(wù)器直接打到數(shù)據(jù)庫(kù)層。那么從用戶訪問(wèn)url到收到返回結(jié)果整體流程是什么樣子呢?

客戶端層,用戶在微信中打開URL,DNS解析域名至服務(wù)器

web服務(wù)器層, Apache、Nginx或Tomcat等

服務(wù)器層,分配php-fpm進(jìn)程,代碼接收參數(shù)進(jìn)行邏輯處理

數(shù)據(jù)持續(xù)化層次,將結(jié)果保存至mysql或Redis層次

客戶端層優(yōu)化方案:(限流)

前端URL使用html靜態(tài)頁(yè)面顯示內(nèi)容,并將頁(yè)面顯示圖片盡量壓縮,減少服務(wù)器帶寬壓力。推薦使用base64解碼圖片

使用連接池控制流量,用戶點(diǎn)擊搶紅包時(shí),發(fā)起ajax請(qǐng)求,調(diào)用后臺(tái)使用java寫的redis incr 接口,每次調(diào)用則鍵值 +1,并將自增id返回,當(dāng)后臺(tái)代碼處理完后再將其鍵值減掉,因?yàn)?b>incr自增為原子級(jí)別,所以前端可以根據(jù)當(dāng)前有多少用戶在等待中。 根據(jù)自身服務(wù)器配置以及業(yè)務(wù)場(chǎng)景預(yù)估N多請(qǐng)求會(huì)導(dǎo)致服務(wù)器出現(xiàn)問(wèn)題,如果當(dāng)前等待處理的請(qǐng)求數(shù)大于N則前端提示用戶 "當(dāng)前請(qǐng)求過(guò)多,請(qǐng)稍后再試",反之則可以正常發(fā)起請(qǐng)求。


Web層優(yōu)化方案(lua+nginx實(shí)現(xiàn)頻率控制)

Nginx來(lái)處理訪問(wèn)控制的方法有多種,實(shí)現(xiàn)的效果也有多種,訪問(wèn)IP段,訪問(wèn)內(nèi)容限制,訪問(wèn)頻率限制等。

用Nginx+Lua+Redis來(lái)做訪問(wèn)限制主要是考慮到高并發(fā)環(huán)境下快速訪問(wèn)控制的需求。

Nginx處理請(qǐng)求的過(guò)程一共劃分為11個(gè)階段,分別是:

`post-read、server-rewrite、find-config、rewrite、post-rewrite、 preaccess、access、post-access、try-  files、content、log`.


在openresty中,可以找到:

`set_by_lua`,`access_by_lua`,`content_by_lua`,`rewrite_by_lua`等方法。

那么訪問(wèn)控制應(yīng)該是,`access`階段。


2.根據(jù)請(qǐng)求的ip段來(lái)控制訪問(wèn)流量,每次接收到搶紅包的url后將redis連接池中id自增,當(dāng)超過(guò)某個(gè)峰值時(shí)跳轉(zhuǎn)到等待頁(yè)。
具體配置方案參考:http://homeway.me/2015/08/11/...

php代碼層(防止出現(xiàn)發(fā)多、重復(fù)領(lǐng)取、權(quán)限等情況)

使用redis queue 隊(duì)列功能來(lái)控制超發(fā)的情況,將每個(gè)算出來(lái)的小紅包lpush至隊(duì)列中,每次收到請(qǐng)求后消費(fèi)最后一個(gè)小紅包,因?yàn)閞edis的的隊(duì)列為阻塞模式,所以當(dāng)隊(duì)列中為空時(shí)是不返回?cái)?shù)據(jù)的,也就可以保證出現(xiàn)并發(fā)時(shí)不會(huì)一個(gè)紅包分配給多人。

使用 redis list集合來(lái)控制重復(fù)領(lǐng)取的情況,每次接收到請(qǐng)求后將用戶id放置已領(lǐng)取的集合中(這點(diǎn)很重要,一定要在消費(fèi)隊(duì)列前放置集合中,要不會(huì)出現(xiàn)因?yàn)椴l(fā)導(dǎo)致重復(fù)領(lǐng)?。M(fèi)成功則跳出,反之則將其移出已領(lǐng)取集合。

因?yàn)闃I(yè)務(wù)需求處理起來(lái)很繁瑣,所以在活動(dòng)創(chuàng)建的時(shí)候就根據(jù)活動(dòng)規(guī)則將可領(lǐng)取的人員放置集合中,權(quán)限判斷可以使用待領(lǐng)取集合來(lái)控制。

以下為我的代碼實(shí)現(xiàn)(小菜一枚,大神勿噴)

   /*
    * @todo 獲取紅包金額
    * @return array
    */
    public function doRush()
    {
        $act_info = $this->getPackInfo($this->act_id);
        if(empty($act_info)){
            return ["code"=>"1","msg"=>"活動(dòng)信息錯(cuò)誤,請(qǐng)聯(lián)系管理員"];
        }
        if($act_info["start_time"] > now()){
            return ["code"=>"2","msg"=>"紅包尚未開搶,請(qǐng)稍后再試"];
        }

        if($act_info["end_time"] <= now()){
            return ["code"=>"1","msg"=>"活動(dòng)已結(jié)束"];
        }
         //將請(qǐng)求用戶先放置已領(lǐng)取的集合中
        if(!$this->redis->sAdd($this->rushed_list_key,$this->user_id)){
            return ["code"=>"1","msg"=>"每個(gè)紅包只能領(lǐng)取一次哦"];
        }
        $money = $this->redis->lPop($this->redpack_money_queue);
        if(empty($money)){
            $this->redis->sRem($this->rushed_list_key,$this->user_id);
            return ["code"=>"1","msg"=>"您來(lái)完了呦,紅包已搶光"];
        }

        //將已搶的用戶和金額記錄至隊(duì)列中
        $add_res = $this->amountAdd($money);
        if($add_res["code"] != 0){
            return ["code"=>"1","msg"=>"系統(tǒng)繁忙,請(qǐng)稍后再試"];
        }
        return ["code"=>"0","msg"=>"success","data"=>$money."元"];

    }

數(shù)據(jù)層(使用異步持續(xù)化)

用戶領(lǐng)取成功后,將用戶id及領(lǐng)取的金額存至已領(lǐng)取的redis queue中,異步進(jìn)程根據(jù)其中的user_id和money值將其數(shù)據(jù)更新至mysql表中

--------------------------------------------------我是萬(wàn)惡的分割線------------------------------------------------------------------

補(bǔ)充說(shuō)明:
本人第一次將實(shí)際開發(fā)過(guò)程以及想法落實(shí)到書面上,對(duì)于我這種小菜來(lái)說(shuō)已經(jīng)很不錯(cuò)了,懇求各位大神勿噴。其中紅包算法和一些處理方案也是第一次接觸,參考了網(wǎng)上很多資料,學(xué)到了很多。如果你有更好的方案的話多多交流~~

                                                                                                                                ----PHP小菜一枚------





文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/30748.html

相關(guān)文章

  • 并發(fā)紅包整體設(shè)計(jì)方案

    摘要:記錄下整體的設(shè)計(jì)思路以及運(yùn)營(yíng)過(guò)程中的各種問(wèn)題。如果錢是負(fù)數(shù)了,還得從已生成的小紅包中抽取回來(lái)將紅包放入隊(duì)列之中創(chuàng)建紅包失敗,請(qǐng)檢查參數(shù)生產(chǎn)和之間的隨機(jī)數(shù),但是概率不是平均的,從到方向概率逐漸加大。 公司前段時(shí)間根據(jù)業(yè)務(wù)方需求需要做一個(gè)搶紅包的活動(dòng),網(wǎng)上也搜索了很多資料。記錄下整體的設(shè)計(jì)思路以及運(yùn)營(yíng)過(guò)程中的各種問(wèn)題。 產(chǎn)品需求: 1.紅包支持配置開始時(shí)間、結(jié)束時(shí)間、類型(隨機(jī)金額或固定金...

    cheukyin 評(píng)論0 收藏0
  • 并發(fā)紅包整體設(shè)計(jì)方案

    摘要:記錄下整體的設(shè)計(jì)思路以及運(yùn)營(yíng)過(guò)程中的各種問(wèn)題。如果錢是負(fù)數(shù)了,還得從已生成的小紅包中抽取回來(lái)將紅包放入隊(duì)列之中創(chuàng)建紅包失敗,請(qǐng)檢查參數(shù)生產(chǎn)和之間的隨機(jī)數(shù),但是概率不是平均的,從到方向概率逐漸加大。 公司前段時(shí)間根據(jù)業(yè)務(wù)方需求需要做一個(gè)搶紅包的活動(dòng),網(wǎng)上也搜索了很多資料。記錄下整體的設(shè)計(jì)思路以及運(yùn)營(yíng)過(guò)程中的各種問(wèn)題。 產(chǎn)品需求: 1.紅包支持配置開始時(shí)間、結(jié)束時(shí)間、類型(隨機(jī)金額或固定金...

    Freeman 評(píng)論0 收藏0
  • 大話后端開發(fā)的奇淫技巧大集合

    摘要:,大家好,很榮幸有這個(gè)機(jī)會(huì)可以通過(guò)寫博文的方式,把這些年在后端開發(fā)過(guò)程中總結(jié)沉淀下來(lái)的經(jīng)驗(yàn)和設(shè)計(jì)思路分享出來(lái)模塊化設(shè)計(jì)根據(jù)業(yè)務(wù)場(chǎng)景,將業(yè)務(wù)抽離成獨(dú)立模塊,對(duì)外通過(guò)接口提供服務(wù),減少系統(tǒng)復(fù)雜度和耦合度,實(shí)現(xiàn)可復(fù)用,易維護(hù),易拓展項(xiàng)目中實(shí)踐例子 Hi,大家好,很榮幸有這個(gè)機(jī)會(huì)可以通過(guò)寫博文的方式,把這些年在后端開發(fā)過(guò)程中總結(jié)沉淀下來(lái)的經(jīng)驗(yàn)和設(shè)計(jì)思路分享出來(lái) 模塊化設(shè)計(jì) 根據(jù)業(yè)務(wù)場(chǎng)景,將業(yè)務(wù)...

    CloudwiseAPM 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

閱讀需要支付1元查看
<