其他配置

基础配置

main

  • 全局配置
  • 主配置段,即全局配置段,对http,mail都有效
user nginx nginx; # 启动Nginx工作进程的用户和组,(指定的是workr进程的身份,master进程始终是以root身份运行的,因为80端口只有特权用户才可以监听)

worker_processes  < number | auto >; # 启动nginx worker进程的数量,一般和cpu核心数相同。也可以定义为auto,表示根据CPU核心数量自动匹配

worker_cpu_affinity 0001 0010 0100 1000; # 将worker进程绑定在某一颗cpu上,这样可以减少进程与不同cpu的反复切换,从而提升性能,0001 0010 0100 1000表示 四颗cpu;0号-3号cpu

error_log  logs/error.log; # 错误日志记录级别和路径

pid        run/nginx.pid; # pid文件路径

worker_priority 0; # worker进程优先级,-20~20(19),数值越小优先级越高

worker_rlimit_nofile 65536; # 所有worker进程能打开的文件数量上线,还包括nginx的所有连接,实际的并发连接数不能超过系统级别的最大打开文件数的限制,最好与ulimit -n的值保持一致,否则在文件描述符不足时会报 Too many open files

daemon off; # 前台运行nginx服务,用于测试、docker等环境

worker_cpu_affinity

  • 前期准备,假设系统中有8颗 CPU,但是 nginx 只开启了4个 worker 进程
# lscpu | grep -E "^CPU\(s\)"
CPU(s):              8


# grep worker_processes /apps/nginx/conf/nginx.conf
worker_processes  4;


# ps aux | grep nginx
root        1853  0.0  0.0  42456   844 ?        Ss   12:21   0:00 nginx: master process nginx
nginx       1854  0.0  0.2  77112  5024 ?        S    12:21   0:00 nginx: worker process
nginx       1855  0.0  0.2  77112  5024 ?        S    12:21   0:00 nginx: worker process
nginx       1856  0.0  0.2  77112  5024 ?        S    12:21   0:00 nginx: worker process
nginx       1857  0.0  0.2  77112  5024 ?        S    12:21   0:00 nginx: worker process
  • 未绑定前 worker 会在不同的 CPU核心工作
# watch -n.5 'ps axo pid,cmd,psr | grep nginx'
   1853 nginx: master process nginx   2
   1854 nginx: worker process         3
   1855 nginx: worker process         4
   1856 nginx: worker process         5
   1857 nginx: worker process         6


# while true ; do ab -c 1000 -n 2000 http://localhost/ ; done


# watch -n.5 'ps axo pid,cmd,psr | grep nginx'
   1853 nginx: master process nginx   2
   1854 nginx: worker process         0
   1855 nginx: worker process         5
   1856 nginx: worker process         3
   1857 nginx: worker process         5



# watch -n.5 'ps axo pid,cmd,psr | grep nginx' 这个命令可以实现每0.5秒自动刷新一次,查看当前系统中所有包含“nginx”的进程的pid、cmd和psr(处理器标识符)信息。
具体解释如下:
  watch -n.5:这个命令用于设置一个定时器,每0.5秒刷新一次命令的输出。
  ps axo pid,cmd,psr:这个命令用于列出包含所有进程的pid,进程的命令名和进程所绑定的处理器标识符。
  grep nginx:这个命令管道符号用于过滤所有包含“nginx”的进程。注意,在某些情况下您可能需要修改grep命令来滤除不需要的进程。
综上所述,该命令对于监控和调试在Linux中运行的nginx进程非常有用。
  • 将 CPU 核心分别与 2、4、6、8 号CPU做亲缘性绑定
# grep worker_cpu_affinity /apps/nginx/conf/nginx.conf
worker_cpu_affinity  00000010 00001000 00100000 10000000;


# while true ; do ab -c 1000 -n 2000 http://localhost/ ; done


# 显示1、3、5、7是正确的,因为CPU是从0开始标号 
# watch -n.5 'ps axo pid,cmd,psr | grep nginx'
   8826 nginx: worker process         1
   8827 nginx: worker process         3
   8828 nginx: worker process         5
   8829 nginx: worker process         7

worker_rlimit_nofile

当 Nginx 处理客户端请求时,Nginx 使用文件描述符来打开与该请求相关联的文件,而这个文件可能是一个静态 HTML 文件、一个动态的 PHP 脚本或任何其他类型的文件。每个这样的文件都被分配一个文件描述符来表示与该文件的连接,当文件已经被打开时,该文件的描述符就会被放入一张描述符表中。

