1、DNS 缓存

1.1 什么是DNS

全称 Domain Name System ,即域名系统。

万维网上作为域名和IP地址相互映射的一个分布式数据库,能够使用户更方便的访问互联网,而不用去记住能够被机器直接读取的IP数串。DNS协议运行在UDP协议之上,使用端口号53。

简单的说,通过域名,最终得到该域名对应的IP地址的过程叫做域名解析(或主机名解析)。

www.dnscache.com (域名) - DNS解析 -> 11.222.33.444 (IP地址)

1.2 DNS缓存解析流程

有dns的地方,就有缓存。浏览器、操作系统、Local DNS、根域名服务器,它们都会对DNS结果做一定程度的缓存。

DNS查询过程如下:

  1. 首先搜索浏览器自身的DNS缓存,如果存在,则域名解析到此完成。
  2. 如果浏览器自身的缓存里面没有找到对应的条目,那么会尝试读取操作系统的hosts文件看是否存在对应的映射关系,如果存在,则域名解析到此完成。
  3. 如果本地hosts文件不存在映射关系,则查找本地DNS服务器(ISP服务器,或者自己手动设置的DNS服务器),如果存在,域名到此解析完成。
  4. 如果本地DNS服务器还没找到的话,它就会向根服务器发出请求,进行递归查询。

 

针对具体某一具体域名的访问,DNS 域名解析过程实际上是一个相当复杂的过程,需要经过多级迭代查询才能成功获取业务地址,以用户通过互联网访问民生银行官方网站系统 www.cmbc.com.cn 为例,其详细过程如下图所示:

java dns缓存时间 jvm dns缓存_缓存

 

  1. 当用户访问民生网站时,在 WEB 浏览器里输入 www.cmbc.com.cn 时,浏览器先检查是否有该网站的缓存(域名与 IP 的映射关系),有则直接使用访问,如果没有 DNS 请求发送到客户端解析器
  2. 假设后续环节都没有缓存,解析器将 DNS 请求发送给运营商 Local DNS 服务器处理,运营商 Local DNS 依次向 cn.、com.cn.、cmbc.com.cn.域名服务器发起迭代查询,并缓存查询结果,同时将结果返回给用户,实现业务访问。
  3. 在高速缓存未超时的时间内,客户浏览器再次发送到域名 www.cmbc.com.cn 的访问将不再需要经过以上迭代查询过程,将直接由客户本地电脑解析器缓存或本地 DNS 服务器缓存直接返回域名对应的 IP 地址

企业内网域名解析系统一般设计为一级(仅权威 DNS 服务器)或两级架构(包含本地 DNS 服务器和权威 DNS 服务器),不需要经过上述运营商多级域名迭代查询过程,其它解析过程与上述过程基本一致,客户端和本地 DNS 服务器同样可提供高速缓功能。

1.3 DNS 缓存作用

      DNS 域名系统给应用访问带来了额外的时延,另外由于 DNS 域名解析采用不可靠的 UDP 协议通讯,受内外部网络环境的影响较大,特别是在有丢包的情况下,导致的时延可能达到数秒。为缓解此问题,DNS 解析采用了缓存(Cache)机制。

      如上节 DNS 解析过程可知,经过第一次客户访问之后,本地 DNS 服务器和客户端均会缓存之前解析到的域名和 IP 地址映射,并基于相关机制设置相应的缓存生存时间(TTL),在 TTL 超时时间段内,后续 DNS 域名解析直接通过客户端本地和本地 DNS 服务器高速缓存解析,不再需要经过迭代查询过程。DNS 缓存可极大提升 DNS 域名解析的效率,一定程度上减少了客户端到用户之间环境对 DNS 域名解析的影响。

      高速缓存的缺点在于它需要消耗一定的系统资源,并增加了域名系统的复杂性。决定解析结果在高速缓存中保留多长时间是在 DNS 域名建设和维护时需要重点考虑的问题。如果缓存时间过短,则可能会导致产生多余的不必要的解析请求,如果缓存时间过长,则可能导致域名变更时客户访问恢复时间过长。

 

1.4 DNS 缓存使用面临的问题

若缓存设置使用不当,则可能给用户访问体验带来负面影响,甚至影响用户正常业务访问。缓存被使用在互联网非受控环境和内网相对可控环境,在不同的环境会面临不同的使用问题,下面来看看缓存在互联网和内网环境使用中可能会面临哪些问题。

1.4.1 互联网环境缓存应用面临的问题

      在互联网环境,缓存存在于浏览器、操作系统、运营商 Local DNS 服务器,其中运营商 Local DNS 是最重要且最不受用户和网站管理员控制的一个环节,如果缓存值设置不合理,将直接影响用户访问,会给企业形象带来负面影响。对于网站管理员来说,互联网环境的缓存面临两大方面问题:

缓存刷新不受控:一般企业为实现线路冗余都会使用多家运营商,因此域名就会被缓存在多家运营商 Local DNS 服务器,当企业域名发生改变时,涉及 Local DNS 服务器众多,在当前环境下,管理员无法刷新运营商 Local DNS 服务器缓存,在缓存未超时的情况下,客户无法获取到正确的域名进行业务访问,只能等待 Local DNS 服务器缓存超时后才能解析到正确的域名,正常访问业务,此种情况可能严重影响客户体验,导致大量的客户投诉。

解析权和缓存值被修改:一些小运营商出于规模、节约成本的考虑,将域名转发到其他运营商进行解析,并把收到的域名缓存值更改为较长的值,这会带来两个方面的问题:

  • 1)权威 DNS 接收到的请求 IP 地址不是客户所在运营商 IP 地址,客户的请求可能会被引导至错误的线路,导致客户访问慢;
  • 2)企业域名发生改变后将等待更长的超时时间才能正常访问业务;同样会给客户带来较差的体验。

 

1.4.2 企业内网缓存应用面临的问题

      企业内网环境相对简单,通常情况下用户会直接向权威服务器发起域名解析请求,内网域名解析路径较互联网可控且环境稳定,无运营商递归查询环节,因此基本不存在不可控的三方服务器和缓存被修改的问题。

      企业内网环境包括两类用户,一类为终端用户,例如柜员、业务管理人员、办公人员,这类用户使用电脑通过浏览器访问目标业务;另一类为生产系统,这类用户为服务器,通过应用软件访问目标业务。两类用户涉及的基础运行环境各不相同,缓存在使用中面临的问题也会有所不同。

终端用户面临的问题

      内网终端用户与互联网用户类似,差异是内网无中间运营商,它的缓存存在于浏览器、终端操作系统,若缓存值设置过长,当出现业务地址变更的时候,用户将无法访问业务,可能会影响办公或者影响客户办理业务,须等待本地缓存超时方可恢复。在终端用户层面,目标业务域名改变一般为单个系统,不会出现大面积变更的情况,且对象为内网用户,可建立统一的标准规范,因此影响范围相对较小。

生产系统面临的问题

      为实现业务快速切换以及运维便利,企业生产系统之间也开始大力推广通过域名方式访问,但生产系统使用的操作系统、编程语言等各不相同。

 

我们针对常用的操作系统和 JDK 环境的 DNS 缓存行为进行了全面测试,具体包括了 Suse12、AIX7.1、JDK1.6/1.7 等常用版本,经过测试得出以下结论:

  • 1)Suse 操作系统默认不开启缓存,当开启缓存时,继承 DNS 记录的缓存值
  • 2)AIX 操作系统默认不开启缓存,当开启缓存时,不继承 DNS 记录的缓存值,继承操作系统本地配置的缓存超时时间
  • 3)JDK 默认开启缓存,不继承 DNS 记录的缓存值,遵循自身配置的超时时间

      从以上实际测试结果可以看出不同的操作系统和 JDK 环境对 DNS 缓存的处理机制不一样。中间件如 Weblogic、Tomcat 建立链接时会调用 JDK,业务在实际部署中,会根据需求选择不同的操作系统和中间件,例如 Suse 和 AIX 的操作系统都可以选择 Weblogic 或者 Tomcat 部署应用,不同的组合 DNS 缓存处理机制会不一样,从而对应用访问产生不同的影响。以 Suse 和 AIX 两类操作系统、中间件使用 Weblogic 为例,来看看缓存的影响:

java dns缓存时间 jvm dns缓存_服务器_02

      假设操作系统和中间件均开启缓存,场景为应用访问数据库,配置 JDK 缓存 30s,操作系统缓存 1 分钟,DNS 域名 TTL 值为 2 分钟,当 APP 成功访问一次 DB 后,JDK 缓存域名时间为 30s,Suse 操作系统继承 DNS TTL 值缓存域名时间为 2 分钟,当域名发生变化时,JDK 经历 30s 后超时,但是操作系统还未超时,获取到的域名仍然为老地址,导致业务访问不通,影响时间增加 1 分半钟。同样的场景,若操作系统为 AIX,它不认可 DNS TTL 值,缓存为配置的 1 分钟,影响时间仅增加 30s。

      由此可见,不同操作系统、不同 JDK、不同 DNS TTL 配置,将会产生不一样的影响,当业务出现故障时由于缓存行为不一致,会给排障增加困难,运维变得复杂,无法满足快速恢复业务的需求,而且生产系统通常都不是孤立存在的,当一个系统出现问题时很有可能产生连锁反应,导致多个业务系统服务不可用,影响面更广,后果更严重。

 

