秒杀百万并发散发型思考方案

秒杀百万并发散发型思考方案

此方案是引用今日头条的一个大牛的方案,不是我想的,我只是熟悉一下制作流程

  1. 最可爱的c端限制方法,每一个进来的直接标识一个随机数,1-100随机一个数,11就让执行下面的流程。这样直接100w编程1w并发,开枪3秒后直接全部不成功。感觉如果这个放在pc端最好加密一下,移动端可能还好点。
  2. Nginx的反向代理层,用以上相同的思路进行。检测某个请求参数,存1/10的通过率,其他返回已抢完。这样并发进入服务器只有1000

①找了很久的资料因为不是专门做这个nginx的没有太多的头绪,网上的资料不是很准确,因为自身能力无法正确锁定搜索词,后来想了想可以这样实现。首先找怎么搞随机数,然后判断是否是11,写一个if,最后输出给路径

②开始我们执行api赋值,因为随机数及时生成也需要验证。那么开始

    #BEGIN

    location /api/ceshi/index

    {

        set $args "a=1&b=2";

        proxy_pass http://xx.xxxxx.com/api/ceshi/index;

    }

    #END

测试输出api  444 502 失败,不太明白哪里错了,再次测试 直接跳转不加参数

    location /ceshiaa

    {

        set $args "a=1&b=2";

        proxy_pass http://xx.xxxxx.com/api/ceshi/ceshi;

    }

