+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-

张贺,多年互联网行业工作经验,担任过网络工程师、系统集成工程师、LINUX系统运维工程师

个人网站:www.zhanghehe.cn

笔者微信:zhanghe15069028807,现居济南历下区

+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-


nginx缓存

基本概念

为什么反向代理最好要有缓存功能

如果前端nginx代理没有缓存的话,那么对于用户的每一个请求,nginx代理都要向后端real-serever再发起一次请求,等到real-serever响应回复报文之后,nginx代理再回复给客户端。当有缓存功能之后,对于经常访问的页面(比如电商网站的首页),nginx代理不用老是去real-serever去拿,而是本地缓存一份,用户再来访问的时候,nginx前端代理直接回复给客户端,会大大的提升用户访问网站的速度。

LVS、nginx、varnish缓存的对比

LVS没有缓存功能,100个用户先后访问同一个网页,LVS也要向后端转发100次。

nginx最出名的是其并发响应的高性能,对于反向代理来说非常的优秀,但是nginx的缓存功能上不如varnish。

varnish和nginx都有反向代理和缓存的功能,varnish更加侧重于缓存。

我们可以将nginx代理和varnish组合起来使用,使用其长处,但每加一级设备报文的速度也就慢了,有没有更好的办法?有,那就是将varnish和nginx安装到同一个系统当中,让它们使用本地进程间通信的方式交互。

所有的信息都能缓存吗

GET、HEAD、PUT、POST,DELETE这五种方法当中,我们没有必要缓存PUT、POST、DELETE方法携带的内容,因为用户通常用这种方法所做的事情都是“一锤子"买卖,假如用户通过PUT提交一些信息,别的用户是不太可能与这个用户提交相同的内容,缓存了也没有什么用。

还有用户私有信息,比如cookie,cookie信息也不能缓存,因为每一个用户的cookie也是不一样的。

缓存什么内容由谁决定

缓存什么内容当然是我们说了算,我们要告诉nginx代理能缓存什么,不能缓存什么。客户端也可以决定不使用nginx代理当中缓存的内容,比如浏览器的shift+F5强刷就表示不使用代理缓存中的内容,而去后端取最新的数据。web集群在可以通过在报文上加上一些缓存控制字段,告诉nginx代理哪些内容可以缓存,哪些内容不可以缓存。

缓存生成的过程

缓存当中缓存的内容是用户经常访问的内容,是经过某种算法算出来的,这些内容并不会凭空而来,而是有一定的访问数据量之后才逐渐生成的,所以缓存上线后对速度的提升不是立竿见影的,而是要等一段时间,当缓存里面缓存了一定的内容之后速度才会明显提升。当然,我们为了让缓存上线就可以使用,可以在上线之间使用压力测试让缓存里面存放一些数据再上线,虽然压力测试所访问的页面可能与真实用户访问的页面有一些出入,但是缓存当中有数据总比没有数据要强吧!做完比做好更重要,更何况,缓存算法会一直生效,会踢出不经常访问的页面,保留命中率最高的页面。

我们拿URI缓存来举例子,假设我们在nginx代理上启用了缓存功能,并告诉nginx代理通过uri进行缓存,当用户访问www.zhanghehe.com.cn的时候,代理第一次肯定是去后端找web集群去拿数据,把数据响应给用户,然后会将www.zhanghehe.com.cn做一次HASH,生成一串字符,从左向右或从右向左取一位、二位、或三位十六进制数据,生成缓存目录,假如在一级目录上取一位的话,一位表示16个目录(4个比特),在二级目录取取二位(8个比特)的话,就表示生成255个子目录,同理还可以再有三级目录,最后将www.zhanghehe.com.cn的响应内容就缓存到最后一级目录下面。

注意,缓存内容是保存在硬盘当中的,但是nginx代理生成的的HASH表会一直保存在内存当中,优先级和速度都是最高的,就像我们在做数据库的索引似的,查第100万条数据与查第一条数据消耗的时间几乎是一样的。

缓存命中的过程

