由于之前找工作,刚来上海挺多事,些久没写博客;至此打算新开一个 “学习录” 系列(以读书笔记和实战心得为主),记录自己 Java 学习路上的收获,共勉。

《深入分析 Java Web 技术内幕》 第一章 深入 Web 请求过程的内容为参考,此篇讲解游览器缓存、DNS 域名解析的过程和 CDN 工作机制。

游览器缓存

缓存可以减少游览器向服务器请求资源的次数,减少网络延时,加快页面响应速度,减少服务器压力。下图中 size 不为 0 的请求就是没有使用缓存。

Memory Cache 会将资源暂时缓存到内存中,在关闭游览器后会释放掉这部分内存空间。受限于计算机内存的大小,当内存使用率高的时候,资源大概率会被缓存到 Disk Cache,它可以长时效的在硬盘中缓存资源。

Cache-Control / Pragma

我们在游览一个页面时发现有异常,通常考虑的就是是不是游览器做的缓存,这个时候可以按 Ctrl + F5 来重新请求到没有缓存的页面。这个组合键会直接向目标 URL 发送请求,而不会使用游览器缓存的数据;它会在 HTTP 的请求头中增加一些请求头,告诉服务器我们要获取最新的数据而不是缓存(以此也可以跳过前端部署的缓存服务器)。

对 HTTP 请求头不太熟悉的同学可以先参考下我的计网学习笔记:Net:计算机网络读书笔记

使用 Ctrl + F5 组合键后在 HTTP 请求头中增加了两项 Pragma:no-cacheCache-Control:no-cache,其字段可选值如下表所示:

可选值 说明
Private 所有内容都将被缓存,在响应头中设置
Private 内容只缓存到私有缓存中,在响应头中设置
no-cache 所有内容都不会被缓存,在请求头和响应头中设置
no-store 所有内容都不会被缓存到缓存或 Internet 临时文件中,在响应头中设置
must-revalidation/proxy-revalidation 如果设置的内容失效,请求必须发送到服务器 / 代理以进行重新验证,在请求头中设置
max-age=xxx 缓存的内容将在 xxx 秒后失效,这个选项只在 HTTP 1.1 中可用,和 Last-Modified 一起使用时优先级较高,在响应头中设置

Cache-Control 请求字段被各个游览器支持得较好,而且它的优先级比较高,和其他的一些请求字段(如 Expires)同时出现时,Cache-Control 会覆盖其他字段。

Expires

Expires:Sat,25 Feb 2012 12:22:17 GMT,超过这个时间值后,缓存的内容将失效,也就是游览器在发出请求之前会检查这个页面的这个字段,看该页面是否已经过期了,过期了就重新向服务器发起请求。

Last-Modified / Etag

Last-Modified 一般用于表示一个服务器上的资源的最后修改时间,通过这个最后修改时间可以判断当前请求的资源是否是最新的。

一般服务端在响应头返回一个 Last-Modified:Sat,25 Feb 2012 12:55:04 GMT,游览器再次请求时就增加一个 If-Modified-Since:Sat,25 Feb 2012 12:55:04 GMT 字段,询问当前请求的资源是否是最新的,如果是最新的就返回 304 Not Modified 状态码,告诉游览器是最新的,服务器也不会传输新的数据。

Etag 字段让服务器给每个页面分配一个唯一的编号,通过编号区分当前页面是否是最新的,比 Last-Modified 更加灵活,但是在后端的 Web 服务器有多台时难以处理,因为每个 Web 服务器都要记住网站的所有资源,否则游览器返回这个编号就没有意义了。

强缓存与协商缓存

Cache-Control 与 Expires 都属于强缓存,在缓存时间内不会向服务器发送请求,直接从缓存中读取资源,一旦在服务器的资源文件发送变化,就会导致服务器和游览器文件不一致的问题。

而 Last-Modified 和 Etag 则属于协商缓存,可以很好的解决这个问题。游览器会携带缓存标识向服务器发起请求,由服务器根据缓存标识决定是否使用缓存。

DNS 域名解析

我们通常使用 URL 域名来请求网络资源,它需要被解析成 IP 地址才能与远程主机建立连接,如何将域名解析成 IP 地址就属于 DNS 解析的工作范畴了。

对 URL 域名仍不了解的同学可以先阅读下:Web:浅析 URL

域名缓存

当用户在游览器中输入域名并按下回车键后,游览器会先检查缓存中有没有这个域名对应的解析过的 IP 地址,如果没有命中,则会去操作系统的缓存中查找是否有这个域名对应的 DNS 解析结果。用户也可以修改系统文件来修改域名对应的 IP,Windows 下为 C:\\Windows\System32\drivers\etc\hosts,Linux 下为 /etc/hosts域名劫持 就是黑客修改把特定的域名解析到它指定的 IP 地址上,所以 Windows 7 中将 hosts 设置成了只读,防止这个文件被轻易修改。

本机的域名缓存 Windows 下可通过 ipconfig /flushdns Linux 下 /etc/init.d/nscd restart 来清除缓存,JVM 也会在 InetAddress 类中缓存 DNS 解析结果。

域名解析

如果在本机中仍然无法完成域名的解析,就会真正请求域名服务器。

  1. 首先会去请求本地区的域名服务器 LDNS,即本地区的互联网应用服务商电信或者联通,它们的域名解析服务器性能都很好,会缓存域名解析结果,80% 的域名解析请求到 LDNS 就结束了,所以 LDNS 承担了主要的域名解析工作。
  2. 如果 LDNS 没有命中,则会依次去请求 Root Server、gTLD Server,顶级域名服务器会查找并将此域名对应的 Name Server 地址返回给 LDNS。Name Server 就是域名注册时的某个域名服务提供商。
  3. LDNS 再向 Name Server 发起请求,Name Server 会查询存储的域名和 IP 的映射关系表,连同一个 TTL 值一起返回给 LDNS,LDNS 会缓存这个域名和 IP 的对应关系,缓存时间由 TTL 值控制。
  4. 最后,LDNS 将解析结果返回给用户,用户根据 TTL 值缓存在本地系统缓存中,域名解析过程结束。

跟踪域名解析过程

Windows 和 Linux 下都可以使用 nslookup 来查询域名的解析结果,Linux 下可用 dig 查询 DNS 的解析过程。

CNAME 为 Canonical Name(别名解析),可以为一个域名设置一个或者多个别名(方便 CDN 配置)。A 为 Address 为域名对应的 IP 地址。

CDN 工作机制

CDN 全称 Content Delivery Network,它将网站的内容发布到最接近用户的网络“边缘”,使用户可以 就近 取得所需的内容,提高用户访问网站的响应速度。

CDN 主要缓存网站中的静态数据,如 CSS、JS、图片和静态页面等数据,

CDN 架构下,当用户发起请求,经迭代解析后 LDNS 将收到域名的注册服务器地址,而公司的 DNS 解析服务器会把它重新 CNAME 到 CDN 全局中的 DNS 负载均衡服务器,再由 GTM 根据是哪个地方的访问用户来分配离这个用户最近的 CDN 节点。

如果 CDN 节点中的请求数据不存在,则会回到源站去获取这个文件,然后再返回给用户。