当客户端连接关闭时,相应的描述符就会从描述符表中删除,同时也会释放被占用的内存和连接。但是,如果有文件描述符泄露或者 Nginx 打开了过多的文件,就会达到系统可以分配给 Nginx 进程的最大文件描述符数,并导致 too many open files 错误和系统瓶颈等问题。

因此,对于高流量的 Web 服务器来说,需要做好资源限制和管理。例如,可以通过增加 “worker_rlimit_nofile” 参数值的方式来扩展 Nginx 可以使用的最大文件描述符数量,以支持更多的并发连接。同时,在处理大量的并发连接时,需要注意每个请求使用的文件描述符数量,并通过一些手段及时地回收描述符资源(如缓存、池化等),避免系统资源耗尽。

events

  • 也属于全局配置
  • 定义 Nginx 如何处理连接的事件,如连接数限制、超时等
events {
    worker_connections  10240; # 定义了每个work进程的最大连接数
    
    use epoll; # 事件驱动模型,默认就是epoll事件驱动,nginx支持众多的事件驱动,比如select、poll、epoll,只能在events段设置
    
    accept_mutex on; # work进程将依次接受新连接。否则,所有的工作进程都会收到新连接的通知,如果新连接的数量很少,一些工作进程可能只会浪费系统资源,on为同一时刻一个请求轮流由work进程处理,默认为off 即收到一个请求 所有work进程都会被唤醒(产生惊群效应),所以生产中此值建议设为on
    
    multi_accept on; # on时Nginx服务器的每个工作进程可以同时接受多个新的网络连接,此指令默认值为off,即默认为一个工作进程只能接受一个网络连接,建议优化,建议此值设为on

}                             

worker_connections

  • 每个work进程的最大连接数
  • 作为 web 服务器时的最大连接数量 = worker_processes * worker_processes
  • 作为反向代理时为(worker_processes * worker_processes)/2
    • 因为每个客户端连接都需要来回传输数据
  • 内核参数和limit限制也要配合修改
    • 例如:tcp_max_syn_backlog,tcp_tw_reuse

use

Nginx 的默认事件驱动模型是 epoll。在 Linux 系统中,使用 epoll 是一种高效的 I/O 多路复用机制,它能够监视多个文件描述符,阻塞并等待其中任何一些感兴趣的事件发生时触发后进行处理,这种方式处理的连接和请求速度快,且能够有效地管理大量的并发连接。因此,epoll 被广泛地应用于各种 Web 服务器、应用服务器和数据库服务器等系统。

其他事件驱动模型:

  • kqueue:如果您的 web 服务器运行在 FreeBSD 系统上,则可以使用 kqueue 作为事件驱动模型。与 epoll 相似,kqueue 也是一种高效的 I/O 多路复用机制。在 Nginx 中,您可以使用 “use kqueue” 配置项来启用 kqueue 模式。
  • select,poll:这两种模型是其他操作系统上的多路复用模型,相比较 epoll 和 kqueue,它们在性能上有所不足,但也可以通过 “use select” 或 “use poll” 配置项来启用这两种模式。

accept_mutex

“accept_mutex” 是 Nginx 的一个配置参数,它控制了 Nginx 如何在多个 worker 进程之间竞争新的连接请求。

当多个进程使用 poll()、epoll() 等函数监听同一个 socket 时,可能会出现多个进程同时将某个 socket 标记为有新的连接,但是只有一个进程可以完成这个新的连接。所有 worker 进程中只能有一个进程处理新连接,其他进程需要等待这个进程处理完之后才能处理下一个连接请求。此时,就需要一个互斥锁机制,防止多个 worker 进程同时处理一个连接。

“accept_mutex” 参数的值默认为 “on”,表示开启锁定机制。也就是说,在接受新连接之前,Nginx 会将所有进程排队处理,只有一个进程可以接受到某个连接。这种方式可以避免多个进程并发接受请求而导致性能下降,从而提高系统的可扩展性。但是,在高流量的情况下,由于使用互斥锁导致某个进程在处理完一个连接后其他进程不能及时接受连接,可能会导致客户端等待时间过长。

在优化一些高负载的 Nginx 环境时,可以考虑关闭 “accept_mutex” 参数来降低 Nginx 在处理高并发连接时的竞争性。关闭此选项可能会增加竞争,但可以提高系统的吞吐量和响应时间。要关闭 “accept_mutex”,可以在 Nginx 配置文件中使用如下配置:

events {
    accept_mutex off;
}

关闭 “accept_mutex” 参数可以减少 Nginx 服务器因为请求等待而导致的延迟,对一些大并发场景下的客户端连接处理效率有所提高。

accept_mutex是互斥锁相关的配置吗?

是的,“accept_mutex” 参数是 Nginx 中与互斥锁相关的配置之一。它的作用是在 Nginx 多个 worker 进程间协调资源竞争的情况下,确保同一时刻仅有一个 worker 进程接受客户端连接。如果不使用互斥锁,多个 worker 进程可能会同时尝试接受同一个客户端连接,从而引起 race condition(竞争条件)问题。

因为在每个 worker 进程内部都存有关于 Nginx 各个模块的相关状态,多进程同时访问可能会导致内存数据错乱。为了避免这种竞争,“accept_mutex” 参数在处理新连接之前使用互斥锁串行化处理连接,以保证只有一个 worker 进程在任何时刻处理新连接。这个互斥锁能够保证只有一个 worker 进程访问临界资源,避免了竞争条件问题。

当然,启用多进程时,同时也带来了性能瓶颈和开销,因为它们需要在不同的进程中访问同一个请求。此时,如开启和关闭 “accept_mutex” 参数需要根据实际情况进行权衡和选择。在高并发或线程穿透/池化等情况下,关闭 “accept_mutex” 可以减少请求等待时间和增加系统吞吐量。但在反向代理、动态负载均衡等场景下,打开 “accept_mutex” 总体上能够改善 Nginx 服务器性能。

什么叫互斥锁?

互斥锁是一种最简单、最基本的同步互斥手段。它是为了保证在多个线程或进程中,只有一个资源能够被操作或访问。简单来说,互斥锁就是保证多个线程/进程同时访问共享资源时,同一时间只有一个线程/进程访问该共享资源,其他线程/进程等待的一种机制。

在访问共享资源之前,线程或进程需要尝试获取这个共享资源的锁,如果成功获取到锁,则可以执行对共享资源的操作。当其他线程/进程再次尝试获取这个共享资源时,由于已经被上一个线程/进程占用,因此在没有获取到互斥量的情况下,被阻塞等待上一个线程/进程释放互斥锁。

需要注意的是,如果不合理地使用互斥锁,容易引起死锁等问题。所谓死锁,是指线程/进程之间互相等待而陷入无限制的等待状态。例如,一个线程在等待获取锁时,其它线程也在等待锁被释放,从而导致所有线程/进程都互相等待,无法继续执行下去。

因此,在编写多线程或者多进程程序时,需要规避这些问题,使用好互斥锁。

互斥锁是用在同一进程内多线程或多进程之间竞争资源的情况,而在不同进程之间的数据共享竞争时,可以使用其他进程间通讯(IPC)的机制,如信号量(semaphore)、管道(pipe)等来实现。

multi_accept

“multi_accept” 是 Nginx 的一个事件模块配置参数,它决定了每个工作进程在接受新连接时是接受单个连接还是接受多个连接。

  • 当 “multi_accept” 被设置为 “on” 时,表示每个 worker 进程可以同时接受多个新的网络连接。在高并发请求场景下,启用该选项可以提高工作进程的处理能力,减少等待新连接的时间,有效地优化性能。
  • 当 “multi_accept” 被设置为 “off” 时,表示每个 worker 进程只能接受单个新的网络连接。当一个新连接被传入时,worker 进程必须完全处理该连接以后,才能继续处理其他的连接请求。这种模式适用于较低的并发请求场景,能够有效地保护服务器防止被暴力攻击等情况下的拒绝服务。

作为下载服务器

  • 处理以"/“结尾的请求,并生成目录列表,可以作为下载服务配置使用
  • 提供像各大镜像网站一样的下载页面,可以充当yum/apt源来使用

相关指令说明

autoindex on | off; # 是否开启自动文件索引功能,默认为off

autoindex_exact_size on | off; # on:计算文件确切大小(单位bytes),off:显示大概大小(单位K、M),默认为on

autoindex_localtime on | off; # on:显示本地服务器时间,off:显示格林威治时间(GMT),默认off

autoindex_format html | xml | json | jsonp; # 索引页面的显示风格,默认为html