我们先不谈缓存的命中过程,我们先来谈一下在文件系统中cat /etc/passwd的步骤,bash程序会通过系统变量找到cat命令代码交给内核执行,然后内核会去硬盘上找/etc/passwd这个文件,怎么找的呢?先要找到根对应的inode号才能找到根的元数据,找到元数据之后才能知道根里面的内容存放到哪些数据块上了,找到了根的数据块,还要从这些数据块当中找到etc目录对应的inode块的地址,再找到etc对应的inote块,然后找到etc目录对应的内容,再找到passwd文件对应的inode号,最后才找到内容。我们发现内核找一个文件真的好麻烦,需要一级一级的找。

缓存命中的过程不是这个样子的,不需要一级一级的找,尽管缓存的内容也会存放在文件系统的二级或三级目录下,但是不需要这样一层一层的找,我们上面说过,生成缓存之后内存里面会有一个HASH表,HASH表是以键值对的方式对数据进行存储的,键是URI哈希之后的内容,而后面的值就是URI对应的块地址,当用户的请求的URi进入到nginx反向代理的时候,首先要哈希URI,然后通过哈希得到的值与哈希表核对,看内存中哈希表是否有缓存的内容,如果有的话直接通过键值的方式去硬盘的数据块当中取出内容,不用经过文件系统查找那一套逐级查看,而是通过哈希表一步到位!

nginx代理缓存关机之后,hash表丢失,开机后会自动根据硬盘中的内容自动生成。

常用模块

proxy_cache

proxy_cache_path:定义缓存的内容存到哪个路径下;Context: http

proxy_cache zone | off; 在缓存起一个名字,方便调用;Context: http, server, location

proxy_cache_key string; 指明要通过什么进行缓存,缓存中用于“键”的内容,下面这是默认值

默认值:proxy_cache_key $scheme$proxy_host$request_uri;

proxy_cache_valid [code ...] time;定义对特定响应码的响应内容的缓存时长;定义在http{...}中;

proxy_cache_use_stale ;后端服务器宕机了,代理是否可以通过缓存的内容来响应,可以在这里定义一个502,假如后端主机返回了502,我们这里可以通过缓存的内容对客户端响应。

proxy_cache_methods GET | HEAD | POST ...;,响应哪些方法,默认仅是GET和HEAD。

第一步:定义缓存

//http段下定义
proxy_cache_path /var/cache/nginx/proxy_cache levels=1:1:1 keys_zone=pxycache:20m max_size=1g inactive=20m;

缓存内容存放在/var/cache/nginx/proxy_cache,目录分为三级结构,每一级目录16个子目录(不会一次性生成),内存中的缓存键的区域名字是pxycache,大小开辟20m的空间,磁盘空间用1g,默认非活动时间(多长时间没有被命中)是10分钟,如果10分钟内某个缓存条目没有被命中就会被清理出去,我们这里定义成20分钟。

第二步:调用缓存

//定义需要调用缓存功能的配置段,例如server{...};
proxy_cache pxycache; #调用缓存,pxycache是第一下定义过的。
proxy_cache_key $request_uri; #根据uri缓存
proxy_cache_valid 200 302 301 10m; #对于后端返回200,302,301状态码的界面缓存10分钟
proxy_cache_valid 404 1m; #404状态码缓存1分钟
proxy_cache_use_stale http_502;
proxy_cache_methods GET HEAD;

//效果查看,果然是三级目录,缓存了两个内容,我们可以查看一下。
[root@nginx_proxy ~]# tree /var/cache/nginx/proxy_cache/
/var/cache/nginx/proxy_cache/
└── 9
└── d
├── 7
│   └── 6666cd76f96956469e7be39d750cc7d9
└── 9
└── 35a63c8a85b1279a0f991ce8828fb9d9
//查看都缓存了什么内容
cat 6666cd76f96956469e7be39d750cc7d9 .
§X^mW^¼¤X^ՒҹX>
"5e571e6d-e"
KEY: /
HTTP/1.1 200 OK
Server: nginx/1.16.1
Date: Fri, 28 Feb 2020 05:27:25 GMT
Content-Type: text/html
Content-Length: 14
Last-Modified: Thu, 27 Feb 2020 01:42:05 GMT
Connection: close
ETag: "5e571e6d-e"
Accept-Ranges: bytes this is 80.11 #整个网页里面的所有内容都缓存了
cat: .: Is a directory

