网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
worker进程主要关注点是与客户端或后端服务器(此时nginx作为中间代理)之间的数据可读/可写等I/O交互事件,所以工作进程的阻塞点是在像select()、epoll_wait()等这样的I/O多路复用函数调用处,以等待发生数据可读/写事件。当然也可能被新收到的进程信号中断。
worker进程个数:
如果负载以CPU密集型应用为主,一般会设置与机器cpu核数一致或少一个(用来处理用户等其他任务);
如果负载以IO密集型为主,如响应大量内容给客户端,则worker数应该为CPU个数的1.5或2倍。
因为更多的worker数,只会导致进程来竞争cpu资源了,从而带来不必要的上下文切换。而且,nginx为了更好的利用多核特性,具有cpu绑定选项,我们可以将某一个进程绑定在某一个核上,这样就不会因为进程的切换带来cache的失效。
更具体的可以根据公式:Nthread = Ncpu*Ucpu*(1+W/C),Ncpu是cpu的个数,Ucpu是cpu的使用率,W为等待时间,C为计算时间。这时需要通过监控工具来获取相应数据来计算。
最后,再以监控工具数据为准进行微调。
4-3、并发处理
A、在master进程里面,先创建socket,并bind、listen在80端口(所以master进程需要root权限);
B、然后再fork出多个worker进程,这样每个worker进程都可以去accept这个socket(会产生惊群问题), 或者使用锁机制,让抢到锁的一个worker进程去accept这个socket,注意这里一般使用select/poll/epoll机制来解决accept阻塞问题;
C、当一个新连接进来后,而只有抢到锁的一个进程可以accept这个连接进行处理(也是放入epoll中);
D、抢到锁的worker进程accept到新连接后,会立即释放锁;然后所有worker进程再次参与抢锁,这样就回到了第二步,进行循环处理并发连接;
4-4、惊群问题
A、生产原因:像上面第二步,多个worker进程等待同一个socket的连接事件,当这个事件发生时,这些进程被同时唤醒,就是惊群。
注意,在linux2.6内核上,accept系统调用已经不存在惊群,但用epoll机制来解决accept阻塞问题,epoll_wait会有惊群问题(新增 EPOLLEXCLUSIVE 选项解决了)。
B、导致后果:许多worker进程被内核重新调度唤醒,只有一个进程可以accept这个连接进行处理,其他余者皆失败,导致性能浪费。
C、nginx解决方案:使用锁机制,让抢到锁的一个worker进程去accept(epoll_wait)这个socket;如果操作系统支持原子整型,才会使用共享内存实现原子上锁,否则使用文件上锁。
5、Nginx配置说明
5-1、配置文件区域说明
nginx主要配置文件nginx.conf,里面主要包括以下几个配置区域,如下表:
| 配置区域 | 说明 |
| main块 | 配置影响nginx全局的指令。一般有运行nginx服务器的用户组,nginx进程pid存放路径,日志存放路径,配置文件引入,允许生成worker process数等。 |
| events块 | 配置影响nginx服务器或与用户的网络连接。有每个进程的最大连接数,选取哪种事件驱动模型处理连接请求,是否允许同时接受多个网路连接,开启多个网络连接序列化等。 |
| http块 | 可以嵌套多个server,配置代理,缓存,日志定义等绝大多数功能和第三方模块的配置。如文件引入,mime-type定义,日志自定义,是否使用sendfile传输文件,连接超时时间,单连接请求数等。 |
| upstream块 | 配置HTTP负载均衡器分配流量到几个应用程序服务器。 |
| server块 | 配置虚拟主机的相关参数,一个http中可以有多个server。 |
| location块 | 配置请求的路由,以及允许根据用户请求的URI来匹配指定的各location以进行访问配置;匹配到时,将被location块中的配置所处理。 |
nginx文件结构如下:
[plain]
view plain
copy
- … #main全局块
- events { #events块
- …
- }
- http #http块
- {
- … #http全局块
- upstream … # upstream负载均衡块
- {
- …
- }
- server #server块
- {
- … #server全局块
- location [PATTERN] #location块
- {
- …
- }
- location [PATTERN]
- {
- …
- }
- }
- server
- {
- …
- }
- … #http全局块
- }
5-2、Nginx核心功能配置
nginx核心功能配置主要是main和events的顶层全局配置,都是配置nginx核心模块(ngx_core_module),管理服务器级别的行为。下表包含是大部分常用的配置选项,更多配置请参考官方文档:http://nginx.org/en/docs/ngx_core_module.html
| 配置类别 | 配置选项 | 上下文 | 语法 | 默认值 | 功能描述 |
| 基本配置 | user | main | user username [groupname] | nobody | 以那个用户身份运行,以在configure指定的用户为准 |
| pid | main | pid /path/to/pid_filename | nginx.pid | 指定nginx的pid文件 |
| worker_rlimit_nofile | main | | 受linux内核文件描述符数量限制 | 指定一个worker进程所能够打开的句柄数。因为Linux对每个进程所能打开的文件描述数量是有限制的,默认一般是1024个,可通过ulimit -n FILECNT或/etc/securit/limits.conf配置修改linux默认能打开的文件句柄数限制。建议值为:系统最大数量/进程数。但进程间工作量并不是平均分配的,所以可以设置在大一些。推荐值为:655350。 |
| 优化性能相关配置 | worker_procrsses | main | worker_processes number | auto; | 1 | **work进程的个数.**如果负载以CPU密集型应用为主,一般会设置与机器cpu核数一致或少一个(用来处理用户等其他任务),如果负载以IO密集型为主,如响应大量内容给客户端,则worker数应该为CPU个数的1.5或2倍。因为更多的worker数,只会导致进程来竞争cpu资源了,从而带来不必要的上下文切换。而且,nginx为了更好的利用多核特性,具有cpu绑定选项,我们可以将某一个进程绑定在某一个核上,这样就不会因为进程的切换带来cache的失效。 |
| worker_cpu_affinity | main | worker_cpu_affinity cpumask …; | 无,不绑定 | 将工作进程绑定到特定的CPU上,减少CPU在进程之间切换的开销。用二进制bit位表示进程绑定在哪个CPU内核。如4工作进程4内核:worker_processes 4; worker_cpu_affinity 0001 0010 0100 1000; 2工作进程4内核: worker_processes 2; worker_cpu_affinity 0101 1010; |
| worker_priority | main | worker_priority number; | 0 | 工作进程调度优先级,-20到19之间的值,值越小越优先调用。如果系统同时运行多个任务,你可能需要提高nginx的工作进程的优先级 |
| timer_resolution | main | timer_resolution interval; | 无 | 每次内核事件调用返回时,都会使用gettimeday()来更新nginx缓存时钟;timer_resolution用于定义每隔多久才会由gettimeday()更新一次缓存时钟;