深入理解Nginx-模块开发与架构解析(第2版)第二章

Nginx的配置

运行中Nginx进程间的关系

# 为什么产品环境下安装master-worker方式配置同时启动多个进程?
- master进程不会对用户提供服务,只用于管理真正提供服务的worker进程,所以master进程可以是唯一的,为管理员 提供命令行服务,如启停、重载配置文件、平滑升级程序等。
master拥有的权限相对worker要大,当任意一个worker进程出现错误,master进程会立刻启动新的worker进程继续服务。
- 多个worker进程处理请求不但可以提供服务的健壮性,还可以充分利用常见的SMP多核架构,实现微观上真正的多核并发处理。
用一个master处理请求肯定是不合适的,将worker进程数量设置与CPU核数一致,真是Nginx与Apache服务器不同之处。
在Apache上每个进程在一个时刻只处理一个请求,因此,如果希望web服务器拥有并发处理的请求数更多,就要把Apache进程或线程数设置得更多,这样大量进程切换会无谓的消耗系统资源。
而Ngnix一个worker进程可以同时处理的请求数只受限于内存大小,而且在架构设计上,不同的worker进程之间处理并发请求时几乎没有同步锁的限制。,worker进程通常不会进入睡眠状态。因此,Nginx上的进程数与CPU核心数相等时,进程间切换的代价是最小的。

图

1.Nginx配置通用语法

tree

# 块配置项:由一个块配置项名和一对大括号组成。
server {
    ...
}

# 配置项的语法格式
配置项名 配置项值1 配置项值2 ...;
access_log logs/access.log main buffer=32k;
说明:
    1.行首是配置项名,配置项名必须是Nginx的某一个模块想要处理的,否则视为非法配置项名。
    2.配置项名输入后,将以空格作为分隔符。
    3.配置项值可以是数字,字符串或正则表达式。
    4.一个配置项可以有一个或多个配置项值,一个配置项的配置项值有多少个取决于解析这个配置项的模块。
    5.配置项值之间也是使用空格作为分隔符。
    6.每行配置的结尾需要加上分号。
    7.如果配置项值中包括语法符号,比如空格需要使用单引号或双引号包裹,否则Nginx会报语法错误。

2.配置项注释
# 使用#注释某一行配置
#pid logs/nginx.pid;
3.配置项的单位
# 大部分模块遵循一些通用规定,如指定空间大小不用每次都精确到字节;指定时间不用精确到毫秒。
- 当指定空间大小时,可使用单位:
    - K或k千字节(KB)
    - M或m兆字节(MB)
- 当指定时间时,可使用单位:
    - ms(毫秒)
    - s(秒)
    - m(分钟)
    - h(小时)
    - d(天)
    - w(周,包含7天)
    - M(月,包含30天)
    - y(年,包含365天)
4.在配置中使用变量
log_format main '$remote_addr - $remote_user [$time_local] "$request"'
# 如remote_addr是一个变量,使用时需要加上$符合。这种变量只有少数模块支持,并非通用。

Nginx服务的基本配置

Nginx运行时,至少必须加载几个核心模块和一个事件类模块。
这些模块运行时所支持的配置项称为基本配置——所有其他模块执行时都依赖的配置项。

基本配置项分为:
    - 调试、定位问题配置项
    - 正常运行的必备配置项
    - 优化性能的配置项
    - 事件类配置项(有些事件类配置项归到优化性能配置项)
    


