网站访问
浏览器地址栏里敲下那串字符,网站访问回车。网站访问屏幕白了一下,网站访问然后内容涌出来——这个过程平均耗时1.8秒。网站访问你大概从没想过,网站访问这1.8秒里发生了多少事。网站访问
先找路。网站访问域名系统把"zhihu.com"翻译成IP地址,网站访问像查电话簿。网站访问全球13台根服务器管着这套翻译规则,网站访问你本地运营商那台DNS服务器大概率缓存过这个域名,网站访问所以这一步通常几十毫秒就完事。网站访问要是网站访问没缓存,就得一层层往上问,网站访问从根域名服务器问到顶级域再到权威服务器,网站访问来回几个回合,几百毫秒就没了。我用过一个小众DNS服务,延迟比运营商默认的低40ms左右,网页打开速度肉眼能感觉到差别。不是玄学。
找到IP只是第一步。TCP三次握手建立连接,客户端发SYN,服务器回SYN-ACK,客户端再回ACK。一来一回,一个半往返时间没了。物理距离摆在那,光在光纤里跑也就每秒20万公里,北京到上海一个来回怎么也得十几毫秒。要是服务器在美国西海岸,单次往返150ms起步,三次握手就吃掉200多毫秒。所以很多网站搞CDN,把静态资源推到离你最近的节点。你访问的其实是离你三公里外的那个缓存服务器,不是远在加州的源站。
连接建好了,发HTTP请求。浏览器说"我要这个页面的HTML",服务器把文件吐回来。通常一个页面HTML也就几十KB,但页面里引用的CSS、JS、图片加起来可能好几MB。以前HTTP/1.1一个连接一次只能处理一个请求,浏览器得开六条并发连接去抢资源。现在HTTP/2多路复用,一条连接搞定所有。我测过同一个站点,HTTP/2比HTTP/1.1首屏加载快了将近一倍。协议升级带来的提升,比换台新电脑还明显。
服务器那边收到请求,事情更多。拿PHP来说,Nginx接到请求转给PHP-FPM,PHP脚本执行,查数据库,拼HTML,再原路返回。数据库查询通常是瓶颈。一条没走索引的SQL能在百万行表里扫三秒,用户那边就是白屏三秒。我见过一个电商详情页,光商品评价的查询就跑了1.2秒,后来加了个联合索引降到8毫秒。用户感知不到这背后的优化,但转化率涨了。
浏览器拿到HTML开始解析,边解析边构建DOM树。遇到<script>标签会暂停解析去下载执行JS,所以前端优化建议把JS放底部或者加defer。CSS放头部,不然页面会闪一下无样式内容。这些细节在网速慢的时候特别明显。我在3G网络下打开某些网站,能看到文字先出来、样式后加载的"裸奔"瞬间,就是这个原因。
最后一步是渲染。浏览器算出每个元素的位置大小,合成图层,画到屏幕上。GPU加速的合成层滚动更流畅,但层数太多显存扛不住。Chrome有个图层边界可视化工具,打开后能看到页面被切成多少层。有些页面切了几百层,滚动起来手机发烫,就是这个原因。
整个过程走完,你看到页面。1.8秒里DNS查询、TCP握手、TLS协商、HTTP请求、服务器处理、浏览器渲染串行加并行地跑了一遍。任何一个环节卡住,用户看到的就是转圈。网站访问这件事,表面上是输入网址看内容,底下是几十个系统在协作。下次页面加载慢的时候,打开开发者工具的Network面板,看看时间轴卡在哪一段。比干等有意思。