limit_rate rate; # 限制响应客户端的传输速率(除GET和HEAD以外的所有方法),单位B/s,即bytes/second,默认值0 即无限制,次指令由ngx_http_core_module提供

范例:实现自建yum源

#准备文件
[root@nginx ~]# ll /data/yum/
total 4
dr-xr-xr-x 4 root root 38 Nov 19  2020 BaseOS
dr-xr-xr-x 3 root root 18 Nov 19  2020 EFI
dr-xr-xr-x 3 root root 76 Nov 19  2020 images
-r--r--r-- 1 root root 87 Nov 19  2020 media.repo

#准备配置
[root@nginx ~]# vim /apps/nginx/conf.d/yum_nginx.conf 
server {
    listen 80;
    server_name www.localyum.com;
    root /data/yum/;
    autoindex on;
    autoindex_localtime on;
    limit_rate 1024k;
}

#浏览器测试访问测试访问
...

#测试限速
[root@clicent ~]#wget www.localyum.com/images/install.img
...
 0% [             ] 3,153,920   1015KB/s  eta 9m 44s  #查看限速

作为上传服务器

  • 依赖 ngx_http_upload_module

相关指令说明

client_max_body_size # 指定客户端请求的最大请求体大小,如果超过该值,Nginx会返回 413 错误。设置size为 0 将禁用对客户端请求正文大小的检查。该参数可以在http、server、location等级别上配置。

client_body_buffer_size # 指定客户端请求体缓冲区大小,如果客户端请求体大小超过该值,Nginx会把请求体写入临时文件。该参数可以在http、server、location等级别上配置。

client_body_temp_path # 指定客户端请求体临时文件的存储路径的参数。

upload_pass # 指定上传数据的目标服务器地址。该参数只能在location级别上配置,用于指定上传数据的后端服务器地址。

upload_store # 指定上传的文件保存路径。该参数只能在location级别上配置,用于指定上传文件保存的路径。

upload_store_access # 指定上传的文件保存路径的权限。该参数只能在location级别上配置,用于指定上传文件保存路径的访问权限。

upload_set_form_field # 指定上传表单域。该参数只能在location级别上配置,用于指定上传表单域。

upload_set_form_field_expires# 指定上传表单域的过期时间。该参数只能在location级别上配置,用于指定上传表单域的过期时间。

upload_cleanup # 指定上传完成后是否清理临时文件。该参数只能在location级别上配置,用于指定上传完成后是否清理临时文件。

client_max_body_size

  • 指定客户端请求的最大请求体大小
  • 如果超过该值,Nginx会返回 413 错误。
  • 设置size为 0 将禁用对客户端请求正文大小的检查。
  • 该参数可以在http、server、location等级别上配置。
  • 注意:如果 php 上传,还需要修改 php.ini 的相关配置

在 Nginx 中,client_max_body_size 配置项用于限制客户端请求体的最大大小。下面是一个示例配置:

http {
    # 设置最大请求体大小为10M
    client_max_body_size 10M;

    server {
        listen 80;
        server_name example.com;

        location /upload {
            # 处理上传请求
            # ...
        }

        # ...
    }
}

在上面的示例中,将客户端请求体的最大大小设置为10M,这将适用于整个 Nginx 实例。然后,通过在一个虚拟主机配置中设置 location 来处理上传请求。

请注意,如果需要更细粒度的控制,可以在 location 中单独设置 client_max_body_size 配置项。例如:

location /upload {
    # 仅允许请求体大小不超过1M的上传请求
    client_max_body_size 1M;

    # 处理上传请求
    # ...
}

这将仅适用于 /upload location 中的上传请求,并将覆盖全局配置。

client_body_temp_path

client_body_temp_path是Nginx中用于指定客户端请求体临时文件的存储路径的参数。当客户端上传的请求体数据超过client_body_buffer_size所设置的大小时,Nginx会把请求体数据写入到指定的临时文件中。

该参数可以在http、server、location等级别上配置。例如:

http {
    client_body_temp_path /var/nginx/client_temp;
    ...
}

server {
    client_body_temp_path /var/nginx/client_temp;
    ...
}

location /upload {
    client_body_temp_path /var/nginx/client_temp;
    ...
}

在上面的配置中,/var/nginx/client_temp是临时文件存储路径。如果没有指定client_body_temp_path参数,Nginx会使用系统默认的临时文件路径。

