Tag Archives: Performance

Web 前端优化最佳实践之 Server 篇

Web 前端优化最佳实践第二部分面向 Server 。目前共计有 6 条实践规则。【注,这最多算技术笔记,查看最原始内容,还请访问:Exceptional Performance : Best Practices for Speeding Up Your Web Site

1. 使用 CDN (Use a Content Delivery Network)

国内 CDN 的普及还不够。不过我们有独特的电信、网通之间的问题,如果针对这个作优化,基本上也算能收到 CDN 或类似的效果吧(假装如此)。【Tin 说国内 CDN 用的挺多,看看 CDN 厂商的市场就知道了,还没走入寻常百姓家】

2. 添加 Expires 或 Cache-Control 信息头 (Add an Expires or a Cache-Control Header)

各个浏览器都有针对的方案, Apache 例子【注意:下面的说明例子还不够精细,具体的环境上还要加一些调整】:

ExpiresActive On
ExpiresByType image/gif "modification plus 1 weeks"

Lighttpd 启用 mod_expire 模块 后:

$HTTP["url"] =~ "\.(jpg|gif|png)$" {
expire.url = ( "" => "access 1 years" )
}

Nginx 例子参考:

location ~* \.(jpg|gif|png)$ {
if (-f $request_filename) {
expires      max;
break;
}
}

3. 压缩内容 (Gzip Components)

对于绝大多数站点,这都是必要的一步,能有效减轻网络流量压力。或许有人担心对 CPU 压缩对于 CPU 的影响,放心大胆的整吧,没事儿。Nginx 例子:

gzip            on;
gzip_types      text/plain text/html text/css ext/javascript;

另外参见:

4. 设置 Etags (Configure ETags)

对于 Etag,可能是多数网站维护者都会忽略的地方。在这一系列优化规则出现之前,可能互联网上绝大多数站点都对这个问题忽略了。当然,Etag 对多数站点性能的影响并不是很大。除非是面向 RSS 的网站。【看到有朋友批评说写的简略,并且说 IE 不支持 ETag。明确说一下:IE 支持 ETag,倒是使用 IIS 要注意相关 Etag Bug。】

补充:我的意思是”很多网站在不注意的情况下都是打开 Etag 的,而没有网站关心如何用,消耗资源而不知。并不是说 Etag 不好,合理利用 Etag ,绝对能取得很好的收益.

5. 尽早刷新 Buffer (Flush the Buffer Early)

对这一条,琢磨了半天,貌似还是异步的思路。能更好的提升用户体验?

6. 对 AJAX 请求使用 GET 方法 (Use GET for AJAX Requests)

XMLHttpRequest POST 要两步,而 GET 只需要一步。但要注意的是在 IE 上 GET 最大能处理的 URL 长度是 2K。

前一篇:

下一篇分析一下 Cookie 。

EOF

Updated: 另请参见楼下高春辉的留言,很精彩

Web 前端优化最佳实践之 内容篇

Yahoo! 的 Exceptional Performance team 在 Web 前端方面作出了卓越的贡献。广为人知的优化规则也由 13 条到 14 条,再到 20 条,乃至现在的 34 条–真是与时俱进啊。最新的 34 条也针对不同的角度做了分类。

面向内容的优化规则目前有 10 条。

1. 尽量减少 HTTP 请求 (Make Fewer HTTP Requests)

作为第一条,可能也是最重要的一条。根据 Yahoo! 研究团队的数据分析,有很大一部分用户访问会因为这一条而取得最大受益。有几种常见的方法能切实减少 HTTP 请求:

2. 减少 DNS 查找 (Reduce DNS Lookups)

必须明确的一点,DNS 查找的开销是很大的。另外,我倒是觉得这是 Yahoo! 所有站点的通病,Yahoo!主站点可能还不够明显,一些分站点,存在明显的类似问题。对于国内站点来说,如果过多的使用了站外的 Widget ,也很容易引起过多的 DNS 查找问题。

3. 避免重定向 (Avoid Redirects)

不是绝对的避免,尽量减少。另外,应该注意一些不必要的重定向。比如对 Web 站点子目录的后面添加个 / (Slash) ,就能有效避免一次重定向。https://www.dbanotes.net/arch 与 https://www.dbanotes.net/arch/ 二者之间是有差异的。如果是 Apache 服务器,通过配置 Alias 或mod_rewrite 或是 DirectorySlash 能够消除这个问题。

4. 使得 Ajax 可缓存 (Make Ajax Cacheable)

