Nginx、Apache和Tomcat在功能、性能和适用场景上各有特点
一、从功能上分析
Nginx:主要处理静态资源,如HTML、CSS、JavaScript文件和图片等。它还支持反向代理和负载均衡,能够高效地处理大量并发连接。Nginx通过异步非阻塞的事件驱动模型,减少了上下文切换的开销,提高了CPU和内存的利用效率
Apache:功能全面,既可以处理静态资源,也可以通过各种模块支持动态内容的生成,如PHP、Perl等。Apache拥有丰富的功能模块,如访问控制、用户认证、URL重写等
Tomcat:专门用于运行Java Servlet和JSP,是一个轻量级的应用服务器。它主要处理动态内容,可以与各种Java框架无缝集成,如Spring、Struts等
二、从性能上分析
Nginx:以其高性能和低资源消耗著称。在高并发场景下,Nginx能够比Apache和Tomcat更好地应对流量高峰,因为它采用异步非阻塞的事件驱动模型,处理大量并发连接时占用内存和CPU资源较少
Apache:在处理静态资源方面的性能不如Nginx,但在合理配置和优化后,也能提供较好的性能。Apache在处理动态内容时表现良好,但其性能受配置和模块影响较大
Tomcat:在处理小到中等规模的并发请求时表现良好,但在处理大量并发连接时可能会出现性能瓶颈。Tomcat的性能受到Java虚拟机(JVM)的影响
三、适用场景分析
Nginx:适合高并发场景,如大型网站和API网关。它也常作为反向代理服务器,用于负载均衡和高可用性
Apache:适合需要处理多种类型内容的网站,特别是那些需要复杂配置和动态内容的网站。Apache的稳定性和丰富的功能使其在企业和政府机构中广泛使用
Tomcat:主要用于开发和部署Java Web应用程序。它特别适合内部网络和小型服务,如不需要流控的场景
从apache和nginx、tomcat架构上分析
- 架构:Apache采用多进程架构,每个请求都由一个独立的进程处理;而Nginx采用异步事件驱动的架构,可以处理更多的并发连接。
- 性能:由于Nginx的架构设计,它可以处理更多的并发连接,而且在高负载情况下表现更加稳定和可靠。因此,Nginx通常被认为是比Apache更高效的Web服务器。
- 配置:Apache的配置文件比较复杂,需要一定的学习和经验才能正确配置;而Nginx的配置文件比较简洁和可读性强,更容易理解和配置。
- 功能:Apache有许多模块可以扩展其功能,例如mod_rewrite用于URL重写,mod_ssl用于SSL加密等;而Nginx的功能比较简单,但是可以通过第三方模块扩展其功能。
-
Nginx处理大并发静态请求效率高于其他软件,可作为负载均衡服务器,可承受3万以上并发连接数,是Apache的10倍。4GB内存的服务器+Apache(prefork模式)一般只能处理3000个并发连接,占用3GB以上内存,Nginx在3万并发连接下,消耗不到2GB内存。
-
Nginx的处理高并发要优于httpd,先从两种Web服务器的工作原理及工作模式说起
-
Apache的三种工作模式
三种mpm介绍
Apache2.x支持插入式并行处理模块,称为多路处理模块(MPM)。在编译apache时必须且只能选择一个MPM,对类unix系统,可以有几个MPM可供选择,它们会影响到apache的速度和可伸缩性。
Prefork——多进程
多进程,每个请求用一个进程响应,这个过程会用到select机制来通知
介绍及适用场景
Prefork多路处理模块(MPM)实现了一个非线程型的、预派生的web服务器。
它的工作方式类似于Apache 1.3,适合于没有线程安全库,需要避免线程兼容性问题的系统。
适用于每个请求相互独立的情况,这样若一个请求出现问题就不会影响到其他请求。
具有很强的自我调节能力,只需要很少的配置指令调整。
最重要的是将MaxClients设置为一个足够大的数值以处理潜在的请求高峰。
同时又不能太大,以致需要使用的内存超出物理内存的大小。
如图
- 工作原理:
- 如果不用“–with-mpm”显式指定某种MPM,prefork就是Unix平台上缺省的MPM。
- 它所采用的预派生子进程方式也是 Apache1.3中采用的模式。prefork本身并没有使用到线程,2.0版使用它是为了与1.3版保持兼容性;
-
- 另一方面,prefork用单独的子进程来处理不同的请求,进程之间是彼此独立的,这也是其成为最稳定的MPM之一。
优点:稳定
缺点:慢,占用资源,不适用高并发场景
Worker——多线程
多线程,一个进程可以生成多个线程,每个线程响应一个请求,但通知机制还是select不过可以接受更多的请求
介绍及适用场景
woker多路处理模块(MPM)使网络服务器支持混合的多线程多进程
由于使用线程来处理请求,所以可以处理海量请求,而系统资源的开销小于基于进程的MPM。
同时使用了多进程,每个进程又有多个线程,以获得基于进程的MPM的稳定性。
(父进程)负责子进程的建立。每个子进程可以建立ThreadsPerChild数量的服务线程和一个监听线程,该监听线程监听接入请求并将其传递给服务线程处理和应答。
不管是Worker模式或是Prefork 模式,Apache总是试图保持一些备用的(spare)或者是空闲的子进程(空闲的服务线程池)用于迎接即将到来的请求。
这样客户端就不需要在得到服务前等候子进程的产生。
如图
- 工作原理:
- 相对于prefork,worker是2.0版中全新的支持多线程和多进程混合模型的MPM。
- 由于使用线程来处理,所以可以处理相对海量的请求,而系统资源的开销要小于基于进程的服务器。
- 但是,worker也使用了多进程,每个进程又生成多个线程,以获得基于进程服务器的稳定性,这种MPM的工作方式将是Apache2.0的发展趋势。
优点:相较于prefork占用的内存较少,可以同时处理更多请求
缺点:使用keep-alive的长连接方式,某个线程一直被占用,即使没有传输数据,也需要一直等待到超时才会被释放。
如果过多的线程被占用,也会导致在高并发场景下无服务线程可用。该情况在prefork模式下同样发生。
Event——基于异步I/O模型
基于异步I/O模型,一个进程或线程,每个进程或线程响应多个用户请求,它是基于事件驱动(也就是epoll机制)实现的
介绍及适用场景
以上两种稳定的MPM方式在非常繁忙的服务器应用下都有些不足。
尽管HTTP的Keepalive方式能减少TCP连接数量和网络负载,但是 Keepalive需要和服务进程或者线程绑定,这就导致一个繁忙的服务器会耗光所有的线程。
Event MPM是解决这个问题的一种新模型,它把服务进程从连接中分离出来。
在服务器处理速度很快,同时具有非常高的点击率时,可用的线程数量就是关键的资源限制此时Event MPM方式是最有效的。
一个以Worker MPM方式工作的繁忙服务器能够承受每秒好几万次的访问量(例如在大型新闻服务站点的高峰时),而Event MPM可以用来处理更高负载。
如图
工作原理:
event基于事件机制的特性,一个进程响应多个用户请求,利用callback机制,让套接字复用,请求过来后进程并不处理请求,而是直接交由其他机制来处理,通过epoll机制来通知请求是否完成;
在这个过程中,进程本身一直处于空闲状态,可以一直接收用户请求。可以实现一个进程程响应多个用户请求。支持持海量并发连接数,消耗更少的资源。
event工作机制
event只在有数据发送的时候才开始建立连接,连接请求才会触发工作线程,
即使用了TCP的一个选项,叫做延迟接受连接TCP_DEFER_ACCEPT,加了这个选项后,
若客户端只进行TCP连接,不发送请求,则不会触发Accept操作,也就不会触发工作线程去干活,进行了简单的防攻击(TCP连接)
优点:
单线程响应多请求,专门有一个线程负责监听管理释放连接,解决了keep-alive场景下资源被长期占用的问题,从而占据更少的内存。
缺点:没有线程安全控制。
如何提高Web服务器的并发连接处理能力
1、基于线程,即一个进程生成多个线程,每个线程响应用户的每个请求。
2、基于事件的模型,一个进程处理多个请求,并且通过epoll机制来通知用户请求完成。
3、基于磁盘的IO(异步I/O)
4、支持mmap内存映射,mmap传统的web服务器,进行页面输入时,都是将磁盘的页面先输入到内核缓存中,再由内核缓存中复制一份到web服务器上mmap机制就是让内核缓存与磁盘进行映射,web服务器,直接复制页面内容即可。不需要先把磁盘的上的页面先输入到内核缓存去
-
Nginx优异之处
-
传统Web服务基于进程/线程,每个进程/线程处理并发连接请求,产生阻塞,利用率低下。
-
新的进程/线程需备好运行时环境,如堆内存、栈内存和执行上下文,占用CPU,过多进程/线程导致线程抖动、上下文切换,进一步降低系统性能。
-
Nginx采用模块化、事件驱动、异步、单线程及非阻塞的架构,多路复用及事件通知机制,每个Worker处理数千个并发连接及请求。
-
Nginx 是一个高性能的 Web 和反向代理服务器, 它具有有很多非常优越的特性。
-
作为 Web 服务器:相比 Apache,Nginx 使用更少的资源,支持更多的并发连接,体现更高的效率。
-
作为负载均衡服务器: Nginx 既可以在内部直接支持 Rails 和 PHP,也可以支持作为 HTTP代理服务器 对外进行服务。Nginx 用 C 编写, 不论是系统资源开销还是 CPU 使用效率都比 Perlbal 要好的多。
-
作为邮件代理服务器: Nginx 同时也是一个非常优秀的邮件代理服务器(最早开发这个产品的目的之一也是作为邮件代理服务器),Last.fm 描述了成功并且美妙的使用经验。
为什么Nginx没有取代Apache
因为两个东西的侧重点不一样,Apache自身内置了很多东西,无需借助其他东西就能够几乎所有的Web类型应用进行支持。
- 而Nginx不同,它在静态文件的处理、高并发方面比较有优势。
- Apache侧重在完整稳定上,而Nginx侧重在轻量高效上,很多时候Apache和Nginx是配合使用的
- Nginx配置在Apache前面,用它挡掉静态文件的请求(网站今天资源的请求占了大部分的),Nginx处理不了的内容才转发给Apache来处理。
Nginx工作原理
Nginx会按需同时运行多个进程:一个主进程(master)和几个工作进程(worker),配置了缓存时还会有缓存加载器进程(cache loader)和缓存管理器进程(cache manager)等。所有进程均是仅含有一个线程,并主要通过“共享内存”的机制实现进程间通信。主进程以root用户身份运行,而worker、cache loader和cache manager均以非特权用户身份运行。
在高连接并发的情况下,Nginx是Apache服务器不错的替代品。
Nginx安装简单,配置文件简洁且支持Perl语法,Bug极少。Nginx启动容易,可7*24不间断运行数月,且可在不中断服务的情况下升级软件版本。
Apache与Nginx比较
在选择Web服务器时,Nginx和Apache都是备受推崇的选择。然而,对于许多开发者和管理员来说,选择哪一个可能会成为一个难以解决的问题。因此,我们需要对两者进行比较,以确定哪一个更适合我们的需求。首先,Nginx以其高效的性能而闻名。它是一个轻量级的Web服务器,可以处理大量并发连接。相比之下,Apache是一个成熟的Web服务器,但它在处理并发连接时可能会出现性能瓶颈。因此,如果您需要处理大量并发连接,Nginx可能是更好的选择。
其次,Nginx具有更好的负载均衡功能。它可以在多个服务器之间均衡地分配流量,以提高性能和可靠性。Apache也可以实现负载均衡,但相对来说要更为复杂。
最后,Nginx的配置文件比Apache更为简单和易于理解。这意味着您可以更快地配置服务器并更快地上线。相比之下,Apache的配置可能会更加复杂,需要更多的时间和精力。
Nginx
轻量级,采用 C 进行编写,同样的 web 服务,会占用更少的内存及资源
抗并发,nginx 以 epoll and kqueue 作为开发模型,处理请求是异步非阻塞的,负载能力比 apache 高很多,而 apache 则是阻塞型的。在高并发下 nginx 能保持低资源低消耗高性能 ,而 apache 在 PHP 处理慢或者前端压力很大的情况下,很容易出现进程数飙升,从而拒绝服务的现象。
nginx 处理静态文件好,静态处理性能比 apache 高三倍以上
nginx 的设计高度模块化,编写模块相对简单
nginx 配置简洁,正则配置让很多事情变得简单,而且改完配置能使用 -t 测试配置有没有问题,apache 配置复杂 ,重启的时候发现配置出错了,会很崩溃
nginx 作为[负载均衡务器],支持 7 层负载均衡
nginx 本身就是一个反向代理服务器,而且可以作为非常优秀的邮件代理服务器
启动特别容易, 并且几乎可以做到 7*24 不间断运行,即使运行数个月也不需要重新启动,还能够不间断服务的情况下进行软件版本的升级。社区活跃,各种高性能模块出品迅速
Apache
apache 的 rewrite 比 nginx 强大,在 rewrite 频繁的情况下,用 apache
apache 发展到现在,模块超多,基本想到的都可以找到
apache 更为成熟,少 bug ,nginx 的 bug 相对较多
apache 超稳定
apache 对 PHP 支持比较简单,nginx 需要配合其他后端用
apache 在处理动态请求有优势,nginx 在这方面是鸡肋,一般动态请求要 apache 去做,nginx 适合静态和反向。
apache 仍然是目前的主流,拥有丰富的特性,成熟的技术和开发社区选择Nginx还是Apache
apache运行php比较好,适合跑动态
nginx比较适合跑静态(如果想让nginx跑动态只能支持跳转)。
现在流行的lanmp架构就是同时使用apache和nginx,静态网页有nginx处理,动态交由apache处理,这样就能更大限度的发挥服务器性能。
通用的方案是,前端 nginx 抗并发,后端 apache 集群,配合起来会更好。
总结
两者最核心的区别在于 apache 是同步多进程模型,一个连接对应一个进程,而 nginx 是异步的,多个连接(万级别)可以对应一个进程一般来说,需要性能的web服务,用nginx 。如果不需要性能只求稳定,更考虑 apache ,后者的各种功能模块实现得比前者,例如 ssl 的模块就比前者好,可配置项多。
epoll(freebsd 上是 kqueue ) 网络 IO 模型是 nginx 处理性能高的根本理由,但并不是所有的情况下都是 epoll 大获全胜的,如果本身提供静态服务的就只有寥寥几个文件,apache 的 select 模型或许比 epoll 更高性能。当然,这只是根据网络 IO 模型的原理作的一个假设,真正的应用还是需要实测了再说的。
综上所述,Apache和Nginx各有优缺点。在选择使用哪种Web服务器时,需要根据具体的需求和场景来综合考虑。
Apache配置参数解析
mpm工作模块
查看三种MPM的静态编译模块
httpd -l
查看静态编辑及动态装载的模块
httpd -m
动态模块路径
ll /usr/lib64/httpd/modules/
apache安装时设置工作模式
[root@localhost httpd-2.4.1]# ./configure --prefix=/usr/local/apache2worker --enable-so --with-mpm=worker
[root@localhost httpd-2.4.1]# make
[root@localhost httpd-2.4.1]# make install
指定--with-mpm=NAME 选项指定MPM,不指定模式的话,默认为Prefork MPM。
配置Event MPM
./configure --prefix=/usr/local/apache2worker --enable-so --enable-nonportable-atomics=yes --with-mpm=event
找到httpd-mpm.conf文件
# perfork MPM
<IfModule mpm_prefork_module>
StartServers 5
MinSpareServers 5
MaxSpareServers 10
MaxRequestWorkers 250
MaxConnectionsPerChild 0
</IfModule>
参数解析
# StartServers: 数量的服务器进程开始
# MinSpareServers: 最小数量的服务器进程,保存备用
# MaxSpareServers: 最大数量的服务器进程,保存备用
# MaxRequestWorkers: 最大数量的服务器进程允许开始
# MaxConnectionsPerChild: 最大连接数的一个服务器进程服务
prefork实际应用原理
prefork 控制进程在最初建立“StartServers”个子进程后,为了满足MinSpareServers设置的需要创建一个进程,每秒按指数级增加,直至最多每秒32个,满足MinSpareServers设置的值为止
这种模式 可以不必在请求到来时再产生新的进程,从而减小了系统开销以增加性能。
MaxSpareServers设置了最大的空闲进程数,如果空闲进程数大于这个值,Apache会自动kill掉一些多余进程。
这个值不要设得过大,但如果设的值比MinSpareServers小,Apache会自动把其调整为 MinSpareServers+1。
如果站点负载较大,可考虑同时加大MinSpareServers和MaxSpareServers。
MaxRequestsPerChild设置的是每个子进程可处理的请求数。每个子进程在处理了“MaxRequestsPerChild”个请求后将自 动销毁。0意味着无限,即子进程永不销毁。
虽然缺省设为0可以使每个子进程处理更多的请求,但如果设成非零值也有两点重要的好处:
1、可防止意外的内存泄 漏。2、在服务器负载下降的时侯会自动减少子进程数。
因此,可根据服务器的负载来调整这个值。
指令集同时将服务请求的数量上的限制。任何连接尝试在MaxRequestWorkerslimit将通常被排队,最多若干基于上ListenBacklog指令。
在apache2.3.13以前的版本MaxRequestWorkers被称为MaxClients
(MaxClients)是这些指令中最为重要的一个,设定的是 Apache可以同时处理的请求,是对Apache性能影响最大的参数。其缺省值150是远远不够的,如果请求总数已达到这个值(可通过ps -ef|grep http|wc -l来确认),那么后面的请求就要排队,直到某个已处理请求完毕。
这就是系统资源还剩下很多而HTTP访问却很慢的主要原因。虽然理论上这个值越大,可以 处理的请求就越多,但Apache默认的限制不能大于256。
# worker MPM
<IfModule mpm_worker_module>
StartServers 3
MinSpareThreads 75
MaxSpareThreads 250
ThreadsPerChild 25
MaxRequestWorkers 400
MaxConnectionsPerChild 0
</IfModule>
参数解析
# StartServers: 初始数量的服务器进程开始
# MinSpareThreads: 最小数量的工作线程,保存备用
# MaxSpareThreads: 最大数量的工作线程,保存备用
# ThreadsPerChild: 固定数量的工作线程在每个服务器进程
# MaxRequestWorkers: 最大数量的工作线程
# MaxConnectionsPerChild: 最大连接数的一个服务器进程服务
woker实际应用原理
Worker 由主控制进程生成“StartServers”个子进程,每个子进程中包含固定的
ThreadsPerChild线程数,各个线程独立地处理请求。同样, 为了不在请求到来时再生成线程,MinSpareThreads和MaxSpareThreads设置了最少和最多的空闲线程数;
而MaxRequestWorkers 设置了同时连入的clients最大总数。如果现有子进程中的线程总数不能满足负载,控制进程将派生新的子进程
MinSpareThreads和 MaxSpareThreads的最大缺省值分别是75和250。这两个参数对Apache的性能影响并不大,可以按照实际情况相应调节 。
ThreadsPerChild是worker MPM中与性能相关最密切的指令。ThreadsPerChild的最大缺省值是64,如果负载较大,64也是不够的。这时要显式使用 ThreadLimit指令,它的最大缺省值是20000。
Worker模式下所能同时处理的请求总数是由子进程总数乘以ThreadsPerChild 值决定的,应该大于等于MaxRequestWorkers。如果负载很大,现有的子进程数不能满足时,控制进程会派生新的子进程。默认最大的子进程总数是16,加大时 也需要显式声明ServerLimit(最大值是20000)。
需要注意的是,如果显式声明了ServerLimit,那么它乘以 ThreadsPerChild的值必须大于等于MaxRequestWorkers,而且MaxRequestWorkers必须是ThreadsPerChild的整数倍,否则 Apache将会自动调节到一个相应值。
# event MPM
<IfModule mpm_event_module>
StartServers 3
MinSpareThreads 75
MaxSpareThreads 250
ThreadsPerChild 25
MaxRequestWorkers 400
MaxConnectionsPerChild 0
</IfModule>
参数解析
# StartServers:初始数量的服务器进程开始
# MinSpareThreads: 最小数量的工作线程,保存备用
# MaxSpareThreads: 最大数量的工作线程,保存备用
# ThreadsPerChild: 固定数量的工作线程在每个服务器进程
# MaxRequestWorkers: 最大数量的工作线程
# MaxConnectionsPerChild: 最大连接数的一个服务器进程服务
配置安装参数
./configure --prefix=/usr/local/apache2
--enable-rewrite --enable-so --enable-headers
--enable-expires --with-mpm=worker
--enable-modules=most --enable-deflate
参数解析
--prefix=/usr/local/apache2 指定安装路径
--enable-rewrite 提供URL重写规则
--enable-so 激活DSO方式动态安装共享目标模块 这个模块本身不可以用DSO
--enable-headers 提供允许对HTTP请求头的控制
--enable-expires 激活通过配置文件控制HTTP的“Expires:”和“Cache-Control:”头内容,即对网站图片、js、css等内容,提供客户端浏览器缓存的设置。这个是apache调优的一个重要选项之一
--with-mpm=worker 选择工作模式 如 prefork event
--enable-deflate 提供对内容的压缩传输编码支持,一般是html、js、css等内容的站点。使用此参数会打打提高传输速度,提升访问者访问的体验。在生产环境中,这是apache调优的一个重要选项之一
配置文件
1.apahce反向代理
ProxyPass /mirror/foo/ http://backend.example/
ProxyPassReverse /mirror/foo/ http://backend.example/
这个配置会导致对http://example/mirror/foo/bar的本地请求在内部转换为对http://backend.example/bar的代理请求。
这两个指令在Apache服务器中用于调整由反向代理服务器发送的HTTP响应头中的URL。
其主要作用是将后端服务器发送的HTTP重定向响应中的Location、Content-Location和URI头里的URL重写为正确的地址
从而避免在Apache作为反向代理时,后端服务器的HTTP重定向导致请求绕过反向代理的问题
2.vhost.conf
开启前在httpd.conf文件打开vhost模块注释
示例
<VirtualHost *:80> #若是其他端口在此处改相应端口
ServerName www.debug_hh #表示要访问的域名 8080其他端口直接在ip:8080
DocumentRoot D:\wamp\www\managerProject\web\src\backend\web #项目的地址
<Directory "D:\wamp\www\managerProject\web\src\backend\web">
Options +Indexes +FollowSymLinks +MultiViews
AllowOverride All
Order deny,allow
allow from all
</Directory>
</VirtualHost>
参数解析
根目录包含 .htacess 配置文件 url重写规则都在里面,出于安全性考虑,一般根目录AllowOverride属性一般都配置成不允许任何Override ,即
<Directory />
AllowOverride None
</Directory>
对于需要重写的目录
< Directory /myaddrroot/>
AllowOverride FileInfo
< /Directory>
在要支持url rewirte的目录启用 Options FollowSymLinks和AllowOverride All
Alias /py "c:/web/py/"
<Directory "c:/web/py/">
Options Indexes FollowSymLinks
AllowOverride All
Order allow,deny
Allow from all
</Directory>
参数解析
AuthConfig 允许使用所有的权限指令
包括AuthDBMGroupFile AuthDBMUserFile AuthGroupFile AuthName AuthTypeAuthUserFile和Require
FileInfo 允许使用文件控制类型的指令
包括AddEncoding AddLanguage AddType DEfaultType ErrorDocument LanguagePriority
Indexes 允许使用目录控制类型的指令
包括AddDescription AddIcon AddIconByEncoding AddIconByType DefaultIcon DirectoryIndex FancyIndexing HeaderName IndexIgnore IndexOptions ReadmeName
Limit 允许使用权限控制指令。它们包括Allow Deny和Order
Options 允许使用控制目录特征的指令.他们包括Options 和XBitHack
Options 参数解析
All 准许以下除MultiViews以外所有功能
MultiViews 允许多重内容被浏览,如果你的目录下有一个叫做foo.txt的文件,那么你可以通过/foo来访问到它,这对于一个多语言内容的站点比较有用
Indexes 若该目录下无index文件,则准许显示该目录下的文件以供选择
IncludesNOEXEC 准许SSI,但不可使用#exec和#include功能
Includes 准许SSI
FollowSymLinks 在该目录中,服务器将跟踪符号链接。注意,即使服务器跟踪符号链接,它也不会改变用来匹配不同区域的路径名,如果在<Local>;标记内设置,该选项会被忽略
SymLinksIfOwnerMatch 在该目录中仅仅跟踪本站点内的链接
ExecCGI 在该目录下准许使用CGI
注:在前,加 + 代表允许目录浏览;加 – 代表禁止目录浏览。
3.访问限制
Require all granted:表示允许所有主机访问
Require all denied:表示拒绝所有主机访问
Require local:表示仅允许本地主机访问
Require [not] host <主机名或域名列表>:表示允许或拒绝指定主机或域名访问
Require [not] ip <IP地址或网段列表>:表示允许或拒绝指定的IP地址或网段访问
Nginx常用命令大全
nginx -s reopen #日志分割
nginx -s reload #重新加载Nginx配置文件
nginx -s stop #强制停止Nginx服务
nginx -s quit #优雅地停止Nginx服务(即处理完所有请求后再停止服务)
nginx -t #检测配置文件是否有语法错误,然后退出
nginx -?,-h #打开帮助信息
nginx -v #显示版本信息并退出
nginx -V #显示版本和配置选项信息,然后退出
nginx -T #检测配置文件是否有语法错误,转储并退出
nginx -q #在检测配置文件期间屏蔽非错误信息
nginx -p prefix #设置前缀路径(默认是:/usr/share/nginx/)
nginx -c filename #设置配置文件(默认是:/etc/nginx/nginx.conf)
nginx -g directives #设置配置文件外的全局指令
killall nginx #杀死所有nginx进程
Nginx在WIndows下常用命令
启动
直接点击Nginx目录下的nginx.exe 或者 cmd运行start nginx
关闭
nginx -s stop 或者 nginx -s quit
stop表示立即停止nginx,不保存相关信息
quit表示正常退出nginx,并保存相关信息
nginx -s stop 或者 nginx -s quit
nginx -s reload :修改配置后重新加载生效
nginx -s reopen :分割日志
nginx -t -c /path/to/nginx.conf 测试nginx配置文件是否正确
Nginx与Tomcat区别
Nginx和Tomcat是两种不同的技术,它们在应用场景、性能、动态处理能力等方面有所区别
应用场景
Nginx通常用作静态内容服务器或代理服务器,可以将外部请求转发给其他应用服务器,如Tomcat、Django等。而Tomcat则主要用作应用服务器,用于运行Java Web应用程序,如JSP和Servlet。
性能在静态内容处理方面,Nginx能够支持高并发,因为它使用了异步非阻塞的模型,能够轻松处理数以百万级别的并发连接。相比之下,Tomcat在静态内容处理方面可能不如Nginx高效。
配置Tomcat配置相对简单,主要修改server.xml等配置文件来管理。而Nginx的配置更为灵活和强大,包括对HTTP、TCP、UDP等多种协议的支持。
安全性Tomcat和Nginx都提供了SSL/TLS加密等安全性功能,但它们的应用场景和安全侧重点不同。Nginx在流媒体等安全敏感场景中表现更佳,而Tomcat则更侧重于应用层面的安全。
扩展性Tomcat通过插件机制可以实现各种功能,但通常需要与Java技术栈结合使用。而Nginx则通过模块化的设计,能够方便地扩展其功能,包括与PHP、Python等其他语言集成。
动态处理能力。Nginx本身不支持动态处理,如JSP或Servlet,需要依赖其他插件或后端软件(如PHP)来支持动态内容。而Tomcat是一个标准的Servlet和JSP容器,能够处理动态内容。
架构设计。Nginx基于事件驱动架构,使用epoll或kqueue等高性能的网络事件模型。而Tomcat则基于传统的请求-响应模型,每个请求都需要一个线程来处理。
日志管理Tomcat主要记录应用程序级别的日志,而Nginx则提供了更详细的日志记录和访问控制功能。
内存和资源消耗。Nginx在内存和资源消耗方面表现出色,因为它使用了轻量级的设计,能够以较低的资源消耗处理高并发的请求。相比之下,Tomcat在内存和资源消耗方面通常更高,因为它需要更多的资源来运行和处理动态内容。
严格意义上来讲,nginx应该叫做HTTP Server,而tomcat是一个Application Server是一个Servlet/JSO应用的容器。
客户端通过HTTP Server访问服务器上存储的资源(HTML文件,图片文件等),HTTP Server只是把服务器上的文件如实通过HTTP协议传输给客户端。服务器往往是运行在HTTP Server的背后,执行应用,将动态的内容转化为静态的内容之后,通过HTTP Server分发到客户端。
nginx搭配tomcat实现负载均衡
Tomcat简介
Apache Tomcat 是一个免费开源的轻量级Servlet容器,由Apache软件基金会的Jakarta项目提供。它主要用于部署和运行Java Servlet和JavaServer Pages (JSP) 应用程序。
Tomcat因其简单易用、配置灵活以及对最新Java EE标准的良好支持而受到开发者们的喜爱。自1999年发布以来,Tomcat已成为Java Web应用程序开发的标准平台之一。无论是初学者还是经验丰富的开发者,都可以轻松地使用Tomcat来搭建Web服务器环境,进行Java Web应用的开发与测试。
Mac安装Tomcat
首先去官网下载tomcat安装包,tomcat下载链接:https://tomcat.apache/download-80.cgi。
进入tomcat的bin目录,然后运行 ./startup.sh
启动Tomcat
访问http://localhost:8080/
,如果看到Tomcat的默认欢迎页面,说明tomcat启动成功。
启动成功之后,记得先执行./shutdown.sh
来关掉tomcat,不然后面使用IDEA来启动时,会报端口已经被占用错误。
创建Java Web项目并配置Tomcat服务器
创建Java Web项目
本文通过maven来创建web项目,这样后面引入其他工具包会更加方便,注意创建项目的时候要添加webapp相关原型方便后续的Web开发。
zhaozhao
刚创建出来的项目的文件目录如下,是没有java目录的。
首先需要创建出java目录,然后检查文件夹的颜色是否正常
不正常的话,标记一下文件夹,将其标记为源代码目录。
配置Tomcat作为服务器
在IDEA中配置Tomcat服务器,选择Local模式以配置本地安装的Tomcat。
因为我们的tomcat是安装在本地的,所以直接选择Local的方式;如果安装在远程,则选择Remote。
如果Application server没有识别出你所安装的tomcat,就点击右边的Configure按钮,选择上面下载的tomcat所在文件夹,手动指定Tomcat的安装路径。 配置完tomcat作为服务器之后,需要创建Artifact,才可以将项目部署到服务器上面。Application context
一般可以设置为项目名,这个名字的作用是用来隔离不同的项目,后续访问的时候,链接为localhost:8080/项目名
。
配置完Tomcat服务器,就可以启动服务。
出现下面的successfully,说明启动成功。
最后尝试访问网站,看看部署是否成功。
nginx和apache的搭建配置可参考 Mac homebrew搭建php nginx apache mysql环境_homebrew安装php-CSDN博客
使用nginx和tomcat实现反向代理和负载均衡
一、nginx操作的常用命令
使用nginx
操作命令的前提条件:必须进入
nginx
的目录
/usr/local/nginx/sbin
# 查看nginx版本号
./nginx -v
# 关闭nginx
./nginx -s stop
# 开启nginx
./nginx
# 重新加载nginx
./nginx -s reload
nginx配置文件
nginx配置文件由三部分组成第一部分,全局块
从配置文件开始到events块之间的内容,主要会设置一些影响nginx服务器整体运行的配置指令。
比如 word_processes 1;值越大,可以支持的并发处理量也越多。第二部分,events块
events块设计的指令主要影响nginx服务器与用户的网络连接,
比如 worker_connections 1024;支持的最大连接数。第三部分,http块
nginx服务器配置中最频繁的部分
http块也包括http全局块、server块。
二、nginx配置反向代理
反向代理的本质目的:当window浏览器访问192.168.186.128并且端口是80时,nginx会转发到http://127.0.0.1:8080的地址。
首先启动linux虚拟机中的tomcat(进入tomcat的bin目录中,执行./startup.sh文件开启tomcat)
可以访问到
进入nginx
的配置文件中,修改server_name
为linux
本机的ip
地址。
这样子配置以后,当window
浏览器访问192.168.186.128
并且端口是80时,nginx会转发到http://127.0.0.1:8080的地址。
然后就实现了nginx
反向代理。
三、nginx配置反向代理服务器转发到多个服务器
要实现的效果:使用nginx反向代理,根据访问的路径不同跳转到不同的服务端口中。
准备工作:准备两个tomcat服务器,一个8080端口,一个8081端口。
首先把刚才的tomcat进程杀掉
[root@bogon src]# ps -ef | grep tomcat
root 8298 1 0 22:36 pts/0 00:00:04 /usr/local/java/jdk1.8.0_231/bin/java -Djava.util.logging.config.file=/opt/apache-tomcat-7.0.96/conf/logging.properties -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Djdk.tls.ephemeralDHKeySize=2048 -Dignore.endorsed.dirs= -classpath /opt/apache-tomcat-7.0.96/bin/bootstrap.jar:/opt/apache-tomcat-7.0.96/bin/tomcat-juli.jar -Dcatalina.base=/opt/apache-tomcat-7.0.96 -Dcatalina.home=/opt/apache-tomcat-7.0.96 -Djava.io.tmpdir=/opt/apache-tomcat-7.0.96/temp org.apache.catalina.startup.Bootstrap start
root 8949 2973 0 23:17 pts/0 00:00:00 grep --color=auto tomcat
[root@bogon src]# kill 8298
[root@bogon src]# ps -ef | grep tomcat
root 8957 2973 0 23:18 pts/0 00:00:00 grep --color=auto tomcat
然后在/usr/src
目录下新建两个文件夹tomcat8080
和tomcat8081
,使用xftp
分别给这两个文件夹传入tomcat压缩包。
如果上传错误就是用命令chmod 777 文件夹名
赋予权限就可以了。
分别解压
tar -xvf apache-tomcat-7.0.96.tar.gz
启动8080端口的tomcat
启动8081端口的tomcat
,解压之后进入到tomcat
的conf
目录中,编辑server.xml
配置文件
[root@bogon tomcat8081]# ls
apache-tomcat-7.0.96 apache-tomcat-7.0.96.tar.gz
[root@bogon tomcat8081]# cd apache-tomcat-7.0.96/
[root@bogon apache-tomcat-7.0.96]# ls
bin BUILDING.txt conf CONTRIBUTING.md lib LICENSE logs NOTICE README.md RELEASE-NOTES RUNNING.txt temp webapps work
[root@bogon apache-tomcat-7.0.96]# cd conf
[root@bogon conf]# ls
catalina.policy catalina.properties context.xml logging.properties server.xml tomcat-users.xml web.xml
[root@bogon conf]# vim server.xml
首先把这个改成8015端口
再分别改成8081端口和8019端口
然后把8081端口的tomcat也启动起来
[root@bogon bin]# ls
bootstrap.jar catalina-tasks.xml configtest.bat digest.bat setclasspath.sh startup.bat tomcat-native.tar.gz version.bat
catalina.bat commons-daemon.jar configtest.sh digest.sh shutdown.bat startup.sh tool-wrapper.bat version.sh
catalina.sh commons-daemon-native.tar.gz daemon.sh setclasspath.bat shutdown.sh tomcat-juli.jar tool-wrapper.sh
[root@bogon bin]# ./startup.sh
Using CATALINA_BASE: /usr/src/tomcat8081/apache-tomcat-7.0.96
Using CATALINA_HOME: /usr/src/tomcat8081/apache-tomcat-7.0.96
Using CATALINA_TMPDIR: /usr/src/tomcat8081/apache-tomcat-7.0.96/temp
Using JRE_HOME: /usr/local/java/jdk1.8.0_231
Using CLASSPATH: /usr/src/tomcat8081/apache-tomcat-7.0.96/bin/bootstrap.jar:/usr/src/tomcat8081/apache-tomcat-7.0.96/bin/tomcat-juli.jar
Tomcat started.
创建文件夹和测试页面,做测试的准备工作。
分别在两个tomcat的webapps文件夹中新建文件夹;
在8080端口的tomcat的webapps中新建文件夹edu,在edu中新建html文件<h1>8080端口</h1>;
在8081端口的tomcat的webapps中新建文件夹vod,在vod中新建html文件<h1>8081!!</h1>;
然后分别在windows浏览器访问
找到nginx配置文件,进行反向代理配置
[root@bogon vod]# cd /usr/local/nginx/conf
[root@bogon conf]# ls
fastcgi.conf fastcgi_params koi-utf mime.types nginx.conf scgi_params uwsgi_params win-utf
fastcgi.conf.default fastcgi_params.default koi-win mime.types.default nginx.conf.default scgi_params.default uwsgi_params.default
[root@bogon conf]# vim nginx.conf
添加一下配置
说明:监听192.168.186.128:9001
地址,如果后面路径是edu
,转发到http://127.0.0.1:8080地址;如果后面地址vod
,则转发到http://127.0.0.1:8081地址。
然后重新加载nginx,进到/usr/local/nginx/sbin
目录
# 先关掉nginx
./nginx -s stop
# 再开启nginx
./nginx
测试后反向代理就完成了
四,nginx配置负载均衡
实现效果:浏览器地址栏输入http://192.168.186.128/edu/a.html,负载均衡效果,平均到8080端口和8081端口中。
准备工作:
两台tomcat服务器,一个8080端口,一个8081端口,上面已经准备过了。
在两台tomcat的webapps目录中分别都创建edu文件夹,在edu文件夹中新建a.html文件
在nginx的配置文件中进行负载均衡的配置
负载均衡配置
在下面的位置添加以下配置。
在server{}中再加入以下规则
刷新以下浏览器,会访问8081端口的tomcat,一直刷新一直在切换。
这说明nginx把多次请求平均分摊到不同的服务器中,实现了负载均衡。
五、负载均衡的分配服务器策略
第一种:轮询
每个请求按时间顺序逐一分配到不同的后端服务器,如果后端服务器down掉,能自动剔除。
第二种:weight权重
weight代表权重,默认是1,权重越高被分配的客户端越多。
upstream myserver {
server 192.168.186.128:8080 weight=5;
server 192.168.186.128:8080 weight=10;
}
第三种:ip_hash
每个请求按访问ip的hash结果分配,这样每个访客固定访问要给后端服务器,可以解决session共享的问题(单点登录会遇到这个问题)。
upstream myserver {
ip_hash;
server 192.168.186.128:8080;
server 192.168.186.128:8080 ;
}
第四种:fair(第三方)
按后端服务器的响应时间来分配请求,响应时间短的优先分配。
upstream myserver {
server 192.168.186.128:8080;
server 192.168.186.128:8080 ;
fair;
}
nginx使用反向代理实现多站点配置
user nginx;
worker_processes auto;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
# 配置官网的服务器
server {
listen 80;
server_name www.yourwebsite;
location / {
proxy_pass http://backend_server_for_website;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
# 配置后台API的服务器
server {
listen 80;
server_name api.yourwebsite;
location / {
proxy_pass http://backend_server_for_api;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
}
在这个配置中,
www.yourwebsite
用于官网,而api.yourwebsite
用于后台API。两个服务器的后端服务器地址需要替换为实际的后端服务地址(例如:http://127.0.0.1:8080
)。确保在配置文件中替换
backend_server_for_website
和backend_server_for_api
为实际的后端服务器地址。
在应用配置后,记得重新加载或重启Nginx以使配置生效:
检测nginx配置文件
nginx -t #这个命令很重要
重新引入nginx配置文件
sudo nginx -s reload
或者
sudo systemctl reload nginx
单网站单服务器的nginx配置
server {
listen 80; # 监听80端口
server_name www.google google; # 带www域名和不带www域名都指向该网站资源
location / {
root /root/www/google; # 网站的静态资源目录,css,js,image文件等
index index.html; # 网站首页
}
if ( $host != 'www.google'){
rewrite ^(.*) $scheme://www.google$1 permanent; # 重定向到www.google
}
}
多网站单服务器的nginx配置
user root; # 重点,Linux系统中创建Nginx的用户,这里设置为root,拥有文件读取权限
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;
#access_log logs/access.log main;
sendfile on;
#tcp_nopush on;
#keepalive_timeout 0;
keepalive_timeout 65;
#gzip on;
server { # 默认的server,也就是显示Nginx默认界面
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;
}
}
# 以上均为nginx.conf文件的默认配置,不需要更改,直接在下面添加即可
# another virtual host using mix of IP-, name-, and port-based configuration
server {
listen 80;
server_name www.baidu;
location / {
root /root/www/baidu; # 网站的静态资源目录,css,js,image文件等
index index.html; # 网站首页
}
}
server {
listen 80;
server_name baidu;
rewrite ^(.*) $scheme://www.$server_name$1 permanent; # 跳转到www域名下
}
server {
listen 80;
server_name www.google;
location / {
root /root/www/google; # 网站的静态资源目录,css,js,image文件等
index index.html; # 网站首页
}
}
server {
listen 80;
server_name google;
rewrite ^(.*) $scheme://www.$server_name$1 permanent; # 跳转到www域名下
}
}
nginx location配置命令详解
1. 概述
在Web服务器的配置中,Nginx的location指令扮演着至关重要的角色。它不仅是Nginx配置的核心组成部分,更是实现灵活路由和请求处理的关键。location指令允许服务器根据请求的URI执行不同的操作,从而为Web应用提供了强大的URL匹配和处理能力。location指令的主要作用是根据用户请求的URI来决定如何处理这个请求。它可以将不同的请求映射到文件系统的不同路径,或者将请求转发到其他服务器。通过合理配置location,我们可以实现诸如静态文件服务、反向代理、负载均衡等多种功能。
在Nginx配置文件中,location指令通常位于server块内。一个server块可以包含多个location块,每个location块定义了一组特定的URI处理规则。当Nginx接收到一个HTTP请求时,它会根据请求的URI逐一匹配这些location块,直到找到最佳匹配。
location指令的灵活性体现在其多样的匹配方式上。它支持精确匹配、前缀匹配、正则表达式匹配等多种匹配模式。这些不同的匹配模式使得Nginx能够处理各种复杂的URL结构,满足不同Web应用的需求。
此外,location指令还可以与其他Nginx指令配合使用,如proxy_pass、rewrite、try_files等,进一步增强了其功能性。这种组合使用使得Nginx能够实现更复杂的请求处理逻辑,如URL重写、请求重定向、错误页面处理等。
然而,location指令的强大功能也带来了一定的复杂性。正确理解和使用location指令需要对其语法规则、优先级顺序、以及与其他指令的交互有深入的了解。不当的配置可能导致意外的行为,如请求被错误路由或无法访问某些资源。
因此,掌握location指令的用法对于Nginx管理员和Web开发者来说至关重要。通过深入学习location指令的各种用法和最佳实践,我们可以充分发挥Nginx的潜力,构建高效、安全、可扩展的Web应用。
在接下来的章节中,我们将详细探讨location指令的语法、匹配规则、优先级以及各种高级应用,帮助读者全面理解和掌握这一强大的Nginx配置工具。
2.location 指令基础
2.1 location 指令的语法
Nginx中的location指令是配置文件中最常用也最重要的指令之一。它定义了如何处理特定的URL请求,使得服务器能够根据不同的请求路径执行不同的操作。location指令的基本语法如下:
location [修饰符] 匹配模式 {
...
}
在这个语法结构中,"修饰符"是可选的,而"匹配模式"则是必须指定的。大括号内包含了当URL匹配成功时要执行的指令集。
修饰符用于定义location的匹配行为,常见的修饰符包括:
“=”:表示精确匹配。如果找到精确匹配,则立即停止搜索。
“^~”:表示如果该符号后面的字符是最佳匹配,则采用该规则,不再进行后续的正则表达式匹配。
“~”:表示区分大小写的正则匹配。
“~*”:表示不区分大小写的正则匹配。如果没有修饰符,则表示前缀匹配。
匹配模式可以是一个字符串,也可以是一个正则表达式。Nginx会根据请求的URI与这个匹配模式进行比较,以决定是否应用该location块中的配置。
以下是一些location指令的实际例子:
location = / {
...
}
这个例子使用了"=“修饰符,表示精确匹配根路径”/"。
location ^~ /images/ {
...
}
这个例子使用了"^~“修饰符,表示如果请求的URI以”/images/"开头,就会使用这个location块的配置,且不再检查其他正则表达式location。
location ~ \.(gif|jpg|png)$ {
...
}
这个例子使用了"~“修饰符,表示对URI进行区分大小写的正则匹配。它会匹配所有以”.gif"、“.jpg"或”.png"结尾的请求。
location /documents/ {
...
}
这个例子没有使用修饰符,表示对"/documents/"路径进行前缀匹配。
在location块内部,我们可以使用各种Nginx指令来定义如何处理匹配的请求。常见的指令包括:
root:指定请求的根目录。
index:指定默认文件。
proxy_pass:将请求转发到另一个服务器。
try_files:按顺序检查文件是否存在。
return:返回特定的HTTP状态码。
例如
location /images/ {
root /data;
try_files $uri $uri/ =404;
}
这个配置表示,对于以"/images/“开头的请求,Nginx会在”/data/images/"目录下查找对应的文件。如果文件不存在,则返回404错误。
理解location指令的语法是配置Nginx服务器的基础。通过灵活运用不同的修饰符和匹配模式,我们可以精确控制Nginx如何处理不同的URL请求,从而实现复杂的Web服务器功能。
2.2 location 指令的匹配规则
Nginx的location指令使用一套复杂而精密的匹配规则来决定如何处理incoming请求。理解这些匹配规则对于正确配置和优化Nginx服务器至关重要。
location指令的匹配过程可以概括为以下几个步骤:
首先,Nginx会检查所有的精确匹配规则(使用"="修饰符的location)。如果找到一个精确匹配,Nginx会立即停止搜索并使用该location块中的配置来处理请求。
如果没有找到精确匹配,Nginx会继续检查前缀匹配规则。在这个阶段,Nginx会记住最长的匹配,并继续搜索。如果遇到一个使用"^~"修饰符的location,且该location是最长匹配,Nginx会立即停止搜索并使用该location。
如果仍然没有找到匹配,或者找到的最长匹配没有"^~"修饰符,Nginx会继续进行正则表达式匹配。正则表达式匹配按照它们在配置文件中出现的顺序进行检查。一旦找到第一个匹配的正则表达式location,Nginx就会停止搜索并使用该location。
如果没有匹配的正则表达式location,Nginx会使用之前记住的最长前缀匹配的location。
这个匹配过程看似复杂,但在实际应用中非常强大和灵活。让我们通过一些具体的例子来深入理解这个过程:
假设我们有以下location配置:
location = / {
# 精确匹配"/"
}
location / {
# 匹配任何以"/"开头的请求
}
location /documents/ {
# 匹配任何以"/documents/"开头的请求
}
location ^~ /images/ {
# 匹配任何以"/images/"开头的请求
}
location ~* \.(gif|jpg|jpeg)$ {
# 匹配任何以gif、jpg或jpeg结尾的请求
}
对于请求/,会精确匹配到第一个location。
对于请求/index.html,会匹配到第二个location。
对于请求/documents/document.html,会匹配到第三个location。
对于请求/images/1.gif,会匹配到第四个location。尽管它也满足最后一个正则表达式location,但由于"^~"修饰符的存在,Nginx会停止在第四个location。
对于请求/documents/1.jpg,会匹配到最后一个location。虽然它也满足第三个location,但正则表达式匹配的优先级更高。
理解这些匹配规则后,我们就可以更好地组织我们的location块。例如,我们可以将更具体的规则放在前面,将更通用的规则放在后面。我们也可以使用"^~"修饰符来确保某些特定的前缀匹配不会被后续的正则表达式匹配覆盖。
此外,在编写location匹配规则时,我们还需要注意以下几点:
路径匹配不包含查询字符串。例如,对于请求/index.html?param=value,location只会尝试匹配/index.html部分。
location中的正则表达式支持捕获组,可以在后续的配置中使用。例如:
location ~ ^/users/(.+)/files/(.+)$ {
add_header X-User $1;
add_header X-File $2;
}
对于请求/users/john/files/document.pdf,这个配置会添加两个响应头:X-User: john和X-File: document.pdf。
Nginx的location匹配是大小写敏感的。如果需要进行大小写不敏感的匹配,可以使用"~*"修饰符。
通过深入理解这些匹配规则,我们可以更好地控制Nginx如何处理不同的请求,从而构建更高效、更灵活的Web服务器配置。
2.3 location 指令的优先级
在Nginx配置中,location指令的优先级是一个关键概念,它决定了当多个location块可能匹配同一个请求时,Nginx将选择哪一个location块来处理该请求。理解这个优先级机制对于正确配置Nginx服务器至关重要。
Nginx的location指令优先级从高到低排序如下:
首先是精确匹配(=)。当Nginx遇到一个与请求URI完全相同的精确匹配location时,它会立即选择该location并停止搜索。这是最高优先级的匹配方式,通常用于处理特定的、明确的请求路径。例如:
location = /login { # 处理登录请求 }
这个location将精确匹配/login路径,而不会匹配/login/或/login.html。
其次是前缀匹配(~)。如果找到一个前缀匹配的location,且该location使用了~修饰符,Nginx会立即停止搜索并选择该location,即使后面可能有更精确的正则表达式匹配。这个修饰符常用于防止正则表达式location覆盖某些特定的前缀匹配。例如:
location ^~ /static/ { # 处理静态文件请求 }
这个location会匹配所有以/static/开头的请求,并且不会被后续的正则表达式location覆盖。
接下来是正则表达式匹配(~ 和 *)。**Nginx**会按照配置文件中正则表达式location出现的顺序进行匹配。一旦找到第一个匹配的正则表达式location,**Nginx**就会停止搜索并使用该location。区分大小写的正则表达式()优先于不区分大小写的正则表达式(~*)。例如:
location ~ \.php$ { # 处理PHP文件请求 } location ~* \.(jpg|jpeg|png|gif)$ { # 处理图片文件请求 }
最后是普通前缀匹配(无修饰符)。如果之前的匹配都未成功,Nginx会选择最长的匹配前缀location。这是最低优先级的匹配方式,通常用作默认处理或作为一个通用的回退选项。例如:
location / { # 处理所有其他请求 }
值得注意的是,在实际配置中,这些不同优先级的location可能会相互影响。例如,考虑以下配置:
location = /api {
# 精确匹配/api
}
location ^~ /api/ {
# 前缀匹配/api/
}
location ~ ^/api/.*\.json$ {
# 正则匹配以.json结尾的/api/请求
}
location /api/ {
# 普通前缀匹配/api/
}
在这个配置中,对于请求/api,会使用第一个location(精确匹配)。
对于请求/api/users,会使用第二个location(^~前缀匹配),即使第三个location(正则匹配)可能也符合条件。
对于请求/api/data.xml,会使用第二个location,而不是第四个location。
理解这种优先级机制可以帮助我们更好地组织Nginx配置,避免潜在的冲突和混淆。
在实际应用中,我们通常会将更具体的规则放在前面,将更通用的规则放在后面。
同时,我们也可以利用不同的修饰符来精确控制Nginx的匹配行为,从而实现复杂的路由和请求处理逻辑。
此外,在处理location优先级时,还需要注意一些细节。例如,正则表达式location的顺序很重要,因为Nginx会使用第一个匹配的正则表达式location。
如果有多个可能匹配的正则表达式location,我们需要仔细考虑它们的顺序。
同时,使用^~修饰符可以有效地防止某些路径被正则表达式location意外匹配。这在处理静态文件或特定的API路径时特别有用。
3.location 匹配修饰符
Nginx的location指令支持多种匹配修饰符,这些修饰符决定了Nginx如何解释和匹配请求的URI。理解这些修饰符的作用和优先级对于正确配置Nginx服务器至关重要。
本节将详细介绍四种主要的location匹配修饰符:精确匹配"=“、前缀匹配”^“、正则匹配”“和”~*",以及普通匹配(无修饰符)。
3.1 精准匹配 =
精确匹配是Nginx location指令中优先级最高的匹配方式。当使用"="修饰符时,Nginx会将请求的URI与指定的模式进行精确比较。如果匹配成功,Nginx将立即停止搜索其他location块,并使用该location的配置来处理请求。
精确匹配通常用于处理特定的、明确的请求路径。例如:。
location = / { # 仅匹配根路径"/" } location = /login { # 仅匹配"/login"路径 }
在这个配置中,第一个location块只会匹配根路径"/“,而不会匹配”/index.html"或任何其他路径。第二个location块只会匹配"/login"路径,而不会匹配"/login/“或”/login.html"。
使用精确匹配可以提高Nginx的处理效率,因为一旦找到匹配,Nginx就不需要继续搜索其他可能的匹配。这对于频繁访问的特定URI特别有用。
3.2 前缀匹配 ^~
前缀匹配使用"^~“修饰符,它的优先级仅次于精确匹配。当Nginx遇到使用”^~"修饰符的location时,如果该location是最长的前缀匹配,Nginx会立即停止搜索并选择该location,即使后面可能存在更精确的正则表达式匹配。
这个修饰符常用于防止正则表达式location覆盖某些特定的前缀匹配。例如:
location ^~ /static/ { # 处理所有以"/static/"开头的请求 }
在这个配置中,所有以"/static/"开头的请求都会被这个location处理,而不会被后续的正则表达式location匹配。这对于处理静态文件特别有用,可以避免不必要的正则表达式匹配,从而提高性能。
3.3 正则匹配 ~ 和 ~*
在 Nginx的location配置中,正则表达式匹配是一种强大而灵活的匹配方式。
它允许我们使用复杂的模式来匹配 URL,从而实现更精细的请求处理。
Nginx提供了两种正则表达式匹配修饰符:~ 和 ~*。
修饰符用于区分大小写的正则表达式匹配。当使用这个修饰符时, Nginx会严格按照大小写来匹配 URL。例如location ~ \.php$ { fastcgi_pass unix:/var/run/php/php7.4-fpm.sock; fastcgi_index index.php; include fastcgi_params; }
这个配置会匹配所有以".php"结尾的URL,但不会匹配".PHP"或".pHp"。这种严格匹配在处理特定文件类型时非常有用,可以确保只有正确的文件扩展名才会被处理。
3.3.1 location引入PHP文件参数解析
1.location ~ .php$ { … }:这个 location 块使用正则表达式匹配所有以 .php 结尾的文件。
2.include snippets/fastcgi-php.conf;:包含一个外部配置文件,通常这个文件包含了处理 PHP 文件所需的 FastCGI 参数。
3.fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;:指定 FastCGI 传递的目标,这里是 PHP-FPM 监听的 Unix Socket 文件。
~* 修饰符用于不区分大小写的正则表达式匹配。使用这个修饰符时,Nginx会忽略大小写差异。例如:
location ~* \.(gif|jpg|jpeg|png|ico)$ { expires 30d; add_header Cache-Control "public, no-transform"; }
这个配置会匹配所有以".gif"、“.jpg”、“.jpeg”、“.png"或”.ico"结尾的URL,不论这些扩展名是大写还是小写。这在处理图片文件时特别有用,因为文件扩展名的大小写可能会有所不同。
正则表达式匹配的优势在于其灵活性。我们可以使用各种正则表达式语法来精确控制匹配行为。例如:
location ~ ^/api/v[0-9]+/ { proxy_pass http://backend; }
这个配置会匹配所有以"/api/v"开头,后面跟着一个或多个数字,再跟着"/"的URL。这可以用来处理不同版本的API请求。
在使用正则表达式匹配时,我们还可以利用捕获组来提取URL中的特定部分。例如:
location ~ ^/users/(\d+)/profile$ { set $user_id $1; proxy_pass http://user_service; proxy_set_header X-User-ID $user_id; }
这个配置会匹配形如"/users/123/profile"的URL,并将用户ID(在这个例子中是"123")捕获到变量$1中。然后,我们可以使用这个变量来设置自定义头部。
需要注意的是,正则表达式匹配在Nginx的location匹配顺序中具有较高的优先级。一旦找到匹配的正则表达式location,Nginx就会停止搜索并使用该location。因此,在配置多个正则表达式location时,我们需要仔细考虑它们的顺序。
此外,过度使用复杂的正则表达式可能会影响Nginx的性能。对于频繁访问的路径,使用前缀匹配或精确匹配可能会更高效。
正则表达式匹配还可以与其他Nginx指令结合使用,以实现更复杂的功能。例如,我们可以结合使用正则表达式location和rewrite指令来实现URL重写:
location ~ ^/old-api/(.*)$ { rewrite ^/old-api/(.*)$ /new-api/$1 last; }
这个配置会将所有以"/old-api/“开头的请求重写为”/new-api/"开头的新URL。
正则表达式匹配(~ 和 ~*)为Nginx的location配置提供了强大的灵活性。通过合理使用这些修饰符,我们可以精确控制Nginx如何处理不同的URL请求,从而实现复杂的路由逻辑和请求处理。
然而,在使用时也需要注意性能影响和配置复杂性,确保正则表达式匹配与其他location配置协调一致,以构建高效、可维护的Nginx服务器配置。
3.3.2 nginx常见正则匹配符号
1:^: 匹配字符串的开始位置;
2:$:匹配字符串的结束位置 ;
3:~ 为区分大小写匹配;
4:~* 为不区分大小写匹配;
5:!~和!~*分别为区分大小写不匹配及不区分大小写不匹配;
6:.* .匹配任意字符,*匹配数量0到正无穷;
7:\. 斜杠用来转义,\.匹配 .;
8:(值1|值2|值3|值4):或匹配模式,例:(jpg|gif|png|bmp)匹配jpg或gif或png或bmp;
9:i不区分大小写
3.3.3 文件及目录匹配
- -f和!-f用来判断是否存在文件;
- -d和!-d用来判断是否存在目录;;
- -e和!-e用来判断是否存在文件或目录;
- -x和!-x用来判断文件是否可执行。
3.4 普通匹配 (无修饰符)
普通匹配是最基本的location匹配方式,它不使用任何修饰符。普通匹配执行前缀匹配,但其优先级最低。如果请求URI与多个普通匹配location相匹配,Nginx会选择最长的匹配。
例如:
location / {
# 匹配所有请求
}
location /api/ {
# 匹配所有以"/api/"开头的请求
}
在这个配置中,对于请求"/api/users",Nginx会选择第二个location,因为它是最长的匹配。对于请求"/index.html",Nginx会选择第一个location。
普通匹配通常用作默认处理或作为一个通用的回退选项。它们常常放在配置文件的末尾,用于处理所有未被其他更具体的location匹配的请求。
理解这些不同的匹配修饰符及其优先级对于正确配置Nginx服务器至关重要。通过合理使用这些修饰符,我们可以创建灵活、高效的Nginx配置,精确控制如何处理不同的HTTP请求。在实际应用中,我们通常会结合使用多种匹配方式,以满足复杂的路由和请求处理需求。
3.5 提醒:location / 和 location = / 不同
千万需要注意,在 Nginx 配置中,location /
和 location = /
虽然看起来相似,但它们的行为有着重要的区别:
匹配范围:
location / 使用前缀匹配,会匹配所有以 / 开头的请求,包括 /index.html、/about、/images/logo.png 等。
location = / 使用精确匹配,只会匹配根路径 /,不会匹配其他路径。
优先级:location = / 的优先级高于 location /。
当请求为根路径 / 时,location = / 会被优先选择。
性能影响:对于根路径请求,location = / 通常会有更好的性能,因为 Nginx 可以立即停止搜索其他 location 块。
常见用途:location / 常用于设置默认的处理规则或作为回退选项。
location = / 常用于专门处理根路径请求,如设置网站首页。
示例配置:
location = / {
# 只处理根路径请求
try_files /index.html =404;
}
location / {
# 处理所有其他请求
try_files $uri $uri/ /index.html;
}
在这个配置中,根路径请求会由第一个 location 块处理,而所有其他请求会由第二个 location 块处理。理解这两种 location 指令的区别可以帮助你更精确地控制 Nginx 的路由行为,优化服务器性能。
4.location 嵌套
在Nginx配置中,location指令不仅可以独立使用,还可以进行嵌套。location嵌套是一种强大的功能,它允许我们创建更复杂、更精细的URL匹配和处理逻辑。通过合理使用location嵌套,我们可以实现更灵活的请求路由和更高效的配置管理。
4.1 嵌套的基本概念
location嵌套指的是在一个location块内部再定义其他location块。这种嵌套结构使得我们可以为某个URL路径定义一般规则,然后在其内部为特定的子路径定义更具体的规则。
嵌套的location遵循与外层location相同的匹配规则和优先级。当一个请求匹配到外层location时,Nginx会继续在其内部的嵌套location中寻找更精确的匹配。
基本的嵌套结构如下:
location /parent/ { # 父级location的配置 location /parent/child/ { # 子级location的配置 } }
在这个例子中,对于以
/parent/
开头的请求,Nginx首先会应用父级location的配置。如果请求的URL进一步匹配/parent/child/
,那么子级location的配置将会被应用,并覆盖父级location中的相关设置。
4.2 嵌套的使用场景
4.2.1 细化静态文件处理
我们可以在处理静态文件的location中嵌套其他location,为不同类型的文件设置特定的处理规则。例如:
location /static/ { root /var/www/static; expires 30d; location ~* \.(css|js)$ { expires 7d; } location ~* \.(jpg|jpeg|png|gif)$ { expires 90d; } }
在这个配置中,所有静态文件默认有30天的过期时间,但CSS和JS文件的过期时间被设置为7天,而图片文件的过期时间则被设置为90天。
4.2.2 精细化api路由
对于复杂的API结构,我们可以使用嵌套location来创建更精确的路由规则。例如:
location /api/ { proxy_pass http://backend; location /api/v1/ { proxy_pass http://backend-v1; } location /api/v2/ { proxy_pass http://backend-v2; } }
这个配置将所有API请求代理到后端服务器,但对于v1和v2版本的API,分别代理到不同的后端服务器。
4.2.3 错误处理
我们可以在location中嵌套其他location来处理特定的错误情况。例如:
location / { try_files $uri $uri/ =404; location = /404.html { internal; root /var/www/error_pages; } }
这个配置在主location中定义了一个嵌套的location来处理404错误,将其指向一个特定的错误页面
参数解析
1.error_page 404 /404.html;:定义当发生 404 错误时,Nginx 应该返回哪个页面。
2.location = /404.html { … }:这个 location 块精确匹配 /404.html 路径。
3.root /var/www/html;:设置 /404.html 文件的根目录,因为这是一个内部重定向,所以需要明确指定根目录。
4.internal;:标记这个 location 块只能从内部重定向访问,而不能直接通过外部请求访问。
5.location 与其他指令的配合
Nginx的location指令虽然强大,但它真正发挥作用是在与其他指令配合使用时。通过与其他指令的组合,我们可以实现更复杂的Web服务器功能,如反向代理、URL重写、文件查找等。本章将详细探讨location指令与三个常用指令的配合使用:proxy_pass、rewrite和try_files。
5.1 与proxy_pass 配合使用
proxy_pass指令是Nginx中用于设置代理服务器的指令。当与location指令配合使用时,它可以将匹配特定URL模式的请求转发到其他服务器。这种配置在实现反向代理、负载均衡等场景中非常有用。
基本语法
location /path {
proxy_pass http://backend;
}
在这个配置中,所有匹配/path
的请求都会被转发到http://backend
服务器。
proxy_pass指令的行为会因为是否在URL末尾添加斜杠而有所不同。例如:
location /api/ { proxy_pass http://backend/; }
在这个配置中,请求
/api/users
会被代理到http://backend/users
。
而如果配置如下:
location /api/ { proxy_pass http://backend; }
请求
/api/users
会被代理到http://backend/api/users
。
我们还可以在proxy_pass中使用变量:
location ~ ^/api/(?<version>v\d+)/ { proxy_pass http://backend/$version$request_uri; }
这个配置会将请求
/api/v1/users
代理到http://backend/v1/api/v1/users
。
在使用proxy_pass时,我们通常还会设置一些额外的代理相关指令,如:
location /api/ {
proxy_pass http://backend;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
这些额外的指令可以确保后端服务器接收到正确的请求头信息。
5.1.1 proxy_pass 命令参数解析
1.proxy_pass http://backend_server;:将所有匹配的请求代理到名为 backend_server 的后端服务器。通常,backend_server 需要在 http 或 upstream 块中定义。
2.proxy_set_header Host $host;:设置代理请求的 Host 头部为客户端的原始请求中的 Host 值。
3.proxy_set_header X-Real-IP $remote_addr;:设置 X-Real-IP 头部为客户端的 IP 地址。
4.proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;:设置 X-Forwarded-For 头部,这是一个用于标识请求来源的链式头部,可以追踪请求穿过多个代理的路径。
5.proxy_set_header X-Forwarded-Proto $scheme;:设置 X-Forwarded-Proto 头部为请求使用的协议(http 或 https)。
6.proxy_pass http://backend_server; 转发到后端服务器,不带 URI
7.proxy_pass http://backend_server/anotherpath/;转发到后端服务器,并带上 URI
8.proxy_pass http://$host:$server_port;使用变量作为代理服务器地址
9.proxy_method GET;转发时保持请求方法
10.proxy_connect_timeout 10s;设置代理连接的超时时间
11.proxy_read_timeout 10s;设置代理读取响应的超时时间:
5.2 与rewrite 配合使用
rewrite指令用于修改请求URI。当与location指令配合使用时,它可以在将请求发送到新位置之前对URI进行重写。这在URL重定向、规范化URL等场景中非常有用。
基本语法如下:
location /old-path {
rewrite ^/old-path(.*)$ /new-path$1 last;
}
在这个配置中,所有以/old-path
开头的请求都会被重写为以/new-path
开头。
rewrite指令的最后一个参数(如last、break、redirect、permanent)决定了重写后的行为:
"last"表示重写后的URI将重新进行位置匹配。
"break"表示重写后停止处理后续rewrite指令。
"redirect"表示返回302临时重定向。
"permanent"表示返回301永久重定向。
例如,实现URL规范化:
location / { rewrite ^([^.]*[^/])$ $1/ permanent; }
这个配置会将不以斜杠结尾的URL重定向到以斜杠结尾的URL。
我们还可以结合正则表达式捕获组来实现更复杂的重写:
location ~* ^/blog/(\d{4})/(\d{2})/(\d{2})/(.*)$ { rewrite ^/blog/(\d{4})/(\d{2})/(\d{2})/(.*)$ /posts/$1-$2-$3-$4 last; }
这个配置会将形如
/blog/2023/05/20/my-post
的URL重写为/posts/2023-05-20-my-post
。
5.3 与try_files 配合使用
try_files指令用于按顺序检查文件是否存在,并使用第一个找到的文件进行请求处理。如果所有指定的文件都不存在,它会使用最后一个参数作为回退。
这个指令在处理静态文件和实现URL回退机制时非常有用。
基本语法如下:
location / {
try_files $uri $uri/ /index.html;
}
在这个配置中,Nginx首先尝试提供与请求URI匹配的文件。如果文件不存在,它会查找同名目录。如果目录也不存在,它会回退到提供/index.html
文件。
try_files指令对于实现单页应用(SPA)的路由非常有用:
location / { try_files $uri $uri/ @backend; } location @backend { proxy_pass http://backend; }
在这个配置中,如果请求的文件不存在,Nginx会将请求代理到后端服务器。
try_files还可以用于实现简单的负载均衡:
location / { try_files /app1$uri /app2$uri @proxy; } location @proxy { proxy_pass http://backend; }
这个配置首先尝试从两个不同的应用目录提供文件,如果都失败了,则将请求代理到后端服务器。
通过将location指令与proxy_pass、rewrite和try_files等指令配合使用,我们可以构建出功能强大、灵活的Nginx配置。这些组合使得Nginx能够处理各种复杂的Web服务场景,从简单的静态文件服务到复杂的反向代理和URL重写。在实际应用中,我们常常需要根据具体需求,灵活运用这些指令的组合,以实现所需的服务器行为。
6.location 的高级应用
Nginx的location指令不仅可以用于基本的URL匹配和请求处理,还可以应用于多种高级场景。本章将深入探讨location在静态文件处理、反向代理和URL重写这三个高级应用中的使用方法和最佳实践。
6.1 location 用于静态文件处理
在Web服务器配置中,高效处理静态文件是一个常见且重要的需求。Nginx的location指令可以很好地满足这一需求,通过合理配置,我们可以实现高性能的静态文件服务。
首先,我们可以使用location指令来匹配特定类型的静态文件:
location ~* \.(jpg|jpeg|png|gif|ico|css|js)$ { root /var/www/static; expires 30d; add_header Cache-Control "public, no-transform"; }
这个配置使用正则表达式匹配常见的静态文件类型。对于匹配的请求,Nginx会在/var/www/static目录中查找文件。同时,我们设置了30天的过期时间,并添加了缓存控制头,以提高客户端缓存效率。
对于不同类型的静态文件,我们可能需要不同的处理策略。例如,我们可以为CSS和JavaScript文件设置不同的缓存策略:
location ~* \.css$ { root /var/www/static; expires 7d; add_header Cache-Control "public, must-revalidate"; } location ~* \.js$ { root /var/www/static; expires 1d; add_header Cache-Control "public, must-revalidate"; }
这里,我们为CSS文件设置了7天的过期时间,而JavaScript文件则设置为1天。这种差异化的策略可以根据文件更新频率来优化缓存效果。
在处理静态文件时,我们还可以使用try_files指令来实现更灵活的文件查找逻辑:
location /images/ { root /var/www/static; try_files $uri $uri/ /images/default.jpg; }
这个配置首先尝试提供请求的文件,如果文件不存在,则查找同名目录,最后回退到默认图片。这种方法可以有效处理文件缺失的情况。
对于大文件的处理,我们可以使用sendfile和tcp_nopush指令来优化传输:
location /downloads/ { root /var/www/files; sendfile on; tcp_nopush on; tcp_nodelay on; keepalive_timeout 65; }
这些指令可以显著提高大文件传输的效率,特别是在处理视频或大型文档下载时。
6.2 location 用于反向代理
反向代理是Nginx的一个重要应用场景,而location指令在配置反向代理时扮演着关键角色。通过location,我们可以精确控制哪些请求应该被代理,以及如何代理这些请求。
基本的反向代理配置如下:
location /api/ {
proxy_pass http://backend_server;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
这个配置将所有以/api/
开头的请求代理到backend_server
。同时,我们设置了一些重要的代理头,以确保后端服务器能够获得正确的客户端信息。
对于不同的API版本,我们可以使用不同的location块来路由请求:
location /api/v1/ { proxy_pass http://backend_v1; } location /api/v2/ { proxy_pass http://backend_v2; }
这种配置允许我们将不同版本的API请求路由到不同的后端服务器,便于实现API的版本控制。
在某些情况下,我们可能需要修改代理请求的路径。这可以通过在proxy_pass指令中指定路径来实现:
location /old_api/ { proxy_pass http://backend/new_api/; }
这个配置会将
/old_api/users
的请求代理到http://backend/new_api/users
,实现了路径的重写。
对于WebSocket连接,我们需要额外的配置来支持长连接:
location /ws/ { proxy_pass http://websocket_server; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; }
这个配置允许WebSocket连接通过Nginx代理到后端的WebSocket服务器。
6.2.1 长连接和短连接详解
在nginx反向代理多台服务器时,会产生大量短连接,大致请求路径为client -> nginx -> web 服务器,由于每台机器上混布了多个web服务并通过nginx反向代理统一分发请求,在服务升级的时候经常出现端口被占用的情况。系统会经常存在过多的time_wait状态。
统计命令如下
netstat (性能一般)
netstat -n | awk '/^tcp/ {++state[$NF]} END {for(key in state) print key,"\t",state[key]}'
ss命令(性能较高)
ss -s
显示
Total: 4122 (kernel 0)
TCP: 37241 (estab 3157, closed 33193, orphaned 858, synrecv 0, timewait 33176/0), ports 0
Transport Total IP IPv6
* 0 - -
RAW 1 1 0
UDP 4 4 0
TCP 4048 4048 0
INET 4053 4053 0
FRAG 0 0 0
time_wait状态的产生机制
IME_WAIT状态是在tcp断开链接时产生的,因为TCP连接是双向的,所以在关闭连接的时候,两个方向各自都需要关闭。先发FIN包的一方执行的是主动关闭;后发FIN包的一方执行的是被动关闭。主动关闭的一方会进入TIME_WAIT状态,并且在此状态停留两倍的MSL时长
MSL指的是报文段的最大生存时间,如果报文段在网络活动了MSL时间,还没有被接收,那么会被丢弃。关于MSL的大小,RFC 793协议中给出的建议是两分钟,不过实际上不同的操作系统可能有不同的设置,以Linux为例,通常是半分钟,两倍的MSL就是一分钟,也就是60秒,并且这个数值是硬编码在内核中的,也就是说除非你重新编译内核,否则没法修改它。
TIME_WAIT状态存在的必要性。虽然双方都同意关闭连接了,而且握手的4个报文也都协调和发送完毕,按理可以直接回到CLOSED状态(就好比从SYN_SEND状态到ESTABLISH状态那样);但是因为我们必须要假想网络是不可靠的,你无法保证你最后发送的ACK报文会一定被对方收到,比如丢包或者延迟到达,因此对方处于LAST_ACK状态下的SOCKET可能会因为超时未收到ACK报文,而重发FIN报文,所以这个TIME_WAIT状态的作用就是用来重发可能丢失的ACK报文,并保证于此。
简单说timewait之所以等待2MSL的时长,是为了避免因为网络丢包或者网络延迟而造成的tcp传输不可靠,而这个time_wait状态则可以最大限度的提升网络传输的可靠性。
TIME_WAIT状态过多的危害
TIME_WAIT状态是TCP链接中正常产生的一个状态,但凡事都有利弊,TIME_WAIT状态过多会存在以下的问题:
(1)在socket的TIME_WAIT状态结束之前,该socket所占用的本地端口号将一直无法释放
(2)在高并发(每秒几万qps)并且采用短连接方式进行交互的系统中运行一段时间后,系统中就会存在大量的time_wait状态,如果time_wait状态把系统所有可用端口 都占完了且尚未被系统回收时,就会出现无法向服务端创建新的socket连接的情况。此时系统几乎停转,任何链接都不能建立。
(3)大量的time_wait状态也会系统一定的fd,内存和cpu资源,当然这个量一般比较小,并不是主要危害
优化time_wait问题
方式一:调整系统内核参数
修改/etc/sysctl.conf文件,一般涉及下面的几个参数:
net.ipv4.tcp_syncookies = 1 表示开启SYN Cookies。当出现SYN等待队列溢出时,启用cookies来处理,可防范少量SYN攻击,默认为0,表示关闭; net.ipv4.tcp_tw_reuse = 1 表示开启重用。允许将TIME-WAIT sockets重新用于新的TCP连接,默认为0,表示关闭; net.ipv4.tcp_tw_recycle = 1 表示开启TCP连接中TIME-WAIT sockets的快速回收,默认为0,表示关闭。 net.ipv4.tcp_fin_timeout = 修改系统默认的 TIMEOUT 时间 net.ipv4.tcp_max_tw_buckets = 5000 表示系统同时保持TIME_WAIT套接字的最大数量,(默认是18000). 当TIME_WAIT连接数量达到给定的值时,所有的TIME_WAIT连接会被立刻清除,并打印警告信息。但这种粗暴的清理掉所有的连接,意味着有些连接并没有成功等待2MSL,就会造成通讯异常。一般不建议调整 net.ipv4.tcp_timestamps = 1(默认即为1)60s内同一源ip主机的socket connect请求中的timestamp必须是递增的。也就是说服务器打开了 tcp_tw_reccycle了,就会检查时间戳,如果对方发来的包的时间戳是乱跳的或者说时间戳是滞后的,那么服务器就会丢掉不回包,现在很多公司都用LVS做负载均衡,通常是前面一台LVS,后面多台后端服务器,这其实就是NAT,当请求到达LVS后,它修改地址数据后便转发给后端服务器,但不会修改时间戳数据,对于后端服务器来说,请求的源地址就是LVS的地址,加上端口会复用,所以从后端服务器的角度看,原本不同客户端的请求经过LVS的转发,就可能会被认为是同一个连接,加之不同客户端的时间可能不一致,所以就会出现时间戳错乱的现象,于是后面的数据包就被丢弃了,具体的表现通常是是客户端明明发送的SYN,但服务端就是不响应ACK,还可以通过下面命令来确认数据包不断被丢弃的现象,所以根据情况使用 其他优化: net.ipv4.ip_local_port_range = 1024 65535 增加可用端口范围,让系统拥有的更多的端口来建立链接,这里有个问题需要注意,对于这个设置系统就会从1025~65535这个范围内随机分配端口来用于连接,如果我们服务的使用端口比如8080刚好在这个范围之内,在升级服务期间,可能会出现8080端口被其他随机分配的链接给占用掉,这个原因也是文章开头提到的端口被占用的另一个原因 net.ipv4.ip_local_reserved_ports = 7005,8001-8100 针对上面的问题,我们可以设置这个参数来告诉系统给我们预留哪些端口,不可以用于自动分配。
优化完内核参数后,可以执行sysctl -p命令,来激活上面的设置永久生效
方式二:调整短链接为长链接
短连接和长连接工作方式的区别:
短连接 连接->传输数据->关闭连接 HTTP是无状态的,浏览器和服务器每进行一次HTTP操作,就建立一次连接,但任务结束就中断连接。 也可以这样说:短连接是指SOCKET连接后发送后接收完数据后马上断开连接。
长连接 连接->传输数据->保持连接 -> 传输数据-> 。。。->关闭连接。 长连接指建立SOCKET连接后不管是否使用都保持连接,但安全性较差。
从区别上可以看出,长连接比短连接从根本上减少了关闭连接的次数,减少了TIME_WAIT状态的产生数量,在高并发的系统中,这种方式的改动非常有效果,可以明显减少系统TIME_WAIT的数量。
当使用nginx作为反向代理时,为了支持长连接,需要做到两点:
从client到nginx的连接是长连接
从nginx到server的连接是长连接
1、保持和client的长连接:
默认情况下,nginx已经自动开启了对client连接的keep alive支持(同时client发送的HTTP请求要求keep alive)。一般场景可以直接使用,但是对于一些比较特殊的场景,还是有必要调整个别参数(keepalive_timeout和keepalive_requests)。
http { keepalive_timeout 120s 120s; keepalive_requests 10000; }
keepalive_timeout: 第一个参数:设置keep-alive客户端连接在服务器端保持开启的超时值(默认75s);值为0会禁用keep-alive客户端连接;
第二个参数:可选、在响应的header域中设置一个值“Keep-Alive: timeout=time”;通常可以不用设置;
keepalive_requests:keepalive_requests指令用于设置一个keep-alive连接上可以服务的请求的最大数量,当最大请求数量达到时,连接被关闭。默认是100。这个参数的真实含义,是指一个keep alive建立之后,nginx就会为这个连接设置一个计数器,记录这个keep alive的长连接上已经接收并处理的客户端请求的数量。如果达到这个参数设置的最大值时,则nginx会强行关闭这个长连接,逼迫客户端不得不重新建立新的长连接。
大多数情况下当QPS(每秒请求数)不是很高时,默认值100凑合够用。但是,对于一些QPS比较高(比如超过10000QPS,甚至达到30000,50000甚至更高) 的场景,默认的100就显得太低。
简单计算一下,QPS=10000时,客户端每秒发送10000个请求(通常建立有多个长连接),每个连接只能最多跑100次请求,意味着平均每秒钟就会有100个长连接因此被nginx关闭。同样意味着为了保持QPS,客户端不得不每秒中重新新建100个连接。因此,就会发现有大量的TIME_WAIT的socket连接(即使此时keep alive已经在client和nginx之间生效)。因此对于QPS较高的场景,非常有必要加大这个参数,以避免出现大量连接被生成再抛弃的情况,减少TIME_WAIT。
2、保持和server的长连接
为了让nginx和后端server(nginx称为upstream)之间保持长连接,典型设置如下:(默认nginx访问后端都是用的短连接(HTTP1.0),一个请求来了,Nginx 新开一个端口和后端建立连接,后端执行完毕后主动关闭该链接)Nginx 1.1以上版本的upstream已经支持keep-alive的,所以我们可以开启Nginx proxy的keep-alive来减少tcp连接:
upstream http_backend { server 127.0.0.1:8080; keepalive 1000;//设置nginx到upstream服务器的空闲keepalive连接的最大数量 } server { ... location /http/ { proxy_pass http://http_backend; proxy_http_version 1.1;//开启长链接 proxy_set_header Connection ""; ... } }
HTTP协议中对长连接的支持是从1.1版本之后才有的,因此最好通过proxy_http_version指令设置为"1.1",而"Connection" header应该被清理。清理的意思,是清理从client过来的http header,因为即使是client和nginx之间是短连接,nginx和upstream之间也是可以开启长连接的。这种情况下必须清理来自client请求中的"Connection" header。但这个地方
需要注意如果有一些认证鉴权的cookie或者session信息在head里面,不建议开启此选项,或者对需要保留的header要保存下来,否则这些信息可能会丢掉从而发不到上游upstream的服务器上。
四次握手示例
nginx 设置header头大小nginx默认的header长度上限是4k,如果超过了这个值 nginx会直接返回400错误
可以通过以下2个参数来调整nginx的header上限
client_header_buffer_size 16k;
large_client_header_buffers 4 16k;
对nginx处理header时的方法:
- 先处理请求的request_line,之后才是request_header。
- 这两者的buffer分配策略相同。
- 先根据client_header_buffer_size配置的值分配一个buffer,如果分配的buffer无法容纳 request_line/request_header,那么就会再次根据large_client_header_buffers配置的参数分配large_buffer,如果large_buffer还是无法容纳,那么就会返回414(处理request_line)/400(处理request_header)错误。
- 如果你的请求中的header都很大,那么应该使用client_header_buffer_size,这样能减少一次内存分配。
- 如果你的请求中只有少量请求header很大,那么应该使用large_client_header_buffers,因为这样就仅需在处理大header时才会分配更多的空间,从而减少无谓的内存空间浪费。
针对get请求,解决请求串过长的问题
对get请求,我们可以通过修改另外两个配置来解决请求串超长的问题:
client_header_buffer_size语法:
client_header_buffer_size size默认值:1k
使用字段:http, server
这个指令指定客户端请求的http头部缓冲区大小绝大多数情况下一个头部请求的大小不会大于1k
不过如果有来自于wap客户端的较大的cookie它可能会大于1k,Nginx将分配给它一个更大的缓冲区。
这个值可以在large_client_header_buffers里面设置。
large_client_header_buffers语法:
large_client_header_buffers number size
默认值:large_client_header_buffers 4 4k/8k
使用字段:http, server指令指定客户端请求的一些比较大的头文件到缓冲区的最大值。
如果一个请求的URI大小超过这个值,服务器将返回一个"Request URI too large" (414)。
同样,如果一个请求的头部字段大于这个值,服务器将返回"Bad request" (400)。
缓冲区根据需求的不同是分开的。默认一个缓冲区大小为操作系统中分页文件大小,通常是4k或8k,
如果一个连接请求将状态转换为keep-alive,这个缓冲区将被释放。
GET提交,请求的数据会附在URL之后
6.3 location 用于URL重写
URL重写是Web服务器中的一个常见需求,可以用于实现URL规范化、重定向旧地址、创建更友好的URL等。
Nginx的location指令结合rewrite指令可以轻松实现这些功能。
基本的URL重写配置如下:
location /old-page.html { rewrite ^/old-page\.html$ /new-page.html permanent; }
这个配置将对
/old-page.html
的请求永久重定向到/new-page.html
。
对于更复杂的重写需求,我们可以使用正则表达式和捕获组:
location ~* ^/blog/(\d{4})/(\d{2})/(\d{2})/(.+)$ { rewrite ^/blog/(\d{4})/(\d{2})/(\d{2})/(.+)$ /posts/$1-$2-$3-$4.html last; }
这个配置将形如
/blog/2023/05/20/my-post
的URL重写为/posts/2023-05-20-my-post.html
。
在某些情况下,我们可能需要根据请求参数来进行重写:
location / { if ($args ~* ^id=(\d+)$) { set $id $1; rewrite ^/$ /items/$id? last; } }
这个配置将带有
id
参数的根路径请求重写为/items/{id}
形式的URL。
对于需要保留原始查询字符串的情况,我们可以使用
$is_args
和$args
变量:location /search { rewrite ^/search$ /new-search$is_args$args? last; }
这个配置将
/search
的请求重写为/new-search
,同时保留原始的查询字符串。
在进行URL重写时,我们还需要注意避免重写循环。使用last标志而不是break可以帮助防止这种情况:
location /loop { rewrite ^/loop$ /page1 last; } location /page1 { rewrite ^/page1$ /page2 last; } location /page2 { return 200 "Final destination"; }
在这个例子中,请求会依次经过/loop、/page1、/page2,最后在/page2处停止并返回响应。
通过这些高级应用,我们可以看到Nginx的location指令在静态文件处理、反向代理和URL重写等场景中的强大功能。合理利用这些功能,可以构建出高效、灵活的Web服务器配置,满足各种复杂的需求。在实际应用中,我们需要根据具体场景选择合适的配置方式,并注意性能和安全性的平衡。
6.3.1 限流控制
Nginx 提供了强大的限流功能,通过 ngx_http_limit_req_module 模块来限制单位时间内客户端的请求数量,防止服务器因过多请求而过载。
配置示例
首先在 http 区块内声明一个限流区域,并指定其共享内存大小及最大请求速率:
http {
limit_req_zone $binary_remote_addr zone=traffic_control:10m rate=10r/s;
server {
listen 80;
location / {
limit_req zone=traffic_control burst=20 nodelay;
proxy_pass http://backend_servers;
}
}
}
参数解析:
limit_req_zone定义了一个名为 traffic_control 的限流区域,共享内存大小为 10MB,最大请求速率为每秒 10 个请求。
limit_req 应用了上述区域,burst=20 允许短时间内的请求爆发,nodelay 表示超出限速的请求立即返回错误。
6.3.2 nginx服务器组模块
nginx的http代理是七层代理,对应的它的负载均衡也是做的七层负载。现在我们先使用stream模块组做四层负载。
服务器组模块全名ngx_http_upstream_module模块,它可以用于定义可由
proxy_pass
fastcgi_pass
uwsgi_pass
scgi_pass
memcached_pass
grpc_pass
指令引用的服务器组
upstream模块本身只能在http模块下进行配置
服务器组模块相关变量
$upstream_addr
保留IP地址和端口,或上游服务器的UNIX域套接字的路径。如果在请求处理期间联系了多个服务器,则它们的地址用逗号分隔。
如果发生从一个服务器组到另一个服务器组的内部重定向,由X-Accel-Redirect 或 error_page发起,则来自服务器地址用逗号分隔。如果无法选择服务器,则该变量将保留服务器组的名称。
$upstream_bytes_received
从上游服务器(1.11.4)接收的字节数。来自多个连接的值由逗号和冒号分隔
$upstream_bytes_sent
发送到上游服务器(1.15.8)的字节数。来自多个连接的值由逗号和冒号分隔。
$upstream_cache_status
保持访问响应缓存的状态(0.8.3)。状态可以是“MISS”、“BYPASS”、“EXPIRED”、“STALE”、“UPDATING”、“REVALIDATED”或“HIT”。
$upstream_connect_time
保持与上游服务器建立的时间(1.9.1);时间以毫秒为单位保存。在SSL的情况下,包括花在握手上的时间。连接的时间由逗号和冒号分隔
$upstream_cookie_[name]
上游服务器在“Set-Cookie”响应头字段(1.7.1)中发送的具有指定名称的cookie。仅保存来自最后一个服务器响应的cookie。
$upstream_header_time
保持从上游服务器(1.7.10)接收响应头所花费的时间,时间以毫秒为单位保持。多个响应的时间由逗号和冒号分隔
$upstream_http_[name]
保留服务器响应头字段。例如,“Server”响应头字段可通过
$upstream_http_server
变量获得。将头域名称转换为变量名称的规则与以“$http_”前缀开头的变量相同,仅保存最后一个服务器响应的标头字段。
$upstream_queue_time
保持请求在上游队列中花费的时间(1.13.9);时间以毫秒为单位保存。多个响应的时间由逗号和冒号分隔。商业版提供该变量
$upstream_response_length
保持从上游服务器获得的响应长度(0.7.27);长度以字节为单位。几个响应的长度由逗号和冒号分隔
$upstream_response_time
保持从上游服务器接收响应所花费的时间;时间以毫秒为单位保存。多个响应时间由逗号和冒号分隔
$upstream_status
保留从上游服务器获得的响应的状态码。几个响应的状态代码由逗号和冒号分隔
$upstream_trailer_[name]
保留从上游服务器(1.13.10)获得的响应末尾字段
使用log_farmat记录这些变量信息 查看
生成的日志
假如其中一个服务器挂掉,将8098端口修改 日志如下
轮询代8098时,日志在upstream_addr记录了两个IP地址,由后面的服务器继续提供服务。
配置指令
upstream
定义一组服务器
upstream name {...}
只能定义在http模块中,服务器可以监听不同的端口。此外,侦听TCP和unix域套接字的服务器可以混合使用。
默认情况下,请求使用加权循环平衡方法在服务器之间分配。如果在与服务器通信期间发生错误,请求将被传递到下一个服务器,依此类推,直到尝试所有正常运行的服务器。如果无法从任何服务器获得成功响应,则客户端将接收到与最后一个服务器通信的结果。
server
定义服务器的地址和其他参数
server address [parameters];
这个地址可以指定为域名或ip地址,带有可选端口,或指定为“unix:”前缀指定的UNIX域套接字路径。
如果未指定端口,则使用端口80.解析为多个IP地址的域名一次定义多个服务器
可以定义以下参数
weight=number
设置服务器的权重,默认为1
max_fails_number
设置在fail_timeout参数设置的持续时间与服务器通信的不成功尝试次数,以考虑服务器在fail_timeout参数设置的持续时间内不可用。默认情况下,不成功的尝试次数设置为1。
零值禁用尝试记录。
被认为不成功的尝试由proxy_next_upstream、fastcgi_next_upstream、uwsgi_next_upstream、scgi_next_upstream、memcached_next_upstream和grpc_next_upstream指令定义。
fail_timeout=time
与服务器通信的指定次数的不成功尝试碰巧认为服务器不可用的时间;以及服务器将被视为不可用的时间段。默认情况下,该参数设置为10秒
backup
将服务器标记为备份服务器。当主服务器不可用时,它将被传递请求。该参数不能与hash、ip_hash、random负载均衡方法一起使用
down
将服务器标记为永久不可用
先测试权重
测试的结果本地80端口出现次数明显增多,8098次之。总体来说,weight设置的值越大,出现的频率越高。
接下测试down和backup
因为本地down掉,8098被用作备用,只有在主服务器挂掉才会被启用请求。只会返回89服务器内容。
这些参数可以一起使用 如下
hash
使用基于散列键值来进行hash操作的负载均衡方法
hash key [consistent];
这个键可以包含文本、变量及其组合。请注意,从组中添加或删除服务器可能会导致将大部分密钥重新映射到不同的服务器。该方法与Cache::Memcached Perl库兼容。
如果指定了consistent参数,则将使用ketama一致哈希方法。该方法确保在将服务器添加到组或从组中删除时,只有少数密钥将重新映射到不同的服务器。这有助于为缓存服务器实现更高的缓存命中率。该方法与将ketama_points参数设置为160的Cache::Memcached::Fast Perl库兼容。
这个可以做URI定位的负载均衡,通过 $uri 变量来实现不同URI访问到不同的后端主机上
注意 :这个是改变均衡策略,使用它时如果哈希条件不存在,会走轮询;如果条件成功,就走hash。
如
测试结果,如果是相同的uri,就一直走同一台后端主机,可以用不同的uri测试
可以看到测试结果,前面两个都是走89服务器的,最后一个是走到88机的80端口
ip_hash
指定组应基于客户端ip地址在服务器之间分配请求
ip_hash;
客户端IPv4地址或整个IPv6地址的前三个八位字节用作散列密钥。该方法确保来自同一客户端的请求将始终传递到同一台服务器,除非该服务器不可用。在后一种情况下,客户端请求将被传递到另一台服务器。很可能,它也将始终是同一台服务器。
从版本1.3.2和1.2.2开始支持IPv6地址。在1.3.1和1.2.2版本之前,无法使用ip_hash负载均衡方法为服务器指定权重。
如果需要临时删除其中一台服务器,则应使用down参数对其进行标记,以保留客户端IP地址的当前散列
这是另外一个均衡策略,可以有效解决session问题。相同的客户端ip会走到同一台服务器上。当然这只是最简单的一个方案,最流行的是直接使用外部存储,如redis来保存session,不管使用何种均衡策略,redis不变就行。
如下
进行测试,日志如下
keepalive
激活缓存以连接到上游服务器
keepalive connections;
连接参数设置保留在每个工作进程缓存中的上游服务器的最大空闲保活连接数。当超过这个数字时,最近最少使用的连接将被关闭。
特别注意的是:keepalive指令不限制nginx工作进程可以打开的上游服务器的连接总数。连接参数应该设置为一个足够小的数字,以便上游服务器也可以处理新的传入连接。
当使用默认循环方法意外的负载均衡方法时,需要在keepalive指令之前激活它们。
对于http,proxy_http_version 指令应设置为“1.1”,并且清除“Connection”标字头字段。
或者有需要传递给下个服务器信息,通过变量将信息提取出来传递
亦或者,可以通过将“Connection:Keep-Alive”标字头传递给上游服务器来使用HTTP/1.0持久连接,但不建议使用此方法。
对于FastCGI服务器,需要设置fastcgi_keep_conn 才能使用keepalive 连接正常工作。scgi和 uwsgi协议没有保持连接的概念。
测试如下
使用Jmeter 或者ab工具 进行压测 不使用长连接的话 查看89服务器连接数量
在访问的时候建立了3千多个连接
使用长连接
只有23个,效果还是不错的
keepalive_requests
设置可以通过一个keepalive连接服务的最大请求数
keepalive_requests number;
默认值1000,在发出最大请求数后,连接将关闭。定期关闭连接对于释放每个连接的内存分配时必要的。因此,使用过高的最大请求书可能会导致内存使用过多,不推荐使用。在1.19.10版本之前,默认值为100。
keepalive_time
限制通过一个保活连接处理请求的最长时间
keepalive_time time;
默认值60s,达到这个时间后,连接在后续请求处理后关闭。
keepalive_timeout
设置一个超过时间,在此期间与上游服务器的空闲保活连接将保持打开状态
keepalive_timeout timeout;
默认值 60s。
last_conn
指定组应使用最少活动连接数的服务器,同时考虑服务器权重
last_conn;
如果有多个这样的服务器,则使用加权循环平衡方法依次尝试它们。
这个均衡侧率时根据哪个服务器建立的连接最少就使用哪个服务器来进行连接的。可以达到效果是保证所有的后端服务器的连接数均衡。不会有服务器承担特别重的任务,其他服务器又很清闲。
random
指定组应使用负载平衡方法,其中将请求传递到随机选择的服务器,同时考虑服务器的权重。
random [two [method]];
可选的two参数指示nginx随机选择两个服务器,然后使用指定的方法选择一个服务器。默认方法是minimum_conn,它将请求传递给活动连接数最少的服务器。
least_time 方法将请求传递给平均响应时间最短且活动连接数最少的服务器。如果指定了minimum_time=header,则使用接收响应头的时间。如果指定了minimum_time=last_byte,则使用接收完整响应的时间。不过这个参数时商业才提供的。
如下
其他商业版指令
server 中的 resolve 、 route 、 service 、 slow_start 、 drain 参数
random 中的 least_time 参数
zone 、 state 、 ntlm 、least_time 、 queue 、 resolver 、 resolver_timeout 、 sticky 、sticky_cookie_insert 配置指令
如果同时写多个均衡策略,以最后一个为准 如
只有$arg_a生效。
nginx反向代理和负载均衡示例图
7.nginx 主体功能介绍和工作解析
Nginx是一款轻量级的Web 服务器/反向代理服务器及电子邮件(IMAP/POP3)代理服务器,并在一个BSD-like 协议下发行。
Nginx 是一个很强大的高性能 Web和 反向代理服务器,它具有很多非常优越的特性:
在高连接并发的情况下,Nginx是 Apache服务器不错的替代品,能够支持高达 50,000 个并发连接数的响应。感谢Nginx为我们选择了 epoll and kqueue作为开发模型。
Nginx作为负载均衡服务器:Nginx 既可以在内部直接支持 Rails 和 PHP 程序对外进行服务,也可以支持作为 HTTP代理服务器对外进行服务。
Nginx采用C进行编写,不论是系统资源开销还是CPU使用效率都比 Perlbal 要好很多。
7.1 nginx 配置实例-动静分离
nginx动静分离简单来说就是把动态静态请求分开,不能理解成只是单纯的把动态页面和静态页面物理分离。严格意义说应该是动态请求根静态请求分开,可以理解成使用nginx处理静态页面,tomcat处理动态页面。
动静分离从目前实现角度来讲大致分为两种
1,一种是纯粹把静态文件独立成单独的域名,放在独立的服务器上,也是目前主流推崇的方案。
2,另外一种方法就是动态跟静态文件混合在一起发布,通过nginx发布。
3,通过location 指定不同的后缀名实现不同的请求转发。
如 通过expires参数设置,可以使浏览器缓存过期时间,减少与服务器之前的请求和流量。
具体Expires定义:是给一个资源设定一个过期时间,也就是说无需去服务端验证,直接通过浏览器自身确认是否过期即可。所以不会产生额外的流量,此种方法非常适合不经常变动的资源。如果经常变动更新的文件,不建议使用expires来缓存。
比如设置3d,表示在这3天之内访问这个url,发送一个请求,比对服务器该文件最后更新时间没有变化,则不会从服务器抓取,返回状态码304;如果有修改,则直接从服务器重新返回状态码200.
7.2 nginx配置高可用的集群
keepalived + nginx 高可用集群 (主从模式)
两台服务器安装nginx
两台服务器安装keepalived
1.使用yum命令进行安装
yum install keepalived -y
安装之后,在etc里面生成目录keepalived,有文件keepalived.conf
2.完成高可用配置(主从配置)
1)修改/etc/keepalived/keepalivec.conf 配置文件
global_defs{
notification_email{
acassen@firewall.loc
failover@firewall.loc
sysadmin@firewall.loc
}
notification_email_from Alexandre.Cassen@firewall.loc
smtp_server 192.168.17.129
smtp_connect_timeout 30
router_id LVS_DEVEL #服务器的名字 vim /etc/hosts 文件添加 127.0.0.1 LVS_DEVEL
}
vrrp_script chk_http_port{
script "/usr/local/src/nginx_check.sh" #检测脚本的路径
interval 2 #(检测脚本执行的间隔单位:秒)
weight 2 #权重参数 当检查脚本的条件成立就设置主机的权重2
}
vrrp_instance VI_1 {
state MASTER # 备份服务器上将 MASTER 改为 BACKUP
interface ens33 #主机网卡,
virtual_router_id 51 # 主、备机的 virtual_router_id 必须相同
priority 90 # 主、备机取不同的优先级,主机值较大,备份机值较小
advert_int 1 #检查主机服务心跳,判断服务是否活着默认是1秒
authentication {
auth_type PASS #权限验证的方式
auth_pass 1111 #密码1111
}
virtual_ipaddress {
192.168.253.50 #VRRP H 虚拟地址,用户访问此IP地址再跳转到nginx服务器
} }
2).在/usr/local/src 添加检测脚本nginx_check.sh
#!/bin/bash
A=`ps -C nginx –no-header |wc -l`
if [ $A -eq 0 ];then
/usr/local/nginx/sbin/nginx
sleep 2
if [ `ps -C nginx --no-header |wc -l` -eq 0 ];then
killall keepalived
fi
fi
3).启动两台服务器上的nginx 和 keepalived
启动 nginx:/usr/local/nginx/sbin/nginx
启动 keepalived:systemctl start keepalived.service
4)测试
在浏览器地址栏输入 虚拟 ip 地址 192.168.253.50
使用命令:ip a 查看虚拟地址绑定的网卡
8.其他相关配置
8.1 mac中ulimit 和 sysctl
可以用ulimit -a 来显示当前的各种用户进程限制。
- 设置打开文件数
- $sudo launchctl limit maxfiles 100000 500000
$sudo ulimit -n 100000
- 设置进程数
- sudo launchctl limit maxproc 100000 100000
- launchctl limit
查看哪些可以修改
man 3 sysctl
sudo ulimit -u 1064
- 设置端口
$sudo sysctl net.inet.ip.portrange.first=10000
要想支持更高数量的TCP并发连接的通讯处理程序,就必须修改系统对当前用户的进程同时打开的文件数量的软限制(soft limit)和硬限制(hardlimit)。
其中软限制是指Linux在当前系统能够承受的告警范围内进一步限制用户同时打开的文件数,超过则会告警;
硬限制则是根据系统硬件资源状况(主要是系统内存)计算出来的系统最多可同时打开的文件数量,超过则无法打开了。
查看网络设置
sysctl -a | grep "net.inet.ip"
8.2 ipv6监听
服务器查看ipv6
netstat -ano|findstr 80
在nginx配置文件中
listen [::]:80
从Nginx 1.3 的某个版本起,默认ipv6only是打开的,也就是上面的语句只会监听IPv6的端口而不会监听IPv4的端口。
虽然Linux系统默认是监听IPv6的某个端口会同时监听对应的IPv4的端口,但是FreeBSD是默认分开IPv6和IPv4的。
所以为了一致性的考虑(新版本Nginx必须推荐这样做),请使用分开监听的方法:
listen 80;
listen [::]:80 ipv6only=on;
只监听一个指定的ipv6地址
和IPv4指定地址一样,就在listen里写上完整的地址就OK了!以一个IPv6地址为例:
listen [2607:f0d0:1002:51::4]:80;
IPv6监听SSL(443)端口
编辑你原来监听443端口的配置文件,如/etc/nginx/conf.d/ssl.conf,修改listen语句为:
listen [::]:443 ssl;
后面的ssl可省掉。443端口的其它用法和80端口一样,这里就不赘述了。
8.3 linux 中编辑器vim常用命令解析
1.Vim编辑器
是linux系统中的文件编辑器,一般系统中默认的是vi 编辑器,vim要比vi要强大一点;使用vim需要安装,安装方式:yum install vim -y (-y表示安装过程不需要确认),vim或vi对小文件操作是很快的,但是较大的文件就打开是有点耗时;
vi/vim编辑器的操作模式分为三种:
a.命令行模式:vi、vim的默认模式;在这一模式中,所有的输入被解释成vi命令,可以执行修改、复制、移动、粘贴和删除正文等命令,也可以移动光标、搜索字符串和退出vi的操作等;
b.编辑模式:从命令行模式切换至编辑模式,输入:a 或 i 或 o 即可;在编辑模式中,可以往一个文件中输入正文;在这一模式下,输入的每一个字符都被vi编辑器解释为输入的正文。使用ESC键返回命令行模式。
说明:按a i o 进入编辑(插入)模式,是有一点区别的;
a :进入插入模式并在光标之后进行插入
i:进入插入模式并在光标之前进行插入
o:进入插入模式并在当前(光标所在)行之下开启新的一行;
c.扩展模式:在一些unix系统上也叫最后一行模式。在这一模式下,可以使用一些高级编辑命令,如:搜索和替代字符串、存盘或者退出vi编辑器等;要进入最后一行模式,需要在命令行模式中输入冒号(:),冒号这一操作将把光标移动到屏幕的最后一行。
2.vim创建文件或者修改文件
a. vim filename 没有文件就创建文件,有就打开文件;默认:命令行模式;
在命令行模式、最后一行模式的命令
补充:查询关键字:/keywords 下一个:n 上一个:#3.echo
a、echo 后面加内容------》输出的后面的内容;b、echo -n 后面加内容----》不换行输出内容;
c、echo -e 后面加内容-----》输出转义字符,如:\t 转义字符,表示:制表符,相当于Tab键;
d、结合重定向符:> (覆盖文件内原内容) 或 >> (在文件原内容后追加,而不覆盖原内容) ;向文件写入内容;
4.文件的查看
cat finame
nl finame
显示的时候,顺道输出行号!
more finame
一页一页的显示文件内容,enter向下
less finame
https://blog.csdn/ak739105231/article/details/89883768
比more更强大,可以向上一页查看;点击键盘Pgup;PgDn两个按钮
5.less命令详解
语法
less(选项)(参数)
选项
-e:文件内容显示完毕后,自动退出;
-f:强制显示文件;
-g:不加亮显示搜索到的所有关键词,仅显示当前显示的关键字,以提高显示速度;
-l:搜索时忽略大小写的差异;
-N:每一行行首显示行号;
-s:将连续多个空行压缩成一行显示;
-S:在单行显示较长的内容,而不换行显示;
-x<数字>:将TAB字符显示为指定个数的空格字符。
参数
文件:指定要分屏显示内容的文件。
8.4 ip 0.0.0.0 与127.0.0.1的区别
0.0.0.0 集合 不清楚 主机 目的 网络 收容所
127.0.0.1 本机地址 Localhost
a、0.0.0.0:它表示的是这样一个集合:所有不清楚的主机和目的网络。
b、255.255.255.255:限制广播地址,这个地址不能被路由器转发。
c、127.0.0.1:本机地址,在Windows系统中,这个地址有一个别名“Localhost”。
0.0.0.0
集合 不清楚 主机 目的 网络 收容所
严格说来,0.0.0.0已经不是一个真正意义上的IP地址了。它表示的是这样一个集合:所有不清楚的主机和目的网络。这里的“不清楚”是指在本机的路由表里没有特定条目指明如何到达。
对本机来说,它就是一个“收容所”,所有不认识的“三无”人员,一律送进去。如果你在网络设置中设置了缺省网关,那么Windows系统会自动产生一个目的地址为0.0.0.0的缺省路由。
255.255.255.255
限制广播地址
不能 路由器 转发
限制广播地址。对本机来说,这个地址指本网段内(同一广播域)的所有主机。
如果翻译成人类的语言,应该是这样:“这个房间里的所有人都注意了!”这个地址不能被路由器转发。
127.0.0.1
本机地址 Localhost
本机地址,主要用于测试。用汉语表示,就是“我自己”。在Windows系统中,这个地址有一个别名“Localhost”。
寻址这样一个地址,是不能把它发到网络接口的。除非出错,否则在传输介质上永远不应该出现目的地址为“127.0.0.1”的数据包。
linux uwsgi配置文件
uwsgi 、fcgi 、wsgi 区别
fcgi:FastCGI协议是一种常用于Web服务器和应用程序之间的通信协议。它允许Web服务器(如Nginx)将请求传递给后端应用程序,并接收处理结果。FastCGI协议本身不包含具体的实现,而是由不同的软件包(如PHP-FPM)来实现。
用spawn-fcgi或者框架自带的工具对各个project分别生成监听进程,然后和http服务互动。这种方法需要对每个项目分别进行配置和管理,管理上较为复杂。
wsgi:这是一个Apache模块,用于在Apache服务器上运行Python Web应用程序。它允许Apache直接作为Web服务器运行Python代码,支持WSGI协议。
利用http服务的mod_wsgi模块来跑各个project,配置较为复杂且内存占用较大
uwsgi: 是一个集成的服务器应用,Nginx通过uwsgi
协议与uWSGI服务器通信,而不是通过传统的HTTP代理方式。uWSGI是一个独立的Web服务器,也可以与Nginx集成使用,安装相对简单且性能较高
mod_uwsgi:这是Apache的一个模块,专门用于在Apache服务器上运行uWSGI服务器。它通过uwsgi协议与uWSGI服务器通信,支持WSGI协议,可以运行Python、Ruby等多种语言的Web应用程序。
fcgi:主要用于将Python应用作为CGI脚本运行,每个请求都会启动一个新的进程,适合轻量级应用,但管理复杂且性能较低
mod_wsgi:通过Apache的mod_wsgi模块运行Python应用。配置较为复杂,适合需要高并发处理的应用,但内存占用较大
mod_uwsgi:uWSGI服务器可以通过uwsgi协议与Nginx通信,实现高效的请求处理和负载均衡。uWSGI作为一个独立的Web服务器或与Nginx集成使用,具有低内存占用和高性能的特点
总结:三者中uwsgi效率最高,是前两者的数倍,可以用在高并发的环境下。对于Apache服务器,FCGI和mod_wsgi通常是用于部署Python Web应用的方法。mod_uwsgi主要用于部署Python Web应用,它使用的是uWSGI协议,而不是FCGI。
fcgi 、 mod_wsgi 、 mod_uwsgi 的安装
首先需要在Apache上安装mod_wsgi模块。可以通过下载源代码编译安装,或者使用包管理器(如apt-get或yum)进行安装
1,FCGI和mod_wsgi的安装:
- fcgi:通常需要安装FastCGI管理器(如PHP-FPM),然后在Web服务器(如Nginx)中配置FastCGI参数,指向FastCGI管理器。
- mod_wsgi:需要在Apache服务器上安装mod_wsgi模块,并通过Apache的配置文件设置WSGIApplicationGroup和其他相关参数来运行Python应用。
对于Debian/Ubuntu系统,可以使用以下命令安装:
sudo apt-get install libapache2-mod-fcgid
sudo apt-get install libapache2-mod-wsgi
对于Red Hat/CentOS系统,可以使用以下命令安装:
sudo yum install mod_fcgid
sudo yum install mod-wsgi
2,mod_uwsgi的安装
- mod_uwsgi:需要在Apache上安装mod_uwsgi模块,并通过Apache的配置文件设置UWSGIOptions和其他相关参数来运行uWSGI服务器。
首先,你需要安装uWSGI。可以使用以下命令安装:
sudo pip install uwsgi
然后,你需要安装mod_uwsgi Apache模块。可以使用以下命令安装:
sudo apt-get install apache2-threaded-dev
sudo pip install mod_uwsgi
注意:上述mod_uwsgi的安装命令可能会根据你的操作系统和Python版本的不同而有所变化。
nginx 其他应用配置
使用docker基础安装方法
docker run \
--restart always \
--name Nginx \
-d \
-p 80:80 \
nginx
注意参数 restart 重启策略,always 是一直保持重启。如果不设置,可以把这条删掉。never\always
8090 - 容器端口、80 - 服务器端口,这样外部通过80端口即可访问。
进入nginx
进入程序:docker exec -it Nginx /bin/bash
[root@vultr ~]# docker exec -it Nginx /bin/bash
root@ed8dc07f2ae6:/# ls
bin boot dev docker-entrypoint.d docker-entrypoint.sh etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var
root@ed8dc07f2ae6:/# cd etc/nginx/
root@ed8dc07f2ae6:/etc/nginx# ls
conf.d fastcgi_params mime.types modules nginx.conf scgi_params uwsgi_params
root@ed8dc07f2ae6:/etc/nginx# pwd
/etc/nginx
root@ed8dc07f2ae6:/# cd /usr/share/nginx/html
root@ed8dc07f2ae6:/usr/share/nginx/html# ls
50x.html index.html
root@ed8dc07f2ae6:/usr/share/nginx/html# cat index.html
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
<p>For online documentation and support please refer to
<a href="http://nginx/">nginx</a>.<br/>
Commercial support is available at
<a href="http://nginx/">nginx</a>.</p>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>
root@ed8dc07f2ae6:/usr/share/nginx/html#
root@ed8dc07f2ae6:/usr/share/nginx/html# exit
exit
退出程序:exit
配置nginx.conf html主页
创建文件目录
[root@vultr ~]# mkdir -p /data/nginx/conf
[root@vultr ~]# mkdir -p /data/nginx/html
拷贝文件
[root@vultr ~]# docker container cp Nginx:/etc/nginx/nginx.conf /data/nginx/conf
[root@vultr ~]# docker container cp Nginx:/usr/share/nginx/html/index.html /data/nginx/html
查看信息
[root@vultr ~]# ls /data/nginx/conf/
nginx.conf
[root@vultr ~]# ls /data/nginx/html/
index.html
部署nginx
docker run \
--restart always \
--name Nginx \
-d \
-v /data/nginx/html:/usr/share/nginx/html \
-v /data/nginx/conf/nginx.conf:/etc/nginx/nginx.conf \
-p 80:80 \
nginx
重启:sudo service nginx restart
证书安装,各厂商都有提供,比较简单,自己申请下载下来即可
里面有2个文件【x.key、x.pem】
配置证书
创建一个default.conf 文件配置ssl信息
单个证书
server {
listen 80;
listen [::]:80;
server_name openai.xfg.im;
rewrite ^(.*) https://$server_name$1 permanent;
}
server {
listen 443 ssl;
server_name openai.xfg.im;
ssl_certificate /etc/nginx/ssl/9740289_openai.xfg.im.pem;
ssl_certificate_key /etc/nginx/ssl/9740289_openai.xfg.im.key;
ssl_session_cache shared:SSL:1m;
ssl_session_timeout 5m;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
location / {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
root /usr/share/nginx/html;
index index.html index.htm;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
可以复制这份文件,在自己本地创建。注意修改域名和SSL文件路径
多个证书
需要给1个以上的域名配置SSL,那么可以配置多组 server 如下
server {
listen 80;
listen [::]:80;
server_name itedus;
rewrite ^(.*) https://$server_name$1 permanent;
}
server {
listen 443 ssl;
server_name itedus;
ssl_certificate /etc/nginx/ssl/9750021_itedus.pem;
ssl_certificate_key /etc/nginx/ssl/9750021_itedus.key;
ssl_session_cache shared:SSL:1m;
ssl_session_timeout 5m;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
location / {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
root /usr/share/nginx/html;
index index.html index.htm;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
server {
listen 80;
listen [::]:80;
server_name chatgpt.itedus;
rewrite ^(.*) https://$server_name$1 permanent;
}
server {
listen 443 ssl;
server_name chatgpt.itedus;
ssl_certificate /etc/nginx/ssl/9749920_chatgpt.itedus.pem;
ssl_certificate_key /etc/nginx/ssl/9749920_chatgpt.itedus.key;
ssl_session_cache shared:SSL:1m;
ssl_session_timeout 5m;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
location / {
proxy_pass http://1.x.x.x:3002;
proxy_http_version 1.1;
chunked_transfer_encoding off;
proxy_buffering off;
proxy_cache off;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
启动服务
在 nginx.conf 的配置文件有这么一句;include /etc/nginx/conf.d/*.conf; 那么只要是 conf.d 文件夹下的文件都会被加载。所以直接在 conf.d/default.conf 配置 SSL 就会被加载。
接下来重新安装 Nginx 即可。安装前记得删除 Nginx 你可以用命令
docker stop Nginx
docker rm Nginx
或者在 Portainer 中操作也可
docker run \
--name Nginx \
-p 443:443 -p 80:80 \
-v /data/nginx/logs:/var/log/nginx \
-v /data/nginx/html:/usr/share/nginx/html \
-v /data/nginx/conf/nginx.conf:/etc/nginx/nginx.conf \
-v /data/nginx/conf/conf.d:/etc/nginx/conf.d \
-v /data/nginx/ssl:/etc/nginx/ssl/ \
--privileged=true -d --restart=always nginx
重定向
在default.conf中添加下面配置 重启nginx
location /d5fe/ {
rewrite ^/d5fe/(.*)$ /$1 break;
proxy_pass https://api.x;
proxy_ssl_server_name on;
proxy_set_header Host api.x;
proxy_set_header Connection '';
proxy_http_version 1.1;
chunked_transfer_encoding off;
proxy_buffering off;
proxy_cache off;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Forwarded-Proto $scheme;
}
auth_request
server {
listen 80;
listen [::]:80;
server_name api.xfg.im;
rewrite ^(.*) https://$server_name$1 permanent;
}
server {
listen 443 ssl;
server_name api.xfg.im;
ssl_certificate /etc/nginx/ssl/9877497_api.xfg.im.pem;
ssl_certificate_key /etc/nginx/ssl/9877497_api.xfg.im.key;
ssl_session_cache shared:SSL:1m;
ssl_session_timeout 5m;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
location / {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
root /usr/share/nginx/html;
index index.html index.htm;
}
location /abc/ {
auth_request /auth;
rewrite ^/abc/(.*)$ /$1 break;
proxy_pass https://api.x;
proxy_ssl_server_name on;
proxy_set_header Host api.x;
proxy_set_header Connection '';
proxy_http_version 1.1;
chunked_transfer_encoding off;
proxy_buffering off;
proxy_cache off;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Forwarded-Proto $scheme;
}
location = /auth {
# 发送子请求到HTTP服务,验证客户端的凭据,返回响应码
internal;
# 设置参数
set $query '';
if ($request_uri ~* "[^\?]+\?(.*)$") {
set $query $1;
}
# 验证成功,返回200 OK
proxy_pass http://1.x.x.x.*:8090/auth/token?$query;
# 发送原始请求
proxy_pass_request_body off;
# 清空 Content-Type
proxy_set_header Content-Type "";
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
目前暂时更新到这里,欢迎有问题大家私信
Nginx、Apache和Tomcat在功能、性能和适用场景上各有特点
一、从功能上分析
Nginx:主要处理静态资源,如HTML、CSS、JavaScript文件和图片等。它还支持反向代理和负载均衡,能够高效地处理大量并发连接。Nginx通过异步非阻塞的事件驱动模型,减少了上下文切换的开销,提高了CPU和内存的利用效率
Apache:功能全面,既可以处理静态资源,也可以通过各种模块支持动态内容的生成,如PHP、Perl等。Apache拥有丰富的功能模块,如访问控制、用户认证、URL重写等
Tomcat:专门用于运行Java Servlet和JSP,是一个轻量级的应用服务器。它主要处理动态内容,可以与各种Java框架无缝集成,如Spring、Struts等
二、从性能上分析
Nginx:以其高性能和低资源消耗著称。在高并发场景下,Nginx能够比Apache和Tomcat更好地应对流量高峰,因为它采用异步非阻塞的事件驱动模型,处理大量并发连接时占用内存和CPU资源较少
Apache:在处理静态资源方面的性能不如Nginx,但在合理配置和优化后,也能提供较好的性能。Apache在处理动态内容时表现良好,但其性能受配置和模块影响较大
Tomcat:在处理小到中等规模的并发请求时表现良好,但在处理大量并发连接时可能会出现性能瓶颈。Tomcat的性能受到Java虚拟机(JVM)的影响
三、适用场景分析
Nginx:适合高并发场景,如大型网站和API网关。它也常作为反向代理服务器,用于负载均衡和高可用性
Apache:适合需要处理多种类型内容的网站,特别是那些需要复杂配置和动态内容的网站。Apache的稳定性和丰富的功能使其在企业和政府机构中广泛使用
Tomcat:主要用于开发和部署Java Web应用程序。它特别适合内部网络和小型服务,如不需要流控的场景
从apache和nginx、tomcat架构上分析
- 架构:Apache采用多进程架构,每个请求都由一个独立的进程处理;而Nginx采用异步事件驱动的架构,可以处理更多的并发连接。
- 性能:由于Nginx的架构设计,它可以处理更多的并发连接,而且在高负载情况下表现更加稳定和可靠。因此,Nginx通常被认为是比Apache更高效的Web服务器。
- 配置:Apache的配置文件比较复杂,需要一定的学习和经验才能正确配置;而Nginx的配置文件比较简洁和可读性强,更容易理解和配置。
- 功能:Apache有许多模块可以扩展其功能,例如mod_rewrite用于URL重写,mod_ssl用于SSL加密等;而Nginx的功能比较简单,但是可以通过第三方模块扩展其功能。
-
Nginx处理大并发静态请求效率高于其他软件,可作为负载均衡服务器,可承受3万以上并发连接数,是Apache的10倍。4GB内存的服务器+Apache(prefork模式)一般只能处理3000个并发连接,占用3GB以上内存,Nginx在3万并发连接下,消耗不到2GB内存。
-
Nginx的处理高并发要优于httpd,先从两种Web服务器的工作原理及工作模式说起
-
Apache的三种工作模式
三种mpm介绍
Apache2.x支持插入式并行处理模块,称为多路处理模块(MPM)。在编译apache时必须且只能选择一个MPM,对类unix系统,可以有几个MPM可供选择,它们会影响到apache的速度和可伸缩性。
Prefork——多进程
多进程,每个请求用一个进程响应,这个过程会用到select机制来通知
介绍及适用场景
Prefork多路处理模块(MPM)实现了一个非线程型的、预派生的web服务器。
它的工作方式类似于Apache 1.3,适合于没有线程安全库,需要避免线程兼容性问题的系统。
适用于每个请求相互独立的情况,这样若一个请求出现问题就不会影响到其他请求。
具有很强的自我调节能力,只需要很少的配置指令调整。
最重要的是将MaxClients设置为一个足够大的数值以处理潜在的请求高峰。
同时又不能太大,以致需要使用的内存超出物理内存的大小。
如图
- 工作原理:
- 如果不用“–with-mpm”显式指定某种MPM,prefork就是Unix平台上缺省的MPM。
- 它所采用的预派生子进程方式也是 Apache1.3中采用的模式。prefork本身并没有使用到线程,2.0版使用它是为了与1.3版保持兼容性;
-
- 另一方面,prefork用单独的子进程来处理不同的请求,进程之间是彼此独立的,这也是其成为最稳定的MPM之一。
优点:稳定
缺点:慢,占用资源,不适用高并发场景
Worker——多线程
多线程,一个进程可以生成多个线程,每个线程响应一个请求,但通知机制还是select不过可以接受更多的请求
介绍及适用场景
woker多路处理模块(MPM)使网络服务器支持混合的多线程多进程
由于使用线程来处理请求,所以可以处理海量请求,而系统资源的开销小于基于进程的MPM。
同时使用了多进程,每个进程又有多个线程,以获得基于进程的MPM的稳定性。
(父进程)负责子进程的建立。每个子进程可以建立ThreadsPerChild数量的服务线程和一个监听线程,该监听线程监听接入请求并将其传递给服务线程处理和应答。
不管是Worker模式或是Prefork 模式,Apache总是试图保持一些备用的(spare)或者是空闲的子进程(空闲的服务线程池)用于迎接即将到来的请求。
这样客户端就不需要在得到服务前等候子进程的产生。
如图
- 工作原理:
- 相对于prefork,worker是2.0版中全新的支持多线程和多进程混合模型的MPM。
- 由于使用线程来处理,所以可以处理相对海量的请求,而系统资源的开销要小于基于进程的服务器。
- 但是,worker也使用了多进程,每个进程又生成多个线程,以获得基于进程服务器的稳定性,这种MPM的工作方式将是Apache2.0的发展趋势。
优点:相较于prefork占用的内存较少,可以同时处理更多请求
缺点:使用keep-alive的长连接方式,某个线程一直被占用,即使没有传输数据,也需要一直等待到超时才会被释放。
如果过多的线程被占用,也会导致在高并发场景下无服务线程可用。该情况在prefork模式下同样发生。
Event——基于异步I/O模型
基于异步I/O模型,一个进程或线程,每个进程或线程响应多个用户请求,它是基于事件驱动(也就是epoll机制)实现的
介绍及适用场景
以上两种稳定的MPM方式在非常繁忙的服务器应用下都有些不足。
尽管HTTP的Keepalive方式能减少TCP连接数量和网络负载,但是 Keepalive需要和服务进程或者线程绑定,这就导致一个繁忙的服务器会耗光所有的线程。
Event MPM是解决这个问题的一种新模型,它把服务进程从连接中分离出来。
在服务器处理速度很快,同时具有非常高的点击率时,可用的线程数量就是关键的资源限制此时Event MPM方式是最有效的。
一个以Worker MPM方式工作的繁忙服务器能够承受每秒好几万次的访问量(例如在大型新闻服务站点的高峰时),而Event MPM可以用来处理更高负载。
如图
工作原理:
event基于事件机制的特性,一个进程响应多个用户请求,利用callback机制,让套接字复用,请求过来后进程并不处理请求,而是直接交由其他机制来处理,通过epoll机制来通知请求是否完成;
在这个过程中,进程本身一直处于空闲状态,可以一直接收用户请求。可以实现一个进程程响应多个用户请求。支持持海量并发连接数,消耗更少的资源。
event工作机制
event只在有数据发送的时候才开始建立连接,连接请求才会触发工作线程,
即使用了TCP的一个选项,叫做延迟接受连接TCP_DEFER_ACCEPT,加了这个选项后,
若客户端只进行TCP连接,不发送请求,则不会触发Accept操作,也就不会触发工作线程去干活,进行了简单的防攻击(TCP连接)
优点:
单线程响应多请求,专门有一个线程负责监听管理释放连接,解决了keep-alive场景下资源被长期占用的问题,从而占据更少的内存。
缺点:没有线程安全控制。
如何提高Web服务器的并发连接处理能力
1、基于线程,即一个进程生成多个线程,每个线程响应用户的每个请求。
2、基于事件的模型,一个进程处理多个请求,并且通过epoll机制来通知用户请求完成。
3、基于磁盘的IO(异步I/O)
4、支持mmap内存映射,mmap传统的web服务器,进行页面输入时,都是将磁盘的页面先输入到内核缓存中,再由内核缓存中复制一份到web服务器上mmap机制就是让内核缓存与磁盘进行映射,web服务器,直接复制页面内容即可。不需要先把磁盘的上的页面先输入到内核缓存去
-
Nginx优异之处
-
传统Web服务基于进程/线程,每个进程/线程处理并发连接请求,产生阻塞,利用率低下。
-
新的进程/线程需备好运行时环境,如堆内存、栈内存和执行上下文,占用CPU,过多进程/线程导致线程抖动、上下文切换,进一步降低系统性能。
-
Nginx采用模块化、事件驱动、异步、单线程及非阻塞的架构,多路复用及事件通知机制,每个Worker处理数千个并发连接及请求。
-
Nginx 是一个高性能的 Web 和反向代理服务器, 它具有有很多非常优越的特性。
-
作为 Web 服务器:相比 Apache,Nginx 使用更少的资源,支持更多的并发连接,体现更高的效率。
-
作为负载均衡服务器: Nginx 既可以在内部直接支持 Rails 和 PHP,也可以支持作为 HTTP代理服务器 对外进行服务。Nginx 用 C 编写, 不论是系统资源开销还是 CPU 使用效率都比 Perlbal 要好的多。
-
作为邮件代理服务器: Nginx 同时也是一个非常优秀的邮件代理服务器(最早开发这个产品的目的之一也是作为邮件代理服务器),Last.fm 描述了成功并且美妙的使用经验。
为什么Nginx没有取代Apache
因为两个东西的侧重点不一样,Apache自身内置了很多东西,无需借助其他东西就能够几乎所有的Web类型应用进行支持。
- 而Nginx不同,它在静态文件的处理、高并发方面比较有优势。
- Apache侧重在完整稳定上,而Nginx侧重在轻量高效上,很多时候Apache和Nginx是配合使用的
- Nginx配置在Apache前面,用它挡掉静态文件的请求(网站今天资源的请求占了大部分的),Nginx处理不了的内容才转发给Apache来处理。
Nginx工作原理
Nginx会按需同时运行多个进程:一个主进程(master)和几个工作进程(worker),配置了缓存时还会有缓存加载器进程(cache loader)和缓存管理器进程(cache manager)等。所有进程均是仅含有一个线程,并主要通过“共享内存”的机制实现进程间通信。主进程以root用户身份运行,而worker、cache loader和cache manager均以非特权用户身份运行。
在高连接并发的情况下,Nginx是Apache服务器不错的替代品。
Nginx安装简单,配置文件简洁且支持Perl语法,Bug极少。Nginx启动容易,可7*24不间断运行数月,且可在不中断服务的情况下升级软件版本。
Apache与Nginx比较
在选择Web服务器时,Nginx和Apache都是备受推崇的选择。然而,对于许多开发者和管理员来说,选择哪一个可能会成为一个难以解决的问题。因此,我们需要对两者进行比较,以确定哪一个更适合我们的需求。首先,Nginx以其高效的性能而闻名。它是一个轻量级的Web服务器,可以处理大量并发连接。相比之下,Apache是一个成熟的Web服务器,但它在处理并发连接时可能会出现性能瓶颈。因此,如果您需要处理大量并发连接,Nginx可能是更好的选择。
其次,Nginx具有更好的负载均衡功能。它可以在多个服务器之间均衡地分配流量,以提高性能和可靠性。Apache也可以实现负载均衡,但相对来说要更为复杂。
最后,Nginx的配置文件比Apache更为简单和易于理解。这意味着您可以更快地配置服务器并更快地上线。相比之下,Apache的配置可能会更加复杂,需要更多的时间和精力。
Nginx
轻量级,采用 C 进行编写,同样的 web 服务,会占用更少的内存及资源
抗并发,nginx 以 epoll and kqueue 作为开发模型,处理请求是异步非阻塞的,负载能力比 apache 高很多,而 apache 则是阻塞型的。在高并发下 nginx 能保持低资源低消耗高性能 ,而 apache 在 PHP 处理慢或者前端压力很大的情况下,很容易出现进程数飙升,从而拒绝服务的现象。
nginx 处理静态文件好,静态处理性能比 apache 高三倍以上
nginx 的设计高度模块化,编写模块相对简单
nginx 配置简洁,正则配置让很多事情变得简单,而且改完配置能使用 -t 测试配置有没有问题,apache 配置复杂 ,重启的时候发现配置出错了,会很崩溃
nginx 作为[负载均衡务器],支持 7 层负载均衡
nginx 本身就是一个反向代理服务器,而且可以作为非常优秀的邮件代理服务器
启动特别容易, 并且几乎可以做到 7*24 不间断运行,即使运行数个月也不需要重新启动,还能够不间断服务的情况下进行软件版本的升级。社区活跃,各种高性能模块出品迅速
Apache
apache 的 rewrite 比 nginx 强大,在 rewrite 频繁的情况下,用 apache
apache 发展到现在,模块超多,基本想到的都可以找到
apache 更为成熟,少 bug ,nginx 的 bug 相对较多
apache 超稳定
apache 对 PHP 支持比较简单,nginx 需要配合其他后端用
apache 在处理动态请求有优势,nginx 在这方面是鸡肋,一般动态请求要 apache 去做,nginx 适合静态和反向。
apache 仍然是目前的主流,拥有丰富的特性,成熟的技术和开发社区选择Nginx还是Apache
apache运行php比较好,适合跑动态
nginx比较适合跑静态(如果想让nginx跑动态只能支持跳转)。
现在流行的lanmp架构就是同时使用apache和nginx,静态网页有nginx处理,动态交由apache处理,这样就能更大限度的发挥服务器性能。
通用的方案是,前端 nginx 抗并发,后端 apache 集群,配合起来会更好。
总结
两者最核心的区别在于 apache 是同步多进程模型,一个连接对应一个进程,而 nginx 是异步的,多个连接(万级别)可以对应一个进程一般来说,需要性能的web服务,用nginx 。如果不需要性能只求稳定,更考虑 apache ,后者的各种功能模块实现得比前者,例如 ssl 的模块就比前者好,可配置项多。
epoll(freebsd 上是 kqueue ) 网络 IO 模型是 nginx 处理性能高的根本理由,但并不是所有的情况下都是 epoll 大获全胜的,如果本身提供静态服务的就只有寥寥几个文件,apache 的 select 模型或许比 epoll 更高性能。当然,这只是根据网络 IO 模型的原理作的一个假设,真正的应用还是需要实测了再说的。
综上所述,Apache和Nginx各有优缺点。在选择使用哪种Web服务器时,需要根据具体的需求和场景来综合考虑。
Apache配置参数解析
mpm工作模块
查看三种MPM的静态编译模块
httpd -l
查看静态编辑及动态装载的模块
httpd -m
动态模块路径
ll /usr/lib64/httpd/modules/
apache安装时设置工作模式
[root@localhost httpd-2.4.1]# ./configure --prefix=/usr/local/apache2worker --enable-so --with-mpm=worker
[root@localhost httpd-2.4.1]# make
[root@localhost httpd-2.4.1]# make install
指定--with-mpm=NAME 选项指定MPM,不指定模式的话,默认为Prefork MPM。
配置Event MPM
./configure --prefix=/usr/local/apache2worker --enable-so --enable-nonportable-atomics=yes --with-mpm=event
找到httpd-mpm.conf文件
# perfork MPM
<IfModule mpm_prefork_module>
StartServers 5
MinSpareServers 5
MaxSpareServers 10
MaxRequestWorkers 250
MaxConnectionsPerChild 0
</IfModule>
参数解析
# StartServers: 数量的服务器进程开始
# MinSpareServers: 最小数量的服务器进程,保存备用
# MaxSpareServers: 最大数量的服务器进程,保存备用
# MaxRequestWorkers: 最大数量的服务器进程允许开始
# MaxConnectionsPerChild: 最大连接数的一个服务器进程服务
prefork实际应用原理
prefork 控制进程在最初建立“StartServers”个子进程后,为了满足MinSpareServers设置的需要创建一个进程,每秒按指数级增加,直至最多每秒32个,满足MinSpareServers设置的值为止
这种模式 可以不必在请求到来时再产生新的进程,从而减小了系统开销以增加性能。
MaxSpareServers设置了最大的空闲进程数,如果空闲进程数大于这个值,Apache会自动kill掉一些多余进程。
这个值不要设得过大,但如果设的值比MinSpareServers小,Apache会自动把其调整为 MinSpareServers+1。
如果站点负载较大,可考虑同时加大MinSpareServers和MaxSpareServers。
MaxRequestsPerChild设置的是每个子进程可处理的请求数。每个子进程在处理了“MaxRequestsPerChild”个请求后将自 动销毁。0意味着无限,即子进程永不销毁。
虽然缺省设为0可以使每个子进程处理更多的请求,但如果设成非零值也有两点重要的好处:
1、可防止意外的内存泄 漏。2、在服务器负载下降的时侯会自动减少子进程数。
因此,可根据服务器的负载来调整这个值。
指令集同时将服务请求的数量上的限制。任何连接尝试在MaxRequestWorkerslimit将通常被排队,最多若干基于上ListenBacklog指令。
在apache2.3.13以前的版本MaxRequestWorkers被称为MaxClients
(MaxClients)是这些指令中最为重要的一个,设定的是 Apache可以同时处理的请求,是对Apache性能影响最大的参数。其缺省值150是远远不够的,如果请求总数已达到这个值(可通过ps -ef|grep http|wc -l来确认),那么后面的请求就要排队,直到某个已处理请求完毕。
这就是系统资源还剩下很多而HTTP访问却很慢的主要原因。虽然理论上这个值越大,可以 处理的请求就越多,但Apache默认的限制不能大于256。
# worker MPM
<IfModule mpm_worker_module>
StartServers 3
MinSpareThreads 75
MaxSpareThreads 250
ThreadsPerChild 25
MaxRequestWorkers 400
MaxConnectionsPerChild 0
</IfModule>
参数解析
# StartServers: 初始数量的服务器进程开始
# MinSpareThreads: 最小数量的工作线程,保存备用
# MaxSpareThreads: 最大数量的工作线程,保存备用
# ThreadsPerChild: 固定数量的工作线程在每个服务器进程
# MaxRequestWorkers: 最大数量的工作线程
# MaxConnectionsPerChild: 最大连接数的一个服务器进程服务
woker实际应用原理
Worker 由主控制进程生成“StartServers”个子进程,每个子进程中包含固定的
ThreadsPerChild线程数,各个线程独立地处理请求。同样, 为了不在请求到来时再生成线程,MinSpareThreads和MaxSpareThreads设置了最少和最多的空闲线程数;
而MaxRequestWorkers 设置了同时连入的clients最大总数。如果现有子进程中的线程总数不能满足负载,控制进程将派生新的子进程
MinSpareThreads和 MaxSpareThreads的最大缺省值分别是75和250。这两个参数对Apache的性能影响并不大,可以按照实际情况相应调节 。
ThreadsPerChild是worker MPM中与性能相关最密切的指令。ThreadsPerChild的最大缺省值是64,如果负载较大,64也是不够的。这时要显式使用 ThreadLimit指令,它的最大缺省值是20000。
Worker模式下所能同时处理的请求总数是由子进程总数乘以ThreadsPerChild 值决定的,应该大于等于MaxRequestWorkers。如果负载很大,现有的子进程数不能满足时,控制进程会派生新的子进程。默认最大的子进程总数是16,加大时 也需要显式声明ServerLimit(最大值是20000)。
需要注意的是,如果显式声明了ServerLimit,那么它乘以 ThreadsPerChild的值必须大于等于MaxRequestWorkers,而且MaxRequestWorkers必须是ThreadsPerChild的整数倍,否则 Apache将会自动调节到一个相应值。
# event MPM
<IfModule mpm_event_module>
StartServers 3
MinSpareThreads 75
MaxSpareThreads 250
ThreadsPerChild 25
MaxRequestWorkers 400
MaxConnectionsPerChild 0
</IfModule>
参数解析
# StartServers:初始数量的服务器进程开始
# MinSpareThreads: 最小数量的工作线程,保存备用
# MaxSpareThreads: 最大数量的工作线程,保存备用
# ThreadsPerChild: 固定数量的工作线程在每个服务器进程
# MaxRequestWorkers: 最大数量的工作线程
# MaxConnectionsPerChild: 最大连接数的一个服务器进程服务
配置安装参数
./configure --prefix=/usr/local/apache2
--enable-rewrite --enable-so --enable-headers
--enable-expires --with-mpm=worker
--enable-modules=most --enable-deflate
参数解析
--prefix=/usr/local/apache2 指定安装路径
--enable-rewrite 提供URL重写规则
--enable-so 激活DSO方式动态安装共享目标模块 这个模块本身不可以用DSO
--enable-headers 提供允许对HTTP请求头的控制
--enable-expires 激活通过配置文件控制HTTP的“Expires:”和“Cache-Control:”头内容,即对网站图片、js、css等内容,提供客户端浏览器缓存的设置。这个是apache调优的一个重要选项之一
--with-mpm=worker 选择工作模式 如 prefork event
--enable-deflate 提供对内容的压缩传输编码支持,一般是html、js、css等内容的站点。使用此参数会打打提高传输速度,提升访问者访问的体验。在生产环境中,这是apache调优的一个重要选项之一
配置文件
1.apahce反向代理
ProxyPass /mirror/foo/ http://backend.example/
ProxyPassReverse /mirror/foo/ http://backend.example/
这个配置会导致对http://example/mirror/foo/bar的本地请求在内部转换为对http://backend.example/bar的代理请求。
这两个指令在Apache服务器中用于调整由反向代理服务器发送的HTTP响应头中的URL。
其主要作用是将后端服务器发送的HTTP重定向响应中的Location、Content-Location和URI头里的URL重写为正确的地址
从而避免在Apache作为反向代理时,后端服务器的HTTP重定向导致请求绕过反向代理的问题
2.vhost.conf
开启前在httpd.conf文件打开vhost模块注释
示例
<VirtualHost *:80> #若是其他端口在此处改相应端口
ServerName www.debug_hh #表示要访问的域名 8080其他端口直接在ip:8080
DocumentRoot D:\wamp\www\managerProject\web\src\backend\web #项目的地址
<Directory "D:\wamp\www\managerProject\web\src\backend\web">
Options +Indexes +FollowSymLinks +MultiViews
AllowOverride All
Order deny,allow
allow from all
</Directory>
</VirtualHost>
参数解析
根目录包含 .htacess 配置文件 url重写规则都在里面,出于安全性考虑,一般根目录AllowOverride属性一般都配置成不允许任何Override ,即
<Directory />
AllowOverride None
</Directory>
对于需要重写的目录
< Directory /myaddrroot/>
AllowOverride FileInfo
< /Directory>
在要支持url rewirte的目录启用 Options FollowSymLinks和AllowOverride All
Alias /py "c:/web/py/"
<Directory "c:/web/py/">
Options Indexes FollowSymLinks
AllowOverride All
Order allow,deny
Allow from all
</Directory>
参数解析
AuthConfig 允许使用所有的权限指令
包括AuthDBMGroupFile AuthDBMUserFile AuthGroupFile AuthName AuthTypeAuthUserFile和Require
FileInfo 允许使用文件控制类型的指令
包括AddEncoding AddLanguage AddType DEfaultType ErrorDocument LanguagePriority
Indexes 允许使用目录控制类型的指令
包括AddDescription AddIcon AddIconByEncoding AddIconByType DefaultIcon DirectoryIndex FancyIndexing HeaderName IndexIgnore IndexOptions ReadmeName
Limit 允许使用权限控制指令。它们包括Allow Deny和Order
Options 允许使用控制目录特征的指令.他们包括Options 和XBitHack
Options 参数解析
All 准许以下除MultiViews以外所有功能
MultiViews 允许多重内容被浏览,如果你的目录下有一个叫做foo.txt的文件,那么你可以通过/foo来访问到它,这对于一个多语言内容的站点比较有用
Indexes 若该目录下无index文件,则准许显示该目录下的文件以供选择
IncludesNOEXEC 准许SSI,但不可使用#exec和#include功能
Includes 准许SSI
FollowSymLinks 在该目录中,服务器将跟踪符号链接。注意,即使服务器跟踪符号链接,它也不会改变用来匹配不同区域的路径名,如果在<Local>;标记内设置,该选项会被忽略
SymLinksIfOwnerMatch 在该目录中仅仅跟踪本站点内的链接
ExecCGI 在该目录下准许使用CGI
注:在前,加 + 代表允许目录浏览;加 – 代表禁止目录浏览。
3.访问限制
Require all granted:表示允许所有主机访问
Require all denied:表示拒绝所有主机访问
Require local:表示仅允许本地主机访问
Require [not] host <主机名或域名列表>:表示允许或拒绝指定主机或域名访问
Require [not] ip <IP地址或网段列表>:表示允许或拒绝指定的IP地址或网段访问
Nginx常用命令大全
nginx -s reopen #日志分割
nginx -s reload #重新加载Nginx配置文件
nginx -s stop #强制停止Nginx服务
nginx -s quit #优雅地停止Nginx服务(即处理完所有请求后再停止服务)
nginx -t #检测配置文件是否有语法错误,然后退出
nginx -?,-h #打开帮助信息
nginx -v #显示版本信息并退出
nginx -V #显示版本和配置选项信息,然后退出
nginx -T #检测配置文件是否有语法错误,转储并退出
nginx -q #在检测配置文件期间屏蔽非错误信息
nginx -p prefix #设置前缀路径(默认是:/usr/share/nginx/)
nginx -c filename #设置配置文件(默认是:/etc/nginx/nginx.conf)
nginx -g directives #设置配置文件外的全局指令
killall nginx #杀死所有nginx进程
Nginx在WIndows下常用命令
启动
直接点击Nginx目录下的nginx.exe 或者 cmd运行start nginx
关闭
nginx -s stop 或者 nginx -s quit
stop表示立即停止nginx,不保存相关信息
quit表示正常退出nginx,并保存相关信息
nginx -s stop 或者 nginx -s quit
nginx -s reload :修改配置后重新加载生效
nginx -s reopen :分割日志
nginx -t -c /path/to/nginx.conf 测试nginx配置文件是否正确
Nginx与Tomcat区别
Nginx和Tomcat是两种不同的技术,它们在应用场景、性能、动态处理能力等方面有所区别
应用场景
Nginx通常用作静态内容服务器或代理服务器,可以将外部请求转发给其他应用服务器,如Tomcat、Django等。而Tomcat则主要用作应用服务器,用于运行Java Web应用程序,如JSP和Servlet。
性能在静态内容处理方面,Nginx能够支持高并发,因为它使用了异步非阻塞的模型,能够轻松处理数以百万级别的并发连接。相比之下,Tomcat在静态内容处理方面可能不如Nginx高效。
配置Tomcat配置相对简单,主要修改server.xml等配置文件来管理。而Nginx的配置更为灵活和强大,包括对HTTP、TCP、UDP等多种协议的支持。
安全性Tomcat和Nginx都提供了SSL/TLS加密等安全性功能,但它们的应用场景和安全侧重点不同。Nginx在流媒体等安全敏感场景中表现更佳,而Tomcat则更侧重于应用层面的安全。
扩展性Tomcat通过插件机制可以实现各种功能,但通常需要与Java技术栈结合使用。而Nginx则通过模块化的设计,能够方便地扩展其功能,包括与PHP、Python等其他语言集成。
动态处理能力。Nginx本身不支持动态处理,如JSP或Servlet,需要依赖其他插件或后端软件(如PHP)来支持动态内容。而Tomcat是一个标准的Servlet和JSP容器,能够处理动态内容。
架构设计。Nginx基于事件驱动架构,使用epoll或kqueue等高性能的网络事件模型。而Tomcat则基于传统的请求-响应模型,每个请求都需要一个线程来处理。
日志管理Tomcat主要记录应用程序级别的日志,而Nginx则提供了更详细的日志记录和访问控制功能。
内存和资源消耗。Nginx在内存和资源消耗方面表现出色,因为它使用了轻量级的设计,能够以较低的资源消耗处理高并发的请求。相比之下,Tomcat在内存和资源消耗方面通常更高,因为它需要更多的资源来运行和处理动态内容。
严格意义上来讲,nginx应该叫做HTTP Server,而tomcat是一个Application Server是一个Servlet/JSO应用的容器。
客户端通过HTTP Server访问服务器上存储的资源(HTML文件,图片文件等),HTTP Server只是把服务器上的文件如实通过HTTP协议传输给客户端。服务器往往是运行在HTTP Server的背后,执行应用,将动态的内容转化为静态的内容之后,通过HTTP Server分发到客户端。
nginx搭配tomcat实现负载均衡
Tomcat简介
Apache Tomcat 是一个免费开源的轻量级Servlet容器,由Apache软件基金会的Jakarta项目提供。它主要用于部署和运行Java Servlet和JavaServer Pages (JSP) 应用程序。
Tomcat因其简单易用、配置灵活以及对最新Java EE标准的良好支持而受到开发者们的喜爱。自1999年发布以来,Tomcat已成为Java Web应用程序开发的标准平台之一。无论是初学者还是经验丰富的开发者,都可以轻松地使用Tomcat来搭建Web服务器环境,进行Java Web应用的开发与测试。
Mac安装Tomcat
首先去官网下载tomcat安装包,tomcat下载链接:https://tomcat.apache/download-80.cgi。
进入tomcat的bin目录,然后运行 ./startup.sh
启动Tomcat
访问http://localhost:8080/
,如果看到Tomcat的默认欢迎页面,说明tomcat启动成功。
启动成功之后,记得先执行./shutdown.sh
来关掉tomcat,不然后面使用IDEA来启动时,会报端口已经被占用错误。
创建Java Web项目并配置Tomcat服务器
创建Java Web项目
本文通过maven来创建web项目,这样后面引入其他工具包会更加方便,注意创建项目的时候要添加webapp相关原型方便后续的Web开发。
zhaozhao
刚创建出来的项目的文件目录如下,是没有java目录的。
首先需要创建出java目录,然后检查文件夹的颜色是否正常
不正常的话,标记一下文件夹,将其标记为源代码目录。
配置Tomcat作为服务器
在IDEA中配置Tomcat服务器,选择Local模式以配置本地安装的Tomcat。
因为我们的tomcat是安装在本地的,所以直接选择Local的方式;如果安装在远程,则选择Remote。
如果Application server没有识别出你所安装的tomcat,就点击右边的Configure按钮,选择上面下载的tomcat所在文件夹,手动指定Tomcat的安装路径。 配置完tomcat作为服务器之后,需要创建Artifact,才可以将项目部署到服务器上面。Application context
一般可以设置为项目名,这个名字的作用是用来隔离不同的项目,后续访问的时候,链接为localhost:8080/项目名
。
配置完Tomcat服务器,就可以启动服务。
出现下面的successfully,说明启动成功。
最后尝试访问网站,看看部署是否成功。
nginx和apache的搭建配置可参考 Mac homebrew搭建php nginx apache mysql环境_homebrew安装php-CSDN博客
使用nginx和tomcat实现反向代理和负载均衡
一、nginx操作的常用命令
使用nginx
操作命令的前提条件:必须进入
nginx
的目录
/usr/local/nginx/sbin
# 查看nginx版本号
./nginx -v
# 关闭nginx
./nginx -s stop
# 开启nginx
./nginx
# 重新加载nginx
./nginx -s reload
nginx配置文件
nginx配置文件由三部分组成第一部分,全局块
从配置文件开始到events块之间的内容,主要会设置一些影响nginx服务器整体运行的配置指令。
比如 word_processes 1;值越大,可以支持的并发处理量也越多。第二部分,events块
events块设计的指令主要影响nginx服务器与用户的网络连接,
比如 worker_connections 1024;支持的最大连接数。第三部分,http块
nginx服务器配置中最频繁的部分
http块也包括http全局块、server块。
二、nginx配置反向代理
反向代理的本质目的:当window浏览器访问192.168.186.128并且端口是80时,nginx会转发到http://127.0.0.1:8080的地址。
首先启动linux虚拟机中的tomcat(进入tomcat的bin目录中,执行./startup.sh文件开启tomcat)
可以访问到
进入nginx
的配置文件中,修改server_name
为linux
本机的ip
地址。
这样子配置以后,当window
浏览器访问192.168.186.128
并且端口是80时,nginx会转发到http://127.0.0.1:8080的地址。
然后就实现了nginx
反向代理。
三、nginx配置反向代理服务器转发到多个服务器
要实现的效果:使用nginx反向代理,根据访问的路径不同跳转到不同的服务端口中。
准备工作:准备两个tomcat服务器,一个8080端口,一个8081端口。
首先把刚才的tomcat进程杀掉
[root@bogon src]# ps -ef | grep tomcat
root 8298 1 0 22:36 pts/0 00:00:04 /usr/local/java/jdk1.8.0_231/bin/java -Djava.util.logging.config.file=/opt/apache-tomcat-7.0.96/conf/logging.properties -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Djdk.tls.ephemeralDHKeySize=2048 -Dignore.endorsed.dirs= -classpath /opt/apache-tomcat-7.0.96/bin/bootstrap.jar:/opt/apache-tomcat-7.0.96/bin/tomcat-juli.jar -Dcatalina.base=/opt/apache-tomcat-7.0.96 -Dcatalina.home=/opt/apache-tomcat-7.0.96 -Djava.io.tmpdir=/opt/apache-tomcat-7.0.96/temp org.apache.catalina.startup.Bootstrap start
root 8949 2973 0 23:17 pts/0 00:00:00 grep --color=auto tomcat
[root@bogon src]# kill 8298
[root@bogon src]# ps -ef | grep tomcat
root 8957 2973 0 23:18 pts/0 00:00:00 grep --color=auto tomcat
然后在/usr/src
目录下新建两个文件夹tomcat8080
和tomcat8081
,使用xftp
分别给这两个文件夹传入tomcat压缩包。
如果上传错误就是用命令chmod 777 文件夹名
赋予权限就可以了。
分别解压
tar -xvf apache-tomcat-7.0.96.tar.gz
启动8080端口的tomcat
启动8081端口的tomcat
,解压之后进入到tomcat
的conf
目录中,编辑server.xml
配置文件
[root@bogon tomcat8081]# ls
apache-tomcat-7.0.96 apache-tomcat-7.0.96.tar.gz
[root@bogon tomcat8081]# cd apache-tomcat-7.0.96/
[root@bogon apache-tomcat-7.0.96]# ls
bin BUILDING.txt conf CONTRIBUTING.md lib LICENSE logs NOTICE README.md RELEASE-NOTES RUNNING.txt temp webapps work
[root@bogon apache-tomcat-7.0.96]# cd conf
[root@bogon conf]# ls
catalina.policy catalina.properties context.xml logging.properties server.xml tomcat-users.xml web.xml
[root@bogon conf]# vim server.xml
首先把这个改成8015端口
再分别改成8081端口和8019端口
然后把8081端口的tomcat也启动起来
[root@bogon bin]# ls
bootstrap.jar catalina-tasks.xml configtest.bat digest.bat setclasspath.sh startup.bat tomcat-native.tar.gz version.bat
catalina.bat commons-daemon.jar configtest.sh digest.sh shutdown.bat startup.sh tool-wrapper.bat version.sh
catalina.sh commons-daemon-native.tar.gz daemon.sh setclasspath.bat shutdown.sh tomcat-juli.jar tool-wrapper.sh
[root@bogon bin]# ./startup.sh
Using CATALINA_BASE: /usr/src/tomcat8081/apache-tomcat-7.0.96
Using CATALINA_HOME: /usr/src/tomcat8081/apache-tomcat-7.0.96
Using CATALINA_TMPDIR: /usr/src/tomcat8081/apache-tomcat-7.0.96/temp
Using JRE_HOME: /usr/local/java/jdk1.8.0_231
Using CLASSPATH: /usr/src/tomcat8081/apache-tomcat-7.0.96/bin/bootstrap.jar:/usr/src/tomcat8081/apache-tomcat-7.0.96/bin/tomcat-juli.jar
Tomcat started.
创建文件夹和测试页面,做测试的准备工作。
分别在两个tomcat的webapps文件夹中新建文件夹;
在8080端口的tomcat的webapps中新建文件夹edu,在edu中新建html文件<h1>8080端口</h1>;
在8081端口的tomcat的webapps中新建文件夹vod,在vod中新建html文件<h1>8081!!</h1>;
然后分别在windows浏览器访问
找到nginx配置文件,进行反向代理配置
[root@bogon vod]# cd /usr/local/nginx/conf
[root@bogon conf]# ls
fastcgi.conf fastcgi_params koi-utf mime.types nginx.conf scgi_params uwsgi_params win-utf
fastcgi.conf.default fastcgi_params.default koi-win mime.types.default nginx.conf.default scgi_params.default uwsgi_params.default
[root@bogon conf]# vim nginx.conf
添加一下配置
说明:监听192.168.186.128:9001
地址,如果后面路径是edu
,转发到http://127.0.0.1:8080地址;如果后面地址vod
,则转发到http://127.0.0.1:8081地址。
然后重新加载nginx,进到/usr/local/nginx/sbin
目录
# 先关掉nginx
./nginx -s stop
# 再开启nginx
./nginx
测试后反向代理就完成了
四,nginx配置负载均衡
实现效果:浏览器地址栏输入http://192.168.186.128/edu/a.html,负载均衡效果,平均到8080端口和8081端口中。
准备工作:
两台tomcat服务器,一个8080端口,一个8081端口,上面已经准备过了。
在两台tomcat的webapps目录中分别都创建edu文件夹,在edu文件夹中新建a.html文件
在nginx的配置文件中进行负载均衡的配置
负载均衡配置
在下面的位置添加以下配置。
在server{}中再加入以下规则
刷新以下浏览器,会访问8081端口的tomcat,一直刷新一直在切换。
这说明nginx把多次请求平均分摊到不同的服务器中,实现了负载均衡。
五、负载均衡的分配服务器策略
第一种:轮询
每个请求按时间顺序逐一分配到不同的后端服务器,如果后端服务器down掉,能自动剔除。
第二种:weight权重
weight代表权重,默认是1,权重越高被分配的客户端越多。
upstream myserver {
server 192.168.186.128:8080 weight=5;
server 192.168.186.128:8080 weight=10;
}
第三种:ip_hash
每个请求按访问ip的hash结果分配,这样每个访客固定访问要给后端服务器,可以解决session共享的问题(单点登录会遇到这个问题)。
upstream myserver {
ip_hash;
server 192.168.186.128:8080;
server 192.168.186.128:8080 ;
}
第四种:fair(第三方)
按后端服务器的响应时间来分配请求,响应时间短的优先分配。
upstream myserver {
server 192.168.186.128:8080;
server 192.168.186.128:8080 ;
fair;
}
nginx使用反向代理实现多站点配置
user nginx;
worker_processes auto;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
# 配置官网的服务器
server {
listen 80;
server_name www.yourwebsite;
location / {
proxy_pass http://backend_server_for_website;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
# 配置后台API的服务器
server {
listen 80;
server_name api.yourwebsite;
location / {
proxy_pass http://backend_server_for_api;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
}
在这个配置中,
www.yourwebsite
用于官网,而api.yourwebsite
用于后台API。两个服务器的后端服务器地址需要替换为实际的后端服务地址(例如:http://127.0.0.1:8080
)。确保在配置文件中替换
backend_server_for_website
和backend_server_for_api
为实际的后端服务器地址。
在应用配置后,记得重新加载或重启Nginx以使配置生效:
检测nginx配置文件
nginx -t #这个命令很重要
重新引入nginx配置文件
sudo nginx -s reload
或者
sudo systemctl reload nginx
单网站单服务器的nginx配置
server {
listen 80; # 监听80端口
server_name www.google google; # 带www域名和不带www域名都指向该网站资源
location / {
root /root/www/google; # 网站的静态资源目录,css,js,image文件等
index index.html; # 网站首页
}
if ( $host != 'www.google'){
rewrite ^(.*) $scheme://www.google$1 permanent; # 重定向到www.google
}
}
多网站单服务器的nginx配置
user root; # 重点,Linux系统中创建Nginx的用户,这里设置为root,拥有文件读取权限
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;
#access_log logs/access.log main;
sendfile on;
#tcp_nopush on;
#keepalive_timeout 0;
keepalive_timeout 65;
#gzip on;
server { # 默认的server,也就是显示Nginx默认界面
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;
}
}
# 以上均为nginx.conf文件的默认配置,不需要更改,直接在下面添加即可
# another virtual host using mix of IP-, name-, and port-based configuration
server {
listen 80;
server_name www.baidu;
location / {
root /root/www/baidu; # 网站的静态资源目录,css,js,image文件等
index index.html; # 网站首页
}
}
server {
listen 80;
server_name baidu;
rewrite ^(.*) $scheme://www.$server_name$1 permanent; # 跳转到www域名下
}
server {
listen 80;
server_name www.google;
location / {
root /root/www/google; # 网站的静态资源目录,css,js,image文件等
index index.html; # 网站首页
}
}
server {
listen 80;
server_name google;
rewrite ^(.*) $scheme://www.$server_name$1 permanent; # 跳转到www域名下
}
}
nginx location配置命令详解
1. 概述
在Web服务器的配置中,Nginx的location指令扮演着至关重要的角色。它不仅是Nginx配置的核心组成部分,更是实现灵活路由和请求处理的关键。location指令允许服务器根据请求的URI执行不同的操作,从而为Web应用提供了强大的URL匹配和处理能力。location指令的主要作用是根据用户请求的URI来决定如何处理这个请求。它可以将不同的请求映射到文件系统的不同路径,或者将请求转发到其他服务器。通过合理配置location,我们可以实现诸如静态文件服务、反向代理、负载均衡等多种功能。
在Nginx配置文件中,location指令通常位于server块内。一个server块可以包含多个location块,每个location块定义了一组特定的URI处理规则。当Nginx接收到一个HTTP请求时,它会根据请求的URI逐一匹配这些location块,直到找到最佳匹配。
location指令的灵活性体现在其多样的匹配方式上。它支持精确匹配、前缀匹配、正则表达式匹配等多种匹配模式。这些不同的匹配模式使得Nginx能够处理各种复杂的URL结构,满足不同Web应用的需求。
此外,location指令还可以与其他Nginx指令配合使用,如proxy_pass、rewrite、try_files等,进一步增强了其功能性。这种组合使用使得Nginx能够实现更复杂的请求处理逻辑,如URL重写、请求重定向、错误页面处理等。
然而,location指令的强大功能也带来了一定的复杂性。正确理解和使用location指令需要对其语法规则、优先级顺序、以及与其他指令的交互有深入的了解。不当的配置可能导致意外的行为,如请求被错误路由或无法访问某些资源。
因此,掌握location指令的用法对于Nginx管理员和Web开发者来说至关重要。通过深入学习location指令的各种用法和最佳实践,我们可以充分发挥Nginx的潜力,构建高效、安全、可扩展的Web应用。
在接下来的章节中,我们将详细探讨location指令的语法、匹配规则、优先级以及各种高级应用,帮助读者全面理解和掌握这一强大的Nginx配置工具。
2.location 指令基础
2.1 location 指令的语法
Nginx中的location指令是配置文件中最常用也最重要的指令之一。它定义了如何处理特定的URL请求,使得服务器能够根据不同的请求路径执行不同的操作。location指令的基本语法如下:
location [修饰符] 匹配模式 {
...
}
在这个语法结构中,"修饰符"是可选的,而"匹配模式"则是必须指定的。大括号内包含了当URL匹配成功时要执行的指令集。
修饰符用于定义location的匹配行为,常见的修饰符包括:
“=”:表示精确匹配。如果找到精确匹配,则立即停止搜索。
“^~”:表示如果该符号后面的字符是最佳匹配,则采用该规则,不再进行后续的正则表达式匹配。
“~”:表示区分大小写的正则匹配。
“~*”:表示不区分大小写的正则匹配。如果没有修饰符,则表示前缀匹配。
匹配模式可以是一个字符串,也可以是一个正则表达式。Nginx会根据请求的URI与这个匹配模式进行比较,以决定是否应用该location块中的配置。
以下是一些location指令的实际例子:
location = / {
...
}
这个例子使用了"=“修饰符,表示精确匹配根路径”/"。
location ^~ /images/ {
...
}
这个例子使用了"^~“修饰符,表示如果请求的URI以”/images/"开头,就会使用这个location块的配置,且不再检查其他正则表达式location。
location ~ \.(gif|jpg|png)$ {
...
}
这个例子使用了"~“修饰符,表示对URI进行区分大小写的正则匹配。它会匹配所有以”.gif"、“.jpg"或”.png"结尾的请求。
location /documents/ {
...
}
这个例子没有使用修饰符,表示对"/documents/"路径进行前缀匹配。
在location块内部,我们可以使用各种Nginx指令来定义如何处理匹配的请求。常见的指令包括:
root:指定请求的根目录。
index:指定默认文件。
proxy_pass:将请求转发到另一个服务器。
try_files:按顺序检查文件是否存在。
return:返回特定的HTTP状态码。
例如
location /images/ {
root /data;
try_files $uri $uri/ =404;
}
这个配置表示,对于以"/images/“开头的请求,Nginx会在”/data/images/"目录下查找对应的文件。如果文件不存在,则返回404错误。
理解location指令的语法是配置Nginx服务器的基础。通过灵活运用不同的修饰符和匹配模式,我们可以精确控制Nginx如何处理不同的URL请求,从而实现复杂的Web服务器功能。
2.2 location 指令的匹配规则
Nginx的location指令使用一套复杂而精密的匹配规则来决定如何处理incoming请求。理解这些匹配规则对于正确配置和优化Nginx服务器至关重要。
location指令的匹配过程可以概括为以下几个步骤:
首先,Nginx会检查所有的精确匹配规则(使用"="修饰符的location)。如果找到一个精确匹配,Nginx会立即停止搜索并使用该location块中的配置来处理请求。
如果没有找到精确匹配,Nginx会继续检查前缀匹配规则。在这个阶段,Nginx会记住最长的匹配,并继续搜索。如果遇到一个使用"^~"修饰符的location,且该location是最长匹配,Nginx会立即停止搜索并使用该location。
如果仍然没有找到匹配,或者找到的最长匹配没有"^~"修饰符,Nginx会继续进行正则表达式匹配。正则表达式匹配按照它们在配置文件中出现的顺序进行检查。一旦找到第一个匹配的正则表达式location,Nginx就会停止搜索并使用该location。
如果没有匹配的正则表达式location,Nginx会使用之前记住的最长前缀匹配的location。
这个匹配过程看似复杂,但在实际应用中非常强大和灵活。让我们通过一些具体的例子来深入理解这个过程:
假设我们有以下location配置:
location = / {
# 精确匹配"/"
}
location / {
# 匹配任何以"/"开头的请求
}
location /documents/ {
# 匹配任何以"/documents/"开头的请求
}
location ^~ /images/ {
# 匹配任何以"/images/"开头的请求
}
location ~* \.(gif|jpg|jpeg)$ {
# 匹配任何以gif、jpg或jpeg结尾的请求
}
对于请求/,会精确匹配到第一个location。
对于请求/index.html,会匹配到第二个location。
对于请求/documents/document.html,会匹配到第三个location。
对于请求/images/1.gif,会匹配到第四个location。尽管它也满足最后一个正则表达式location,但由于"^~"修饰符的存在,Nginx会停止在第四个location。
对于请求/documents/1.jpg,会匹配到最后一个location。虽然它也满足第三个location,但正则表达式匹配的优先级更高。
理解这些匹配规则后,我们就可以更好地组织我们的location块。例如,我们可以将更具体的规则放在前面,将更通用的规则放在后面。我们也可以使用"^~"修饰符来确保某些特定的前缀匹配不会被后续的正则表达式匹配覆盖。
此外,在编写location匹配规则时,我们还需要注意以下几点:
路径匹配不包含查询字符串。例如,对于请求/index.html?param=value,location只会尝试匹配/index.html部分。
location中的正则表达式支持捕获组,可以在后续的配置中使用。例如:
location ~ ^/users/(.+)/files/(.+)$ {
add_header X-User $1;
add_header X-File $2;
}
对于请求/users/john/files/document.pdf,这个配置会添加两个响应头:X-User: john和X-File: document.pdf。
Nginx的location匹配是大小写敏感的。如果需要进行大小写不敏感的匹配,可以使用"~*"修饰符。
通过深入理解这些匹配规则,我们可以更好地控制Nginx如何处理不同的请求,从而构建更高效、更灵活的Web服务器配置。
2.3 location 指令的优先级
在Nginx配置中,location指令的优先级是一个关键概念,它决定了当多个location块可能匹配同一个请求时,Nginx将选择哪一个location块来处理该请求。理解这个优先级机制对于正确配置Nginx服务器至关重要。
Nginx的location指令优先级从高到低排序如下:
首先是精确匹配(=)。当Nginx遇到一个与请求URI完全相同的精确匹配location时,它会立即选择该location并停止搜索。这是最高优先级的匹配方式,通常用于处理特定的、明确的请求路径。例如:
location = /login { # 处理登录请求 }
这个location将精确匹配/login路径,而不会匹配/login/或/login.html。
其次是前缀匹配(~)。如果找到一个前缀匹配的location,且该location使用了~修饰符,Nginx会立即停止搜索并选择该location,即使后面可能有更精确的正则表达式匹配。这个修饰符常用于防止正则表达式location覆盖某些特定的前缀匹配。例如:
location ^~ /static/ { # 处理静态文件请求 }
这个location会匹配所有以/static/开头的请求,并且不会被后续的正则表达式location覆盖。
接下来是正则表达式匹配(~ 和 *)。**Nginx**会按照配置文件中正则表达式location出现的顺序进行匹配。一旦找到第一个匹配的正则表达式location,**Nginx**就会停止搜索并使用该location。区分大小写的正则表达式()优先于不区分大小写的正则表达式(~*)。例如:
location ~ \.php$ { # 处理PHP文件请求 } location ~* \.(jpg|jpeg|png|gif)$ { # 处理图片文件请求 }
最后是普通前缀匹配(无修饰符)。如果之前的匹配都未成功,Nginx会选择最长的匹配前缀location。这是最低优先级的匹配方式,通常用作默认处理或作为一个通用的回退选项。例如:
location / { # 处理所有其他请求 }
值得注意的是,在实际配置中,这些不同优先级的location可能会相互影响。例如,考虑以下配置:
location = /api {
# 精确匹配/api
}
location ^~ /api/ {
# 前缀匹配/api/
}
location ~ ^/api/.*\.json$ {
# 正则匹配以.json结尾的/api/请求
}
location /api/ {
# 普通前缀匹配/api/
}
在这个配置中,对于请求/api,会使用第一个location(精确匹配)。
对于请求/api/users,会使用第二个location(^~前缀匹配),即使第三个location(正则匹配)可能也符合条件。
对于请求/api/data.xml,会使用第二个location,而不是第四个location。
理解这种优先级机制可以帮助我们更好地组织Nginx配置,避免潜在的冲突和混淆。
在实际应用中,我们通常会将更具体的规则放在前面,将更通用的规则放在后面。
同时,我们也可以利用不同的修饰符来精确控制Nginx的匹配行为,从而实现复杂的路由和请求处理逻辑。
此外,在处理location优先级时,还需要注意一些细节。例如,正则表达式location的顺序很重要,因为Nginx会使用第一个匹配的正则表达式location。
如果有多个可能匹配的正则表达式location,我们需要仔细考虑它们的顺序。
同时,使用^~修饰符可以有效地防止某些路径被正则表达式location意外匹配。这在处理静态文件或特定的API路径时特别有用。
3.location 匹配修饰符
Nginx的location指令支持多种匹配修饰符,这些修饰符决定了Nginx如何解释和匹配请求的URI。理解这些修饰符的作用和优先级对于正确配置Nginx服务器至关重要。
本节将详细介绍四种主要的location匹配修饰符:精确匹配"=“、前缀匹配”^“、正则匹配”“和”~*",以及普通匹配(无修饰符)。
3.1 精准匹配 =
精确匹配是Nginx location指令中优先级最高的匹配方式。当使用"="修饰符时,Nginx会将请求的URI与指定的模式进行精确比较。如果匹配成功,Nginx将立即停止搜索其他location块,并使用该location的配置来处理请求。
精确匹配通常用于处理特定的、明确的请求路径。例如:。
location = / { # 仅匹配根路径"/" } location = /login { # 仅匹配"/login"路径 }
在这个配置中,第一个location块只会匹配根路径"/“,而不会匹配”/index.html"或任何其他路径。第二个location块只会匹配"/login"路径,而不会匹配"/login/“或”/login.html"。
使用精确匹配可以提高Nginx的处理效率,因为一旦找到匹配,Nginx就不需要继续搜索其他可能的匹配。这对于频繁访问的特定URI特别有用。
3.2 前缀匹配 ^~
前缀匹配使用"^~“修饰符,它的优先级仅次于精确匹配。当Nginx遇到使用”^~"修饰符的location时,如果该location是最长的前缀匹配,Nginx会立即停止搜索并选择该location,即使后面可能存在更精确的正则表达式匹配。
这个修饰符常用于防止正则表达式location覆盖某些特定的前缀匹配。例如:
location ^~ /static/ { # 处理所有以"/static/"开头的请求 }
在这个配置中,所有以"/static/"开头的请求都会被这个location处理,而不会被后续的正则表达式location匹配。这对于处理静态文件特别有用,可以避免不必要的正则表达式匹配,从而提高性能。
3.3 正则匹配 ~ 和 ~*
在 Nginx的location配置中,正则表达式匹配是一种强大而灵活的匹配方式。
它允许我们使用复杂的模式来匹配 URL,从而实现更精细的请求处理。
Nginx提供了两种正则表达式匹配修饰符:~ 和 ~*。
修饰符用于区分大小写的正则表达式匹配。当使用这个修饰符时, Nginx会严格按照大小写来匹配 URL。例如location ~ \.php$ { fastcgi_pass unix:/var/run/php/php7.4-fpm.sock; fastcgi_index index.php; include fastcgi_params; }
这个配置会匹配所有以".php"结尾的URL,但不会匹配".PHP"或".pHp"。这种严格匹配在处理特定文件类型时非常有用,可以确保只有正确的文件扩展名才会被处理。
3.3.1 location引入PHP文件参数解析
1.location ~ .php$ { … }:这个 location 块使用正则表达式匹配所有以 .php 结尾的文件。
2.include snippets/fastcgi-php.conf;:包含一个外部配置文件,通常这个文件包含了处理 PHP 文件所需的 FastCGI 参数。
3.fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;:指定 FastCGI 传递的目标,这里是 PHP-FPM 监听的 Unix Socket 文件。
~* 修饰符用于不区分大小写的正则表达式匹配。使用这个修饰符时,Nginx会忽略大小写差异。例如:
location ~* \.(gif|jpg|jpeg|png|ico)$ { expires 30d; add_header Cache-Control "public, no-transform"; }
这个配置会匹配所有以".gif"、“.jpg”、“.jpeg”、“.png"或”.ico"结尾的URL,不论这些扩展名是大写还是小写。这在处理图片文件时特别有用,因为文件扩展名的大小写可能会有所不同。
正则表达式匹配的优势在于其灵活性。我们可以使用各种正则表达式语法来精确控制匹配行为。例如:
location ~ ^/api/v[0-9]+/ { proxy_pass http://backend; }
这个配置会匹配所有以"/api/v"开头,后面跟着一个或多个数字,再跟着"/"的URL。这可以用来处理不同版本的API请求。
在使用正则表达式匹配时,我们还可以利用捕获组来提取URL中的特定部分。例如:
location ~ ^/users/(\d+)/profile$ { set $user_id $1; proxy_pass http://user_service; proxy_set_header X-User-ID $user_id; }
这个配置会匹配形如"/users/123/profile"的URL,并将用户ID(在这个例子中是"123")捕获到变量$1中。然后,我们可以使用这个变量来设置自定义头部。
需要注意的是,正则表达式匹配在Nginx的location匹配顺序中具有较高的优先级。一旦找到匹配的正则表达式location,Nginx就会停止搜索并使用该location。因此,在配置多个正则表达式location时,我们需要仔细考虑它们的顺序。
此外,过度使用复杂的正则表达式可能会影响Nginx的性能。对于频繁访问的路径,使用前缀匹配或精确匹配可能会更高效。
正则表达式匹配还可以与其他Nginx指令结合使用,以实现更复杂的功能。例如,我们可以结合使用正则表达式location和rewrite指令来实现URL重写:
location ~ ^/old-api/(.*)$ { rewrite ^/old-api/(.*)$ /new-api/$1 last; }
这个配置会将所有以"/old-api/“开头的请求重写为”/new-api/"开头的新URL。
正则表达式匹配(~ 和 ~*)为Nginx的location配置提供了强大的灵活性。通过合理使用这些修饰符,我们可以精确控制Nginx如何处理不同的URL请求,从而实现复杂的路由逻辑和请求处理。
然而,在使用时也需要注意性能影响和配置复杂性,确保正则表达式匹配与其他location配置协调一致,以构建高效、可维护的Nginx服务器配置。
3.3.2 nginx常见正则匹配符号
1:^: 匹配字符串的开始位置;
2:$:匹配字符串的结束位置 ;
3:~ 为区分大小写匹配;
4:~* 为不区分大小写匹配;
5:!~和!~*分别为区分大小写不匹配及不区分大小写不匹配;
6:.* .匹配任意字符,*匹配数量0到正无穷;
7:\. 斜杠用来转义,\.匹配 .;
8:(值1|值2|值3|值4):或匹配模式,例:(jpg|gif|png|bmp)匹配jpg或gif或png或bmp;
9:i不区分大小写
3.3.3 文件及目录匹配
- -f和!-f用来判断是否存在文件;
- -d和!-d用来判断是否存在目录;;
- -e和!-e用来判断是否存在文件或目录;
- -x和!-x用来判断文件是否可执行。
3.4 普通匹配 (无修饰符)
普通匹配是最基本的location匹配方式,它不使用任何修饰符。普通匹配执行前缀匹配,但其优先级最低。如果请求URI与多个普通匹配location相匹配,Nginx会选择最长的匹配。
例如:
location / {
# 匹配所有请求
}
location /api/ {
# 匹配所有以"/api/"开头的请求
}
在这个配置中,对于请求"/api/users",Nginx会选择第二个location,因为它是最长的匹配。对于请求"/index.html",Nginx会选择第一个location。
普通匹配通常用作默认处理或作为一个通用的回退选项。它们常常放在配置文件的末尾,用于处理所有未被其他更具体的location匹配的请求。
理解这些不同的匹配修饰符及其优先级对于正确配置Nginx服务器至关重要。通过合理使用这些修饰符,我们可以创建灵活、高效的Nginx配置,精确控制如何处理不同的HTTP请求。在实际应用中,我们通常会结合使用多种匹配方式,以满足复杂的路由和请求处理需求。
3.5 提醒:location / 和 location = / 不同
千万需要注意,在 Nginx 配置中,location /
和 location = /
虽然看起来相似,但它们的行为有着重要的区别:
匹配范围:
location / 使用前缀匹配,会匹配所有以 / 开头的请求,包括 /index.html、/about、/images/logo.png 等。
location = / 使用精确匹配,只会匹配根路径 /,不会匹配其他路径。
优先级:location = / 的优先级高于 location /。
当请求为根路径 / 时,location = / 会被优先选择。
性能影响:对于根路径请求,location = / 通常会有更好的性能,因为 Nginx 可以立即停止搜索其他 location 块。
常见用途:location / 常用于设置默认的处理规则或作为回退选项。
location = / 常用于专门处理根路径请求,如设置网站首页。
示例配置:
location = / {
# 只处理根路径请求
try_files /index.html =404;
}
location / {
# 处理所有其他请求
try_files $uri $uri/ /index.html;
}
在这个配置中,根路径请求会由第一个 location 块处理,而所有其他请求会由第二个 location 块处理。理解这两种 location 指令的区别可以帮助你更精确地控制 Nginx 的路由行为,优化服务器性能。
4.location 嵌套
在Nginx配置中,location指令不仅可以独立使用,还可以进行嵌套。location嵌套是一种强大的功能,它允许我们创建更复杂、更精细的URL匹配和处理逻辑。通过合理使用location嵌套,我们可以实现更灵活的请求路由和更高效的配置管理。
4.1 嵌套的基本概念
location嵌套指的是在一个location块内部再定义其他location块。这种嵌套结构使得我们可以为某个URL路径定义一般规则,然后在其内部为特定的子路径定义更具体的规则。
嵌套的location遵循与外层location相同的匹配规则和优先级。当一个请求匹配到外层location时,Nginx会继续在其内部的嵌套location中寻找更精确的匹配。
基本的嵌套结构如下:
location /parent/ { # 父级location的配置 location /parent/child/ { # 子级location的配置 } }
在这个例子中,对于以
/parent/
开头的请求,Nginx首先会应用父级location的配置。如果请求的URL进一步匹配/parent/child/
,那么子级location的配置将会被应用,并覆盖父级location中的相关设置。
4.2 嵌套的使用场景
4.2.1 细化静态文件处理
我们可以在处理静态文件的location中嵌套其他location,为不同类型的文件设置特定的处理规则。例如:
location /static/ { root /var/www/static; expires 30d; location ~* \.(css|js)$ { expires 7d; } location ~* \.(jpg|jpeg|png|gif)$ { expires 90d; } }
在这个配置中,所有静态文件默认有30天的过期时间,但CSS和JS文件的过期时间被设置为7天,而图片文件的过期时间则被设置为90天。
4.2.2 精细化api路由
对于复杂的API结构,我们可以使用嵌套location来创建更精确的路由规则。例如:
location /api/ { proxy_pass http://backend; location /api/v1/ { proxy_pass http://backend-v1; } location /api/v2/ { proxy_pass http://backend-v2; } }
这个配置将所有API请求代理到后端服务器,但对于v1和v2版本的API,分别代理到不同的后端服务器。
4.2.3 错误处理
我们可以在location中嵌套其他location来处理特定的错误情况。例如:
location / { try_files $uri $uri/ =404; location = /404.html { internal; root /var/www/error_pages; } }
这个配置在主location中定义了一个嵌套的location来处理404错误,将其指向一个特定的错误页面
参数解析
1.error_page 404 /404.html;:定义当发生 404 错误时,Nginx 应该返回哪个页面。
2.location = /404.html { … }:这个 location 块精确匹配 /404.html 路径。
3.root /var/www/html;:设置 /404.html 文件的根目录,因为这是一个内部重定向,所以需要明确指定根目录。
4.internal;:标记这个 location 块只能从内部重定向访问,而不能直接通过外部请求访问。
5.location 与其他指令的配合
Nginx的location指令虽然强大,但它真正发挥作用是在与其他指令配合使用时。通过与其他指令的组合,我们可以实现更复杂的Web服务器功能,如反向代理、URL重写、文件查找等。本章将详细探讨location指令与三个常用指令的配合使用:proxy_pass、rewrite和try_files。
5.1 与proxy_pass 配合使用
proxy_pass指令是Nginx中用于设置代理服务器的指令。当与location指令配合使用时,它可以将匹配特定URL模式的请求转发到其他服务器。这种配置在实现反向代理、负载均衡等场景中非常有用。
基本语法
location /path {
proxy_pass http://backend;
}
在这个配置中,所有匹配/path
的请求都会被转发到http://backend
服务器。
proxy_pass指令的行为会因为是否在URL末尾添加斜杠而有所不同。例如:
location /api/ { proxy_pass http://backend/; }
在这个配置中,请求
/api/users
会被代理到http://backend/users
。
而如果配置如下:
location /api/ { proxy_pass http://backend; }
请求
/api/users
会被代理到http://backend/api/users
。
我们还可以在proxy_pass中使用变量:
location ~ ^/api/(?<version>v\d+)/ { proxy_pass http://backend/$version$request_uri; }
这个配置会将请求
/api/v1/users
代理到http://backend/v1/api/v1/users
。
在使用proxy_pass时,我们通常还会设置一些额外的代理相关指令,如:
location /api/ {
proxy_pass http://backend;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
这些额外的指令可以确保后端服务器接收到正确的请求头信息。
5.1.1 proxy_pass 命令参数解析
1.proxy_pass http://backend_server;:将所有匹配的请求代理到名为 backend_server 的后端服务器。通常,backend_server 需要在 http 或 upstream 块中定义。
2.proxy_set_header Host $host;:设置代理请求的 Host 头部为客户端的原始请求中的 Host 值。
3.proxy_set_header X-Real-IP $remote_addr;:设置 X-Real-IP 头部为客户端的 IP 地址。
4.proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;:设置 X-Forwarded-For 头部,这是一个用于标识请求来源的链式头部,可以追踪请求穿过多个代理的路径。
5.proxy_set_header X-Forwarded-Proto $scheme;:设置 X-Forwarded-Proto 头部为请求使用的协议(http 或 https)。
6.proxy_pass http://backend_server; 转发到后端服务器,不带 URI
7.proxy_pass http://backend_server/anotherpath/;转发到后端服务器,并带上 URI
8.proxy_pass http://$host:$server_port;使用变量作为代理服务器地址
9.proxy_method GET;转发时保持请求方法
10.proxy_connect_timeout 10s;设置代理连接的超时时间
11.proxy_read_timeout 10s;设置代理读取响应的超时时间:
5.2 与rewrite 配合使用
rewrite指令用于修改请求URI。当与location指令配合使用时,它可以在将请求发送到新位置之前对URI进行重写。这在URL重定向、规范化URL等场景中非常有用。
基本语法如下:
location /old-path {
rewrite ^/old-path(.*)$ /new-path$1 last;
}
在这个配置中,所有以/old-path
开头的请求都会被重写为以/new-path
开头。
rewrite指令的最后一个参数(如last、break、redirect、permanent)决定了重写后的行为:
"last"表示重写后的URI将重新进行位置匹配。
"break"表示重写后停止处理后续rewrite指令。
"redirect"表示返回302临时重定向。
"permanent"表示返回301永久重定向。
例如,实现URL规范化:
location / { rewrite ^([^.]*[^/])$ $1/ permanent; }
这个配置会将不以斜杠结尾的URL重定向到以斜杠结尾的URL。
我们还可以结合正则表达式捕获组来实现更复杂的重写:
location ~* ^/blog/(\d{4})/(\d{2})/(\d{2})/(.*)$ { rewrite ^/blog/(\d{4})/(\d{2})/(\d{2})/(.*)$ /posts/$1-$2-$3-$4 last; }
这个配置会将形如
/blog/2023/05/20/my-post
的URL重写为/posts/2023-05-20-my-post
。
5.3 与try_files 配合使用
try_files指令用于按顺序检查文件是否存在,并使用第一个找到的文件进行请求处理。如果所有指定的文件都不存在,它会使用最后一个参数作为回退。
这个指令在处理静态文件和实现URL回退机制时非常有用。
基本语法如下:
location / {
try_files $uri $uri/ /index.html;
}
在这个配置中,Nginx首先尝试提供与请求URI匹配的文件。如果文件不存在,它会查找同名目录。如果目录也不存在,它会回退到提供/index.html
文件。
try_files指令对于实现单页应用(SPA)的路由非常有用:
location / { try_files $uri $uri/ @backend; } location @backend { proxy_pass http://backend; }
在这个配置中,如果请求的文件不存在,Nginx会将请求代理到后端服务器。
try_files还可以用于实现简单的负载均衡:
location / { try_files /app1$uri /app2$uri @proxy; } location @proxy { proxy_pass http://backend; }
这个配置首先尝试从两个不同的应用目录提供文件,如果都失败了,则将请求代理到后端服务器。
通过将location指令与proxy_pass、rewrite和try_files等指令配合使用,我们可以构建出功能强大、灵活的Nginx配置。这些组合使得Nginx能够处理各种复杂的Web服务场景,从简单的静态文件服务到复杂的反向代理和URL重写。在实际应用中,我们常常需要根据具体需求,灵活运用这些指令的组合,以实现所需的服务器行为。
6.location 的高级应用
Nginx的location指令不仅可以用于基本的URL匹配和请求处理,还可以应用于多种高级场景。本章将深入探讨location在静态文件处理、反向代理和URL重写这三个高级应用中的使用方法和最佳实践。
6.1 location 用于静态文件处理
在Web服务器配置中,高效处理静态文件是一个常见且重要的需求。Nginx的location指令可以很好地满足这一需求,通过合理配置,我们可以实现高性能的静态文件服务。
首先,我们可以使用location指令来匹配特定类型的静态文件:
location ~* \.(jpg|jpeg|png|gif|ico|css|js)$ { root /var/www/static; expires 30d; add_header Cache-Control "public, no-transform"; }
这个配置使用正则表达式匹配常见的静态文件类型。对于匹配的请求,Nginx会在/var/www/static目录中查找文件。同时,我们设置了30天的过期时间,并添加了缓存控制头,以提高客户端缓存效率。
对于不同类型的静态文件,我们可能需要不同的处理策略。例如,我们可以为CSS和JavaScript文件设置不同的缓存策略:
location ~* \.css$ { root /var/www/static; expires 7d; add_header Cache-Control "public, must-revalidate"; } location ~* \.js$ { root /var/www/static; expires 1d; add_header Cache-Control "public, must-revalidate"; }
这里,我们为CSS文件设置了7天的过期时间,而JavaScript文件则设置为1天。这种差异化的策略可以根据文件更新频率来优化缓存效果。
在处理静态文件时,我们还可以使用try_files指令来实现更灵活的文件查找逻辑:
location /images/ { root /var/www/static; try_files $uri $uri/ /images/default.jpg; }
这个配置首先尝试提供请求的文件,如果文件不存在,则查找同名目录,最后回退到默认图片。这种方法可以有效处理文件缺失的情况。
对于大文件的处理,我们可以使用sendfile和tcp_nopush指令来优化传输:
location /downloads/ { root /var/www/files; sendfile on; tcp_nopush on; tcp_nodelay on; keepalive_timeout 65; }
这些指令可以显著提高大文件传输的效率,特别是在处理视频或大型文档下载时。
6.2 location 用于反向代理
反向代理是Nginx的一个重要应用场景,而location指令在配置反向代理时扮演着关键角色。通过location,我们可以精确控制哪些请求应该被代理,以及如何代理这些请求。
基本的反向代理配置如下:
location /api/ {
proxy_pass http://backend_server;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
这个配置将所有以/api/
开头的请求代理到backend_server
。同时,我们设置了一些重要的代理头,以确保后端服务器能够获得正确的客户端信息。
对于不同的API版本,我们可以使用不同的location块来路由请求:
location /api/v1/ { proxy_pass http://backend_v1; } location /api/v2/ { proxy_pass http://backend_v2; }
这种配置允许我们将不同版本的API请求路由到不同的后端服务器,便于实现API的版本控制。
在某些情况下,我们可能需要修改代理请求的路径。这可以通过在proxy_pass指令中指定路径来实现:
location /old_api/ { proxy_pass http://backend/new_api/; }
这个配置会将
/old_api/users
的请求代理到http://backend/new_api/users
,实现了路径的重写。
对于WebSocket连接,我们需要额外的配置来支持长连接:
location /ws/ { proxy_pass http://websocket_server; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; }
这个配置允许WebSocket连接通过Nginx代理到后端的WebSocket服务器。
6.2.1 长连接和短连接详解
在nginx反向代理多台服务器时,会产生大量短连接,大致请求路径为client -> nginx -> web 服务器,由于每台机器上混布了多个web服务并通过nginx反向代理统一分发请求,在服务升级的时候经常出现端口被占用的情况。系统会经常存在过多的time_wait状态。
统计命令如下
netstat (性能一般)
netstat -n | awk '/^tcp/ {++state[$NF]} END {for(key in state) print key,"\t",state[key]}'
ss命令(性能较高)
ss -s
显示
Total: 4122 (kernel 0)
TCP: 37241 (estab 3157, closed 33193, orphaned 858, synrecv 0, timewait 33176/0), ports 0
Transport Total IP IPv6
* 0 - -
RAW 1 1 0
UDP 4 4 0
TCP 4048 4048 0
INET 4053 4053 0
FRAG 0 0 0
time_wait状态的产生机制
IME_WAIT状态是在tcp断开链接时产生的,因为TCP连接是双向的,所以在关闭连接的时候,两个方向各自都需要关闭。先发FIN包的一方执行的是主动关闭;后发FIN包的一方执行的是被动关闭。主动关闭的一方会进入TIME_WAIT状态,并且在此状态停留两倍的MSL时长
MSL指的是报文段的最大生存时间,如果报文段在网络活动了MSL时间,还没有被接收,那么会被丢弃。关于MSL的大小,RFC 793协议中给出的建议是两分钟,不过实际上不同的操作系统可能有不同的设置,以Linux为例,通常是半分钟,两倍的MSL就是一分钟,也就是60秒,并且这个数值是硬编码在内核中的,也就是说除非你重新编译内核,否则没法修改它。
TIME_WAIT状态存在的必要性。虽然双方都同意关闭连接了,而且握手的4个报文也都协调和发送完毕,按理可以直接回到CLOSED状态(就好比从SYN_SEND状态到ESTABLISH状态那样);但是因为我们必须要假想网络是不可靠的,你无法保证你最后发送的ACK报文会一定被对方收到,比如丢包或者延迟到达,因此对方处于LAST_ACK状态下的SOCKET可能会因为超时未收到ACK报文,而重发FIN报文,所以这个TIME_WAIT状态的作用就是用来重发可能丢失的ACK报文,并保证于此。
简单说timewait之所以等待2MSL的时长,是为了避免因为网络丢包或者网络延迟而造成的tcp传输不可靠,而这个time_wait状态则可以最大限度的提升网络传输的可靠性。
TIME_WAIT状态过多的危害
TIME_WAIT状态是TCP链接中正常产生的一个状态,但凡事都有利弊,TIME_WAIT状态过多会存在以下的问题:
(1)在socket的TIME_WAIT状态结束之前,该socket所占用的本地端口号将一直无法释放
(2)在高并发(每秒几万qps)并且采用短连接方式进行交互的系统中运行一段时间后,系统中就会存在大量的time_wait状态,如果time_wait状态把系统所有可用端口 都占完了且尚未被系统回收时,就会出现无法向服务端创建新的socket连接的情况。此时系统几乎停转,任何链接都不能建立。
(3)大量的time_wait状态也会系统一定的fd,内存和cpu资源,当然这个量一般比较小,并不是主要危害
优化time_wait问题
方式一:调整系统内核参数
修改/etc/sysctl.conf文件,一般涉及下面的几个参数:
net.ipv4.tcp_syncookies = 1 表示开启SYN Cookies。当出现SYN等待队列溢出时,启用cookies来处理,可防范少量SYN攻击,默认为0,表示关闭; net.ipv4.tcp_tw_reuse = 1 表示开启重用。允许将TIME-WAIT sockets重新用于新的TCP连接,默认为0,表示关闭; net.ipv4.tcp_tw_recycle = 1 表示开启TCP连接中TIME-WAIT sockets的快速回收,默认为0,表示关闭。 net.ipv4.tcp_fin_timeout = 修改系统默认的 TIMEOUT 时间 net.ipv4.tcp_max_tw_buckets = 5000 表示系统同时保持TIME_WAIT套接字的最大数量,(默认是18000). 当TIME_WAIT连接数量达到给定的值时,所有的TIME_WAIT连接会被立刻清除,并打印警告信息。但这种粗暴的清理掉所有的连接,意味着有些连接并没有成功等待2MSL,就会造成通讯异常。一般不建议调整 net.ipv4.tcp_timestamps = 1(默认即为1)60s内同一源ip主机的socket connect请求中的timestamp必须是递增的。也就是说服务器打开了 tcp_tw_reccycle了,就会检查时间戳,如果对方发来的包的时间戳是乱跳的或者说时间戳是滞后的,那么服务器就会丢掉不回包,现在很多公司都用LVS做负载均衡,通常是前面一台LVS,后面多台后端服务器,这其实就是NAT,当请求到达LVS后,它修改地址数据后便转发给后端服务器,但不会修改时间戳数据,对于后端服务器来说,请求的源地址就是LVS的地址,加上端口会复用,所以从后端服务器的角度看,原本不同客户端的请求经过LVS的转发,就可能会被认为是同一个连接,加之不同客户端的时间可能不一致,所以就会出现时间戳错乱的现象,于是后面的数据包就被丢弃了,具体的表现通常是是客户端明明发送的SYN,但服务端就是不响应ACK,还可以通过下面命令来确认数据包不断被丢弃的现象,所以根据情况使用 其他优化: net.ipv4.ip_local_port_range = 1024 65535 增加可用端口范围,让系统拥有的更多的端口来建立链接,这里有个问题需要注意,对于这个设置系统就会从1025~65535这个范围内随机分配端口来用于连接,如果我们服务的使用端口比如8080刚好在这个范围之内,在升级服务期间,可能会出现8080端口被其他随机分配的链接给占用掉,这个原因也是文章开头提到的端口被占用的另一个原因 net.ipv4.ip_local_reserved_ports = 7005,8001-8100 针对上面的问题,我们可以设置这个参数来告诉系统给我们预留哪些端口,不可以用于自动分配。
优化完内核参数后,可以执行sysctl -p命令,来激活上面的设置永久生效
方式二:调整短链接为长链接
短连接和长连接工作方式的区别:
短连接 连接->传输数据->关闭连接 HTTP是无状态的,浏览器和服务器每进行一次HTTP操作,就建立一次连接,但任务结束就中断连接。 也可以这样说:短连接是指SOCKET连接后发送后接收完数据后马上断开连接。
长连接 连接->传输数据->保持连接 -> 传输数据-> 。。。->关闭连接。 长连接指建立SOCKET连接后不管是否使用都保持连接,但安全性较差。
从区别上可以看出,长连接比短连接从根本上减少了关闭连接的次数,减少了TIME_WAIT状态的产生数量,在高并发的系统中,这种方式的改动非常有效果,可以明显减少系统TIME_WAIT的数量。
当使用nginx作为反向代理时,为了支持长连接,需要做到两点:
从client到nginx的连接是长连接
从nginx到server的连接是长连接
1、保持和client的长连接:
默认情况下,nginx已经自动开启了对client连接的keep alive支持(同时client发送的HTTP请求要求keep alive)。一般场景可以直接使用,但是对于一些比较特殊的场景,还是有必要调整个别参数(keepalive_timeout和keepalive_requests)。
http { keepalive_timeout 120s 120s; keepalive_requests 10000; }
keepalive_timeout: 第一个参数:设置keep-alive客户端连接在服务器端保持开启的超时值(默认75s);值为0会禁用keep-alive客户端连接;
第二个参数:可选、在响应的header域中设置一个值“Keep-Alive: timeout=time”;通常可以不用设置;
keepalive_requests:keepalive_requests指令用于设置一个keep-alive连接上可以服务的请求的最大数量,当最大请求数量达到时,连接被关闭。默认是100。这个参数的真实含义,是指一个keep alive建立之后,nginx就会为这个连接设置一个计数器,记录这个keep alive的长连接上已经接收并处理的客户端请求的数量。如果达到这个参数设置的最大值时,则nginx会强行关闭这个长连接,逼迫客户端不得不重新建立新的长连接。
大多数情况下当QPS(每秒请求数)不是很高时,默认值100凑合够用。但是,对于一些QPS比较高(比如超过10000QPS,甚至达到30000,50000甚至更高) 的场景,默认的100就显得太低。
简单计算一下,QPS=10000时,客户端每秒发送10000个请求(通常建立有多个长连接),每个连接只能最多跑100次请求,意味着平均每秒钟就会有100个长连接因此被nginx关闭。同样意味着为了保持QPS,客户端不得不每秒中重新新建100个连接。因此,就会发现有大量的TIME_WAIT的socket连接(即使此时keep alive已经在client和nginx之间生效)。因此对于QPS较高的场景,非常有必要加大这个参数,以避免出现大量连接被生成再抛弃的情况,减少TIME_WAIT。
2、保持和server的长连接
为了让nginx和后端server(nginx称为upstream)之间保持长连接,典型设置如下:(默认nginx访问后端都是用的短连接(HTTP1.0),一个请求来了,Nginx 新开一个端口和后端建立连接,后端执行完毕后主动关闭该链接)Nginx 1.1以上版本的upstream已经支持keep-alive的,所以我们可以开启Nginx proxy的keep-alive来减少tcp连接:
upstream http_backend { server 127.0.0.1:8080; keepalive 1000;//设置nginx到upstream服务器的空闲keepalive连接的最大数量 } server { ... location /http/ { proxy_pass http://http_backend; proxy_http_version 1.1;//开启长链接 proxy_set_header Connection ""; ... } }
HTTP协议中对长连接的支持是从1.1版本之后才有的,因此最好通过proxy_http_version指令设置为"1.1",而"Connection" header应该被清理。清理的意思,是清理从client过来的http header,因为即使是client和nginx之间是短连接,nginx和upstream之间也是可以开启长连接的。这种情况下必须清理来自client请求中的"Connection" header。但这个地方
需要注意如果有一些认证鉴权的cookie或者session信息在head里面,不建议开启此选项,或者对需要保留的header要保存下来,否则这些信息可能会丢掉从而发不到上游upstream的服务器上。
四次握手示例
nginx 设置header头大小nginx默认的header长度上限是4k,如果超过了这个值 nginx会直接返回400错误
可以通过以下2个参数来调整nginx的header上限
client_header_buffer_size 16k;
large_client_header_buffers 4 16k;
对nginx处理header时的方法:
- 先处理请求的request_line,之后才是request_header。
- 这两者的buffer分配策略相同。
- 先根据client_header_buffer_size配置的值分配一个buffer,如果分配的buffer无法容纳 request_line/request_header,那么就会再次根据large_client_header_buffers配置的参数分配large_buffer,如果large_buffer还是无法容纳,那么就会返回414(处理request_line)/400(处理request_header)错误。
- 如果你的请求中的header都很大,那么应该使用client_header_buffer_size,这样能减少一次内存分配。
- 如果你的请求中只有少量请求header很大,那么应该使用large_client_header_buffers,因为这样就仅需在处理大header时才会分配更多的空间,从而减少无谓的内存空间浪费。
针对get请求,解决请求串过长的问题
对get请求,我们可以通过修改另外两个配置来解决请求串超长的问题:
client_header_buffer_size语法:
client_header_buffer_size size默认值:1k
使用字段:http, server
这个指令指定客户端请求的http头部缓冲区大小绝大多数情况下一个头部请求的大小不会大于1k
不过如果有来自于wap客户端的较大的cookie它可能会大于1k,Nginx将分配给它一个更大的缓冲区。
这个值可以在large_client_header_buffers里面设置。
large_client_header_buffers语法:
large_client_header_buffers number size
默认值:large_client_header_buffers 4 4k/8k
使用字段:http, server指令指定客户端请求的一些比较大的头文件到缓冲区的最大值。
如果一个请求的URI大小超过这个值,服务器将返回一个"Request URI too large" (414)。
同样,如果一个请求的头部字段大于这个值,服务器将返回"Bad request" (400)。
缓冲区根据需求的不同是分开的。默认一个缓冲区大小为操作系统中分页文件大小,通常是4k或8k,
如果一个连接请求将状态转换为keep-alive,这个缓冲区将被释放。
GET提交,请求的数据会附在URL之后
6.3 location 用于URL重写
URL重写是Web服务器中的一个常见需求,可以用于实现URL规范化、重定向旧地址、创建更友好的URL等。
Nginx的location指令结合rewrite指令可以轻松实现这些功能。
基本的URL重写配置如下:
location /old-page.html { rewrite ^/old-page\.html$ /new-page.html permanent; }
这个配置将对
/old-page.html
的请求永久重定向到/new-page.html
。
对于更复杂的重写需求,我们可以使用正则表达式和捕获组:
location ~* ^/blog/(\d{4})/(\d{2})/(\d{2})/(.+)$ { rewrite ^/blog/(\d{4})/(\d{2})/(\d{2})/(.+)$ /posts/$1-$2-$3-$4.html last; }
这个配置将形如
/blog/2023/05/20/my-post
的URL重写为/posts/2023-05-20-my-post.html
。
在某些情况下,我们可能需要根据请求参数来进行重写:
location / { if ($args ~* ^id=(\d+)$) { set $id $1; rewrite ^/$ /items/$id? last; } }
这个配置将带有
id
参数的根路径请求重写为/items/{id}
形式的URL。
对于需要保留原始查询字符串的情况,我们可以使用
$is_args
和$args
变量:location /search { rewrite ^/search$ /new-search$is_args$args? last; }
这个配置将
/search
的请求重写为/new-search
,同时保留原始的查询字符串。
在进行URL重写时,我们还需要注意避免重写循环。使用last标志而不是break可以帮助防止这种情况:
location /loop { rewrite ^/loop$ /page1 last; } location /page1 { rewrite ^/page1$ /page2 last; } location /page2 { return 200 "Final destination"; }
在这个例子中,请求会依次经过/loop、/page1、/page2,最后在/page2处停止并返回响应。
通过这些高级应用,我们可以看到Nginx的location指令在静态文件处理、反向代理和URL重写等场景中的强大功能。合理利用这些功能,可以构建出高效、灵活的Web服务器配置,满足各种复杂的需求。在实际应用中,我们需要根据具体场景选择合适的配置方式,并注意性能和安全性的平衡。
6.3.1 限流控制
Nginx 提供了强大的限流功能,通过 ngx_http_limit_req_module 模块来限制单位时间内客户端的请求数量,防止服务器因过多请求而过载。
配置示例
首先在 http 区块内声明一个限流区域,并指定其共享内存大小及最大请求速率:
http {
limit_req_zone $binary_remote_addr zone=traffic_control:10m rate=10r/s;
server {
listen 80;
location / {
limit_req zone=traffic_control burst=20 nodelay;
proxy_pass http://backend_servers;
}
}
}
参数解析:
limit_req_zone定义了一个名为 traffic_control 的限流区域,共享内存大小为 10MB,最大请求速率为每秒 10 个请求。
limit_req 应用了上述区域,burst=20 允许短时间内的请求爆发,nodelay 表示超出限速的请求立即返回错误。
6.3.2 nginx服务器组模块
nginx的http代理是七层代理,对应的它的负载均衡也是做的七层负载。现在我们先使用stream模块组做四层负载。
服务器组模块全名ngx_http_upstream_module模块,它可以用于定义可由
proxy_pass
fastcgi_pass
uwsgi_pass
scgi_pass
memcached_pass
grpc_pass
指令引用的服务器组
upstream模块本身只能在http模块下进行配置
服务器组模块相关变量
$upstream_addr
保留IP地址和端口,或上游服务器的UNIX域套接字的路径。如果在请求处理期间联系了多个服务器,则它们的地址用逗号分隔。
如果发生从一个服务器组到另一个服务器组的内部重定向,由X-Accel-Redirect 或 error_page发起,则来自服务器地址用逗号分隔。如果无法选择服务器,则该变量将保留服务器组的名称。
$upstream_bytes_received
从上游服务器(1.11.4)接收的字节数。来自多个连接的值由逗号和冒号分隔
$upstream_bytes_sent
发送到上游服务器(1.15.8)的字节数。来自多个连接的值由逗号和冒号分隔。
$upstream_cache_status
保持访问响应缓存的状态(0.8.3)。状态可以是“MISS”、“BYPASS”、“EXPIRED”、“STALE”、“UPDATING”、“REVALIDATED”或“HIT”。
$upstream_connect_time
保持与上游服务器建立的时间(1.9.1);时间以毫秒为单位保存。在SSL的情况下,包括花在握手上的时间。连接的时间由逗号和冒号分隔
$upstream_cookie_[name]
上游服务器在“Set-Cookie”响应头字段(1.7.1)中发送的具有指定名称的cookie。仅保存来自最后一个服务器响应的cookie。
$upstream_header_time
保持从上游服务器(1.7.10)接收响应头所花费的时间,时间以毫秒为单位保持。多个响应的时间由逗号和冒号分隔
$upstream_http_[name]
保留服务器响应头字段。例如,“Server”响应头字段可通过
$upstream_http_server
变量获得。将头域名称转换为变量名称的规则与以“$http_”前缀开头的变量相同,仅保存最后一个服务器响应的标头字段。
$upstream_queue_time
保持请求在上游队列中花费的时间(1.13.9);时间以毫秒为单位保存。多个响应的时间由逗号和冒号分隔。商业版提供该变量
$upstream_response_length
保持从上游服务器获得的响应长度(0.7.27);长度以字节为单位。几个响应的长度由逗号和冒号分隔
$upstream_response_time
保持从上游服务器接收响应所花费的时间;时间以毫秒为单位保存。多个响应时间由逗号和冒号分隔
$upstream_status
保留从上游服务器获得的响应的状态码。几个响应的状态代码由逗号和冒号分隔
$upstream_trailer_[name]
保留从上游服务器(1.13.10)获得的响应末尾字段
使用log_farmat记录这些变量信息 查看
生成的日志
假如其中一个服务器挂掉,将8098端口修改 日志如下
轮询代8098时,日志在upstream_addr记录了两个IP地址,由后面的服务器继续提供服务。
配置指令
upstream
定义一组服务器
upstream name {...}
只能定义在http模块中,服务器可以监听不同的端口。此外,侦听TCP和unix域套接字的服务器可以混合使用。
默认情况下,请求使用加权循环平衡方法在服务器之间分配。如果在与服务器通信期间发生错误,请求将被传递到下一个服务器,依此类推,直到尝试所有正常运行的服务器。如果无法从任何服务器获得成功响应,则客户端将接收到与最后一个服务器通信的结果。
server
定义服务器的地址和其他参数
server address [parameters];
这个地址可以指定为域名或ip地址,带有可选端口,或指定为“unix:”前缀指定的UNIX域套接字路径。
如果未指定端口,则使用端口80.解析为多个IP地址的域名一次定义多个服务器
可以定义以下参数
weight=number
设置服务器的权重,默认为1
max_fails_number
设置在fail_timeout参数设置的持续时间与服务器通信的不成功尝试次数,以考虑服务器在fail_timeout参数设置的持续时间内不可用。默认情况下,不成功的尝试次数设置为1。
零值禁用尝试记录。
被认为不成功的尝试由proxy_next_upstream、fastcgi_next_upstream、uwsgi_next_upstream、scgi_next_upstream、memcached_next_upstream和grpc_next_upstream指令定义。
fail_timeout=time
与服务器通信的指定次数的不成功尝试碰巧认为服务器不可用的时间;以及服务器将被视为不可用的时间段。默认情况下,该参数设置为10秒
backup
将服务器标记为备份服务器。当主服务器不可用时,它将被传递请求。该参数不能与hash、ip_hash、random负载均衡方法一起使用
down
将服务器标记为永久不可用
先测试权重
测试的结果本地80端口出现次数明显增多,8098次之。总体来说,weight设置的值越大,出现的频率越高。
接下测试down和backup
因为本地down掉,8098被用作备用,只有在主服务器挂掉才会被启用请求。只会返回89服务器内容。
这些参数可以一起使用 如下
hash
使用基于散列键值来进行hash操作的负载均衡方法
hash key [consistent];
这个键可以包含文本、变量及其组合。请注意,从组中添加或删除服务器可能会导致将大部分密钥重新映射到不同的服务器。该方法与Cache::Memcached Perl库兼容。
如果指定了consistent参数,则将使用ketama一致哈希方法。该方法确保在将服务器添加到组或从组中删除时,只有少数密钥将重新映射到不同的服务器。这有助于为缓存服务器实现更高的缓存命中率。该方法与将ketama_points参数设置为160的Cache::Memcached::Fast Perl库兼容。
这个可以做URI定位的负载均衡,通过 $uri 变量来实现不同URI访问到不同的后端主机上
注意 :这个是改变均衡策略,使用它时如果哈希条件不存在,会走轮询;如果条件成功,就走hash。
如
测试结果,如果是相同的uri,就一直走同一台后端主机,可以用不同的uri测试
可以看到测试结果,前面两个都是走89服务器的,最后一个是走到88机的80端口
ip_hash
指定组应基于客户端ip地址在服务器之间分配请求
ip_hash;
客户端IPv4地址或整个IPv6地址的前三个八位字节用作散列密钥。该方法确保来自同一客户端的请求将始终传递到同一台服务器,除非该服务器不可用。在后一种情况下,客户端请求将被传递到另一台服务器。很可能,它也将始终是同一台服务器。
从版本1.3.2和1.2.2开始支持IPv6地址。在1.3.1和1.2.2版本之前,无法使用ip_hash负载均衡方法为服务器指定权重。
如果需要临时删除其中一台服务器,则应使用down参数对其进行标记,以保留客户端IP地址的当前散列
这是另外一个均衡策略,可以有效解决session问题。相同的客户端ip会走到同一台服务器上。当然这只是最简单的一个方案,最流行的是直接使用外部存储,如redis来保存session,不管使用何种均衡策略,redis不变就行。
如下
进行测试,日志如下
keepalive
激活缓存以连接到上游服务器
keepalive connections;
连接参数设置保留在每个工作进程缓存中的上游服务器的最大空闲保活连接数。当超过这个数字时,最近最少使用的连接将被关闭。
特别注意的是:keepalive指令不限制nginx工作进程可以打开的上游服务器的连接总数。连接参数应该设置为一个足够小的数字,以便上游服务器也可以处理新的传入连接。
当使用默认循环方法意外的负载均衡方法时,需要在keepalive指令之前激活它们。
对于http,proxy_http_version 指令应设置为“1.1”,并且清除“Connection”标字头字段。
或者有需要传递给下个服务器信息,通过变量将信息提取出来传递
亦或者,可以通过将“Connection:Keep-Alive”标字头传递给上游服务器来使用HTTP/1.0持久连接,但不建议使用此方法。
对于FastCGI服务器,需要设置fastcgi_keep_conn 才能使用keepalive 连接正常工作。scgi和 uwsgi协议没有保持连接的概念。
测试如下
使用Jmeter 或者ab工具 进行压测 不使用长连接的话 查看89服务器连接数量
在访问的时候建立了3千多个连接
使用长连接
只有23个,效果还是不错的
keepalive_requests
设置可以通过一个keepalive连接服务的最大请求数
keepalive_requests number;
默认值1000,在发出最大请求数后,连接将关闭。定期关闭连接对于释放每个连接的内存分配时必要的。因此,使用过高的最大请求书可能会导致内存使用过多,不推荐使用。在1.19.10版本之前,默认值为100。
keepalive_time
限制通过一个保活连接处理请求的最长时间
keepalive_time time;
默认值60s,达到这个时间后,连接在后续请求处理后关闭。
keepalive_timeout
设置一个超过时间,在此期间与上游服务器的空闲保活连接将保持打开状态
keepalive_timeout timeout;
默认值 60s。
last_conn
指定组应使用最少活动连接数的服务器,同时考虑服务器权重
last_conn;
如果有多个这样的服务器,则使用加权循环平衡方法依次尝试它们。
这个均衡侧率时根据哪个服务器建立的连接最少就使用哪个服务器来进行连接的。可以达到效果是保证所有的后端服务器的连接数均衡。不会有服务器承担特别重的任务,其他服务器又很清闲。
random
指定组应使用负载平衡方法,其中将请求传递到随机选择的服务器,同时考虑服务器的权重。
random [two [method]];
可选的two参数指示nginx随机选择两个服务器,然后使用指定的方法选择一个服务器。默认方法是minimum_conn,它将请求传递给活动连接数最少的服务器。
least_time 方法将请求传递给平均响应时间最短且活动连接数最少的服务器。如果指定了minimum_time=header,则使用接收响应头的时间。如果指定了minimum_time=last_byte,则使用接收完整响应的时间。不过这个参数时商业才提供的。
如下
其他商业版指令
server 中的 resolve 、 route 、 service 、 slow_start 、 drain 参数
random 中的 least_time 参数
zone 、 state 、 ntlm 、least_time 、 queue 、 resolver 、 resolver_timeout 、 sticky 、sticky_cookie_insert 配置指令
如果同时写多个均衡策略,以最后一个为准 如
只有$arg_a生效。
nginx反向代理和负载均衡示例图
7.nginx 主体功能介绍和工作解析
Nginx是一款轻量级的Web 服务器/反向代理服务器及电子邮件(IMAP/POP3)代理服务器,并在一个BSD-like 协议下发行。
Nginx 是一个很强大的高性能 Web和 反向代理服务器,它具有很多非常优越的特性:
在高连接并发的情况下,Nginx是 Apache服务器不错的替代品,能够支持高达 50,000 个并发连接数的响应。感谢Nginx为我们选择了 epoll and kqueue作为开发模型。
Nginx作为负载均衡服务器:Nginx 既可以在内部直接支持 Rails 和 PHP 程序对外进行服务,也可以支持作为 HTTP代理服务器对外进行服务。
Nginx采用C进行编写,不论是系统资源开销还是CPU使用效率都比 Perlbal 要好很多。
7.1 nginx 配置实例-动静分离
nginx动静分离简单来说就是把动态静态请求分开,不能理解成只是单纯的把动态页面和静态页面物理分离。严格意义说应该是动态请求根静态请求分开,可以理解成使用nginx处理静态页面,tomcat处理动态页面。
动静分离从目前实现角度来讲大致分为两种
1,一种是纯粹把静态文件独立成单独的域名,放在独立的服务器上,也是目前主流推崇的方案。
2,另外一种方法就是动态跟静态文件混合在一起发布,通过nginx发布。
3,通过location 指定不同的后缀名实现不同的请求转发。
如 通过expires参数设置,可以使浏览器缓存过期时间,减少与服务器之前的请求和流量。
具体Expires定义:是给一个资源设定一个过期时间,也就是说无需去服务端验证,直接通过浏览器自身确认是否过期即可。所以不会产生额外的流量,此种方法非常适合不经常变动的资源。如果经常变动更新的文件,不建议使用expires来缓存。
比如设置3d,表示在这3天之内访问这个url,发送一个请求,比对服务器该文件最后更新时间没有变化,则不会从服务器抓取,返回状态码304;如果有修改,则直接从服务器重新返回状态码200.
7.2 nginx配置高可用的集群
keepalived + nginx 高可用集群 (主从模式)
两台服务器安装nginx
两台服务器安装keepalived
1.使用yum命令进行安装
yum install keepalived -y
安装之后,在etc里面生成目录keepalived,有文件keepalived.conf
2.完成高可用配置(主从配置)
1)修改/etc/keepalived/keepalivec.conf 配置文件
global_defs{
notification_email{
acassen@firewall.loc
failover@firewall.loc
sysadmin@firewall.loc
}
notification_email_from Alexandre.Cassen@firewall.loc
smtp_server 192.168.17.129
smtp_connect_timeout 30
router_id LVS_DEVEL #服务器的名字 vim /etc/hosts 文件添加 127.0.0.1 LVS_DEVEL
}
vrrp_script chk_http_port{
script "/usr/local/src/nginx_check.sh" #检测脚本的路径
interval 2 #(检测脚本执行的间隔单位:秒)
weight 2 #权重参数 当检查脚本的条件成立就设置主机的权重2
}
vrrp_instance VI_1 {
state MASTER # 备份服务器上将 MASTER 改为 BACKUP
interface ens33 #主机网卡,
virtual_router_id 51 # 主、备机的 virtual_router_id 必须相同
priority 90 # 主、备机取不同的优先级,主机值较大,备份机值较小
advert_int 1 #检查主机服务心跳,判断服务是否活着默认是1秒
authentication {
auth_type PASS #权限验证的方式
auth_pass 1111 #密码1111
}
virtual_ipaddress {
192.168.253.50 #VRRP H 虚拟地址,用户访问此IP地址再跳转到nginx服务器
} }
2).在/usr/local/src 添加检测脚本nginx_check.sh
#!/bin/bash
A=`ps -C nginx –no-header |wc -l`
if [ $A -eq 0 ];then
/usr/local/nginx/sbin/nginx
sleep 2
if [ `ps -C nginx --no-header |wc -l` -eq 0 ];then
killall keepalived
fi
fi
3).启动两台服务器上的nginx 和 keepalived
启动 nginx:/usr/local/nginx/sbin/nginx
启动 keepalived:systemctl start keepalived.service
4)测试
在浏览器地址栏输入 虚拟 ip 地址 192.168.253.50
使用命令:ip a 查看虚拟地址绑定的网卡
8.其他相关配置
8.1 mac中ulimit 和 sysctl
可以用ulimit -a 来显示当前的各种用户进程限制。
- 设置打开文件数
- $sudo launchctl limit maxfiles 100000 500000
$sudo ulimit -n 100000
- 设置进程数
- sudo launchctl limit maxproc 100000 100000
- launchctl limit
查看哪些可以修改
man 3 sysctl
sudo ulimit -u 1064
- 设置端口
$sudo sysctl net.inet.ip.portrange.first=10000
要想支持更高数量的TCP并发连接的通讯处理程序,就必须修改系统对当前用户的进程同时打开的文件数量的软限制(soft limit)和硬限制(hardlimit)。
其中软限制是指Linux在当前系统能够承受的告警范围内进一步限制用户同时打开的文件数,超过则会告警;
硬限制则是根据系统硬件资源状况(主要是系统内存)计算出来的系统最多可同时打开的文件数量,超过则无法打开了。
查看网络设置
sysctl -a | grep "net.inet.ip"
8.2 ipv6监听
服务器查看ipv6
netstat -ano|findstr 80
在nginx配置文件中
listen [::]:80
从Nginx 1.3 的某个版本起,默认ipv6only是打开的,也就是上面的语句只会监听IPv6的端口而不会监听IPv4的端口。
虽然Linux系统默认是监听IPv6的某个端口会同时监听对应的IPv4的端口,但是FreeBSD是默认分开IPv6和IPv4的。
所以为了一致性的考虑(新版本Nginx必须推荐这样做),请使用分开监听的方法:
listen 80;
listen [::]:80 ipv6only=on;
只监听一个指定的ipv6地址
和IPv4指定地址一样,就在listen里写上完整的地址就OK了!以一个IPv6地址为例:
listen [2607:f0d0:1002:51::4]:80;
IPv6监听SSL(443)端口
编辑你原来监听443端口的配置文件,如/etc/nginx/conf.d/ssl.conf,修改listen语句为:
listen [::]:443 ssl;
后面的ssl可省掉。443端口的其它用法和80端口一样,这里就不赘述了。
8.3 linux 中编辑器vim常用命令解析
1.Vim编辑器
是linux系统中的文件编辑器,一般系统中默认的是vi 编辑器,vim要比vi要强大一点;使用vim需要安装,安装方式:yum install vim -y (-y表示安装过程不需要确认),vim或vi对小文件操作是很快的,但是较大的文件就打开是有点耗时;
vi/vim编辑器的操作模式分为三种:
a.命令行模式:vi、vim的默认模式;在这一模式中,所有的输入被解释成vi命令,可以执行修改、复制、移动、粘贴和删除正文等命令,也可以移动光标、搜索字符串和退出vi的操作等;
b.编辑模式:从命令行模式切换至编辑模式,输入:a 或 i 或 o 即可;在编辑模式中,可以往一个文件中输入正文;在这一模式下,输入的每一个字符都被vi编辑器解释为输入的正文。使用ESC键返回命令行模式。
说明:按a i o 进入编辑(插入)模式,是有一点区别的;
a :进入插入模式并在光标之后进行插入
i:进入插入模式并在光标之前进行插入
o:进入插入模式并在当前(光标所在)行之下开启新的一行;
c.扩展模式:在一些unix系统上也叫最后一行模式。在这一模式下,可以使用一些高级编辑命令,如:搜索和替代字符串、存盘或者退出vi编辑器等;要进入最后一行模式,需要在命令行模式中输入冒号(:),冒号这一操作将把光标移动到屏幕的最后一行。
2.vim创建文件或者修改文件
a. vim filename 没有文件就创建文件,有就打开文件;默认:命令行模式;
在命令行模式、最后一行模式的命令
补充:查询关键字:/keywords 下一个:n 上一个:#3.echo
a、echo 后面加内容------》输出的后面的内容;b、echo -n 后面加内容----》不换行输出内容;
c、echo -e 后面加内容-----》输出转义字符,如:\t 转义字符,表示:制表符,相当于Tab键;
d、结合重定向符:> (覆盖文件内原内容) 或 >> (在文件原内容后追加,而不覆盖原内容) ;向文件写入内容;
4.文件的查看
cat finame
nl finame
显示的时候,顺道输出行号!
more finame
一页一页的显示文件内容,enter向下
less finame
https://blog.csdn/ak739105231/article/details/89883768
比more更强大,可以向上一页查看;点击键盘Pgup;PgDn两个按钮
5.less命令详解
语法
less(选项)(参数)
选项
-e:文件内容显示完毕后,自动退出;
-f:强制显示文件;
-g:不加亮显示搜索到的所有关键词,仅显示当前显示的关键字,以提高显示速度;
-l:搜索时忽略大小写的差异;
-N:每一行行首显示行号;
-s:将连续多个空行压缩成一行显示;
-S:在单行显示较长的内容,而不换行显示;
-x<数字>:将TAB字符显示为指定个数的空格字符。
参数
文件:指定要分屏显示内容的文件。
8.4 ip 0.0.0.0 与127.0.0.1的区别
0.0.0.0 集合 不清楚 主机 目的 网络 收容所
127.0.0.1 本机地址 Localhost
a、0.0.0.0:它表示的是这样一个集合:所有不清楚的主机和目的网络。
b、255.255.255.255:限制广播地址,这个地址不能被路由器转发。
c、127.0.0.1:本机地址,在Windows系统中,这个地址有一个别名“Localhost”。
0.0.0.0
集合 不清楚 主机 目的 网络 收容所
严格说来,0.0.0.0已经不是一个真正意义上的IP地址了。它表示的是这样一个集合:所有不清楚的主机和目的网络。这里的“不清楚”是指在本机的路由表里没有特定条目指明如何到达。
对本机来说,它就是一个“收容所”,所有不认识的“三无”人员,一律送进去。如果你在网络设置中设置了缺省网关,那么Windows系统会自动产生一个目的地址为0.0.0.0的缺省路由。
255.255.255.255
限制广播地址
不能 路由器 转发
限制广播地址。对本机来说,这个地址指本网段内(同一广播域)的所有主机。
如果翻译成人类的语言,应该是这样:“这个房间里的所有人都注意了!”这个地址不能被路由器转发。
127.0.0.1
本机地址 Localhost
本机地址,主要用于测试。用汉语表示,就是“我自己”。在Windows系统中,这个地址有一个别名“Localhost”。
寻址这样一个地址,是不能把它发到网络接口的。除非出错,否则在传输介质上永远不应该出现目的地址为“127.0.0.1”的数据包。
linux uwsgi配置文件
uwsgi 、fcgi 、wsgi 区别
fcgi:FastCGI协议是一种常用于Web服务器和应用程序之间的通信协议。它允许Web服务器(如Nginx)将请求传递给后端应用程序,并接收处理结果。FastCGI协议本身不包含具体的实现,而是由不同的软件包(如PHP-FPM)来实现。
用spawn-fcgi或者框架自带的工具对各个project分别生成监听进程,然后和http服务互动。这种方法需要对每个项目分别进行配置和管理,管理上较为复杂。
wsgi:这是一个Apache模块,用于在Apache服务器上运行Python Web应用程序。它允许Apache直接作为Web服务器运行Python代码,支持WSGI协议。
利用http服务的mod_wsgi模块来跑各个project,配置较为复杂且内存占用较大
uwsgi: 是一个集成的服务器应用,Nginx通过uwsgi
协议与uWSGI服务器通信,而不是通过传统的HTTP代理方式。uWSGI是一个独立的Web服务器,也可以与Nginx集成使用,安装相对简单且性能较高
mod_uwsgi:这是Apache的一个模块,专门用于在Apache服务器上运行uWSGI服务器。它通过uwsgi协议与uWSGI服务器通信,支持WSGI协议,可以运行Python、Ruby等多种语言的Web应用程序。
fcgi:主要用于将Python应用作为CGI脚本运行,每个请求都会启动一个新的进程,适合轻量级应用,但管理复杂且性能较低
mod_wsgi:通过Apache的mod_wsgi模块运行Python应用。配置较为复杂,适合需要高并发处理的应用,但内存占用较大
mod_uwsgi:uWSGI服务器可以通过uwsgi协议与Nginx通信,实现高效的请求处理和负载均衡。uWSGI作为一个独立的Web服务器或与Nginx集成使用,具有低内存占用和高性能的特点
总结:三者中uwsgi效率最高,是前两者的数倍,可以用在高并发的环境下。对于Apache服务器,FCGI和mod_wsgi通常是用于部署Python Web应用的方法。mod_uwsgi主要用于部署Python Web应用,它使用的是uWSGI协议,而不是FCGI。
fcgi 、 mod_wsgi 、 mod_uwsgi 的安装
首先需要在Apache上安装mod_wsgi模块。可以通过下载源代码编译安装,或者使用包管理器(如apt-get或yum)进行安装
1,FCGI和mod_wsgi的安装:
- fcgi:通常需要安装FastCGI管理器(如PHP-FPM),然后在Web服务器(如Nginx)中配置FastCGI参数,指向FastCGI管理器。
- mod_wsgi:需要在Apache服务器上安装mod_wsgi模块,并通过Apache的配置文件设置WSGIApplicationGroup和其他相关参数来运行Python应用。
对于Debian/Ubuntu系统,可以使用以下命令安装:
sudo apt-get install libapache2-mod-fcgid
sudo apt-get install libapache2-mod-wsgi
对于Red Hat/CentOS系统,可以使用以下命令安装:
sudo yum install mod_fcgid
sudo yum install mod-wsgi
2,mod_uwsgi的安装
- mod_uwsgi:需要在Apache上安装mod_uwsgi模块,并通过Apache的配置文件设置UWSGIOptions和其他相关参数来运行uWSGI服务器。
首先,你需要安装uWSGI。可以使用以下命令安装:
sudo pip install uwsgi
然后,你需要安装mod_uwsgi Apache模块。可以使用以下命令安装:
sudo apt-get install apache2-threaded-dev
sudo pip install mod_uwsgi
注意:上述mod_uwsgi的安装命令可能会根据你的操作系统和Python版本的不同而有所变化。
nginx 其他应用配置
使用docker基础安装方法
docker run \
--restart always \
--name Nginx \
-d \
-p 80:80 \
nginx
注意参数 restart 重启策略,always 是一直保持重启。如果不设置,可以把这条删掉。never\always
8090 - 容器端口、80 - 服务器端口,这样外部通过80端口即可访问。
进入nginx
进入程序:docker exec -it Nginx /bin/bash
[root@vultr ~]# docker exec -it Nginx /bin/bash
root@ed8dc07f2ae6:/# ls
bin boot dev docker-entrypoint.d docker-entrypoint.sh etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var
root@ed8dc07f2ae6:/# cd etc/nginx/
root@ed8dc07f2ae6:/etc/nginx# ls
conf.d fastcgi_params mime.types modules nginx.conf scgi_params uwsgi_params
root@ed8dc07f2ae6:/etc/nginx# pwd
/etc/nginx
root@ed8dc07f2ae6:/# cd /usr/share/nginx/html
root@ed8dc07f2ae6:/usr/share/nginx/html# ls
50x.html index.html
root@ed8dc07f2ae6:/usr/share/nginx/html# cat index.html
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
<p>For online documentation and support please refer to
<a href="http://nginx/">nginx</a>.<br/>
Commercial support is available at
<a href="http://nginx/">nginx</a>.</p>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>
root@ed8dc07f2ae6:/usr/share/nginx/html#
root@ed8dc07f2ae6:/usr/share/nginx/html# exit
exit
退出程序:exit
配置nginx.conf html主页
创建文件目录
[root@vultr ~]# mkdir -p /data/nginx/conf
[root@vultr ~]# mkdir -p /data/nginx/html
拷贝文件
[root@vultr ~]# docker container cp Nginx:/etc/nginx/nginx.conf /data/nginx/conf
[root@vultr ~]# docker container cp Nginx:/usr/share/nginx/html/index.html /data/nginx/html
查看信息
[root@vultr ~]# ls /data/nginx/conf/
nginx.conf
[root@vultr ~]# ls /data/nginx/html/
index.html
部署nginx
docker run \
--restart always \
--name Nginx \
-d \
-v /data/nginx/html:/usr/share/nginx/html \
-v /data/nginx/conf/nginx.conf:/etc/nginx/nginx.conf \
-p 80:80 \
nginx
重启:sudo service nginx restart
证书安装,各厂商都有提供,比较简单,自己申请下载下来即可
里面有2个文件【x.key、x.pem】
配置证书
创建一个default.conf 文件配置ssl信息
单个证书
server {
listen 80;
listen [::]:80;
server_name openai.xfg.im;
rewrite ^(.*) https://$server_name$1 permanent;
}
server {
listen 443 ssl;
server_name openai.xfg.im;
ssl_certificate /etc/nginx/ssl/9740289_openai.xfg.im.pem;
ssl_certificate_key /etc/nginx/ssl/9740289_openai.xfg.im.key;
ssl_session_cache shared:SSL:1m;
ssl_session_timeout 5m;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
location / {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
root /usr/share/nginx/html;
index index.html index.htm;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
可以复制这份文件,在自己本地创建。注意修改域名和SSL文件路径
多个证书
需要给1个以上的域名配置SSL,那么可以配置多组 server 如下
server {
listen 80;
listen [::]:80;
server_name itedus;
rewrite ^(.*) https://$server_name$1 permanent;
}
server {
listen 443 ssl;
server_name itedus;
ssl_certificate /etc/nginx/ssl/9750021_itedus.pem;
ssl_certificate_key /etc/nginx/ssl/9750021_itedus.key;
ssl_session_cache shared:SSL:1m;
ssl_session_timeout 5m;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
location / {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
root /usr/share/nginx/html;
index index.html index.htm;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
server {
listen 80;
listen [::]:80;
server_name chatgpt.itedus;
rewrite ^(.*) https://$server_name$1 permanent;
}
server {
listen 443 ssl;
server_name chatgpt.itedus;
ssl_certificate /etc/nginx/ssl/9749920_chatgpt.itedus.pem;
ssl_certificate_key /etc/nginx/ssl/9749920_chatgpt.itedus.key;
ssl_session_cache shared:SSL:1m;
ssl_session_timeout 5m;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
location / {
proxy_pass http://1.x.x.x:3002;
proxy_http_version 1.1;
chunked_transfer_encoding off;
proxy_buffering off;
proxy_cache off;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
启动服务
在 nginx.conf 的配置文件有这么一句;include /etc/nginx/conf.d/*.conf; 那么只要是 conf.d 文件夹下的文件都会被加载。所以直接在 conf.d/default.conf 配置 SSL 就会被加载。
接下来重新安装 Nginx 即可。安装前记得删除 Nginx 你可以用命令
docker stop Nginx
docker rm Nginx
或者在 Portainer 中操作也可
docker run \
--name Nginx \
-p 443:443 -p 80:80 \
-v /data/nginx/logs:/var/log/nginx \
-v /data/nginx/html:/usr/share/nginx/html \
-v /data/nginx/conf/nginx.conf:/etc/nginx/nginx.conf \
-v /data/nginx/conf/conf.d:/etc/nginx/conf.d \
-v /data/nginx/ssl:/etc/nginx/ssl/ \
--privileged=true -d --restart=always nginx
重定向
在default.conf中添加下面配置 重启nginx
location /d5fe/ {
rewrite ^/d5fe/(.*)$ /$1 break;
proxy_pass https://api.x;
proxy_ssl_server_name on;
proxy_set_header Host api.x;
proxy_set_header Connection '';
proxy_http_version 1.1;
chunked_transfer_encoding off;
proxy_buffering off;
proxy_cache off;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Forwarded-Proto $scheme;
}
auth_request
server {
listen 80;
listen [::]:80;
server_name api.xfg.im;
rewrite ^(.*) https://$server_name$1 permanent;
}
server {
listen 443 ssl;
server_name api.xfg.im;
ssl_certificate /etc/nginx/ssl/9877497_api.xfg.im.pem;
ssl_certificate_key /etc/nginx/ssl/9877497_api.xfg.im.key;
ssl_session_cache shared:SSL:1m;
ssl_session_timeout 5m;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
location / {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
root /usr/share/nginx/html;
index index.html index.htm;
}
location /abc/ {
auth_request /auth;
rewrite ^/abc/(.*)$ /$1 break;
proxy_pass https://api.x;
proxy_ssl_server_name on;
proxy_set_header Host api.x;
proxy_set_header Connection '';
proxy_http_version 1.1;
chunked_transfer_encoding off;
proxy_buffering off;
proxy_cache off;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Forwarded-Proto $scheme;
}
location = /auth {
# 发送子请求到HTTP服务,验证客户端的凭据,返回响应码
internal;
# 设置参数
set $query '';
if ($request_uri ~* "[^\?]+\?(.*)$") {
set $query $1;
}
# 验证成功,返回200 OK
proxy_pass http://1.x.x.x.*:8090/auth/token?$query;
# 发送原始请求
proxy_pass_request_body off;
# 清空 Content-Type
proxy_set_header Content-Type "";
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
目前暂时更新到这里,欢迎有问题大家私信