1.5 DNS 缓存在实际应用中的考虑

      DNS 缓存在使用中会面临缓存无法刷新、被修改以及缓存控制复杂等问题,无论在互联网还是内网,缓存设置不合理都将导致用户无法访问业务,影响用户体验,那么缓存设置就显得尤为重要,它在实际应用中应该如何考虑?

      首先,哪些情况下域名会发生改变,从而出现影响用户访问的情况:

  • 主动操作:由于系统新建迁移、灾备切换等有计划的变更操作
  • 被动操作:当出现故障需要紧急更改域名对应的服务地址恢复业务

      不同场景产生的影响时间以及紧迫程度有所不同,就有不同的考虑因素,下面针对不同的场景分别进行介绍。

 

1.5.1、主动操作之缓存考虑因素

      针对主动操作的情况,有计划性,会有充足的时间准备,内网和互联网环境均可提前将域名对应的缓存值更改为更小的值,操作等待时间大于设置的缓存值即可,以确保递归服务器缓存了设置较小的 TTL 值,待操作完成后再更改回原有 TTL 值,无需人工干预。

      另外,避免缓存带来影响,还可以规范架构部署,例如通过负载均衡或者虚地址方式对外提供服务,可减少域名变化的情况,负载均衡或者虚地址方式可把操作隐藏在服务端,不会传达到客户端,可直接避免缓存时间给用户带来的影响。

1.5.2、被动操作之互联网缓存考虑因素

      互联网用户直接面向运营商,面临的问题是无法刷新缓存和缓存值被修改,要解决域名更改后无法快速生效的问题,需要从运营商入手:

 

刷新运营商 Local DNS 缓存

      当我行一条运营商线路故障时,这条线路对应业务 DNS 记录被用户及对应运营商 Local DNS 服务器缓存,经了解,三大运营商正在开发刷新缓存的功能,电信和联通支持基于单个域名自助刷新全国对应 Local DNS 缓存,目前正处于测试阶段,预计三分钟可以完成全国 Local DNS 缓存强制刷新;移动目前支持北京地区 Local DNS 缓存记录刷新,其他地区正在计划开发中。

      三大运营商都支持刷新缓存的情况下,将很大程度解决缓存生效慢的问题。但是一些小运营商不在合作范围内,目前仍然没有办法更新他们的缓存,可能会有少量地区客户仍然会有所影响。

避免缓存被修改

      互联网环境最大的问题是 Local DNS 缓存,缓存时间被修改,有没有方式可以避开 Local DNS?近几年 HTTP DNS 技术出现了,它是基于 HTTP 协议向 HTTP DNS 服务器发送域名解析请求,替代了基于 DNS 协议向运营商 Local DNS 发起解析请求的传统方式,有效的避开了运营商 Local DNS,就避免了缓存值被第三方修改

HTTP DNS 解析流程

java dns缓存时间 jvm dns缓存_java dns缓存时间_03

 

  • 1、客户端通过 HTTP/HTTPS 协议向 HTTP DNS 集群发起查询请求,携带用户域名和终端 IP
  • 2、服务集群查询 CDN 内部调度系统,将域名最佳访问节点 IP 响应给客户端
  • 3、客户端收到响应结果向节点发起请求
  • 4、客户端拿到最优 IP 后,发起业务访问
  • 5、若客户端访问 HTTP DNS 集群失败,可自动切换为传统方式通过运营商 Local DNS 进行解析查询

HTTP DNS 优点

  1. 绕过运营商 Local DNS,防劫持
  2. 能直接获取到客户端 IP 地址,更精准的返回结果,避免跨运营商
  3. 无运营商缓存,域名变更快速生效
  4. HTTP DNS 可以在终端 APP DNS 缓存超时之前提前进行解析,规避了缓存再解析导致延时的问题
  5. 与传统方式互备,当 HTTP DNS 不可用时可选择传统方式备份访问

HTTP DNS 适用场景

      HTTP DNS 主要是为 APP 类或桌面应用提供服务,如游戏、电商、金融、音视频、社交类 APP。HTTP DNS 需要在 APP 加载相应的 SDK 对默认的 DNS 请求方式进行修改,因此 HTTP DNS 的实现需要开发配合和深度介入,另外一般一个 APP 的访问会涉及多个域名,每个域名都使用 HTTP DNS 还是只是部分域名访问使用 HTTP DNS 需要评估。更细节的实现如缓存规则、更新规则、监控及切换规则也需要进行详细的考虑和设计。

 

1.5.3、被动操作之内网缓存考虑因素

      内网生产环境的域名访问在推广初期,从无到有,看似简单的域名请求,需要增加到 JDK、操作系统等环节的访问,这些环节缓存开启情况不同,要实施域名访问需重点考虑是否要开启缓存,缓存时间配置为多少合适。

1.5.4.1 是否开启缓存的考虑

      生产系统之间的交互有别于终端与系统之间的交互,生产系统交互频次高、时延要求高,若不开启缓存会在哪些方面有所影响?

