赞
踩
http协议时超文本传输协议的缩写,用于从万维网服务器传输超文本到本地浏览器的传输协议
http工作原理
http协议工作于客户端-服务端架构上,浏览器作为http客户端通过url向http服务端即web服务器发送所有请求 web的服务器有:nginx、apache服务器、iis服务器等 web服务器根据接收到的请求后,向客户端发送响应信息 http默认端口号为80,但也可以修改为8080或其他端口 http三点注意事项: http是无连接的:无连接的含义是限制每次链接只处理一个请求,服务器处理完客户的请求,并受到客户的应答后,即断开连接,采用这种方式节省传输时间 http是媒体独立的:意味着只要客户端和服务端知道如何处理数据内容,任何类型的数据都可以通过http发送,客户端以及服务器指定使用适合的mime-type内容类型 http是无状态的:http协议是无状态协议,无状态是指对于事务处理没有记忆能力,缺少状态意味着如果后续处理需要前面的信息,则它必须重传,这样可能导致每次连接传送的数据量增大,另一方面,在服务器不要要先前信息时它的应答就较快。
以下图展示了http协议通信流程
http消息结构
http是基于客户端/服务端的架构模型,通过一个可靠的链接来交换信息,是一个无状态的请求/响应协议 一个http客户端是一个应用程序(web浏览器或其他任何客户端),通过连接到服务器达到向服务器发送一个或多个http的请求目的 一个http服务端同样也是一个应用程序(通常是一个web服务,如apache web服务器或iis服务器等),通过接受客户端的请求并向客户端发送http响应数据 http使用统一资源标识符来传输数据和建立连接 一旦建立连接后,数据消息就通过类似internet邮件所使用的格式和多用途internet邮件扩展来传送
客户端请求响应
客户端发送一个http请求到服务器的请求消息包括以下格式:请求行(request line)、请求头部(header)、空行和请求数据四个部分组成,下图给出了请求报文的一般格式
服务端响应消息
http响应也由四个部分组成,分别是:状态栏、消息报头、空行和响应正文
实例: 下列实例是典型的使用get来传递数据的实例: 客户端请求: connected to www.testpm.cn(42.244.247.240)prot 80 > GET /hello.txt HTTP/1.1 # 请求方式与版本协议。 > User-Agent: curl/7.29.0 #用什么客户端访问 > Host: www.testpm.cn #主机名,域名。主机和端口号, > Accept: */* #匹配什么文件类型,“*” 是通用匹配。匹配所有类型 服务端响应: < HTTP/1.1 200 OK #请求返回的状态码 < Server: nginx/1.22.0 #请求的服务和版本号 < Date: Thu, 04 Jul 2019 08:19:40 GMT < Content-Type: text/plain #文本类型,有html,plain:普通文本 < Content-Length: 12 < Last-Modified: Thu, 04 Jul 2019 08:13:25 GMT < Connection: keep-alive #是否支持长连接 < ETag: "5d1db525-c" #标识,每次访问如果与最开始的一样返回304否则校验不一致返回200 < Accept-Ranges: bytes 输出结果: hello world
http请求方法
根据http标准,http请求可以使用多种请求方法 http1.0定义了三种请求方法:GET,POST和HEAD方法 http1.1 新增了五种请求方法:OPTIONS,PUT,DELETE,TEACE和CONNECT方法 重点方法: GET 单纯获取数据(获取一个index.html页面) POST 上传/创建文件(会产生新的数据) PUT 保存数据(覆盖/更新文件,图片等,不会产生新的数据) DELETE 删除
http响应头消息
http请求头提供了关于请求,响应或者其他的发送实体的信息
应答头 | 说明 |
---|---|
Allow | 服务器支持哪些请求方法(如GET、POST等)。 |
Content-Encoding | 文档的编码(Encode)方法。只有在解码之后才可以得到Content-Type头指定的内容类型。利用gzip压缩文档能够显著地减少HTML文档的下载时间。Java的GZIPOutputStream可以很方便地进行gzip压缩,但只有Unix上的Netscape和Windows上的IE 4、IE 5才支持它。因此,Servlet应该通过查看Accept-Encoding头(即request.getHeader("Accept-Encoding"))检查浏览器是否支持gzip,为支持gzip的浏览器返回经gzip压缩的HTML页面,为其他浏览器返回普通页面。 |
Content-Length | 表示内容长度。只有当浏览器使用持久HTTP连接时才需要这个数据。如果你想要利用持久连接的优势,可以把输出文档写入 ByteArrayOutputStream,完成后查看其大小,然后把该值放入Content-Length头,最后通过byteArrayStream.writeTo(response.getOutputStream()发送内容。 |
Content-Type | 表示后面的文档属于什么MIME类型。Servlet默认为text/plain,但通常需要显式地指定为text/html。由于经常要设置Content-Type,因此HttpServletResponse提供了一个专用的方法setContentType。 |
Date | 当前的GMT时间。你可以用setDateHeader来设置这个头以避免转换时间格式的麻烦。 |
Expires | 应该在什么时候认为文档已经过期,从而不再缓存它? |
Last-Modified | 文档的最后改动时间。客户可以通过If-Modified-Since请求头提供一个日期,该请求将被视为一个条件GET,只有改动时间迟于指定时间的文档才会返回,否则返回一个304(Not Modified)状态。Last-Modified也可用setDateHeader方法来设置。 |
Location | 表示客户应当到哪里去提取文档。Location通常不是直接设置的,而是通过HttpServletResponse的sendRedirect方法,该方法同时设置状态代码为302。 |
Refresh | 表示浏览器应该在多少时间之后刷新文档,以秒计。除了刷新当前文档之外,你还可以通过setHeader("Refresh", "5; URL=http://host/path")让浏览器读取指定的页面。 注意这种功能通常是通过设置HTML页面HEAD区的<META HTTP-EQUIV="Refresh" CONTENT="5;URL=http://host/path">实现,这是因为,自动刷新或重定向对于那些不能使用CGI或Servlet的HTML编写者十分重要。但是,对于Servlet来说,直接设置Refresh头更加方便。 注意Refresh的意义是"N秒之后刷新本页面或访问指定页面",而不是"每隔N秒刷新本页面或访问指定页面"。因此,连续刷新要求每次都发送一个Refresh头,而发送204状态代码则可以阻止浏览器继续刷新,不管是使用Refresh头还是<META HTTP-EQUIV="Refresh" ...>。 注意Refresh头不属于HTTP 1.1正式规范的一部分,而是一个扩展,但Netscape和IE都支持它。 |
Server | 服务器名字。Servlet一般不设置这个值,而是由Web服务器自己设置。 |
Set-Cookie | 设置和页面关联的Cookie。Servlet不应使用response.setHeader("Set-Cookie", ...),而是应使用HttpServletResponse提供的专用方法addCookie。参见下文有关Cookie设置的讨论。 |
WWW-Authenticate | 客户应该在Authorization头中提供什么类型的授权信息?在包含401(Unauthorized)状态行的应答中这个头是必需的。例如,response.setHeader("WWW-Authenticate", "BASIC realm=\"executives\"")。 注意Servlet一般不进行这方面的处理,而是让Web服务器的专门机制来控制受密码保护页面的访问(例如.htaccess)。 |
当浏览者访问一个网页时,浏览者的浏览器会向所在服务器发出请求,当浏览器接收并显示网页前,此网页所在的服务器会返回一个包含http状态码的信息头用以响应浏览器的请求 http状态码的英文为http status code 下面是常见的http状态码 200 请求成功 301 资源(网页等)被永久转移到其他url 302 资源(网页等)被临时转移到其他url 403 服务器理解请求客户端的请求,但是拒绝执行此请求,权限不足 404 请求的资源(网页等)不存在 500 内部服务器错误
状态码分类 http状态码由三个十进制数字组成,第一个十进制数字定义了状态码的类型,后两个数字没有分类的作用,http状态码佛那个分为5种类型
http状态码列表
状态码 | 状态码英文名称 | 中文描述 |
---|---|---|
100 | Continue | 继续。客户端应继续其请求 |
101 | Switching Protocols | 切换协议。服务器根据客户端的请求切换协议。只能切换到更高级的协议,例如,切换到HTTP的新版本协议 |
200 | OK | 请求成功。一般用于GET与POST请求 |
201 | Created | 已创建。成功请求并创建了新的资源 |
202 | Accepted | 已接受。已经接受请求,但未处理完成 |
203 | Non-Authoritative Information | 非授权信息。请求成功。但返回的meta信息不在原始的服务器,而是一个副本 |
204 | No Content | 无内容。服务器成功处理,但未返回内容。在未更新网页的情况下,可确保浏览器继续显示当前文档 |
205 | Reset Content | 重置内容。服务器处理成功,用户终端(例如:浏览器)应重置文档视图。可通过此返回码清除浏览器的表单域 |
206 | Partial Content | 部分内容。服务器成功处理了部分GET请求 |
300 | Multiple Choices | 多种选择。请求的资源可包括多个位置,相应可返回一个资源特征与地址的列表用于用户终端(例如:浏览器)选择 |
301 | Moved Permanently | 永久移动。请求的资源已被永久的移动到新URI,返回信息会包括新的URI,浏览器会自动定向到新URI。今后任何新的请求都应使用新的URI代替 |
302 | Found | 临时移动。与301类似。但资源只是临时被移动。客户端应继续使用原有URI |
303 | See Other | 查看其它地址。与301类似。使用GET和POST请求查看 |
304 | Not Modified | 未修改。所请求的资源未修改,服务器返回此状态码时,不会返回任何资源。客户端通常会缓存访问过的资源,通过提供一个头信息指出客户端希望只返回在指定日期之后修改的资源 |
305 | Use Proxy | 使用代理。所请求的资源必须通过代理访问 |
306 | Unused | 已经被废弃的HTTP状态码 |
307 | Temporary Redirect | 临时重定向。与302类似。使用GET请求重定向 |
400 | Bad Request | 客户端请求的语法错误,服务器无法理解 |
401 | Unauthorized | 请求要求用户的身份认证 |
402 | Payment Required | 保留,将来使用 |
403 | Forbidden | 服务器理解请求客户端的请求,但是拒绝执行此请求 |
404 | Not Found | 服务器无法根据客户端的请求找到资源(网页)。通过此代码,网站设计人员可设置"您所请求的资源无法找到"的个性页面 |
405 | Method Not Allowed | 客户端请求中的方法被禁止 |
406 | Not Acceptable | 服务器无法根据客户端请求的内容特性完成请求 |
407 | Proxy Authentication Required | 请求要求代理的身份认证,与401类似,但请求者应当使用代理进行授权 |
408 | Request Time-out | 服务器等待客户端发送的请求时间过长,超时 |
409 | Conflict | 服务器完成客户端的PUT请求是可能返回此代码,服务器处理请求时发生了冲突 |
410 | Gone | 客户端请求的资源已经不存在。410不同于404,如果资源以前有现在被永久删除了可使用410代码,网站设计人员可通过301代码指定资源的新位置 |
411 | Length Required | 服务器无法处理客户端发送的不带Content-Length的请求信息 |
412 | Precondition Failed | 客户端请求信息的先决条件错误 |
413 | Request Entity Too Large | 由于请求的实体过大,服务器无法处理,因此拒绝请求。为防止客户端的连续请求,服务器可能会关闭连接。如果只是服务器暂时无法处理,则会包含一个Retry-After的响应信息 |
414 | Request-URI Too Large | 请求的URI过长(URI通常为网址),服务器无法处理 |
415 | Unsupported Media Type | 服务器无法处理请求附带的媒体格式 |
416 | Requested range not satisfiable | 客户端请求的范围无效 |
417 | Expectation Failed | 服务器无法满足Expect的请求头信息 |
500 | Internal Server Error | 服务器内部错误,无法完成请求 |
501 | Not Implemented | 服务器不支持请求的功能,无法完成请求 |
502 | Bad Gateway | 作为网关或者代理工作的服务器尝试执行请求时,从远程服务器接收到了一个无效的响应 |
503 | Service Unavailable | 由于超载或系统维护,服务器暂时的无法处理客户端的请求。延时的长度可包含在服务器的Retry-After头信息中 |
504 | Gateway Time-out | 充当网关或代理的服务器,未及时从远端服务器获取请求 |
505 | HTTP Version not supported | 服务器不支持请求的HTTP协议的版本,无法完成处理 |
1、nginx介绍
nginx是一个高性能的http和反向代理服务,也是一个mimap/pop3/smtp服务 nginx是一款轻量级的web服务器/反向代理服务器及电子邮件代理服务器,并在一个bsd-like协议下发行,特点是占有内存少,并发能力强,事实上nginx的并发能力确实在同类型的网页服务器中表现较好,中国大陆使用nginx网址用户有:百度、京东、新浪、网易、腾讯、淘宝等 在高连接并发的情况下,nginx是apache服务器不错的替代品
2、为什么选择nginx
nginx是一个高性能的web和反向代理服务器,它具有很多优越的特性 单机环境下参考服务器配置,并发连接数在7000-8000左右,集群模式20000+左右 作为web服务器:相比apache,nginx使用更少的资源,支持更多的并发连接,体现更高的效率,这点使nginx尤其受到虚拟主机提供商的欢迎,能够支持高达50000个并发连接数的响应 作为负载均衡器:nginx即可以在内部直接支持reils和php,也可以支持作为http代理服务器对外进行服务,nginx用c语言编写,不论是系统资源开销还是cpu使用效率都比perlbal要好的多 作为邮件代理服务器:nginx同时也是一个非常优秀的邮件代理服务器,last.fm描述了成功并且美妙的使用经验 nginx安装非常的简单,配置文件非常简介(还能够支持perl语法),bugs非常少的服务器:nginx启动特别容易,并且几乎可以做到7*24不间断运行,即使运行数个月也不需要重新启动,还能够在不间断服务器的情况下进行软件版本的升级
(1)、i/o multipexing多并发
第一种方法,最传统的多进程并发模型(每进来一个新的i/o流会分配一个新的进程管理)
第二种方法,i/o多路复用(单个线程,通过记录跟踪每个i/o流的状态,来同时管理多个i/o流) i/o multiplexing 这里面的 multiplexing 指的其实是在单个线程通过记录跟踪每一个Sock(I/O流)的状态来 同时管理多个I/O流。发明它的原因,是尽量多的提高服务器的吞吐能力。 在同一个线程里面, 通过拨开关的方式,来同时传输多个I/O流
(2)、nginx使用epoll接受请求的过程是怎样的
nginx会有很多连接进来,epoll会把他们都监视起来,然后像拨开关一样,谁有数据就拨向谁,然后调用相应的代码处理 select,poll,epoll都是i/o多路复用的具体的实现,他们出现是有先后顺序的 i/o多路复用这个概念被提出来以后,相继出现了多个方案 select是一个实现的 select被实现以后很快就暴露出了很多问题 select会修改传入的参数数组,这对于一个需要调用很多次的函数,是非常不友好的 select如果任何一个sock出现数据,select仅仅会返回,但是并不会告诉你是那个sock上有数据,只能自己一个个找 select只能监听1024个链接 select不是线程安全的,如果把一个sock加入到select,然后突然另外一个线程发现,这个sock不用,要收回,这个select不支持 poll去掉了1024个链接的限制,从设计上来说,不再修改传入数组,但是poll仍然不是线程安全的,只能在一个线程里面处理一组i/o流 epoll是i/o多路复用最新的一个实现,epoll修复了poll和select绝大部分问题,比如:epoll是线程安装的,epoll不仅会显示sock组里面的数据,还会具体显示哪个sock有数据
(3)、异步、非阻塞
pstree | grep nginx -------------------- |-nginx---4*[nginx] -------------------- 查看nginx下有几个进程 pstree 是用来显示进程树的命令行工具,和tree的效果差不多 nginx开启的时候会自动开启两个进程,1个master进程,多个worker进程,具体个数可以在nginx配置文件中定义 每进来一个request,会有一个worker进程去处理,但不是全部的处理,处理到可能发生阻塞的地方,比如向上游(后端)服务器转发request,并等待请求返回,那么这个处理的worker不会这么等着,会在发送去请求后注册一个事件“如果upstream返回了告诉我一声”,他就去休息去了,这就是异步,此时如果再有request进来,就可以再按这种方式来处理,这就是非阻塞和io多路复用,而一旦上游服务器返回了,就会触发这个事件,worker才回来接手,worker才会来接手,这request才会接着往下走,这就是异步回调
4、nginx的内部结束架构
nginx服务器,以其处理网络请求的高并发、高性能及高效率,获得了行业界的广泛认可,今年已稳居web服务器部署排名第二的位置,并被广泛用于反向代理和负载均衡 nginx器独特的内部技术结构设计,下图:
简要说明: 1、nginx启动时,会生成两种类型的进程,一个是主进程(master),一个或多个工作进程(worker)。主进程并不处理网络请求,主要负责调度工作进程,也就是图示的三项:加载配置、启动工作进程及非停升级,所以nginx启动后,查看操作系统的进程列表,至少能看到两个nginx进程 2、服务器实际处理网络请求及相应的是工作进程(worker),在类unix系统上,nginx可以配置多个worker,而每个worker进程都可以同时处理数以千记的网络请求 3、模块化设计,nginx的worker,包括核心和功能性模块,核心模块负责维持一个运行循环(run-loop),执行网络请求处理的不同阶段的模块功能,如网络读写、存储读写、内容传输、外出过滤、以及将请求发往上游服务器等,而其代码的模块化设计,也使得我们可以根据需要对功能模块进行适当的选择和修改,编译成具有特定功能的服务器 4、事件驱动,异步及非阻塞,可以说是nginx得以获得高并发、高性能的关键因素,同时也得益于linux、solaris及类bsd等操作系统内核中事件通知及i/o性能增强功能的采用、如kqueue、epoll及event ports 5、代理(proxy)设计,可以说是nginx深入骨髓的设计,无论是对于http,还是fastcgi、memcache、redis等的网络请求或响应,本质上都采用了代理机制,所有nignx天生就是高性能的代理服务器
nginx部署-yum安装 访问nginx官网:http://www.nginx.org nginx版本类型: mainline version 主线版,即开发版 stable version 最新的稳定版,生产环境上建议使用的版本 legacy version 遗留的老版本的稳定版 yum安装nginx 1、配置yum源的官网 wget http://nginx.org/download/nginx-1.26.0.tar.gz 2、需要设置nginx软件包的存储库 要设置yum存储库,需要创建名为/etc/yum.repos.d/nginx.repo的文件,并输入以下内容 ------------------------------- [nginx-stable] name=nginx stable repo baseurl=http://nginx.org/packages/centos/$releasever/$basearch/ gpgcheck=1 enabled=1 gpgkey=https://nginx.org/keys/nginx_signing.key [nginx-mainline] name=nginx mainline repo baseurl=http://nginx.org/packages/mainline/centos/$releasever/$basearch/ gpgcheck=1 enabled=0 gpgkey=https://nginx.org/keys/nginx_signing.key ------------------------------- 不交互模式修改配置 yum install -y yum-utils yum-config-manager --enable nginx-mainline 3、安装nginx软件包 yum install nginx -y 4、格式化打印 nginx -V 详细显示nginx的配置 nginx version: nginx/1.22.0 built by gcc 4.8.5 20150623 (Red Hat 4.8.5-44) (GCC) built with OpenSSL 1.0.2k-fips 26 Jan 2017 TLS SNI support enabled configure arguments: --prefix=/usr/local/nginx --group=nginx --user=nginx --sbin-path=/usr/local/nginx/sbin/nginx --conf-path=/etc/nginx/nginx.conf --error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --http-client-body-temp-path=/usr/local/nginx/tmp/client_body --http-proxy-temp-path=/usr/local/nginx/tmp/proxy --http-fastcgi-temp-path=/usr/local/nginx/tmp/fastcgi --pid-path=/var/run/nginx.pid --lock-path=/var/lock/nginx --with-http_stub_status_module --with-http_ssl_module --with-http_gzip_static_module --with-pcre --with-http_realip_module --with-stream --add-module=nginx-upstream-fair nginx -v 只显示nginx版本 5、设置开机启动 systemctl enable nginx 在浏览器输入ip进行访问
1、安装编译环境 yum install -y gcc gcc-c++ pcre pcre-devel openssl openssl-devel zlib zlib-devel libtermcap-devel readline-devel ncurses-devel bison libtool-ltdl bzip2-devel libicu-devel libunwind-devel libaio-devel 2、创建nginx用户 useradd nginx 3、安装nginx wget http://nginx.org/download/nginx-1.26.0.tar.gz 安装源码包 tar xzf nginx-1.26.0.tar.gz -C /usr/local 解压nginx源码包 MAKE_NGINX_PATH=/usr/local/nginx-1.22.0 添加变量 wget https://github.com/gnosek/nginx-upstream-fair/archive/master.zip -P $MAKE_NGINX_PATH && \ unzip $MAKE_NGINX_PATH/master.zip -d $MAKE_NGINX_PATH && \ mv $MAKE_NGINX_PATH/nginx-upstream-fair-master $MAKE_NGINX_PATH/nginx-upstream-fair 下载upstream模块压缩包,并将该模块放到上面定义的变量下面,解压模块压缩包并指定位置,修改名字 sed -ri "s/default_port/no_port/g" $MAKE_NGINX_PATH/nginx-upstream-fair/ngx_http_upstream_fair_module.c 修改版本问题,-r使用正则,-i确认修改 cd $MAKE_NGINX_PATH 进入/usr/local/nginx-1.22.0 ./configure --prefix=/usr/local/nginx \ --group=nginx \ --user=nginx \ --sbin-path=/usr/local/nginx/sbin/nginx \ --conf-path=/etc/nginx/nginx.conf \ --error-log-path=/var/log/nginx/error.log \ --http-log-path=/var/log/nginx/access.log \ --http-client-body-temp-path=/usr/local/nginx/tmp/client_body \ --http-proxy-temp-path=/usr/local/nginx/tmp/proxy \ --http-fastcgi-temp-path=/usr/local/nginx/tmp/fastcgi \ --pid-path=/var/run/nginx.pid \ --lock-path=/var/lock/nginx \ --with-http_stub_status_module \ --with-http_ssl_module \ --with-http_gzip_static_module \ --with-pcre \ --with-http_realip_module \ --with-stream \ --add-module=nginx-upstream-fair 设置编译参数 以上编译参数的详解 ------------------------------ ./configure --prefix=/usr/local/nginx \ --group=nginx \ 启动的组 --user=nginx \ 启动的用户 --sbin-path=/usr/local/nginx/sbin/nginx \ 命令 --conf-path=/etc/nginx/nginx.conf \ 配置文件 --error-log-path=/var/log/nginx/error.log \ 错误日志 --http-log-path=/var/log/nginx/access.log \ 访问日志 --http-client-body-temp-path=/usr/local/nginx/tmp/client_body \ 运行过程中产生的临时文件 --http-proxy-temp-path=/usr/local/nginx/tmp/proxy \ --http-fastcgi-temp-path=/usr/local/nginx/tmp/fastcgi \ --pid-path=/var/run/nginx.pid \ pid文件 --lock-path=/var/lock/nginx \ pid锁文件 --with-http_stub_status_module \ 模块 --with-http_ssl_module \ --with-http_gzip_static_module \ --with-pcre \ --with-http_realip_module \ --with-stream \ --add-module=nginx-upstream-fair 加入模块的路径 ------------------------------ make && make install && mkdir $MAKE_NGINX_PATH/tmp 编译,编译安装,创建目录tmp 4、nginx编译参数 /usr/local/nginx/sbin/nginx -V 模块参数具体功能 --------------------------------------------------------------------- --with-cc-opt='-g -O2 -fPIE -fstack-protector //设置额外的参数将被添加到CFLAGS变量。(FreeBSD或者ubuntu使用) --param=ssp-buffer-size=4 -Wformat -Werror=format-security -D_FORTIFY_SOURCE=2' --with-ld-opt='-Wl,-Bsymbolic-functions -fPIE -pie -Wl,-z,relro -Wl,-z,now' --prefix=/usr/local/nginx //指向安装目录 --conf-path=/etc/nginx/nginx.conf //指定配置文件 --http-log-path=/var/log/nginx/access.log //指定访问日志 --error-log-path=/var/log/nginx/error.log //指定错误日志 --lock-path=/var/lock/nginx.lock //指定lock文件 --pid-path=/run/nginx.pid //指定pid文件 --http-client-body-temp-path=/var/lib/nginx/body //设定http客户端请求临时文件路径 --http-fastcgi-temp-path=/var/lib/nginx/fastcgi //设定http fastcgi临时文件路径 --http-proxy-temp-path=/var/lib/nginx/proxy //设定http代理临时文件路径 --http-scgi-temp-path=/var/lib/nginx/scgi //设定http scgi临时文件路径 --http-uwsgi-temp-path=/var/lib/nginx/uwsgi //设定http uwsgi临时文件路径 --with-debug //启用debug日志 --with-pcre-jit //编译PCRE包含“just-in-time compilation” --with-ipv6 //启用ipv6支持 --with-http_ssl_module //启用ssl支持 --with-http_stub_status_module //获取nginx自上次启动以来的状态 --with-http_realip_module //允许从请求标头更改客户端的IP地址值,默认为关 --with-http_auth_request_module //实现基于一个子请求的结果的客户端授权。如果该子请求返回的2xx响应代码,所述接入是允许的。如果它返回401或403中,访问被拒绝与相应的错误代码。由子请求返回的任何其他响应代码被认为是一个错误。 --with-http_addition_module //作为一个输出过滤器,支持不完全缓冲,分部分响应请求 --with-http_dav_module //增加PUT,DELETE,MKCOL:创建集合,COPY和MOVE方法 默认关闭,需编译开启 --with-http_geoip_module //使用预编译的MaxMind数据库解析客户端IP地址,得到变量值 --with-http_gunzip_module //它为不支持“gzip”编码方法的客户端解压具有“Content-Encoding: gzip”头的响应。 --with-http_gzip_static_module //在线实时压缩输出数据流 --with-http_image_filter_module //传输JPEG/GIF/PNG 图片的一个过滤器)(默认为不启用。gd库要用到) --with-http_spdy_module //SPDY可以缩短网页的加载时间 --with-http_sub_module //允许用一些其他文本替换nginx响应中的一些文本 --with-http_xslt_module //过滤转换XML请求 --with-mail //启用POP3/IMAP4/SMTP代理模块支持 --with-mail_ssl_module //启用ngx_mail_ssl_module支持启用外部模块支持 --------------------------------------------------------------------- 5、修改配置文件/etc/nginx/nginx.conf 全局参数设置 worker_processes 4; 设置nginx启动的进程数量,一般设置成与逻辑cpu数量相同 error_log logs/error.log; 指定错误日志 woerker_rlimit_nofile 102400; 设置一个nignx进程能打开的最大文件数 pid /var/run/nginx.pid; 设置指定的pid,在kill-9的时候直接删除该文件中的数字即可杀死nginx的进程 events { 如何处理网络连接 worker_connections 1024; 设置一个进程的最大并发数 } http服务相关设置 http { include mime.types: 调用该文件所在的的目录中mime.types文件 default_type application/octet-stream; 如果找不到mime.types文件则使用该文件 log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"'; access_log /var/log/nginx/access.log main; 日志文件的位置 sendfile on; 是否调用sendfile函数输出文件,一般设置为on,若nginx是用来进行磁盘io负载应用时,可以设置为off,降低系统负载 gizp on; 是否开启gzip压缩,将注释去掉开启 keepalive_timeout 65; 设置最长连接的超时时间 虚拟服务器的相关设置 server { listen 80; 设置监听的端口 server_name localhost; 设置绑定的主机名、域名或IP地址 charser utf-8; 设置编码字符 location / { root /var/www/nginx; 设置服务器默认网络的根目录位置,需要手动创建 index index,html 设置默认打开的文档 } error_page 500 502 503 504 /50x.html; 设置错误信息的返回页面 location = /50x.html; root /usr/local/nginx/html; 显示错误的界面文档 } } nginx.conf的组成: nginx.conf一共有三部分组成,分别为:全局块、events块、http块。在http块中又包含http全局块、多个server块,每个server块中又包含server全局块以及多个location块。在同一配置块中嵌套的配置块,各个之间不存在次序关系 6、检测nginx配置文件是否正确 /usr/local/nginx/sbin/nginx -t 7、启动nginx服务 /usr/local/nginx/sbin/nginx 添加环境变量方法一 echo 'export PATH=$PATH:/usr/local/nginx/bin'>>/etc/profile 添加环境变量方法二 ln -s /usr/local/nginx/sbin/nginx /usr/bin/nginx 8、通过nginx命令控制nginx服务 nginx -c /pate/nginx.conf 以特定目录下的配置文件启动nginx nginx -s reload 修改配置后重新加载生效 nginx -s reopen 重新打开日志文件 nginx -s stop 快速停止nginx nginx -s quit 完整有序的停止nginx nginx -t 测试当前配置文件是否正确 nginx -t -c /path/to/nginx.conf 测试特定的nginx配置文件是否正确 注意: nginx -s reload 命令加载修改后的配置文件,命令下达后发生如下事件 (1)、nginx的master进程检查配置文件的正确性,若是错误则返回错误信息,nginx继续采用原配置文件进行工作(因为worker未受到影响) (2)、nginx启动新的worker进程,采用新的配置文件 (3)、nginx将新的请求分配给新的worker进程 (4)、nginx等待以前的worker进程的全部请求已经都返回后,关闭相关的worker进程 (5)、重复上面过程,直到全部旧的worker进程都被关闭掉 9、实现nginx开机自启 vim /usr/lib/systemd/system/nginx.service ------------------------------ [Unit] Description=The nginx HTTP and reverse proxy server After=network-online.target remote-fs.target nss-lookup.target Wants=network-online.target [Service] Type=forking PIDFile=/run/nginx.pid ExecStartPre=/usr/bin/rm -f /run/nginx.pid ExecStartPre=/usr/local/nginx/sbin/nginx -t ExecStart=/usr/local/nginx/sbin/nginx ExecReload=/usr/local/nginx/sbin/nginx -s reload KillSignal=SIGQUIT TimeoutStopSec=5 KillMode=process PrivateTmp=true [Install] WantedBy=multi-user.target ------------------------------ systemctl daemon-reload systemctl enable nginx --now 10、nginx日志文件详解 nginx日志文件分为log_format和access_log两部分 log_format 定义记录的格式,其语法为 log_format 样式名称 格式详情 配置文件中默认有 log_format main 'remote_addr - remote_user [time_local] "request" ' 'status body_bytes_sent "$http_referer" ' '"http_user_agent" "http_x_forwarded_for"'; 详细解释:远程用户的名称,通常是-,除非在nginx中启用了http基本身份验证 log_format nginx配置命令,用于定义日志的格式 main 日志格式的名称,可以在其他nginx配置中使用这个名称来引用这个格式 remote_addr 客户端的ip地址 remote_user 远程用户的名称,通常是-,除非在nginx中启用了http基本身份验证 [time_local] 请求的本地时间 request 完整的原始请求行,例如:GET /index.html HTTP/1.1 status http响应的状态码,例如:200、404等 body_bytes_sent 发送给客户端的响应体的大小(以字节为单位) $htpp_referer 请求头中的referer字段,表示请求的来源url,如果请求没有引用页面,则该字段为空 $http_user_agent 请求头中的user-agent字段,描述了发送请求的浏览器或者其他客户端的类型 $http_x_forwarded_for 请求头中的x-forwarded-for字段,这通常用于标识http请求的ip来源地址,当请求通过代理或负载均衡器时特别有用 访问日志的模板: 192.168.253.1 - - [23/Jun/2024:17:14:41 +0800] "GET /favicon.ico HTTP/1.1" 404 3332 "http://192.168.253.143/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36" "-"
log_format日志文件参数
log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"'; $remote_addr 描述:客户端的IP地址。如果Nginx位于反向代理(如负载均衡器)后面,并且您希望记录实际客户端的IP地址,您可能需要配置real_ip_header指令和set_real_ip_from指令。 示例:192.168.1.1 $remote_user 描述:如果Nginx配置了基本认证,则此变量包含用户名。否则,它通常是空的。 示例:username [$time_local] 描述:记录请求时间的本地时区。 示例:[10/Oct/2023:14:02:03 +0800] "$request" 描述:完整的HTTP请求行,包括方法(如GET或POST)、请求的URI和HTTP协议版本。 示例:"GET /index.html HTTP/1.1" $status 描述:HTTP响应状态码。 示例:200(表示成功)或404(表示未找到) $body_bytes_sent 描述:发送给客户端的响应体字节数,不包括响应头。 示例:1234 "$http_referer" 描述:HTTP头部中的"Referer"字段的值,表示请求的来源页面。如果没有,则为"-"。 示例:"https://www.example.com/another-page.html" 或 "-" "$http_user_agent" 描述:HTTP头部中的"User-Agent"字段的值,表示发出请求的客户端信息(如浏览器类型、版本等)。 示例:"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/106.0.0.0 Safari/537.36" "$http_x_forwarded_for" 描述:HTTP头部中的"X-Forwarded-For"字段的值,通常用于记录原始客户端的IP地址,当请求通过代理或负载均衡器传递时。 示例:"10.0.0.1, 192.168.1.1"
nginx配置文件格式
全局配置块 user nginx; worker_processes suto; error_log /var/log/nginx/error.log; pid /run/nginx.pid; epoll 驱动配置 events { #一般不修改,目的是优化nginx worker_connections 1024; } 协议块 http { 常见配置 1、日志格式 2、默认类型 # 虚拟主机 server{ 常见配置 1、监听的ip和端口 2、域名 # 请求级别 location / { 网页在哪里 转发到某一台 } }
7、nginx高级应用
使用alias实现虚拟目录
location /test { root /usr/share/nginx/html; index index.html; } 配置文件中定义为root,在浏览器访问ip/test,访问的将是/usr/share/nginx/html/test/index.html location /test { alias /usr/share/nginx/html; index index.html; } 配置文件中定义为alias,在浏览器访问ip/test,访问的将是/var/share/nginx/html/index.html alias定义的是一个真实存在的路径,但是location后面跟的路径是为假的 root定义的是一个真实存在的路径,但是location后面跟的路径必须是真的,否则会显示页面访问不到
通过stub_status模块进行监控nginx的工作状态
1、通过nginx -V命令查看是否已安装stub_status模块 2、编辑/etc/nginx/nginx.conf配置文件 -------------------------------------------- location /nginx-status { stub_status on; access_log /var/log/nginx/nginxstatus.log; 设置日志文件的位置 auth_basic "nginx-status"; 指定认证机制(与location后面的内容相同即可) auth_basic_user_file /etc/nginx/htpasswd; 指定认证的密码文件 } -------------------------------------------- 3、创建认证口令文件并添加用户qianfeng和zdgg,密码用md5加密 yum install -y httpd-tools htpasswd -c -m /etc/nginx/htpasswd jiaming -c覆盖密码文件,-m MD5加密 htpasswd -m /etc/nginx/htpasswd zsgg 4、重启服务 nginx -s reload 5、客户端访问http://ip/nginx-status即可 Active connections: 2 server accepts handled requests 27 27 40 Reading: 0 Writing: 1 Waiting: 1 Active connections – 活跃的连接数量 server accepts handled requests — 总共处理了27个连接 , 成功创建27次握手, 总共处理了40个请求。 reading — 读取客户端的连接数。 writing — 响应数据到客户端的数量。 waiting — 开启 keep-alive 的情况下,这个值等于 active – (reading+writing), 意思就是 Nginx 已经处理完正在等候下一次请求指令的驻留连接。 注意:使用htpawwsd命令需要先安装httpd-tools
使用limit_rate限制客户端传输的速度
编辑/etc/nginx/nginx.conf ----------------------- location / { root /usr/share/nginx/html; autoindex on; 将软件下载到本地,使客户端可以直接下载,但是存放软件包的目录下,只能有软件包,如果有其他的文件或目录,否则会导致访问不到软件包 limit_rate 2k; 对每个连接的限速为2k/s } ----------------------- nginx -s stop 浏览器中直接访问主机ip即可,可以看到软件包
什么是虚拟主机
虚拟主机是一种特殊的软硬件技术,它可以将网络上的每一台计算器分成多个虚拟主机,每个虚拟主机可以独立对外提供www服务,这样就可以实现一台主机对外提供多个web服务,每个虚拟主机之间是独立的,互不影响。 nginx可以实现虚拟主机的配置,nginx支持三种类型的虚拟主机配置 1、基于域名的虚拟主机(servre_name来区分虚拟主机--应用:外部网站) 2、基于ip的虚拟主机(一台主机绑定多个ip地址) 3、基于端口的虚拟主机(端口来区分虚拟主机--应用:公司内部网络,外部网站的管理后台)
基于端口、ip、域名的环境
yum install -y nginx echo 123 > /usr/share/nginx/html/index.html echo 456 > /usr/share/nginx/html/default.html 以下的配置均在nginx配置文件中的server模块中添加
基于端口的虚拟主机
vim /etc/nginx/nginx.conf ----------------------------------------- server { listen 80; root /usr/share/nginx/html; index index.html; } server { listen 81; root /usr/share/nginx/html; index default.html; } ----------------------------------------- 浏览器中访问主机ip:80端口,访问页面为123 浏览器中访问主机ip:81端口,访问页面为456 Windows是会根据后缀来判断文件类型的,如果后缀Windows识别不出来就会自动下载下来
基于ip的虚拟主机
vim /etc/nginx/nginx.conf ----------------------------------------- server { listen 192.168.253.131:80; root /usr/share/nginx/html; index index.html; } server { listen 192.168.253.130:80; root /usr/share/nginx/html; index default.html; } ----------------------------------------- 修改完配置需要重新启动nginx,nginx -s reload刷新配置文件没有用 浏览器中访问主机192.168.253.131,访问页面为123 浏览器中访问主机192.168.253.130,访问页面为456
基于域名的虚拟主机
vim /etc/nginx/nginx.conf ----------------------------------------- server { listen 80; server_name www.index.com; root /usr/share/nginx/html; index index.html; } server { listen 80; server_name www.default.com; root /usr/share/nginx/html; index default.html; } ----------------------------------------- 需要在windows的文件管理中,"C:\Windows\System32\drivers\etc\hosts"文件下添加ip和域名 例如:192.168.253.131 www.index.com www.default.com 修改完配置需要重新启动nginx,nginx -s reload刷新配置文件没有用 浏览器中访问主机www.index.com,访问页面为123 浏览器中访问主机www.default.com,访问页面为456 配置时尽量是全域名,www.jiaming.com这样,不要写成jiaming.com容易匹配不到
9、nginx proxy代理
(1)、代理原理
反向代理产生的背景: 在计算器世界里,由于单个服务器的处理客户端请求能力有一个极限,当用户的接入请求蜂拥而入时,会造成服务器忙不过来的局面,可以使用多个服务器来共同分担成千上万的用户请求,这些服务器提供相同的服务,对于用户来说,根本感觉不到任何差别 反向代理服务器的实现: 需要有一个负载均衡设备(即反向代理服务器)来分发用户请求,将用户请求分发到空闲的服务器上,服务器返回自己的服务器到负载均衡设备,负载均衡设备将服务器的服务返回用户
(2)、正/反向代理的区别
正向代理: 正向代理的过程隐藏了真实的请求客户端,服务器不知道真是的客户端是谁,客户端请求的服务端都被代理服务器代替请求。正向代理代理的是请求方,也就是客户端。比如要访问国外的软件,一般不能访问,只能先安装一个翻墙的软件,让翻墙软件代理我去访问国外的软件,这个软件就叫做正向代理 正向代理中,proxy和client同属一个lan
反向代理: 反向代理的过程中隐藏了真实的服务器,客户不知道真正提供服务的人是谁,客户端请求的服务器都被代理服务器处理,反向代理代理的是响应方。请求www.baidu.com时,Www.baidu.com就是反向代理服务器,真实提供服务的服务器有很多台,反向代理服务器会把我们的请求分转发到真实提供服务的各台服务器,nginx就是性能非常好的反向代理服务器,用来做负载均衡 访问www.baidu.com时正向代理的过程
正向代理和反向代理对比示意图 两者的区别在于代理的对象不一样: 正向代理中代理的对象是客户端,proxy和client同属一个lan,对server透明 反向代理中代理的对象是服务端,proxy和server同属一个lan,对client透明
(3)、知识扩展
1、没有使用lvs时,客户端请求直接到反向代理nginx,nginx分发到各个服务器,服务端响应再由nginx返回给客户端,这样请求和响应都经过nginx的模型使其性能降低,这时用lvs+nginx解决 2、lvs+nginx,客户端请求先有lvs接受,分发给nginx,再由nginx转发给服务端,lvs有三种方式:NAT模式(natwork address tarnslation)网络转换地址,DR模式(直接路由模式),ip隧道模式,路由方式使服务器响应不经过lvs,由nginx直接返回给客户端。
1、http server和application server的区别和联系 apache/nginx使静态服务器(http server): nginx优点:负载均衡、反向代理、处理静态文件优势。nginx处理静态请求的速度高于apache; apache优点:相对于tomcat服务器来说,处理静态文件是它的优势,速度快。apache是静态解析,适合静态html、图片等。 http server关心的是http协议层面的传输和访问控制,所以apache/nginx上可以看到代理、负载均衡等功能 http server(nginx/apache)常用作静态内容服务和代理服务器,将外来请求转发给后面的应用服务(tomcat、jboss、jetty等) 应用服务器(tomcat/jboss/jetty)是动态服务器(application server): 应用服务器application server是一个应用执行的容器,他首先需要支持开发语言的runtime(对于tomcat来说,就是java,若是ruby/pathon等其他语言开发的应用也无法直接运行在tomcat上)。 2、应用服务器(如tomcat)往往也会集成 HTTP Server 的功能,nginx也可以通过模块开发来提供应用功能,只是不如专业的 HTTP Server 那么强大,所以应用服务器往往是运行在 HTTP Server 的背后,执行应用,将动态的内容转化为静态的内容之后,通过 HTTP Server 分发到客户端。 3、常用开源集群软件有:lvs,keepalived,haproxy,nginx,git,jenkins,ansible,tomcat,zabbix,rabbitmq,redis,apache,heartbeat 常用商业集群硬件有:F5, Netscaler,Radware,A10等
需要使用到squid软件包 yum install -y squid vim /etc/squid/squid.conf
acl jiaming src 192.168.253.0/24 定义一个名为jiaming的访问控制列表(ACL),匹配来自192.168.253.0/24子网的源ip地址 http_access allow jiaming 使用http_access指令允许来自ACL定义jiaming源ip地址的请求 systemctl restart squid
acl denytest url_regex -i jd 解释: acl 表示定义或声明一个访问控制列表 denytest 是acl定义规则的名字 usl_reges 表示acl规则将使用正则表达式来匹配请求的url -i 表示正则表达式匹配时忽略大小写 jd 用于匹配url中包含jd的请求 http_access deny all 解释: http_access 表示定义HTTP请求的访问权限 deny 表示拒绝匹配该条件的请求。 all 表示这条规则适用于所有用户或所有来源的请求,这里没有引用前面定义的denytest ACL。 要使这条规则与denytest ACL关联,可以这么做 http_access deny denytest systemctl restart squid 重启服务,使规则生效 在浏览器设置中添加代理,代理ip为配置squid的机器ip 成功访问浏览器的网页代表正向代理成功 或者在squid的访问日志中查看 tail -f /var/log/squid/access.log
(4)、nginx proxy配置
ngx_http_proxy_module 代理模块 ============================================================== 代理 Syntax: proxy_pass URL; #代理的后端服务器URL Default: — Context: location, if in location, limit_except 缓冲区 Syntax: proxy_buffering on | off; Default: proxy_buffering on; #缓冲开关 Context: http, server, location proxy_buffering开启的情况下,nignx会把后端返回的内容先放到缓冲区当中,然后再返回给客户端 (边收边传,不是全部接收完再传给客户端)。 Nginx 全局配置中的 tcp_nopush 的作用就是 数据包会累计到一定大小之后才会发送 。而 tcp_nodelay 是尽快发送数据,所以若你启用了 buffer,建议关闭 tcp_nodelay。 Syntax: proxy_buffer_size size; Default: proxy_buffer_size 4k|8k; #缓冲区大小 Context: http, server, location Syntax: proxy_buffers number size; Default: proxy_buffers 4k|8k; #缓冲区数量 Context: http, server, location Syntax: proxy_busy_buffers_size size; Default: proxy_busy_buffers_size 8k|16k;#忙碌的缓冲区大小控制同时传递给客户端的buffer数量 Context: http, server, location 头信息 Syntax: proxy_set_header field value; Default: proxy_set_header Host $proxy_host; #设置真实客户端地址 proxy_set_header Connection close; Context: http, server, location 超时 Syntax: proxy_connect_timeout time; Default: proxy_connect_timeout 60s; #链接超时 Context: http, server, location Syntax: proxy_read_timeout time; Default: proxy_read_timeout 60s; Context: http, server, location Syntax: proxy_send_timeout time; #nginx进程向fastcgi进程发送request的整个过程的超时时间 Default: proxy_send_timeout 60s; Context: http, server, location #buffer 工作原理 1. 所有的proxy buffer参数是作用到每一个请求的。每一个请求会按照参数的配置获得自己的buffer。proxy buffer不是global而是 request的。 2. proxy_buffering 是为了开启response buffering of the proxied server,开启后proxy_buffers和proxy_busy_buffers_size参数才会起作用。 3. 无论proxy_buffering是否开启,proxy_buffer_size(main buffer)都是工作的,proxy_buffer_size所设置的buffer_size的作用是用来存储upstream端response的header。 4. 在proxy_buffering 开启的情况下,Nginx将会尽可能的读取所有的upstream端传输的数据到buffer,直到proxy_buffers设置的所有buffer们 被写满或者数据被读取完(EOF)。此时nginx开始向客户端传输数据,会同时传输这一整串buffer们。同时如果response的内容很大的话,Nginx会接收并把他们写入到temp_file里去。大小由proxy_max_temp_file_size控制。如果busy的buffer 传输完了会从temp_file里面接着读数据,直到传输完毕。 5. 一旦proxy_buffers设置的buffer被写入,直到buffer里面的数据被完整的传输完(传输到客户端),这个buffer将会一直处在busy状态,我们不能对这个buffer进行任何别的操作。所有处在busy状态的buffer size加起来不能超过proxy_busy_buffers_size,所以proxy_busy_buffers_size是用来控制同时传输到客户端的buffer数量的。
启用nginx proxy代理
环境:两台nginx真实服务器 一台用于后端真实服务器,一台用于代理服务器 =================================================== 后端真实服务器 yum install -y nginx nginx echo 123 > /usr/share/nginx/html/index.html =================================================== 代理服务器: yum install -y nginx vim /etc/nginx/nginx.conf ----------------------------------- server { listen 80; server_name localhost; location / { proxy_pass http://10.0.105.199:80; proxy_redirect default; proxy_set_header Host $http_host; proxy_set_header X-Real-IP $remote_addr; #proxy_set_header REMOTE-HOST $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_connect_timeout 30; proxy_send_timeout 60; proxy_read_timeout 60; proxy_buffering on; proxy_buffer_size 32k; proxy_buffers 4 128k; proxy_busy_buffers_size 256k; proxy_max_temp_file_size 256k; } ----------------------------------- nginx 启动nginx nginx -s reload 重新加载配置文件
nginx proxy配置文件详解
proxy_pass :真实服务器的地址,可以是ip也可以是域名和url地址 proxy_redirect :如果真实服务器使用的是的真实IP:非默认端口。则改成IP:默认端口。 proxy_set_header:重新定义或者添加发往后端服务器的请求头 proxy_set_header X-Real-IP :启用客户端真实地址(否则日志中显示的是代理在访问网站) proxy_set_header X-Forwarded-For:记录代理地址 proxy_connect_timeout::后端服务器连接的超时时间发起三次握手等候响应超时时间 proxy_send_timeout:后端服务器数据回传时间就是在规定时间之内后端服务器必须传完所有的数据 proxy_read_timeout :nginx接收upstream(上游/真实) server数据超时, 默认60s, 如果连续的60s内没有收到1个字节, 连接关闭。像长连接 proxy_buffering on;开启缓存 proxy_buffer_size:proxy_buffer_size只是响应头的缓冲区 proxy_buffers 4 128k; 内容缓冲区域大小 proxy_busy_buffers_size 256k; 从proxy_buffers划出一部分缓冲区来专门向客户端传送数据的地方 proxy_max_temp_file_size 256k;超大的响应头存储成文件。 proxy_set_header X-Real-IP 未配置 Nginxbackend 的日志:记录只有192.168.107.112 配置 Nginxbackend 的日志,记录的有192.168.107.16 192.168.107.107 192.168.107.112 proxy_buffers 的缓冲区大小一般会设置的比较大,以应付大网页。 proxy_buffers当中单个缓冲区的大小是由系统的内存页面大小决定的,Linux系统中一般为4k。 proxy_buffers由缓冲区数量和缓冲区大小组成的。总的大小为number*size。 若某些请求的响应过大,则超过_buffers的部分将被缓冲到硬盘(缓冲目录由_temp_path指令指定), 当然这将会使读取响应的速度减慢, 影响用户体验. 可以使用proxy_max_temp_file_size指令关闭磁盘缓冲.
(5)、nginx负载均衡
负载均衡的作用
如果你的nginx服务器给2台web服务器做代理,负载均衡算法采用轮询,那么当你的一台机器web程序关闭造成web不能访问,那么nginx服务器分发请求还是会给这台不能访问的web服务器,如果这里的响应连接时间过长,就会导致客户端的页面一直在等待响应,对用户来说体验就打打折扣,这里我们怎么避免这样的情况发生呢。这里我配张图来说明下问题。
如果负载均衡中其中web2发生这样的情况,nginx首先会去web1请求,但是nginx在配置不当的情况下会继续分发请求道web2,然后等待web2响应,直到我们的响应时间超时,才会把请求重新分发给web1,这里的响应时间如果过长,用户等待的时间就会越长。
配置解决方案
proxy_connect_timeout 1; #nginx服务器与被代理的服务器建立连接的超时时间,默认60秒 proxy_read_timeout 1; #nginx服务器向被代理服务器组发出read请求后,等待响应的超时间,默认为60秒。 proxy_send_timeout 1; #nginx服务器向被代理服务器组发出write请求后,等待响应的超时间,默认为60秒。 proxy_ignore_client_abort on; #客户端断网时,nginx服务器是否中断对被代理服务器的请求。默认为off。 使用upstream指令配置一组服务器作为被代理服务器,服务器中的访问算法遵循配置的负载均衡规则,同时可以使用该指令配置在发生哪些异常情况时,将请求顺次交由下一组服务器处理. proxy_next_upstream timeout; #反向代理upstream中设置的服务器组,出现故障时,被代理服务器返回的状态值。error|timeout|invalid_header|http_500|http_502|http_503|http_504|http_404|off error 建立连接或向被代理的服务器发送请求或读取响应信息时服务器发生错误。 timeout 建立连接,想被代理服务器发送请求或读取响应信息时服务器发生超时。 invalid_header 被代理服务器返回的响应头异常。 off 无法将请求分发给被代理的服务器。 http_400,.... 被代理服务器返回的状态码为400,500,502,等
upstream 这个配置是写一组被代理的服务器地址,然后配置负载均衡的算法。这里的被代理服务器地址有两种写法。 vim /etc/nginx/nginx.conf ----------------------------------- upstream jiaming { server 192.168.253.140:80; server 192.168.253.142:80; } server { listen 80; location / { proxy_pass http://jiaming; } } -----------------------------------
负载均衡算法
upstream 支持4种负载均衡调度算法: 轮询(默认) 每个请求按时间顺序逐一分配到不同的后端服务器; ip_hash 每个请求按访问IP的hash结果分配,同一个IP客户端固定访问一个后端服务器。可以保证来自同一ip的请求被打到固定的机器上,可以解决session问题。 hash $request_url 按访问url的hash结果来分配请求,使每个url定向到同一个后端服务器。后台服务器为缓存的时候提高效率。 fair 这是比上面两个更加智能的负载均衡算法。此种算法可以依据页面大小和加载时间长短智能地进行负载均衡,也就是根据后端服务器的响应时间来分配请求,响应时间短的优先分配。Nginx本身是不支持fair的,如果需要使用这种调度算法,必须下载Nginx的 upstream_fair模块。
热备:如果你有2台服务器,当一台服务器发生事故时,才启用第二台服务器给提供服务。服务器处理请求的顺序:AAAAAA突然A挂了,BBBBBBBBBBBBBB..... --------------------------------------- upstream myweb { server 172.17.14.2:8080; server 172.17.14.3:8080 backup; #热备 } --------------------------------------- 轮询:nginx默认就是轮询其权重都默认为1,服务器处理请求的顺序:ABABABABAB.... --------------------------------------- upstream myweb { server 172.17.14.2:8080; server 172.17.14.3:8080; } --------------------------------------- 加权轮询:跟据配置的权重的大小而分发给不同服务器不同数量的请求。如果不设置,则默认为1。下面服务器的请求顺序为:ABBABBABBABBABB.... --------------------------------------- upstream myweb { server 172.17.14.2:8080 weight=1; server 172.17.14.3:8080 weight=2; } --------------------------------------- ip_hash:nginx会让相同的客户端ip请求相同的服务器。 --------------------------------------- upstream myweb { server 172.17.14.2:8080; server 172.17.14.3:8080; ip_hash; } --------------------------------------- nginx负载均衡配置状态参数 down 表示当前的server暂时不参与负载均衡。 backup 预留的备份机器。当其他所有的非backup机器出现故障或者忙的时候,才会请求backup机器,因此这台机器的压力最轻。 max_fails 允许请求失败的次数,默认为1。当超过最大次数时,返回proxy_next_upstream 模块定义的错误。 fail_timeout 在经历了max_fails次失败后,暂停服务的时间单位秒。max_fails可以和fail_timeout一起使用
nginx配置7层协议及4层协议方法
7层协议 OSI(Open System Interconnection)是一个开放性的通行系统互连参考模型,他是一个定义的非常好的协议规范,共包含七层协议。直接上图,这样更直观些:
4层协议 TCP/IP协议 之所以说TCP/IP是一个协议族,是因为TCP/IP协议包括TCP、IP、UDP、ICMP、RIP、TELNETFTP、SMTP、ARP、TFTP等许多协议,这些协议一起称为TCP/IP协议。 从协议分层模型方面来讲,TCP/IP由四个层次组成:网络接口层、网络层、传输层、应用层。
在nginx做负载均衡,负载多个服务,部分服务是需要7层的,部分服务是需要4层的,也就是说7层和4层配置在同一个配置文件中。 环境部署: 一台代理服务器,两台后端真实服务器 代理服务器使用nginx作为代理软件 后端真实服务器作为四七层服务 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 配置代理服务器的nginx配置文件 vim /etc/nginx/nginx.conf ----------------------------- #七层配置 upstream testweb { server 10.0.105.199:80; server 10.0.105.202:80; } server { listen 80; location / { proxy_pass http://testweb; } } } #四层配置 stream { upstream myweb { server 10.0.105.199:8081; server 10.0.105.202:8081; } server { listem 81; proxy_pass myweb; } } ----------------------------- yum安装的nginx默认不可以直接使用stream模块,需要下载一个依赖 yum search nginx 查看yum下载nginx自带的模块 yum install -y nginx-mod-stream.x86_64 下载这个模块后,stream模块才可以使用 浏览器中访问代理服务器ip:80端口,跳转到被代理服务器的80端口,采用轮询模式 浏览器中访问代理服务器ip:81端口,跳转到被代理服务器的8081端口,采用轮询模式
完整版四七层同时布置
代理服务器 vim /etc/nginx/nginx.conf ------------------------------------- http { upstream jiaming { server 192.168.253.149:80; server 192.168.253.141:80; } server { listen 80; location / { proxy_pass http://jiaming; } } } stream { upstream li { server 192.168.253.141:81; server 192.168.253.149:81; } server { listen 81; proxy_pass li; } } ------------------------------------- 两台后端真实服务器,配置相同即可 ------------------------------------- http { #..... server { listen 80; location / { root /usr/share/nginx/html1; index index.html; } } server { listen 81; location / { root /usr/share/nginx/html2; index index.html; } } } ------------------------------------- 在第一台后端真实服务器上创建发布目录文件 mkdir /usr/share/nginx/html1 /usr/share/nginx/html2 echo nginx1-80 > /usr/share/nginx/html1/index.html echo nginx1-81 > /usr/share/nginx/html2/index.html 在第台后端真实服务器上创建发布目录文件 mkdir /usr/share/nginx/html1 /usr/share/nginx/html2 echo nginx2-80 > /usr/share/nginx/html1/index.html echo nginx2-80 > /usr/share/nginx/html2/index.html 浏览器中访问代理服务器ip的80端口和81端口,会代理到后端真实服务器相对应的内容
(6)、nginx会话保持
nginx会话保持主要有以下几种实现方式 1、ip_hash ip_hash使用源地址哈希算法,将同一客户端的请求总是发往同一个后端服务器,除非该服务器不可用。 ----------------------------- upstream myweb { server 192.168.253.100:80; server 192.168.253.101:80; ip_hash; } ----------------------------- ip_hash简单易用,但有如下问题: 当后端服务器宕机后,session会丢失; 来自同一局域网的客户端会被转发到同一个后端服务器,可能导致负载失衡; 不适用于CDN网络,不适用于前段还有代理的情况。 2、sticky_cookie_insert 使用sticky_cookie_insert启用会话亲缘关系,这会导致来自同一客户端的请求被传递到一组服务器的同一台服务器。与ip_hash不同之处在于,它不是基于IP来判断客户端的,而是基于cookie来判断。因此可以避免上述ip_hash中来自同一局域网的客户端和前段代理导致负载失衡的情况。(需要引入第三方模块才能实现) ----------------------------- upstream myweb { server 192.168.253.100:80; server 192.168.253.101:80; sticky expires=1h domain=3evip.cn path=/; #sticky 用于确保客户端的后续请求被路由到处理其第一个请求的同一服务器 #expires=1h: 客户端的会话粘性在1小时后过期。过期后,Nginx Plus将不再确保后续请求被路由到同一服务器。 #domain=3evip.cn: 这定义了哪些域名(或子域名)的请求应该具有粘性。在这个例子中,只有来自3evip.cn的请求(以及它的任何子域名)才会具有粘性。 #path=/: 这定义了哪些URL路径的请求应该具有粘性。/表示所有路径的请求都应该有粘性。如果你只想让特定路径的请求具有粘性,你可以修改这个值。 } ----------------------------- 说明: expires:设置浏览器中保持cookie的时间 domain:定义cookie的域 path:为cookie定义路径 jvm_route jvm_route是通过session_cookie这种方式来实现session粘性。将特定会话附属到特定tomcat上,从而解决session不同步问题,但是无法解决宕机后会话转移问题。如果在cookie和url中并没有session,则这只是个简单的round-robin负载均衡。 3、jvm_route jvm_route是通过session_cookie这种方式来实现session粘性。将特定会话附属到特定tomcat上,从而解决session不同步问题,但是无法解决宕机后会话转移问题。如果在cookie和url中并没有session,则这只是个简单的round-robin负载均衡。 jvm_route的原理 一开始请求过来,没有带session的信息,jvm_route就根据round robin的方法,发到一台Tomcat上面 Tomcat添加上session信息,并返回给客户 用户再次请求,jvm_route看到session中有后端服务器的名称,他就把请求转到对应的服务器上 暂时jvm_route模块还不支持fair的模式。jvm_route的工作模式和fair是冲突的。对于某个特定用户,当一直为他服务的Tomcat宕机后,默认情况下它会重试max_fails的次数,如果还是失败,就重新启用round robin的方式,而这种情况下就会导致用户的session丢失。 4、用后端服务器自身通过相关机制保持session同步,如:使用数据库、redis、memcached 等做session复制
try_file和errorr_page
try_file用于在多个可能的文件或URI之间进行测试,以确定要返回给客户端的文件或执行的操作 try_files file ... uri; 这里的 file ... 是一系列的文件路径或URI,Nginx会按照给定的顺序检查这些文件或URI是否存在。一旦找到存在的文件或URI,Nginx就会停止进一步搜索并返回该资源。如果没有找到任何资源,Nginx将跳转到最后的 uri,该 uri 通常是一个处理请求的备用位置,如返回错误页面或执行一个特定的处理逻辑。 ----------------------------- server { listen 80; root /var/www/example.com; location / { try_files $uri $uri/ /index.html; } } ----------------------------- 在这个示例中,当一个请求到达时,Nginx会首先尝试返回与 $uri 对应的文件。如果该文件不存在,Nginx会尝试将 $uri 作为目录来处理(即尝试返回该目录下的默认文件,如 index.html)。如果这也不存在,Nginx将返回 /index.html,这通常是一个通用的错误页面或应用程序的入口点。 error_page 用于配置在特定 HTTP 错误发生时返回给客户端的页面或处理方式 error_page code ... [=|=code] uri; error_page code ... [=|=code] @named_location; code:一个或多个 HTTP 错误代码,如 404、502 等。 [=|=code]:可选的,用于改变返回给客户端的 HTTP 响应码。如果指定 =,则不会改变实际的错误代码,而只改变返回的页面内容;如果指定 =code,则会改变实际的 HTTP 响应码。 uri:在错误发生时返回给客户端的 URI。可以是本地路径或远程 URL。 @named_location:一个命名的 location 块,用于在错误发生时执行特定的处理逻辑。 指定静态错误页面 ----------------------------- error_page 404 /404.html; location = /404.html { root /usr/share/nginx/html; } ----------------------------- 改变错误响应码 当发生 502 或 503 错误时,返回本地的 /50x.html 页面,但将 HTTP 响应码改为 200。 ----------------------------- error_page 502 503 =200 /50x.html; location = /50x.html { root /usr/share/nginx/html; } ----------------------------- 使用命名的 location 当发生 404 错误时,执行名为 @custom_404 的 location 块中的处理逻辑。 ----------------------------- error_page 404 @custom_404; location @custom_404 { default_type text/plain; return 404 'Custom 404 Page...'; } ----------------------------- error_page 指令可以在 http、server、location 和 limit_except 上下文中使用。 对于同一个 HTTP 状态码,error_page 指令在一个 location 块中只能执行一次。如果定义了多次,只有第一次会被执行。 在 error_page 后面的 URI 或命名 location 中,可以执行任何有效的 Nginx 指令,包括代理、重定向等。 当 error_page 后面跟的是一个动态内容(如由 FastCGI、uWSGI 或其他后端服务器处理的内容)时,后端服务器返回的状态码也会被返回给客户端。
为了加快网站的解析速度,可以把动态页面和静态页面由不同的服务器来解析,加快解析速度。降低原来单个服务器的压力。 在动静分离的tomcat的时候比较明显,因为tomcat解析静态很慢,其实这些原理的话都很好理解,简单来说,就是使用正则表达式匹配过滤,然后交个不同的服务器。
动静分离部署
三台机器,一台负载均衡器,一台静态服务器,一台动态服务器 三台都下载nginx,动态服务器再下载一个php 负载均衡器: 在nginx的配置文件http模块中添加 vim /etc/nginx/nginx.conf ---------------------------------- upstream jiaming { server 192.168.253.140; server 192.168.253.142; } server { listen 80; location / { proxy_pass http://jiaming; } } ---------------------------------- 静态服务器: vim /etc/nginx/nginx.conf ---------------------------------- server { listen 80; root /usr/share/nginx/html; index a.mp4; include /etc/nginx/default.d/*.conf; } ---------------------------------- 将视频拉取到/usr/share/nginx/html目录下,并改名为a.mp4,后缀格式要对,Windows是会根据后缀进行区别的,再下载一张照片到本地,当输入ip/跟图片的名字,就可以看到图片 动态服务器: vim /etc/nginx/nginx.conf ---------------------------------- server { listen 80; location / { root /usr/share/nginx/html; index index.php; } location ~ \.php$ { root /usr/share/nginx/html; fastcgi_pass unix:///dev/shm/php-fpm-80.sock; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi_params; } } ---------------------------------- 安装php,安装php脚本在下面 写一个index.php文件放到/usr/share/nginx/html目录下 vim /usr/share/nginx/html/index.php ---------------------------------- <?php echo "woaixuexi"; phpinfo(); ?> ---------------------------------- 启动nginx和php nginx systemctl start php80-php-fpm
安装php脚本
VERSION_ID=$(cat /etc/redhat-release | sed -r 's/.* ([0-9]+)\..*/\1/') yum remove -y remi-release yum install -y https://mirrors.ustc.edu.cn/remi/enterprise/remi-release-${VERSION_ID}.rpm sed -e 's|^mirrorlist=|#mirrorlist=|g' \ -e 's|^#baseurl=http://rpms.remirepo.net|baseurl=https://mirrors.ustc.edu.cn/remi|g' \ -i /etc/yum.repos.d/remi*.repo yum clean all yum makecache id nginx &>/dev/null && { phpUser='nginx' } || { id www 2>/dev/null || useradd -s /sbin/nologin www phpUser='www' } # ----------------------------------------------- # version="56" # version="74" version="80" yum install -y php${version} php${version}-php-fpm php${version}-php-mysqlnd php${version}-php-bcmath php${version}-php-pdo php${version}-php-openssl php${version}-php-gd php${version}-php-mbstring php${version}-php-xml php${version}-php-mcrypt php${version}-php-zip && { if [ ! -f "/etc/opt/remi/php${version}/php-fpm.d/www.conf.bak" ]; then \cp /etc/opt/remi/php${version}/php-fpm.d/www.conf /etc/opt/remi/php${version}/php-fpm.d/www.conf.bak fi echo "[www] user = ${phpUser} group = ${phpUser} listen = /dev/shm/php-fpm-${version}.sock listen.allowed_clients = 127.0.0.1 listen.owner = ${phpUser} listen.group = ${phpUser} listen.mode = 0666 pm = dynamic pm.max_children = 50 pm.start_servers = 20 pm.min_spare_servers = 20 pm.max_spare_servers = 50 slowlog = /var/opt/remi/php${version}/log/php-fpm/www-slow.log php_admin_value[error_log] = /var/opt/remi/php${version}/log/php-fpm/www-error.log php_admin_flag[log_errors] = on php_value[session.save_handler] = files php_value[session.save_path] = /var/opt/remi/php${version}/lib/php/session php_value[soap.wsdl_cache_dir] = /var/opt/remi/php${version}/lib/php/wsdlcache" >/etc/opt/remi/php${version}/php-fpm.d/www.conf systemctl restart php${version}-php-fpm systemctl enable --now php${version}-php-fpm chown -R ${phpUser}:${phpUser} /var/opt/remi/php${version}/lib/php/session chown -R ${phpUser}:${phpUser} /var/opt/remi/php${version}/lib/php/wsdlcache }
11、nginx防盗链问题
两个网站 A 和 B, A网站引用了B网站上的图片,这种行为就叫做盗链。 防盗链,就是要防止A引用B的图片。
(1)、nginx放置网络资源被盗用模块
nginx 防止网站资源被盗用模块 如何区分哪些是不正常的用户 HTTP Referer是Header的一部分,当浏览器向Web服务器发送请求的时候,一般会带上Referer,告诉服务器我是从哪个页面链接过来的,服务器借此可以获得一些信息用于处理,例如防止未经允许的网站盗链图片、文件等。因此HTTP Referer头信息是可以通过程序来伪装生成的,所以通过Referer信息防盗链并非100%可靠,但是,它能够限制大部分的盗链情况. 比如在www.google.com 里有一个www.baidu.com 链接,那么点击这个www.baidu.com ,它的header 信息里就有:Referer=http://www.google.com
!!!没有设置防盗链的配置 两台服务器,一台作为后端真实服务器,一台作为盗链者服务器,均下载nginx 后端真实服务器只需要下载一张照片,并将照片放到nginx发布目录,改名为a.jpg 盗链者服务器只需要在nginx默认访问页面的内容换成后端真实服务器的ip/url即可 vim /usr/share/nginx/html/index.html --------------------------------- <html> <img src="http://后端真实服务器ip/要盗的内容usl"/> #例如:<img src="http://192.168.253.142/z.jpg"/> </html> --------------------------------- 浏览器中访问盗链者的ip,则直接可以访问到后端真实服务器的内容,流量知名度都被盗链者拿走了,服务器的负载压力让后端真实服务器承受了 !!!设置防盗链的配置 --------------------------------- server { listen 80; root /usr/share/nginx/html; index z.jpg; location ~ \.(jpg|mp4) { valid_referers 192.168.253.140; if ($invalid_referer) { return 301 https://www.baidu.com/; #此处可以直接写403,访问的时候直接报403错误页面,或者写301永久重定向到baidu.com } } --------------------------------- nginx -s reload 没有设置防盗链的情况下,访问192.168.253.140(为盗链者的ip),页面会显示192.168.253.142的z.jpg图片 设置完防盗链的情况下,访问192.168.253.140时,页面不会显示192.168.253.142的z.jpg图片,而是直接重定向到baidu.com ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ valid_referers的参数: none: 表示请求头中缺少 Referer 字段,即直接访问(如直接在浏览器打开一个图片)。 blocked: 表示 Referer 字段不为空,但值被防火墙或代理服务器修改或删除了,通常这些值不以 "http://" 或 "https://" 开头。 server_names: 表示一个或多个服务器名称,即允许的 Referer 头部字段值。从 Nginx 0.5.33 版本开始,可以在名称中使用通配符 "*" 号。 例如:server_names example.com *.example.com; string: 表示任意字符串,可以是服务器名称或可选的 URI 前缀。 允许使用通配符 "*" 号。 例如:string http://*.example.org/images/; regular expression(正则表达式): 以 "~" 开头,用于匹配 Referer 头部字段值的更复杂模式。 例如:valid_referers ~* ^http://([^.]+\.example\.com|example\.org)/; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 怎么跳过防盗链 在盗链者的发布页面添加 vim s.py ---------------------------------------------------- #!/usr/bin/python3 import requests head = { #定义head的变量值为192.168.253.141的ip "Referer": "http://192.168.253.141/" } r = requests.get(url="http://192.168.253.142", headers=head) #引用head的变量,当执行该脚本时,headers=head将成为我的ip,代替我去请求,141该ip是被允许的,我的ip140是不被允许的,所以该脚本的返回值将是200成功 print(r.status_code) ---------------------------------------------------- chmod +x ./s.py ./s.py
什么是Rewrite
Rewrite对称URL Rewrite,即URL重写,就是把传入Web的请求重定向到其他URL的过程。 URL Rewrite最常见的应用是URL伪静态化,是将动态页面显示为静态页面方式的一种技术。比如 [http://www.123.com/news/index.php?id=123](http://www.123.com/news/index.php?id=123) 使用URLRewrite 转换后可以显示为 [http://www.123](http://www.123) .com/news/123.html对于追求完美主义的网站设计师,就算是网页的地址也希望看起来尽量简洁明快。 理论上,搜索引擎更喜欢静态页面形式的网页,搜索引擎对静态页面的评分一般要高于动态页面。所以,UrlRewrite可以让我们网站的网页更容易被搜索引擎所收录。 从安全角度上讲,如果在URL中暴露太多的参数,无疑会造成一定量的信息泄漏,可能会被一些黑客利用,对你的系统造成一定的破坏,所以静态化的URL地址可以给我们带来更高的安全性。 实现网站地址跳转,例如用户访问360buy.com,将其跳转到jd.com。例如当用户访问tianyun.com的80端口时,将其跳转到443端口
Rewrite 相关指令
Nginx Rewrite 相关指令有 if 、rewrite、set、return
if 语句(应用环境server,location)
if (condition) { … } if 可以支持如下条件判断匹配符号 ~ 正则匹配 (区分大小写) ~* 正则匹配 (不区分大小写) !~ 正则不匹配 (区分大小写) !~* 正则不匹配 (不区分大小写) -f 和!-f 用来判断是否存在文件 -d 和!-d 用来判断是否存在目录 -e 和!-e 用来判断是否存在文件或目录 -x 和!-x 用来判断文件是否可执行 在匹配过程中可以引用一些Nginx的全局变量 $args 请求中的参数; $document_root 针对当前请求的根路径设置值; $host 请求信息中的"Host",如果请求中没有Host行,则等于设置的服务器名; $limit_rate 对连接速率的限制; $request_method 请求的方法,比如"GET"、"POST"等; $remote_addr 客户端地址; $remote_port 客户端端口号; $remote_user 客户端用户名,认证用; $request_filename 当前请求的文件路径名(带网站的主目录/usr/local/nginx/html/images/a.jpg) $request_uri 当前请求的文件路径名(不带网站的主目录/images/a.jpg) $query_string 与$args相同; $scheme 用的协议,比如http或者是https $server_protocol 请求的协议版本,"HTTP/1.0"或"HTTP/1.1"; $server_addr 服务器地址,如果没有用listen指明服务器地址,使用这个变量将发起一次系统调用以取得地址(造成资源浪费); $server_name 请求到达的服务器名; $document_uri 与$uri一样,URI地址; $server_port 请求到达的服务器端口号;
Rewrite flag
rewrite 指令根据表达式来重定向URI,或者修改字符串。可以应用于**server,location, if**环境下每行rewrite指令最后跟一个flag标记,支持的flag标记有: last 相当于Apache里的[L]标记,表示完成rewrite。默认为last。 break 本条规则匹配完成后,终止匹配,不再匹配后面的规则 redirect 返回302临时重定向,浏览器地址会显示跳转后的URL地址 permanent 返回301永久重定向,浏览器地址会显示跳转后URL地址 redirect 和 permanent区别则是返回的不同方式的重定向,对于客户端来说一般状态下是没有区别的。而对于搜索引擎,相对来说301的重定向更加友好,如果我们把一个地址采用301跳转方式跳转的话,搜索引擎会把老地址的相关信息带到新地址,同时在搜索引擎索引库中彻底废弃掉原先的老地址。使用302重定向时,搜索引擎(特别是google)有时会查看跳转前后哪个网址更直观,然后决定显示哪个,如果它觉的跳转前的URL更好的话,也许地址栏不会更改,那么很有可能出现URL劫持的现像。在做URI重写时,有时会发现URI中含有相关参数,如果需要将这些参数保存下来,并且在重写过程中重新引用,可以用到 () 和 $N 的方式来解决。
set和return指令
set 指令是用于定义一个变量,并且赋值 应用环境:server,location,if return 指令用于返回状态码给客户端 应用环境:server,location,if
注意
last 标记在本条 rewrite 规则执行完后,会对其所在的 server { … } 标签重新发起请求; break 标记则在本条规则匹配完成后,停止匹配,不再做后续的匹配; 使用 alias 指令时,必须使用 last; 使用 proxy_pass 指令时,则必须使用break。
案例1: http://192.168.253.141/a ==> http://192.168.253.141/b ------------------------------ location /a { rewrite .* /b; } location /b { root /usr/share/nginx/html; index index.html; } ------------------------------ 需要有/usr/share/nginx/html/b/index.html文件 案例2: http://192.168.253.141/1/a ==> http://192.168.253.141/2/a a/index.html ------------------------------ location /1/a { rewrite ^/1/(.*)$ /2/$1; } location /2/a { root /usr/share/nginx/html; index index.html; } ------------------------------ 需要有/usr/share/nginx/html/2/a/index.html文件 案例3: http://192.168.253.140/a/ ==> http://www.baidu.com ------------------------------ location /a { if ( $host ~* 192.168.253.140 ) { rewrite .* http://www.baidu.com; } } ------------------------------ 案例4: http://192.168.253.140/a ==> http://baidu.com/a ------------------------------ location /a { if ( $host ~* 192.168.253.140 ) { rewrite /(.*)$ http://www.baidu.com/$1; } } ------------------------------ 案例5: http://192.168.253.140/a/jiaming.html ==> http://192.168.253.140/b/a.html?user=jiaming ------------------------------ location /a/jiaming.html { if ( $host ~* 192.168.253.140 ) { rewrite ^/a/(.*).html$ http://$host/b/a.html?user=$1; } } location /b/a.html { root /usr/share/nginx/html; } ------------------------------ 需要有/usr/share/nginx/html/b/a.html文件 案例6: http://li/11-22-33/index.html ==> http://li/11/22/33/index.html ------------------------------ location /li { rewrite ^/li/(.*)-(.*)-(.*)/(.*)$ /li/$1/$2/$3/$4; } location /li/11/22/33/index.html { root /usr/share/nginx/html; } ------------------------------ 需要有/usr/share/nginx/html/li/11/22/33/index.html文件 set 指令: 案例7: http://jia.jiaming.com ==> http://www.jiaming.com/jia http://ming.jiaming.com ==> http://www.jiaming.com/ming ------------------------------ location / { root /usr/share/nginx/html; index index.html; if ( $host ~* ^www.jiaming.com$ ) { break; } if ( $host ~* "^(.*)\.jiaming\.com$" ) { set $user $1; rewrite .* http://www.jiaming.com/$user permanent; } } location /jia { root /usr/share/nginx/html; index index.html; } location /ming { root /usr/share/nginx/html; index index.html; } ------------------------------ 需要有/usr/share/nginx/html/jia和/usr/share/nginx/html/ming文件 并且需要在server模块中添加域名,在Windows的域名解析中添加www.jiaming.com和jia.jiaming.com域名,和在Linux系统hosts文件中添加这两个域名,需要域名解析 案例8: 如果访问.sh结尾的文件则返回403操作拒绝错误 ------------------------------ location / { root /usr/share/nginx/html; index index.html; } location ~* \.sh$ { return 403; } ------------------------------
Apache 的 https ( rewrite )
yum -y install httpd mod_ssl vim /etc/httpd/conf.d/vip9999.conf
Nginx 的 HTTP 配置主要包括三个区块,结构如下 ------------------------------------------------ http { # 这个是协议级别 include mime.types; default_type application/octet-stream; keepalive_timeout 65; gzip on; server { # 这个是服务器级别 listen 80; server_name localhost; location / { # 这个是请求级别 root html; index index.html index.htm; } } } ------------------------------------------------
location 区段
location 是在 server 块中配置,根据不同的 URI 使用不同的配置,来处理不同的请求。 location 是有顺序的,会被第一个匹配的location 处理。 基本语法如下: location [=|~|~*|^~|@] pattern{……} location 前缀含义 = 表示精确匹配,优先级也是最高的 ^~ 表示uri以某个常规字符串开头,理解为匹配url路径即可 ~ 表示区分大小写的正则匹配 ~* 表示不区分大小写的正则匹配 / 通用匹配,任何请求都会匹配到 @ 内部服务跳转 location 配置示例 本地解析域名host 1、没有修饰符 表示:必须以指定模式开始 ------------------------ location /abc { root /home/www/nginx; index 2.html; } ------------------------ 如下是对的: http://主机ip/abc http://主机ip/abc?p1 http://主机ip/abc/ http://主机ip/abcde 2、=表示:必须与指定的模式精确匹配 ------------------------------------- location / { root /usr/share/nginx/html; index index.html index.htm; } location = /abc { root /usr/share/nginx/html; index index.html index.htm; } ------------------------------------- 如下是对的: http://主机ip/abc http://主机ip/abc?p1 http://主机ip/abc/ 如下是错的 http://主机ip/abcde 3、~ 表示:指定的正则表达式要区分大小写 -------------------------- server { server_name qf.com; location ~ ^/abc$ { …… } } -------------------------- 如下是对的: http://主机ip/abc http://qf.com/abc?p1=11&p2=22 如下是错的 http://主机ip/ABC http://主机ip/abc/ http://主机ip/abcde 4、~* 表示:指定的正则表达式不区分大小写 -------------------------- server { server_name qf.com; location ~* ^/abc$ { …… } } -------------------------- 如下是对的: http://主机ip/abc http://主机ip/ABC http://主机ip/abc?p1=11&p2=22 如下是错的 http://主机ip/abc/ http://主机ip/abcde 5、^~ :类似于无修饰符的行为,也是以指定模式开始,不同的是,如果模式匹配,那么就停止搜索其他模式了。 -------------------------- server { listen 80; server_name localhost; location ^~ /abc { root /var/www/nginx; index index.html; } } -------------------------- 6、@ :定义命名 location 区段,这些区段客户段不能访问,只可以由内部产生的请求来访问,如try_files或error_page等 ---------------------------------------------------- server { listen 80; server_name localhost; location / { root /usr/share/nginx/html; index index.html; try_files /index.htm /a.html /b.html @error; } location @error { return 409; } } ----------------------------------------------------
server { listen 80; server_name 127.0.0.1; location /abc { return 302 https://www.baidu.com; } location ~ /abc { return 302 https://www.taobao.com; } location ^~ /abc/ { return 302 https://www.jd.com; } location ~* /ABC { return 302 https://www.pingduoduo.com; } location = /abc { return 302 https://www.vip.com; } } 查找顺序和优先级 1:带有“=“的精确匹配优先 2:没有修饰符的精确匹配 3:正则表达式按照他们在配置文件中定义的顺序 4:带有“^~”修饰符的,开头匹配 5:带有“~” 或“~*” 修饰符的,如果正则表达式与URI匹配 6:没有修饰符的,如果指定字符串与URI开头匹配 = 大于 ^~ 大于 ~|~*|!~|!~* 大于 / 多个location配置的情况下匹配顺序为:首先匹配 =,其次匹配^~, 其次是按正则匹配,最后是交给 / 通用匹配。当有匹配成功时候,停止匹配,按当前匹配规则处理请求。 (1) =:表示完全匹配; (2) ^~:匹配URI的前缀,并且后面的正则表达式不再匹配,如果一个URI同时满足两个规则的话,匹配最长的规则; (3) ~:匹配正则表达式,大小写敏感; (4) ~*:匹配正则表达式,大小写不敏感; 优先级:(1)> (2) > (3) = (4)
location 区段匹配示例 location = / { # 只匹配 / 的查询. [ configuration A ] } location / { # 匹配任何以 / 开始的查询,但是正则表达式与一些较长的字符串将被首先匹配。 [ configuration B ] } location ^~ /images/ { www.abc. # 匹配任何以 /images/ 开始的查询并且停止搜索,不检查正则表达式。 [ configuration C ] } location ~* \.(gif|jpg|jpeg)$ { # 匹配任何以gif, jpg, or jpeg结尾的文件,但是所有 /images/ 目录的请求将在Configuration C中处理。 [ configuration D ] } 各请求的处理如下例: / → configuration A /documents/document.html → configuration B /images/1.gif → configuration C /documents/1.jpg → configuration D
root 、alias 指令区别
location /img/ { alias /var/www/image/; } #若按照上述配置的话,则访问/img/目录里面的文件时,ningx会自动去/var/www/image/目录找文件 location /img/ { root /var/www/image; } #若按照这种配置的话,则访问/img/目录下的文件时,nginx会去/var/www/image/img/目录下找文件。] server { listen 80; server_name localhost; location /cloud { #http://localhost/cloud #/usr/share/nginx/html/cloud root /usr/share/nginx/html; index index.html; } location /cloud { #http://localhost/cloud #/usr/share/nginx/html alias /usr/share/nginx/html/; index index.html; } } alias 是一个目录别名的定义, root 则是最上层目录的定义。 还有一个重要的区别是alias后面必须要用“/”结束,否则会找不到文件的,而root则可有可无
nginx 日志介绍
nginx 有一个非常灵活的日志记录模式,每个级别的配置可以有各自独立的访问日志, 所需日志模块 ngx_http_log_module 的支持,日志格式通过 log_format 命令来定义,日志对于统计和排错是非常有利的,下面总结了 nginx 日志相关的配置 包括 access_log、log_format、open_log_file_cache、log_not_found、log_subrequest、rewrite_log、error_log 设置访问日志 access_log path [format [buffer=size] [gzip[=level]] [flush=time] [if=condition]]; 关闭访问日志 access_log off; path 指定日志的存放位置。 format 指定日志的格式。默认使用预定义的`combined`。 buffer 用来指定日志写入时的缓存大小。默认是64k。 gzip 日志写入前先进行压缩。压缩率可以指定,从1到9数值越大压缩比越高,压缩的速度也越慢。默认是1。 flush 设置缓存的有效时间。如果超过flush指定的时间,缓存中的内容将被清空。 if 条件判断。如果指定的条件计算为0或空字符串,那么该请求不会写入日志。 作用域: 可以应用access_log指令的作用域分别有http,server,location,limit_except。也就是说,在这几个作用域外使用该指令,Nginx会报错 access_log /var/logs/nginx-access.log 该例子指定日志的写入路径为/var/logs/nginx-access.log,日志格式使用默认的combined access_log /var/logs/nginx-access.log buffer=32k gzip flush=1m 该例子指定日志的写入路径为/var/logs/nginx-access.log,日志格式使用默认的combined,指定日志的缓存大小为 32k,日志写入前启用 gzip 进行压缩,压缩比使用默认值 1,缓存数据有效时间为1分钟。
log_format 指令
Nginx 预定义了名为 combined 日志格式,如果没有明确指定日志格式默认使用该格式: --------------------------------------------------------------- log_format combined '$remote_addr - $remote_user [$time_local] ' '"$request" $status $body_bytes_sent ' '"$http_referer" "$http_user_agent"'; --------------------------------------------------------------- 如果不想使用Nginx预定义的格式,可以通过`log_format`指令来自定义。 语法: log_format name [escape=default|json] string ...; name 格式名称。在 access_log 指令中引用。 escape 设置变量中的字符编码方式是json还是default,默认是default。 string 要定义的日志格式内容。该参数可以有多个。参数中可以使用Nginx变量。 log_format 指令中常用的一些变量: $remote_addr, $http_x_forwarded_for #记录客户端IP地址 $remote_user #记录客户端用户名称 $request #记录请求的URL和HTTP协议 $status #记录请求状态 $body_bytes_sent #发送给客户端的字节数,不包括响应头的大小 $bytes_sent #发送给客户端的总字节数 $http_referer #记录从哪个页面链接访问过来的,可以根据该参数进行防盗链设置 $http_user_agent #记录客户端浏览器相关信息 $time_local #通用日志格式下的本地时间。 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 自定义日志格式的使用: --------------------------------------------------------------- access_log /var/logs/nginx-access.log main log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"'; --------------------------------------------------------------- 使用log_format指令定义了一个main的格式,并在access_log指令中引用了它。假如客户端有发起请求:https://主机ip/,我们看一下我截取的一个请求的日志记录: 10.0.105.207 - - [01/Jul/2019:10:44:36 +0800] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36" "-" --------------------------------------------------------------- 我们看到最终的日志记录中$remote_user、$http_referer、$http_x_forwarded_for都对应了一个-,这是因为这几个变量为空。 --------------------------------------------------------------- 面试时:注意日志里面的ip地址一定要在第一列。
error_log 指令
错误日志在Nginx中是通过error_log指令实现的。该指令记录服务器和请求处理过程中的错误信息。 语法:(配置错误日志文件的路径和日志级别) ---------------------------------- error_log file [level]; Default: error_log logs/error.log error; ---------------------------------- file 参数指定日志的写入位置。 level 参数指定日志的级别。level可以是debug, info, notice, warn, error, crit, alert,emerg中的任意值。可以看到其取值范围是按紧急程度从低到高排列的。只有日志的错误级别等于或高于level指定的值才会写入错误日志中。默认值是error。 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 基本用法 error_log /var/logs/nginx/nginx-error.log 配置段:main, http, mail, stream, server, location作用域。 例子中指定了错误日志的路径为:/var/logs/nginx/nginx-error.log,日志级别使用默认的 error。 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ open_log_file_cache 指令 每一条日志记录的写入都是先打开文件再写入记录,然后关闭日志文件。如果你的日志文件路径中使用了变量,如 access_log /var/logs/$host/nginx-access.log,为提高性能,可以使用open_log_file_cache指令设置日志文件描述符的缓存。 语法: open_log_file_cache max=N [inactive=time] [min_uses=N] [valid=time]; 默认值: open_log_file_cache off; max 设置缓存中最多容纳的文件描述符数量,如果被占满,采用LRU算法将描述符关闭。 inactive 设置缓存存活时间,默认是10s。 min_uses 在inactive时间段内,日志文件最少使用几次,该日志文件描述符记入缓存,默认是1次。 valid 设置多久对日志文件名进行检查,看是否发生变化,默认是60s。 off 不使用缓存。默认为off。 open_log_file_cache max=1000 inactive=20s valid=1m min_uses=2; 配置段:http、server、location作用域中。 例子中,设置缓存最多缓存1000个日志文件描述符,20s内如果缓存中的日志文件描述符至少被被访问2次,才不会被缓存关闭。每隔1分钟检查缓存中的文件描述符的文件名是否还存在。 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ log_not_found 指令 是否在error_log中记录不存在的错误(404)。默认是 基本语法: log_not_found on | off; 默认值: log_not_found on; 配置段: http, server, location作用域。 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ log_subrequest 指令 是否在access_log中记录子请求的访问日志。默认不记录 基本语法 log_subrequest on | off; 默认值: log_subrequest off; 配置段: http, server, location作用域。 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ rewrite_log 指令 由ngx_http_rewrite_module模块提供的。用来记录重写日志的。对于调试重写规则建议开启,启用时将在error log中记录notice级别的重写日志。 基本语法: rewrite_log on | off; 默认值: rewrite_log off; 配置段: http, server, location, if作用域。 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ nginx 日志配置总结 Nginx中通过access_log和error_log指令配置访问日志和错误日志,通过log_format我们可以自定义日志格式。如果日志文件路径中使用了变量,我们可以通过open_log_file_cache 指令来设置缓存,提升性能。其他的根据自己的使用场景定义。 详细的日志配置信息可以参考Nginx官方文档 (https://link.juejin.im/?target=http%3A%2F%2Fnginx.org%2Fen%2Fdocs%2Fvarindex.html)
15、nginx 的平滑升级
为什么要对 nginx 平滑升级
随着 nginx 越来越流行,并且 nginx 的优势也越来越明显,nginx 的版本迭代也来时加速模式,1.9.0版本的nginx更新了许多新功能,例如 stream 四层代理功能,伴随着 nginx 的广泛应用,版本升级必然越来越快,线上业务不能停,此时 nginx 的升级就是运维的工作了 nginx 方便地帮助我们实现了平滑升级。其原理简单概括,就是: (1)在不停掉老进程的情况下,启动新进程。 (2)老进程负责处理仍然没有处理完的请求,但不再接受处理请求。 (3)新进程接受新请求。 (4)老进程处理完所有请求,关闭所有连接后,停止。 这样就很方便地实现了平滑升级。一般有两种情况下需要升级 nginx,一种是确实要升级 nginx 的版本,另一种是要为 nginx 添加新的模块。
nginx 平滑升级原理
多进程模式下的请求分配方式 nginx 默认工作在多进程模式下,即主进程(master process)启动后完成配置加载和端口绑定等动作,fork出指定数量的工作进程(worker process),这些子进程会持有监听端口的文件描述符(fd),并通过在该描述符上添加监听事件来接受连接(accept)。 信号的接收和处理 nginx 主进程在启动完成后会进入等待状态,负责响应各类系统消息,如SIGCHLD、SIGHUP、SIGUSR2等。 Nginx信号简介 主进程支持的信号: TERM, INT: 立刻退出 QUIT: 等待工作进程结束后再退出 KILL: 强制终止进程 HUP: 重新加载配置文件,使用新的配置启动工作进程,并逐步关闭旧进程。 USR1: 重新打开日志文件 USR2: 启动新的主进程,实现热升级 WINCH: 逐步关闭工作进程 工作进程支持的信号: TERM, INT: 立刻退出 QUIT: 等待请求处理结束后再退出 USR1: 重新打开日志文件
编译安装低版本进行测试: yum install -y gcc gcc-c++ pcre pcre-devel openssl openssl-devel zlib zlib-devel readline-devel ncurses-devel bison libtool-ltdl bzip2-devel libicu-devel libunwind-devel libaio-devel #安装依赖包 useradd nginx -s /sbin/nologin wget http://nginx.org/download/nginx-1.20.0.tar.gz yum install -y tar yum install -y unzip tar -xvf nginx-1.22.0.tar.gz -C /usr/local/ MAKE_NGINX_PATH=/usr/local/nginx-1.16.0 wget https://github.com/gnosek/nginx-upstream-fair/archive/master.zip -P $MAKE_NGINX_PATH && \ unzip $MAKE_NGINX_PATH/master.zip -d $MAKE_NGINX_PATH && \ mv $MAKE_NGINX_PATH/nginx-upstream-fair-master $MAKE_NGINX_PATH/nginx-upstream-fair sed -ri "s/default_port/no_port/g" $MAKE_NGINX_PATH/nginx-upstream-fair/ngx_http_upstream_fair_module.c #版本有可能不兼容,修改default_port修改为no_port cd $MAKE_NGINX_PATH ./configure --prefix=/usr/local/nginx \ --group=nginx \ --user=nginx \ --sbin-path=/usr/local/nginx/sbin/nginx \ --conf-path=/etc/nginx/nginx.conf \ --error-log-path=/var/log/nginx/error.log \ --http-log-path=/var/log/nginx/access.log \ --http-client-body-temp-path=/usr/local/nginx/tmp/client_body \ --http-proxy-temp-path=/usr/local/nginx/tmp/proxy \ --http-fastcgi-temp-path=/usr/local/nginx/tmp/fastcgi \ --pid-path=/var/run/nginx.pid \ --lock-path=/var/lock/nginx \ --with-http_stub_status_module \ --with-http_ssl_module \ --with-http_gzip_static_module \ --with-pcre \ --with-http_realip_module \ --with-stream \ --add-module=nginx-upstream-fair make -j 2 && make install && mkdir /usr/local/nginx/tmp cd /usr/local/nginx/sbin ./nginx 开始进行平滑升级: wget http://nginx.org/download/nginx-1.26.0.tar.gz
nginx错误页面包括404 403 500 502 503 504等页面,只需要在server中增加以下配置即可: ---------------------------------- #error_page 404 403 500 502 503 504 /404.html; location = /404.html { root /usr/local/nginx/html; } /usr/local/nginx/html/ 路径下必须有404.html这个文件 ----------------------------------
404.html上如果引用其他文件的png或css就会有问题,显示不出来,因为其他文件的访问也要做配置; 为了简单,可以将css嵌入文件中,图片用base编码嵌入;如下: vim 404.html ---------------------------------- <!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1" /> <title>404</title> <style> .layout-table{display:table;height:100%;width:100%;vertical-align: middle;margin-top:150px} .layout-table-cell{display: table-cell;vertical-align: middle;text-align:center} .layout-tip{font-size:28px;color:#373737;margin: 0 auto;margin-top:16px;border-bottom: 1px solid #eee;padding-bottom: 20px;width: 360px;} #tips{font-size:18px;color:#666666;margin-top:16px;} </style> </head> <body class="layui-layout-body"> <div class="layui-layout layui-layout-admin"> <div class="layui-body"> <div class="layout-table"> <div class="layout-table-cell"> <img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAV4AAACMCAYAAAA0qsGKAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyBpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNSBXaW5kb3dzIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOkIwRDQ0ODRFMzMyODExRThBQ0Q5Q0UyNkNCMkE4MDk0IiB4bXBNTTpEb2N1bWVudElEPSJ4bXAuZGlkOkIwRDQ0ODRGMzMyODExRThBQ0Q5Q0UyNkNCMkE4MDk0Ij4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6QjBENDQ4NEMzMzI4MTFFOEFDRDlDRTI2Q0IyQTgwOTQiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6QjBENDQ4NEQzMzI4MTFFOEFDRDlDRTI2Q0IyQTgwOTQiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz4Qz6opAAAU5klEQVR42uxd3XXjthKe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" class="layout-img"> <p class="layout-tip">哎呀,找不到该页面啦!</p> <p id="tips">请检查您的网络连接是否正常或者输入的网址是否正确</p> </div> </div> </div> </div> </body> </html> ----------------------------------
展示效果
流量限制(rate-limiting),是Nginx中一个非常实用,却经常被错误理解和错误配置的功能。我们可以用来限制用户在给定时间内HTTP请求的数量。请求,可以是一个简单网站首页的GET请求,也可以是登录表单的 POST 请求。流量限制可以用作安全目的,比如可以减慢暴力密码破解的速率。通过将传入请求的速率限制为真实用户的典型值,并标识目标URL地址(通过日志),还可以用来抵御 DDOS 攻击。更常见的情况,该功能被用来保护上游应用服务器不被同时太多用户请求所压垮。 以下将会介绍Nginx的流量限制的基础知识和高级配置,流量限制在Nginx Plus中也适用。
Nginx如何限流
Nginx的”流量限制”使用漏桶算法(leaky bucket algorithm),该算法在通讯和分组交换计算机网络中广泛使用,用以处理带宽有限时的突发情况。就好比,一个桶口在倒水,桶底在漏水的水桶。如果桶口倒水的速率大于桶底的漏水速率,桶里面的水将会溢出;同样,在请求处理方面,水代表来自客户端的请求,水桶代表根据”先进先出调度算法”(FIFO)等待被处理的请求队列,桶底漏出的水代表离开缓冲区被服务器处理的请求,桶口溢出的水代表被丢弃和不被处理的请求。
配置基本的限流
“流量限制”配置两个主要的指令,limit_req_zone和limit_req,如下所示: zone=mylimitx当有恶意ip在一秒钟访问很多次,就会被存进该目录中,以后将会禁止该ip访问 limit_rep每秒钟十次刷新,超过就会报错 vim /etc/nginx/nginx.conf ---------------------------------- limit_req_zone $binary_remote_addr zone=mylimit:10m rate=10r/s; upstream myweb { server 需要被代理的服务器; } server { listen 80; location /login { limit_req zone=mylimit; proxy_pass http://myweb; } } ---------------------------------- 被代理服务器配置: ---------------------------------- server { listen 80; server_name localhost; location /login { root /usr/share/nginx/html; index index.html index.html; } } ---------------------------------- limit_req_zone指令定义了流量限制相关的参数,而limit_req指令在出现的上下文中启用流量限制(示例中,对于”/login/”的所有请求)。
limit_req_zone指令通常在HTTP块中定义,使其可在多个上下文中使用,它需要以下三个参数:
Key 定义应用限制的请求特性。示例中的 Nginx 变量$binary_remote_addr,保存客户端IP地址的二进制形式。这意味着,我们可以将每个不同的IP地址限制到,通过第三个参数设置的请求速率。(使用该变量是因为比字符串形式的客户端IP地址$remote_addr,占用更少的空间) Zone 定义用于存储每个IP地址状态以及被限制请求URL访问频率的共享内存区域。保存在内存共享区域的信息,意味着可以在Nginx的worker进程之间共享。定义分为两个部分:通过zone=keyword标识区域的名字,以及冒号后面跟区域大小。16000个IP地址的状态信息,大约需要1MB,所以示例中区域可以存储160000个IP地址。 Rate 定义最大请求速率。在示例中,速率不能超过每秒10个请求。Nginx实际上以毫秒的粒度来跟踪请求,所以速率限制相当于每100毫秒1个请求。因为不允许”突发情况”(见下一章节),这意味着在前一个请求100毫秒内到达的请求将被拒绝。 ----------------------------------------------------- 当Nginx需要添加新条目时存储空间不足,将会删除旧条目。如果释放的空间仍不够容纳新记录,Nginx将会返回503状态码(Service Temporarily Unavailable)。另外,为了防止内存被耗尽,Nginx每次创建新条目时,最多删除两条60秒内未使用的条目。 limit_req_zone`指令设置流量限制和共享内存区域的参数,但实际上并不限制请求速率。所以需要通过添加 limit_req指令,将流量限制应用在特定的location或者server块。在上面示例中,我们对/login/请求进行流量限制。 现在每个IP地址被限制为每秒只能请求10次/login/,更准确地说,在前一个请求的100毫秒内不能请求该URL。
处理突发
如果我们在100毫秒内接收到2个请求,怎么办?对于第二个请求,Nginx将给客户端返回状态码503。这可能并不是我们想要的结果,因为应用本质上趋向于突发性。相反地,我们希望缓冲任何超额的请求,然后及时地处理它们。我们更新下配置,在limit_req中使用burst参数: ----------------------------------------------------- limit_req_zone $binary_remote_addr zone=mylimit:10m rate=10r/s; upstream myweb { server 被代理服务器ip; } server { listen 80; location /login { limit_req zone=mylimit burst=20; proxy_pass http://myweb; } } ----------------------------------------------------- burst参数定义了超出zone指定速率的情况下(示例中的mylimit区域,速率限制在每秒10个请求,或每100毫秒一个请求),客户端还能发起多少请求。上一个请求100毫秒内到达的请求将会被放入队列,我们将队列大小设置为20。 如果你设置了每秒只允许 10 个请求,并且 burst 为 5,那么在短时间内可能会有 15 个请求被接收,但只有 10 个会立即被处理,剩下的 5 个会在“缓冲区”中等待。
无延迟的排队
配置burst参数将会使通讯更流畅,但是可能会不太实用,因为该配置会使站点看起来很慢。在上面的示例中,队列中的第20个包需要等待2秒才能被转发,此时返回给客户端的响应可能不再有用。要解决这个情况,可以在burst参数后添加nodelay参数: ----------------------------------------------------- limit_req_zone $binary_remote_addr zone=mylimit:10m rate=10r/s; upstream myweb { server 被代理服务器ip; } server { listen 80; location /login { limit_req zone=mylimit burst=20 nodelay; proxy_pass http://myweb; } } ----------------------------------------------------- 使用nodelay参数,Nginx仍将根据burst参数分配队列中的位置,并应用已配置的速率限制,而不是清理队列中等待转发的请求。相反地,当一个请求到达“太早”时,只要在队列中能分配位置,Nginx将立即转发这个请求。将队列中的该位置标记为”taken”(占据),并且不会被释放以供另一个请求使用,直到一段时间后才会被释放(在这个示例中是,100毫秒后)。 假设如前所述,队列中有20个空位,从给定的IP地址发出的21个请求同时到达。Nginx会立即转发这个21个请求,并且标记队列中占据的20个位置,然后每100毫秒释放一个位置。如果是25个请求同时到达,Nginx将会立即转发其中的21个请求,标记队列中占据的20个位置,并且返回503状态码来拒绝剩下的4个请求。 现在假设,第一组请求被转发后101毫秒,另20个请求同时到达。队列中只会有一个位置被释放,所以Nginx转发一个请求并返回503状态码来拒绝其他19个请求。如果在20个新请求到达之前已经过去了501毫秒,5个位置被释放,所以Nginx立即转发5个请求并拒绝另外15个。 效果相当于每秒10个请求的“流量限制”。如果希望不限制两个请求间允许间隔的情况下实施“流量限制”,nodelay参数是很实用的。 对于大部分部署,建议使用burst和nodelay参数来配置limit_req指令。
高级配置示例
通过将基本的“流量限制”与其他Nginx功能配合使用,我们可以实现更细粒度的流量限制。 1、白名单 下面这个例子将展示,如何对任何不在白名单内的请求强制执行“流量限制”: ----------------------------------------------------- geo $limit { default 1; 10.35.186.0/24 0; 192.168.253.0/24 0; } map $limit $limit_key { 0 ""; 1 $binary_remote_addr; } limit_req_zone $limit_key zone=req_zone:10m rate=5r/s; server { listen 80; location / { limit_req zone=req_zone burst=10 nodelay; root /usr/share/nginx/html; index index.html index.hml; } } ----------------------------------------------------- 这个例子同时使用了geo和map指令。geo块将给在白名单中的IP地址对应的$limit变量分配一个值0,给其它不在白名单中的分配一个值1。然后我们使用一个映射将这些值转为key,如下: 如果$limit变量的值是0,$limit_key变量将被赋值为空字符串 如果$limit变量的值是1,$limit_key变量将被赋值为客户端二进制形式的IP地址 两个指令配合使用,白名单内IP地址的$limit_key变量被赋值为空字符串,不在白名单内的被赋值为客户端的IP地址。当limit_req_zone后的第一个参数是空字符串时,不会应用“流量限制”,所以白名单内的IP地址(10.35.186.0/24和192.168.253.0/24 网段内)不会被限制。其它所有IP地址都会被限制到每秒5个请求。 limit_req指令将限制应用到/的location块,允许在配置的限制上最多超过10个数据包的突发,并且不会延迟转发。 2、location 包含多limit_req指令 我们可以在一个location块中配置多个limit_req指令。符合给定请求的所有限制都被应用时,意味着将采用最严格的那个限制。例如,多个指令都制定了延迟,将采用最长的那个延迟。同样,请求受部分指令影响被拒绝,即使其他指令允许通过也无济于事。 扩展前面将“流量限制”应用到白名单内IP地址的例子: ----------------------------------------------------- http { #... limit_req_zone $limit_key zone=req_zone:10m rate=5r/s; limit_req_zone $binary_remote_addr zone=req_zone_wl:10m rate=15r/s; server { listen 80; #... location / { limit_req zone=req_zone burst=10 nodelay; limit_req zone=req_zone_wl burst=20 nodelay; #... } } } ----------------------------------------------------- 白名单内的IP地址不会匹配到第一个“流量限制”,而是会匹配到第二个req_zone_wl,并且被限制到每秒15个请求。不在白名单内的IP地址两个限制能匹配到,所以应用限制更强的那个:每秒5个请求。
6、配置流量控制相关功能
1、配置日志记录 默认情况下,Nginx会在日志中记录由于流量限制而延迟或丢弃的请求,如下所示: 2019/02/13 04:20:00 [error] 120315#0: *32086 limiting requests, excess: 1.000 by zone "mylimit", client: 192.168.1.2, server: nginx.com, request: "GET / HTTP/1.0", host: "nginx.com" 日志条目中包含的字段: limiting requests 表明日志条目记录的是被“流量限制”请求 excess 每毫秒超过对应“流量限制”配置的请求数量 zone 定义实施“流量限制”的区域 client 发起请求的客户端IP地址 server 服务器IP地址或主机名 request 客户端发起的实际HTTP请求 hostHTTP 报头中host的值 默认情况下,Nginx以error级别来记录被拒绝的请求,如上面示例中的[error]所示(Ngin以较低级别记录延时请求,一般是info级别)。如要更改Nginx的日志记录级别,需要使用limit_req_log_level指令。这里,我们将被拒绝请求的日志记录级别设置为warn: ----------------------------------------------------- limit_req_zone $binary_remote_addr zone=mylimit:10m rate=10r/s; upstream myweb { server 192.168.253.140:80; } server { listen 80; location /login { limit_req zone=mylimit burst=20 nodelay; limit_req_log_level warn; proxy_pass http://myweb; proxy_set_header Host $host:$server_port; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } } ----------------------------------------------------- limit_req_log_level warn; 将记录日志的级别修改为warn proxy_set_header Host $host:$server_port; 重新定义或者添加发往后端服务器的请求头 proxy_set_header X-Real-IP $remote_addr; 启用客户端真实地址(否则日志中显示的是代理在访问网站) proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 记录代理地址
2、发送到客户端的错误代码 一般情况下,客户端超过配置的流量限制时,Nginx响应状态码为503(Service Temporarily Unavailable)。可以使用limit_req_status指令来设置为其它状态码(例如下面的444状态码): ----------------------------------------------------- limit_req_zone $binary_remote_addr zone=mylimit:10m rate=10r/s; upstream myweb { server 192.168.253.140:80; } server { listen 80; location /login { limit_req zone=mylimit burst=20 nodelay; limit_req_log_level warn; limit_req_status 444; proxy_pass http://myweb; proxy_set_header Host $host:$server_port; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } } ----------------------------------------------------- limit_req_status 444; limit_req_status指令来设置为其它状态码,当前设置的是444状态码 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 记录代理地址
nginx 访问控制模块
基于IP的访问控制:http_access_module 基于用户的信任登录:http_auth_basic_module
基于IP的访问控制
1、配置语法 Syntax:allow address | CIDR | unix: | all; default:默认无 Context:http,server,location,limit_except Syntax:deny address | CIDR | unix: | all; default:默认无 Context:http,server,location,limit_except 2、配置测试 修改/etc/nginx/nginx.conf内容如下: ------------------------------------- server { listen 80; server_name localhost; location ~ ^/admin { #/home/www/html/admin/index.html root /home/www/html; index index.html index.hml; deny 192.168.1.8; allow all; #deny 192.168.1.8; } } ------------------------------------- 如果先允许访问,在定义拒绝访问。那么拒绝访问不生效。先写范围小的。 虚拟机宿主机IP为192.168.1.8,虚拟机IP为192.168.1.11,故这里禁止宿主机访问,允许其他所有IP访问。 宿主机访问http://192.168.1.11/admin,显示403 Forbidden。 当然也可以反向配置,同时也可以使用IP网段的配置方式,如allow 192.168.1.0/24;,表示满足此网段的IP都可以访问。 3、指定location拒绝所有请求 如果你想拒绝某个指定URL地址的所有请求,而不是仅仅对其限速,只需要在location块中配置deny all指令: ------------------------------------- server { listen 80; location /foo.html { root /home/www/html; deny all; } } ------------------------------------- 4、局限性 remote_addr只能记录上一层与服务器直接建立连接的IP地址,若中间有代理,则记录的是代理的IP地址。只会显示代理服务器的ip http_x_forwarded_for可以记录每一层级的IP。可以显示代理服务器和真实客户端访问的ip
5、解决方法 采用别的HTTP头信息控制访问,如HTTP_X_FORWARD_FOR(无法避免被改写) 结合geo模块 通过HTTP自定义变量传递
3、基于用户的信任登录
配置语法 Syntax:auth_basic string | off; default:auth_basic off; Context:http,server,location,limit_except Syntax:auth_basic_user_file file; default:默认无 Context:http,server,location,limit_except file:存储用户名密码信息的文件。 配置: yum install -y httpd-tools htpasswd -cm /etc/nginx/auth_conf jiaming 创建密码的指令,-c覆盖这个文件,-m使用md5进行哈希算法加密,指定存储用户密码的路径,jiaming指定用户名 vim /etc/nginx/nginx.conf ------------------------------------- server { listen 80; location / { root /usr/share/nginx/html/; index index.html; auth_basic "Auth access test!"; auth_basic_user_file /etc/nginx/auth_conf; #指定存储用户密码的路径 } } ------------------------------------- nginx -s reload 在浏览器中访问测试,用户是htpasswd创建的 局限性 用户信息依赖文件方式 操作管理机械,效率低下 解决方法 Nginx结合LUA实现高效验证 Nginx和LDAP打通,利用nginx-auth-ldap模块 Nginx只做中间代理,具体认证交给应用。
19、nginx 变量
Nginx 同 Apache 和 Lighttpd 等其他 Web 服务器的配置方法不太相同,Nginx的配置文件使用语法的就是一门微型的编程语言。可以类似写程序一般编写配置文件,可操作性很大。既然是编程语言,一般也就少不了“变量”这种东西。 1、nginx变量简介 所有的 Nginx变量在 Nginx 配置文件中引用时都须带上 $ 前缀 在 Nginx 配置中,变量只能存放一种类型的值,有且也只存在一种类型,那就是字符串类型 nginx可以使用变量简化配置与提高配置的灵活性,所有的变量值都可以通过这种方式引用: 2、nginx 变量的定义和使用 nginx中的变量分为两种,自定义变量与内置预定义变量
自定义变量
(1)声明变量 可以在sever,http,location等标签中使用set命令(非唯一)声明变量,语法如下: set $变量名 变量值 nginx 中的变量必须都以$开头 nginx 的配置文件中所有使用的变量都必须是声明过的,否则 nginx 会无法启动并打印相关异常日志 (2)变量的可见性 nginx 变量的一个有趣的特性就是nginx中每一个变量都是全局可见的,而他们又不是全局变量。如下例子 ------------------------ location /a/ { return 200 $a; } location /b/ { set $a "hello nginx"; return 200 $a; } ------------------------ 由于变量是全局可见的所以nginx启动不会报错,而第一个location中并不知道$a的具体值因此返回的响应结果为一个空字符串。 在不同层级的标签中声明的变量性的可见性规则如下: location标签中声明的变量中对这个location块可见 server标签中声明的变量对server块以及server块中的所有子块可见 http标签中声明的变量对http块以及http块中的所有子块可见 (3)配置 $foo=hello ? ------------------------ server { listen 80; server_name localhost; location /test { set $foo hello; return 200 "$foo"; } } ------------------------ nginx -s reload 访问主机ip/test 输出:hello (4)使用大括号插值 在“变量插值”的上下文中,还有一种特殊情况,即当引用的变量名之后紧跟着变量名的构成字符时(比如后跟字母、数字以及下划线),我们就需要使用特别的记法来消除歧义,例如: ------------------------ server { ... location /test { set $first "hello "; return 200 ${foo}world; } } ------------------------ 访问主机ip/test 输出:hello world 这里,我们在 echo 配置指令的参数值中引用变量 foo 的时候,后面紧跟着 world 这个单词,所以如果直接写作 "fooworld" 则 Nginx “变量插值”计算引擎会将之识别为引用了变量 fooworld. 为了解决这个难题,Nginx 的字符串记法支持使用花括号在 之后把变量名围起来,比如这里的 ${foo}。 (5)变量作用域 set 指令(以及前面提到的 geo 指令)不仅有赋值的功能,它还有创建 Nginx 变量的副作用,即当作为赋值对象的变量尚不存在时,它会自动创建该变量。比如在上面这个例子中,如果 $a 这个变量尚未创建,则 set 指令会自动创建 $a 这个用户变量。如果我们不创建就直接使用它的值,则会报错。 例如 ------------------------ server { ... location /bad { return 200 $foo; } } ------------------------ 此时 Nginx 服务器会拒绝加载配置: 报错:unknown "foo" variable Nginx 变量的创建和赋值操作发生在全然不同的时间阶段,Nginx 变量的创建只能发生在 Nginx 配置加载的时候,或者说 Nginx 启动的时候,而赋值操作则只会发生在请求实际处理的时候。 这意味着不创建而直接使用变量会导致启动失败,同时也意味着我们无法在请求处理时动态地创建新的 Nginx 变量。 Nginx 变量一旦创建,其变量名的可见范围就是整个 Nginx 配置,甚至可以跨越不同虚拟主机的 server 配置块。我们来看一个例子: ---------------------------------- server { listen 80; location /foo { return 200 "foo = [$foo]"; } location /bar { set $foo 32; return 200 "foo = [$foo]"; } } ---------------------------------- curl 主机ip/foo 输出:foo = [] curl 主机ip/bar 输出:foo = [32] curl 主机ip/foo 输出:foo = [] 这里我们在 location /bar 中用 set 指令创建了变量 foo,于是在整个配置文件中这个变量都是可见的,因此我们可以在 location /foo 中直接引用这个变量而不用担心 Nginx 会报错。 从这个例子我们可以看到,set 指令因为是在 location /bar 中使用的,所以赋值操作只会在访问 /bar 的请求中执行。而请求 /foo 接口时,我们总是得到空的 foo值,因为用户变量未赋值就输出的话,得到的便是空字符串。 从这个例子我们可以窥见的另一个重要特性是,Nginx 变量名的可见范围虽然是整个配置,但每个请求都有所有变量的独立副本,或者说都有各变量用来存放值的容器的独立副本,彼此互不干扰。比如前面我们请求了 /bar 接口后,foo 变量被赋予了值 32,但它丝毫不会影响后续对 /foo 接口的请求所对应的 foo 值(它仍然是空的!),因为各个请求都有自己独立的 $foo 变量的副本。 对于 Nginx 新手来说,最常见的错误之一,就是将 Nginx 变量理解成某种在请求之间全局共享的东西,或者说“全局变量”。而事实上,Nginx 变量的生命期是不可能跨越请求边界的。 关于 Nginx 变量的另一个常见误区是认为变量容器的生命期,是与 location 配置块绑定的。其实不然。我们来看一个涉及“内部跳转”的例子: ---------------------------------- server { listen 80; location /foo { set $a hello; echo_exec /bar; } location /bar { echo "a = [$a]"; } } ---------------------------------- curl 主机ip/foo 输出:a = [hello] 这里我们在 location /foo 中,使用第三方模块 ngx_echo 提供的 echo_exec 配置指令,发起到 location /bar 的“内部跳转”。所谓“内部跳转”,就是在处理请求的过程中,于服务器内部,从一个 location 跳转到另一个 location 的过程。这不同于利用 HTTP 状态码 301 和 302 所进行的“外部跳转”,因为后者是由 HTTP 客户端配合进行跳转的,而且在客户端,用户可以通过浏览器地址栏这样的界面,看到请求的 URL 地址发生了变化。内部跳转和 Bourne Shell(或 Bash)中的 exec 命令很像,都是“有去无回”。另一个相近的例子是 C 语言中的 goto 语句。 既然是内部跳转,当前正在处理的请求就还是原来那个,只是当前的 location 发生了变化,所以还是原来的那一套 Nginx 变量的容器副本。对应到上例,如果我们请求的是 /foo 这个接口,那么整个工作流程是这样的:先在 location /foo 中通过 set 指令将 a 变量的值赋为字符串 hello,然后通过 echo_exec 指令发起内部跳转,又进入到 location /bar 中,再输出 a 变量的值。因为 a 还是原来的 a,所以我们可以期望得到 hello 这行输出。测试证实了这一点: 但如果我们从客户端直接访问 /bar 接口,就会得到空的 a 变量的值,因为它依赖于 location /foo 来对 a 进行初始化。 从上面这个例子我们看到,一个请求在其处理过程中,即使经历多个不同的 location 配置块,它使用的还是同一套 Nginx 变量的副本。这里,我们也首次涉及到了“内部跳转”这个概念。值得一提的是,标准 ngx_rewrite 模块的 rewrite 配置指令其实也可以发起“内部跳转”,例如上面那个例子用 rewrite 配置指令可以改写成下面这样的形式: ---------------------------------- server { listen 80; location /foo { set $a hello; rewrite ^ /bar; # ^匹配任何字符开头,这里没有具体写匹配什么开头,就是匹配所有 } location /bar { echo "a = [$a]"; } } ---------------------------------- curl 主机ip/foo 输出:a = [hello] 从上面这个例子我们看到,Nginx 变量值容器的生命期是与当前正在处理的请求绑定的,而与 location 无关。
添加echo指令
wget http://nginx.org/download/nginx-1.16.0.tar.gz tar xf nginx-1.16.0.tar.gz cd nginx-1.16.0 wget https://github.com/openresty/echo-nginx-module/archive/v0.61.tar.gz tar xf v0.61.tar.gz 在nginx原有编译参数中添加 --add-module=解压后的目录名,然后重新编译即可
内置预定义变量
内置预定义变量即无需声明就可以使用的变量,通常包括一个http请求或响应中一部分内容的值,以下为一些常用的内置预定义变量
变量名 | 定义 |
---|---|
$arg_PARAMETER | GET请求中变量名PARAMETER参数的值。 |
$args | 这个变量等于GET请求中的参数。例如,foo=123&bar=blahblah;这个变量只可以被修改 |
$binary_remote_addr | 二进制码形式的客户端地址。 |
$body_bytes_sent | 传送页面的字节数 |
$content_length | 请求头中的Content-length字段。 |
$content_type | 请求头中的Content-Type字段。 |
$cookie_COOKIE | cookie COOKIE的值。 |
$document_root | 当前请求在root指令中指定的值。 |
$document_uri | 与$uri相同。 |
$host | 请求中的主机头(Host)字段,如果请求中的主机头不可用或者空,则为处理请求的server名称(处理请求的server的server_name指令的值)。值为小写,不包含端口。 |
$hostname | 机器名使用 gethostname系统调用的值 |
$http_HEADER | HTTP请求头中的内容,HEADER为HTTP请求中的内容转为小写,-变为_(破折号变为下划线),例如:$http_user_agent(Uaer-Agent的值); |
$sent_http_HEADER | HTTP响应头中的内容,HEADER为HTTP响应中的内容转为小写,-变为_(破折号变为下划线),例如: $sent_http_cache_control, $sent_http_content_type…; |
$is_args | 如果$args设置,值为"?",否则为""。 |
$limit_rate | 这个变量可以限制连接速率。 |
$nginx_version | 当前运行的nginx版本号。 |
$query_string | 与$args相同。 |
$remote_addr | 客户端的IP地址。 |
$remote_port | 客户端的端口。 |
$remote_user | 已经经过Auth Basic Module验证的用户名。 |
$request_filename | 当前连接请求的文件路径,由root或alias指令与URI请求生成。 |
$request_body | 这个变量(0.7.58+)包含请求的主要信息。在使用proxy_pass或fastcgi_pass指令的location中比较有意义。 |
$request_body_file | 客户端请求主体信息的临时文件名。 |
$request_completion | 如果请求成功,设为"OK";如果请求未完成或者不是一系列请求中最后一部分则设为空。 |
$request_method | 这个变量是客户端请求的动作,通常为GET或POST。包括0.8.20及之前的版本中,这个变量总为main request中的动作,如果当前请求是一个子请求,并不使用这个当前请求的动作。 |
$request_uri | 这个变量等于包含一些客户端请求参数的原始URI,它无法修改,请查看$uri更改或重写URI。 |
$scheme | 所用的协议,比如http或者是https,比如rewrite ^(.+)$ $scheme://example.com$1 redirect; |
$server_addr | 服务器地址,在完成一次系统调用后可以确定这个值,如果要绕开系统调用,则必须在listen中指定地址并且使用bind参数。 |
$server_name | 服务器名称。 |
$server_port | 请求到达服务器的端口号。 |
$server_protocol | 请求使用的协议,通常是HTTP/1.0或HTTP/1.1。 |
$uri | 请求中的当前URI(不带请求参数,参数位于args),不同于浏览器传递的args),不同于浏览器传递的args),不同于浏览器传递的request_uri的值,它可以通过内部重定向,或者使用index指令进行修改。不包括协议和主机名,例如/foo/bar.html |
Nginx 内建变量最常见的用途就是获取关于请求或响应的各种信息。
1、uri vs request_uri 由 ngx_http_core 模块提供的内建变量 uri,可以用来获取当前请求的 URI(经过解码,并且不含请求参数), 而 request_uri 则用来获取请求最原始的 URI (未经解码,并且包含请求参数)。 vim /etc/nginx/nginx.conf ---------------------------------- location /test-uri { echo "uri = $uri"; echo "request_uri = $request_uri"; } ---------------------------------- nginx -s reload 输入:curl localhost/test-uri 输出:uri = /test-uri request_uri = /test-uri 输入:curl "localhost/test-uri?a=3&b=4" 输出:uri = /test-uri request_uri = /test-uri?a=3&b=4 输入:curl "localhost/test-uri/hello%20world?a=3&b=4" 输出:uri = /test-uri/hello world request_uri = /test-uri/hello%20world?a=3&b=4 %20在usi中代表空格的含义,url会将%20解码展示出来,request_usi会展示最原始的uri请求,未解码 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 2、$arg_XXX 另一个特别常用的内建变量其实并不是单独一个变量,而是有无限多变种的一群变量,即名字以 arg_ 开头的所有变量,我们估且称之为 arg_XXX 变量群。 一个例子是 arg_name,这个变量的值是当前请求中名为 name 的参数的值,而且还是未解码的原始形式的值。 ---------------------------------- location /test-arg { return 200 "name = $arg_name \n age = $arg_age"; } ---------------------------------- nginx -s reload 输入:curl localhost/test-arg 输出:name: class: 输入:curl "localhost/test-arg?name=Tom&class=3" 输出:name: Tom class: 3 输入:curl "localhost/test-arg?name=hello%20world&class=9" 输出:name: hello%20world class: 9 3、$arg_XXX 不区分大小写 其实 $arg_name 不仅可以匹配 name 参数,也可以匹配 NAME 参数,抑或是 Name,Nginx 会在匹配参数名之前,自动把原始请求中的参数名调整为全部小写的形式。 输入:curl "localhost/test-arg?NAME=Marry" 输出:name: Marry class: 输入:curl "localhost/test-arg?Name=Jimmy" 输出:name: Jimmy class:
20、nginx 监控
nginx的基础监控
进程监控 端口监控 注意: 这两个是必须要加在zabbix监控,加触发器有问题及时告警。 web 服务器 nginx 以其高性能与抗并发能力越来越多的被用户使用 作为一款服务器产品,其运行状态是运维密切关注的,因此,对 nginx 的实时监控就必须要关注的了 nginx 提供了 ngx_http_stub_status_module,ngx_http_reqstat_module模块,这个模块提供了基本的监控功能 作为官方企业版的 nginx plus 通过 ngx_http_status_module 提供了更加完善的监控功能
监控的主要指标
名称 | 描述 | 指标类型 |
---|---|---|
Accepts(接受) | NGINX 所接受的客户端连接数 | 资源: 功能 |
Handled(已处理) | 成功的客户端连接数 | 资源: 功能 |
Dropped(已丢弃,计算得出) | 丢弃的连接数(接受 - 已处理) | 工作:错误* |
Requests(请求数) | 客户端请求数 | 工作:吞吐量 |
我们需要对以下主要的指标进行监控: 1、基本活跃指标 Accepts(接受)、Handled(已处理)、Requests(请求数)是一直在增加的计数器。Active(活跃)、Waiting(等待)、Reading(读)、Writing(写)随着请求量而增减。 NGINX worker 进程接受 OS 的连接请求时 Accepts 计数器增加,而Handled 是当实际的请求得到连接时(通过建立一个新的连接或重新使用一个空闲的)。这两个计数器的值通常都是相同的,如果它们有差别则表明连接被Dropped,往往这是由于资源限制,比如已经达到 NGINX 的worker_connections的限制。 2、每秒请求数 QPS 按照固定时间间隔采样请求数据,计算出单位时间的请求量可以看到你的 web 服务器的请求情况 通过持续的 QPS 监控,可以立刻发现是否被恶意攻击或对服务的可用性进行评估 虽然当问题发生时,通过 QPS 不能定位到确切问题的位置,但是他却可以在第一时间提醒你环境可能出问题了 3、服务器错误率 通过监控固定时间间隔内的错误代码(4XX代码表示客户端错误,5XX代码表示服务器端错误),可以了解到客户端收到的结果是否是正确的错误率突然的飙升很可能是你的网站漏洞发出的信号 如果你希望通过 access log 分析错误率,那么你需要配置 nginx 的日志模块,让 nginx 将响应码写入访问日志 4、请求处理时间 请求处理时间也可以被记录在 access log 中,通过分析 access log,统计请求的平均响应时间,通过持续观察,可以发现上游服务器的问题
指标的收集
介绍了这么多的监控指标,事实上,上面介绍的仅仅是基本的监控指标,针对实际的情况,还有很多指标十分具有监控的必要 那么,怎么去收集这些指标进行监控呢? 通过在编译时加入nginx的ngx_http_stub_status_module模块我们可以实时监控以下基本的指标: 1、nginx Stub Status 监控模块安装 nginx -V -V大写会显示版本号和模块等信息、v小写仅显示版本信息 如果没有ngx_http_stub_status_module此模块,需要重新安装,编译命令如下: ./configure –with-http_stub_status_module vim /etc/nginx/nginx.conf ---------------------------------- server { listen 80; location /nginx-status { stub_status on; access_log /var/log/nginx/access.log; } } ---------------------------------- 2、nginx 状态查看 配置完成后在浏览器中输入主机ip/nginx-status查看 显示信息: Active connections: 2 server accepts handled requests 26 26 48 Reading: 0 Writing: 1 Waiting: 1 详细解释: Accepts(接受)、Handled(已处理)、Requests(请求数)是一直在增加的计数器。Active(活跃)、Waiting(等待)、Reading(读)、Writing(写)随着请求量而增减 3、Stub Status 参数说明 active connections – 活跃的连接数量 server accepts handled requests — 总共处理了1075个连接 , 成功创建1064次握手, 总共处理了6253个请求 每个连接有三种状态waiting、reading、writing reading —读取客户端的Header信息数.这个操作只是读取头部信息,读取完后马上进入writing状态,因此时间很短。 writing — 响应数据到客户端的Header信息数.这个操作不仅读取头部,还要等待服务响应,因此时间比较长。 waiting — 开启keep-alive后等候下一次请求指令的驻留连接. 正常情况下waiting数量是比较多的,并不能说明性能差。反而如果reading+writing数量比较多说明服务并发有问题。
当用户请求连接Nginx服务器时,accepts计数器会加一。且当服务器处理该连接请求时,handled计数器同样会加一。一般而言,两者的值是相等的,除非达到了某些资源极限(如worker_connection的限制)。 用户连接请求被处理,就会进入 active 状态。如果该连接没有其他 request,则进入 waiting 的子状态;如果有 request,nginx 会读取 request 的 header,计数器 request 加一,进入 reading 的子状态。 reading 状态持续时间非常短,header 被读取后就会进入 writing 状态。事实上,直到服务器将响应结果返回给用户之前,该连接会一直保持 writing 状态。所以说,writing 状态一般会被长时间占用。 一旦 NGINX 成功处理一个连接时,连接会移动到Active状态,在这里对客户端请求进行处理: Active状态: Waiting 活跃的连接也可以处于 Waiting 子状态,如果有在此刻没有活跃请求的话。新连接可以绕过这个状态并直接变为到 Reading 状态,最常见的是在使用“accept filter(接受过滤器)” 和 “deferred accept(延迟接受)”时,在这种情况下,NGINX 不会接收 worker 进程的通知,直到它具有足够的数据才开始响应。如果连接设置为 keep-alive ,那么它在发送响应后将处于等待状态。 Reading 当接收到请求时,连接离开 Waiting 状态,并且该请求本身使 Reading 状态计数增加。在这种状态下 NGINX 会读取客户端请求首部。请求首部是比较小的,因此这通常是一个快速的操作。 Writing 请求被读取之后,其使 Writing 状态计数增加,并保持在该状态,直到响应返回给客户端。这意味着,该请求在 Writing 状态时, 一方面 NGINX 等待来自上游系统的结果(系统放在 NGINX “后面”),另外一方面,NGINX 也在同时响应。请求往往会在 Writing 状态花费大量的时间。 通常,一个连接在同一时间只接受一个请求。在这种情况下,Active 连接的数目 == Waiting 的连接 + Reading 请求 + Writing 。 怎么利用这些参数? 开源的 Nginx 提供的原始参数中,实时性的会比较有用,如 Active connections、Reading、Writing 以及 Waiting。这些数据能够反映当前 Nginx 的负载情况,方便在服务器出现问题时及时发现问题。而另一些数据由于不是状态量,Nginx 无法计算当前的量值而改做其统计数,如 accepts、handled 和 requests。 对于维护网站人员,accepts、handled 和 requests 的统计值用处是不大的,值得参考的是短时间内这三者数值的增量。这个短时间可以是一秒,如 accepts_per_second、handled_per_second 和 requests_per_second。一个简单的做法就是每秒都去读取这些参数,返回一个和上一秒的差值就行。当然,handled_per_second 替换成 dropped_per_second=accepts_per_second-handled_per_second 就更完美了。 通过这七个参数,就可以从连接到请求全方位的监控起 Nginx 的运行状态。为了方便检测,对每次获取的参数保留下来,然后按时间展现出来。下图展示了 Nginx 在运行时的参考数据。 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 4、Reqstat 模块监控 描述 ngx_http_reqstat_module 模块 这个模块计算定义的变量,根据变量值分别统计 nginx 的运行状况。 可以监视的运行状况有:连接数、请求数、各种响应码范围的请求数、输入输 出流量、rt、upstream访问等。 可以指定获取所有监控结果或者一部分监控结果。 利用变量添加自定义监控状态。总的监控状态最大个数为50个。 回收过期的监控数据。 设置输出格式 跟踪请求,不受内部跳转的影响 不要使用与响应相关的变量作为条件,比如"$status" 编译 默认编入Tengine,可通过 --without-http_reqstat_module 编译此模块,或通过--with-http_reqstat_module=shared 编译为so模块。 使用so模块加载的话,请确保其顺序在"ngx_http_lua_module"之后。可以借助"nginx -m"来确认。 Syntax req_status zone_name1 [zone_name2 [zone_name3 [...]]] Default none Context http、server、location 开启统计,可以指定同时统计多个目标,每一个zone_name对应一个目标。 Syntax req_status_show [zone_name1 [zone_name2 [...]]] Default 所有建立的共享内存目标 Context location 按格式返回统计结果。可指定返回部分目标的统计结果。 Synta xreq_status_show_field field_name1 [field_name2 [field_name3 [...]]] Default all the fields, including user defined fields Context location 定义输出格式。可以使用的字段:内置字段,以上面的名字来表示;自定义字段,用变量表示。 'kv'总是每行的第一个字段。 Syntax req_status_zone_add_indecator zone_name _uarl[var2[...]] Default none Context http 通过变量增加自定义字段,新增加的字段目前会展现在每行的末尾。 Syntax req_status_zone_key_length zone_name length Default none Context http 定义某个共享内存块中key的最大长度,默认值104。key中超出的部分会被截断。 Syntax req_status_zone_recycle zone_name times seconds Default none Context http 定义某个共享内存块过期数据的回收。回收在共享内存耗尽时自动开启。只会回收访问频率低于设置值的监控数据。 req_status_zone_recycle demo_zone 10 60; 频率定义为 times / seconds,默认值为10r/min
安装模块:
tengine官方说req-statu模块默认安装。但是并没有。而且tengine的req-status模块不能分upstream监控,从github引入第三方模块解决该问题 yum与编译安装的nginx扩展模块安装: yum install -y unzip 下载或者上传一个和当前的nginx版本一样的nginx的tar包。 tar xzf nginx-1.16.0.tar.gz -C /usr/local/ wget https://github.com/zls0424/ngx_req_status/archive/master.zip -O ngx_req_status.zip #下载模块 unzip ngx_req_status.zip cp -r ngx_req_status-master/ /usr/local/ #与解压的nginx在同一级目录下 cd /usr/local/nginx-1.16.0/ yum -y install pcre pcre-devel openssl openssl-devel gcc gcc-c++ zlib zlib-devel yum -y install patch.x86_64 patch -p1 < ../ngx_req_status-master/write_filter-1.7.11.patch ./configure 添加上原来的参数 --add-module=/usr/local/ngx_req_status-master make -j2 mv /usr/sbin/nginx /usr/sbin/nginx_bak cp objs/nginx /usr/sbin/ systemctl restart nginx nginx -V 如果发现编译的配置文件有变化就成功了! 配置如下: 需要在http里面配置。 注意,添加了此配置,只有重启nginx才能生效。 vim /etc/nginx/nginx.conf ---------------------------------- req_status_zone server_name $server_name 256k; req_status_zone server_addr $server_addr 256k; req_status_zone server_url $server_name$uri 256k; req_status server_name server_addr server_url; server { server_name localhost; location /req-status { req_status_show on; } } ---------------------------------- 指令介绍 req_status_zone 语法: req_status_zone name string size 默认值: None 配置块: http 定义请求状态ZONE,请求按照string分组来排列,例如: req_status_zone server_url $server_name$uri 256k; 域名+uri将会形成一条数据,可以看到所有url的带宽,流量,访问数 req_status 语法: req_status zone1[ zone2 ] 默认值: None 配置块: http, server, location 在location中启用请求状态,你可以指定更多zones。 req_status_show 语法: req_status_show on 默认值: None 配置块: location 在当前位置启用请求状态处理程序
请求状态信息包括以下字段: zone_name - 利用req_status_zone定义的分组标准。例如,按照服务器名称对请求进行分组后; key - 请求按分组标准分组后的分组标识(即组名)。例如按服务器名称分组时,组名可能是10.0.105.196; max_active - 该组的最大并发连接数; max_bw - 该组的最大带宽; traffic - 该组的总流量; requests - 该组的总请求数; active - 该组当前的并发连接数; bandwidth - 该组当前带宽。
补充
查看Nginx并发进程数:ps -ef | grep nginx | wc -l 查看Web服务器TCP连接状态:netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}' LISTEN:侦听来自远方的TCPport的连接请求 SYN-SENT:再发送连接请求后等待匹配的连接请求 SYN-RECEIVED:再收到和发送一个连接请求后等待对方对连接请求的确认 ESTABLISHED:代表一个打开的连接 FIN-WAIT-1:等待远程TCP连接中断请求,或先前的连接中断请求的确认 FIN-WAIT-2:从远程TCP等待连接中断请求 CLOSE-WAIT:等待从本地用户发来的连接中断请求 CLOSING:等待远程TCP对连接中断的确认 LAST-ACK:等待原来的发向远程TCP的连接中断请求的确认 TIME-WAIT:等待足够的时间以确保远程TCP接收到连接中断请求的确认 CLOSED:没有不论什么连接状态
nginx access log 分析
nginx 的 access log 中可以记录很多有价值的信息,通过分析 access log,可以收集到很多指标 python 编写的 linux 工具 ngxtop 就实现了对 access log 的分析功能 制作nginx的日志切割,每天凌晨切割并压缩。 PV 即Page View, 即页面浏览量或点击量,用户每次刷新即被计算一次。 UV 即Unique Visitor,访问您网站的一台电脑客户端为一个访客。00:00-24:00内相同的客户端只被计算一次。 面试: 1.根据访问IP统计UV awk '{print $1}' access.log|sort | uniq -c |wc -l 2.统计访问URL统计PV awk '{print $7}' access.log|wc -l 3.查询访问最频繁的URL awk '{print $7}' access.log|sort | uniq -c |sort -n -k 1 -r|more 4.查询访问最频繁的IP awk '{print $1}' access.log|sort | uniq -c |sort -n -k 1 -r|more 5.查询访问最频繁的前10的IP awk '{print $1}' access.log|sort | uniq -c |sort -n -k 1 -r|head -n 10
https 介绍
HTTPS(全称:HyperText Transfer Protocol over Secure Socket Layer) HTTP 协议(HyperText Transfer Protocol,超文本传输协议):是客户端浏览器或其他程序与Web服务器之间的应用层通信协议 。 HTTPS 协议(HyperText Transfer Protocol over Secure Socket Layer):可以理解为HTTP+SSL/TLS, 即 HTTP 下加入 SSL 层,HTTPS 的安全基础是 SSL,因此加密的详细内容就需要 SSL,用于安全的 HTTP 数据传输。
如上图所示 HTTPS 相比 HTTP 多了一层 SSL/TLS SSL(Secure Socket Layer,安全套接字层):1994年为 Netscape(网景公司) 所研发,SSL 协议位于 TCP/IP 协议与各种应用层协议之间,为数据通讯提供安全支持。 TLS(Transport Layer Security,传输层安全):其前身是 SSL,它最初的几个版本(SSL 1.0、SSL 2.0、SSL 3.0)由网景公司开发,1999年从 3.1 开始被 IETF 标准化并改名,发展至今已经有 TLS 1.0、TLS 1.1、TLS 1.2 三个版本。SSL3.0和TLS1.0由于存在安全漏洞,已经很少被使用到。TLS 1.3 改动会比较大,目前还在草案阶段,目前使用最广泛的是TLS 1.1、TLS 1.2。
加密算法
据记载,公元前400年,古希腊人就发明了置换密码;在第二次世界大战期间,德国军方启用了“恩尼格玛”密码机,所以密码学在社会发展中有着广泛的用途。 1、对称加密 有流式、分组两种,加密和解密都是使用的同一个密钥。 例如:DES、AES-GCM、ChaCha20-Poly1305等 2、非对称加密 加密使用的密钥和解密使用的密钥是不相同的,分别称为:公钥、私钥,公钥和算法都是公开的,私钥是保密的。非对称加密算法性能较低,但是安全性超强,由于其加密特性,非对称加密算法能加密的数据长度也是有限的。 例如:RSA、DSA、ECDSA、 DH、ECDHE 3、哈希算法 将任意长度的信息转换为较短的固定长度的值,通常其长度要比信息小得多,且算法不可逆。 例如:MD5、SHA-1、SHA-2、SHA-256 等 4、数字签名 签名就是在信息的后面再加上一段内容(信息经过hash后的值),可以证明信息没有被修改过。hash值一般都会加密后(也就是签名)再和信息一起发送,以保证这个hash值不被修改。
HTTPS 原理
如上图所示,HTTP请求过程中,客户端与服务器之间没有任何身份确认的过程,数据全部明文传输,“裸奔”在互联网上,所以很容易遭到黑客的攻击,如下:
可以看到,客户端发出的请求很容易被黑客截获,如果此时黑客冒充服务器,则其可返回任意信息给客户端,而不被客户端察觉,所以我们经常会听到一词“劫持”,
http传输面临的风险有:
窃听风险:黑客可以获知通信内容。 篡改风险:黑客可以修改通信内容。 冒充风险:黑客可以冒充他人身份参与通信。
HTTP 向 HTTPS 演化的过程
如上图所示,此种方式属于对称加密,双方拥有相同的密钥,信息得到安全传输,但此种方式的缺点是: (1)不同的客户端、服务器数量庞大,所以双方都需要维护大量的密钥,维护成本很高 (2)因每个客户端、服务器的安全级别不同,密钥极易泄露 第二步:既然使用对称加密时,密钥维护这么繁琐,那我们就用非对称加密试试
如上图所示,客户端用公钥对请求内容加密,服务器使用私钥对内容解密,反之亦然,但上述过程也存在缺点: (1)公钥是公开的(也就是黑客也会有公钥),所以第 ④ 步私钥加密的信息,如果被黑客截获,其可以使用公钥进行解密,获取其中的内容 第三步:非对称加密既然也有缺陷,那我们就将对称加密,非对称加密两者结合起来,取其精华、去其糟粕,发挥两者的各自的优势
如上图所示 (1)第 ③ 步时,客户端说:(咱们后续回话采用对称加密吧,这是对称加密的算法和对称密钥)这段话用公钥进行加密,然后传给服务器 (2)服务器收到信息后,用私钥解密,提取出对称加密算法和对称密钥后,服务器说:(好的)对称密钥加密 (3)后续两者之间信息的传输就可以使用对称加密的方式了 遇到的问题: (1)客户端如何获得公钥 (2)如何确认服务器是真实的而不是黑客 第四步:获取公钥与确认服务器身份
1、获取公钥 (1)提供一个下载公钥的地址,回话前让客户端去下载。(缺点:下载地址有可能是假的;客户端每次在回话前都先去下载公钥也很麻烦) (2)回话开始时,服务器把公钥发给客户端(缺点:黑客冒充服务器,发送给客户端假的公钥) 2、那有木有一种方式既可以安全的获取公钥,又能防止黑客冒充呢? 那就需要用到终极武器了:SSL 证书(申购)
如上图所示,在第 ② 步时服务器发送了一个SSL证书给客户端,SSL 证书中包含的具体内容有: (1)证书的发布机构CA (2)证书的有效期 (3)公钥 (4)证书所有者 (5)签名 3、客户端在接受到服务端发来的SSL证书时,会对证书的真伪进行校验,以浏览器为例说明如下: (1)首先浏览器读取证书中的证书所有者、有效期等信息进行一一校验 (2)浏览器开始查找操作系统中已内置的受信任的证书发布机构CA,与服务器发来的证书中的颁发者CA比对,用于校验证书是否为合法机构颁发 (3)如果找不到,浏览器就会报错,说明服务器发来的证书是不可信任的。 (4)如果找到,那么浏览器就会从操作系统中取出 颁发者CA 的公钥,然后对服务器发来的证书里面的签名进行解密 (5)浏览器使用相同的hash算法计算出服务器发来的证书的hash值,将这个计算的hash值与证书中签名做对比 (6)对比结果一致,则证明服务器发来的证书合法,没有被冒充 (7)此时浏览器就可以读取证书中的公钥,用于后续加密了 4、所以通过发送SSL证书的形式,既解决了公钥获取问题,又解决了黑客冒充问题,一箭双雕,HTTPS加密过程也就此形成 所以相比HTTP,HTTPS 传输更加安全 (1) 所有信息都是加密传播,黑客无法窃听。 (2) 具有校验机制,一旦被篡改,通信双方会立刻发现。 (3) 配备身份证书,防止身份被冒充。
HTTPS 总结
综上所述,相比 HTTP 协议,HTTPS 协议增加了很多握手、加密解密等流程,虽然过程很复杂,但其可以保证数据传输的安全。所以在这个互联网膨胀的时代,其中隐藏着各种看不见的危机,为了保证数据的安全,维护网络稳定,建议大家多多推广HTTPS。 HTTPS 缺点: 1. SSL 证书费用很高,以及其在服务器上的部署、更新维护非常繁琐 2. HTTPS 降低用户访问速度(多次握手) 3. 网站改用HTTPS 以后,由HTTP 跳转到 HTTPS 的方式增加了用户访问耗时(多数网站采用302跳转) 4. HTTPS 涉及到的安全算法会消耗 CPU 资源,需要增加大量机器(https访问过程需要加解密)
1、申请证书与认证 要搭建https服务首先需有SSL证书,证书通常是在第三方申请,在阿里云的安全服务中有SSL证书这一项,可以在里面申请免费的证书; 也可以在自己电脑中生成,虽然也能完成加密,但是浏览器是不认可的,因此最好还是去第三方申请
2、购买域名
3、购买云服务器
将证书下载到云服务器,解压 在云服务器上下载nginx,并配置 -------------------------------------------------------------- server { listen 80; server_name www.jiaming.asia; rewrite .* https://$host$request_uri redirect; } server { listen 443 ssl; server_name www.jiaming.asia; access_log /var/log/nginx/https_access.log main; ssl_certificate /etc/nginx/cert/jiaming.asia_bundle.crt; ssl_certificate_key /etc/nginx/cert/jiaming.asia.key; ssl_session_timeout 5m; ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_ciphers ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP; ssl_prefer_server_ciphers on; location / { root /usr/share/nginx/html; index shuya.mp4; } } --------------------------------------------------------------
nginx性能优化
当我需要进行性能优化时,说明我们服务器无法满足日益增长的业务。性能优化是一个比较大的课题,需要从以下几个方面进行探讨 1、当前系统结构瓶颈 2、了解业务模式 3、性能与安全
当前系统结构瓶颈
首先需要了解的是当前系统瓶颈,用的是什么,跑的是什么业务。里面的服务是什么样子,每个服务最大支持多少并发。比如针对nginx而言,我们处理静态资源效率最高的瓶颈是多大?能支持多少qps访问请求?怎么得出系统当前的结构瓶颈? 可以通过查看当前cpu负荷,内存使用率,进程使用率来做简单判断。还可以通过操作系统的一些工具来判断当前系统性能瓶颈,如分析对应的日志,查看请求数量。也可以通过nginx http_stub_status_module模块来查看对应的连接数,总握手次数,总请求数。也可以对线上进行压力测试,来了解当前的系统能性能,并发数,做好性能评估。
了解业务模式
虽然我们是在做性能优化,但还是要熟悉业务,最终目的都是为业务服务的。我们要了解每一个接口业务类型是什么样的业务,比如电子商务抢购模式,这种情况平时流量会很小,但是到了抢购时间,流量一下子就会猛涨。也要了解系统层级结构,每一层在中间层做的是代理还是动静分离,还是后台进行直接服务。需要我们对业务接入层和系统层次要有一个梳理
性能与安全
性能与安全也是一个需要考虑的因素,往往大家注重性能忽略安全或注重安全又忽略性能。比如说我们在设计防火墙时,如果规则过于全面肯定会对性能方面有影响。如果对性能过于注重在安全方面肯定会留下很大隐患。所以大家要评估好两者的关系,把握好两者的孰重孰轻,以及整体的相关性。权衡好对应的点。
系统与nginx性能优化
大家对相关的系统瓶颈及现状有了一定的了解之后,就可以根据影响性能方面做一个全体的评估和优化。 - 网络(网络流量、是否有丢包,网络的稳定性都会影响用户请求) - 系统(系统负载、饱和、内存使用率、系统的稳定性、硬件磁盘是否有损坏) - 服务(连接优化、内核性能优化、http服务请求优化都可以在nginx中根据业务来进行设置) - 程序(接口性能、处理请求速度、每个程序的执行效率) - 数据库、底层服务 上面列举出来每一级都会有关联,也会影响整体性能,这里主要关注的是nginx服务这一层。
文件句柄
在linux/unix操作系统中一切皆文件,我们的设备是文件,文件是文件,文件夹也是文件。当我们用户每发起一次请求,就会产生一个文件句柄。文件句柄可以简单的理解为`文件句柄就是一个索引`。文件句柄就会随着请求量的增多,进程调用频繁增加,那么产生的文件句柄也就会越多。 系统默认对文件句柄是有限制的,不可能会让一个进程无限制的调用句柄。因为系统资源是有限的,所以我们需要限制每一个服务能够使用多大的文件句柄。操作系统默认使用的文件句柄是1024个句柄。 ~~~~~~~~~~~~~~~~~~~~~~~ 设置方式 - 系统全局性修改 - 用户局部性修改 - 进程局部性修改 1、系统全局性修该和用户局部性修改 vim /etc/security/limits.conf -------------------------------- #root只是针对root这个用户来限制,soft只是发提醒,操作系统不会强制限制,一般的站点设置为一万左右就ok了 root soft nofile 65535 root hard nofile 65535 # *代表通配符 所有的用户 * soft nofile 25535 * hard nofile 25535 -------------------------------- 可以看到root和*,root代表是root用户,*代表的是所有用户,后面的数字就是文件句柄大小。大家可以根据个人业务来进行设置。 2、进程局部性修改 vim /etc/nginx/nginx.conf -------------------------------- worker_rlimit_nofile 65535; #进程限制,全局配置中添加 -------------------------------- 3、cpu的亲和配置 cpu的亲和能够使nginx对于不同的work工作进程绑定到不同的cpu上面去。就能够减少在work间不断切换cpu,把进程通常不会在处理器之间频繁迁移,进程迁移的频率小,来减少性能损耗 查看物理cpu: cat /proc/cpuinfo | grep "physical id" | sort|uniq | wc -l 查看cpu核心数: cat /proc/cpuinfo|grep "cpu cores"|uniq 查看cpu使用率: top 回车后按 1 4、配置worker_processes vim /etc/nginx/nginx.conf 将刚才查看到自己cpu * cpu核心就是worker_processes -------------------------------- worker_processes 2; #根据自己cpu核心数配置/这里也可以设置为auto,全局配置中添加 --------------------------------
nginx 隐藏版本
http { server_tokens off; }
nginx 修改上传文件大小
http { client_max_body_size 10m; }
nginx 启用压缩传输
http { #开启gzip gzip on; #低于1kb的资源不压缩 gzip_min_length 1k; #压缩级别1-9,越大压缩率越高,同时消耗cpu资源也越多,建议设置在5左右。 gzip_comp_level 5; #需要压缩哪些响应类型的资源,多个空格隔开。不建议压缩图片. gzip_types text/plain application/javascript application/x-javascript text/javascript text/xml text/css; #配置禁用gzip条件,支持正则。此处表示ie6及以下不启用gzip(因为ie低版本不支持) gzip_disable "MSIE [1-6]\."; #是否添加“Vary: Accept-Encoding”响应头 gzip_vary on; }
ab接口压力测试工具
ab是Apache超文本传输协议(HTTP)的性能测试工具。其设计意图是描绘当前所安装的Apache的执行性能,主要是显示你安装的Apache每秒可以处理多少个请求。 yum install httpd-tools ab -n 2000 -c 2 http://127.0.0.1/ -n 总的请求数 -c 并发数 -k 是否开启长连接 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 参数选项: -n:即requests,用于指定压力测试总共的执行次数 -c:即concurrency,用于指定的并发数 -t:即timelimit,等待响应的最大时间(单位:秒) -b:即windowsize,TCP发送/接收的缓冲大小(单位:字节) -p:即postfile,发送POST请求时需要上传的文件,此外还必须设置-T参数 -u:即putfile,发送PUT请求时需要上传的文件,此外还必须设置-T参数 -T:即content-type,用于设置Content-Type请求头信息,例如:application/x-www-form-urlencoded,默认值为text/plain -v:即verbosity,指定打印帮助信息的冗余级别 -w:以HTML表格形式打印结果 -i:使用HEAD请求代替GET请求 -x:插入字符串作为table标签的属性 -y:插入字符串作为tr标签的属性 -z:插入字符串作为td标签的属性 -C:添加cookie信息,例如:"Apache=1234"(可以重复该参数选项以添加多个) -H:添加任意的请求头,例如:"Accept-Encoding: gzip",请求头将会添加在现有的多个请求头之后(可以重复该参数选项以添加多个) -A:添加一个基本的网络认证信息,用户名和密码之间用英文冒号隔开 -P:添加一个基本的代理认证信息,用户名和密码之间用英文冒号隔开 -X:指定使用的和端口号,例如:"126.10.10.3:88" -V:打印版本号并退出 -k:使用HTTP的KeepAlive特性 -d:不显示百分比 -S:不显示预估和警告信息 -g:输出结果信息到gnuplot格式的文件中 -e:输出结果信息到CSV格式的文件中 -r:指定接收到错误信息时不退出程序 -H:显示用法信息,其实就是ab -help ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 内容解释: Server Software: nginx/1.10.2 (服务器软件名称及版本信息) Server Hostname: 192.168.1.106(服务器主机名) Server Port: 80 (服务器端口) Document Path: /index1.html. (供测试的URL路径) Document Length: 3721 bytes (供测试的URL返回的文档大小) Concurrency Level: 1000 (并发数) Time taken for tests: 2.327 seconds (压力测试消耗的总时间) Complete requests: 5000 (的总次数) Failed requests: 688 (失败的请求数) Write errors: 0 (网络连接写入错误数) Total transferred: 17402975 bytes (传输的总数据量) HTML transferred: 16275725 bytes (HTML文档的总数据量) Requests per second: 2148.98 [#/sec] (mean) (平均每秒的请求数) 这个是非常重要的参数数值,服务器的吞吐量 Time per request: 465.338 [ms] (mean) (所有并发用户(这里是1000)都请求一次的平均时间) Time request: 0.247 [ms] (mean, across all concurrent requests) (单个用户请求一次的平均时间) Transfer rate: 7304.41 [Kbytes/sec] received 每秒获取的数据长度 (传输速率,单位:KB/s) ... Percentage of the requests served within a certain time (ms) 50% 347 ## 50%的请求在347ms内返回 66% 401 ## 60%的请求在401ms内返回 75% 431 80% 516 90% 600 95% 846 98% 1571 99% 1593 100% 1619 (longest request) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ab性能指标: 1、吞吐率(Requests per second) 服务器并发处理能力的量化描述,单位是reqs/s,指的是在某个并发用户数下单位时间内处理的请求数。某个并发用户数下单位时间内能处理的最大请求数,称之为最大吞吐率。记住:吞吐率是基于并发用户数的。这句话代表了两个含义: 吞吐率和并发用户数相关 不同的并发用户数下,吞吐率一般是不同的 计算公式:总请求数/处理完成这些请求数所花费的时间,即 Request per second=Complete requests/Time taken for tests 必须要说明的是,这个数值表示当前机器的整体性能,值越大越好 2、并发连接数(The number of concurrent connections) 并发连接数指的是某个时刻服务器所接受的请求数目,简单的讲,就是一个会话。 3、并发用户数(Concurrency Level) 要注意区分这个概念和并发连接数之间的区别,一个用户可能同时会产生多个会话,也即连接数。在HTTP/1.1下,IE7支持两个并发连接,IE8支持6个并发连接,FireFox3支持4个并发连接,所以相应的,我们的并发用户数就得除以这个基数。 4.用户平均请求等待时间(Time per request) 计算公式:处理完成所有请求数所花费的时间/(总请求数/并发用户数),即: Time per request=Time taken for tests/(Complete requests/Concurrency Level) 5.服务器平均请求等待时间(Time per request:across all concurrent requests) 计算公式:处理完成所有请求数所花费的时间/总请求数,即: Time taken for/testsComplete requests 可以看到,它是吞吐率的倒数。同时,它也等于用户平均请求等待时间/并发用户数,即 Time per request/Concurrency Level
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。