csdn的图片显示有问题,为了更好的阅读体验,请移步nginx-blog
![image.png](https://img-blog.csdnimg.cn/img_convert/5a930a077c0e7f4a8d17fe69e4350e9c.png#clientId=u4080493f-2439-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=586&id=LL1zE&margin=[object Object]&name=image.png&originHeight=1172&originWidth=2112&originalType=binary&ratio=1&rotation=0&showTitle=false&size=928999&status=done&style=none&taskId=uddb9f030-3d60-4932-8c4c-cced0a440f1&title=&width=1056)
![A82E994B-DDE1-4C48-A3B1-4CC72150E101.png](https://img-blog.csdnimg.cn/img_convert/8fcb61262648556243573ef2cebdcfcc.png#clientId=u4080493f-2439-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=511&id=u59c349bd&margin=[object Object]&name=A82E994B-DDE1-4C48-A3B1-4CC72150E101.png&originHeight=1022&originWidth=1938&originalType=binary&ratio=1&rotation=0&showTitle=false&size=973178&status=done&style=none&taskId=udfc4d868-cc8d-4074-9e67-588b458f05f&title=&width=969)
![image.png](https://img-blog.csdnimg.cn/img_convert/988d8f4f89b21b29a6f917d1ec6385b2.png#clientId=u4080493f-2439-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=413&id=u4baf27df&margin=[object Object]&name=image.png&originHeight=826&originWidth=1516&originalType=binary&ratio=1&rotation=0&showTitle=false&size=690551&status=done&style=none&taskId=u093b0ccd-1ef0-476e-8b8f-a703c56616d&title=&width=758)
![image.png](https://img-blog.csdnimg.cn/img_convert/9ecab8688370426e90478d09afdef67e.png#clientId=u4080493f-2439-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=415&id=u546695db&margin=[object Object]&name=image.png&originHeight=830&originWidth=1480&originalType=binary&ratio=1&rotation=0&showTitle=false&size=815741&status=done&style=none&taskId=u2c247769-0483-4af3-a4c5-377f3d3f97e&title=&width=740)
![image.png](https://img-blog.csdnimg.cn/img_convert/09e3250a79debfec4cd89096ae285712.png#clientId=u4080493f-2439-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=432&id=ufa43ac01&margin=[object Object]&name=image.png&originHeight=864&originWidth=1456&originalType=binary&ratio=1&rotation=0&showTitle=false&size=646525&status=done&style=none&taskId=ua093ced4-fbab-4ecb-b65f-e2afac5a6ab&title=&width=728)
web日志分析工具:goaccess
![image.png](https://img-blog.csdnimg.cn/img_convert/765e71d44e2b05963f0da598491c8bec.png#clientId=u4080493f-2439-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=433&id=u167fc52b&margin=[object Object]&name=image.png&originHeight=866&originWidth=1512&originalType=binary&ratio=1&rotation=0&showTitle=false&size=771135&status=done&style=none&taskId=ueb77d876-4757-4a44-929f-609bbe79b3b&title=&width=756)
![image.png](https://img-blog.csdnimg.cn/img_convert/9194fd240c0abcc046ff29bc20fba349.png#clientId=u4080493f-2439-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=428&id=uc42cac93&margin=[object Object]&name=image.png&originHeight=856&originWidth=1486&originalType=binary&ratio=1&rotation=0&showTitle=false&size=651764&status=done&style=none&taskId=u66318642-6518-4f37-881c-daa3d2ee47b&title=&width=743)
![image.png](https://img-blog.csdnimg.cn/img_convert/7c1b704a6ed8c85e613c15786dacc07a.png#clientId=u4080493f-2439-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=418&id=u555e3556&margin=[object Object]&name=image.png&originHeight=836&originWidth=1326&originalType=binary&ratio=1&rotation=0&showTitle=false&size=194153&status=done&style=none&taskId=u171d1452-7cc7-4148-819a-3072fd184a3&title=&width=663)
基于异或算法,明文可以转为密文,密文也可以转为明文,而且性能好,只需要一次便历过程。
![image.png](https://img-blog.csdnimg.cn/img_convert/fd3fbb5fbb960452435c45b3cc29224d.png#clientId=u4080493f-2439-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=355&id=u8daa4a38&margin=[object Object]&name=image.png&originHeight=710&originWidth=1590&originalType=binary&ratio=1&rotation=0&showTitle=false&size=341051&status=done&style=none&taskId=u9747b1f9-8adb-4fff-904d-31432c7860a&title=&width=795)
自己发出去的文本用私钥加密,接收方使用公钥加密;反之,接收方回复消息使用公钥加密,自己使用私钥解密。
![image.png](https://img-blog.csdnimg.cn/img_convert/39d03fffcf3a084561b1c6156a12bcb1.png#clientId=u4080493f-2439-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=450&id=u88a77c62&margin=[object Object]&name=image.png&originHeight=900&originWidth=1534&originalType=binary&ratio=1&rotation=0&showTitle=false&size=529082&status=done&style=none&taskId=ue0ecf4c4-4058-4ead-8437-50c04108c19&title=&width=767)
在Nginx上可以设置为:
ssl_verify_client on;#以便 OCSP 验证工作
ssl_ocsp on;#启用客户端证书链的 OCSP 验证
resolver 192.0.2.1;#解析器应指定为解析 OCSP 响应器主机名
![image.png](https://img-blog.csdnimg.cn/img_convert/69e078c9d8fdb1af94f76bdd54a26491.png#clientId=u4080493f-2439-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=424&id=u08d2c9e7&margin=[object Object]&name=image.png&originHeight=848&originWidth=1510&originalType=binary&ratio=1&rotation=0&showTitle=false&size=644753&status=done&style=none&taskId=u3637df4c-3da2-4c23-8cc1-93edeb8830b&title=&width=755)
浏览器获取到证书后如何生效,需要验证证书链:
![image.png](https://img-blog.csdnimg.cn/img_convert/2c002bc589a99d0a9f8e65007aa060de.png#clientId=u4080493f-2439-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=403&id=u7bd89cd0&margin=[object Object]&name=image.png&originHeight=806&originWidth=1596&originalType=binary&ratio=1&rotation=0&showTitle=false&size=706121&status=done&style=none&taskId=u25b277c3-4a01-4f3a-aa71-ab14d0bed78&title=&width=798)
说明:
站点证书由三部分构成(根证书、二级证书、主证书),操作系统的根证书很难修改,大部分浏览器(除firebox)使用的是操作系统的证书库。所以浏览器在验证证书是否有效时,除了验证nginx发过来的两个证书(二级证书和主站点证书)是否过期外,还要要在根证书是否有效且被认证。
![image.png](https://img-blog.csdnimg.cn/img_convert/f339ad9338f8dc16768cc927f20e99cd.png#clientId=u4080493f-2439-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=445&id=ufb99ad14&margin=[object Object]&name=image.png&originHeight=890&originWidth=1614&originalType=binary&ratio=1&rotation=0&showTitle=false&size=717638&status=done&style=none&taskId=u72971e82-41b9-420d-b364-d9cf4dc558a&title=&width=807)
第一步:浏览器向服务器发送clinet hello消息,告诉服务器我支持哪些加密算法;
第二步:服务器把最偏向的加密算法发送给客户端,发送server hello消息,告诉服务器最终选择哪个安全套件;
第三步:服务器向客户端发送证书链;
第四步:客户端验证服务器相关证书;
第五步:服务器发送server hello done,且在第五步前向客户的发送加密算法的公共参数;
第六步:浏览器根据公共参数生成自己的私钥,再把公钥发送给服务器;
第七步:服务器生成自己的一对公钥和私钥,用自己的私钥和客户端发来的私钥,生成双方加密的密钥。
第八步:浏览器根据服务器发来的公钥和自己生成的私钥也会生成双方加密的密钥,通过非对称加密,二者生成的密钥是相同的。
第九步:服务器使用生成的密钥加密发送的消息,传给浏览器。
Nginx对加密算法的优化:
对于小文件,Nginx需要优化非对称加密算法,适当弱化密码强度;
对于大文件,需要考虑优化对称加密算法(AES)。
[root]:yum install python2-certbot-nginx
[root]:certbot --nginx --nginx-server-root=conf目录 -d 需要安装证书的server name
openresty.org–>下载–>源码发布–下载–>解压
![image.png](https://img-blog.csdnimg.cn/img_convert/8e64c04ec1fa6875e0165ab5bc5a2f3d.png#clientId=u4080493f-2439-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=216&id=u1ff86b65&margin=[object Object]&name=image.png&originHeight=432&originWidth=1130&originalType=binary&ratio=1&rotation=0&showTitle=false&size=497671&status=done&style=none&taskId=u7369271d-1f04-43a0-9dcf-43f18a49c33&title=&width=565)
编译一个基本的openresty .configure
make&make install
![image.png](https://img-blog.csdnimg.cn/img_convert/8ff7fd74b248eb71038c46e939aab14f.png#clientId=u4080493f-2439-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=295&id=u2936c073&margin=[object Object]&name=image.png&originHeight=590&originWidth=1524&originalType=binary&ratio=1&rotation=0&showTitle=false&size=230878&status=done&style=none&taskId=uba1fba36-a7c0-4dda-9ee6-9a7020d9543&title=&width=762)
![image.png](https://img-blog.csdnimg.cn/img_convert/92991b0bb602363177d3d0211bc1591f.png#clientId=u4080493f-2439-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=438&id=ud746df97&margin=[object Object]&name=image.png&originHeight=876&originWidth=1600&originalType=binary&ratio=1&rotation=0&showTitle=false&size=816530&status=done&style=none&taskId=ua40d20a8-ec6a-4ac8-b50b-dac5dec87ec&title=&width=800)
![image.png](https://img-blog.csdnimg.cn/img_convert/132a2632c10ec0bc69bcf6e24f431b67.png#clientId=u4080493f-2439-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=427&id=u487ab640&margin=[object Object]&name=image.png&originHeight=854&originWidth=1412&originalType=binary&ratio=1&rotation=0&showTitle=false&size=560212&status=done&style=none&taskId=u3bf290f2-ccfd-458a-94da-318e85a25e4&title=&width=706)
Nginx包含master进程和子进程,子进程又分为两大类,Cache相关进程和worker进程,子进程间的通信是通过共享内存来解决的。
master进程:用来管理worker进程,负责监控worker进程正常工作,是否需要重新加载配置文件等。
缓存:是多个worker进程共享的,同时也会被cache manager(缓存的关联)和cache loader(缓存的载入)进程使用。cache manager和cache loader进程使用是用于后端发来的动态请求做缓存的来使用的。
为了保证Nginx的高可用性,nginx被设计为多进程的模式,因为多线程不同线程会共享一块内存空间,线程间相互影响,如果一个第三方模块导致地址越界等问题会使得整个Nginx全部挂掉。
![image.png](https://img-blog.csdnimg.cn/img_convert/76a9a9f2f5fadfbd23b014247897b9cf.png#clientId=u4080493f-2439-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=420&id=u1019b4de&margin=[object Object]&name=image.png&originHeight=840&originWidth=1520&originalType=binary&ratio=1&rotation=0&showTitle=false&size=556853&status=done&style=none&taskId=u1a9a6968-3180-4cb3-9b6f-c758e22b7be&title=&width=760)
![image.png](https://img-blog.csdnimg.cn/img_convert/13350fb3a5e7a3daa389954c93f8d6d7.png#clientId=u4080493f-2439-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=480&id=ua44596f6&margin=[object Object]&name=image.png&originHeight=960&originWidth=1794&originalType=binary&ratio=1&rotation=0&showTitle=false&size=965935&status=done&style=none&taskId=u8e0ac1bc-328a-46e5-b34d-a6332fcd8a0&title=&width=897)
![image.png](https://img-blog.csdnimg.cn/img_convert/bfa2d518a1a0c01c52530a5a8cec6b41.png#clientId=u4080493f-2439-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=393&id=u5e6dc846&margin=[object Object]&name=image.png&originHeight=786&originWidth=1450&originalType=binary&ratio=1&rotation=0&showTitle=false&size=703236&status=done&style=none&taskId=u2436f5c7-22ff-44a9-b7c7-dff30a2e78d&title=&width=725)
![image.png](https://img-blog.csdnimg.cn/img_convert/43b1b71f4c35dc3d73724868c7e7b5ec.png#clientId=u4080493f-2439-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=399&id=u06a3e15a&margin=[object Object]&name=image.png&originHeight=798&originWidth=1512&originalType=binary&ratio=1&rotation=0&showTitle=false&size=442930&status=done&style=none&taskId=u6576c8e6-74a3-4490-b5e9-24029966232&title=&width=756)
优化的关闭只针对Http请求,对于websocket,TCP,UDP,Nginx无法得知worker是否在处理请求。
![image.png](https://img-blog.csdnimg.cn/img_convert/066e2fb4943863f6fa2bf51a410b9b7c.png#clientId=u4080493f-2439-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=396&id=u267339ed&margin=[object Object]&name=image.png&originHeight=792&originWidth=1426&originalType=binary&ratio=1&rotation=0&showTitle=false&size=504452&status=done&style=none&taskId=ubc2ac892-79a0-4e7d-ba7b-80c350f4624&title=&width=713)
Nginx是一个事件驱动的框架,事件是指网络事件,一个网络连接对应两个事件(读事件和写事件)
![image.png](https://img-blog.csdnimg.cn/img_convert/9280954645b4f9265cbc81fbcac07fcb.png#clientId=u4080493f-2439-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=674&id=u0565fcd0&margin=[object Object]&name=image.png&originHeight=1348&originWidth=2472&originalType=binary&ratio=1&rotation=0&showTitle=false&size=1078525&status=done&style=none&taskId=u633d97ba-b09e-4edb-94b3-01ebc78ba71&title=&width=1236)
![image.png](https://img-blog.csdnimg.cn/img_convert/d29b4aafc136d5d2757bb3ba373b6e59.png#clientId=u4080493f-2439-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=672&id=u5ede5806&margin=[object Object]&name=image.png&originHeight=1344&originWidth=2434&originalType=binary&ratio=1&rotation=0&showTitle=false&size=971254&status=done&style=none&taskId=u834386c2-d0e9-410e-85a1-edc29a53265&title=&width=1217)
![image.png](https://img-blog.csdnimg.cn/img_convert/08c76618ae8f5ccfd5ec683262cfd5dd.png#clientId=u4080493f-2439-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=657&id=ue85904c3&margin=[object Object]&name=image.png&originHeight=1314&originWidth=2394&originalType=binary&ratio=1&rotation=0&showTitle=false&size=1049871&status=done&style=none&taskId=uaea3a798-39f8-4825-9bcb-400c221f76b&title=&width=1197)
![image.png](https://img-blog.csdnimg.cn/img_convert/1d96a2afb5dd2a97bdcc69b15f9b7d94.png#clientId=u4080493f-2439-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=659&id=u1e9fce32&margin=[object Object]&name=image.png&originHeight=1318&originWidth=2266&originalType=binary&ratio=1&rotation=0&showTitle=false&size=570999&status=done&style=none&taskId=u6cc79520-a8d8-41a7-9be6-5c635283aa3&title=&width=1133)
上图nginx等待服务器内核的事件队列使用epool来处理的。
![image.png](https://img-blog.csdnimg.cn/img_convert/9474b53f85db98bf69f54525559ffae8.png#clientId=u4080493f-2439-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=677&id=uf37f6e9b&margin=[object Object]&name=image.png&originHeight=1354&originWidth=2398&originalType=binary&ratio=1&rotation=0&showTitle=false&size=1073766&status=done&style=none&taskId=udcf0d437-d241-47e1-b3bc-2995e6b7fb1&title=&width=1199)
![image.png](https://img-blog.csdnimg.cn/img_convert/0de6f4b958800851f83c494f6ac2ad96.png#clientId=u4080493f-2439-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=673&id=u30e09ba8&margin=[object Object]&name=image.png&originHeight=1346&originWidth=2418&originalType=binary&ratio=1&rotation=0&showTitle=false&size=1149441&status=done&style=none&taskId=u6a575f63-c9a8-4d8e-87d2-dc1be5c0ebc&title=&width=1209)
nginx是用户态直接切换的,除非操作系统分给worker的时间分片到期了,否则一直工作,所以将worker的优先级调为-19,可以使得操作系统给worker分配更多的时间分片,提高Nginx性能。
阻塞和非阻塞是线程在访问某个资源时,数据是否准备就绪的一种处理方式。
阻塞方法:操作系统或者底层C库提供的方法或者是一个系统调用,这个方法可能是我的进程进入sleep状态(当前条件不满足,操作系统把我的进程切换到另外一个进程)。
非阻塞方法:我们调用该方法永远不会在我们时间分片未用完时,切换到另外一个进程。
同步和异步是用户态的调用方式而言。
同步:调用方法时,需要等待返回结果。
异步:调用方法后,无需等待返回结果,被调用方法处理完成后后主动通知给调用方。(支付回调)
![image.png](https://img-blog.csdnimg.cn/img_convert/5ce9869660cf411fea86265e2e5259a0.png#clientId=u4080493f-2439-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=635&id=mmbW1&margin=[object Object]&name=image.png&originHeight=1270&originWidth=2308&originalType=binary&ratio=1&rotation=0&showTitle=false&size=756496&status=done&style=none&taskId=ufef84591-1516-49f2-bdb2-77410e81f32&title=&width=1154)
![image.png](https://img-blog.csdnimg.cn/img_convert/c4ac4d3b176088f38c291a011f86417c.png#clientId=u4080493f-2439-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=668&id=ue53dda1d&margin=[object Object]&name=image.png&originHeight=1336&originWidth=2320&originalType=binary&ratio=1&rotation=0&showTitle=false&size=1003491&status=done&style=none&taskId=uc340540a-9101-4d2d-b070-8579213e891&title=&width=1160)
![image.png](https://img-blog.csdnimg.cn/img_convert/9b0d811d24cdf1061d68c45fd0cdd533.png#clientId=u4080493f-2439-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=670&id=u34e4073a&margin=[object Object]&name=image.png&originHeight=1340&originWidth=2498&originalType=binary&ratio=1&rotation=0&showTitle=false&size=1394172&status=done&style=none&taskId=u5d50ab4e-b982-4007-8151-ab0a6cb8a63&title=&width=1249)
openResty使得我们可以通过写同步的的方法,实际上以异步的来执行。
![image.png](https://img-blog.csdnimg.cn/img_convert/e28a283a8cdeee392c2e3164fe55f244.png#clientId=u4080493f-2439-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=682&id=u8e0d1bec&margin=[object Object]&name=image.png&originHeight=1364&originWidth=2400&originalType=binary&ratio=1&rotation=0&showTitle=false&size=951445&status=done&style=none&taskId=u1e94db26-886a-48c5-9d00-3bb89d8d66e&title=&width=1200)
![image.png](https://img-blog.csdnimg.cn/img_convert/da7ede8968243725eef8515bce8704eb.png#clientId=ue2063783-0659-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=504&id=uceec0e31&margin=[object Object]&name=image.png&originHeight=1008&originWidth=2000&originalType=binary&ratio=1&rotation=0&showTitle=false&size=765616&status=done&style=none&taskId=u78964cdd-88b3-461b-bb13-9d9927ab610&title=&width=1000)
说明:
每一个连接对应2个事件(读事件和写事件),如上图是通过数组序号来配合使用的。消耗的内存如下:
一个connection(232)+2个event(96*2) = 424字节。设置的连接数越多,消耗的内存就越大。
内存池配置512字节,并不意味着只能分配512字节,当内存超过预分配内存大小时,是可以继续分配的。提前分配内存空间,减小分配的资源消耗。
请求池大小,默认4K。
因为连接需要存储的上下文信息很少,只需要帮助后面的请求读取最初一部分字节就行;对于请求而言,需要保存大量上下文信息,比如:url和header。其对性能的影响比较小,极端场景下,url特别长,可以修改配置,增大请求内存池预分配的空间大小;通常情况下,url和header都很小,可以考虑降低请求内存池的预分配空间大小,最大化Nginx的并发量。
内存池对减小内存碎片和第三方模块开发是很有意义的。
在如上代码中,同时使用了rbtree和链表:
lua_shared_dict dogs 10m;//使用红黑树来保存每一个key-value,每一个节点是它的key,节点值就是value。
//当内存大于10m时,使用lru方式淘汰,最先设置了key-value就会被淘汰,这就说明每个key-value连在了一起形成了一张链表。
如何把一整块内存切割成小块分配给每个红黑树节点使用的?Slab内存管理
Slab会把共享内存切割很多页面(4K),每个页面被切分为不同的slot(不同的slot分配内存空间不同128|256|512,乘2方式向上增长)。
Bestfit:比如30字节的内存,会被分配到32字节的slot。
编译安装(在编译安装OpenResty时,使用add-module把tengine的slab_stat模块安装进来):
案例:
nginx的数据容器包括:数组、链表、队列、哈希表、红黑树、基数树
多块连续内存,每块连续内存中可以存放许多元素。
nginx_list_T
nginx_queue_T
nginx_hash_elt_T
哈希表每个元素占用连续的内存。value是指针,指向用户数据,len长度,name就是hash的key。
Hash表应用于静态不变的内容。
Max size:控制了最大的hash表Bucket的个数,并不是实际最大hash表bucket的个数。
Bucket size:每个bucket的大小,向上对齐(cache line)。比如64位操作系统,操作系统每次读取64个字节,但bucket size配置60,这个时候实际是Nginx会设置为64,与操作系统对齐。,bucket size配置尽量不要超过64字节,以免占用内存过高。
红黑树本身是一个二叉树,包含左节点和右节点。其次是一个查找二叉树,左节点比右节点小。可能会退化成一个链表,如右图。
(1)查看哪些模块支持动态模块:./configure —help | more
(2)把一个模块动态编译到nginx
(3)打开动态模块配置
load_module module/nginx_http_image_filter_module.so
image_filter resize 15 10;
该条配置指令能处于的配置块。
上图表明:log_format能在http模块上配置;access_log能在http,server…等模块配置。
一个配置存在多个配置块是是可以合并的。值指令可以合并;动作类指令不可以合并。判断依据:看该条配置的生效阶段。
值指令向上覆盖:
http模块指令合并规则:
例如:
server{
server_name [aa.com](http://aa.com) [bb.com](http://bb.com); #其中aa.com是主域名
server_name_in_redirect off;
redirect 302 /redirect;
}
如上配置:如果访问bb.com,会直接跳转到bb.com/redirect
如果配置:
server{
server_name [aa.com](http://aa.com) [bb.com](http://bb.com); #其中aa.com是主域名
server_name_in_redirect on;
redirect 302 /redirect;
}
如上配置:如果访问bb.com,会302到aa.com/redirect
(1)每一个阶段会有多个模块得到执行。
(2)limit_req和limit_conn都在preaccess阶段得到执行,但是如果limit_req阻止了本次请求,就会直接返回,limit_conn就得不到执行。
(3)access阶段的access执行通过后,后续auth_basic和auth_request两个阶段不会执行,直接跳到precontent阶段,同理content阶段也是如此。
(1)realip模块
把realip模块编译进Nginx模块?
三个指令:
set_real_ip_from:设置可信赖的ip(如本机IP或者机器某台机器IP),找到用户真实ip
real_ip_header:ip值从哪个参数中取(X-Real_Ip |X-Forwarded-For)
real_ip_recursive:环回地址,取 X-Forwarded-For最后一个地址如果和客户端地址一样就pass掉,取上一个地址。
(2)如何拿到真实的用户IP地址?
说明:当网络请求过程中,存在很多反向代理服务器时,Nginx会把用户真实的ip写在X-Real_IP中,而每经过一层反向代理,会吧上一层IP追加在X-Forwarded-For中。
(1)rewrite模块return指令
error_page:收到某个特定的返回码时,重定向某个url或者给用户返回特定内容。
return示例:
server与location块下的return指令关系?
server块的return先于location块的return执行。
return与error_page指令的关系?
访问不存在的资源,执行error_page指令;如果执行了return指令,error_page得不到执行。
(2) rewrite指令
案例:
问题1:rewrite指令优先级高于return
问题2:依次返回“test3”、“test3”、”third!”
问题3:不携带break,就往下执行到return 200 ‘second’模块
问题:依次返回301、302、302、301
rewrite日志记录:rewrite_log:on就可以开启了
(1)location指令
匹配规则:
匹配结果:
/Test1:5,6;
/Test1/:1,3,5;
/Test1/Test2:2,4,5
/Test1/Test2/:4,5
/test1/Test2:2
匹配顺序
同上问题,返回什么?
/Test1:exact match!
/Test1/:stop regular expressions match!
/Test1/Test2:lonest regular expressions match!
/Test1/Test2/:lonest regular expressions match!
/test1/Test2:lonest regular expressions match!
(1)limit_conn指令
$binary_remote_addr 关键字,这里是限制同一客户端ip地址;
限制连接数:
要限制连接,必须先有一个容器对连接进行计数,在http段加入如下代码:
“zone=” 给它一个名字,可以随便叫,这个名字要跟下面的 limit_conn 一致
$binary_remote_addr = 用二进制来储存客户端的地址,1m 可以储存 32000 个并发会话
上图配置说明:现在某个ip的并发数为1,超过1就返回500,记warn级别日志,网站返回速率为50字节/s
(1)limit_req指令
limit_req_zone:$binary_remote_addr zone=one:10m rate=2r/m;
location / {
limit_req zone=one burst=3 nodely;
}
第一段配置参数:
第二段配置参数:
说明:limit_conn模块优先级大于limit_req。
示例:
satisfy all:access的3和指令均放行这个请求,这个请求才向下执行,任何一个拒绝,400或500返回。
anny:access的3和指令有一个指令放行这个请求,这个请求就向下执行。
/root :404
/root/1.txt :—>html/first/root/1.txt 也是404
/alias:—>html/index.html 200
/alias/1.txt:—>html/first/1.txt 200
(2)3个nginx变量
(3)static模块对url不以斜杠结尾却访问目录的的做法
示例:
结果:403,valid,valid,valid,403,valid,403,valid
3.12 keepalive
一个服务的扩展方向:
A:水平扩展,加机器;
B:纵向扩展:把业务复杂的服务,拆分为业务小的服务,上层nginx通过location把请求分发到不同的服务中去;
C:Z轴扩展:基于用户的信息进行扩展。例如根据请求ip或者其他信息,把请求分发到特定的服务中去;
时间缓存:Nginx从下游服务拿到信息后,一边发给客户端,一边把返回内容缓存在nginx中;
空间缓存:上游服务请求nginx,nginx可以预请求下游服务,把数据缓存到nginx中;
keepalive:nginx和下游服务最多保持多少个空闲的http连接
keepalive_request:一个tcp最多跑多少个请求
keepalive_timeout:一个tcp连接空闲多少秒后关闭
官方解释下就是:反向代理的场景,upstream后端用域名时,配置resolver以便于nginx能够解析该域名。
当proxy_pass 后面接变量时,而且设置了resolver,会把变量的负载值通过resolver来解析,其他情况通过本地dns服务,etc或host 来解释域名。
https://www.jianshu.com/p/5caa48664da5
upstream iphashtest {
ip_hash;
hash user_$arg_username;#使用username作为hash算法的关键字
server 127.0.0.1:8011;
server 127.0.0.1:8012;
}
使用hash算法,下游服务器异常会导致大量请求的路由策略失效。一致性hash算法能有效解决该问题。
把0-232围成一个环,4个服务均有的分布在环上,0-230请求第一个服务,以此类推;
扩容后:
扩容后只会改变node2—node4前半段的hash点。
如上所有算法均可以使用upstream_zone来使得所有worker生效。
http://proxyups/addurl会被换为:http://proxyups/a
client_body_buffer_size:Nginx分配给请求数据的Buffer大小,如果请求的数据小于client_body_buffer_size直接将数据先在内存中存储。如果请求的值大于client_body_buffer_size小于client_max_body_size,就会将数据先放到client_body_buffer_size的内存中,再一遍一遍地写到临时文件中。
client_body_in_single_buffer:客户端请求数据的body一律存储到内存buffer中。当然,如果HTTP包体的大小超过了下面client_body_buffer_size设置的值,包体还是会写入到磁盘文件中。
client_max_body_size 默认 1M,表示 客户端请求服务器最大允许大小,在“Content-Length”请求头中指定。如果请求的正文数据大于client_max_body_size,HTTP协议会报错 413 Request Entity Too Large。就是说如果请求的正文大于client_max_body_size,一定是失败的。如果需要上传大文件,一定要修改该值。
2次读取body时间超过60s后,返回408.
关闭无用的连接,减少资源浪费。
使用操作系统设置的默认keepalive相关配置来控制tcp的keepalive来降低资源使用。
proxy_bind隶属于proxy_module,为向后端建立连接时的local ip,在nginx源码中只支持bind一个ip进行回源,若想使用多个ip进行回源时,可以修改源码支持bind ip数组。在实际应用中我就是这样做的。bind ip数据轮询选择ip进行回源与upstream建立连接,以解决单ip回源连接数限制问题。
proxy_bind:它的用法主要有两类用途,第一类用途就是当我们nginx上有多个ip地址时,可能有多个路由的策略是不同的,比如内网或者外网等,这个时候不要使用系统默认给我们选择的ip地址,而是主动使用一个ip地址。这个时候用proxy_bind。第二种场景,很可能为了传递一个ip地址,就是透传ip地址的策略,比如在stream反向代理中会很常用,在之后还会详述。这里先说下proxy_bind用法。
proxy_bind $remote_addr 也就是客户端的地址绑定到这里。绑定变量的时候呢,如果地址不是本地的地址,linux必须要加transparent。非linux操作系统呢需要保证worker进程有root 权限的,才能人为的修改socket的local address。
proxy_buffer_size:限定了接收自上游的http response中header的最大值。所以当上游的server发送了http响应,如果有set cookie这种特别长的header可能就会导致整个全部的response header超出了这个值。超出完之后这个请求就不能够被nginx正确的处理了。我们的error.log中会看到upstream sent too big header
就是这样的一个原因。
proxy_buffering:来控制我们是不是先接收完整的包体,接收完了才开始转发。或者说不接收完,而是每接收一部分就同步的向客户端发送我收到的那部分响应。这两种方式各有各的好处。通常情况下默认开启(on)。因为我们认为上游服务和我们nginx走的是内网,网速更快。如果我们边发边接收上游边往客户端发。因为客户端跟nginx之间的网速可能很慢。所以就会导致,对于比较大的body 的时候,nginx长时间与上游建立连接。而上游比如说tomcat、Django等它们的并发能力是很弱的。当然如果我们用了proxy_buffering off 它的优点是能让客户端及时接收到响应,特别是一些大包体的情况下。客户端不用再等待。
在我们接收上游发来的HTTP包体,即使我们开启了proxy_buffering on也并不一定向磁盘中写入包体,因为如果包体非常的小,在内存中就可以放入的话,就没有必要写到磁盘中,因为磁盘io总是比较慢的。所以这个时候就有了proxy_buffers指令。也就是包体大小没有超过这个设定值就不用写入磁盘。否则的话就要写入磁盘了。
proxy_buffering ,默认开启,希望尽快释放上游服务器的连接,当然proxy_buffering 还有一个nginx特定的header。这个header(X-Accel-Buffering头部)只有nginx才会认。当上游的tomcat 如果在response中加入X-Accel-Buffering头部,如果配置为yes,就会强制要求nginx先接收完上游的http body 再向client发送。也就是它会替换指定的内容。
当我们向磁盘中写入包体的时候还有三个指令,proxy_max_temp_file_size、proxy_temp_file_write_size、proxy_temp_path。
proxy_max_temp_file_size:限制写入磁盘中这个文件的最大值。如果上游服务中返回了非常大的文件超出了临时文件大小也会出错的。默认是1G。
proxy_temp_file_write_size:每一次向磁盘文件中写入的字节数。
proxy_temp_path:设定了存放临时文件的目录在哪里,以及目录level层级。
proxy_busy_buffers_size。虽然被缓存所有的响应,我们希望更及时的向客户端发送部分响应。比如我们收到1G文件。当我们接收到前8k或前16k(proxy_busy_buffers_size 8k|16k)的时候,就先向客户端转发接收到的这一部分响应的话就可以使用proxy_busy_buffers_size 。
proxy_read_timeout:两次读取操作之间最多60秒的超时。两次读取是一个TCP层的一个概念。
proxy_limit_reate:限速,和客户端limit_rate 有些类似,但是它限制的是读取上游的响应,而不是发送给上游服务的网速。设置为0表示不限制读取上游响应的速度。
proxy_store:把临时文件改名到root对应的目录下,默认不开启,如果是string
,可再次指定,使用变量的方式,指定这个文件存放的位置。
我们接收到了上游发来的http header跟http body,其实对上游发来的http header是有很多控制nginx行为的这样一些头部的。我们在反向代理这一层也可以去修改上游发来的header中的内容,以及它们所产生的效用。接下来看看这两种行为是怎么发生的。
第三部分讲的http 过滤模块。当我们生成的响应向客户端发送的时候。这个内容必须经历过滤模块的处理。对于nginx作为反向代理的时候也是同样的。nginx下游服务返回的一些header会被那些过滤模块处理(图中)。
比如ngx_http_modified_filter_module,它根据上游服务返回的cache control等等这些header,去修改到底是发送200还是304响应码给客户端。所以上游一些header的内容会改变作为反向代理的nginx的行为。
proxy_ignore_header可以禁止某些响应头改变nginx行为。
nginx提供了一个指令proxy_ignore_header,禁用上游中一些header 的功能。当然不是所有的header 都具有功能,这个指令只针对于具有特殊功能的header才发生作用。
说明:
(1)X-Pad:是apache 使用的header,目前已经很少用了。
(2)X-Aceel-:只有nginx才认。
(3)如果上述这四类header你想发送给客户端,就使用proxy_pass_header。
修改下游服务器response header中的头部set-cookie中的内容。proxy_cookie_domain修改下游服务器返回的cookie中的域名;
proxy_dedirect:对于我们上游服务发送的响应中有一个location,location后面的url可以做一次替换。
(1)反向代理服务配置:
(2)下游服务配置:
直接访问localhost:8012如下所示有个aaa的header:
访问反向代理服务时也有个aaa的header:
(3)禁用反向代理服务的aaa:
proxy_hide_header aaa;
再次访问反向代理服务,发现没有了aaa的header。
(4)打开proxy_pass_header,可以把下游服务的nginx版本返回给客户端:
proxy_pass_header server
再次访问反向代理服务,发现server是nginx 1.15.6而非反向代理的openresty。
总结:以上几节课包括从proxy_pass指令来指定由反向代理来指定请求到生成向上游发送请求的内容,以及接收客户端发来的http body并与上游服务建立连接并上游服务的响应内容以及处理响应头部,以上几个环节,就是nginx作为反向代理处理客户端与上游服务之间的所有流程。
我们讨论了nginx作为反向代理时,从客户端接收http body,到完整的接收下游的响应并转发响应的流程。其中在nginx与下游服务建立连接时。提到过proxy_next_upstream指令,这个指令可以在第一台的错误的响应后重新选择另一台下游服务器处理请求返回给客户端这样的功能。
能够生效的前提是没有向客户端发送一个字节。只要向客户端已经发送了一个字节了,说明下游的服务已经生效了,就不能选用一个新的下游服务了。它一定是在接收到并开始转发一个字节之前nginx判定为错误,这个功能才能生效。proxy_next_upstream后面可以跟很多不同的参数(error、timeout那些)。
配置:
nginx与上游建立连接读取响应,发送请求等等这些过程中,只要出现错误等等。error都可以满足这样的场景。这种错误主要是网络错误。比如TCP层、IP层的错误。
超时有connection timeout 、read timeout、 write timeout,这个timeout可以命中这些场景。当出现这种场景的时候将执行重选另一个下游服务。
则是我们收到的下游服务http header,它是不合法的。
http_可以跟一个明确的响应code。上游返回一个403或500,其实它既不是网络错误,也不是超时,也不是invalid_header。但是我们就是可以针对这样的错误从新选择一个新的upstream上游去处理。
根据RFC 7231文档中规定了post、lock等method的请求。在下游服务不能使用next_upstream上游服务的,去重选一个新的服务时候,当我们配置了这个non_idempotent就可以启用proxy_next_upstream功能。
关闭 proxy_next_upstream功能。
两个相关指令:
proxy_next_upstream_timeout 超时时间;proxy_next_upstream_tries 重试次数
反向代理配置:
下游服务:
(1)关闭proxy_next_upstream,访问反向代理服务就会在8011和8012端口服务上轮询
(2)打开proxy_next_upstream,且关闭下游8013服务,访问反向代理服务,一直是8011服务做响应。
(3)修改反向代理服务配置:
location /httperr {
proxy_next_upstream http_500;//下游服务返回500时生效
proxy_pass http://nextups;
}
访问反向代理服务,一直是8011服务做响应。
当下游响应码大于等于 300时,就应该使用error_page来处理请求返回给客户端。
proxy_intercept_errors 默认off。这个时候上游返回怎样的响应,客户端就会原封不动的拿到这个响应。比如上游返回来一个404,我们的error_page 配置的404是不会生效的。只有把proxy_intercept_errors 设置为on的时候error_page 就会生效了。
代理服务配置:
proxy_intercept_errors 为on时,配置了error_page,发现500错误码的时候返回test1.txt。
在互联网中使用缓存是最有效的提升访问速度的方法。在web服务器场景中不仅要考虑nginx作为缓存服务时的使用方法,还要考虑浏览器缓存生效的场景。浏览器的缓存是否生效可以通过nginx的指令去控制。而浏览器的缓存对用户的体验提升也是最大的。
Last-Modified:比较简单,也就是我们访问的资源,比如我们使用了一个js文件,这个js文件的在服务器上上次被修改时间。
这节课介绍在nginx之上配置上游服务器返回的响应的缓存。会涉及到一些指令的值,它是与第二部分课程中介绍过nginx进程结构的时候谈到的Cache Manager、Cache Loader 这两个进程。
内容是放到磁盘上的,但是它的元素信息为了加快访问是放到内存中的。所以首先在proxy_cache_path指令中定义好共享内存。因为我们有多个worker进程,所以这些元信息一定是在共享内存中的。第二个定义在磁盘中哪个位置去存放缓存文件。proxy_cache_path定义好以后,其中keys_zone的name就是共享内存的名字,size就是共享内存的大小。共享内存的名字就是给proxy_cache使用的。也就是在proxy_cache_path定义了一批缓存文件存放的位置和共享内存的名称。也许有很多location,它们定义了各自独立的缓存的key或缓存策略。但是它们都可以使用同一个proxy_cache_path指定的keys_zone。所以proxy_cache在location中可以通过这个zone指定使用哪一个proxy_cache中的设置。
use_temp_path:使用这个临时文件目录,最后改名都会放到path中。但为什么会有这个设置呢?是因为,很可能nginx所在的机器中有多个文件系统,甚至有些网络文件系统。如果我们开始的use_temp_path 目录是在一个磁盘上,而path是在另外一个磁盘上。跨磁盘复制是在cp文件。如果在一个磁盘上,那最后的改名也只是改名而已。
proxy_cache_convert_head:默认为on,会把header方法转换成get方法。
EXPIRED:表示nginx cache_vaild设置的时间还没有过期,用户的请求获取到缓存,但是上游服务器指定的缓存时间也许是小于cache_vaild设置的时间,根据上游的说法来说缓存已经过期了,但nginx配置的时候,这个缓存仍然在使用。所以和这个时候是EXPIRED,缓存已经过期。
补充说明:
proxy_cache_methods GET | POST|HEAD...//对哪些请求方法使用缓存
补充说明:
从下游服务定义缓存多少时间(0不缓存;@前缀表示缓存当天的某个时间)
nginx重启或者意外退出时,所以缓存就会失效,这个时候接收下游服务全部穿透Nginx打到下游服务,导致下游服务压力剧增。
proxy_cache_use_stale:第一个请求来了后打到下游服务,后续的请求给客户端响应旧的缓存内容,直至第一个请求的下游响应被缓存。
对应缓存有问题的响应:
例子:
proxy_cache_background_update:第一个请求来了把旧的缓存响应给客户端,同时向下游服务发送一个子请求,后续的请求给客户端响应旧的缓存内容。直至第一个请求的子请求收到下游服务响应内容后,更新缓存,后续的请求均可使用到新缓存。
[root]:#curl xxx.com/get?key=hello
[root]:#world//取出了hello的值
补充说明:
memcached_gzip_flag:如果设置的key使用了gzip压缩,取出的时候需要这个指令来标识。
由nginx_http_proxy_module模块实现
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection “upgrade”;
服务器配置:
设置了http2_push和http3_push_preload
请求:nghttp2 -ns https://localhost:4430/
请求:nghttp2 -ns https://localhost:4430/test/test.html
协议:grpc协议(https://grpc.io)
模块:ngx_http_grpc_module,默认开启,可以通过without–ngx_http_grpc_module禁用
依赖:ngx_http_v2_module模块
服务器配置:
连接:
telnet localhost:10004,返回如下:
反向代理配置:
下游服务配置:
收到上游带ssl的请求,剥离调ssl证书,向下游服务发送请求。
worker_process number | auto #一般设置为cpu核数
如何查看上下文切换次数?
什么决定CPU时间片的大小?
O1调度算法(CFS)
使用linux内核3.9以上,打开reuseport,提高性能。
说明:正常TCP三次握手需要等待server返回syn+ack后,发送ack+http请求,fast open tcp是第一次建立连接后,client保存cookie,第二次直接带上cookie请求sever,减少前面2次握手。
通告窗口?
收到对方的syn后,在回复ack时需要告诉请求方我还有多大的空间接收你的内容,这就是通告窗口。
滑动窗口:发送方主动限制流量
滑动窗口:接收方限制限制流量
实际流量:滑动窗口和滑动窗口的最小值
检查实际断连的连接
用于维持和客户端的防火墙有活跃的网络包
(1)configure概要,使用了哪些库或者功能
(2)一些重要文件的路径
说明:当if指令连续出现时,最后一个if为真的模块将一直影响到该模块结束。