链接建立影响

      经过测试,Weblogic 和 Tomcat 中间件建立一个链接分别会发起 2 个 DNS 请求,且要求 2 个请求都成功后方可建立链接,此处行为一致,但中间件会部署在某个操作系统上,由于 Suse 和 AIX 操作系统的超时重传机制不同,当网络出现丢包时,两类中间件行为结果不一样,若开启缓存,有一个 DNS 请求成功了就会被缓存,就能成功建立链接,若不开启缓存,面对超时时间不同、重传次数不同的问题,就很难评估何时能正常建立链接,出现问题时就很难分析业务影响和业务恢复时间,为排障增加了难度。

时延影响

      大部分系统为提高利用率以及实现高可靠性,应用采用双中心双活部署。在大二层的部署架构下,存在大量跨同城中心的访问流量,每一次跨中心访问都会增加一次时延,对于高频交互系统,在不开启缓存的情况下每次交互都会发起一次 DNS 请求,就会额外增加时延,会对系统带来访问缓慢的问题,严重时可能会影响交易。

      生产系统计划使用域名访问时,每笔交易对于访问 DNS 增加的时延带来的影响很难进行评估以及精准的测试影响结果,为避免通过域名访问增加的时延对生产系统带来影响,考虑开启具备缓存功能环节的缓存,但若仅针对时延要求高的系统开启缓存,那么生产环境就会存在不同的配置标准,又增加了运维的复杂性,因此,从运维规范、统一的角度考虑开启缓存。缓存功能开启了,缓存时间设置多长才能既满足快速访问业务又满足缓存及时失效的需求?

 

1.5.4.2 缓存时间考虑

      生产系统部署环境涉及的操作系统、中间件、系统程序等环节都存在缓存功能,导致 DNS 配置的域名缓存值对于业务系统的时间影响不可控,就无法真实了解缓存时间对业务的影响,以及更改域名对应的地址后业务恢复时间也无法掌握。要想解决生产系统面临的类型多和层级多的问题,可以从统一标准入手:

参考唯一 TTL 值

      统一开启各节点缓存器认可 DNS 服务器配置的 TTL 值,参考标准唯一,超时时间明确;对于无法参考 DNS TTL 值的环节,统一配置为与 DNS TTL 相同的超时时间

统一操作系统超时重传机制

      统一不同操作系统超时重传时间间隔、重传次数等参数

规范开发

     部分用特殊语言编写的业务系统有自己独有的缓存规则,需要规范开发规则,可调整遵循 DNS 规则

 

1.5.4.3 如何设置 TTL 值

      缓存超时间(TTL)是缓存技术中的一个重要参数,对缓存效果起着决定性的作用。TTL 时间设置较长,域名就能缓存更长时间,用户就能更快实现访问,TTL 时间设置较短,域名就更快超时,用户就需要等待域名解析才能正常访问。因此,TTL 时间设置的长短将直接影响用户的体验效果。TTL 值设置大小需要根据业务特性、业务环境、DNS 服务器性能等因素综合考虑,针对不同应用场景的缓存值设置规则可参考如下建议:

互联网环境

      互联网环境由于运营商 Local DNS 缓存服务器的存在,具有不可控性,因此不适宜配置较长的缓存时间,建议参考 DNS 性能配置较小缓存值,例如设置为分钟级。

内网终端环境

      内网终端环境相对可控,且大部分业务都是通过标准模式虚服务方式对外提供服务,域名变更概率较小,为减少终端访问频率,缓存值建议配置稍长时间,例如设置为小时级。

内网生产环境

      生产系统变更的概率较大,且若缓存更新不及时可能会带来重大的业务影响,因此生产系统不适宜配置较长的缓存超时时间,建议参考 DNS 性能配置为秒到分钟级。

 

2、CDN 缓存

2.1 什么是CDN

全称 Content Delivery Network,即内容分发网络。

摘录一个形象的比喻,来理解CDN是什么。

10年前,还没有火车票代售点一说,12306.cn更是无从说起。那时候火车票还只能在火车站的售票大厅购买,而我所在的小县城并不通火车,火车票都要去市里的火车站购买,而从我家到县城再到市里,来回就是4个小时车程,简直就是浪费生命。后来就好了,小县城里出现了火车票代售点,甚至乡镇上也有了代售点,可以直接在代售点购买火车票,方便了不少,全市人民再也不用在一个点苦逼的排队买票了。

简单的理解CDN就是这些代售点(缓存服务器)的承包商,他为买票者提供了便利,帮助他们在最近的地方(最近的CDN节点)用最短的时间(最短的请求时间)买到票(拿到资源),这样去火车站售票大厅排队的人也就少了。也就减轻了售票大厅的压力(起到分流作用,减轻服务器负载压力)。

用户在浏览网站的时候,CDN会选择一个离用户最近的CDN边缘节点来响应用户的请求,这样海南移动用户的请求就不会千里迢迢跑到北京电信机房的服务器(假设源站部署在北京电信机房)上了。