猜测可能是我的php文件中的接入写错了,测试直接使用$this->request()输出测试(我用的是tp6

多次测试结果,不是tp的写法问题,是api/ceshi/index的问题可能是写法不对,再次测试,对了这个走的路径是GET方式

测试过程中几次中断,刚才还好改了几下就不行了,结论,最好重载nginx配置,可能缓存问题导致的。

 

测试发现这个location是不能写和下面接口一样的,eee,好吧孤陋寡闻了。

那么修改为ceshixx可以实现,那个http://这个网址是否可以换成别的我在想办法把,我用的bt面板,所以可以在网站哪里,直接修改配置文件,xx.xxxxx记得换成你们自己的

    

#BEGIN

    location =/ceshixx

    {

        set $args "a=1&b=2";

        proxy_pass http://xx.xxxxx.com/ceshi/ceshi/ceshi;

    }

  #END

输出正常,如果测试几个总不出来,可能是nginx缓存问题,重载配置,等一下应该就好了。

那么下面我开始写随机数和判断。

找了很多网上的资料有一个是安装插件然后去随机生成的需要set好几下,我就去搜了一下他的那个压缩包的名字,也没有什么好看的资料,后来我翻了一下bt中的server中的nginx,看到了lua这个几个字,nginx好像是可以调用lua的那么测试了一下这个

 

成功输出随机数,那么一个问题,这样调用在高并发的情景下,合适吗?查询了一些资料都在解释,高并发状态nginx调用lua是可以解决部分场景的就是说应该可以这样用。累死。。

下面综合执行

上面只是输出了一个随机数,但是要调用判断,还是不会,经过找了几个小时资料终于执行成功

 

这个也有点问题,就是不支持中文好像,只能写个bushi

那么下面开始组合使用

 

 

还是500说明这样行,在block执行nginx的写法是不行的,再去找找

If 这东西记得放一个空格 我草

经过查找资料终于实现部分功能我草,据说这样使用set_by_lua的方式是不太好的,如果以后使用请找服务器端给你写个lua然后用content_by_lua_block的方式给你引进来吧

 

下面再次开始执行跳转,这里成功了,也出现了几个问题,proxy_pass不能出现在if里面,charset如果不设置,输出text/html就乱码了,但是json没事

 

    #BEGIN

    location =/ceshixx

    {

      #设置content type

      default_type application/json;

      #charset utf-8;

      set_by_lua $rd '

        local a = math.random(10)

        return a;

      ';

      if ($rd != '1') {

        return 201 '{"status":"success","result":"已经卖完了","code":"201"}';

      }

      set $args "a=1&b=2";

      proxy_pass http://xx.xxxxx.com/ceshi/ceshi/ceshi;

    }

    #END

 

  1. 程序入口来一个布隆过滤器

解释一下布隆过滤器,

①使用hash的方式进行判定输入的是否已经存在(输入过)

public function index(){

    dump($this->JSHash("ceshi1"));

    dump($this->ELFHash("ceshi1"));

    dump($this->FNVHash("ceshi1"));

}

    /**

     * Justin Sobel编写的按位散列函数

     */

    public function JSHash($string, $len = null)

    {

        $hash = 1315423911;

        $len || $len = strlen($string);

        for ($i=0; $i<$len; $i++) {

            $hash ^= (($hash << 5) + ord($string[$i]) + ($hash >> 2));

        }

//        var_dump(($hash % 0xFFFFFFFF) & 0xFFFFFFFF);die;

        return ($hash % 0xFFFFFFFF) & 0xFFFFFFFF;

    }

    /**

     * 类似于PJW Hash功能,但针对32位处理器进行了调整。它是基于UNIX的系统上的widley使用哈希函数。

     */

    public function ELFHash($string, $len = null)

    {

        $hash = 0;

        $len || $len = strlen($string);

        for ($i=0; $i<$len; $i++) {

            $hash = ($hash << 4) + ord($string[$i]); $x = $hash & 0xF0000000; if ($x != 0) { $hash ^= ($x >> 24);

            }

            $hash &= ~$x;

        }

//        var_dump(($hash % 0xFFFFFFFF) & 0xFFFFFFFF);die;

        return ($hash % 0xFFFFFFFF) & 0xFFFFFFFF;

    }

 

       /**

     * 参考 http://www.isthe.com/chongo/tech/comp/fnv/

     */

    public function FNVHash($string, $len = null)

    {

        $prime = 16777619; //32位的prime 2^24 + 2^8 + 0x93 = 16777619

        $hash = 2166136261; //32位的offset

        $len || $len = strlen($string);

        for ($i=0; $i<$len; $i++) {

            $hash = (int) ($hash * $prime) % 0xFFFFFFFF;

            $hash ^= ord($string[$i]);

        }

//        var_dump(($hash % 0xFFFFFFFF) & 0xFFFFFFFF);die;

        return ($hash % 0xFFFFFFFF) & 0xFFFFFFFF;

    }

②这三个选一个使用

看了很多网上的描述其实,布隆过滤简单来说就是用hash的方式把传入的一种规定的格式转换成int的不重复整数串。

其实这个实现方式到了这里已经很简单了,其实好多应用其实已经应该是封装好的了。

https://learnku.com/articles/35803

用这个吧挺好用的 判断和事务都有了

要不就搜索布隆过滤器php等关键词基本都一样,这个看的还好。

set的删除还是比较麻烦的嵌入塞进去,也挺麻烦。然后直接设置shell过一个条件,然后执行删除相应的库得了,这个里面可以选一个特用的库,记得别删错了。Select()一定记得要不删了常用的 不笑了吗?

 

这个是三重选择,就是直接全部判断三种是否都没有 那么就是没有了,其实到这里的需求已经很小了。

  1. 库存为零,程序入口拦截请求。

在程序初始的地方进行判断一个此次活动的redis标识是否存在,如果存在返回已经抢完,如果没有执行下面的程序。

  1. 如果客户没有购买,那么可以在执行前设置一个redis参数 购买个数 如果少一个就用decr 多一个就用incr45可以并起来。
  2. 数据在确认订单的时候就需要插入数据库了,如果redis爆了,兹,返回抢完把,要不就集群,1000并发单机基本可以了,前端页面的秒杀多几项确认,就可以顺带拉开sql的执行。

 

posted @ 2021-05-07 11:21  tiantian啊  阅读(80)  评论(0)    收藏  举报