不少人可能或多或少了解过nginx
,即便没有使用过nginx
,可是可能用Apache
搭建过简单的web
服务器,用tomcat
写过一些简单的动态页面,其实这些功能nginx均可以实现。javascript
nginx
最重要的三个使用场景我的认为是静态资源服务
、反向代理服务
和api服务
。css
web
请求走进服务之后会先通过nginx
再到应用服务,而后再去访问redis
或者mysql
提供基本的数据功能。html
这就有个问题,应用服务由于要求开发效率高,因此他的运行效率是很低的,他的qbs
,tps
并发都是受限的,因此就须要把不少的应用服务组成集群,向用户提供高可用性。java
不少服务构成集群的时候,须要nginx
具备反向代理的功能,能够把动态请求传导给对应的应用服务。服务集群必定会带来两个需求,动态的扩容和容灾。mysql
反向代理必须具有负载均衡的功能,其次在链路中,nginx
是处在企业内网的边缘节点,随着网络链路的增加,用户体验到的时延会增长。linux
把一些全部用户看起来不变的,或者在一段时间内看起来不变的动态内容缓存在nginx
部分,由nginx
直接向用户提供访问,用户的时延就会减小不少。nginx
反向代理衍生出另外的功能叫缓存,他可以加速访问,而不少时候在访问像css
或js
文件又或者一些小图片是没有必要由应用服务来访问的,他只须要直接由nginx
提供访问就能够了这就是nginx
的静态资源功能。web
应用服务它自己的性能有很大的问题,数据库服务要比应用服务好的多,缘由是数据库他的业务场景比较简单,并发性能和tps
都要远高于应用服务。由nginx
直接去访问数据库或者redis
也是不错的选择。正则表达式
还能够利用nginx
强大的并发性能,实现如web
防火墙的一些业务功能,这就要求nginx
服务有很是强大的业务处理功能,openResty
和nginx
集成了一些工具库来实现此功能。redis
全球化和物联网的快速发展,致使接入互联网中的人与设备的数量都在快速的上升,数据的快速爆炸,对硬件性能提出很高的要求。
摩尔定律代表以前服务跑在1GHZ
的CPU
上的服务更新到2GHZ
的CPU
时服务会有两倍的性能提高。
可是到了本世纪初,摩尔定律在单颗CPU
的频率上已经失效了,CPU
开始向着多核方向发展,当服务器如今是跑在8
核CPU
上时,一年半之后换到了16
核的CPU
,服务的性能一般是不会有一倍的提高的。
这些性能主要损耗在操做系统和大量的软件没有作好服务于多核架构的准备,好比说像Apache
是低效的,由于他的架构模型里一个进程同一时间,只会处理一个链接,一个请求。只有在这个请求处理完之后才会去处理下一个请求。
它实际上在使用操做系统的进程间切换的特性,由于操做系统微观上是有限的CPU
,可是操做系统被设计为同时服务于数百甚至上千的进程。
Apache
一个进程只能服务于一个链接,这种模式会致使当Apache
须要面对几十万,几百万链接的时候,他没有办法去开几百万的进程,而进程间切换的代价成本又过高啦。
当并发的链接数越多,这种无谓的进程间切换引起的性能消耗又会越大。
nginx
是专门为了这种应用场景而生的,能够处理数百万甚至上千万的并发链接,nginx
目前在web
市场份额中排行第二,在过去几年他增加极度迅速,在不久的未来nginx
在web
端的应用将远远超过其余服务器。
大部分的程序和服务器随着并发链接数的上升他的RPS
数会急剧的降低,这里的原理就像以前所说过的,他的设计架构是有问题的。
nginx
的第一个优势就是高并发和高性能同时具有的,每每高并发只须要对每个链接所使用的内存尽可能的少就能够达到。
而具备高并发的同时达到高性能,每每须要很是好的设计,那nginx
能够达到什么样的标准呢?
好比说如今主流的一些服务器32
核64G
的内存能够轻松达到数千万的并发连接,若是是处理一些简单的静态资源请求,能够达到一百万的RPS
这种级别。
其次nginx
的可扩展性很是好,主要在于他的模块化设计很是的稳定,并且nginx
的第三方模块的生态圈很是的丰富。甚至于有像TNG
,openRestry
这种第三方插件。丰富的生态圈为nginx
丰富的功能提供了保证。
第三个优势是它的高可靠性,所谓的高可靠性是指nginx
能够在服务器上持续不间断的运行数年,而不少web
服务器每每运行几周或者几个月就须要作一次重启。
对于nginx
这种高并发高性能的反向代理服务器而言,他每每运行在企业内网的边缘节点上,若是企业想提供4个9
,5个9
,甚至更高的高可用性时,对于nginx
持续运行可以down
机的时间一年可能只能以秒来计。因此在这种角色中,nginx
的高可靠性给提供了很是好的保证。
第四个优势热部署,是指能够在不中止服务的状况下升级nginx
,这对于nginx
来讲很是的重要,由于在nginx
可能跑了数百万的并发链接。
若是是普通的服务可能只需kill
掉进程再重启的方式就能够处理好,可是对于nginx
而言,由于kill
掉nginx
进程,会致使操做系统为全部的已经创建链接的客户端发送一个tcp
中的reset
报文。而不少客户端是没有办法很好的处理请求的。
在大并发场景下,一些偶然事件就会致使必然的恶性结果,因此热部署是很是有必要的。
第五个优势是BSD
许可证,BSD Listens
是指nginx
不只是开源的免费的,并且能够在有定制须要的场景下,去修改nginx
源代码,再运行在商业场景下,这是合法的。
以上的优势是nginx
最核心的特性。
首先是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
去定位根本性的问题。
nginx
每发布一个版本的时候会有三个特性,一个是feature
,就是他新增了哪些功能,bugfix
表示他修复了哪些bug
,change
表示作了哪些重构。
每个版本都有mainline
主干版本和stable
稳定版本。
在nginx
的官网点击右下角的download
,就能够看到版本号列表,单数版本表示主干版本,会新增不少功能,但不必定稳定。双数版本是稳定版本。
CHANGES
文件中能够看到每个版本含有的新增功能,修复的bug
,以及作了哪些小的重构。
大概在2009
年之后nginx
的bugfix
数量已经大幅度减小,因此nginx
相对已经很稳定了。
nginx
的开发时间是在2002
年,可是他在2004
年10
月4
日推出了第一个版本,在2005年
曾经作过一次大的重构。
由于nginx
优秀的设计,使得他的生态圈极为丰富,模块的设计,架构的设计都没有再作过大的变更。
在2009
年nginx
开始支持windows
操做系统,2011
年1.0
正式版本发布,同时nginx
的商业公司nginx Plus
也成立了,在2015
年nginx
发布了几个重要的功能。
其中提供stream
,四层反向代理
,他在功能上彻底能够替代传统使用的LVS
, 而且具备更丰富的功能。
免费开源: nginx.org
商业版本: nginx.com
开源免费的nginx
在2002
年开始开发,到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
是一个很好的选择。
安装nginx
有两种方法,除了编译外,还能够直接用操做系统上自带的一些工具,好比说yum
,apt-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
复制代码
其中会有feature
,bugfix
,change
三种特性在里面。
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
文件里则是Linux
对nginx
的帮助文件,里面标识了最基本的nginx
帮助和配置。
src
目录是nginx
的核心源码。
编译前能够先看一下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.log
和error.log
在log
文件夹下。
能够看到在conf
目录下全部文件就是在源代码中conf
目录copy过来的,其中的内容也是彻底相同的。
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
中也放置了listen
,limit_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
模块,好比说像stream
或mime
是没有办法去解析指令的。
upstream
表示上游服务,当nginx
须要与Tomcat
等企业内网的其它服务交互的时候呢,能够定义一个upstream
。
server
对应的一个或一组域名,location
是url
表达式。
须要帮助的时候能够用-?
或者 -h
获取帮助信息。
nginx -?
nginx -h
复制代码
默认状况下编译出来的nginx
会寻找执行configure
命令时指定的配置文件。在命令行中能够指定另外一个配置文件用-c 路径
。
还能指定一些配置用-g
,指令就是在nginx
的configure
目录里的指令。
nginx
操做运行中的进程通常是经过发送信号,能够经过linux
的kill
命令也能够用nginx -s
子命令,子命令后能够用stop
,quit
,reload
,reopen
。
nginx -s stop # 中止nginx服务
nginx -s quit # 优雅的中止nginx服务
nginx -s reload # 重载配置文件
nginx -s reopen # 从新开始记录日志文件。
复制代码
-t
能够测试一下配置文件是否合法问题。
-V
是在编译时用configure
脚本执行所加的全部参数。
修改nginx
配置文件中的一些值,好比说conf/nginx.conf
文件中,打开tcp_nopush
。
当修改完配置文件之后,能够直接执行nginx -s reload
命令nginx
是在不中止对客户服务的状况下使用了tcp_nopush
新的配置项,很是的简单。
nginx
在运行的状况下想更换最新版本的nginx
,根据以前所说的,nginx
编译方法下载一个新的nginx
。
把最新版本的nginx
编译后的可执行文件nginx
,copy
到目录中替换掉正在运行的nginx
文件。copy
完成须要给正在运行的nginx
的master
进程发送一个信号,告诉他开始进行热部署作一次版本升级,给nginx
的master
进程发送一个信号,USR2
信号。
kill -USR2 进程号(13195)
复制代码
nginx
会新启一个master
进程使用的正式刚刚复制过来的最新的nginx
二进制文件。
旧的worker
也在运行,新的master会生成新的worker
,他们会平滑的把全部的请求过渡到新的进程中。
新的请求新的链接会进入新的nginx
进程中,这时须要向老的nginx
进程发送一个信号叫作WINCH
,告诉他优雅的关闭全部进程。
kill -WINCH 13195
复制代码
这时老的worker
进程会优雅的退出,可是老的master
进程还在,只是是没有worker
进程了。
这说明全部的请求已经所有切换到新的nginx
中了,若是须要把新版本退回到老版本,能够向老的进程发送reload
命令,让他从新把worker
进程拉起来。再把新版本关掉。因此保留master
是为了容许作版本回退。
好比说当前的日志已经很大了。须要把之前的日志备份到另一个文件中,可是nginx
仍是正常运行的。
这就要经过reopen
命令来作,首先须要把当前正在使用的日志copy
一份放在另外的位置.
mv access_log bak.log
复制代码
接着执行命令reopen
。
nginx -s reopen
复制代码
就从新生成了一个access.log
, 本来的log
备份成了bak.log
,就实现了日志切割。
固然这种方法会很是很差用,实际上每每是每一天,或者是每一周执行一第二天至切割,能够先写成一个bash
脚本。
在bash
脚本中首先把文件复制一下,再执行-s reopen
命令,最后把脚本放在crontab
中。
编辑conf/nginx.conf
文件找到server
代码块中,listen
配置监听端8080
端口,而后须要配置一个location
,使用/
让全部的请求都访问到www
文件夹。
这里须要指定url
的后缀与文件的后缀一一对应,有两种用法,root
和alias
,root
是系统的跟目录,因此一般使用alias
,alias
是nginx
的安装目录。
server {
listen 8080;
...
location / {
alias www/;
...
}
...
}
复制代码
作完配置以后启动nginx
在浏览器中访问localhost:8080
就能够了。
nginx -s reload
复制代码
作完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
服务传输效率会高不少。
nginx
给提供了一个官方模块叫作autoindex
,他能够提供当访问以/
结尾的url
时,显示目录的结构。使用方法也特别简单,就是autoindex on
加入一个指令就能够了。
location / {
autoindex on;
}
复制代码
他会把所访问的文件夹内全部文件列出来,当打开一个目录时,能够继续显示目录中的文件,这是一个很好的静态资源帮助功能。
好比公网带宽是有限的,当有不少并发用户使用带宽时,他们会造成一个争抢关系,可让用户访问某些大文件的时候来限制他的速度,节省足够的带宽给用户访问一些必要的小文件。
就可使用set
命令,配合一些内置的变量实现这种功能,好比说加上set $limit_rate 1k
,限制nginx
向客户浏览器发送响应的一个速度。意思是每秒传输多少数据到浏览器中。
location / {
set $limit_rate 1k;
}
复制代码
首先须要设置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中查看每一条都是设置的格式。
因为上游服务要处理很是复杂的业务逻辑并且强调开发效率,因此他的性能并不怎么样,使用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
找到。
这里有个很重要的特性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;
}
复制代码
加完这些参数之后,能够尝试停掉上游服务,而后访问站点,能够发现站点仍然是能够访问的。就是由于被缓存了。
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.lo
g统计信息上的变迁,对分析网站的运营状况很是有帮助,能够看到每一个时间点,每一周每一天,甚至不一样的国家地区使用不一样浏览器和操做系统的人使用站点的一个比例和分布。
SSL
的全称是Secure Sockets Layer
,如今不少时候使用的是TLS
也就是Transport Layer Security
。能够将TLS
看作是SSL
的升级版。
SSL
是网景公司在1995
年推出的,后来由于微软把本身的IE浏览器
捆绑windows
一块儿卖出致使网景遇到很大的发展困境,网景把SSL
协议交给IETF
组织。
在1999
年,应微软的要求IETF
把SSL
改名为TLS1.0
,在06
,08
到2018
年TLS
分别发布了1.1
,1.2
和1.3
协议。
那么TLS
协议到底是怎样保证http
的明文消息被加密的呢?
在ISO/OSI
七层模型中,应用层是http
协议,在应用层之下,表示层也就是TLS
所发挥做用的这一层,经过握手
,交换密钥
,告警
,对称加密
的方式使http
层没有感知的状况下作到了数据的安全加密。
当抓包或者观察服务端配置时,能够看到安全密码的配置,安全密码的配置决定了TLS
协议是怎样保证实文被加密的。这里大概有四个组成部分。
第一个组成部分叫作密钥交换,也就是ECDHE
,这其实是一个椭圆曲线加密算法的表达,密钥交换是为了让浏览器和服务器之间怎样各自独立的生成密钥,数据传输时他们会用密钥去加密数据。加解密是须要使用到对方的密钥的因此须要进行交换。
在密钥交换过程当中,须要让浏览器和服务器各自去验证对方的身份,而验证身份是须要一个算法的,叫作RSA
。
进行数据加密,解密这种通信的时候,须要用到对称加密算法AES_128——GCM
,其中第一个部分AES
表达了是怎样一种算法,128
表示了AES
算法里支持了3
种加密强度,使用128
位这种一个加密强度。AES
中有不少分组模式GCM
是一种比较新的分组模式,能够提升多核CPU
状况下加密和解密的一个性能。
SHA_256
是摘要算法,他用来把不定长度的字符串生成固定长度的更短的摘要。
在对称加密场景中,两个想通信的人张三和李四,他们共同持有同一把密钥,张三能够把原始明文的文档,经过这一把密钥加密生成一个密文文档,而李四拿到文档之后呢,他能够用这把密钥还原转换为原始的明文文档,而中间的任何人若是没有持有这把密钥,即便他知道了对称加密的算法他也没有办法把密文还原成原始文档。
那么对称加密究竟的实现能够以RC4
对称加密的序列算法来描述。
使用异或(xor
)操做, 他是一个位操做,好比1
和0
进行异或获得1
,0
和1
也获得了1
,那么相同的1
和1
或者0
和0
进行异或操做都会获得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 # 明文
复制代码
密文能够用同一把密钥彻底还原成了明文,因此对称加密有一个最大的优势就是他的性能很是的好,他只要遍历一次就能够获得最终的密文,解密的过程也是同样,而非对称加密他的性能就会差不少。
非对称加密根据一个数学原理,他会生成一对密钥,这一对密钥中若是称其中一个叫作公开钥匙(公钥
),那么另外一个就叫作私有钥匙(私钥
)。
公钥和私钥做用就是同一份命名文档若是用公钥加密了那么只有用对应的私钥才能把它解密,一样道理,若是文档用私钥加密了用公钥才能解密。
好比说李四他有一对公钥和私钥,那么他就能够把他的公钥发布给你们,好比张三是其中的一我的,他拿到了李四的公钥,加密操做是怎么作的呢?
张三若是想传递一份原始文档给李四,那么张三就能够拿着李四的公钥对原始文档进行加密,把密文再发送给李四,李四用本身的私钥才能进行解密,其余人即便获得了这份文档也没有办法进行解密。
---------- ---------- ----------
| ------ | 李四的公钥 | ------ | 李四的私钥 | ------ |
| ------ | -----------> | -- 密 -- | -----------> | ------ |
| ------ | 加密 | ------ | 解密 | ------ |
---------- ---------- ----------
原始文档 加密文档 原始文档
复制代码
公钥和私钥还有第二种用途,就是身份验证,好比如今有一段信息李四用它的私钥进行了加密,而后把密文发给了张三,只要张三若是可使用李四的公钥解开这份文档,那么就证实这段密文确实是由李四发出的。由于只有李四有本身的加密私钥,若是是王五加密的文档张三用李四的公钥是解不开的,只有用李四私钥加密的使用李四的公钥才能解开。
这里其实还有个问题,李四怎么就知道消息真的是张三发过来的。这里面涉及到一个新的概念叫公信机构。在多方通讯的过程当中必须有一个公信机构CA,负责颁发证书和把证书过时的。
做为站点的维护者就是证书的订阅人,首先必须申请一个证书,申请证书可能须要登记是谁,属于什么组织,想作什么。
登记机构经过CSR
发给CA
,CA
中心经过后会生成一对公钥和私钥,公钥在CA
保存着,公钥私钥证书订阅人拿到以后就会把它部署到本身的web
服务器,当浏览器访问站点的时候,服务器会把公钥证书发给浏览器,浏览器须要向CA
验证证书是否合法和有效的。若是有效就证实没有被篡改。
因为CA
会把过时的证书放在CRL
服务器里,服务器会把全部过时的证书造成一条链条因此他的性能很是的差,后来又推出了OCSP
程序能够就一个证书去查询是否过时,因此浏览器是能够直接去查询OCSP
响应程序的,但OCSP
响应程序性能还不是很高。
nginx会有一个OCSP
的开关,当打开开关之后会由nginx
主动的去OCSP
去查询,大量的客户端直接从nginx
就能够获取到证书是否有效。
证书一共有3
种类型。
第一种叫作域名验证DV
证书,也就是说证书只会去验证域名的归属是否正确,申请证书的时候只要域名指向的服务器是正在申请证书的服务器,就能够成功的申请到证书。
第二种证书叫作组织验证OV
证书,组织验证就是在申请证书的时候会去验证填写的机构,企业名称是不是正确的,申请OV
证书每每须要几天的时间,不像DV
证书,基本上实时就能够获取到,OV
证书的价格远远高于DV
证书,DV
证书不少都是免费的。
比OV
证书作更严格的是EV
证书,大部分浏览器对EV
证书显示的很是友好,他会把证书申请时所填写的机构名称在浏览器的地址栏中显示出来。
浏览器在安全角度对DV
,OV
,,EV
证书他的效果是同样的。惟一验证的就是证书链。
若是你点击网站地址栏中的锁头标志,打开证书链的时候,能够发现存在三个级别,目前全部主证书都是由根证书、二级证书、主证书三个证书构成的。
之因此须要三级机构是由于根证书的验证是很是谨慎的,如windows
,安卓等操做系统每年以上才会去更新一次根证书库,因此一个新的根证书CA
机构是很难快速的加入到操做系统或者浏览器中的。
大部分浏览器他使用的是操做系统的证书库,只有像firefox
这种浏览器会维护本身的根证书库,因此浏览器在验证证书是否有效时,除了验证有没有过时之外,最主要就是在验证根证书是否是有效的,是否是被跟证书库所承认的。
nginx
在向浏览器发送证书的时候须要发送两个证书,根证书是被操做系统或者浏览器内置的并不须要发送。首先发送站点的主证书,接着会发送二级证书,浏览器会自动去认证二级证书的签发机构,根证书是否是有效的。
浏览器和服务器之间通讯时确认对方是信赖的人其实就是验证给站点颁发根证书的发行者是否是有效的。
TLS的通讯过程主要想完成四个目的。
浏览器会向服务器发送一个client hello
消息。有一浏览器很是多样化,并且版本在不停的变动。因此不一样的浏览器所支持的安全套件,加密算法都是不一样的。这一步主要是告诉服务器,浏览器支持哪些加密算法。
nginx
有本身可以支持的加密算法列表,以及他倾向于使用的哪个加密算法套件,nginx
会选择一套他最喜欢的加密套件发送给客户端。
若是想复用session
,也就是说nginx
打开了session cache
,但愿在一天内断开连接的客户端不用再次协商密钥,能够直接去复用以前的密钥。
server hello
信息中主要会发送究竟选择哪个安全套件。
nginx
会把本身的公钥证书发送给浏览器,公钥证书中包含证书链,浏览器能够找到本身的根证书库,去验证证书是不是有效。
服务器会发送server hello done
,若是以前协商的安全套件是椭圆曲线算法,这时会把椭圆曲线的参数发送给客户端。客户端须要根据椭圆曲线的公共参数,生成本身的私钥后再把公钥发送给服务器。
服务器有了本身的私钥,会把公钥发送给客户端,服务端能够根据本身的私钥和客户端的私钥,共同生成双方加密的密钥。
客户端根据服务器发来的公钥和他本身的私钥也能够生成一个密钥。
服务器和客户端各自生成的密钥是相同的,是由非对称加密算法保证的。接着能够用生成的密钥进行数据加密,进行通讯。
TLS
通讯主要在作两件事,第一个是交换密钥,第二个是加密数据,主要的性能消耗也是这两点。
nginx在这里是有性能优化的,主要是他的算法性能,对于小文件,握手是影响QPS
性能的主要指标,对于大文件而言,主要考虑对称加密算法的性能好比AES
,对称加密算法虽然性能很好,可是对很是大的一个文件,测吞吐量时仍是AES
的性能比较好的。
当以小文件为主时主要考验的是nginx
的非对称加密的性能,好比说RSA
,当主要处理大文件时主要考验的是对称加密算法的性能,好比说AES
。
面对的场景是小文件比较多时重点应该优化椭圆曲线算法的一些密码强度,看是否是有所下降,当主要面对大的文件处理的时候须要考虑AES
算法是否是能够替换为更有效的算法,或者把密码强度调得更小一些。
首先须要有一个域名好比说yindong.zhiqianduan.com
他是一个http
的网址。
接着开始安装工具,必须的工具。
若是系统是CentOS
,可使用yum
安装,优班图系统可使用wget
工具下载。
yum install pthon2-certbot-nginx
复制代码
安装好会提供certbot
命令,当后缀加上--nginx
的时候就开始为nginx
的conf
自动执行相应的修改。一般他会默认修改/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
的访问302
到https
从而禁掉不安全的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
是表示加密的时候使用怎样的参数,这些参数会决定网络安全的加密强度。
在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
复制代码
经过帮助文件能够看到OpenResty
和nginx
基本没有太大的不一样,只不过OpenResty
他集成了不少第三方模块,好比http_echo
, http_xss
等等,这些在nginx
的官方版本中是没有的。这些模块不少是OpenResty
的做者写的。
最核心的lua_module
核心模块一般是不能移除来的,移除来以后整个lua
就不能运行了。其余的配置项和官方的nginx
基本上是同样的。
./configure
make install
复制代码
要将lua
代码添加到OpenResty
当中首先打开OpenResty
的conf
文件,在文件中是能够直接添加lua
代码的,可是不能直接的把lua
的语法放在conf
中,由于nginx
的解析器配置语法和lua
代码是不相同的。
在OpenResty
的nginx_lua_module
中提供了几条指令,其中有一条叫作content_by_lua
, 是在http
请求处理的内容生成阶段用lua
代码来处理。
增长一个location
,当输入/lua
的时候,使用lua
代码进行处理, 为了使输出的文本可以以浏览器直接显示文本的方式显示,添加一个default_type text/html
,在content_by_lua
中加一些最简单的命令来演示lua是怎么生效的。
在OpenResty
的lua
模块中提供了一些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
就能够看到效果了。
经过OpenResty
的nginx_lua_http
模块能够用它提供的API
完成不少功能,能够用lua
语言自己的一些工具库,把lua
语言添加进来参与响应的过程。
能够用lua
语言以及相应的提供的工具库直接访问redis
,mysql
或者tomcat
等服务,而后把不一样的响应经过程序逻辑组合成相应的内容返回给用户。