2.2 CDN缓存

关于CDN缓存,在浏览器本地缓存失效后,浏览器会向CDN边缘节点发起请求。类似浏览器缓存,CDN边缘节点也存在着一套缓存机制。CDN边缘节点缓存策略因服务商不同而不同,但一般都会遵循http标准协议,通过http响应头中的

Cache-control: max-age //后面会提到

的字段来设置CDN边缘节点数据缓存时间。

当浏览器向CDN节点请求数据时,CDN节点会判断缓存数据是否过期,若缓存数据并没有过期,则直接将缓存数据返回给客户端;否则,CDN节点就会向服务器发出回源请求,从服务器拉取最新数据,更新本地缓存,并将最新数据返回给客户端。 CDN服务商一般会提供基于文件后缀、目录多个维度来指定CDN缓存时间,为用户提供更精细化的缓存管理。

2.3 CDN 优势

  1. CDN节点解决了跨运营商和跨地域访问的问题,访问延时大大降低。
  2. 大部分请求在CDN边缘节点完成,CDN起到了分流作用,减轻了源服务器的负载。 戳此处详细了解CDN工作过程

 

3、浏览器缓存(http缓存)

对着这张图先发呆30秒~

java dns缓存时间 jvm dns缓存_缓存_04

3.1 什么是浏览器缓存

java dns缓存时间 jvm dns缓存_DNS_05

简单来说,浏览器缓存其实就是浏览器保存通过HTTP获取的所有资源,是浏览器将网络资源存储在本地的一种行为。

3.2 缓存的资源去哪里了?

你可能会有疑问,浏览器存储了资源,那它把资源存储在哪里呢?

memory cache

MemoryCache顾名思义,就是将资源缓存到内存中,等待下次访问时不需要重新下载资源,而直接从内存中获取。Webkit早已支持memoryCache。
目前Webkit资源分成两类,一类是主资源,比如HTML页面,或者下载项,一类是派生资源,比如HTML页面中内嵌的图片或者脚本链接,分别对应代码中两个类:MainResourceLoader和SubresourceLoader。虽然Webkit支持memoryCache,但是也只是针对派生资源,它对应的类为CachedResource,用于保存原始数据(比如CSS,JS等),以及解码过的图片数据。

disk cache

DiskCache顾名思义,就是将资源缓存到磁盘中,等待下次访问时不需要重新下载资源,而直接从磁盘中获取,它的直接操作对象为CurlCacheManager。

  • |memory cache | disk cache

相同点

只能存储一些派生类资源文件

只能存储一些派生类资源文件

不同点

退出进程时数据会被清除

退出进程时数据不会被清除

存储资源

一般脚本、字体、图片会存在内存当中

一般非脚本会存在内存当中,如css等

因为CSS文件加载一次就可渲染出来,我们不会频繁读取它,所以它不适合缓存到内存中,但是js之类的脚本却随时可能会执行,如果脚本在磁盘当中,我们在执行脚本的时候需要从磁盘取到内存中来,这样IO开销就很大了,有可能导致浏览器失去响应。

三级缓存原理 (访问缓存优先级)

  1. 先在内存中查找,如果有,直接加载。
  2. 如果内存中不存在,则在硬盘中查找,如果有直接加载。
  3. 如果硬盘中也没有,那么就进行网络请求。
  4. 请求获取的资源缓存到硬盘和内存。

3.3 浏览器缓存的优点

1.减少了冗余的数据传输

2.减少了服务器的负担,大大提升了网站的性能

3.加快了客户端加载网页的速度

3.4 浏览器缓存的分类

  1. 强缓存
  2. 协商缓存

浏览器再向服务器请求资源时,首先判断是否命中强缓存,再判断是否命中协商缓存!

3.4.1 强缓存

浏览器在加载资源时,会先根据本地缓存资源的 header 中的信息判断是否命中强缓存,如果命中则直接使用缓存中的资源不会再向服务器发送请求。

这里的 header 中的信息指的是 expires 和 cahe-control.

3.4.1.1 Expires:

该字段是 http1.0 时的规范,它的值为一个绝对时间的 GMT 格式的时间字符串,比如 Expires:Mon,18 Oct 2066 23:59:59 GMT。这个时间代表着这个资源的失效时间,在此时间之前,即命中缓存。这种方式有一个明显的缺点,由于失效时间是一个绝对时间,所以当服务器与客户端时间偏差较大时,就会导致缓存混乱。

3.4.1.2 Cache-Control:

Cache-Control 是 http1.1 时出现的 header 信息,主要是利用该字段的 max-age 值来进行判断,它是一个相对时间,例如 Cache-Control:max-age=3600,代表着资源的有效期是 3600 秒。cache-control 除了该字段外,还有下面几个比较常用的设置值:

no-cache:需要进行协商缓存,发送请求到服务器确认是否使用缓存。

