欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

PHP没有数据库连接池怎么破?PHP环境下使用Nginx ngx_http_limit_req_module模块的高负载解决方案

程序员文章站 2023-01-30 09:17:01
线上运行了一套辅助是利用了开源的php改的,之前也没怎么玩过php,没想到这玩意儿还是有不少坑的。突然某一天一个用户做线上活动,然后短时间内涌进来了上万的请求,然后连接耗尽,短时间内几乎拖垮了整个系...

线上运行了一套辅助是利用了开源的php改的,之前也没怎么玩过php,没想到这玩意儿还是有不少坑的。突然某一天一个用户做线上活动,然后短时间内涌进来了上万的请求,然后连接耗尽,短时间内几乎拖垮了整个系统。导致系统奔溃的有多方面原因,今天主要针对php没有数据库连接池的原因来分析。

在php里,数据库连接在请求到达时建立,请求结束时释放。如果同时几千个请求到达,那就同时会建立几千个数据库连接,非常恐怖。而且php木有比较好的数据库连接池驱动方案,所以我们得另想办法。

解决这种问题有三种办法:
1.使用mysql proxy中间件。mysql proxy提供了连接池管理的功能。但是我们没有采用此方法,因为情况紧急,没有人熟悉这玩意儿。
2.使用php-fpm。php-fpm是php的一个fastcgi进程管理器。通过配置可以控制同时处理php请求的进程数。
具体可以参考:http://www.linuxde.net/2013/06/14638.html
但是我们也没用使用此方案,因为安装配置过程比较麻烦。
3.使用nginx的ngx_http_limit_req_module来控制请求。
此模块可以通过自定义的键值来限制请求频率。限制的方法就像漏斗,每秒固定处理请求数,然后推迟超出的请求,最后超出最大值的直接503返回拒绝。
我们使用了此方案,是因为只需简单配置,而且可以灵活控制限制请求的场景。例如,对于静态资源的请求我们不做限制,而对于php的请求做限制。还可以从url地址里提取出变量信息作为键,来达到更细的请求限制。
下面贴部分我们的配置给大家讲解下。

http {
    ......
    limit_req_zone $limit_key zone=limit_one:50m rate=30r/s;
    #定义limit_key为key的变量名,用于后面赋值,每个key都有自己的计数器。limit_one为zone的名称。rate表示每秒最多接受30个同时请求。
    server {
        ......
        if ( $request_uri ~* .*php.* ) {
              set $mp_limit_key $binary_remote_addr;
              #对于全部php首先有个默认的key,使用客户端的ip作为key。相当于每个客户端ip都会在zone的限制内。
         }
        if ( $query_string ~* .*id/(d+).php.* ) {
              set $mp_limit_key $1;
              #提取id后面的值作为key。
        }
        if ( $query_string ~* .*appid/wx(.*).html.* ) {
              set $mp_limit_key $1;
              #提取appid作为key。
        }
        limit_req zone=limit_one burst=200;
        #限制limit_one在此server内的漏斗容量为200。假设一个key对应的请求数为200,那么第一秒内在处理的为30个请求,其余的170个请求在等待排队。假设一个key对应的请求数为300,那么超出200的部分将直接返回503。
        .......
    }
}