需要注意的是,临时文件应该存储在具有足够空间的磁盘分区中,并且应该定期清理。可以使用定时任务或者在Nginx配置中设置清理规则,避免临时文件过多占用磁盘空间。

client_body_temp_path 的数据存储结构:

client_body_temp_path参数指定的是Nginx存储客户端请求体临时文件的路径,而客户端请求体临时文件存储结构是由Nginx自动创建和管理的。

默认情况下,Nginx会在client_body_temp_path指定的路径下创建一个以"client_body_temp"开头的临时文件夹,用于存储客户端请求体的临时文件。在这个临时文件夹下,Nginx会根据客户端请求体的大小动态创建以"nginx_client_body_“开头的多个临时文件,每个临时文件的大小为client_body_buffer_size参数指定的大小。

例如,如果client_body_temp_path指定的路径为/var/nginx/client_tempclient_body_buffer_size为8k,客户端请求体大小为20k,那么Nginx会在/var/nginx/client_temp路径下创建一个名为client_body_temp的临时文件夹,并且会创建3个临时文件:

  • nginx_client_body_0: 大小为8k,存储客户端请求体的前8k数据。
  • nginx_client_body_1: 大小为8k,存储客户端请求体的第9k到16k数据。
  • nginx_client_body_2: 大小为4k,存储客户端请求体的最后4k数据。

当客户端请求体的数据全部写入到临时文件中后,Nginx会将这些临时文件合并为一个文件,并将文件存储到upload_store参数指定的目录中。

需要注意的是,如果上传的请求体数据比较大,且client_body_buffer_size设置的比较小,Nginx可能会创建大量的临时文件。这时应该调整client_body_buffer_size参数的大小,以减少临时文件的数量。

nginx 状态页

  • 由 ngx_http_stub_status_module 模块提供此功能

  • 在编译安装nginx时需要添加编译参数 –with-http_stub_status_module,否则配置完成后会提示语法错误

  • 注意:状态页显示的是整个服务器的状态,而非虚拟主机的状态

    • 是的,您所说的是正确的。nginx的状态页可以在server或location语句块中定义,但它显示的是整个服务器的状态,而不是虚拟主机的状态。无论您在哪个虚拟主机中定义状态页,它都会显示整个服务器的状态。如果您想要监视每个虚拟主机的状态,可以考虑使用第三方模块或者其他监控工具。
  • Content:server、location

nginx 状态页生产案例

server {
    listen       80;
    server_name  www.azheng.com;
...
    location /nginx_status {
        stub_status;
        allow 127.0.0.1; # 配合zabbix agent监控使用 所以只允许本机访问即可
        deny all;
    }
}

输出结果说明

# curl http://www.azheng.com/nginx_status
Active connections: 10
server accepts handled requests # accepts、handled、requests 对应 53、55、109
         53      53      109 