响应时间对 Ajax 来说至关重要,否则用户体验绝对好不到哪里去。提高响应时间的有效手段就是 Cache 。其它的一些优化规则对这一条也是有效的。

5. 延迟载入组件 (Post-load Components)

6. 预载入组件 (Preload Components)

上面两条严格说来,都是属于异步这个思想灵活运用的事儿。

7. 减少 DOM 元素数量 (Reduce the Number of DOM Elements)

8. 切分组件到多个域 (Split Components Across Domains)

主要的目的是提高页面组件并行下载能力。但不要跨太多域名,否则就和第二条有些冲突了。

9. 最小化 iframe 的数量 (Minimize the Number of iframes)

熟悉 SEO 的朋友知道 iframe 是 SEO 的大忌。针对前端优化来说 iframe 有其好处,也有其弊端,一分为二看问题吧。

10. 杜绝 http 404 错误 (No 404s)

对页面链接的充分测试加上对 Web 服务器 error 日志的不断跟踪能有效减少 404 错误,亦能提升用户体验。值得一提的是,CSS 与 Java Script 引起的 404 错误因为定位稍稍”难”一点而往往容易被忽略。

这是内容篇的 10 条。应该说具体引导性的内容还不够详细。逐渐会根据自己的理解补充上来。

EOF

Unix/Linux 的 Load 初级解释

几乎每个接触类 Unix 操作系统的工程师都知道如何查看系统负载。但这东西的工作机理到底是怎样的,可能没有多少能说清楚。对比了一些相关信息,加上自己的理解,做一下笔记。

什么是 Load ? 什么是 Load Average ?

Load 就是对计算机干活多少的度量(WikiPedia: the system load is a measure of the amount of work that a computer system is doing)。也有简单的说是进程队列的长度. Load Average 就是一段时间 (1 分钟、5分钟、15分钟) 内平均 Load 。【最好的参考文章:UNIX® Load Average Part 1: How It Works

下面是一个 uptime 命令输出:

$ uptime
18:57:48 up 423 days, 3:55, 2 users, load average: 1.16, 1.12, 1.20

尽管各种信息来源的定义都不太确定。能确定的一件事情是,你不能精确获取当前时间的 Load . 最小的计算粒度是 5 秒钟(CALC_LOAD 每 5HZ 计算一次, 5HZ 为 5秒钟,这里的 HZ 是系统定义的变量). 参见 Linux Kernel 这段代码:

 869        count -= ticks;
870        if (unlikely(count < 0)) {
871                active_tasks = count_active_tasks();
872                do {
873                        CALC_LOAD(avenrun[0], EXP_1, active_tasks); 
874 CALC_LOAD(avenrun[1], EXP_5, active_tasks);
875 CALC_LOAD(avenrun[2], EXP_15, active_tasks);
876 count += LOAD_FREQ; 877 } while (count < 0); 878 } 879}

如何判断系统是否已经 Over Load ?

对一般的系统来说,根据 CPU 数量去判断,如上面的例子, 如果平均负载始终在 1.2 以下,而你是 2 颗 CPU 的机器。那么基本不会出现 CPU 不够用的情况。也就是 Load 平均要小于 CPU 的数量。

这是 Solaris 性能与工具(Solaris Performance Tools ) 一书推荐的评估方法。【在这里要推荐一下这本书,尽管在 Load 这个地方没有达到我期望的那么细致。但全书揭示了非常多的性能信息。每个 DBA、架构师 的必须书。】

这么说实际上带来另外两个疑问:

1 如果是多核 CPU / 超线程的机器怎么判断? 对这样的机器,我的建议是看操作系统怎么识别的 CPU,根据系统识别出来的逻辑 CPU 数量来判断。如果要考虑性能系数,建议参考一下 Oracle 针对不同架构下多核 CPU 的收费标准。

2 如果应用是面向线程的怎么判断? 这实际上和 M:N 线程模型有关。你的系统是怎样的? 把这个问题考虑进去即可了。

多数情况下,Load 过高都未必和 CPU 有关。或许倒是有一个例外的,就是应用场景的问题。比如用单 CPU 的机器去做高并发 Web 服务器,麻烦就来了

Load 与容量规划(Capacity Planning)

任何一个相对成熟的站点都会利用 Cacti(基于RRDTool) 等工具进行容量规划工作。抓取的 Load 会传 1、5、15 分钟列值过去,这三个度量采用哪个呢? 15 分钟为首选【参见Gunther 的 PPT】。

Load 与系统预警

