Nginx学习记录,nginx记录


  • Nginx重启 kill -HUP pid,从容重启Nginx或者用来重新加载配置文件
  • ./nginx -s reload 重启nginx
  • ./nginx -s stop 停止nginx

nginx的工作方式

nginx采用了异步非阻塞的方式来处理请求,
- 在nginx中,每个进程会有一个连接数的最大上限,这个上限与系统对fd的限制不一样。在操作系统中,通过ulimit -n,我们可以得到一个进程所能够打开的fd的最大数,即nofile,因为每个socket连接会占用掉一个fd,所以这也会限制我们进程的最大连接数,当然也会直接影响到我们程序所能支持的最大并发数,当fd用完后,再创建socket时,就会失败。nginx通过设置worker_connectons来设置每个进程支持的最大连接数。如果该值大于nofile,那么实际的最大连接数是nofile,nginx会有警告。nginx在实现时,是通过一个连接池来管理的,每个worker进程都有一个独立的连接池,连接池的大小是worker_connections。这里的连接池里面保存的其实不是真实的连接,它只是一个worker_connections大小的一个ngx_connection_t结构的数组。并且,nginx会通过一个链表free_connections来保存所有的空闲ngx_connection_t,每次获取一个连接时,就从空闲连接链表中获取一个,用完后,再放回空闲连接链表里面。
- 在这里,很多人会误解worker_connections这个参数的意思,认为这个值就是nginx所能建立连接的最大值。其实不然,这个值是表示每个worker进程所能建立连接的最大值,所以,一个nginx能建立的最大连接数,应该是worker_connections * worker_processes。当然,这里说的是最大连接数,对于HTTP请求本地资源来说,能够支持的最大并发数量是worker_connections*worker_processes,而如果是HTTP作为反向代理来说,最大并发数量应该是worker_connections * worker_processes/2。因为作为反向代理服务器,每个并发会建立与客户端的连接和与后端服务的连接,会占用两个连接。
- 那么,我们前面有说过一个客户端连接过来后,多个空闲的进程,会竞争这个连接,很容易看到,这种竞争会导致不公平,如果某个进程得到accept的机会比较多,它的空闲连接很快就用完了,如果不提前做一些控制,当accept到一个新的tcp连接后,因为无法得到空闲连接,而且无法将此连接转交给其它进程,最终会导致此tcp连接得不到处理,就中止掉了。很显然,这是不公平的,有的进程有空余连接,却没有处理机会,有的进程因为没有空余连接,却人为地丢弃连接。那么,如何解决这个问题呢?首先,nginx的处理得先打开accept_mutex选项,此时,只有获得了accept_mutex的进程才会去添加accept事件,也就是说,nginx会控制进程是否添加accept事件。nginx使用一个叫ngx_accept_disabled的变量来控制是否去竞争accept_mutex锁。在第一段代码中,计算ngx_accept_disabled的值,这个值是nginx单进程的所有连接总数的八分之一,减去剩下的空闲连接数量,得到的这个ngx_accept_disabled有一个规律,当剩余连接数小于总连接数的八分之一时,其值才大于0,而且剩余的连接数越小,这个值越大。再看第二段代码,当ngx_accept_disabled大于0时,不会去尝试获取accept_mutex锁,并且将ngx_accept_disabled减1,于是,每次执行到此处时,都会去减1,直到小于0。不去获取accept_mutex锁,就是等于让出获取连接的机会,很显然可以看出,当空余连接越少时,ngx_accept_disable越大,于是让出的机会就越多,这样其它进程获取锁的机会也就越大。不去accept,自己的连接就控制下来了,其它进程的连接池就会得到利用,这样,nginx就控制了多进程间连接的平衡了。

ngx_accept_disabled = ngx_cycle->connection_n / 8
    - ngx_cycle->free_connection_n;

if (ngx_accept_disabled > 0) {
    ngx_accept_disabled--;

} else {
    if (ngx_trylock_accept_mutex(cycle) == NGX_ERROR) {
        return;
    }

    if (ngx_accept_mutex_held) {
        flags |= NGX_POST_EVENTS;

    } else {
        if (timer == NGX_TIMER_INFINITE
                || timer > ngx_accept_mutex_delay)
        {
            timer = ngx_accept_mutex_delay;
        }
    }
}

ngx_accept_disabled = worker_processes_all_connection/8 - worker_processes_free


nginx的日志

-nginx开启调试日志
1. 要开启调试日志,首先需要在配置Nginx时打开调试功能,然后编译:

./configure --with-debug ...

然后在配置文件中设置error_log的级别为:

error_log /path/to/log debug;

这里设置的是一级日志为debug级别
Nginx的Windows二进制版本总是将调试日志开启的,因此只需要设置debug的日志级别即可。

2.日志级别分析:
在此,我们通过分析Nginx源码了解下Nginx将日志分为几个等级及不同日志等级之间的相互关系:

Ngx_log.h代码

#define NGX_LOG_STDERR 0
#define NGX_LOG_EMERG 1
#define NGX_LOG_ALERT 2
#define NGX_LOG_CRIT 3
#define NGX_LOG_ERR 4
#define NGX_LOG_WARN 5
#define NGX_LOG_NOTICE 6
#define NGX_LOG_INFO 7
#define NGX_LOG_DEBUG 8

#define NGX_LOG_DEBUG_CORE 0x010
#define NGX_LOG_DEBUG_ALLOC 0x020
#define NGX_LOG_DEBUG_MUTEX 0x040
#define NGX_LOG_DEBUG_EVENT 0x080
#define NGX_LOG_DEBUG_HTTP 0x100
#define NGX_LOG_DEBUG_MAIL 0x200
#define NGX_LOG_DEBUG_MYSQL 0x400

#define NGX_LOG_DEBUG_FIRST NGX_LOG_DEBUG_CORE
#define NGX_LOG_DEBUG_LAST NGX_LOG_DEBUG_MYSQL
#define NGX_LOG_DEBUG_CONNECTION 0x80000000
#define NGX_LOG_DEBUG_ALL 0x7ffffff0

其中默认有效的第一级别日志是”stderr”,”emerg”,”alert”,”crit”,”error”,”warn”,”notice”,”info”,”debug”。 而Ngx_log.h内列出的其他debug第二级别日志:”debug_core”,”debug_alloc”,”debug_mutex”,”debug_event”,”debug_http”,”debug_mail”,”debug_mysql”等则需要在配置Nginx时启动调试日志功能才能使用(即一级日志级别是debug,二级日子才有效),并且用户可以通过修改Ngx_log.h及Ngx_log.c源码来更新debug第二级别。


注意:ngnix中
第一级别日志之间是互斥的,如果配置文件内加入如下配置项:

error_log path/logs/error.log warn;
error_log path/logs/error.log info;

ngnix启动会报错,信息如下

[emerg]: duplicate log level "info" in /path/conf/nginx.conf:XX

但是需要注意的是,在配置文件不同block中是允许重新定义错误日志的。但是当用户在重新定义错误日志时,如果没有指定相应的日志级别,那么调试日志将会被屏蔽。下面的例子里,在server层中重新定义的日志就屏蔽了这个虚拟主机的调试日志:

error_log  /path/to/log  debug;#调试日志

http {
    server {
        error_log  /path/to/log;#用户在block中,定义的日志,没有指定级别
        ...

为了避免这个问题,可以注释这行重新定义日志的配置,或者也给日志指定debug级别:

error_log  /path/to/log  debug;#调试日志

http {
    server {
        error_log  /path/to/log debug; #用户在block中,定义的日志,没有指定级别
        ...

第二级别日志是多选的,用户可以根据项目需要配置多个第二级别日志:

error_log  logs/error.log debug_mysql;
error_log  logs/error.log debug_core;

在第一级别日志与第二级别日志组合配置时,仅有在第一级别日志为”debug”时才可以有第二级别的配置,其他第一级别日志的情况下指定第二级别日志将无法启动Nginx,如:

error_log  logs/error.log error;
error_log  logs/error.log debug_core;

启动Nginx将获得如下错误信息:

[emerg]: invalid log level “debug_http” in /path/conf/nginx.conf:XX

3.日志格式设置:

用户在使用Nginx提供web服务的时候,可能会有很多场景需要记录日志,如打点日志,访问日志,数据统计日志,性能分析日志等。为了更加方便的对日志进行分析,我们可以通过设置日志格式的方式来要求Nginx按照用户要求进行日志的展现。

控制nginx日志输出的指令如下:

log_format  customLog "$remote_addr^A$remote_user^A$time_local^A$request_method^A$uri^A$args^A$server_protocol"
        "^A$status^A$body_bytes_sent^A$http_referer"
        "^A$http_user_agent";
access_log /path/logs/access.log customLog;

上面例子中通过使用特殊字符(^A)来作为日志字段的分隔符,用户后续可以使用sort和grep之类的工具对特定url做分析,如统计各url请求量倒排取前50个:

awk -F^A '{print $5}' /path/logs/access.log | sort | uniq -c | sort -nr | head -50

类似上面的日志定制化设置,可以让用户在调试日志的过程中随心所欲,如鱼得水。 详细的log_format指令和access_log指令,用户可以访问Nginx官网的HttpLog模块 http://wiki.nginx.org/HttpLogModule

4.调试日志的几个注意点:

error_log /dev/null crit;
[alert]: could not open error log file: open() "/path/log/nginx/error.log" failed (13: Permission denied)
error_log  /path/to/log;

events {
    debug_connection   10.232.10.1;
    debug_connection   10.232.10.0/24;
}

相关内容

    暂无相关文章