Reading: 2 Writing: 3 Waiting: 5
  • Active connections:

    • 当前 Nginx 正在处理的活跃连接数,包括连接等待空闲连接数,此值等于Reading+Writing+Waiting之和
  • Server accepts handled requests:

    • Accepts:
      • 表示 Nginx 启动以来接受的 TCP 连接总数。当客户端向 Nginx 发起请求时,Nginx 会接受客户端的 TCP 连接,这个过程称为 Accept。Accepts 数量越多,说明 Nginx 接受了越多的客户端连接,但并不一定代表 Nginx 处理了所有连接请求。
    • Handled:
      • 表示 Nginx 启动以来成功处理的连接总数,即已经接受并成功处理客户端的 TCP 连接。在 Nginx 处理请求的过程中,它会根据配置进行一些操作(比如代理请求、处理静态文件、负载均衡等),如果这些操作都成功完成,则连接被视为已经被处理了。
      • 通常等于accepts,除非由有worker_connections限制等被拒绝的连接
    • Requests:
      • 表示 Nginx 启动以来处理的请求总数,即已经接受并成功处理客户端请求的总数。通常情况下,一个连接可以对应多个请求,因此 Requests 数量通常会大于 Handled 数量。
  • Reading:

    • Nginx 目前正在读取客户端请求的连接数。
    • Reading 数值越大,说明排队现象严重,性能不足,数值越小,表示性能越好
      • 在 Nginx 状态页中,“Reading” 指标表示当前正在读取客户端请求的连接数,数值越大表示有越多的连接在等待 Nginx 读取请求,而 “Waiting” 指标表示已经读取完请求,正在等待后端响应的连接数,数值越大表示有越多的连接在等待响应。
      • 因此,对于 “Reading” 指标,数值越大表示有越多的请求在等待 Nginx 读取,意味着有更多的请求进入了队列中,排队等待 Nginx 处理,反映了当前系统的请求处理性能不足。而数值越小表示 Nginx 能够更快地读取请求,性能相对较好。
      • 需要注意的是,这些指标并不能直接反映系统的绝对性能水平,它们只是 Nginx 处理连接和请求的状态指标,可以帮助管理员了解当前系统的负载情况和性能状况,可以通过这些指标来调整 Nginx 的配置和性能优化,以提高系统的处理性能和吞吐量。
  • Writing:

    • Nginx 目前正在向客户端写入响应的连接数。
    • Writing 数值越大,说明访问量越大
      • 在 Nginx 状态页中,“Writing” 指标表示当前正在向客户端发送响应的连接数,数值越大表示有越多的连接正在向客户端发送响应,反映了当前系统的并发请求数量,而不是访问量大小。
      • 访问量通常是指一段时间内访问某个网站或应用程序的用户数量,通常通过访问日志或网站统计工具进行统计。而 “Writing” 指标仅仅反映了当前系统正在处理的并发请求数量,可以用于帮助管理员了解系统的负载情况和性能状况,但并不能直接反映访问量大小。
      • 需要注意的是,系统的性能瓶颈通常不仅仅取决于并发请求数量,还受到系统硬件配置、软件优化等多个因素的影响。因此,在进行性能优化时,需要从多个角度进行考虑和分析,以找到系统的瓶颈并进行针对性的优化。
  • Waiting:

    • Nginx 目前正在等待客户端请求或正在处理内部操作的连接数。

    • 开启keepalive的情况下,Waiting 的值等于 active-(reading+Writing)

      • 在开启 Keepalive 的情况下,Nginx 会重用已经建立的连接来处理多个请求,这可以减少连接的建立和断开开销,提高性能和响应速度。在这种情况下,Nginx 状态页中的 “Waiting” 指标表示当前正在等待处理请求的连接数,而 “Active” 指标表示当前正在处理请求的连接数。

      • 因此,如果同时开启了 Keepalive,那么 “Waiting” 指标的值通常可以通过 “Active”、“Reading” 和 “Writing” 指标计算得出,即:

        • Waiting = Active - (Reading + Writing)
        • 这个公式的含义是,等待处理请求的连接数等于当前正在处理请求的连接数减去正在读取请求的连接数和正在向客户端发送响应的连接数。

      • 这个值反映了有多少个连接正在等待处理请求,反映了系统的请求处理性能和连接处理能力。需要注意的是,这个公式仅在开启 Keepalive 的情况下才成立,在没有开启 Keepalive 的情况下,“Waiting” 指标和 “Active” 指标的含义和计算方法可能不同。

分析网站当前访问量

[root@centos8 ~]# curl http://www.azheng.com/nginx_status 2>/dev/null | awk '/Reading/{print $2,$4,$6}'
2 3 5

#说明
2 #当前状态,正在读取客户端请求报文首部过程中的连接数,数值越大,说明排队现象严重,性能不足
3 #当前状态,正在向客户端发送响应报文过程中的连接数,数值越大,说明访问量越大
5 #当前状态,正在等待客户端发出请求的空闲连接数

PV

Nginx 状态页中并没有直接统计页面访问量(PV)的指标。不过,可以通过一些其他的方式来估算网站的 PV,比如:

  1. 统计 Nginx 访问日志:通过分析 Nginx 访问日志可以统计网站的 PV。可以使用类似 AWStats、Webalizer、GoAccess 等工具来分析 Nginx 访问日志,生成相应的统计报表。
  2. 集成第三方网站统计工具:可以使用像 Google Analytics、百度统计等第三方网站统计工具来跟踪网站访问量。这些工具通常需要在网站页面中嵌入相应的代码,通过 JavaScript 统计用户访问行为。
  3. 使用专业的统计工具:还可以使用一些专业的网站访问统计工具,比如 CNZZ、友盟等,这些工具通常需要注册账户并在网站中添加统计代码,可以提供详细的用户行为分析和统计报表。

需要注意的是,以上的统计方法都会对服务器产生一定的性能影响,因此需要根据实际情况进行选择和优化。

Nginx 第三方模块

