Linux之统计ip排行

面试或者笔试中,经常会出现一道题,那就是,统计nginx日志中,访问量前N个的IP地址。

自问我对Linux还算是比较了解,知道过几个命令,但是组装起来用,确实是一门学问。

以下是我盲写的执行结果

执行结果,好像并不进入人意,不可能访问量最高的ip是9次。

上面的命令拆分起来,可以理解为:

打印第一列->去重,并且统计->倒叙排列->取前10条

看起来,好像没什么问题,但是问题出在了uniq上面了

uniq其实只用了去掉相邻的重复记录的,也就是,我们在使用uniq的时候,其实是应该先按照排序,然后再进行去重操作

改正后的命令如下

相比起前一个命令,第2个sort还增加了 -n,这是因为,我们使用uniq的时候,进行了计数,我们再根据计数(-n)进行倒叙排列(-r),最后前10条(head -10)记录.

Linux自定义PHP的环境变量

很多时候,我们会使用 PHP的$_SERVER数组,通过这个数组,可以获取一些服务器的变量信息。但是不同的模式下,这个全局数组是不一样的。比如,在web模式下,$_SERVER 是获取的fastcgi_params,在cli模式下,获取的是环境变量(也就是常见的Linux 的export设置的)

举个例子,我们要设置$_SERVER[‘AAAAA’]=’test_data’

刚开始,不管web模式下,还是cli模式下,都是没有这个值的。

web模式

cli模式

更改nginx 的环境变量

找到fastcgi_params文件,一般是和nginx.conf在同一个目录,

$ sudo nginx -s reload 

然后刷新页面

更改cli模式先的环境变量

$ vim ~/.bashrc

$ source ~/.bashrc
$ php -r 'var_dump($_SERVER["AAAAA"]);';

一次由于curl调用https接口导致的502

背景描述

最近在调研百度人脸识别的服务,百度的人脸识别是免费的,但是有QPS的限制,QPS免费的最大值是5,也就是峰值在每秒5次,都是可以免费使用的。我从百度平台下载的SDK,但是到了第一步就被卡主了。

当我使用检测接口的时候,频繁出现 502。在之前,本地运行PHP的时候,也会偶尔出现502,但是并没有这么高。这次变态的浮现率是100%.

查了下nginx日志*173 upstream prematurely closed connection while reading response header from upstream, client: 127.0.0.1, server: sdeno-api, request: "GET /facev1/test HTTP/1.1", upstream: "fastcgi://127.0.0.1:9000"

在网上查了一下,说什么的都有,大多数是在说nginx的问题。没有一个能够解决问题。

发现问题

我发现,出现http 502 的接口使用了curl,所以很可能是curl代码有问题。我自己有写了一段代码,调用百度首页http://www.baidu.com,咦?正常返回啊。完全没有问题。后来百度查了很多,最终发现一个不起眼的问题 php curl 调用https出现502问题。我验证了一些,我曹,果然只有https接口是不正常的。

解决办法

后来找到了一个靠谱的方法,那就是使用sudo重启php-fpm.

$ brew services stop php53
$ sudo brew services start php53

其实除了这样,还可以考虑下重装或者升级PHP的版本。我把本地的php5.3卸载了,重新安装了php5.6也解决了问题。

$ brew uninstall php53
$ brew install php56

关于limit_req和limit_conn的区别

request和connection区别

在nginx里面,limit_req和limit_conn都是用来限流的但是两者不在一个层次上,在此之前,需要先清楚request和connect的区别。
request是请求,是http层面的。connection是链接,指的是tcp层面。所以,从含义上面可以知道两者不在一个层次。
我们在打开一个网页的时候,请求过程一般就是先经过tcp三次握手,然后在进行http请求。也就是一个connection建立之后,可以有很多request。

一个connection建立,只要服务器处理的过来,可以处理任意多的request都是没有问题的

好了,现在知道区别了。

limit_conn

