一文带你了解Nginx基础知识 | 建议收藏

1. 概述

不少人可能或多或少了解过nginx,即便没有使用过nginx,可是可能用Apache搭建过简单的web服务器,用tomcat写过一些简单的动态页面,其实这些功能nginx均可以实现。javascript

nginx最重要的三个使用场景我的认为是静态资源服务反向代理服务api服务css

web请求走进服务之后会先通过nginx再到应用服务,而后再去访问redis或者mysql提供基本的数据功能。html

这就有个问题,应用服务由于要求开发效率高,因此他的运行效率是很低的,他的qbstps并发都是受限的,因此就须要把不少的应用服务组成集群,向用户提供高可用性。java

不少服务构成集群的时候,须要nginx具备反向代理的功能,能够把动态请求传导给对应的应用服务。服务集群必定会带来两个需求,动态的扩容和容灾。mysql

反向代理必须具有负载均衡的功能,其次在链路中,nginx是处在企业内网的边缘节点,随着网络链路的增加,用户体验到的时延会增长。linux

把一些全部用户看起来不变的,或者在一段时间内看起来不变的动态内容缓存在nginx部分,由nginx直接向用户提供访问,用户的时延就会减小不少。nginx

反向代理衍生出另外的功能叫缓存,他可以加速访问,而不少时候在访问像cssjs文件又或者一些小图片是没有必要由应用服务来访问的,他只须要直接由nginx提供访问就能够了这就是nginx的静态资源功能。web

应用服务它自己的性能有很大的问题,数据库服务要比应用服务好的多,缘由是数据库他的业务场景比较简单,并发性能和tps都要远高于应用服务。由nginx直接去访问数据库或者redis也是不错的选择。正则表达式

还能够利用nginx强大的并发性能,实现如web防火墙的一些业务功能,这就要求nginx服务有很是强大的业务处理功能,openRestynginx集成了一些工具库来实现此功能。redis

2. 历史背景

全球化和物联网的快速发展,致使接入互联网中的人与设备的数量都在快速的上升,数据的快速爆炸,对硬件性能提出很高的要求。

摩尔定律代表以前服务跑在1GHZCPU上的服务更新到2GHZCPU时服务会有两倍的性能提高。

可是到了本世纪初,摩尔定律在单颗CPU的频率上已经失效了,CPU开始向着多核方向发展,当服务器如今是跑在8CPU上时,一年半之后换到了16核的CPU,服务的性能一般是不会有一倍的提高的。

这些性能主要损耗在操做系统和大量的软件没有作好服务于多核架构的准备,好比说像Apache是低效的,由于他的架构模型里一个进程同一时间,只会处理一个链接,一个请求。只有在这个请求处理完之后才会去处理下一个请求。

它实际上在使用操做系统的进程间切换的特性,由于操做系统微观上是有限的CPU,可是操做系统被设计为同时服务于数百甚至上千的进程。

Apache一个进程只能服务于一个链接,这种模式会致使当Apache须要面对几十万,几百万链接的时候,他没有办法去开几百万的进程,而进程间切换的代价成本又过高啦。

当并发的链接数越多,这种无谓的进程间切换引起的性能消耗又会越大。

nginx是专门为了这种应用场景而生的,能够处理数百万甚至上千万的并发链接,nginx目前在web市场份额中排行第二,在过去几年他增加极度迅速,在不久的未来nginxweb端的应用将远远超过其余服务器。

3. nginx的优势

大部分的程序和服务器随着并发链接数的上升他的RPS数会急剧的降低,这里的原理就像以前所说过的,他的设计架构是有问题的。

nginx的第一个优势就是高并发和高性能同时具有的,每每高并发只须要对每个链接所使用的内存尽可能的少就能够达到。

而具备高并发的同时达到高性能,每每须要很是好的设计,那nginx能够达到什么样的标准呢?

好比说如今主流的一些服务器3264G的内存能够轻松达到数千万的并发连接,若是是处理一些简单的静态资源请求,能够达到一百万的RPS这种级别。

其次nginx的可扩展性很是好,主要在于他的模块化设计很是的稳定,并且nginx的第三方模块的生态圈很是的丰富。甚至于有像TNG,openRestry这种第三方插件。丰富的生态圈为nginx丰富的功能提供了保证。

第三个优势是它的高可靠性,所谓的高可靠性是指nginx能够在服务器上持续不间断的运行数年,而不少web服务器每每运行几周或者几个月就须要作一次重启。

对于nginx这种高并发高性能的反向代理服务器而言,他每每运行在企业内网的边缘节点上,若是企业想提供4个95个9,甚至更高的高可用性时,对于nginx持续运行可以down机的时间一年可能只能以秒来计。因此在这种角色中,nginx的高可靠性给提供了很是好的保证。

第四个优势热部署,是指能够在不中止服务的状况下升级nginx,这对于nginx来讲很是的重要,由于在nginx可能跑了数百万的并发链接。

若是是普通的服务可能只需kill掉进程再重启的方式就能够处理好,可是对于nginx而言,由于killnginx进程,会致使操做系统为全部的已经创建链接的客户端发送一个tcp中的reset报文。而不少客户端是没有办法很好的处理请求的。

在大并发场景下,一些偶然事件就会致使必然的恶性结果,因此热部署是很是有必要的。

第五个优势是BSD许可证,BSD Listens是指nginx不只是开源的免费的,并且能够在有定制须要的场景下,去修改nginx源代码,再运行在商业场景下,这是合法的。