第三方模块是对nginx功能的扩展,第三方模块需要在编译安装时加入参数 –add-module=第三方模块的路径来进行添加

echo module

  • URL:https://github.com/openresty/echo-nginx-module

echo模块的安装

#clone代码(需要提前安装git)
[root@centos8 ~]# cd /usr/local/src/
[root@centos8 src]# git clone https://github.com/openresty/echo-nginx-module.git

#查看当前nginx的编译选项
[root@centos8 ~]# nginx -V
nginx version: nginx/1.18.0
built by gcc 8.4.1 20200928 (Red Hat 8.4.1-1) (GCC) 
built with OpenSSL 1.1.1g FIPS  21 Apr 2020
TLS SNI support enabled
configure arguments: --prefix=/apps/nginx --user=nginx --group=nginx --with-http_ssl_module --with-http_v2_module --with-http_realip_module --with-http_stub_status_module --with-http_gzip_static_module --with-pcre --with-stream --with-stream_ssl_module --with-stream_realip_module

#开始重新编译安装,末尾加上第三方模块的路径
[root@centos8 src]# cd /usr/local/src/nginx-1.18.0/
[root@centos8 nginx-1.18.0]# ./configure --prefix=/apps/nginx --user=nginx --group=nginx --with-http_ssl_module --with-http_v2_module --with-http_realip_module --with-http_stub_status_module --with-http_gzip_static_module --with-pcre --with-stream --with-stream_ssl_module --with-stream_realip_module --add-module=/usr/local/src/echo-nginx-module/
[root@centos8 nginx-1.18.0]# make && make install

测试echo模块

[root@centos8 ~]# vim /apps/nginx/conf/conf.d/pc.conf
server {
...
    location /echo {
        echo "hello world";
        echo $remote_addr;
    }
...    
}

[root@centos8 ~]# systemctl restart nginx.service

[root@18 ~]# curl www.azheng.com/echo
hello world
10.0.0.18

#重新编译nginx后会新老版本并存
[root@aliyun ~]# ll /apps/nginx/sbin/
total 15352
-rwxr-xr-x 1 root  root  8126200 Apr 26 10:34 nginx
-rwxr-xr-x 1 nginx nginx 7591104 Jan 26 14:32 nginx.old

其他 nginx 第三方模块

自定义访问日志

定义日志

  • 注意:log_format字段只能在http语句块设置
Syntax:	log_format name [escape=default|json|none] string ...;
Default: log_format combined "...";
Context: http

引用日志

  • 访问日志可以对指定的server定义,即定义多个,而错误日志一般只定义一个
语法:	access_log path [format [buffer=size] [gzip[=level]] [flush=time] [if=condition]];
access_log off;
默认:	access_log logs/access.log combined;
语境:	http, server, location, if in location, limit_except

示例:访问日志输出为json格式

http {
    include       mime.types;
    default_type  application/octet-stream;
    charset  utf-8;
    
    # 原有日志格式
    log_format  main  '$remote_addr - $remote_user [$time_local] "$request"'
                      '$status $body_bytes_sent "$http_referer"'
                      '"$http_user_agent" "$http_x_forwarded_for" $request_time';
    # json日志格式
    log_format log_json '{"@timestamp": "$time_local",'
                        '"remote_addr": "$remote_addr",'
                        '"referer": "$http_referer",'
                        '"request": "$request",'
                        '"status": $status,'
                        '"bytes": $body_bytes_sent,'
                        '"agent": "$http_user_agent",'
                        '"x_forwarded": "$http_x_forwarded_for",'
                        '"up_addr": "$upstream_addr",'
                        '"up_host": "$upstream_http_host",'
                        '"up_resp_time": "$upstream_response_time",'
                        '"request_time": "$request_time"'
                        ' }';

    access_log  logs/access.log log_json; # 引用日志路径和格式名称

    (省略内容)
}
http {
...
    # 改为json日志格式
    log_format log_json '{"@timestamp": "$time_local",'
                        '"remote_addr": "$remote_addr",'
                        '"referer": "$http_referer",'
                        '"request": "$request",'
                        '"status": $status,'
                        '"bytes": $body_bytes_sent,'
                        '"user_agent": "$http_user_agent",'
                        '"x_forwarded": "$http_x_forwarded_for",'
                        '"up_addr": "$upstream_addr",'
                        '"up_host": "$upstream_http_host",'
                        '"up_resp_time": "$upstream_response_time",'
                        '"request_time": "$request_time"'
                        ' }';
    access_log  logs/access.log log_json; # 引用日志格式名称
...
}