很多对可用性要求比较高的环境都建立了 邮件或SMS 报警机制。关于 Load 报警阈值的制定也有看到不太合理的时候。这里建议 Critical 值(如果用 Nagios 之类的工具你明白这是什么)上限为 物理 CPU 的个数(当然你可以设置比这个低)。但比这个值高的话,意义就不大了。比如,数据库服务器有 4 颗 CPU,那么 Load 高于 4 就应该报警出来,设置比 4 高可能意义不大,因为接到报警还有个人为响应时间...

误解 一:系统 Load 高一定是性能有问题。

真相:系统 Load 高也或许是因为在进行 CPU 密集型的计算(比如编译)

误解 二:系统 Load 高一定是 CPU 能力问题或数量不够。

真相:Load 高只是代表需要运行的队列累积过多了。但队列中的任务实际可能是耗 CPU的,也可能是耗 I/O 乃至其它因素的。

误解 三:系统长期 Load 高,首选增加 CPU。

真相:Load 只是表象,不是实质。增加 CPU 个别时候会临时看到系统 Load 下降,但治标不治本。

小小一个 Load 讲究其实不少。英文信息其实比较全的,尽量保证加入一点新信息到这篇文章里。入看到有写的不合理的地方或者有异议,请指正或告知。

--EOF--

FAQ 1:数据库服务器突然 CPU 100% 繁忙,咋办?

A :一般情况下,这是由糟糕的 SQL 引起。建议抓取 Slow Query Log ,针对 I/O 开销比较大(重点看全表扫描)的 SQL 进行优化。根据经验值,每个 CPU Core 一秒钟能处理 100-400MB 数据量。如果是大量的并发 I/O 操作,尽管存储的吞吐可能还没那么大,也可能会把 CPU "塞满"。

Movable Type 的性能问题

我算得上是 Movable Type 的忠实用户。这两年来,WordPress 快成为 独立 Blog 的标准配置了,MT 可以说每况愈下。自从升级到 MT4 之后,明显感觉 Blog 性能糟糕了很多,每一次发文章都要与 HTTP 500 错误战斗半天才能成功,读者留言也非常费劲,有段时间非常灰心丧气,都不想继续写下去了。如果说 MT 3 之前是与 SPAM 战斗,到了 MT 4 就完全是折腾性能问题了。虽然 MT 4 之后的每次小版本发布都宣称性能上有很大改进,实际表现总是欠佳。

一些常规的 MT 优化技巧 其实作用都不大,我还把 MT 用的数据库索引分析了一遍,删掉了好几个价值不大的索引,虽然不是无用功,但也解决不了问题,因为瓶颈根本不在 DB 这里。大多数 Movable Type 用户的应用场景是在 Dreamhost 上,在这个环境里要想找到应用的瓶颈还真的是个技术活。缺乏 Profiling 工具不说,如果调用某个命令消耗了资源稍微过份一点,立刻被系统 Kill 掉。

其实 MT 的设计思想还是很不错的,大部分页面都 Build 成静态页面,减少对数据库的压力。一般来说,这比 WordPress 频繁调用数据库的方式(当然 WP 是可以起用 Cache 的),应该在性能上有更好的表现才是。问题是 Dreamhost 对每个用户提供的硬件资源其实是很差的,尤其是磁盘 I/O 。我的所有页面加起来也不过几千个,如果只是访问静态页面或是数据库其实问题都不大的,麻烦出现在构建页面或者是遇到留言行为的时候,MT 会调用若干个磁盘上的模版文件,加上 Perl 本身的系统开销,消耗的资源就到了 Dreamhost 的极限,然后进程就被无情的 Kill 掉了。估计是用户群抱怨太多,从 MTOS 4.1.1 版本开始总算有了一个性能框架 专门用以分析性能问题(并且号召用户提供性能数据以便协助解决性能问题)。启用了一段时间后,收集到的 Log 响应时间典型是这样的:

MT::Template::build[Comment Response]=0.60070
MT::App::Comments::run=28.24320
Total=28.85665

或许在 I/O 不错的系统上,表现会好吧。Dreamhost 上文件都是放置在 NFS 上的,而且众多用户共用一个系统,只能将就一下。

今天看到 4.15 的改进中,已经可以 Cache Template Module 了。甘愿作小白鼠,升级。盼望这次能有效解决特定应用场景的性能问题。不过开启了性能 Log 看了半天,效果并非很显著,

后记:

经验证的有效办法之一

通过Cache提升MT基于Tag搜索的速度,只在第一次构建需要的 Tag 时候会占用平时一样的系统资源。再次搜索时,开销大大降低。”抱怨的同时要有解决办法”。

EOF