1.用于调试进程和定位问题的配置项
序号 分类 语法 默认 说明
序号 分类 语法 默认 说明
1 是否以守护进程方式运行Nginx daemon on/off; daemon on; 守护进程(daemon)是脱离终端并在后台运行的进程。脱离终端是为了避免执行过程中信息在终端上显示,同时也避免进程被终端输入中断。
2 是否以master/worker方式工作 master_process on/off; master_process on; 提供该方式方便跟踪调试Nginx。如果不使用该方式,在worker异常时无法fork出worker子进程来处理请求。
3 error日志的设置 error_log /path/file level; error_log logs/error.log error; 错误日志是定位Nginx问题的最佳工具。level是日志级别,取值:debug,info,notice,warn,error,crit,alert,emerg。从左至右依次增大
4 是否处理几个特殊的调试点 debug_points [stop/abort] / 用于帮助用户跟踪调试Nginx。设置stop时,Nginx执行到这些调试点时就会发出SIGSTOP信息用以调试;设置abort时,会产生一个coredump文件,可使用gdp来查看。通常不使用该配置项。
5 仅对指定客户端输出debug级别日志 debug_connection [IP/CIDR / 该配置实际属于事件类配置,因此需写到events块events{debug_connection 10.224.66.14; debug_connection 10.224.57.0/24;}
6 限制coredump核心转储文件的大小 worker_rlimit_core size; / 在Linux系统中,当进程发生错误或收到信号终止,系统会将进程执行时的内存内容(核心镜像)写入一个文件(core文件),用作调试,这就是所谓的核心转储(core dumps)。当Nginx进程出现一些非法操作(如内存越界)导致进程直接被操作系统结束时,会生成核心转储core文件,可从core文件获取当时的堆栈、寄存器等信息,帮助定位问题。若不对文件大小进行限制可能达到几GB,这样随便几次coredumps就会把磁盘占满。
7 指定coredump文件生成目录 working_directory_ path; / worker进程的工作目录,这个配置唯一用途就是coredump文件所放置的目录,协助定位问题。需确保worker进程有权限向working_directory指定的目录中写入文件。

如果日志设置debug级别或使用debug_connection,在configure时加入--with-debug

2.正常运行的配置项
序号 分类 语法 默认 说明
序号 分类 语法 默认 说明
1 定义环境变量 env VAR/VAR=VALUE; / 该配置项可以让用户之间设置操作系统上的环境变量。eg:env TESTPATH=/tmp/
2 嵌入其他配置文件 include /path/file / 该配置项可以将其他配置文件嵌入到当前nginx.conf文件中,它的参数可以是相对路径(相对于Nginx的配置目录,即nginx.conf所在目录),也可以是绝对路径。eg:includ mime.types; include vhost/星.conf;库看到参数值可以是一个明确文件,也可以是含有通配符“*”的文件名,同时一次嵌入多个配置文件
3 pid文件路径 pid path/file; pid logs/nginx.pid; 保存master进程ID的pid文件存放路径。默认与configure执行时的参数“--pid-path”所指定的路径是相同的,可随时修改,确保Nginx有权限在相应目标中创建pid文件,该文件直接影响Nginx是否可以运行。
4 Nginx worker进程运行的用户及用户组 user username[groupname]; user nobody nobody; user用于设置master进程启动后,fork出的worker进程运行在哪个用户和用户组下。当按照“user username;”设置,用户组名与用户名相同。若用户在configure参数执行时使用--user=username和--group=groupname时,nginx.conf将使用参数中指定的用户和用户组。
5 指定Nginx worker进程可以打开的最大文件句柄描述符个数 worker_rlimit_nofile limit; / 设置一个worker进程可以打开的最大文件句柄数。
6 限制信号队列 worker_rlimit_sigpending limit; / 设置每个用户发往Nginx的信号队列的大小。即,当某个用户的信号队列满了,这个用户再发送信号量会被丢掉。
3.优化性能的配置项
序号 分类 语法 默认 说明
序号 分类 语法 默认 说明
1 Nginx worker进程个数 worker_processes number; worker_processes 1; master/worker运行方式下,定义worker进程个数。worker进程数量会直接影响性能,配置多少个worker进程与业务需求有关。每个worker都是单线程的进程。它们会调用各个模块以实现多种多样的功能。如果这些模块确认不会出现阻塞式调用,有多少CPU内核就应该配置多少个进程。反之,应配置稍多一些的worker进程。如:业务方面致使用户读取本地磁盘上的静态资源文件,而且服务器上的内存较小,以至于大部分的请求访问静态资源时都必须读取磁盘(磁头寻址是缓慢的),而不是内存中的磁盘缓存,那么磁盘I/O调用可能会阻塞worker进程少量时间,进而导致服务整体性能下降。多worker进程可以重发利用多核系统架构,但若worker进程数多于CPU内核数,会增大进程间切换带来的消耗(Linux是抢占式内核)一般情况下,用户应配置CPU核数相同的worker进程数,并绑定CPU内核
2 绑定Nginx worker进程到指定的CPU内核 worker_cpu_affinity cpumask [cpumask...] / 为什么要绑定?假设每一个worker进程都是非常繁忙,如果每一个worker都在抢同一个CPU,那么会出现同步问题。反之,每一个worker独享一个CPU,就在内核的调度上实现完全的并发。eg:有4颗CPU内核,就可以进行如下配置:worker_processes 4; worker_cpu_addinity 1000 0100 0010 0001;该配置仅对Linux操作系统有效,它使用sched_sctaffinity()系统调用实现这个功能。
3 SSL硬件加速 ssl_engine device; / 如果服务器上游SSL硬件加速设备,就可以进行配置加快SSL协议的处理。可以使用OpenSSL提供的命令查看是否有SSL硬件加速设备:openssl engine -t
4 系统调用gettimeofday的执行频率 timer_resolution t; / 默认情况下,每次内核的事件调用(epoll、select、poll、kqueue等)返回时,都会执行一次gettimeofday,实现用内核的时钟更新一次Nginx中缓存时钟。中间有一次内核态到用户态的复制,因此,实现代价不小。可以使用该配置降低调用频率。eg:timer_resolution 100ms;表示至少每100ms才调用一次gettimeofday。但目前大多数内核中,x86-64体系架构,gettimeofday只是一次vsyscall,仅仅对共享内存页中的数据做访问,并不是通常的系统调用。一般不需使用该配置,若希望日志时间更准确可以使用。
5 Nginx worker进程优先级设置 worker_priority nice; worker priority 0; 用于设置Nginx worker进程的nice优先级,在Linux或其他Unix操作系统中,当许多进程都处于可执行状态时,将按照所有的进程的优先级来决定本次内核选择哪一个执行。进程所分配的CPU时间片大小与进程优先级相关。成正比,即优先级越高,分配的时间片也越大。(默认最小时间片5ms,最大时间片800ms),优先级高的会占用更多的系统资源。优先级由静态优先级和内核根据进程执行情况所做的动态调整(目前只有+-5的调整)共同决定。nice值是进程的静态优先级,它的取值范围是-20~+19,从高至低。若希望Nginx占有更多资源,可以将nice值设置小一点但不建议小于内核进程nice值(通常为-5)
4.事件类配置项
序号 分类 语法 默认 说明
序号 分类 语法 默认 说明
1 是否打开accept锁 accept_mutex[on/off]; accept_mutex on; accept_mutex是Nginx负载均衡锁。这把锁可以让多个worker进程轮流地、序列化地与新的客户端建立TCP连接。当某一个worker建立的连接数达到worker_connections配置的最大数7/8时会大大减小该worker试图建立TCP连接的机会。以此实现所有worker进程之上处理的客户端请求数尽量接近。该锁默认打开。若关闭,建立TCP耗时会更短,但worker进程之间的负载会非常不均衡,不建议关闭。
2 lock文件的路径 lock_file path/file; lock_file logs/nginx.lock accept锁可能需要这个lock文件,如果accept锁关闭,lock_file配置完全不生效。若打开锁,且由于编译程序、操作系统结构等因素导致Nginx不支持原子锁,这时才会用文件锁实现accept锁,lock_file指定的lock文件才会生效。
3 使用accept锁到真正建立连接之间的延迟时间 accept_mutex_delay Nms; accept_mutex_delay 500ms; 使用accept锁,同一时间只有一个worker进程能够取到accept锁。该锁不是阻塞锁,若娶不到立刻返回,若一个worker视图取accept锁,取不到需要等accpet_mutex_delay定义的时间间隔后才能再次取锁。
4 批量建立新连接mult_accept [on/off]; multi_accept off; 当事件模型通知有新连接时,尽可能对本地调度中客户端发起的所有TCP请求都建立连接。
5 选择事件模型 use [kqueue/rtsig/epoll/ /dev/poll /select/poll/eventport]; Nginx会自动使用最合适的事件模型 对于Linux操作系统,可供选择的事件驱动模型有poll、select和epoll三种。epoll当然是性能最高的。
6 每个worker的最大连接数 worker_connections number; / 每个worker进程可以同时处理的最大连接数。

用HTTP核心模块配置一个静态Web服务器

静态Web服务器的主要功能由ngx_http_core_module模块(HTTP框架的主要成员)实现。
http {
    gzip on;
    upstream {
        ...
    }
    ...
    server {
        listen localhost:80;
        ...
        location /webstatic {
            if ... {
                
            }
            root /opt/webresource;
            ...
        }
        location ~*.(jpg|jpeg|png|jpe|gif)$ {
            ...
        }
    }
    server {
        ...
    }
}

所有HTTP配置项都必须直属于http块、server块、location块、upstream块或if块等(HTTP配置项自然必须会在http{}块之内)。
Nginx为配置一个完整的静态Web服务器提供了非常多的功能,分为以下8类:虚拟主机与请求的分类、文件路径的定义、内存及磁盘资源的分配、网络连接的设置、MIME类型的设置、对客户端请求的限制、文件操作的优化、对客户端请求的特殊处理。

1.虚拟主机与请求的分发

经常有多个主机域名对应着同一个IP地址情况,这时在nginx.conf中就可以按照server_name(对应用户请求的主机域名)并通过server块来定义虚拟主机,每个server块就是一个虚拟主机,它只处理与之对应的主机域名请求。
一台服务器上的Nginx以不同的方式处理访问不同主机域名的HTTP请求。
序号 分类 语法 默认 配置块 说明
序号 分类 语法 默认 配置块 说明
1 监听端口 listen address:port[default(在0.8.21已废弃)]/[default_server]/[bcaklog=num]/[rcvbuf=size]/[sndbuf=size]/[accept_filter=filter]/[deferred]/[bind]/ [ipv6only=[on/off]] /[ssl] listen 80; server listen参数决定Nginx服务如何监听端口。在listen后可以只加IP地址、端口号或主机名。不加端口号,默认监听80端口。参数说明:default/default_server--将所在的server块作为整个Web服务默认server块。如果没有设置该参数,将在nginx.conf配置文件中找到第一个server作为默认server块。如果无法匹配配置文件中的所有主机域名时,则会使用默认虚拟主机; backlog=num--表示TCP中backlog队列的大小。默认为-1,表不予设置。若设置队列满了,客户端建立连接将会失败; revbuf=size--表设置监听句柄的SO_RCVBUF参数; sndbuf=size--表设置监听句柄的SO_SNDBUF参数; accept_filter--设置accept过滤器,只对FreeBSD操作系统有用;deffered--在设置参数后,若用户发起连接请求,且完成了TCP的三次握手,内核也不会为这次的连接调度worker进程来处理,只有用户真的发生数据(内核已经在网卡中收到请求数据包),内核才会唤醒worker进程处理这个连接。【这个参数适用于大并发情况下,减轻worker进程的负担。】;bind--绑定当前端口/地址对,如127.0.0.1:8000,只有同时对一个端口监听多个地址时才会生效;ssl--在当前监听的端口上建立连接必须基于SSL协议。
2 主机名称 server_name name[...]; server_name ""; server server_name后可跟多个主机名称,如server_name wwww.testweb.com、download.testweb.com;在处理一个HTTP请求时,Nginx会取出header头中的Host与每个server中的server_name进行匹配,以此决定到底由哪一个server来处理这个请求。有可能一个Host与多个Server块中的server_name都匹配,这时会根据匹配优先级选择实际处理的server块。server_name与Host的匹配优先级:1)首先匹配选择所有字符串完全匹配的server_name,如www.testweb.com 2)其次选择通配符在前面的server_name,如.testweb.com 3)再次选择通配符在后面的server_name,如www.testweb. 4)最后选择使用正则表达式才匹配的server_name,如~^.testweb.com$;若都不匹配,会按下列顺序选择处理server块:1)优先选择listen配置项后加入[default
3 server_names_hash_bucket_size server_names_hash_bucket_size size; server_names_hash_bucket_size 32 64 128;
4 server_names_hash_max_size server_names_hash_max_size size; server_names_hash_max_size 512; http、server、location 该配置项会影响散列表的冲突率,值越大消耗的内存越多,但散列key的冲突率越低,检索速度更快;值越小,消耗内存越小,但散列key的冲突率可能增高
5 重定向主机名称的处理 server_name_in_redirect on/off; server_name_in_redirect on; http、server或location 该配置需配合server_name使用,on打开时,表示重定向请求时会使用server_name里配置的第一个主机名代替原先请求的Host头部;使用off时,则重定向请求时使用请求本身的Host头部
6 location location[=//*/^~/@]/uri/{...} / server 该配置会根据用户请求中的url来匹配上面的/uri表达式,如果可以配置则选择location{}块中的配置来处理用户请求。location匹配规则:1)=表示把uri作为字符串,完全匹配 2)~表示uri是大小写敏感的 3)~*表示忽略字母大小写问题 4)^~表示匹配uri只需前半部分与uri匹配即可,如location ~^ /image/{# 以/image/开始的请求都会匹配上} 5)@表示仅用于Nginx服务内部请求之间的重定向,带有@的location不直接处理用户请求。location是有顺序的,当一个请求匹配多个时,实际这个请求是被第一个处理

Nginx正是使用server_name配置项针对特定Host域名的请求提供不同的服务,以此实现虚拟主机功能。

实践出真知~
原文地址:https://www.cnblogs.com/NolaLi/p/14422475.html