http {
    limit_conn_zone $binary_remote_addr zone=one:20m;
    limit_conn one 1; #最多可以进行1个connection
    client_body_buffer_size 256M;
    include       mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for" "$request_filename"';
    sendfile        on;

    keepalive_timeout  65;
    include servers/*.conf;
}

上面的配置文件的含义很明白,nginx只接受最多一个connect,我们使用ab命令查看下

$ ab -n10  http://sdeno-api/info/php #默认通过一个connect送10个request

从截图看来,在一个并发下,处理10个request下完全没有问题

接下来我们使用2个并发,2个请求试下,也就是两个用户,每个用户发送一个request

$ ab -n2 -c2 http://sdeno-api/info/php

从截图中可以看到,由于nginx设置了至多限制一个并发,所以导致两个用户的请求只能有一个被处理掉,另外一个返回http 503

limit_req

下面更改下nginx.conf配置文件

http {
    limit_conn_zone $binary_remote_addr zone=one:20m;
    limit_req_zone $binary_remote_addr zone=req_one:20m rate=1r/s;
    limit_conn one 20;
    limit_req zone=req_one burst=5;
    client_body_buffer_size 256M;
    include       mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for" "$request_filename"';
    sendfile        on;

    keepalive_timeout  65;
    include servers/*.conf;
}

上面的配置的含义是请求速率限制为1r/s,然后再缓存5个request,然后再依次处理请求(令牌桶算法)

$ ab -n10 -c10 http://sdeno-api/info/php

我们使用压测命令,10个并发,10个请求,根据配置的文件,当有请求过来,nginx先处理一个请求,然后将5个请求缓存下来(burst=5),根据设置的速率1r/s进行处理,也就是一共能够处理6个请求,其余的请求则被丢掉。

接下来我们再继续更改下nginx配置文件

$ ab -n10 -c10 http://sdeno-api/info/php
http {
    limit_conn_zone $binary_remote_addr zone=one:20m;
    limit_req_zone $binary_remote_addr zone=req_one:20m rate=1r/s;
    limit_conn one 20;
    limit_req zone=req_one burst=5 nodelay;
    client_body_buffer_size 256M;
    include       mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for" "$request_filename"';
    sendfile        on;

    keepalive_timeout  65;
    include servers/*.conf;
}

咦?增加了nodelay好像和不加有点不同。这是因为请求过来的时候,会爆发出一个峰值的处理能力,处理的总的请求数是burst+1,其余的请求丢弃。

总结

  • request和connect是完全不同层面的含义,一个属于http,一个属于tcp

  • limit_req zone=req_zone burst=5 依照在limti_req_zone中配置的rate来处理请求,同时设置了一个大小为5的缓冲队列,在缓冲队列中的请求会等待慢慢处理,超过了burst缓冲队列长度和rate处理能力的请求被直接丢弃,表现为对收到的请求有延时

  • limit_req zone=req_zone burst=5 nodelay 依照在limti_req_zone中配置的rate来处理请求,同时设置了一个大小为5的缓冲队列,当请求到来时,会爆发出一个峰值处理能力,对于峰值处理数量之外的请求,直接丢弃。

参考文献

使用Nginx实现流量限流

Nginx是高性能的http服务器,同时也可以作为一个反向代理的服务器,甚至还可以作为一个IMAP/pop3/SMTP服务器。Nginx除了负责请求的负载均衡和分发等工作外,自带的限流模块也可以帮助运维人员限制流量的速率。

更改配置

开启Nginx的限流功能

http {
    #定义每个IP的session空间大小
    limit_conn_zone $binary_remote_addr zone=one:20m;
    #与limit_conn_zone类似,定义每个允许发起的请求速率
    limit_req_zone $binary_remote_addr zone=req_one:20m rate=1r/s;
    #定义每个IP发起的并发连接数
    limit_conn one 10;
    #缓存还没来得及处理的请求
    limit_req zone=req_one burst=100;

    #rewrite_log on;
    #error_log /var/log/nginxrewrite.log notice;
        client_body_buffer_size 256M;
        include       mime.types;
        default_type  application/octet-stream;

        log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for" "$request_filename"';
        sendfile        on;

        keepalive_timeout  65;
        include servers/*.conf;
}

进行验证

我们使用Linux或者mac自带的ab命令进行验证,并且实时查看access.log。在Nginx配置文件中,我们设置的请求速率是每秒1个请求,那我们则需要设置每秒超多1个请求才行

$ ab -n 20 http://sdeno-api/info/php

从截图的日志中,我们可以看出Nginx限流模块确实可以限制请求速率。

其他

由于nginx的版本问题,旧版本会limit_conn_zone->limit_zone

使用docker搭建lnmp (二)

docker 名为容器。何为容器,也就是所谓的瓶子,罐子。用可以容纳东西的容器,不同容器之间互不影响。比如,一个瓶子装酒精,一个瓶子装水,非人为状态下,两个瓶子是没有关联的。

同样,docker也就是这个作用,每个docker可以作为叫做一个“瓶子”,每个”瓶子”可以当做PHP的运行环境,可以当做Java的运行环境。环境完全独立。外部的环境(内存,操作系统,CPU等)相当于柜子,承载着这些”瓶子”。

Read More »