nginx入门
nginx 功能介绍
Nginx因为它的稳定性、丰富的模块库、灵活的配置和低系统资源的消耗而闻名.业界一致认为它是Apache2.2+mod_proxy_balancer的轻量级代替者,不仅因为响应静态页面的速度非常快,而且它的模块数量是Apache的2/3。对proxy和rewrite模块的支持很彻底,还支持mod_fcgi、ssl、vhosts ,适合用做mongrel clusters前端HTTP响应。
nginx和Apache一样用模块化设计,nginx模块包括内置模块和第三方模块,其中内置模块中包含主模块和事件模块。
nginx可以提供的服务
- web 服务.
- 负载均衡 (反向代理)
- web cache(web 缓存)
nginx 的优点
- 高并发。静态小文件
- 占用资源少。2万并发、10个线程,内存消耗几百M。
- 功能种类比较多。web,cache,proxy。每一个功能都不是特别强。
- 支持epoll模型,使得nginx可以支持高并发。
- nginx 配合动态服务和Apache有区别。(FASTCGI 接口)
- 利用nginx可以对IP限速,可以限制连接数。
- 配置简单,更灵活。
[
](https://blog.csdn.net/qq_29677867/article/details/90112120)
nginx应用场合
- 静态服务器(图片,视频服务),另个lighttpd。并发几万,html,js,css,flv,jpg,gif等。
- 动态服务,nginx—fastcgi 方式运行PHP,jsp。(PHP并发约500-1500,MySQL 并发约300-1500)。
- 反向代理,负载均衡。日pv2000W以下,都可直接用nginx做代理。
- 缓存服务。类似 SQUID,VARNISH。
[
](https://blog.csdn.net/qq_29677867/article/details/90112120)
主流web服务产品对比说明
Apache-特性
- 2.2版本本身稳定强大,据官方说:其2.4版本性能更强。
- prefork模式取消了进程创建开销,性能很高。
- 处理动态业务数据时,因关联到后端的引擎和数据库,瓶颈不在与Apache本身。
- 高并发时消耗系统资源相对多一些。
- 基于传统的select模型。
- 扩展库,DSO方法。
nginx-特性
- 基于异步IO模型(epoll,kqueue),性能强,能够支持上万并发。
- 对小文件支持很好,性能很高(限静态小文件1M)。
- 代码优美,扩展库必须编译进主程序。
- 消耗代码资源比较低。
- lighttpd(百度贴吧,豆瓣)
- 基于异步IO模式,性能和nginx相近。
- 扩展库是SO模式,比nginx要灵活。
- 通过差距(mod_secdownload)可实现文件URL地址加密。
[
](https://blog.csdn.net/qq_29677867/article/details/90112120)
web服务产品性能对比测试
静态数据性能对比
- 处理静态文件Apache性能比nginx和lighttpd要差。
- nginx在处理小文件优势明显。
- 处理静态小文件(小于1M),nginx和lighttpd比Apache更有优势,lighttpd最强。
动态数据性能对比
- 处理动态内容三者相差不大,主要取决于PHP和数据库压力。
- 当处理动态数据时,三者差距不大,从测试结果看,Apache更有优势。这是因为处理动态数据能力取决于PHP和后端数据的提供服务能力。即瓶颈不在web服务器上。
- 一般PHP引擎的并发值300-1000,JAVA引擎并发300-1000,数据库并发300-1000.
[
](https://blog.csdn.net/qq_29677867/article/details/90112120)
为什么nginx总体性能比Apache高。
- nginx用最新epoll、kqueue网络IO模型,而Apache使用床头的select模式。
- 目前Linux下能承受高并发访问的squid、Memcached 都采用的是epoll网络IO模型。
如何选择WEB服务器:
静态业务:高并发、采用nginx,lighttpd,根据自己掌握程度或公司要求。 动态业务:采用nginx和Apache均可。 既有静态业务又有动态业务:nginx或Apache,不要多选要单选。 动态业务可由前端代理(haproxy),根据页面元素的类型,向后转发给相应的服务器处理。 思想:工作都不要追求一步到位,满足需求的前提下,先用再逐步完善。 提示:nginx做web(Apache,lighttpd)、反向代理(haproxy、lvs、nat)及缓存服务器(squid)也是不错的。 最终建议:对外业务nginx,对内业务Apache(yum httpd mysql-server php)。
nginx实战过程
nginx其他命令
nginx -s signalsignal:stop — fast shutdownquit — graceful shutdownreload — reloading the configuration filereopen — reopening the log files用来打开日志文件,这样nginx会把新日志信息写入这个新的文件中
nginx配置文件
worker_processes 1;events {worker_connections 1024;}http {include mime.types;default_type application/octet-stream;sendfile on;keepalive_timeout 65;server {listen 80;server_name localhost;location / {root html;index index.html index.htm;}error_page 500 502 503 504 /50x.html;location = /50x.html {root html;}}}
测试配置文件是否正常
shell> /data/nginx/sbin/nginx -tnginx: the configuration file /data/nginx-1.10.3/conf/nginx.conf syntax is oknginx: configuration file /data/nginx-1.10.3/conf/nginx.conf test is successfulshell> curl -I http://localhostHTTP/1.1 200 OK
正向代理和反向代理
反向代理(Reverse Proxy)对应的是正向代理(Forward Proxy),他们的区别:
正向代理: 一般的访问流程是客户端直接向目标服务器发送请求并获取内容,使用正向代理后,客户端改为向代理服务器发送请求,并指定目标服务器(原始服务器),然后由代理服务器和原始服务器通信,转交请求并获得的内容,再返回给客户端。正向代理隐藏了真实的客户端,为客户端收发请求,使真实客户端对服务器不可见;
[
](https://blog.csdn.net/Janson_Lin/article/details/105954705)
举个具体的例子 🌰,你的浏览器无法直接访问谷哥,这时候可以通过一个代理服务器来帮助你访问谷哥,那么这个服务器就叫正向代理。
反向代理: 与一般访问流程相比,使用反向代理后,直接收到请求的服务器是代理服务器,然后将请求转发给内部网络上真正进行处理的服务器,得到的结果返回给客户端。反向代理隐藏了真实的服务器,为服务器收发请求,使真实服务器对客户端不可见。一般在处理跨域请求的时候比较常用。现在基本上所有的大型网站都设置了反向代理。
[
](https://blog.csdn.net/Janson_Lin/article/details/105954705)
举个具体的例子 🌰,去饭店吃饭,可以点川菜、粤菜、江浙菜,饭店也分别有三个菜系的厨师 👨🍳,但是你作为顾客不用管哪个厨师给你做的菜,只用点菜即可,小二将你菜单中的菜分配给不同的厨师来具体处理,那么这个小二就是反向代理服务器。
简单的说,一般给客户端做代理的都是正向代理,给服务器做代理的就是反向代理。
正向代理和反向代理主要的原理区别可以参见下图:
配置反向代理
反向代理是工作中最常用的服务器功能,经常被用来解决跨域问题,下面简单介绍一下如何实现反向代理。
首先进入 Nginx 的主配置文件:
改完保存退出,nginx -s reload 重新加载,进入默认网址,那么现在就直接跳转到 B 站了,实现了一个简单的代理。
实际使用中,可以将请求转发到本机另一个服务器上,也可以根据访问的路径跳转到不同端口的服务中。
比如我们监听 9001 端口,然后把访问不同路径的请求进行反向代理:
- 把访问 http://127.0.0.1:9001/edu 的请求转发到 http://127.0.0.1:8080
- 把访问 http://127.0.0.1:9001/vod 的请求转发到 http://127.0.0.1:8081
这种要怎么配置呢,首先同样打开主配置文件,然后在 http 模块下增加一个 server 块:
server {listen 9001;server_name *.sherlocked93.club;location ~ /edu/ {proxy_pass http://127.0.0.1:8080;}location ~ /vod/ {proxy_pass http://127.0.0.1:8081;}}
反向代理还有一些其他的指令,可以了解一下:
- proxy_set_header:在将客户端请求发送给后端服务器之前,更改来自客户端的请求头信息;
- proxy_connect_timeout:配置 Nginx 与后端代理服务器尝试建立连接的超时时间;
- proxy_read_timeout:配置 Nginx 向后端服务器组发出 read 请求后,等待相应的超时时间;
- proxy_send_timeout:配置 Nginx 向后端服务器组发出 write 请求后,等待相应的超时时间;
proxy_redirect:用于修改后端服务器返回的响应头中的 Location 和 Refresh。
跨域 CORS 配置
关于简单请求、非简单请求、跨域的概念,前面已经介绍过了,还不了解的可以看看前面的讲解。现在前后端分离的项目一统天下,经常本地起了前端服务,需要访问不同的后端地址,不可避免遇到跨域问题

要解决跨域问题,我们来制造一个跨域问题。首先和前面设置二级域名的方式一样,先设置好 fe.sherlocked93.club 和 be.sherlocked93.club 二级域名,都指向本云服务器地址,虽然对应 IP 是一样的,但是在 fe.sherlocked93.club 域名发出的请求访问 be.sherlocked93.club 域名的请求还是跨域了,因为访问的 host 不一致(如果不知道啥原因参见前面跨域的内容)。使用反向代理解决跨域
在前端服务地址为 fe.sherlocked93.club 的页面请求 be.sherlocked93.club 的后端服务导致的跨域,可以这样配置:
server {listen 9001;server_name fe.sherlocked93.club;location / {proxy_pass be.sherlocked93.club;}}
这样就将对前一个域名 fe.sherlocked93.club 的请求全都代理到了 be.sherlocked93.club,前端的请求都被我们用服务器代理到了后端地址下,绕过了跨域
这里对静态文件的请求和后端服务的请求都以 fe.sherlocked93.club 开始,不易区分,所以为了实现对后端服务请求的统一转发,通常我们会约定对后端服务的请求加上 /apis/ 前缀或者其他的 path 来和对静态资源的请求加以区分,此时我们可以这样配置:
# 请求跨域,约定代理后端服务请求path以/apis/开头location ^~/apis/ {# 这里重写了请求,将正则匹配中的第一个分组的path拼接到真正的请求后面,并用break停止后续匹配rewrite ^/apis/(.*)$ /$1 break;proxy_pass be.sherlocked93.club;# 两个域名之间cookie的传递与回写proxy_cookie_domain be.sherlocked93.club fe.sherlocked93.club;}
这样,静态资源我们使用 fe.sherlocked93.club/xx.html,动态资源我们使用 fe.sherlocked93.club/apis/getAwo,浏览器页面看起来仍然访问的前端服务器,绕过了浏览器的同源策略,毕竟我们看起来并没有跨域。
也可以统一一点,直接把前后端服务器地址直接都转发到另一个 server.sherlocked93.club,只通过在后面添加的 path 来区分请求的是静态资源还是后端服务,看需求了
配置 header 解决跨域
当浏览器在访问跨源的服务器时,也可以在跨域的服务器上直接设置 Nginx,从而前端就可以无感地开发,不用把实际上访问后端的地址改成前端服务的地址,这样可适性更高。
比如前端站点是 fe.sherlocked93.club,这个地址下的前端页面请求 be.sherlocked93.club 下的资源,比如前者的 fe.sherlocked93.club/index.html 内容是这样的:
<html><body><h1>welcome fe.sherlocked93.club!!<h1><script type='text/javascript'>var xmlhttp = new XMLHttpRequest()xmlhttp.open("GET", "http://be.sherlocked93.club/index.html", true);xmlhttp.send();</script></body></html>
很明显这里是跨域请求,在浏览器中直接访问 http://be.sherlocked93.club/index.html 是可以访问到的,但是在 fe.sherlocked93.club 的 html 页面访问就会出现跨域。
在 /etc/nginx/conf.d/ 文件夹中新建一个配置文件,对应二级域名 be.sherlocked93.club :
# /etc/nginx/conf.d/be.sherlocked93.club.confserver {listen 80;server_name be.sherlocked93.club;add_header 'Access-Control-Allow-Origin' $http_origin; # 全局变量获得当前请求origin,带cookie的请求不支持*add_header 'Access-Control-Allow-Credentials' 'true'; # 为 true 可带上 cookieadd_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS'; # 允许请求方法add_header 'Access-Control-Allow-Headers' $http_access_control_request_headers; # 允许请求的 header,可以为 *add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';if ($request_method = 'OPTIONS') {add_header 'Access-Control-Max-Age' 1728000; # OPTIONS 请求的有效期,在有效期内不用发出另一条预检请求add_header 'Content-Type' 'text/plain; charset=utf-8';add_header 'Content-Length' 0;return 204; # 200 也可以}location / {root /usr/share/nginx/html/be;index index.html;}}
负载均衡
使用nginx做负载均衡的两大模块:
- upstream 定义负载节点池。
- location 模块 进行URL匹配。
- proxy模块 发送请求给upstream定义的节点池。

负载均衡在之前已经介绍了相关概念了,主要思想就是把负载均匀合理地分发到多个服务器上,实现压力分流的目的。
主要配置如下:
http {upstream myserver {# ip_hash; # ip_hash 方式# fair; # fair 方式server 127.0.0.1:8081; # 负载均衡目的服务地址server 127.0.0.1:8080;server 127.0.0.1:8082 weight=10; # weight 方式,不写默认为 1}server {location / {proxy_pass http://myserver;proxy_connect_timeout 10;}}}
Nginx 提供了好几种分配方式,默认为轮询,就是轮流来。有以下几种分配方式:
- 轮询,默认方式,每个请求按时间顺序逐一分配到不同的后端服务器,如果后端服务挂了,能自动剔除;
- weight,权重分配,指定轮询几率,权重越高,在被访问的概率越大,用于后端服务器性能不均的情况;
- ip_hash,每个请求按访问 IP 的 hash 结果分配,这样每个访客固定访问一个后端服务器,可以解决动态网页 session 共享问题。负载均衡每次请求都会重新定位到服务器集群中的某一个,那么已经登录某一个服务器的用户再重新定位到另一个服务器,其登录信息将会丢失,这样显然是不妥的;
- fair(第三方),按后端服务器的响应时间分配,响应时间短的优先分配,依赖第三方插件 nginx-upstream-fair,需要先安装
动静分离
为了加快网站的解析速度,可以把动态页面和静态页面由不同的服务器来解析,加快解析速度,降低原来单个服务器的压力。
动静分离
一般来说,都需要将动态资源和静态资源分开,由于 Nginx 的高并发和静态资源缓存等特性,经常将静态资源部署在 Nginx 上。如果请求的是静态资源,直接到静态资源目录获取资源,如果是动态资源的请求,则利用反向代理的原理,把请求转发给对应后台应用去处理,从而实现动静分离。
使用前后端分离后,可以很大程度提升静态资源的访问速度,即使动态服务不可用,静态资源的访问也不会受到影响。
配置动静分离
动静分离在之前也介绍过了,就是把动态和静态的请求分开。方式主要有两种,一种 是纯粹把静态文件独立成单独的域名,放在独立的服务器上,也是目前主流推崇的方案。另外一种方法就是动态跟静态文件混合在一起发布, 通过 Nginx 配置来分开。
通过 location 指定不同的后缀名实现不同的请求转发。通过 expires 参数设置,可以使浏览器缓存过期时间,减少与服务器之前的请求和流量。具体 expires 定义:是给一个资源设定一个过期时间,也就是说无需去服务端验证,直接通过浏览器自身确认是否过期即可,所以不会产生额外的流量。此种方法非常适合不经常变动的资源。(如果经常更新的文件,不建议使用 expires 来缓存),我这里设置 3d,表示在这 3 天之内访问这个URL,发送一个请求,比对服务器该文件最后更新时间没有变化。则不会从服务器抓取,返回状态码 304,如果有修改,则直接从服务器重新下载,返回状态码 200
server {location /www/ {root /data/;index index.html index.htm;}location /image/ {root /data/;autoindex on;}}
gzip 压缩
gzip 是一种常用的网页压缩技术,传输的网页经过 gzip 压缩之后大小通常可以变为原来的一半甚至更小(官网原话),更小的网页体积也就意味着带宽的节约和传输速度的提升,特别是对于访问量巨大大型网站来说,每一个静态资源体积的减小,都会带来可观的流量与带宽的节省。
百度可以找到很多检测站点来查看目标网页有没有开启 gzip 压缩,在下随便找了一个 <网页GZIP压缩检测> 输入掘金 juejin.im 来偷窥下掘金有没有开启 gzip。
这里可以看到掘金是开启了 gzip 的,压缩效果还挺不错,达到了 52% 之多,本来 34kb 的网页体积,压缩完只需要 16kb,可以想象网页传输速度提升了不少。
Nginx 配置 gzip
使用 gzip 不仅需要 Nginx 配置,浏览器端也需要配合,需要在请求消息头中包含 Accept-Encoding: gzip(IE5 之后所有的浏览器都支持了,是现代浏览器的默认设置)。一般在请求 html 和 css 等静态资源的时候,支持的浏览器在 request 请求静态资源的时候,会加上 Accept-Encoding: gzip 这个 header,表示自己支持 gzip 的压缩方式,Nginx 在拿到这个请求的时候,如果有相应配置,就会返回经过 gzip 压缩过的文件给浏览器,并在 response 相应的时候加上 content-encoding: gzip 来告诉浏览器自己采用的压缩方式(因为浏览器在传给服务器的时候一般还告诉服务器自己支持好几种压缩方式),浏览器拿到压缩的文件后,根据自己的解压方式进行解析
先来看看 Nginx 怎么进行 gzip 配置,和之前的配置一样,为了方便管理,还是在 /etc/nginx/conf.d/ 文件夹中新建配置文件 gzip.conf :
# /etc/nginx/conf.d/gzip.confgzip on; # 默认off,是否开启gzipgzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript;# 上面两个开启基本就能跑起了,下面的愿意折腾就了解一下gzip_static on;gzip_proxied any;gzip_vary on;gzip_comp_level 6;gzip_buffers 16 8k;# gzip_min_length 1k;gzip_http_version 1.1;
稍微解释一下:
- gzip_types:要采用 gzip 压缩的 MIME 文件类型,其中 text/html 被系统强制启用;
- gzip_static:默认 off,该模块启用后,Nginx 首先检查是否存在请求静态文件的 gz 结尾的文件,如果有则直接返回该 .gz 文件内容;
- gzip_proxied:默认 off,nginx做为反向代理时启用,用于设置启用或禁用从代理服务器上收到相应内容 gzip 压缩;
- gzip_vary:用于在响应消息头中添加 Vary:Accept-Encoding,使代理服务器根据请求头中的 Accept-Encoding 识别是否启用 gzip 压缩;
- gzip_comp_level:gzip 压缩比,压缩级别是 1-9,1 压缩级别最低,9 最高,级别越高压缩率越大,压缩时间越长,建议 4-6;
- gzip_buffers:获取多少内存用于缓存压缩结果,16 8k 表示以 8k*16 为单位获得;
- gzip_min_length:允许压缩的页面最小字节数,页面字节数从header头中的 Content-Length 中进行获取。默认值是 0,不管页面多大都压缩。建议设置成大于 1k 的字节数,小于 1k 可能会越压越大;
- gzip_http_version:默认 1.1,启用 gzip 所需的 HTTP 最低版本;
这个配置可以插入到 http 模块整个服务器的配置里,也可以插入到需要使用的虚拟主机的 server 或者下面的 location 模块中,当然像上面我们这样写的话就是被 include 到 http 模块中了。
其他更全的配置信息可以查看 <官网文档ngx_http_gzip_module>,配置前是这样的:
配置之后 response 的 header 里面多了一个 Content-Encoding: gzip,返回信息被压缩了:
注意了,一般 gzip 的配置建议加上 gzip_min_length 1k,不加的话:
由于文件太小,gzip 压缩之后得到了 -48% 的体积优化,压缩之后体积还比压缩之前体积大了,所以最好设置低于 1kb 的文件就不要 gzip 压缩了 🤪
Webpack 的 gzip 配置
当前端项目使用 Webpack 进行打包的时候,也可以开启 gzip 压缩:
// vue-cli3 的 vue.config.js 文件const CompressionWebpackPlugin = require('compression-webpack-plugin')module.exports = {// gzip 配置configureWebpack: config => {if (process.env.NODE_ENV === 'production') {// 生产环境return {plugins: [new CompressionWebpackPlugin({test: /\.js$|\.html$|\.css/, // 匹配文件名threshold: 10240, // 文件压缩阈值,对超过10k的进行压缩deleteOriginalAssets: false // 是否删除源文件})]}}},...}
由此打包出来的文件如下图:
这里可以看到某些打包之后的文件下面有一个对应的 .gz 经过 gzip 压缩之后的文件,这是因为这个文件超过了 10kb,有的文件没有超过 10kb 就没有进行gzip 打包,如果你期望压缩文件的体积阈值小一点,可以在 compression-webpack-plugin 这个插件的配置里进行对应配置。
那么为啥这里 Nginx 已经有了 gzip 压缩,Webpack 这里又整了个 gzip 呢,因为如果全都是使用 Nginx 来压缩文件,会耗费服务器的计算资源,如果服务器的 gzip_comp_level 配置的比较高,就更增加服务器的开销,相应增加客户端的请求时间,得不偿失。
如果压缩的动作在前端打包的时候就做了,把打包之后的高压缩等级文件作为静态资源放在服务器上,Nginx 会优先查找这些压缩之后的文件返回给客户端,相当于把压缩文件的动作从 Nginx 提前给 Webpack 打包的时候完成,节约了服务器资源,所以一般推介在生产环境应用 Webpack 配置 gzip 压缩
配置高可用集群(双机热备)
当主 Nginx 服务器宕机之后,切换到备份 Nginx 服务器
首先安装 keepalived,
yum install keepalived -y
然后编辑 /etc/keepalived/keepalived.conf 配置文件,并在配置文件中增加 vrrp_script 定义一个外围检测机制,并在 vrrp_instance 中通过定义 track_script 来追踪脚本执行过程,实现节点转移:
global_defs{notification_email {acassen@firewall.loc}notification_email_from Alexandre@firewall.locsmtp_server 127.0.0.1smtp_connect_timeout 30 // 上面都是邮件配置,没卵用router_id LVS_DEVEL // 当前服务器名字,用hostname命令来查看}vrrp_script chk_maintainace { // 检测机制的脚本名称为chk_maintainacescript "[[ -e/etc/keepalived/down ]] && exit 1 || exit 0" // 可以是脚本路径或脚本命令// script "/etc/keepalived/nginx_check.sh" // 比如这样的脚本路径interval 2 // 每隔2秒检测一次weight -20 // 当脚本执行成立,那么把当前服务器优先级改为-20}vrrp_instanceVI_1 { // 每一个vrrp_instance就是定义一个虚拟路由器state MASTER // 主机为MASTER,备用机为BACKUPinterface eth0 // 网卡名字,可以从ifconfig中查找virtual_router_id 51 // 虚拟路由的id号,一般小于255,主备机id需要一样priority 100 // 优先级,master的优先级比backup的大advert_int 1 // 默认心跳间隔authentication { // 认证机制auth_type PASSauth_pass 1111 // 密码}virtual_ipaddress { // 虚拟地址vip172.16.2.8}}
其中检测脚本 nginx_check.sh,这里提供一个:
#!/bin/bashA=`ps -C nginx --no-header | wc -l`if [ $A -eq 0 ];then/usr/sbin/nginx # 尝试重新启动nginxsleep 2 # 睡眠2秒if [ `ps -C nginx --no-header | wc -l` -eq 0 ];thenkillall keepalived # 启动失败,将keepalived服务杀死。将vip漂移到其它备份节点fifi