no-store:禁止使用缓存,每一次都要重新请求数据。

public:可以被所有的用户缓存,包括终端用户和 CDN 等中间代理服务器。

private:只能被终端用户的浏览器缓存,不允许 CDN 等中继缓存服务器对其缓存。

Cache-Control 与 Expires 可以在服务端配置同时启用,同时启用的时候 Cache-Control 优先级高。

3.4.2 协商缓存

当强缓存没有命中的时候,浏览器会发送一个请求到服务器,服务器根据 header 中的部分信息来判断是否命中缓存。如果命中,则返回 304 ,告诉浏览器资源未更新,可使用本地的缓存。

这里的 header 中的信息指的是 Last-Modify/If-Modify-Since 和 ETag/If-None-Match.

3.4.2.1 Last-Modify/If-Modify-Since:

浏览器第一次请求一个资源的时候,服务器返回的 header 中会加上 Last-Modify,Last-modify 是一个时间标识该资源的最后修改时间。

当浏览器再次请求该资源时,request 的请求头中会包含 If-Modify-Since,该值为缓存之前返回的 Last-Modify。服务器收到 If-Modify-Since 后,根据资源的最后修改时间判断是否命中缓存。

如果命中缓存,则返回 304,并且不会返回资源内容,并且不会返回 Last-Modify。

缺点:

短时间内资源发生了改变,Last-Modified 并不会发生变化。

周期性变化。如果这个资源在一个周期内修改回原来的样子了,我们认为是可以使用缓存的,但是 Last-Modified 可不这样认为,因此便有了 ETag。

3.4.2.2 ETag/If-None-Match:

与 Last-Modify/If-Modify-Since 不同的是,Etag/If-None-Match 返回的是一个校验码。ETag 可以保证每一个资源是唯一的,资源变化都会导致 ETag 变化。服务器根据浏览器上送的 If-None-Match 值来判断是否命中缓存。

与 Last-Modified 不一样的是,当服务器返回 304 Not Modified 的响应时,由于 ETag 重新生成过,response header 中还会把这个 ETag 返回,即使这个 ETag 跟之前的没有变化。

Last-Modified 与 ETag 是可以一起使用的,服务器会优先验证 ETag,一致的情况下,才会继续比对 Last-Modified,最后才决定是否返回 304。

 

3.4.3 浏览器缓存总结

当浏览器再次访问一个已经访问过的资源时,它会这样做:

1.看看是否命中强缓存,如果命中,就直接使用缓存了。

2.如果没有命中强缓存,就发请求到服务器检查是否命中协商缓存。

3.如果命中协商缓存,服务器会返回 304 告诉浏览器使用本地缓存。

4.否则,返回最新的资源。

 

4 清除缓存

4.1 浏览器清除缓存

      通过设置hosts文件可以强制指定域名对应的IP,当修改hosts文件,想要浏览器生效,最直接的方法关闭浏览器后重新开启;如果不想重启浏览器,只需要清空浏览器的DNS缓存即可。清空DNS缓存在chrome、firefox下很容易做到。具体操作如下:

chrome:

chrome://net-internals/#dns 并回车,该页面会显示当前所有DNS缓存,通过点击“Clear host cache”,可以清空所有DNS缓存。有时候此方法可能不能立刻生效,可以使用另外一个设置,在地址栏中输入 chrome://settings/ 并回车,通过搜索“预测网络操作”找到配置项“预测网络操作,以提高网页加载速度”,去掉前面的勾即可。

firefox:

      在地址栏中 about:config 并回车,可能会出现一个警告信息,直接点击按钮进入,会出现firefox的所有配置信息,通过搜索dns进行过滤,可以看到一项名为 network.dnsCacheExpirationGracePeriod 项,它对应的值就是DNS缓存的时间,双击此项,会出现修改的提示框,填入 0 (不缓存DNS)即可

 

4.2 如何清除缓存

各大浏览器默认开启了DNS缓存功能,所以在先访问有个不存在域名后,再把该域名添加到本地hosts文件指向本地后,用该浏览器访问依然会提示域名不存在。。。

4.2.1 Firefox解决方式:

Firefox有dns缓存功能,但是Firefox默认缓存时间只有1分钟,可以通过修改该默认值加快DNS解析速度,方法如下:

  •       打开一个新的窗口,地址栏输 入 about:config,回车,进入设置界面。然后搜索 network.dnsCacheExpiration ,把原来的60改成 6000(表示缓存6000秒),再搜索network.dnsCacheEntries 把默认的20改成1000(表示缓存1000条)。如果没 有上面两个项目,新建它们即可,新建条目类型为整数型。 当然也可以按照需要设置成其它的值。

但是dns缓存太久了也会出问题,比如有的网站ip换了,就无法访问了。
针对这样的问题,还可以安装一个 firefox 插件来开启或者 关闭dns cache功能,https://addons.mozilla.org/zh-CN/firefox/addon/5914 。