以上的优势是nginx最核心的特性。

4. 主要组成部分

首先是nginx的可执行文件,它是由nginx自身的框架、官方模块以及各类第三方模块共同构建的文件。他有完整的系统,全部的功能都由他提供。

第二个部分是nginx.conf配置文件,相似于骑车的驾驶员,虽然可执行文件已经提供了许多功能,但这些功能有没有开启,或者开启了之后定义了怎样的行为处理请求,都是由nginx.conf配置文件决定的。

nginx的第三个组成部分叫作access.log访问日志,access.log会记录下每一条nginx处理过的http请求信息与响应信息。

第四个组成部分是error.log错误日志,当出现了一些不可预期的问题时,能够经过error.log去把问题定位出来。

这四个部分是相辅相成的。

nginx的可执行文件和nginx.conf定义了处理请求的方式。若是想对web服务,作一些运营或者运维的分析,须要对access.log作进一步的分析。若是出现了任何未知的错误,或者与预期的行为不一致时,应该经过error.log去定位根本性的问题。

5. 版本规则

nginx每发布一个版本的时候会有三个特性,一个是feature,就是他新增了哪些功能,bugfix表示他修复了哪些bugchange表示作了哪些重构。

每个版本都有mainline主干版本和stable稳定版本。

nginx的官网点击右下角的download,就能够看到版本号列表,单数版本表示主干版本,会新增不少功能,但不必定稳定。双数版本是稳定版本。

CHANGES文件中能够看到每个版本含有的新增功能,修复的bug,以及作了哪些小的重构。

大概在2009年之后nginxbugfix数量已经大幅度减小,因此nginx相对已经很稳定了。

nginx的开发时间是在2002年,可是他在2004104日推出了第一个版本,在2005年曾经作过一次大的重构。

由于nginx优秀的设计,使得他的生态圈极为丰富,模块的设计,架构的设计都没有再作过大的变更。

2009nginx开始支持windows操做系统,20111.0正式版本发布,同时nginx的商业公司nginx Plus也成立了,在2015nginx发布了几个重要的功能。

其中提供stream四层反向代理,他在功能上彻底能够替代传统使用的LVS, 而且具备更丰富的功能。

6. 版本选择

免费开源: nginx.org

商业版本: nginx.com

开源免费的nginx2002年开始开发,到2004年发布第一个版本,2011年开源版的nginx发布了1.0稳定版,同年nginx的做者成立了一家商业公司,开始推出nginx Plus商业版的nginx

商业版的nginx在整合第三方模块上还有运营监控以及技术支持上有不少优势,但他有个最大的缺点就是不开源,因此一般在国内会使用nginx.org开源版的。

阿里巴巴也推出了Tengine版本,Tengine的优势就是在阿里巴巴生态下他经历了很是严苛的考验,Tengine之因此会存在也是由于他的不少特性领先于nginx的官方版本。

因此Tengine其实是修改了nginx官网版本的主干代码,固然框架被修改之后Tengine就遇到了一个明显的问题,没有办法跟着nginx的官方版本同步的升级。Tengine也可使用nginx的第三方模块。

OpenResty的做者章亦春在阿里巴巴的时候开发了Lua语言版本的openResty,由于nginx的第三方模块开发的难度至关大,章亦春把nginx非阻塞事件的一种框架以Lua语言的方式提供给了广大开发者。

OenRestry兼具了高性能,以及开发效率高的特色,OpenResty一样有开源版和商业版,目前多使用openresty.org站点下的开源版本。商业版OpenRestry的主要特色是技术支持相对比较好不少。

若是你没有太多的业务诉求,那么使用开源版的nginx就足够了,若是你须要开发Api服务器,或者须要开发web防火墙,openrestry是一个很好的选择。

7. 编译配置

安装nginx有两种方法,除了编译外,还能够直接用操做系统上自带的一些工具,好比说yumapt-get,直接去安装nginx

可是直接安装nginx有个问题,就是nginx的二进制文件不会把模块直接编译进来,毕竟nginx的官方模块,并非每个默认都会开启的。

若是想添加第三方的nginx模块,就必须经过编译nginx的方式。

编译nginx主要分为六个部分,首先须要下载nginx,从nginx.org网站上直接下载就能够。

打开nginx.org在页面中找到右下角donwload,选择Stable版本的下来连接,右键复制连接地址便可,进入到Linux中使用wget进行下载

cd  /home/nginx
wget http://nginx.org/download/nginx-1.18.0.tar.gz
复制代码

下载完nginx压缩包之后首先解压压缩包。

tar -xzf nginx-1.18.0.tar.gz
复制代码

接着进入解压后的目录经过ll命令查看全部文件。

cd nginx-1.18.0
ll
复制代码

第一个目录叫auto目录。

cd auto
复制代码

auto目录里面有四个子目录,cc是用于编译的,lib库和对操做系统的判断在os里面,其余全部的文件都是为了辅助config脚本执行的时候断定nginx支持哪些模块以及当前的操做系统有什么样的特性能够供给nginx使用。

CHANGES文件标记了nginx每个版本中提供了哪些特性和bugfix

cat ../CHANGES
复制代码

其中会有featurebugfixchange三种特性在里面。

CHANGES.ru文件是俄罗斯语言的CHANGES文件,可能由于做者是个俄罗斯人。

conf文件是一个示例文件,就是把nginx安装好之后,为了方便运维配置,会把config里面的示例文件copy到安装目录。

configure脚本用来生成中间文件,执行编译前的一个一些配置,也就是记录编译前的设定信息,编译时使用。