超时相关

这里超时相关指的是向后请求或向后发送的连接或报文超时,后就是web集群,如果想定义从nginx代理向客户端的就得通过nginx的一些相关超时模块keepalive等。

proxy_connect_timeout time; 三次握手的超时时间,默认为60s;最长为75s;

proxy_read_timeout time; 请求的超时时间,默认为60s;最长为75s;

proxy_send_timeout time; 发送超时时长,默认为60s;最长为75s;

为什么会超时呢?超时的原因很简单,比如主机突然宕机了,三次握手会中断,代理向后发送的请求报文,或者发送的报文都可能会超时,再次强调,我们这里的超时时间指提nginx代理到web集群这一段的超时时间,而不是面向客户端的一侧,想要定义面向客户端一侧的超时时间也很简单,在nginx代理上通过nginx_http一些模块定义即可,我在nginx那一篇博客当中有详细阐述,这里不过多阐述。

//示例
server {
listen 80;
server_name www.zhanghehe.com.cn; proxy_cache pxycache;
proxy_cache_key $request_uri;
proxy_cache_valid 200 302 301 10m;
proxy_cache_valid 404 1m;
proxy_cache_use_stale http_502;
proxy_cache_methods GET HEAD;
proxy_connect_timeout 60s;
proxy_read_timeout 60s;
proxy_send_timeout 60s; location / {
proxy_pass http://192.168.80.11:80;
} location /admin {
proxy_pass http://192.168.80.11;
} location /images {
proxy_pass http://192.168.80.11/images/;
}
}

常见架构

第一种架构当中,静态页面nginx代理自己就处理了,动态页面使用php-fpm来处理,但php-fpm处理动态并发请求的能力太差了,所以又有第二种架构,让apache和php结合在一起,前端nginx代理通过http协议传递给apche,然后apache和php使用本地进程间的通信方式,大大提高了并发请求。

第三种架构更好一些,nginx代理专心处理代理和缓存,静态内容也不管了,分发给一台专门的服务器。

前三种架构在数据库方面没有做优化,实际是数据库是最慢的一环,我们可以在apache+php下旁挂一个memcache,memcache的性能没的说,内存级缓存,每秒几十万的处理量,而数据库每秒不到一百个,性能大大提高,但因其支持的数据类型较少,所以慢慢被redis代替,redis支持的数据类型更多,而且硬盘也能做存储,内存当中的数据不会丢失。

