01 Nginx的高并发处理
文章目录
- Nginx的高并发处理
- 1.为什么需要Nginx?
- 2.Nginx概述
- 2.1 Nginx介绍
- 2.2 Nginx和apache的优缺点
- 2.2.1 Nginx相对于apache的优点
- 2.2.2 apache相对于Nginx的优点
- 2.2.3 Tengine介绍
- 3. Nginx的下载与安装
- 3.1 Nginx下载
- 3.2 Nginx的源码安装
- 3.2.1 安装前的准备工作
- 3.2.2 安装Nginx
- 4. Nginx的工作模型
- 4.1 Master-Worker 模式
- 4.2 accept_mutex
- 4.3 为什么使用进程不使用线程?
- 4.4 如何处理并发请求?
- 5. Nginx参数详解
- 5.1 nginx.conf 配置文件全览
- 5.1.1 第一部分:全局块
- 5.1.2 第二部分:events块
- 5.1.3 第三部分:http块{}
- 5.1.3.1 http全局块
- 5.1.3.2 server块
- 5.2 工作模式与连接数上限
- 5.3 开启零拷贝
- 5.4 keepalive_timeout
- 5.5 是否启用压缩
- 5.6 autoindex
- 5.7 nginx虚拟主机演示
- 5.8 日志配置
- 5.9 Location
- 5.10 Bug https protocol requires SSL support in
- 6. 反向代理
- 6.1 正向代理服务器
- 6.2 反向代理服务器
- 6.3 反向代理之负载均衡
- 7. Nginx调优
- 7.1 worker_processes 的设置
- 7.2 worker_cpu_affinity的设置
- 8. session共享
- 8.1 session一致性解决方案
- 8.2 安装memcached
- 8.2.1 node2 和 node3上安装jdk 和 tomcat
- 8.2.2 nginx1上安装memcached
- 8.2.3 配置session 共享(node2 和 node3)
- 9. 反向代理之动静分离
- 9.1 动静分离需求分析
- 9.3 动静分离具体实现
- gitee地址:大型网站高并发处理
大型网站高并发处理传送门:
- 01 Nginx的高并发处理
- 02 Nginx和Keepalived高可用
Nginx的高并发处理
1.为什么需要Nginx?
比如:淘宝双11,在1秒中就会有上百万的并发。在做web项目时,通常通过Tomcat来做,在进程里启动线程的方式。服务器需要处理线程的创建与销毁、线程调度,这些都需要消耗一定的资源。所以,经过测试单个Tomcat支持最高并发如下:
怎么解决高并发问题,解决单个服务器过载问题?
答:Nginx起到反向代理的功能,实现负载均衡,解决高并发问题。通过轮询将请求转发到其他服务器节点上。Nginx可以做到50000左右的并发。
转发:
- 建立握手连接
- 接收请求.分析url
- 转发给对应的后端服务器
- 等待后端的响应
2.Nginx概述
2.1 Nginx介绍
Nginx (“engine x”) 是一个高性能的 静态 HTTP 和 反向代理 服务器,也是一个 IMAP/POP3/SMTP 代理服务器。
第一个公开版本 0.1.0 发布于 2004 年 10 月 4 日。
其将源代码以类 BSD 许可证的形式发布,因它的稳定性、丰富的功能集、示例配置文件和低系统资源的消耗而闻名
官方测试 nginx 能够支撑 5 万并发链接,并且 cpu、内存等资源消耗却非常低,运行非常稳定
2011 年 6 月 1 日,nginx 1.0.4 发布。apache httpd
Nginx 是一款轻量级的 Web 服务器/反向代理服务器及电子邮件(IMAP/POP3)代理服务器,并在一个 BSD-like 协议下发行。由俄罗斯的程序设计师 Igor Sysoev 所开发,其特点是占有内存少,并发能力强,事实上 nginx 的并发能力确实在同类型的网页服务器中表现较好,中国大陆使用 nginx 网站用户有:新浪、网易、腾讯等。
2.2 Nginx和apache的优缺点
2.2.1 Nginx相对于apache的优点
轻量级,同样起 web 服务,比 apache 占用更少的内存及资源
抗并发 , nginx 处 理请求是异步非阻塞 ( 可 参 考 文 章 https://zhuanlan.zhihu.com/p/82935440)的,而 apache 则是阻塞型的, 在高并发下 nginx 能保持低资源低消耗高性能 NIO netty NIO
高度模块化的设计,编写模块相对简单
社区活跃,各种高性能模块出品迅速
2.2.2 apache相对于Nginx的优点
rewrite ,比 nginx 的 rewrite 强大
模块超多,基本想到的都可以找到
少 bug ,nginx 的 bug 相对较多
Nginx 配置简洁, Apache 复杂
最核心的区别在于apache是同步多进程模型,一个连接对应一个进程中线程;nginx是异步非阻塞的,多个连接(万级别)可以对应一个进程
2.2.3 Tengine介绍
tengine 网址:http://tengine.taobao.org/
Tengine 是由淘宝网发起的 Web 服务器项目。它在 Nginx 的基础上,针对大访问量网站的需求,添加了很多高级功能和特性。Tengine 的性能和稳定性已经在大型的网站如淘宝网,天猫商城等得到了很好的检验。它的最终目标是打造一个高效、稳定、安全、易用的Web 平台
从2011年12月开始,Tengine 成为一个开源项目,Tengine 团队在积极地开发和维护着它。Tengine 团队的核心成员来自于淘宝、搜狗等互联网企业。Tengine 是社区合作的成果,我们欢迎大家参与其中,贡献自己的力量
tengine和nginx性能测试 : http://tengine.taobao.org/document_cn/benchmark_cn.html
Tengine 相比 Nginx 默认配置,提升 200%的处理能力。
Tengine 相比 Nginx 优化配置,提升 60%的处理能力。
tengine 更详细参数解释详见: http://tengine.taobao.org/nginx_docs/cn/docs/
3. Nginx的下载与安装
3.1 Nginx下载
官网下载 Nginx 软件 http://nginx.org 。Nginx 官方提供了三个类型的版本:
Mainline Version:主线版,是最新版,但未经过过多的生产测试。
Stable Version:稳定版,生产环境使用版本。
Legacy Version:老版本。
我们需要下载的是 Stable Version。其中又分为两种版本:Linux 版与 Windows 版。 开发时这两个版本我们都下载。Linux 版用于生产环境,而 Windows 版用于开发测试。
3.2 Nginx的源码安装
3.2.1 安装前的准备工作
克隆一个没有安装其它软件的纯净主机。名为:nginx1。完成以下配置:
修改主机名
vim /etc/sysconfig/network
修改网络配置
vim /etc/sysconfig/network-scripts/ifcfg-eth0
3.2.2 安装Nginx
安装源码编译以及 Nginx 依赖的库
[root@nginx1 ~]# yum install gcc gcc-c++ pcre pcre-devel openssl openssl-devel zlib zlib-devel -y
创建存放源文件的文件夹
首先在目录/opt 下创建 apps 目录,用于存放源文件以及解压后的文件
[root@nginx1 ~]# mkdir /opt/apps/
上传 Nginx 到 2 创建的目录
解压 Nginx
[root@nginx1 apps]# pwd /opt/apps [root@nginx1 apps]# ls nginx-1.16.1.tar.gz [root@nginx1 apps]# tar -zxvf nginx-1.16.1.tar.gz
进入到/opt/apps 目录中的 Nginx 解压包目录,查看 Nginx 的目录。 其中各个目录中存放的文件作用为:
- auto:存放 Nginx 自动安装的相关文件
- conf:存放 Nginx 服务器配置文件
- configure:命令,用于对即将安装的软件的配置,完成 makefile 编译文件的生成
- contrib:存放由其他机构贡献的文档材料
- html:存放 Nginx 欢迎页面
- man:manual,手册,存放 Nginx 帮助文档
- src:存放 Nginx 源码
生成 makefile
在 Nginx 解压目录下运行 make 命令,用于完成编译。但此时会给出提示:没有指定目标,并且没有发现编译文件 makefile。编译命令 make 需要根据编译文件makefile 进行编译,所以在编译之前需要先生成编译文件 makefile。使用 configure命令可以生成该文件。那么,configure 命令需要配置些什么参数呢?使用
--help
可以查看到可以使用的参数说明。这些参数可以分为三类:- 第一类:基本信息的配置
- 第二类:默认没有安装,可以指定安装的模块,使用–with开头。Nginx 的高扩展性就体现在这里
- 第三类:默认已经安装,可以指定卸载的模块,使用–without开头
下面是简单配置的命令执行。命令中每一行的最后添加了反斜杠\表示当前命令并未结束,回车不会执行该命令。执行成功后,会给出配置报告。下面以安装对 https 访问协议支持的模块 http_ssl_module 为例。
--prefix
:用于指定 nginx 的安装目录。注意,安装目录与解压目录不一样--http_ssl_module
:https 访问协议需要安装 Http 安全连接协议模块 SSL(Secure SocketsLayer,安全套接层)。注意,在执行过 configure 命令后并不会立即生成/usr/local/nginx 目录,也不会马上开始安装指定的模块,而仅仅是将命令中指定的参数及默认配置写入到即将要生成的 Makefile 文件中
配置报告以两部分构成:第一部分给出了配置的系统库;第二部分给出了系统配置信息
- path prefix:Nginx 安装目录
- binary file:Nginx 命令文件
- modules path:Nginx 模块存放路径
- configuration prefix:Nginx 配置文件存放路径
- configuration file:Nginx 配置文件名
- pid file:Nginx 的进程 id 文件
- error log file:错误日志文件
- http access log file:http 访问日志文件;
- http xxx:其它 http 请求相关的文件。
配置成功后,再次查看 Nginx 解压目录,发现其中多出了一个文件 Makefile。后面的编译就是依靠该文件进行的。
复杂安装:
注意: /var/tmp/nginx/client目录需要手动创建,并且需要创建nginx用户与用户组
[root@nginx1 nginx-1.16.1]# mkdir –p /var/tmp/nginx/client [root@nginx1 nginx-1.16.1]# pwd /opt/apps/nginx-1.16.1 [root@nginx1 nginx-1.16.1]# ./configure \ --prefix=/opt/nginx \ --sbin-path=/usr/sbin/nginx\ --conf-path=/etc/nginx/nginx.conf \ --error-log-path=/var/log/nginx/error.log \ --http-log-path=/var/log/nginx/access.log \ --pid-path=/var/run/nginx/nginx.pid \ --lock-path=/var/lock/nginx.lock \ --user=nginx \ 10 --group=nginx \ --with-http_ssl_module \ --with-http_flv_module \ --with-http_stub_status_module \ --with-http_gzip_static_module \ --http-client-body-temp-path=/var/tmp/nginx/client/ \ --http-proxy-temp-path=/var/tmp/nginx/proxy/ \ --http-fastcgi-temp-path=/var/tmp/nginx/fcgi/ \ --http-uwsgi-temp-path=/var/tmp/nginx/uwsgi \ --http-scgi-temp-path=/var/tmp/nginx/scgi \ --with-pcre
简单安装:使用简单安装,指定安装目录和 https 访问支持
[root@nginx1 nginx-1.16.1]# ./configure --prefix=/opt/nginx --with-http_ssl_module --with-http_gzip_static_module --error-log-path=/var/log/nginx/nginx.log --pid-path=/var/log/nginx/pid
编译安装
这是两个命令,make 为编译命令,make install 为安装命令,可以分别执行。这里使用&&将两个命令连接执行,会在前面命令执行成功的前提下才会执行第二个命令
[root@nginx1 nginx-1.16.1]# make && make install
nginx命令随处可用
在 Nginx 的安装目录/opt/nginx 中有一个 sbin 目录,其中存放着 nginx 的命令程序 nginx。默认情况下,若要使用 nginx 命令,则必须要在/opt/nginx/sbin 目录中,或指定命令路径,使用起来很不方便。
[root@nginx1 ~]# cd /opt/nginx/ [root@nginx1 nginx]# ls conf html logs sbin [root@nginx1 nginx]# cd sbin/ [root@nginx1 sbin]# ls nginx [root@nginx1 sbin]# ./nginx [root@nginx1 sbin]# ps aux|grep nginx root 1131 0.0 0.1 47332 1196 ? Ss 11:31 0:00 nginx: master process ./nginx nobody 1132 0.0 0.1 47772 1784 ? S 11:31 0:00 nginx: worker process root 1134 0.0 0.0 103256 864 pts/0 S+ 11:31 0:00 grep nginx [root@nginx1 sbin]# kill -9 1131 1132 [root@nginx1 sbin]# ps aux|grep nginx root 1136 0.0 0.0 103256 864 pts/0 S+ 11:32 0:00 grep nginx
为了能够在任意目录下均可直接执行 nginx 命令,通过下面的方式来完成。
添加安装的 nginx 到服务列表:将如下内容添加到/etc/init.d/nginx 脚 本中,nginx 需要具有可执行权限。
[root@nginx1 nginx-1.16.1]# vim /etc/init.d/nginx#!/bin/sh # # nginx - this script starts and stops the nginx daemon # # chkconfig: - 85 15 # description: Nginx is an HTTP(S) server, HTTP(S) reverse \ # proxy and IMAP/POP3 proxy server # processname: nginx # config: /etc/nginx/nginx.conf # config: /etc/sysconfig/nginx # pidfile: /var/run/nginx.pid# Source function library. . /etc/rc.d/init.d/functions# Source networking configuration. . /etc/sysconfig/network# Check that networking is up. [ "$NETWORKING" = "no" ] && exit 0nginx="/opt/nginx/sbin/nginx" prog=$(basename $nginx)NGINX_CONF_FILE="/opt/nginx/conf/nginx.conf"[ -f /etc/sysconfig/nginx ] && . /etc/sysconfig/nginxlockfile=/var/lock/subsys/nginxmake_dirs() {# make required directoriesuser=`nginx -V 2>&1 | grep "configure arguments:" | sed 's/[^*]*--user=\([^ ]*\).*/\1/g' -`options=`$nginx -V 2>&1 | grep 'configure arguments:'`for opt in $options; do if [ `echo $opt | grep '.*-temp-path'` ]; then value=`echo $opt | cut -d "=" -f 2` if [ ! -d "$value" ]; then # echo "creating" $value mkdir -p $value && chown -R $user $value fi fi done }start() { [ -x $nginx ] || exit 5[ -f $NGINX_CONF_FILE ] || exit 6 make_dirs echo -n $"Starting $prog: " daemon $nginx -c $NGINX_CONF_FILE retval=$? echo [ $retval -eq 0 ] && touch $lockfile return $retval }stop() { echo -n $"Stopping $prog: " killproc $prog -QUIT retval=$? echo [ $retval -eq 0 ] && rm -f $lockfile return $retval }restart() { configtest || return $? stop sleep 1 start }reload() { configtest || return $?echo -n $"Reloading $prog: " killproc $nginx -HUP RETVAL=$? echo }force_reload() { restart }configtest() { $nginx -t -c $NGINX_CONF_FILE }rh_status() { status $prog }rh_status_q() { rh_status >/dev/null 2>&1 }case "$1" in start) rh_status_q && exit 0 $1;; stop)rh_status_q || exit 0 $1;; restart|configtest)$1;; reload) rh_status_q || exit 7 $1;; force-reload) force_reload ;; status) rh_status ;; condrestart|try-restart) rh_status_q || exit 0 ;; *)echo $"Usage: $0{start|stop|status|restart|condrestart|try-restart|reload|force-reloa d|configtest}" exit 2 esac
修改 nginx 文件的执行权限
[root@nginx1 sbin]# chmod +x /etc/init.d/nginx
添加该文件到系统服务中去
[root@nginx1 ~]# chkconfig --add nginx
查看是否添加成功
[root@nginx1 ~]# chkconfig |grep nginx nginx 0:off 1:off 2:off 3:off 4:off 5:off 6:off
启动
[root@nginx1 ~]# service nginx start Starting nginx:
访问:
停止
[root@nginx1 ~]# service nginx stop
重新装载
[root@nginx1 ~]# service nginx reload
查看状态
[root@nginx1 ~]# service nginx status
设置开机启动
[root@nginx1 ~]# chkconfig nginx on [root@nginx1 ~]# chkconfig auditd 0:off 1:off 2:on 3:on 4:on 5:on 6:off blk-availability 0:off 1:on 2:on 3:on 4:on 5:on 6:off crond 0:off 1:off 2:on 3:on 4:on 5:on 6:off htcacheclean 0:off 1:off 2:off 3:off 4:off 5:off 6:off httpd 0:off 1:off 2:off 3:off 4:off 5:off 6:off ip6tables 0:off 1:off 2:on 3:on 4:on 5:on 6:off iptables 0:off 1:off 2:off 3:off 4:off 5:off 6:off iscsi 0:off 1:off 2:off 3:on 4:on 5:on 6:off iscsid 0:off 1:off 2:off 3:on 4:on 5:on 6:off lvm2-monitor 0:off 1:on 2:on 3:on 4:on 5:on 6:off mdmonitor 0:off 1:off 2:on 3:on 4:on 5:on 6:off multipathd 0:off 1:off 2:off 3:off 4:off 5:off 6:off netconsole 0:off 1:off 2:off 3:off 4:off 5:off 6:off netfs 0:off 1:off 2:off 3:on 4:on 5:on 6:off network 0:off 1:off 2:on 3:on 4:on 5:on 6:off nginx 0:off 1:off 2:on 3:on 4:on 5:on 6:off ntpd 0:off 1:off 2:on 3:on 4:on 5:on 6:off ntpdate 0:off 1:off 2:off 3:off 4:off 5:off 6:off postfix 0:off 1:off 2:on 3:on 4:on 5:on 6:off rdisc 0:off 1:off 2:off 3:off 4:off 5:off 6:off restorecond 0:off 1:off 2:off 3:off 4:off 5:off 6:off rsyslog 0:off 1:off 2:on 3:on 4:on 5:on 6:off saslauthd 0:off 1:off 2:off 3:off 4:off 5:off 6:off sshd 0:off 1:off 2:on 3:on 4:on 5:on 6:off udev-post 0:off 1:on 2:on 3:on 4:on 5:on 6:off
4. Nginx的工作模型
4.1 Master-Worker 模式
Nginx 在启动后,会有一个 master 进程和多个相互独立的 worker 进程。
[root@nginx1 ~]# ps aux|grep nginx root 1230 0.0 0.1 47328 1196 ? Ss 12:10 0:00 nginx: master process /opt/nginx/sbin/nginx -c /opt/nginx/conf/nginx.conf nobody 1231 0.0 0.2 47772 2124 ? S 12:10 0:00 nginx: worker process root 1260 0.0 0.0 103256 864 pts/0 S+ 12:42 0:00 grep nginx
Master进程接收来自外界的信号,向各 worker 进程发送信号,每个进程都有可能来处理这个连接。
Master 进程能监控 Worker 进程的运行状态,当 worker 进程退出后(异常情况下), 会自动启动新的 worker 进程
4.2 accept_mutex
由于所有子进程都继承了父进程的 sockfd,那么当连接进来时,所有子进程都将收到通知并“争着”与它建立连接,这就叫“惊群现象”。大量的进程被激活又挂起,只有一个进程可以 accept() 到这个连接,这当然会消耗系统资源。Nginx 提供了一个 accept_mutex加在 accept 上的一把共享锁。即每个 worker 进程在执行 accept 之前都需要先获取锁,获取不到就放弃执行 accept()。有了这把锁之后,同一时刻,就只会有一个进程去accpet(),这样就不会有惊群问题了。
当一个 worker 进程在 accept()这个连接之后,就开始读取请求,解析请求,处理请求, 产生数据后,再返回给客户端,最后才断开连接,完成一个完整的请求。一个请求,完全由worker 进程来处理,而且只能在一个 worker 进程中处理。
4.3 为什么使用进程不使用线程?
多线程涉及到线程的调度,调度涉及到一些锁,使用进程而不使用线程可以节省锁带来的开销。每个 worker 进程都是独立的进程,不共享资源,不需要加锁。同时在编程以及问题查上时,也会方便很多。
独立进程,减少风险。采用独立的进程,可以让互相之间不会影响,一个进程退出后, 其它进程还在工作,服务不会中断,master 进程则很快重新启动新的 worker 进程。当然, worker 进程的也能发生意外退出。
4.4 如何处理并发请求?
每进来一个 request,会有一个 worker 进程去处理。但不是全程的处理,处理到什么程度呢?处理到可能发生阻塞的地方,比如向上游(后端)服务器转发 request,并等待请求返回。那么,这个处理的 worker 不会这么傻等着,他会在发送完请求后,注册一个事件:“如果 upstream 返回了,告诉我一声,我再接着干”。于是他就休息去了。此时,如果再有 request 进来,他就可以很快再按这种方式处理。而一旦上游服务器返回了,就会触发这个事件,worker 才会来接手,这个 request 才会接着往下走。由于 web server的工作性质决定了每个 request 的大部份生命都是在网络传输中,实际上花费在 server机器上的时间片不多,这就是几个进程就能解决高并发的秘密所在,一个worker进程可以处理上万的并发。
5. Nginx参数详解
5.1 nginx.conf 配置文件全览
nginx 由三部分组成,#是注释
[root@nginx1 ~]# vim /opt/nginx/conf/nginx.conf#---全局块开始----
#user nobody;
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 块开始====
events { worker_connections 1024;
}
#====events 块结束====#****http 块开始****
http {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"';......
}
#****http 块结束****
5.1.1 第一部分:全局块
从配置文件开始到 events 之间的内容,主要会设置一些影响 nginx 服务器整体运行的配置参数。主要包括配置运行 Nginx 服务器的用户(组)、允许生成的 worker process 数,进程 PID 存放路径、日志存放路径和类型以及配置文件的引 入等。
#user nobody;
worker_processes 1;#error_log logs/error.log;
#error_log logs/error.log notice;
#error_log logs/error.log info;#pid logs/nginx.pid;
worker_processes 是 Nginx 服务器并发处理服务的关键配置,值越大,可以支持的并发处理量也越多,但是会受到硬件、软件等设备的制约。CPU的核数与可同时运行的进程数相同
error_log 配置 nginx 日志文件的全路径名
pid 配置进程 PID 存放路径
5.1.2 第二部分:events块
events {worker_connections 1024;
}
events 块涉及的参数主要影响 Nginx 服务器与用户的网络连接,常用的设置包括
- 是否开启对多 work process 下的网络连接进行序列化,
- 是否允许同时接受多个网络连接,
- 选取哪种事件驱动模型来处理连接请求,
- 每个 work process 可以同时支持的最大连接数等
上述的例子表示每个 work process 支持的最大连接数为 1024。这部分的配置对 Nginx的性能影响比较大,在实际中应该灵活配置。
5.1.3 第三部分:http块{}
这是 Nginx 服务器配置中最频繁的部分,代理、缓存和日志定义等绝大多数功能和第三方模块的配置都在这里。需要注意的是:http 块也可以包括 http 全局块、server 块。
5.1.3.1 http全局块
http 全局块配置的指令包括文件引入、MIME-TYPE 定义、连接超时时间、单链接请求数上限等。
http {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; # 是否启动压缩server { ......}
}
5.1.3.2 server块
这块和虚拟主机有密切关系,虚拟主机从用户角度看,和一台独立的硬件主机是完全一样的,该技术的产生是为了节省互联网服务器硬件成本。
每个 http 块可以包括多个 server 块,而每个 server 块就相当于一个虚拟主机。而每个server 块也分为全局 server 块以及同时包含多个 location 块
#gzip on;server {listen 80; #监听的端口号server_name localhost; #监听的域名#charset koi8-r; # 字符集编码#access_log logs/host.access.log main; # 日志文件location / {root html;index index.html index.htm;}#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;}# proxy the PHP scripts to Apache listening on 127.0.0.1:80##location ~ \.php$ {# proxy_pass http://127.0.0.1;#}# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000##location ~ \.php$ {# root html;# fastcgi_pass 127.0.0.1:9000;# fastcgi_index index.php;# fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name;# include fastcgi_params;#}# deny access to .htaccess files, if Apache's document root# concurs with nginx's one##location ~ /\.ht {# deny all;#}}# another virtual host using mix of IP-, name-, and port-based configuration##server {# listen 8000;# listen somename:8080;# server_name somename alias another.alias;# location / {# root html;# index index.html index.htm;# }#}# HTTPS server##server {# listen 443 ssl;# server_name localhost;# ssl_certificate cert.pem;# ssl_certificate_key cert.key;# ssl_session_cache shared:SSL:1m;# ssl_session_timeout 5m;# ssl_ciphers HIGH:!aNULL:!MD5;# ssl_prefer_server_ciphers on;# location / {# root html;# index index.html index.htm;# }#}
全局server块
最常见的配置是本虚拟主机的监听配置和本虚拟主机的名称或 IP 配置。
server {listen 80;#监听的端口号 server_name localhost;#监听的域名 #charset koi8-r; # 字符集编码#access_log logs/host.access.log main; # 日志文件
location块
一个 server 块可以配置多个 location 块,与location块进行匹配,匹配到哪里,从哪里出去
这块的主要作用是基于 Nginx 服务器接受到的请求字符串(例如 server_name/uri-string), 对虚拟主机名称(也可以是 IP 别名)之外的字符串(列如 前面的/uri-string)进行匹配,对特定的请求进行处理。地址定向、数据缓存和应答控制等功能,还有许多第三方模块的配置也在这里进行。
5.2 工作模式与连接数上限
#user nobody;
worker_processes 1;
events { use epoll; worker_connections 1024;
}
用户与工作进程
正如下面演示的,nginx启动后,会有一个master进程与worker进程;当杀死worker进程时,会立即启动一个新的worker进程
[root@nginx1 ~]# service nginx status nginx is stopped [root@nginx1 ~]# service nginx start Starting nginx: [ OK ] [root@nginx1 ~]# ps aux|grep nginx root 1355 0.0 0.1 47328 1188 ? Ss 13:59 0:00 nginx: master process /opt/nginx/sbin/nginx -c /opt/nginx/conf/nginx.conf nobody 1356 0.0 0.1 47772 1780 ? S 13:59 0:00 nginx: worker process root 1359 0.0 0.0 103256 864 pts/0 S+ 13:59 0:00 grep nginx [root@nginx1 ~]# kill -9 1356 [root@nginx1 ~]# ps aux|grep nginx root 1355 0.0 0.1 47328 1336 ? Ss 13:59 0:00 nginx: master process /opt/nginx/sbin/nginx -c /opt/nginx/conf/nginx.conf nobody 1360 0.0 0.1 47772 1780 ? S 13:59 0:00 nginx: worker process root 1362 0.0 0.0 103256 860 pts/0 S+ 13:59 0:00 grep nginx[root@nginx1 ~]# id nobody uid=99(nobody) gid=99(nobody) groups=99(nobody) [root@nginx1 ~]# cat /etc/passwd|grep nobody nobody:x:99:99:Nobody:/:/sbin/nologin
use epoll
参考事件模型,use [ kqueue | rtsig | epoll | /dev/poll | select | poll ]; epoll 模型是 Linux 2.6 以上版本内核中的高性能网络 I/O 模型,如果跑在 FreeBSD上面,就用 kqueue 模型。
worker_connections 1024;
单个后台 worker process 进程的最大并发链接数。并发总数是 worker_processes 和 worker_connections 的乘积即:
max_clients=worker_processes∗worker_connectionsmax\_clients = worker\_processes * worker\_connectionsmax_clients=worker_processes∗worker_connections
在 设 置 了 反 向 代 理 的 情 况 下 , max_clients=worker_processes∗worker_connections/4max\_clients=worker\_processes * worker\_connections / 4max_clients=worker_processes∗worker_connections/4
为什么上面反向代理要除以 4,应该说是一个经验值
根据以上条件,正常情况下的 Nginx Server 可以应付的最大连接数为:4 * 8000 = 32000
worker_connections 值的设置跟物理内存大小有关
因为并发受 IO 约束,max_clients 的值须小于系统可以打开的最大文件数
系统可以打开的最大文件数和内存大小成正比,一般 1GB 内存的机器上可以打开的文件数大约是 10 万左右 。我们来看看 360M 内存的 VPS 可以打开的文件句柄数是多少:
$ cat /proc/sys/fs/file-max 34336
32000 < 34336,即并发连接总数小于系统可以打开的文件句柄总数,这样就在操作系统可以承受的范围之内 。worker_connections 的值需根据 worker_processes 进程数目和系统可以打开的最大文件总数进行适当地进行设置使得并发总数小于操作系统可以打开的最大文件数目 。其实质也就是根据主机的物理 CPU 和内存进行配置 。当然,理论上的并发总数可能会和实际有所偏差,因为主机还有其他的工作进程需要消耗系统资源。
5.3 开启零拷贝
 sendfile 实际上是 Linux2.0+以后的推出的一个系统调用,web 服务器可以通过调整自身的配置来决定是否利用 sendfile 这个系统调用。sendfile() 不但能减少切换次数而且还能减少拷贝次数。
先来看一下不用 sendfile 的传统网络传输过程:
硬盘 >> kernel buffer >> user buffer>> kernel socket buffer >>协议栈
一个基于 socket 的服务,首先读硬盘数据,然后写数据到 socket 来完成网络传输的。
read(file,tmp_buf, len);
write(socket,tmp_buf, len);
上面 2 行用代码解释了这一点,不过上面 2 行简单的代码掩盖了底层的很多操作。来看看底层是怎么执行上面 2 行代码的:
- 系统调用 read()产生一个上下文切换:从 user mode 切换到 kernel mode,然后 DMA 执行拷贝,把文件数据从硬盘读到一个 kernel buffer 里。
- 数据从 kernel buffer 拷贝到 user buffer,然后系统调用 read() 返回,这时又产生一个上下文切换:从 kernel mode 切换到 user mode。
- 系统调用 write()产生一个上下文切换:从 user mode 切换到 kernel mode,然后把步骤 2 读到 user buffer 的数据拷贝到 kernel buffer(数据第 2 次拷贝到kernel buffer),不过这次是个不同的 kernel buffer,这个 buffer 和 socket 相关联
- 系统调用 write()返回,产生一个上下文切换:从 kernel mode 切换到 user mode ,然后 DMA 从 kernel buffer 拷贝数据到协议栈。
上面 4 个步骤有 4 次上下文切换,有 4 次拷贝,我们发现如果能减少切换次数和拷贝次数将会有效提升性能。在 kernel2.0+ 版本中,系统调用 sendfile() 就是用来简化上面步骤提升性能的。sendfile() 不但能减少切换次数而且还能减少拷贝次数。
再来看一下用 sendfile()来进行网络传输的过程:
硬盘 >> kernel buffer (快速拷贝到 kernelsocket buffer) >>协议栈
sendfile(socket,file, len);
系统调用 sendfile()通过 DMA 把硬盘数据拷贝到 kernel buffer,然后数据被 kernel 直接拷贝到另外一个与 socket 相关的 kernel buffer。这里没有 user mode 和 kernel mode 之间的切换,在 kernel 中直接完成了从一个 buffer 到另一个 buffer 的拷贝。
DMA 把数据从 kernel buffer 直接拷贝给协议栈,没有切换,也不需要数据从 user mode 拷贝到 kernel mode,因为数据就在 kernel 里
简单说,sendfile 是个比 read 和 write 更高性能的系统接口, 不过需要注意的是, sendfile 是将 in_fd 的内容发送到 out_fd 。而 in_fd 不能是 socket , 也就是 只能文件句柄。 所以当 Nginx 是一个静态文件服务器的时候,开启 SENDFILE 配置项能大大提高 Nginx 的性能。 但是当 Nginx 是作为一个反向代理来使用的时候,SENDFILE 则没什么用了,因为 Nginx 是反向代理的时候。 in_fd 就不是文件句柄而是 socket,此时就不符合 sendfile 函数的参数要求了。
5.4 keepalive_timeout
keepalive_timeout 65
测试时改为 0,便于看出负载切换的效果,部署到生产前进行优化(生产时默认65)来提高效率。
5.5 是否启用压缩
#gzip on;
压缩可以有效减少文件的大小,有利于网络传输。
5.6 autoindex
autoindex on;
: 开启目录列表访问,适合下载服务器,默认关闭。在浏览器上访问nginx就可以看到对应目录下有哪些文件,点击可以下载。
5.7 nginx虚拟主机演示
虚拟主机,就是将一台物理服务器虚拟为多个服务器来使用,从而实现在一台服务器上配置多个站点,即可以在一台物理主机上配置多个域名。Nginx 中,一个 server 标签就是一台虚拟主机,配置多个 server 标签就虚拟出了多台主机。
Nginx 虚拟主机的实现方式有两种:
域名虚拟方式
域名虚拟方式是指不同的虚拟机使用不同的域名,通过不同的域名虚拟出不同的主机;
端口虚拟方式
端口虚拟方式是指不同的虚拟机使用相同的域名不同的端口号,通过不同的端口号虚拟出不同的主机。基于端口的虚拟方式不常用。
修改 nginx.conf 文件
[root@nginx1 ~]# vim /opt/nginx/conf/nginx.conf#user nobody; 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; }http {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;server {listen 80;server_name www.sxthenhao.com;location / {root /mnt;autoindex on;}}server {listen 80;server_name www.123.com;location / {root html;index index.html index.htm;}} }
重新加载 nginx:
[root@nginx1 ~]# service nginx reload nginx: the configuration file /opt/nginx/conf/nginx.conf syntax is ok nginx: configuration file /opt/nginx/conf/nginx.conf test is successful Reloading nginx:
修改本机 hosts 文件(C:\Windows\System32\drivers\etc)
192.168.236.105 nginx1 www.123.com www.sxt.com
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gnMwRZQj-1639662151711)(01 Nginx的高并发处理/image-20211215170845288.png)]
访问测试(谷歌浏览器打不开,微软浏览器可以打开,未找到原因)
对比下图,
这样就实现了一台物理主机,使用两个域名可以进行访问。
5.8 日志配置
Nginx 还可以作为日志服务器
[root@nginx1 ~]# cd /opt/nginx/logs/
[root@nginx1 logs]# ls
access.log
[root@nginx1 logs]# tail -f access.log # tail-f表示监视这个文件
192.168.236.1 - - [15/Dec/2021:17:21:08 +0800] "GET / HTTP/1.1" 200 396 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.93 Safari/537.36 Edg/96.0.1054.53"
192.168.236.1 - - [15/Dec/2021:17:21:08 +0800] "GET /favicon.ico HTTP/1.1" 404 187 "http://www.123.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.93 Safari/537.36 Edg/96.0.1054.53"
192.168.236.1 - - [15/Dec/2021:17:22:32 +0800] "GET / HTTP/1.1" 200 163 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.93 Safari/537.36 Edg/96.0.1054.53"
192.168.236.1 - - [15/Dec/2021:17:22:32 +0800] "GET /favicon.ico HTTP/1.1" 404 187 "http://www.sxt.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.93 Safari/537.36 Edg/96.0.1054.53"
192.168.236.1 - - [15/Dec/2021:17:22:37 +0800] "GET /cdrom/ HTTP/1.1" 200 475 "http://www.sxt.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.93 Safari/537.36 Edg/96.0.1054.53"
192.168.236.1 - - [15/Dec/2021:17:22:38 +0800] "GET / HTTP/1.1" 200 163 "http://www.sxt.com/cdrom/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.93 Safari/537.36 Edg/96.0.1054.53"
192.168.236.1 - - [15/Dec/2021:17:26:05 +0800] "GET /favicon.ico HTTP/1.1" 404 187 "http://www.123.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.93 Safari/537.36 Edg/96.0.1054.53"
192.168.236.1 - - [15/Dec/2021:17:26:16 +0800] "GET / HTTP/1.1" 200 163 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.93 Safari/537.36 Edg/96.0.1054.53"
192.168.236.1 - - [15/Dec/2021:17:26:16 +0800] "GET /favicon.ico HTTP/1.1" 404 187 "http://www.sxthenhao.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.93 Safari/537.36 Edg/96.0.1054.53"
192.168.236.1 - - [15/Dec/2021:17:26:56 +0800] "GET /cdrom/ HTTP/1.1" 200 475 "http://www.sxthenhao.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.93 Safari/537.36 Edg/96.0.1054.53"
本地浏览器访问:http://www.123.com/2019-12-03maxwd19,先不管 404 的问题,查看日志多了一天记录
修改一下 http://www.123.com/2019-12-04maxwd20,日志又记录一条
当然日志格式我们也可以自定义 :
日志的默认配置是:
[root@nginx1 ~]# vim /opt/nginx/conf/nginx.conf
#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;
修改为:
log_format myfmt '$remote_addr,$remote_user,$time_local,$request';
然后在主机名下,设置所使用的日志格式,做如下配置:
server {listen 80;server_name www.sxthenhao.com;access_log logs/myfmt.log myfmt;location / {root /mnt;autoindex on;}}
然后,将nginx进行重启
[root@nginx1 ~]# service nginx restart
nginx: the configuration file /opt/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /opt/nginx/conf/nginx.conf test is successful
Stopping nginx: [ OK ]
Starting nginx: [ OK ]
此时,如果访问https://www.123.com,日志格式还是默认配置,监视access.log还会增加一条;如果访问https://www.sxthenhao.com,日志格式使用自定义的格式,在文件logs/myfmt.log增加一条
5.9 Location
参考:http://tengine.taobao.org/nginx_docs/cn/docs/http/ngx_http_core_module.html#location
语法: location [ = | ~ | ~* | ^~ ] uri { ... }location @name { ... }
默认值:一
上下文:server, location
可以使用前缀字符串或者正则表达式定义路径。使用正则表达式需要在路径开始添加“~*
”前缀 (不区分大小写),或者“~
”前缀(区分大小写)。为了根据请求URI查找路径,nginx先检查前缀字符串定义的路径 (前缀路径),在这些路径中找到能最精确匹配请求URI的路径。然后nginx按在配置文件中的出现顺序检查正则表达式路径, 匹配上某个路径后即停止匹配并使用该路径的配置,否则使用最大前缀匹配的路径的配置。
正则表达式中可以包含匹配组(0.7.40),结果可以被后面的其他指令使用。
如果最大前缀匹配的路径以“^~
”开始,那么nginx不再检查正则表达式。
而且,使用“=
”前缀可以定义URI和路径的精确匹配。如果发现匹配,则终止路径查找。 比如,如果请求“/
”出现频繁,定义“location = /
”可以提高这些请求的处理速度, 因为查找过程在第一次比较以后即结束。这样的路径明显不可能包含嵌套路径。
让我们用一个例子解释上面的说法:
location = / {[ configuration A ]
}location / {[ configuration B ]
}location /documents/ {[ configuration C ]
}location ^~ /images/ {[ configuration D ]
}location ~* \.(gif|jpg|jpeg)$ { [ configuration E ]
}
请求“/”匹配配置 A,
请求“/index.html”匹配配置 B,
请求“/documents/document.html”匹配配置 C,
请求“/images/1.gif”匹配配置 D,
请求“/documents/1.jpg”匹配配置 E。
总结:
location映射(ngx_http_core_module)
location [=/~l~*|^~] uri { ...}
- location URI{}:最大前缀匹配,对当前路径及子路径下的所有对象都生效;
- location = URI{}:精确匹配指定的路径,不包括子路径,因此,只对当前资源生效;注意URL最好为具体路径。
- location ~ URI{}:
- location *URI{}:模式匹配URl,此处的URl可使用正则表达式,区分字符大小写,~*不区分字符大小写;
- location ^~URI{}:不使用正则表达式
- 优先级:=>^~ >|* >/dir/
location配置规则
- location 的执行逻辑跟 location的编辑顺序无关。
矫正:这句话不全对,“普通location”的匹配规则是“最大前缀”,因此“普通location的确与location编辑顺序无关;但是“正则 location ”的匹配规则是“顺序匹配,且只要匹配到第一个就停止后面的匹配"; - "普通location ”与“正则 location”之间的匹配顺序是?先匹配普通location,再“考志”匹配正则 location .
- 注意这里的“考虑”是“可能”的意思,也就是说匹配完“普通location”后,有的时候需要继续匹配“正则 location",有的时候则不需要继续匹配“正则 location ”。两种情况下,不需要继续匹配正则 location :
- 当普通 location前面指定了“^~”,特别告诉 Nginx本条著通 location一旦匹配上,则不需要继续正则匹配:
- 当普通location恰好严格匹配上,不是最大前缀匹配则不再延续匹配正则
- location 的执行逻辑跟 location的编辑顺序无关。
nginx收到请求头:判定ip, port,hosts决定server
请求头:
- host:决策server负责处理-
- uri:决策location
- 反向代理:proxy_pass ip:port[uri];
nginx location匹配:用客户端的uri匹配location的uri
先普通
顺序无关
最大前缀
匹配规则简单
打断:
- ^~
- 完全匹配
再正则
不完全匹配
正则特殊性:一条URI可以和多条location匹配上
有顺序的
先匹配,先应用,即时退出匹配
修改 nginx.conf 配置文件
[root@nginx1 ~]# vim /opt/nginx/conf/nginx.confserver {listen 80;server_name www.sxthenhao.com;access_log logs/myfmt.log myfmt;location / {root /mnt;autoindex on;}location /aabb {proxy_pass http://192.168.236.102/; #带上/访问该 url 对应的首页,}}
重新加载nginx
[root@nginx1 ~]# service nginx restart nginx: the configuration file /opt/nginx/conf/nginx.conf syntax is ok nginx: configuration file /opt/nginx/conf/nginx.conf test is successful Stopping nginx: [ OK ] Starting nginx:
访问测试
先在虚拟机主机node2中配置
[root@node2 ~]# ls /var cache db empty games lib local lock log mail nis opt preserve run spool tmp www yp [root@node2 ~]# cd /var/www [root@node2 www]# ls cgi-bin error html icons [root@node2 www]# cd html/ [root@node2 html]# ls [root@node2 html]# vim index.htmlfrom 192.168.236.102[root@node2 html]# service httpd start Starting httpd: httpd: Could not reliably determine the server's fully qualified domain name, using 192.168.236.102 for ServerName[ OK ]
此时,访问www.sxthenhao.com/aabb也可以跳转到http://192.168.236.102/。
修改 nginx.conf
[root@nginx1 ~]# vim /opt/nginx/conf/nginx.confserver {listen 80;server_name www.sxthenhao.com;access_log logs/myfmt.log myfmt;location / {root /mnt;autoindex on;}location /aabb {proxy_pass http://192.168.236.102/;}location /baidu {proxy_pass https://www.baidu.com/; #尽量在服务器端跳转,不要在客户端跳转,这里是https}}[root@nginx1 ~]# service nginx restart nginx: the configuration file /opt/nginx/conf/nginx.conf syntax is ok nginx: configuration file /opt/nginx/conf/nginx.conf test is successful Stopping nginx: [ OK ] Starting nginx:
此时,浏览器中访问[www.sxthenhao.com/aabb](http://www.sxthenhao.com/baidu,即可以跳到百度首页!
但是当我们查询(比如:ssd)时出现
所以,修改nginx.conf
[root@nginx1 ~]# vim /opt/nginx/conf/nginx.confserver {listen 80;server_name www.sxthenhao.com;access_log logs/myfmt.log myfmt;location / {root /mnt;autoindex on;}location /aabb {proxy_pass http://192.168.236.102/;}location /baidu {proxy_pass https://www.baidu.com/;}location ~* /s.* {proxy_pass https://www.baidu.com; }}[root@nginx1 ~]# service nginx restart nginx: the configuration file /opt/nginx/conf/nginx.conf syntax is ok nginx: configuration file /opt/nginx/conf/nginx.conf test is successful Stopping nginx: [ OK ] Starting nginx: [ OK ]
5.10 Bug https protocol requires SSL support in
[root@nginx1 conf]# service nginx reload
nginx: [emerg] https protocol requires SSL support in /opt/nginx/conf/nginx.conf:45
nginx: configuration file /opt/nginx/conf/nginx.conf test failed
当初编译的时候没有启用 SSL 支持,在配置反向代理到 https 的网站时,编辑配置文件报错,无法启动 nginx。
解决办法:先将 nginx.conf 备份/root/目录下,删除/opt/nginx 和/opt/apps/nginx-1.16.1,然后在解压一份,最后编译安装。
[root@nginx1 nginx-1.16.1]# ./configure --prefix=/opt/nginx --with-http_ssl_module
[root@nginx1 nginx-1.16.1]# make && make install
[root@nginx1 nginx-1.16.1]# cd /opt/nginx/conf/
[root@nginx1 conf]# cp /root/nginx.conf ./
cp: overwrite `./nginx.conf'? yes
[root@nginx1 conf]# service
nginx reload nginx: the configuration file /opt/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /opt/nginx/conf/nginx.conf test is successful Reloading nginx:
然后再访问 http://www.sxthenhao.com/sxt,即可正常访问!
6. 反向代理
代理服务器根据其代理对象的不同,可以分为正向代理服务器与反向代理服务器。这里 的“正”与“反”均是站在客户端角度来说的。
6.1 正向代理服务器
正向代理是对客户端的代理。客户端 C 想要从服务端 S 获取资源,但由于某些原因 ,不能直接访问服务端,而是通过另外一台主机 P 向服务端发送请求。当服务端处理完毕请求后,将响应发送给主机 P,主机 P 在接收到来自服务端的响应后,将响应又转给了客户端 C。此时的主机 P,就称为客户端 C 的正向代理服务器。
客户端在使用正向代理服务器时是知道其要访问的目标服务器的地址等信息的。正向代理服务器是为服务用户(客户端)而架设的主机,与服务端无关,对服务器端透明。
正向代理架构图:
代理服务器
代理服务器-缓存
6.2 反向代理服务器
反向代理(Reverse Proxy)方式是指以代理服务器来接受 internet 上的连接请求,然后将请求转发给内部网络上的服务器,并将从服务器上得到的结果返回给 internet上请求连接的客户端,此时代理服务器对外就表现为一个反向代理服务器。
6.3 反向代理之负载均衡
负载均衡(Load Balancing):就是将对请求的处理分摊到多个操作单元上进行。这个均衡是指在大批量访问前提下的一种基本均衡,并非是绝对的平均。对于 Web 工程中的负载均衡,就是将相同的 Web 应用部署到多个不同的 Web 服务器上,形成多个 Web 应用服务器。当请求到来时,由负载均衡服务器负责将请求按照事先设定好的比例向 Web 应用服务器进行分发,从而增加系统的整体吞吐量。
负载均衡可以通过负载均衡软件实现,也可通过硬件负载均衡器实现
硬件负载均衡
硬件负载均衡器的性能稳定,且有生产厂商作为专业的服务团队。但其成本很高,一台硬件负载均衡器的价格一般都在十几万到几十万,甚至上百万。知名的负载均衡器有 F5、Array、 深信服、梭子鱼等
软件负载均衡
软件负载均衡成本几乎为零,基本都是开源软件。例如:LVS、HAProxy、Nginx 等。
实例:该机群包含一台 nginx1 服务器,两台 Web 服务器(node2 和 node3)。
一种方式是:
在nginx1中,修改nginx.conf文件
[root@nginx1 ~]# cd /opt/nginx/conf/ [root@nginx1 conf]# vim nginx.confgzip on;upstream rss {server 192.168.236.102;server 192.168.236.103;}server {listen 80;server_name www.sxthenhao.com;access_log logs/myfmt.log myfmt;location / {root /mnt;autoindex on;}location /toms {proxy_pass http://rss/;}location /aabb {proxy_pass http://192.168.236.102/;}location /baidu {proxy_pass https://www.baidu.com/;}location ~* /s.* {proxy_pass https://www.baidu.com;}}
重启 nginx
[root@nginx1 conf]# service nginx restart nginx: the configuration file /opt/nginx/conf/nginx.conf syntax is ok nginx: configuration file /opt/nginx/conf/nginx.conf test is successful Stopping nginx: [ OK ] Starting nginx:
在node2与node3服务器上,同时启动httpd服务
[root@node2 ~]# service httpd start Starting httpd: httpd: Could not reliably determine the server's fully qualified domain name, using 192.168.236.102 for ServerName[ OK ] [root@node3 html]# service httpd start Starting httpd: httpd: Could not reliably determine the server's fully qualified domain name, using 192.168.236.103 for ServerName[ OK ]
请求测试:http://www.sxthenhao.com/toms,发现已经实现了负载均衡。(中小企业一般使用该方式)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rvtZ9lMX-1639662151718)(01 Nginx的高并发处理/image-20211216133134346.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1Kc01eja-1639662151718)(01 Nginx的高并发处理/image-20211216133156204.png)]
另一种方式是:
通过在 Nginx 服务器上配置 hosts 本地域名解析:
[root@nginx1 conf]# vim /etc/hosts 192.168.20.101 node1 192.168.20.102 node2 xxx 192.168.20.103 node3 xxx 192.168.20.104 node4
修改 nginx.conf 配置文件,添加如下配置
location /cats { proxy_pass http://xxx/; }
重启 nginx,测试:http://www.sxthenhao.com/cats
一样能够实现负载均衡的目的(大型企业使用该方式,一般还会搭建一个 DNS 域名解析服
务器,只需要修改 DNS 域名解析服务器就 ok 了)
7. Nginx调优
7.1 worker_processes 的设置
打开 nginx.conf 配置文件,可以看到 worker_processes 的默认值为 1。
[root@nginx1 conf]# vim nginx.conf#user nobody;
worker_processes auto;
worker_processes,工作进程,用于指定 Nginx 的工作进程数量。该值应该设置为多少合适呢?其数值一般设置为 CPU 内核数量,或内核数量的整数倍。注意,现代的CPU 一般都是多核的,即一块 CPU 中包含多个内核。若当前系统具有 2 块 CPU,而每块CPU 中包含 2 个内核,那么,worker_processes 的值一般可以设置为 4 或 8。当然,也可以设置为 2。 不过需要注意,该值不仅仅取决于 CPU 内核数量,还与硬盘数量及负载均衡模式相关。 在不确定时可以指定其值为auto。
7.2 worker_cpu_affinity的设置
为了进一步提高系统性能,我们会将 worker 进程与具体的内核进行绑定。该绑定操作是通过 worker_cpu_affinity 属性进行设置的。不过,若指定worker_processes 的值为 auto,则无法设置 worker_cpu_affinity。
该设置是通过二进制进行的。每个内核使用一个二进制位表示,0 代表内核关闭,1 代表内核开启。也就是说,有几个内核,就需要使用几个二进制位。下面通过几个例子来增进对worker_processes 与 worker_cpu_affinity 的理解。
8. session共享
http 协议是无状态的,即你连续访问某个网页 100 次和访问 1 次对服务器来说是没有区别对待的,因为它记不住你。那么,在一些场合,确实需要服务器记住当前用户怎么办?比如用户登录邮箱后,接下来要收邮件、写邮件,总不能每次操作都让用户输入用户名和密码吧,为了解决这个问题,session 的方案就被提了出来,事实上它并不是什么新技术, 而且也不能脱离 http 协议以及任何现有的 web 技术 。
session 的常见实现形式是会话 cookie(session cookie),即未设置过期时间的 cookie,这个 cookie 的默认生命周期为浏览器会话期间,只要关闭浏览器窗口,cookie 就消失了。实现机制是当用户发起一个请求的时候,服务器会检查该请求中是否包含 sessionid,如果未包含,则系统会创造一个名为 JSESSIONID 的输出 cookie 返回给浏览器(只放入内存,并不存在硬盘中),并将其以 HashTable 的形式写到服务器的内存里面;**当已经包含 sessionid时,服务端会检查找到与该 session 相匹配的信息,如果存在则直接使用该 sessionid,若不存在则重新生成新的 session。**这里需要注意的是 session 始终是由服务端创建的,并非浏览器自己生成的。 但是浏览器的 cookie 被禁止后 session 就需要用 get 方法的 URL 重写的机制或使用 POST 方法提交隐藏表单的形式来实现 。
首先我们应该明白,为什么要实现共享,如果你的网站是存放在一个机器上,那么是不存在这个问题的,因为会话数据就在这台机器,但是如果你使用了负载均衡把请求分发到不同的机器呢?这个时候会话 id 在客户端是没有问题的,但是如果用户的两次请求到了两台不同的机器,而它的 session 数据可能存在其中一台机器,这个时候就会出现取不到 session 数据的情况,于是 session 的共享就成了一个问题。
8.1 session一致性解决方案
共享session,专门管理session的软件:memcached缓存服务,可以和tomat整合,帮助tomat共享管理session。
8.2 安装memcached
8.2.1 node2 和 node3上安装jdk 和 tomcat
- 在node2上安装 jdk并分发到node3上
- 在node2上的/etc/profile中增加java环境变量,让变量生效
- 解压tomcat,修改 ROOT/index.jsp,并分别启动tomcat
- node3与node2同理
[root@node2 apps]# ls
apache-tomcat-7.0.69.tar.gz jdk-7u80-linux-x64.rpm nginx-1.8.1.tar.gz[root@node2 ~]# cd /opt/apps/[root@node2 apps]# rpm -ivh jdk-7u80-linux-x64.rpm[root@node2 jdk1.7.0_80]# vim /etc/profile export JAVA_HOME=/usr/java/jdk1.7.0_80
export PATH=$PATH:$JAVA_HOME/bin
[root@node2 apps]# source /etc/profile
[root@node2 apps]# jps[root@node2 apps]# tar -zxvf apache-tomcat-7.0.69.tar.gz -C /opt/[root@node2 opt]# mv apache-tomcat-7.0.69/ tomcat-7.0.69/
[root@node2 opt]# ls
apps tomcat-7.0.69
[root@node2 opt]# cd tomcat-7.0.69/
[root@node2 tomcat-7.0.69]# ls
bin conf lib LICENSE logs NOTICE RELEASE-NOTES RUNNING.txt temp webapps work
[root@node2 tomcat-7.0.69]# cd webapps/ROOT/# 修改 ROOT/index.jsp,dG 全删后,添加:
[root@node2 ROOT]# vim index.jsp from node2 session=<%=session.getId()%>[root@node2 ROOT]# cd /opt/tomcat-7.0.69/bin/
[root@node2 bin]# ls
bootstrap.jar commons-daemon-native.tar.gz digest.sh startup.bat tool-wrapper.sh
catalina.bat configtest.bat setclasspath.bat startup.sh version.bat
catalina.sh configtest.sh setclasspath.sh tomcat-juli.jar version.sh
catalina-tasks.xml daemon.sh shutdown.bat tomcat-native.tar.gz
commons-daemon.jar digest.bat shutdown.sh tool-wrapper.bat
[root@node2 bin]# ./startup.sh
Using CATALINA_BASE: /opt/tomcat-7.0.69
Using CATALINA_HOME: /opt/tomcat-7.0.69
Using CATALINA_TMPDIR: /opt/tomcat-7.0.69/temp
Using JRE_HOME: /usr/java/jdk1.7.0_80
Using CLASSPATH: /opt/tomcat-7.0.69/bin/bootstrap.jar:/opt/tomcat-7.0.69/bin/tomcat-juli.jar
Tomcat started.
修改 nginx.conf
[root@nginx1 conf]# vim nginx.confupstream rss { server 192.168.236.102:8080; server 192.168.236.103:8080; } [root@nginx1 conf]# service nginx restart
nginx: the configuration file /opt/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /opt/nginx/conf/nginx.conf test is successful
Stopping nginx: [ OK ]
Starting nginx: [ OK ]
访问测试 http://www.sxthenhao.com/toms,刷新 session 一直改变。
8.2.2 nginx1上安装memcached
[root@nginx1 conf]# yum install libevent -y[root@nginx1 conf]# yum install memcached -y[root@nginx1 conf]# memcached -d -m 128m -p 11211 -l 192.168.236.105 -u root -P /tmp/
-d
:后台启动服务-m
:缓存大小-p
:端口-l
:IP-P
:服务器启动后的系统进程 ID,存储的文件-u
:服务器启动是以哪个用户名作为管理用户
[root@nginx1 conf]# ps aux|grep memcached
root 1390 0.0 0.0 330844 888 ? Ssl 15:24 0:00 memcached -d -m 128m -p 11211 -l 192.168.236.105 -u root -P /tmp/
root 1397 0.0 0.0 103256 868 pts/0 S+ 15:26 0:00 grep memcached
8.2.3 配置session 共享(node2 和 node3)
拷贝 jar 到 tomcat 的 lib 下,jar 包见附件
配置 tomcat,每个 tomcat 里面的 context.xml 中加入
[root@node3 bin]# cd /opt/ [root@node3 opt]# ls apps tomcat-7.0.69 [root@node3 opt]# cd tomcat-7.0.69/ [root@node3 tomcat-7.0.69]# ls bin conf lib LICENSE logs NOTICE RELEASE-NOTES RUNNING.txt temp webapps work [root@node3 tomcat-7.0.69]# cd conf/ [root@node3 conf]# ls Catalina catalina.properties logging.properties tomcat-users.xml catalina.policy context.xml server.xml web.xml [root@node3 conf]# vim context.xml <Manager className="de.javakaffee.web.msm.MemcachedBackupSessionManager" memcachedNodes="n1:192.168.236.105:11211" sticky="false" lockingMode="auto" sessionBackupAsync="false" requestUriIgnorePattern=".*\.(ico|png|gif|jpg|css|js)$" sessionBackupTimeout="1000" transcoderFactoryClass="de.javakaffee.web.msm.serializer.kryo.KryoTranscoderFactory"/>
tomcat 添加 jar 包和配置信息之后需要重启
[root@node3 conf]# cd ../bin/ [root@node3 bin]# ls bootstrap.jar commons-daemon-native.tar.gz digest.sh startup.bat tool-wrapper.sh catalina.bat configtest.bat setclasspath.bat startup.sh version.bat catalina.sh configtest.sh setclasspath.sh tomcat-juli.jar version.sh catalina-tasks.xml daemon.sh shutdown.bat tomcat-native.tar.gz commons-daemon.jar digest.bat shutdown.sh tool-wrapper.bat [root@node3 bin]# ./shutdown.sh Using CATALINA_BASE: /opt/tomcat-7.0.69 Using CATALINA_HOME: /opt/tomcat-7.0.69 Using CATALINA_TMPDIR: /opt/tomcat-7.0.69/temp Using JRE_HOME: /usr/java/jdk1.7.0_80 Using CLASSPATH: /opt/tomcat-7.0.69/bin/bootstrap.jar:/opt/tomcat-7.0.69/bin/tomcat-juli.jar [root@node3 bin]# ./startup.sh Using CATALINA_BASE: /opt/tomcat-7.0.69 Using CATALINA_HOME: /opt/tomcat-7.0.69 Using CATALINA_TMPDIR: /opt/tomcat-7.0.69/temp Using JRE_HOME: /usr/java/jdk1.7.0_80 Using CLASSPATH: /opt/tomcat-7.0.69/bin/bootstrap.jar:/opt/tomcat-7.0.69/bin/tomcat-juli.jar Tomcat started.
[root@node2 opt]# cd tomcat-7.0.69/bin/ [root@node2 bin]# ls bootstrap.jar commons-daemon-native.tar.gz digest.sh shutdown.sh tool-wrapper.bat catalina.bat configtest.bat index.jsp startup.bat tool-wrapper.sh catalina.sh configtest.sh setclasspath.bat startup.sh version.bat catalina-tasks.xml daemon.sh setclasspath.sh tomcat-juli.jar version.sh commons-daemon.jar digest.bat shutdown.bat tomcat-native.tar.gz [root@node2 bin]# ./ shutdown.sh -bash: ./: is a directory [root@node2 bin]# ./shutdown.sh Using CATALINA_BASE: /opt/tomcat-7.0.69 Using CATALINA_HOME: /opt/tomcat-7.0.69 Using CATALINA_TMPDIR: /opt/tomcat-7.0.69/temp Using JRE_HOME: /usr/java/jdk1.7.0_80 Using CLASSPATH: /opt/tomcat-7.0.69/bin/bootstrap.jar:/opt/tomcat-7.0.69/bin/tomcat-juli.jar [root@node2 bin]# ./startup.sh Using CATALINA_BASE: /opt/tomcat-7.0.69 Using CATALINA_HOME: /opt/tomcat-7.0.69 Using CATALINA_TMPDIR: /opt/tomcat-7.0.69/temp Using JRE_HOME: /usr/java/jdk1.7.0_80 Using CLASSPATH: /opt/tomcat-7.0.69/bin/bootstrap.jar:/opt/tomcat-7.0.69/bin/tomcat-juli.jar Tomcat started.
最后实现的效果是共享session,
9. 反向代理之动静分离
9.1 动静分离需求分析
Nginx 动静分离简单来说就是把动态和静态请求分开,不能理解成知识单纯的把动态页面和静态页面物理分离。严格意义上说应该是动态请求和静态请求分开,可以理解成使用 Nginx 处理静态请求,Tomcat 处理动态请求。 将动态的资源交给tomcat来做响应,将静态资源单独作成静态资源服务器,由nginx来提供响应,这样可以减轻tomcat的负载,静态资源也方便统一的管理与存储。当网站规模比较小时,动态资源与静态资源整到一起由tomcat来处理也是可以的。当并发比较多时,如果仍然由tomcat处理,对于tomcat的系统消耗非常大。主流趋势是将动态资源与静态资源做一个分离。(建议阅读:《淘宝技术这十年》)
动静分离从目前实现方式大致分为两种:
一是纯粹的把静态文件独立成单独的域名,放在独立的服务器上,也是目前主流推崇的方案。
二是动态和静态文件混合在一起发布,通过 nginx 分开。通过 location 指定不同的后缀名实现不同的请求转发。
9.3 动静分离具体实现
修改node2、node3上的index.jsp
node2:
[root@node2 bin]# cd /opt/tomcat-7.0.69/webapps/ROOT/ [root@node2 ROOT]# vim index.jsp <link rel="stylesheet" type="text/css" href="/css/index.css"> #链接使用css样式 <img src="/image/logo.jpg" ><br/> # 通过img到这个标签 <font class="myfont"> # 字体 from 192.168.236.102 <br/> session=<%=session.getId()%></font>
node3:
[root@node3 bin]# cd /opt/tomcat-7.0.69/webapps/ROOT/ [root@node3 ROOT]# vim index.jsp <link rel="stylesheet" type="text/css" href="/css/index.css"> <img src="/image/logo.jpg" ><br/> <font class="myfont"> from 192.168.236.103 <br/> session=<%=session.getId()%></font>
从 nginx1 克 隆 nginx2, nginx2中修改主机名与IP地址
vim /etc/sysconfig/network
vim /etc/sysconfig/network-scripts/ifcfg-eth0
修 改 /etc/udev/ rules.d/70-persistent-net.rules
[root@nginx2 rules.d]# pwd /etc/udev/rules.d [root@nginx2 rules.d]# vim 70-persistent-net.rules
将原来的 eth0 一行删掉(dd),并将 eth0,改为 eth1
如果nginx1中memcached未开启,则需要先开启;如果开启,则忽略这一步.
[root@nginx1 ~]# memcached -d -m 128m -p 11211 -l 192.168.236.105 -u root -P /tmp/ [root@nginx1 ~]# ps aux|grep memcached root 1201 0.0 0.0 330844 884 ? Ssl 21:09 0:00 memcached -d -m 128m -p 11211 -l 192.168.236.105 -u root -P /tmp/ root 1208 0.0 0.0 103256 868 pts/0 S+ 21:10 0:00 grep memcached
同时,node2与node3中的tomcat保持开启
此时,
在 nginx2 服务器上创建目录 /data/image 和/data/css,然后将 logo.jpg 和 index.css 上传到对应的目录
[root@nginx2 ~]# mkdir -p /data/image /data/css或者[root@nginx2 ~]# mkdir -p /data/{image,css}
将 logo.jpg 和 index.css 上传到对应的目录
修改 nginx2 服务器上的 nginx.conf 配置文件
[root@nginx2 ~]# vim /opt/nginx/conf/nginx.conf keepalive_timeout 0;#keepalive_timeout 65;gzip on;server {listen 80;server_name 192.168.236.106;location / {root /mnt;autoindex on; }location /image {root /data;}location /css {root /data;}} }[root@nginx2 data]# service nginx restart nginx: the configuration file /opt/nginx/conf/nginx.conf syntax is ok nginx: configuration file /opt/nginx/conf/nginx.conf test is successful Stopping nginx: [ OK ] Starting nginx: [ OK ]
修改 nginx1 服务器上的 nginx.conf 配置文件
[root@nginx1 ~]# vim /opt/nginx/conf/nginx.conf ... keepalive_timeout 0;#keepalive_timeout 65;gzip on;upstream rss {server 192.168.236.102:8080;server 192.168.236.103:8080;}server {listen 80;server_name www.sxthenhao.com;access_log logs/myfmt.log myfmt;location / {root /mnt;autoindex on;}location /image {proxy_pass http://192.168.236.106;}location /css {proxy_pass http://192.168.236.106;}location /toms {proxy_pass http://rss/;}location /aabb {proxy_pass http://192.168.236.102/;}location /baidu {proxy_pass https://www.baidu.com/;...
然后重新加载 nginx
[root@nginx1 ~]# service nginx restart nginx: the configuration file /opt/nginx/conf/nginx.conf syntax is ok nginx: configuration file /opt/nginx/conf/nginx.conf test is successful Stopping nginx: [ OK ] Starting nginx: [ OK ]
浏览器测试 http://www.sxthenhao.com
01 Nginx的高并发处理相关推荐
- NGINX的高并发处理
NGINX的worker抢占机制 在master里面,先建立需要lfd,然后fork出多个worker进程,当用户进入nginx服务的时候,每个worker的lfd变的可读,并且这些worker会抢占 ...
- 高并发处理之商品详情页
首页 博客 专栏·视频 下载 论坛 问答 代码 直播 能力认证 高校 会员中心 收藏 动态 消息 创作中心 高并发处理之商品详情页 卜大伟 2019-01-18 11:13:47 2488 收藏 ...
- Java架构师成长直通车:LVS+Nginx实现高可用集群
LVS+Nginx实现高可用集群 常见服务器 安装 Nginx(CentOS) Nginx 的进程模型 Nginx 事件处理 nginx.conf 核心配置文件 Nginx 的跨域配置和防盗链 负载均 ...
- LVS+Nginx实现高可用集群
LVS+Nginx实现高可用集群 常见服务器 [安装 Nginx(CentOS)](#安装 Nginx(CentOS)) [Nginx 的进程模型](#Nginx 的进程模型) [Nginx 事件处理 ...
- redis高并发处理由浅入深(备java基础,javaee课程)-任亮-专题视频课程
redis高并发处理由浅入深(备java基础,javaee课程)-10331人已学习 课程介绍 Redis是一款依据BSD开源协议发行的高性能Key-Value存储系统(cache a ...
- 分布式架构 高并发处理
分布式架构 高并发处理 高并发介绍 在同时或者极短时间内,有大量请求到达服务端,每个请求都需要服务端耗费资源进行处理,并做出相应反馈 服务端比如同时开启进程数,能同时运行的线程数.网络连接数.CPU运 ...
- .NET6 高并发处理
.net6 高并发处理方案 .Net Core技术栈高并发秒杀的处理方案 高并发秒杀电商系统分析与设计原则 [视频]高并发处理思路分表分库.消息列队.缓存.Nginx 其它 .NET6 学习之旅
- Nginx--大型网站高并发处理
Nginx–>大型网站高并发处理 文章目录 **Nginx**-->**大型网站高并发处理** 一,产生背景 二,负载均衡(Load Balance) 2.1 高并发 2.2 负载均衡 2 ...
- nginx+keepalived高可用web架构
nginx+keepalived高可用web架构 1.下载所需的软件包 (1).keepalived软件包keepalived-1.1.20.tar.gz (2).nginx软件包nginx-1.1. ...
- 分布式架构高可用架构篇_04_Keepalived+Nginx实现高可用Web负载均衡
一.场景需求 二.Keepalived 简要介绍 Keepalived 是一种高性能的服务器高可用或热备解决方案,Keepalived 可以用来防止服务器单点故障的发生,通过配合 Nginx 可以实现 ...
最新文章
- 集体终止合作 航空代理模式走投无路背后
- 福利来了!国内TOP3的超级云计算,免费领2000核时计算资源!
- 论文阅读笔记03-fast-rcnn
- django不修改数据库创外键_Django——model(建表,增删改查,外键,多对多)
- 存储映射I/O(一)
- 从pheatmap无缝迁移至ComplexHeatmap
- 【Flink】Flink报错OutofMemoryError : Direct buffer memory
- 如何在 Python 数据中灵活运用 Pandas 索引?
- Day6 数据清洗(2)
- java树广度优先_如何在功能上生成树广度优先 . (使用Haskell)
- RS-485 接口电路--转载
- 传华为公司又一名技术部员工乔向英猝死
- html5模拟真实摇骰子,Axure教程:模拟真实摇骰子交互
- JS代码错误:Deleting local variable in strict mode
- 中文手机评论情感分析系列(二)
- Technica Engineering Enhanced Ethernet Switch, 车载以太网交换机功能介绍(100/1000BASE-T1 Switch, AVB/TSN)
- Threejs教程之着色器
- 今天的打拼,是为了与众不同的明天!
- CSR8675学习笔记:USB HID通信
- 《互联网+:小米案例版》的读书笔记