contrib目录提供了两个脚本和vim工具,也就是让vim打开config配置文件时支持代码高亮。

contrib目录下vim的全部文件copy到本身的目录中

cp -r contrib/vim/* ~/.vim/
复制代码

就能够把nginx语言的语法高亮显示在vim中了。

html目录里面提供了两个标准的HTML文件,一个是发现500错误的时候能够重定向到的文件,另外一个是默认的nginx的欢迎界面index.html

man文件里则是Linuxnginx的帮助文件,里面标识了最基本的nginx帮助和配置。

src目录是nginx的核心源码。

8. 开始编译

编译前能够先看一下configure支持哪些参数。

./configure --help | more
复制代码

首先就是肯定nginx执行中会去找哪些目录下的文件做为辅助文件。好比用动态模块时--modules-path就会产生做用。--lock-path肯定nginx.lock文件放在哪里等。

若是没有任何变更的话只须要指定--prefix=PATH就能够了,设定一个安装目录。

第二类参数主要是用来肯定使用哪些模块和不使用哪些模块的,前缀一般是--with--without

好比说--with-http_ssl_module或者--with-http_v2_module一般须要主动加--with的时候,意味着模块默认是不会编译进nginx的。

而模块中显示--without好比说--without-http_charset_module意味着默认他会编译进nginx中,加了参数是把他移除默认的nginx的模块中。

第三类参数中指定nginx编译须要的一些特殊的参数,好比说用cc编译的时候须要加一些什么样的优化参数,或者说要打印debug级别的日志(--with-debug)以及须要加一些第三方的模块(--with-zlib-asm=CPU)

这里指定的nginx的安装目录是在/home/nginx目录下。

./configure --prefix=/home/nginx/nginx/
复制代码

若是没有任何报错nginx就已经编译成功了,全部nginx的配置特性以及nginx运行时的目录都会列在最下方。

config执行完以后,会看到生成了一些中间文件。中间文件会放在objs文件夹下。最重要的是会生成一个文件叫作ngx_modules.c他决定了接下来执行编译时哪些模块会被编译进nginx。能够打开看一下全部被编译进nginx的模块都会列在这里,他们最后会造成一个叫作ngx_modules的数组。

执行make编译。

make
复制代码

编译完成之后若是没有任何错误,就能够看见生成了大量的中间文件,以及最终的nginx二进制文件。

cd objs/
ll
复制代码

最后进行make install

make install
复制代码

安装完成以后在--prefix指定的安装目录中能够看到不少目录,nginx的执行文件就在sbin目录下。

决定nginx功能的配置文件在conf下,access.logerror.loglog文件夹下。

能够看到在conf目录下全部文件就是在源代码中conf目录copy过来的,其中的内容也是彻底相同的。

9. 配置语法

nginx可执行文件中已经指定了他包含了哪些模块,但每个模块都会提供独一无二的配置语法。

这些全部的配置语法,会遵循一样的语法规则。

nginx的配置文件是一个ascii的文本文件,主要有两部分组成,指令指令快

http {
    include mime.types;
    upstream thwp {
        server 127.0.0.1:8000;
    }

    server {
        listen 443 http2;
        # nginx配置语法
        limit_req_zone $binary_remote_addr zone=one:10 rate=1r/s;
        location ~* \.(gif|jpg|jpeg)$ {
            proxy_cache my_cache;
            expires 3m;
        }
    }
}
复制代码

上面http就是一个指令快,include mime.types;就是一条指令。

每条指令以分号结尾,指令和参数间以空格分隔。include mime.types;include是一个指令名,mime.types是参数中间能够用一个或多个空格分隔。参数能够有多个,好比下面的limit_req_zone有三个参数,多个参数之间也是用空格分隔。

两条指令间是以;做为分隔符的,两条指令放在一行中写也是没有问题的。只不过可读性会变得不好。

第三个指令块是以 {} 组成的,他会将多条指令组织到一块儿,好比upstream,他把一条指令server放在了thwp指令块下面。

server中也放置了listenlimit_req_zone这些指令,他也能够包含其余的指令块,好比说location

有些指令能够有名字,好比upstream,后面有个thwp做为他的名字。

具体什么样的指令有名字什么样的指令没有名字是由提供指令块的nginx模块来决定的,他也能够决定指令块后面有一个或者说多个参数,或者说没有参数。

include语句容许引入多个配置文件以提高可维护性。在例子中mime.types文件中其实里面是含有不少条不一样的文件的后缀名与http协议中mime格式的对照关系表。

include是导入其余配置模块的意思。

#符号能够添加注释,提高可读性,好比在listen后面加了一个nginx配置语法的注释,以描述下面一些配置的表达。

使用$符号可使用变量,能够看下limit_req_zone这里用了一个参数叫作$binary_remote_addr,这是一个变量描述的是远端的地址。

部分指令的参数是支持正则表达式的,好比location后面能够看到,他能够支持很是复杂的正则表达式,并且能够把正则表达式括号里的内容经过$1,$2,$3的方式取出来。

nginx的配置文件中当涉及到时间的时候,还有许多表达方式,好比下面的方式:

ms -> 毫秒
s  -> 秒
m  -> 分钟
h  -> 小时
d  -> 天
w  -> 周
M  -> 月
y  -> 年
复制代码

好比location中的expires 3m;就表示3分钟后但愿cache刷新。

空间也是有单位的,当后面不加任何后缀名时表示字节bytes,加了k或者K表示千字节,m表示兆字节,g表示G字节。

http大括号里面全部的指令都是由http模块去解析和执行的,非http模块,好比说像streammime是没有办法去解析指令的。

upstream表示上游服务,当nginx须要与Tomcat等企业内网的其它服务交互的时候呢,能够定义一个upstream

server对应的一个或一组域名,locationurl表达式。

10. 重载,热部署,日志切割

须要帮助的时候能够用-? 或者 -h获取帮助信息。

nginx -?
nginx -h
复制代码

默认状况下编译出来的nginx会寻找执行configure命令时指定的配置文件。在命令行中能够指定另外一个配置文件用-c 路径

还能指定一些配置用-g,指令就是在nginxconfigure目录里的指令。

nginx操做运行中的进程通常是经过发送信号,能够经过linuxkill命令也能够用nginx -s子命令,子命令后能够用stopquitreloadreopen

nginx -s stop # 中止nginx服务
nginx -s quit # 优雅的中止nginx服务
nginx -s reload # 重载配置文件
nginx -s reopen # 从新开始记录日志文件。
复制代码

-t能够测试一下配置文件是否合法问题。

-V是在编译时用configure脚本执行所加的全部参数。

1. 重载配置文件

修改nginx配置文件中的一些值,好比说conf/nginx.conf文件中,打开tcp_nopush

当修改完配置文件之后,能够直接执行nginx -s reload命令nginx是在不中止对客户服务的状况下使用了tcp_nopush新的配置项,很是的简单。

2. 热部署

nginx在运行的状况下想更换最新版本的nginx,根据以前所说的,nginx编译方法下载一个新的nginx

把最新版本的nginx编译后的可执行文件nginxcopy到目录中替换掉正在运行的nginx文件。copy完成须要给正在运行的nginxmaster进程发送一个信号,告诉他开始进行热部署作一次版本升级,给nginxmaster进程发送一个信号,USR2信号。

kill -USR2 进程号(13195)
复制代码

nginx会新启一个master进程使用的正式刚刚复制过来的最新的nginx二进制文件。

旧的worker也在运行,新的master会生成新的worker,他们会平滑的把全部的请求过渡到新的进程中。

新的请求新的链接会进入新的nginx进程中,这时须要向老的nginx进程发送一个信号叫作WINCH,告诉他优雅的关闭全部进程。

kill -WINCH 13195
复制代码

这时老的worker进程会优雅的退出,可是老的master进程还在,只是是没有worker进程了。

这说明全部的请求已经所有切换到新的nginx中了,若是须要把新版本退回到老版本,能够向老的进程发送reload命令,让他从新把worker进程拉起来。再把新版本关掉。因此保留master是为了容许作版本回退。

3. 日志切割

好比说当前的日志已经很大了。须要把之前的日志备份到另一个文件中,可是nginx仍是正常运行的。

这就要经过reopen命令来作,首先须要把当前正在使用的日志copy一份放在另外的位置.

mv access_log bak.log
复制代码

接着执行命令reopen

nginx -s reopen
复制代码

就从新生成了一个access.log, 本来的log备份成了bak.log,就实现了日志切割。

固然这种方法会很是很差用,实际上每每是每一天,或者是每一周执行一第二天至切割,能够先写成一个bash脚本。

bash脚本中首先把文件复制一下,再执行-s reopen命令,最后把脚本放在crontab中。

11. 静态资源Web服务器

编辑conf/nginx.conf文件找到server代码块中,listen配置监听端8080端口,而后须要配置一个location,使用/让全部的请求都访问到www文件夹。

这里须要指定url的后缀与文件的后缀一一对应,有两种用法,rootaliasroot是系统的跟目录,因此一般使用aliasaliasnginx的安装目录。

server {
    listen 8080;
    ...
    location / {
        alias www/;
        ...
    }
    ...
}
复制代码

作完配置以后启动nginx在浏览器中访问localhost:8080就能够了。

nginx -s reload
复制代码

1. 开启gzip

作完gzip压缩传输的字节数会大幅度减小,因此一般会打开gzip

首先打开nginx.conf文件,找到http代码块中的gzip相关选项,打开gzip(off -> on), gzip_min_length是小于多少字节再也不执行压缩,由于小于必定的字节http传输直接就能够发送了,压缩反而消耗cpu性能,gzip_comp_level表明压缩级别,gzip_types是针对某些类型的文件才作gzip压缩。

http {
    ...
    gzip on;
    gzip_min_length 1;
    gzip_comp_level 2;
    gzip_types text/plain applicaton/x-javascript text/css image/png;
    ...
}
复制代码

配置好后重启nginx, 浏览器中查看就会发现,传输的文件已经减小了不少,响应头中多出了Content-encoding: gzip。使用gzip之后整个web服务传输效率会高不少。

2. 打开目录结构

nginx给提供了一个官方模块叫作autoindex,他能够提供当访问以/结尾的url时,显示目录的结构。使用方法也特别简单,就是autoindex on加入一个指令就能够了。

location / {
    autoindex on;
}
复制代码

他会把所访问的文件夹内全部文件列出来,当打开一个目录时,能够继续显示目录中的文件,这是一个很好的静态资源帮助功能。

3. 网速限制

好比公网带宽是有限的,当有不少并发用户使用带宽时,他们会造成一个争抢关系,可让用户访问某些大文件的时候来限制他的速度,节省足够的带宽给用户访问一些必要的小文件。

就可使用set命令,配合一些内置的变量实现这种功能,好比说加上set $limit_rate 1k,限制nginx向客户浏览器发送响应的一个速度。意思是每秒传输多少数据到浏览器中。

location / {
    set $limit_rate 1k;
}
复制代码

4. 日志

首先须要设置access日志格式,找到一个指令叫作log_format, 他用来定义日志的格式,这里可使用变量。

http {
    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地址,$time_local表示当时的时间。$status是返回的状态码。格式定义好以后须要定义一个名字,这里是main

不一样的名字能够对不一样的域名下,作不一样格式的日志记录,或者对不一样的url记录不一样日志格式。

配置好log_format以后,就能够用access_log指令,配置日志了。access_log所在的代码块决定了日志的位置好比access_log这里放在了server下,也就是全部请求这个路径和端口的请求日志,都会记录到logs/yindong.log文件中,使用的格式就是main

server {
    listen 8080;
    access_log logs/yindong.log main;
    location / {
        alias dlib;
    }
}
复制代码

配置好yindong.log后,全部的请求在完成以后都会记录下一条日志,能够进入logs/yindong.log中查看每一条都是设置的格式。

12. 反向代理服务

因为上游服务要处理很是复杂的业务逻辑并且强调开发效率,因此他的性能并不怎么样,使用nginx做为反向代理之后,能够由一台nginx把请求按照负载均衡算法代理分配给多台上游服务器工做。

这就实现了水平扩展的可能,在用户无感知的状况下,添加更多的上游服务器,来提高处理性能,而当上游服务器出现问题的时候,nginx能够自动的把请求从有问题的服务器,转交给正常的服务器。

反向代理须要添加一个upstream,就是上游服务server,访问地址是127.0.0.1:8080若是有不少台上游服务能够依次的放在这里。

upstream设置的一批服务叫local。对全部的请求使用proxy_pass一条指令,代理到local里。

upstream local{
    server 127.0.0.1:8080;
}
server {
    server_name yindong.com;
    listen 80;
    location / {
        proxy_set_header Host $host;
        proxt_set_header X-Real_IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        # 反向代理转发
        proxy_pass http://local;
    }
}
复制代码

由于反向代理的缘由,真实的服务器拿到的信息是通过nginx代理服务器转发的,因此不少信息都不是真实的,好比说域名ip都是代理服务器发送过来的,因此须要在location中作一些配置处理。

经过proxy_set_header能够把有一些值添加一条新的header发送到上游,好比说叫x-real-ip,而后把他的值设为从tcp连接里面拿到的远端ip地址。

$host也是一样的由于用户直接访问的域名,是他在浏览器输入的,既可让他在上游服务器能够处理域名,也能够由反向代理来处理。

全部这些配置特性均可以在官网中的http_proxy_module找到。

1. 缓存

这里有个很重要的特性proxy_cache, 由于当nginx做为反向代理时,一般只有动态的请求,也就是不一样的用户访问同一个url看到的内容是不一样的,才会交由上游服务处理。

可是有一些内容多是一段时间不会发生变化的,为了减轻上游服务器的压力,就会让nginx把上游服务返回的内容缓存一段时间,好比缓存一天,在一天以内即便上游服务器对内容的响应发生了变化,也无论,只会去拿缓存住的这段内容向浏览器作出响应。

由于nginx的性能远远领先于上游服务器的性能。因此使用一个特性后,对一些小的站点会有很是大的性能提高。

配置缓存服务器首先要去经过proxy_cache_path这条指令去设置缓存文件写在哪一个目录下。

好比这里是/tmp/nginxcache, 以及这些文件的命名方式,这些文件的关键词key,要放在共享内存中的。这里开了10MB的共享内存,命名为my_cache

proxy_cache_patj /tmp/nginxcache levels=1:2 keys_zone=my_cache:10m max_size=10g inactive=60m use_temp_path_off;
复制代码

缓存的使用方法就是在须要作缓存的url路径下,添加proxy_cache, 后面所跟的参数就是刚刚开辟的那个共享内存,在共享内存中所设置的key就是同一个url访问时对不一样的用户可能展现的东西是不同的,因此用户这个变量就要放在key中。

这里作一个很是简单的key,好比说访问的host url可能加了一些参数,这些参数可能已经指明了是哪一个用户哪一个资源,$host$uri$is_args$args; 这些做为一个总体的key

location / {
    proxy_cache my_cache;
    proxy_cache_key $host$uri$is_args$args;
    proxy_cache_valid 200 304 302 1d;
}
复制代码

加完这些参数之后,能够尝试停掉上游服务,而后访问站点,能够发现站点仍然是能够访问的。就是由于被缓存了。

13. 监控access日志

Access日志记录了nginx很是重要的信息,能够用日志来分析定位问题,也能够用它来分析用户的运营数据,可是若是想实时分析Access.log相对来讲还比较困难。

有一款工具叫GoAccess能够以图形化的方式,经过websocket协议实时的把Access.log的变迁反应到浏览器中,方便分析问题。

GoAccess的站点是 https://goaccess.io, 以一种很是友好的图形化方式显示。

GoAccess使用-o参数生成新的html文件,把当前access.log文件中的内容以html图表的方式展现出来,当access.log变迁的时候GoAccess会新起一个socket进程,经过端口的方式把新的access.log推送到客户端。

goaccess access.log -o report.html --log-format=COMBINED
复制代码

首先制定access.log程序制定的位置(yindong.log), 把它输出到../html/report.html文件中,使用的是--real-time-html就是实时更新页面的方式,时间格式--time-format='%H:%M:%S', 日期格式--date-format='%d/%b/%Y', 以及日志格式--log-format=COMBINED

cd logs
goaccess yindong.log -o ../html/report.html --real-time-html --time-format='%H:%M:%S' --date-format='%d/%b/%Y' --log-format=COMBINED
复制代码

GoAccess的安装能够用yum或者wget,也能够下载源码进行编译。

启动完成以后能够看到一条log叫作 WebSocket server ready to accept new client connections, 也就是他已经打开了一个新的websocket监口,当访问report.html的时候,会向进程发起链接, 由进程给推送最新的log变动。

接下来还要在nginx.conf中添加location,当访问/report.html时候用alias重定向到report.html

server {
    ...
    location /report.html {
        alias /usr/local/openresty/nginx/html/report.html;
    }
    ...
}
复制代码

打开localhost:8080/report.html就能够看到效果了。

使用GoAccess.log能够很是直观的看到access.log统计信息上的变迁,对分析网站的运营状况很是有帮助,能够看到每一个时间点,每一周每一天,甚至不一样的国家地区使用不一样浏览器和操做系统的人使用站点的一个比例和分布。

14. SSL安全协议

SSL的全称是Secure Sockets Layer,如今不少时候使用的是TLS也就是Transport Layer Security。能够将TLS看作是SSL的升级版。

SSL是网景公司在1995年推出的,后来由于微软把本身的IE浏览器捆绑windows一块儿卖出致使网景遇到很大的发展困境,网景把SSL协议交给IETF组织。

1999年,应微软的要求IETFSSL改名为TLS1.0,在06082018TLS分别发布了1.11.21.3协议。

那么TLS协议到底是怎样保证http的明文消息被加密的呢?

ISO/OSI七层模型中,应用层是http协议,在应用层之下,表示层也就是TLS所发挥做用的这一层,经过握手交换密钥告警对称加密的方式使http层没有感知的状况下作到了数据的安全加密。

当抓包或者观察服务端配置时,能够看到安全密码的配置,安全密码的配置决定了TLS协议是怎样保证实文被加密的。这里大概有四个组成部分。

第一个组成部分叫作密钥交换,也就是ECDHE,这其实是一个椭圆曲线加密算法的表达,密钥交换是为了让浏览器和服务器之间怎样各自独立的生成密钥,数据传输时他们会用密钥去加密数据。加解密是须要使用到对方的密钥的因此须要进行交换。

在密钥交换过程当中,须要让浏览器和服务器各自去验证对方的身份,而验证身份是须要一个算法的,叫作RSA

进行数据加密,解密这种通信的时候,须要用到对称加密算法AES_128——GCM,其中第一个部分AES表达了是怎样一种算法,128表示了AES算法里支持了3种加密强度,使用128位这种一个加密强度。AES中有不少分组模式GCM是一种比较新的分组模式,能够提升多核CPU状况下加密和解密的一个性能。

SHA_256是摘要算法,他用来把不定长度的字符串生成固定长度的更短的摘要。

15. 对称加密、非对称加密

在对称加密场景中,两个想通信的人张三和李四,他们共同持有同一把密钥,张三能够把原始明文的文档,经过这一把密钥加密生成一个密文文档,而李四拿到文档之后呢,他能够用这把密钥还原转换为原始的明文文档,而中间的任何人若是没有持有这把密钥,即便他知道了对称加密的算法他也没有办法把密文还原成原始文档。

那么对称加密究竟的实现能够以RC4对称加密的序列算法来描述。

使用异或(xor)操做, 他是一个位操做,好比10进行异或获得101也获得了1,那么相同的11或者00进行异或操做都会获得0

在一个场景下1010是共同持有的密钥,0110是明文,张三执行加密的时候就会获得密文1100

1 0 1 0 # 密钥
  xor   # 异或操做
0 1 1 0 # 明文
  | |    # 输出
1 1 0 0 # 密文
复制代码

异或有一个对称的特性,就是把密文与密钥一样的作异或操做能够获得明文。

1 0 1 0 # 密钥
  xor   # 异或操做
1 1 0 0 # 密文
  | |    # 输出
0 1 1 0 # 明文
复制代码

密文能够用同一把密钥彻底还原成了明文,因此对称加密有一个最大的优势就是他的性能很是的好,他只要遍历一次就能够获得最终的密文,解密的过程也是同样,而非对称加密他的性能就会差不少。

非对称加密根据一个数学原理,他会生成一对密钥,这一对密钥中若是称其中一个叫作公开钥匙(公钥),那么另外一个就叫作私有钥匙(私钥)。

公钥和私钥做用就是同一份命名文档若是用公钥加密了那么只有用对应的私钥才能把它解密,一样道理,若是文档用私钥加密了用公钥才能解密。

好比说李四他有一对公钥和私钥,那么他就能够把他的公钥发布给你们,好比张三是其中的一我的,他拿到了李四的公钥,加密操做是怎么作的呢?

张三若是想传递一份原始文档给李四,那么张三就能够拿着李四的公钥对原始文档进行加密,把密文再发送给李四,李四用本身的私钥才能进行解密,其余人即便获得了这份文档也没有办法进行解密。

----------                ----------                  ----------  
|  ------  |  李四的公钥    |  ------  |   李四的私钥     |  ------ | 
|  ------  | -----------> |  -- 密 -- |  ----------->  |  ------ |
|  ------  |    加密       |  ------  |     解密        |  ------ |
 ----------                ----------                  ----------
   原始文档                    加密文档                     原始文档 
复制代码

公钥和私钥还有第二种用途,就是身份验证,好比如今有一段信息李四用它的私钥进行了加密,而后把密文发给了张三,只要张三若是可使用李四的公钥解开这份文档,那么就证实这段密文确实是由李四发出的。由于只有李四有本身的加密私钥,若是是王五加密的文档张三用李四的公钥是解不开的,只有用李四私钥加密的使用李四的公钥才能解开。

16. SSL证书的公信力

这里其实还有个问题,李四怎么就知道消息真的是张三发过来的。这里面涉及到一个新的概念叫公信机构。在多方通讯的过程当中必须有一个公信机构CA,负责颁发证书和把证书过时的。

做为站点的维护者就是证书的订阅人,首先必须申请一个证书,申请证书可能须要登记是谁,属于什么组织,想作什么。

登记机构经过CSR发给CACA中心经过后会生成一对公钥和私钥,公钥在CA保存着,公钥私钥证书订阅人拿到以后就会把它部署到本身的web服务器,当浏览器访问站点的时候,服务器会把公钥证书发给浏览器,浏览器须要向CA验证证书是否合法和有效的。若是有效就证实没有被篡改。

因为CA会把过时的证书放在CRL服务器里,服务器会把全部过时的证书造成一条链条因此他的性能很是的差,后来又推出了OCSP程序能够就一个证书去查询是否过时,因此浏览器是能够直接去查询OCSP响应程序的,但OCSP响应程序性能还不是很高。

nginx会有一个OCSP的开关,当打开开关之后会由nginx主动的去OCSP去查询,大量的客户端直接从nginx就能够获取到证书是否有效。

证书一共有3种类型。

第一种叫作域名验证DV证书,也就是说证书只会去验证域名的归属是否正确,申请证书的时候只要域名指向的服务器是正在申请证书的服务器,就能够成功的申请到证书。

第二种证书叫作组织验证OV证书,组织验证就是在申请证书的时候会去验证填写的机构,企业名称是不是正确的,申请OV证书每每须要几天的时间,不像DV证书,基本上实时就能够获取到,OV证书的价格远远高于DV证书,DV证书不少都是免费的。

OV证书作更严格的是EV证书,大部分浏览器对EV证书显示的很是友好,他会把证书申请时所填写的机构名称在浏览器的地址栏中显示出来。

浏览器在安全角度对DVOV,,EV证书他的效果是同样的。惟一验证的就是证书链。

若是你点击网站地址栏中的锁头标志,打开证书链的时候,能够发现存在三个级别,目前全部主证书都是由根证书、二级证书、主证书三个证书构成的。

之因此须要三级机构是由于根证书的验证是很是谨慎的,如windows,安卓等操做系统每年以上才会去更新一次根证书库,因此一个新的根证书CA机构是很难快速的加入到操做系统或者浏览器中的。

大部分浏览器他使用的是操做系统的证书库,只有像firefox这种浏览器会维护本身的根证书库,因此浏览器在验证证书是否有效时,除了验证有没有过时之外,最主要就是在验证根证书是否是有效的,是否是被跟证书库所承认的。

nginx在向浏览器发送证书的时候须要发送两个证书,根证书是被操做系统或者浏览器内置的并不须要发送。首先发送站点的主证书,接着会发送二级证书,浏览器会自动去认证二级证书的签发机构,根证书是否是有效的。

浏览器和服务器之间通讯时确认对方是信赖的人其实就是验证给站点颁发根证书的发行者是否是有效的。

17. SSL协议握手时nginx的性能瓶颈

TLS的通讯过程主要想完成四个目的。

1. 验证对方身份

浏览器会向服务器发送一个client hello消息。有一浏览器很是多样化,并且版本在不停的变动。因此不一样的浏览器所支持的安全套件,加密算法都是不一样的。这一步主要是告诉服务器,浏览器支持哪些加密算法。

2. 对安全套件达成共识

nginx有本身可以支持的加密算法列表,以及他倾向于使用的哪个加密算法套件,nginx会选择一套他最喜欢的加密套件发送给客户端。

若是想复用session,也就是说nginx打开了session cache,但愿在一天内断开连接的客户端不用再次协商密钥,能够直接去复用以前的密钥。

server hello信息中主要会发送究竟选择哪个安全套件。

3. 传递并生成密钥

nginx会把本身的公钥证书发送给浏览器,公钥证书中包含证书链,浏览器能够找到本身的根证书库,去验证证书是不是有效。

4. 对数据进行加密通信

服务器会发送server hello done,若是以前协商的安全套件是椭圆曲线算法,这时会把椭圆曲线的参数发送给客户端。客户端须要根据椭圆曲线的公共参数,生成本身的私钥后再把公钥发送给服务器。

服务器有了本身的私钥,会把公钥发送给客户端,服务端能够根据本身的私钥和客户端的私钥,共同生成双方加密的密钥。

客户端根据服务器发来的公钥和他本身的私钥也能够生成一个密钥。

服务器和客户端各自生成的密钥是相同的,是由非对称加密算法保证的。接着能够用生成的密钥进行数据加密,进行通讯。

TLS通讯主要在作两件事,第一个是交换密钥,第二个是加密数据,主要的性能消耗也是这两点。

nginx在这里是有性能优化的,主要是他的算法性能,对于小文件,握手是影响QPS性能的主要指标,对于大文件而言,主要考虑对称加密算法的性能好比AES,对称加密算法虽然性能很好,可是对很是大的一个文件,测吞吐量时仍是AES的性能比较好的。

当以小文件为主时主要考验的是nginx的非对称加密的性能,好比说RSA,当主要处理大文件时主要考验的是对称加密算法的性能,好比说AES

面对的场景是小文件比较多时重点应该优化椭圆曲线算法的一些密码强度,看是否是有所下降,当主要面对大的文件处理的时候须要考虑AES算法是否是能够替换为更有效的算法,或者把密码强度调得更小一些。

18. 用免费SSL证书实现一个HTTPS站点

首先须要有一个域名好比说yindong.zhiqianduan.com他是一个http的网址。

接着开始安装工具,必须的工具。

若是系统是CentOS,可使用yum安装,优班图系统可使用wget工具下载。

yum install pthon2-certbot-nginx
复制代码

安装好会提供certbot命令,当后缀加上--nginx的时候就开始为nginxconf自动执行相应的修改。一般他会默认修改/usr/local/目录下的nginx配置。能够经过--nginx-server-root指定nginx.conf所在的路径。

使用-d指定须要申请证书的域名,好比说yindong.zhiqianduan.com

certbot --nginx --nginx-server-root=/usr/local/nginx/conf/ -d yindong.zhiqianduan.com
复制代码

首先他会去获取一个证书,接着会等待验证,而后把证书部署到nginx.conf文件中。最后提示两个选择,第一不要作任何的重定向,第二作重定向。重定向就是将http的访问302https从而禁掉不安全的http访问。

选择以后就可使用https访问yindong.zhiqianduan.com域名了。https://yindong.zhiqianduan.com

他是在在server指令块中增长了443端口,让后将公钥证书和私钥证书部署好,并把一些通用的参数经过include加入到配置文件中。

由于ssl中最消耗性能是的握手,因此为了下降握手增长了sessin_cache, 设置1m,能够为大约4000个连接创建服务。也就是说每一个http连接握手创建第一次之后若是断开了再次连接,那么在session_timeout时间之内是不用进行再次握手的。能够复用以前的密钥,session_timeout设置了1440m,也就是一天。

ssl_protocols表示https支持哪些版本的TLS协议,ssl_prefer_server_ciphers表示nginx开始决定使用哪些协议与浏览器进行通讯,他是经过ssl_ciphers中的安全套件,全部的安全套件以分号分隔,是有顺序的,排在前面的会优先被使用。

最后server中的ssl_dhparam是表示加密的时候使用怎样的参数,这些参数会决定网络安全的加密强度。

19. 基于OpenResty用Lua语言实现简单服务

openresty的站点(openresty.org)下载,在源码发布中找到最新版本,复制他的下载连接进行下载。

wget http://openresty.org/download/openresty-1.13.6.2.tar.gz
复制代码

下载完成之后解压压缩包,而后进入到源代码目录,能够发现openresty目录和nginx的源代码目录相比少了不少东西,少的这些东西都在bundle目录下,build目录是编译之后生成的一些中间目标文件。

bundle目录中有不少模块,最核心的是nginx的源代码,也就说当前的OpenResty是基于对应的nginx版本进行的二次开发。

全部nginx对应版本中没有的特性都不可能出如今OpenResty的版本中。

其余的目录又分为两类,第一类是nginx的第三方模块,都是一些C模块,一般会以ngx开头。第二类模块是LUA模块,是lua代码写就的,他须要使用刚刚那些C模块提供的各类功能,在编译的时候主要是在编译C模块。

./configure --help | more
复制代码

经过帮助文件能够看到OpenRestynginx基本没有太大的不一样,只不过OpenResty他集成了不少第三方模块,好比http_echo, http_xss等等,这些在nginx的官方版本中是没有的。这些模块不少是OpenResty的做者写的。

最核心的lua_module核心模块一般是不能移除来的,移除来以后整个lua就不能运行了。其余的配置项和官方的nginx基本上是同样的。

./configure

make install
复制代码

要将lua代码添加到OpenResty当中首先打开OpenRestyconf文件,在文件中是能够直接添加lua代码的,可是不能直接的把lua的语法放在conf中,由于nginx的解析器配置语法和lua代码是不相同的。

OpenRestynginx_lua_module中提供了几条指令,其中有一条叫作content_by_lua, 是在http请求处理的内容生成阶段用lua代码来处理。

增长一个location,当输入/lua的时候,使用lua代码进行处理, 为了使输出的文本可以以浏览器直接显示文本的方式显示,添加一个default_type text/html,在content_by_lua中加一些最简单的命令来演示lua是怎么生效的。

OpenRestylua模块中提供了一些API,好比说ngx.say会生成http响应,他是放在http请求的body中的,并非放在header中的。

能够经过ngx.say语法将内容添加到body中的文本中。这里经过ngx.req.get_headers把用户请求时的http头取出来,而后找出UA,把值返回给浏览器。

server {
    server_name yindong.com;
    listen 80;

    location /lua {
        default_type text/html;
        content_by_lua 'ngx.say("User-Agent: ", ngx.req.get_headers()["User-Agent"])';
    }

    location / {
        alias html/yindong/;
    }
}
复制代码

访问/lua就能够看到效果了。

经过OpenRestynginx_lua_http模块能够用它提供的API完成不少功能,能够用lua语言自己的一些工具库,把lua语言添加进来参与响应的过程。

能够用lua语言以及相应的提供的工具库直接访问redismysql或者tomcat等服务,而后把不一样的响应经过程序逻辑组合成相应的内容返回给用户。

相关文章
相关标签/搜索