nginx反向代理(2)的更多相关文章

  1. 使用python自动生成docker nginx反向代理配置

    由于在测试环境上用docker部署了多个应用,而且他们的端口有的相同,有的又不相同,数量也比较多,在使用jenkins发版本的时候,不好配置,于是想要写一个脚本,能在docker 容器创建.停止的时候 ...

  2. Nginx反向代理,负载均衡,redis session共享,keepalived高可用

    相关知识自行搜索,直接上干货... 使用的资源: nginx主服务器一台,nginx备服务器一台,使用keepalived进行宕机切换. tomcat服务器两台,由nginx进行反向代理和负载均衡,此 ...

  3. Nginx反向代理部署指南

    一.反向代理 我们都知道,80端口是web服务的默认端口,其他主机访问web服务器也是默认和80端口进行web交互,而一台服务器也只有一个80端口,这是约定俗成的标准. 我们来看下面两个场景: 1.服 ...

  4. Nginx 反向代理、负载均衡、页面缓存、URL重写及读写分离详解

    转载:http://freeloda.blog.51cto.com/2033581/1288553 大纲 一.前言 二.环境准备 三.安装与配置Nginx 四.Nginx之反向代理 五.Nginx之负 ...

  5. Nginx反向代理和负载均衡

    一.Nginx反向代理设置 从80端口转向其他端口反向代理(Reverse Proxy)方式是指以代理服务器来接受internet上的连接请求,然后将请求转发给内部网络上的服务器,并将从服务器上得到的 ...

  6. nginx 反向代理

    nginx 反向代理 vim nginx.conf http { ..... upstream "tomcatweb" { server 172.30.13.199:8080; s ...

  7. 关于nginx反向代理后获取不到客户端的真实ip地址问题

    前段时间在我的网站上用nginx做了一下反向代理,最近发现不能获取客户端ip了,都是拿到的127.0.0.1的本地ip... 通过查资料后,再去看了看我的配置文件,结果发现我没有如下配置: nginx ...

  8. Nginx反向代理配置可跨域

    由于业务需要,同一项目中的前端代码放在静态环境中,而后端代码放在tomcat中,但此时问题却出现了:前端使用ajax请求后端获取数据时出现如下报错 XMLHttpRequest cannot load ...

  9. Nginx反向代理搭建配置

    1.反向代理方式是指以代理服务器来接受internet上的连接请求,然后将请求转发给内部网络上的服务器,并将服务器上得到的结果返回给internet 上请求连接的客户端,此时代理服务器对外就表现为一个 ...

  10. nginx反向代理docker registry报”blob upload unknown"解决办法

    问题症状:keepalived+nginx反向代理后端docker registry群集时,使用docker客户机向registry push镜像时出现 "blob upload unkno ...

随机推荐

  1. 传奇脚本:#AutoRun NPC SEC 参数说明

    传奇脚本:#AutoRun NPC SEC 参数说明 SEC:按秒运行MIN:按分运行HOUR:按小时运行DAY:按天运行RunOnDay:按每天什么时候运行RUNONWEEK:按星期几及时间运行机器 ...

  2. P3368 (模板)树状数组2

    借这个题学新姿势,这个题需要利用差分才能AC,普通树状树有3个点过不了. 差分原理(参考题解区大佬): 一个例子,一组数据 $ a[] = { 1, 5, 4, 2, 3 } $,差分后得到 $ b[ ...

  3. touchstart和click 自动区分

    var clickEvent = (function() { if ('ontouchstart' in document.documentElement === true) return 'touc ...

  4. python练习:编写一个程序,要求用户输入一个整数,然后输出两个整数root和pwr,满足0<pwr<6,并且root**pwr等于用户输入的整数。如果不存在这样一对整数,则输入一条消息进行说明。

    python练习:编写一个程序,要求用户输入一个整数,然后输出两个整数root和pwr,满足0<pwr<6,并且root**pwr等于用户输入的整数.如果不存在这样一对整数,则输入一条消息 ...

  5. 4_3 救济金发放(UVa133)<子过程/函数设计>

    为了缩短领救济品的队伍,NNGLRP决定了以下策略:每天所有来申请救济品的人会被放在一个大圆圈,面朝里面.标明一个人为编号1号,其他的就从那个人开始逆时针开始编号直到N.一个官员一开始逆时针数,数k个 ...

  6. spring data flow

    spring data flow相当于一个快速发布应用的平台.并可以通过消息队列(kafa,rabbitMQ)把多个应用链接在一起进行链式处理数据.支持的平台是: Cloud Foundry Apac ...

  7. 语义化标签&唯一性标签

    语义化标签 em\i表示倾斜,b\strong表示加粗,但其中只有strong和em具有着重的语义 img:alt属性当图片无法显示,显示alt的文字,根本需求是为了SEO,是必须属性,alt属性长度 ...

  8. node.js express 中文参考手册

    https://www.runoob.com/w3cnote/express-4-x-api.html 原文地址:https://www.zybuluo.com/bajian/note/444152 ...

  9. 【原】jenkins知识点_凭据(一)

    一:凭据 1.目的: 与第三方网站或应用程序进行交互,如代码仓库.云存储系统和服务等 2.操作路径: Jenkins-凭据-系统-全局凭据 3.权限 Jenkins 中保存的凭证可以用于: 任何适用于 ...

  10. Redis数据存储结构之String

    前言: 在Redis使用中,我们最常使用的操作是set key value,或 get key value .这里面包含了redis最基本的数据类型:String,字符串类型是redis中最基本的类型 ...