示例:蜜点使用

log_format log_json '{"timestamp": "$time_iso8601",'
                    '"remote_addr": "$remote_addr",'
                    '"remote_port": "$remote_port",'
                    '"server_addr": "$server_addr",'
                    '"server_port": "$server_port",'
                    '"server_protocol": "$server_protocol",'
                    '"host": "$host",'
                    '"request_uri": "$request_uri",'
                    '"request_method": "$request_method",'
                    '"status_code": $status,'
                    '"http_user_agent": "$http_user_agent",'
                    ' }';

自定义错误日志

Syntax: error_log file [level];
Default: error_log logs/error.log error;
Context: main, http, mail, stream, server, location


# [level]选项,指定错误日志记录的级别:
# 详细程度由高到低(越往下只有很严重的才记录)
debug
info
notice
warn
error
crit
alert
emerg

范例

# vim /apps/nginx/conf.d/llinux.cn.conf
server {
    listen 80;
    listen 443 ssl;
    server_name llinux.cn;
    error_log /apps/nginx/logs/llinux.cn_error.log error;
...


# 验证
# tail -f /apps/nginx/logs/llinux.cn_error.log
2023/04/06 18:48:47 [error] 1725623#0: *2 open() "/data/wordpress/ewqemowq" failed (2: No such file or directory), client: 114.254.10.26, server: llinux.cn, request: "GET /ewqemowq HTTP/1.1", host: "llinux.cn"
2023/04/06 18:48:47 [error] 1725623#0: *2 open() "/data/wordpress/404.svg" failed (2: No such file or directory), client: 114.254.10.26, server: llinux.cn, request: "GET /404.svg HTTP/1.1", host: "llinux.cn", referrer: "https://llinux.cn/ewqemowq"

错误日志输出为json格式

Nginx日志默认是按照文本格式输出的。要将Nginx日志格式更改为JSON格式,可以使用第三方的Nginx模块(如ngx_http_log_module_with_json)或者手动编写Lua脚本。

使用ngx_http_log_module_with_json模块:

步骤如下:

  1. 下载ngx_http_log_module_with_json源码,并将其保存在Nginx源码的/modules目录下。
  2. 运行./configure脚本时添加–add-module=modules/ngx_http_log_module_with_json选项,如下所示:
./configure --add-module=modules/ngx_http_log_module_with_json
  • 在nginx.conf配置文件中增加以下内容来定义使用JSON格式的日志输出:
log_format json escape=json '{ "time": "$time_iso8601", '
                            '"remote_addr": "$remote_addr", '
                            '"remote_user": "$remote_user", '
                            '"request": "$request", '
                            '"status": "$status", '
                            '"body_bytes_sent": "$body_bytes_sent", '
                            '"http_referer": "$http_referer", '
                            '"http_user_agent": "$http_user_agent", '
                            '"http_x_forwarded_for": "$http_x_forwarded_for",'
                            '"request_time": $request_time }';

在上述JSON格式日志模板中,我们可以选择包含想要的字段并定义它们的输出格式。

  • 修改Nginx配置文件,将access_log和error_log中的格式修改为使用定义的JSON格式日志模板。例如:
access_log /var/log/nginx/access.log json;
error_log /var/log/nginx/error.log json;

使用Lua脚本:

安装ngx_lua模块,并使用Lua脚本编写自定义的log_by_lua脚本,以将Nginx日志输出为JSON格式。

在Lua脚本中,可以通过ngx.log函数来记录日志。例如,可以使用以下Lua脚本来记录访问日志:

location / {
    log_by_lua '
        local cjson = require("cjson.safe")
        local log = {
            time = ngx.utctime(),
            remote_addr = ngx.var.remote_addr,
            uri = ngx.var.uri,
            status = ngx.status
        }
        ngx.log(ngx.NOTICE, cjson.encode(log))
    ';
}

在此Lua脚本中,我们使用cJSON.safe库将日志记录为具有以下属性的JSON对象:时间,远程地址,URI和状态。然后,我们将该日志记录为“notice”级别日志。然后将其添加到Nginx配置文件中。

总的来说,将Nginx错误日志输出为JSON格式有多种方法,具体取决于使用的第三方模块或脚本。

Lua

  • 参考文档:https://www.runoob.com/lua/lua-tutorial.html