4.2.2 IE解决方式:

禁用DNS缓存的方法,将下面内容保存为注册表文件,在运行写入注册表:

Windows Registry Editor Version 5.00

[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Internet Settings]
"DnsCacheEnabled"=dword:00000000
"DnsCacheTimeout"=dword:00000000
"ServerInfoTimeOut"=dword:00000000

写入注册表以后IE将不再缓存DNS,我们对hosts便会立即生效,无需再重启浏览器。

如果需要恢复IE的DNS缓存,只需清楚我们之前写入的注册表内容。跟上面的方法一样:

Windows Registry Editor Version 5.00

[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Internet Settings]
"DnsCacheEnabled"=-
"DnsCacheTimeout"=-
"ServerInfoTimeOut"=-

4.2.3 Chrome浏览器:

为了加快访问速度,Google Chrome浏览器采用了预提DNS记录,在本地建立DNS缓存的方法,加快网站的连接速度。你在谷歌Chrome浏览器的地址栏中输入about:DNS,回车,就可以看到本地的DNS缓存。

firefox下有个DNS Flusher插件,但没有chrome版本,其实在chrome下清除DNS缓存非常简单:
1、用chrome打开:chrome://net-internals/#dns
2、点击上面的“clean host cache”

也可以清空在工具中选择清空Cache,这样DNS cache会一同清空。

 

4.2.4 系统清除DNS缓存

微软windows下如何清空dns

 在微软windows下,你可以用命令ipconfig /flushd ns来清空dns 缓存内容。

你也可以用命令ipconfig /displaydns 来查看dns缓存内容。

 

Mac OSX下如何清空dns缓存
在Mac OSX中,你可以用这个命令lookupd -flushcache 来清空保留的缓存。
bash-2.05a$ lookupd -flushcache
 

Linux 下如何清空dns缓存

在linux中,nscd进程负责管理DNS缓存。
要清空DNS缓存,重启nscd守护进程就行了。
要重启nscd进程,使用命令(不带引号)'/etc/rc.d/init.d/nscd restart '

 

4.3 本修改本地hosts文件,浏览器不会立即生效

经常做Web开发的工程师,都会遇到需要将某个域名绑定到特定IP上,进行测试的情况。大家一般都会用修改hosts文件的方式来解决,但是经常也会遇到修改hosts不生效的情况,而且有时生效,有时不生效的情况也有发生,这到底是为什么呢?

起:DNS缓存机制

关于DNS缓存的机制,有一篇非常详细的文章What really happens when you navigate to a URL

简单来说,一条域名的DNS记录会在本地有两种缓存:浏览器缓存和操作系统(OS)缓存。在浏览器中访问的时候,会优先访问浏览器缓存,如果未命中则访问OS缓存,最后再访问DNS服务器(一般是ISP提供),然后DNS服务器会递归式的查找域名记录,然后返回。

DNS记录会有一个ttl值(time to live),单位是秒,意思是这个记录最大有效期是多少。经过实验,OS缓存会参考ttl值,但是不完全等于ttl值,而浏览器DNS缓存的时间跟ttl值无关,每种浏览器都使用一个固定值
这里有一篇文章,做过详细的测试Why Web Browser DNS Caching Can Be A Bad Thing

 

后来我也做过测试,Mac下Chrome(23.0.1271.101)的DNS缓存时间是1分钟。Safari下DNS缓存时间大约为10秒。

解:hosts文件修改的原理

那么在修改hosts文件之后,发生了什么事情呢?这里不妨先提提Chrome下的一个工具:chrome://net-internals/#dns。这里列出了目前系统中的DNS缓存和Chrome中使用的情况。通过这个工具,可以看到:

1

**在修改hosts文件后,所有OS中DNS缓存会被清空,而浏览器缓存则不发生变化。**

网上盛传chrome://net-internals/#dns下的"Clear Host Cache"可以清空DNS缓存,这里博主做了一个测试,这里清空的仅仅是OS的缓存,而并非浏览器DNS缓存。当某条DNS记录显示"Expired"的时候,才表示浏览器DNS缓存已经被清除。所以使用Clear Host Cache其实是没有用的。

那么回到最初的问题上来,为什么修改hosts文件之后,有时会立刻生效,有时却一直不生效呢?其实原因很简单,这是因为浏览器缓存的过期时间,是从某个域名上次查询DNS记录开始计算的。

例如:我00秒的时候使用chrome访问过www.google.com.hk,此时浏览器DNS缓存产生,然后我修改了hosts文件,将 www.google.com.hk指向本地127.0.0.1,然后在05秒的时候尝试再次访问这个地址,因为浏览器DNS缓存未过期,所以hosts 修改无法体现出来。

