Nginx学习课题
Nginx概述
Nginx是一款自由的、开源的、高性能的HTTP服务器和反向代理服务器;同时也是一个IMAP、POP3、SMTP代理服务器;Nginx可以作为一个HTTP服务器进行网站的发布处理,另外Nginx可以作为反向代理进行负载均衡的实现。
Nginx基础架构
- 源码目录结构
.
├── auto 自动检测系统环境以及编译相关的脚本
│ ├── cc 关于编译器相关的编译选项的检测脚本
│ ├── lib Nginx编译所需要的一些库的检测脚本
│ ├── os 与平台相关的一些系统参数与系统调用相关的检测
│ └── types 与数据类型相关的一些辅助脚本
├── conf 存放默认配置文件,在make install后,会拷贝到安装目录中去
├── contrib 存放一些实用工具,如geo配置生成工具(geo2nginx.pl)
├── html 存放默认的网页文件,在make install后,会拷贝到安装目录中去
├── man Nginx的man手册
└── src 存放Nginx的源代码
├── core Nginx核心源代码,包括常用数据结构的定义,及Nginx初始化运行的核心代码如main函数
├── event 对系统事件处理机制的封装,以及定时器的实现相关代码
│ └── modules 不同事件处理方式的模块化,如select、poll、epoll、kqueue等
├── http Nginx作为http服务器相关的代码
│ └── modules 包含http的各种功能模块
├── mail Nginx作为邮件代理服务器相关的代码
├── misc 一些辅助代码,测试c++头的兼容性,以及对google_perftools的支持
└── os 主要是对各种不同体系统结构所提供的系统函数的封装,对外提供统一的系统调用接口
- Nginx工作代码包括核心和功能模块。 Nginx的核心是负责维护严格的运行循环,并在请求处理的每个阶段执行模块代码的适当部分。模块构成了大部分的演示和应用层功能。模块读取和写入网络和存储,转换内容,执行出站过滤,应用服务器端包含操作,并在启用代理时将请求传递给上游服务器。
- Nginx的模块化架构通常允许开发人员扩展一组Web服务器功能,而无需修改Nginx内核。 Nginx模块略有不同,即核心模块,事件模块,阶段处理程序,协议,可变处理程序,过滤器,上游和负载均衡器。此时,Nginx不支持动态加载的模块;即在构建阶段将模块与核心一起编译。然而,对于未来的主要版本,计划对可加载模块和ABI的支持。
- 在处理与接受,处理和管理网络连接和内容检索相关的各种操作时,Nginx在基于Linux,Solaris和BSD的操作系统中使用事件通知机制和一些磁盘I / O性能增强,如kqueue,epoll,和事件端口。目标是为操作系统提供尽可能多的提示,以便及时获取入站和出站流量,磁盘操作,读取或写入套接字,超时等异步反馈。对于每个基于Unix的Nginx操作系统,大量优化了对多路复用和高级I / O操作的不同方法的使用。
Nginx的架构设计
- 优秀的模块化设计
- 事件驱动架构
- 请求多阶段异步处理
- 管理进程多工作的设计
Nginx架构图:
Nginx多层次结构图:
Nginx处理事件模型图:
Nginx主要优点
- 热部署
得益于master管理进程与worker工作进程的分离设计,使的Nginx具有热部署的功能,那么在7×24小时不间断服务的前提下,升级Nginx的可执行文件。也可以在不停止服务的情况下修改配置文件,更换日志文件等功能。
- 高并发
Nginx在网络应用中表现超群,在于其独特的设计。许多网络或应用服务器大都是基于线程或者进程的简单框架,最突出的地方就在于其成熟的事件驱动框架,它能应对现代硬件上成千上万的并发连接,10万远未封顶。
- 低内存消耗
在一般的情况下,10000个非活跃的HTTP Keep-Alive 连接在Nginx中仅消耗2.5M的内存,这也是Nginx支持高并发连接的基础。
- 处理响应请求快
在正常的情况下,单次请求会得到更快的响应。在高峰期,Nginx可以比其他的Web服务器更快的响应请求。
- 高可用性
对于访问量巨大的网站,面对高负载Nginx + keepalived 可对前端Nginx实现HA高可用。
Nginx反向代理与负载均衡原理
-
反向代理(Reverse Proxy)方式是指以代理服务器来接受internet上的连接请求,然后将请求转发给内部网络上的服务器,并将从服务器上得到的结果返回给internet上请求连接的客户端,此时代理服务器对外就表现为一个反向代理服务器。Nginx在做反向代理时,提供性能稳定,并且能够提供配置灵活的转发功能。Nginx可以根据不同的正则匹配,采取不同的转发策略,比如图片文件结尾的走文件服务器,动态页面走web服务器,只要你正则写的没问题,又有相对应的服务器解决方案,你就可以随心所欲的玩。并且Nginx对返回结果进行错误页跳转,异常判断等。如果被分发的服务器存在异常,他可以将请求重新转发给另外一台服务器,然后自动去除异常服务器。
Nginx反向代理工作流程如下:
-
负载均衡(Load Balance)是指将请求分摊到多个操作单元上进行执行,例如Web服务器、FTP服务器、企业关键应用服务器和其它关键任务服务器等,从而共同完成工作任务。
Nginx支持的负载均衡调度算法方式如下:
1.weight轮询(默认):接收到的请求按照顺序逐一分配到不同的后端服务器,即使在使用过程中,某一台后端服务器宕机,nginx会自动将该服务器剔除出队列,请求受理情况不会受到任何影响。 这种方式下,可以给不同的后端服务器设置一个权重值(weight),用于调整不同的服务器上请求的分配率;权重数据越大,被分配到请求的几率越大;该权重值,主要是针对实际工作环境中不同的后端服务器硬件配置进行调整的。
2.ip_hash:每个请求按照发起客户端的ip的hash结果进行匹配,这样的算法下一个固定ip地址的客户端总会访问到同一个后端服务器,这也在一定程度上解决了集群部署环境下session共享的问题。
3.(fair)(第三方):智能调整调度算法,动态的根据后端服务器的请求处理到响应的时间进行均衡分配,响应时间短处理效率高的服务器分配到请求的概率高,响应时间长处理效率低的服务器分配到的请求少;结合了前两者的优点的一种调度算法。但是需要注意的是Nginx默认不支持fair算法,如果要使用这种调度算法,请安装upstream_fair模块
4.url_hash(第三方):按照访问的url的hash结果分配请求,每个请求的url会指向后端固定的某个服务器,可以在nginx作为静态服务器的情况下提高缓存效率。同样要注意nginx默认不支持这种调度算法,要使用的话需要安装nginx的hash软件包
轮询算法流程图:
Ip hash算法流程图:
Nginx web运维实验
一、实验环境
准备3台虚拟机,其中一台搭建Nginx代理服务器,另外两台搭建测试服务器,实现使用Nginx的反向代理与负载均衡模块配置基于域名主机的访问。在整个实验环境中,我们假定webserver-1和webserver-1提供pzy.nginx.com的网站内容服务,Nginx在webserver-1和webserver-2前面作为反向代理服务器与负载均衡服务器,当用户访问pzy.nginx.com时,Nginx负载均衡器会把请求分发到两个节点服务器上,由节点服务器返回实际的内容数据。
主机类型 | 操作系统 | IP地址 | 作用 |
---|---|---|---|
宿主机 | MacOS 10.14 | 192.168100.1/24 | 远程3台虚拟机,进行配置,同时也作为测试使用的客户端。 |
虚拟机1:lb-1 | CentOS 7.4 | 192.168.100.105/24 | 用作负载均衡服务器和代理服务器,将请求分担到Web节点服务器中 |
虚拟机2:webserver-1 | CentOS 7.4 | 192.168.100.106/24 | Web节点服务器webserver-1 |
虚拟机3:webserver-2 | CentOS 7.4 | 192.168.100.107/24 | Web节点服务器webserver-2 |
实验拓扑:
二、环境搭建
- 在webserver-1服务器上安装apache
# 在webserver-1上安装httpd服务
[root@webserver-1 ~]# yum -y install httpd
# 修改默认主页内容为"webserver-1 is ok"
[root@webserver-1 ~]# echo "webserver-1 is ok" > /var/www/html/index.html
# 启动htppd并设为开机自启动
[root@webserver-1 ~]# systemctl start httpd
[root@webserver-1 ~]# systemctl enable httpd
Created symlink from /etc/systemd/system/multi-user.target.wants/httpd.service to /usr/lib/systemd/system/httpd.service.
# 关闭并禁用防火墙
[root@webserver-1 ~]# systemctl stop firewalld
[root@webserver-1 ~]# systemctl disable firewalld
# 修改默认监听端口为8080
[root@webserver-1 ~]# vim /etc/httpd/conf/httpd.conf
# Change this to Listen on specific IP addresses as shown below to
# prevent Apache from glomming onto all bound IP addresses.
#
#Listen 12.34.56.78:80
Listen 8080
# 重启httpd
[root@webserver-1 ~]# systemctl restart httpd
# 查看httpd监听端口
[root@webserver-1 ~]# netstat -anlpt | grep httpd
tcp6 0 0 :::8080 :::* LISTEN 6955/httpd
# 访问测试
[root@webserver-1 ~]# curl 192.168.100.106:8080
webserver-1 is ok
webserver-2按照webserver-1的步骤执行即可,不同的地方是将监听端口改为9090。在本地浏览器上输入http://192.168.100.106:8080和http://192.168.100.107:9090可以分别打开如下网页:
- 在服务器lb-1上编译安装Nginx
1.到官网上查看最新稳定版为nginx-1.16.0
# 安装nginx依赖包
[root@lb-1 ~]# yum -y install pcre-devel zlib-devel gcc-c++
# 下载Nginx-1.16.0
[root@lb-1 ~]# wget http://nginx.org/download/nginx-1.16.0.tar.gz
# 解压安装包
[root@lb-1 ~]# tar zxvf nginx-1.16.0.tar.gz
# 配置并检查依赖,添加用户和组nginx
[root@lb-1 nginx-1.16.0]# ./configure --prefix=/usr/local/nginx --user=nginx --group=nginx --with-http_stub_status_module
# 添加系统用户nginx
[root@lb-1 nginx-1.16.0]# useradd -s /sbin/nologin nginx -M
[root@lb-1 nginx-1.16.0]# tail -l /etc/passwd
games:x:12:100:games:/usr/games:/sbin/nologin
ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
nobody:x:99:99:Nobody:/:/sbin/nologin
systemd-network:x:192:192:systemd Network Management:/:/sbin/nologin
dbus:x:81:81:System message bus:/:/sbin/nologin
polkitd:x:999:998:User for polkitd:/:/sbin/nologin
sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin
postfix:x:89:89::/var/spool/postfix:/sbin/nologin
chrony:x:998:996::/var/lib/chrony:/sbin/nologin
nginx:x:1000:1000::/home/nginx:/sbin/nologin
# 加速编译
[root@lb-1 nginx-1.16.0]# make -j 33
# 编译安装
[root@lb-1 nginx-1.16.0]# make install
# 添加软链接
[root@lb-1 nginx-1.16.0]# ln -s /usr/local/nginx/sbin/nginx /usr/sbin/
# 测试nginx语法
[root@lb-1 nginx-1.16.0]# nginx -t
nginx: the configuration file /usr/local/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /usr/local/nginx/conf/nginx.conf test is successful
2.配置nginx
[root@lb-1 nginx-1.16.0]# vim /usr/local/nginx/conf/nginx.conf
user nginx;
worker_processes 1;
#error_log logs/error.log;
#error_log logs/error.log notice;
#error_log logs/error.log info;
#pid logs/nginx.pid;
events {
worker_connections 1024;
#接受尽可能多的链接
multi_accept on;
#设置轮询方法
use epoll;
}
http {
#关闭错误页面中版本号
server_tokens off;
#发送所有头文件,不要缓存数据
tcp_nopush on;
tcp_nodelay on;
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"';
#access_log logs/access.log main;
#缓冲数据
sendfile on;
#tcp_nopush on;
#keepalive_timeout 0;
keepalive_timeout 65;
#gzip on;
upstream webserver {
server 192.168.100.106:8080 weight=10;
server 192.168.100.107:9090 weight=10;
}
server {
listen 80;
server_name pzy.nginx.com;
#charset koi8-r;
#access_log logs/host.access.log main;
location / {
root html;
index index.html index.htm;
proxy_pass http://webserver;
}
#添加日志
access_log /var/logs/nginx/access_log;
#error_page 404 /404.html;
# redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
3.配置完成后重启nginx并检查语法
[root@lb-1 nginx-1.16.0]# nginx -s reload
[root@lb-1 nginx-1.16.0]# nginx -t
nginx: the configuration file /usr/local/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /usr/local/nginx/conf/nginx.conf test is successful
4.查看nginx监听状态
root@lb-1 nginx-1.16.0]# netstat -anlpt | grep nginx
tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN 10315/nginx: master
5.创建日志目录
[root@lb-1 nginx-1.16.0]# mkdir -p /var/logs/nginx/
6.修改本地主机hosts文件
pzy# vim /etc/hosts
##
# Host Database
#
# localhost is used to configure the loopback interface
# when the system is booting. Do not change this entry.
##
127.0.0.1 localhost
255.255.255.255 broadcasthost
::1 localhost
192.168.100.105 pzy.nginx.com
三、负载均衡测试
在新的窗口中动态查看日志信息
[root@lb-1 ~]# curl pzy.nginx.com
webserver-1 is ok
[root@webserver-1 ~]# curl pzy.nginx.com
webserver-2 is ok
[root@webserver-1 ~]# curl pzy.nginx.com
webserver-1 is ok
[root@lb-1 ~]# tail -f /var/logs/nginx/access_log
查看日志,可以看到各个节点的访问请求
浏览器访问pzy.nginx.com刷新,我们可以看到两种页面,说明nginx已经把我们的请求分发到不同的地方去了,已实现轮询
四、Nginx参数优化
- 配置整理
# 运行用户
user www-data;
# 启动进程,通常设置成和cpu的数量相等
worker_processes 1;
# 全局错误日志及PID文件
error_log /var/log/nginx/error.log;
pid /var/run/nginx.pid;
# 工作模式及连接数上限
events {
use epoll; #epoll是多路复用IO(I/O Multiplexing)中的一种方式,但是仅用于linux2.6以上内核,可以大大提高nginx的性能
worker_connections 1024; #单个后台worker process进程的最大并发链接数
# multi_accept on;
}
#设定http服务器,利用它的反向代理功能提供负载均衡支持
http {
#设定mime类型,类型由mime.type文件定义
include /etc/nginx/mime.types;
default_type application/octet-stream;
#设定日志格式
access_log /var/log/nginx/access.log;
#sendfile 指令指定 nginx 是否调用 sendfile 函数(zero copy 方式)来输出文件,对于普通应用,
#必须设为 on,如果用来进行下载等应用磁盘IO重负载应用,可设置为 off,以平衡磁盘与网络I/O处理速度,降低系统的uptime.
sendfile on;
#将tcp_nopush和tcp_nodelay两个指令设置为on用于防止网络阻塞
tcp_nopush on;
tcp_nodelay on;
#连接超时时间
keepalive_timeout 65;
#开启gzip压缩
gzip on;
gzip_disable "MSIE [1-6]\.(?!.*SV1)";
#设定请求缓冲
client_header_buffer_size 1k;
large_client_header_buffers 4 4k;
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;
#设定负载均衡的服务器列表
upstream mysvr {
#weigth参数表示权值,权值越高被分配到的几率越大
#本机上的Squid开启3128端口
server 192.168.8.1:3128 weight=5;
server 192.168.8.2:80 weight=1;
server 192.168.8.3:80 weight=6;
}
server {
#侦听80端口
listen 80;
#定义使用www.xx.com访问
server_name www.xx.com;
#设定本虚拟主机的访问日志
access_log logs/www.xx.com.access.log main;
#默认请求
location / {
root /root; #定义服务器的默认网站根目录位置
index index.php index.html index.htm; #定义首页索引文件的名称
fastcgi_pass www.xx.com;
fastcgi_param SCRIPT_FILENAME $document_root/$fastcgi_script_name;
include /etc/nginx/fastcgi_params;
}
# 定义错误提示页面
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /root;
}
#静态文件,nginx自己处理
location ~ ^/(images|javascript|js|css|flash|media|static)/ {
root /var/www/virtual/htdocs;
#过期30天,静态文件不怎么更新,过期可以设大一点,如果频繁更新,则可以设置得小一点。
expires 30d;
}
#PHP 脚本请求全部转发到 FastCGI处理. 使用FastCGI默认配置.
location ~ \.php$ {
root /root;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME /home/www/www$fastcgi_script_name;
include fastcgi_params;
}
#设定查看Nginx状态的地址
location /NginxStatus {
stub_status on;
access_log on;
auth_basic "NginxStatus";
auth_basic_user_file conf/htpasswd;
}
#禁止访问 .htxxx 文件
location ~ /\.ht {
deny all;
}
}
#第一个虚拟服务器
server {
#侦听192.168.8.x的80端口
listen 80;
server_name 192.168.8.x;
#对aspx后缀的进行负载均衡请求
location ~ .*\.aspx$ {
root /root;#定义服务器的默认网站根目录位置
index index.php index.html index.htm;#定义首页索引文件的名称
proxy_pass http://mysvr;#请求转向mysvr 定义的服务器列表
#以下是一些反向代理的配置可删除.
proxy_redirect off;
#后端的Web服务器可以通过X-Forwarded-For获取用户真实IP
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
client_max_body_size 10m; #允许客户端请求的最大单文件字节数
client_body_buffer_size 128k; #缓冲区代理缓冲用户端请求的最大字节数,
proxy_connect_timeout 90; #nginx跟后端服务器连接超时时间(代理连接超时)
proxy_send_timeout 90; #后端服务器数据回传时间(代理发送超时)
proxy_read_timeout 90; #连接成功后,后端服务器响应时间(代理接收超时)
proxy_buffer_size 4k; #设置代理服务器(nginx)保存用户头信息的缓冲区大小
proxy_buffers 4 32k; #proxy_buffers缓冲区,网页平均在32k以下的话,这样设置
proxy_busy_buffers_size 64k; #高负荷下缓冲大小(proxy_buffers*2)
proxy_temp_file_write_size 64k; #设定缓存文件夹大小,大于这个值,将从upstream服务器传
}
}
}
-
优化nginx进程个数的策略
在高并发、高访问量的web服务场景,需要事先启动好更多的nginx进程,以保证快速响应并处理大量并发用户的请求。
worker_processes 1;一般调整到与CPU的核数相同(如,2个四核的cpu计为8)
# 查看LInux可查看CPU个数及总核数 grep processor /proc/cpuinfo|wc -l # 查看CPU总颗数 grep 'physical id' /proc/cpuinfo|sort|uniq|wc -l # 通过执行top命令,然后按数字1,即可显示所有的CPU核数 top 按1键就会显示第一个的信息 Cpu0 : 0.0%us, 0.0%sy, 0.0%ni,100.0%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0
-
优化绑定不同的nginx进程到不同的CPU上
默认情况下,nginx的进程跑在某一个CPU或CPU的某一个核上,导致nginx进程使用硬件的资源不均,本节的优化是不同的nginx进程给不同的CPU处理,充分有效的利用有效的硬件资源
# 四核cpu配置 worker_processes 4; worker_cpu_affinity 0001 0010 0100 1000; # 双核配置 worker_processes 2; worker_cpu_affinity 0101 1010;
还有一个命令taskset -c用来分配服务给CPU
-
开启高效传输模式
sendfile on;
tcp_nopush on;
tcp_nodelay on;
server_tokens off;
server_names_hash_bucket_size 128;
server_names_hash_max_size 512;
keepalive_timeout 65;
client_header_timeout 15s;
client_body_timeout 15s;
send_timeout 60s;
五、Nginx监控
- 通过安装http_stub_status_module模块实现页面监控展示
# 查看模块安装情况
[root@lb-1 nginx-1.16.0]# /usr/local/nginx/sbin/nginx -V
nginx version: nginx/1.16.0
built by gcc 4.8.5 20150623 (Red Hat 4.8.5-36) (GCC)
configure arguments: --prefix=/usr/local/nginx --user=nginx --group=nginx --with-http_stub_status_module
# 修改配置文件nginx.conf,在server块中增加
location /nginx_status {
# 开启nginx状态监控
stub_status on;
# 关闭日志
access_log off;
# Security: Only allow access from 192.168.100.1 IP #
allow 192.168.100.1;
# Send rest of the world to /dev/null #
#deny all;
}
# 重启nginx
[root@lb-1 nginx-1.16.0]# nginx -s reload
本地浏览器输入192.168.100.105/nginx_status查看监控状态
Active connections: 1
server accepts handled requests
9 9 79
Reading: 0 Writing: 1 Waiting: 0
ctive connections:与后端建立的服务连接数
server accepts handled requests:Nginx总共处理了9个连接,成功创建了9次握手,总共处理了79个请求
Reading:nginx读取到客户端的Header信息数
Writing:nginx返回到客户端的Header信息数
Waiting:开启Keep-alive的情况下,这个值等于 Active -(Reading + Writing)。表示nginx已经处理完成,正在等候下次一次请求的连接数。
说明:如果Reading + Writing数量比较高,表示当前并发很大;如果Waiting较大,表示处理的很快,已经在等待之后的请求了。
- 通过命令查看监控详情
1.查看哪些ip正在连接
[root@lb-1 ~]# netstat -an
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address Foreign Address State
tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN
tcp 0 0 127.0.0.1:25 0.0.0.0:* LISTEN
tcp 0 0 192.168.100.105:22 192.168.100.1:51630 ESTABLISHED
tcp6 0 0 :::22 :::* LISTEN
tcp6 0 0 ::1:25 :::* LISTEN
udp 0 0 127.0.0.1:323 0.0.0.0:*
udp6 0 0 ::1:323 :::*
raw6 0 0 :::58 :::* 7
2.查看当前Nginx运行状态
[root@lb-1 ~]# netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}'
ESTABLISHED 1
CLOSE_WAIT:表示被动关闭
ESTABLISHED:当前并发连接数
TIME_WAIT:主动关闭,处理完毕,等待超时结束的连接数
3.查看Web服务和Nginx进程数
[root@lb-1 ~]# ps -ef | grep httpd | wc -l
1
[root@lb-1 ~]# ps -ef | grep nginx | wc -l
3
4.查看http占用内存的平均数
[root@lb-1 ~]# ps aux|grep -v grep|awk '/httpd/{sum+=$6;n++};END{print sum/n}'
976
5.查看Nginx中访问前10的ip
# 格式:awk '{print $1}' 日志文件路径 | sort | uniq -c | sort -nr -k1 | head -n 10
[root@lb-1 ~]# awk '{print $1}' /var/logs/nginx/access_log | sort
192.168.100.1
192.168.100.1
192.168.100.1
192.168.100.1
192.168.100.1
192.168.100.1
...