另一种情况下,我很久都没有访问www.baidu.com了,然后我修改了hosts文件,将其指向127.0.0.1,这时因为浏览器没有DNS缓存,所以会查询操作系统中的DNS缓存,结果此时hosts文件生效!

前面也提到,Safari的浏览器DNS缓存时间大约为10秒,所以一般调试程序的时候,很多人都习惯修改hosts后,用Safari来调试,因为大部分情况下,修改hosts之后,浏览器DNS缓存已经失效了。

那么怎么主动清除浏览器DNS缓存呢?博主目前也没有找到办法,测试过Chrome下的“清除缓存”选项,发现没有起到期望的效果。

那么,就请在修改hosts之后,耐下心来,稍等几十秒吧

 

5 JVM DNS 缓存

5.1 介绍

域名解析并非一个简单的过程,其解析结果可能会被层层缓存,如浏览器 DNS 缓存、操作系统 DNS 缓存、ISP 的 DNS缓存,容易被忽略的是 JVM 本身也会对 DNS 进行缓存。

JVM 的 DNS 缓存可以通过以下参数进行配置:

  • networkaddress.cache.ttl
  • sun.net.inetaddr.ttl
  1. 如果开启了 SecurityManager,优先从 ${java.home}/jre/lib/security/java.security 中读取参数 networkaddress.cache.ttl,单位为秒。
  2. 如果未读取到,则会读取启动参数 sun.net.inetaddr.ttl 作为缓存 ttl.
  3. 如果以上参数均未读取到,并且未开启 SecurityManager,则会使用默认值 30s.
  4. 否则使用初始值 -1,表示永久生效。

以上逻辑可以在 InetAddressCachePolicy.class 中体现,反编译后,有如下代码

static {
        Integer var0 = (Integer)AccessController.doPrivileged(new PrivilegedAction<Integer>() {
            public Integer run() {
                String var1;
                
                // 优先读取 networkaddress.cache.ttl
                try {
                    var1 = Security.getProperty("networkaddress.cache.ttl");
                    if (var1 != null) {
                        return Integer.valueOf(var1);
                    }
                } catch (NumberFormatException var3) {
                    ;
                }
                    
               // 未读取到,则读取启动参数 sun.net.inetaddr.ttl
                try {
                    var1 = System.getProperty("sun.net.inetaddr.ttl");
                    if (var1 != null) {
                        return Integer.decode(var1);
                    }
                } catch (NumberFormatException var2) {
                    ;
                }

                return null;
            }
        });
        if (var0 != null) {
            cachePolicy = var0.intValue();
            if (cachePolicy < 0) {
                cachePolicy = -1;
            }

            propertySet = true;
        } else if (System.getSecurityManager() == null) {
            // 如果未启用 SecurityManager,使用默认值 30
            cachePolicy = 30;
        }

其中 cachePolicy 初始值为 -1,表示缓存永不失效。

我们通过以下代码对 DNS 缓存参数进行测试:

public class HostProcessor implements Runnable {

    private int count = 1;

    /**
     * 每秒解析1次 www.baidu.com 的 IP
     */
    @Override
    public void run() {
        while (true) {
            System.out.println(count);
            printIp("www.baidu.com");

            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            count = count + 1;
            System.out.print("\r\n");
        }
    }

    /**
     * 解析并打印 IP
     */
    private void printIp(String host) {
        InetAddress address = null;
        try {
            address = Inet4Address.getByName(host);
        } catch (UnknownHostException e) {
            e.printStackTrace();
        }

        if (address == null) {
            return;
        }

        System.out.println(address.getHostAddress());
        System.out.println(address.getHostName());
    }

    public static void main(String[] args) {
        Thread thread = new Thread(new HostProcessor());
        thread.start();
    }
}

5.2 networkaddress.cache.ttl 参数测试

首先修改 java.security 中的 networkaddress.cache.ttl 配置,改为以下值:

networkaddress.cache.ttl=15

启动程序,开始打印域名对应 IP 后,立刻修改 /etc/hosts,将 www.baidu.com 指向到陌生 IP:

47.95.164.112   www.baidu.com

观察控制台输出,有如下结果:

 

java dns缓存时间 jvm dns缓存_服务器_06

在 15 秒后,对 host 映射的修改才反应出来

5.3 sun.net.inetaddr.ttl 参数测试

注释掉 java.security 中的 networkaddress.cache.ttl 配置,如下:

#networkaddress.cache.ttl=15

添加程序启动参数:

-Dsun.net.inetaddr.ttl=10

同样启动程序后,将原先 host 文件的修改回退,观察到如下输出:

java dns缓存时间 jvm dns缓存_服务器_07

在 10 秒后,对 host 映射的修改才反应出来

除了解析成功的结果,JVM 也会缓存解析失败的结果,可以通过下列参数配置:

  • networkaddress.cache.negative.ttl
  • sun.net.inetaddr.negative.ttl
    这里不展开介绍