云计算 反思课 3 提高 Web 服务性能的策略与思考

学习是一个不断改进方法论的过程,课程项目 6 MySQL 和 HBase 配置及测试,因为自己对于搭建基于 NoSQL 数据库的 Web 服务缺乏足够的经验,在具体对前后端进行优化的时候走了很多弯路,也意识到了没有目的的优化很可能是劣化,这里主要整理一下自己对于优化问题的思考。


应用场景

因为涉及到具体的问题,所以先大概说明一下应用场景,方便之后的叙述。事情大概是这样的:

  • 数据是 5100W 条左右带 tag 的 tweet
  • 这些 tweet 有各种语言
  • 只有读请求,每次需要返回指定用户用指定 tag 发送的 tweet
  • 前端使用 Undertow,后端是部署在 Amazon EMR 的 HBase
  • 有一定的预算限制(不能开多台机器来凑)

难点在于,优化问题其实是一个涉及多层级多组件的『复杂』问题,需要考虑的东西很多,更纠结的是,整个系统是符合『木桶理论』的,也就是最短板决定了系统的整体性能。那么就牵扯出两个关键问题:短板在哪里?短板怎么解决。

一些思考

对于 Web 服务来说,所谓优化,可以简单粗暴分为两个子类,一是增加吞吐量,二是增加并发数。优化的整体思路,按照实施的顺序来看,大概是这样的:

  1. 充分理解应用场景
    • 服务具体接收的请求的格式和具体需要返回的内容是什么
    • 是偏向于读,还是偏向于写,亦或者是读写比较均衡
    • 数据量大概是多少,分布式集群(如果要用)的基本配置是什么
  2. 数据格式设计
    • 根据具体的场景,需要思考具体数据库的设计
    • 如果是读比较多,可以考虑对数据进行预处理,用空间换时间
    • 如果是写比较多,则需要尽可能减少冗余,减少改动时需要同步更新的记录
  3. 分析服务瓶颈(慢在哪里)
    • 使用什么工具,监控什么指标来寻找瓶颈
    • 根据输出的日志(这里需要自己决定输出什么)来找寻请求的规律
    • 根据日志的数据统计,找到短板所在
    • 这一步其实并不简单,更可怕的是,如果在这里分析错误,就会把整个优化带入死胡同(去优化并不需要优化的问题)
  4. 充分利用硬件资源
    • 在预算限制下有没有开够机器
    • 对于每台机器,其 CPU,内存,带宽等资源有没有尽可能使用
    • 如果没有尽量利用,就说明钱没有花在刀刃上,可以考虑更换不同类型的机器,Amazon 提供了『通用』,『内存优化』和『计算优化』这几种不同的机器,可以根据监控的数据,根据前后端不同的任务来决定具体使用什么类型的机器
  5. 解决木桶效应,不同层优化
    • 算法 + 数据结构优化
    • 事务处理逻辑优化,尽可能减少单次请求需要的资源(包括计算、内存和带宽资源)
    • 硬件优化,vertical scaling 或者 horizontal scaling
    • 分布式结构优化,采用 ELB 或 Hadoop

一些策略

前面从总体的思路切入,这里因为涉及到具体的指标要求,所以会从细节方面切入。

首先要意识到从我们在浏览器中输入网址,到最后看到显示的内容之间发生了什么。因为这里不是网络分析课(Amazon 的网络我们能调优的范围也有限),所以 DNS 路由之类的内容这里不提,具体可以参考计算机网络一文。

那么到底中间的过程是什么呢?其实就 3 步:

  1. 页面模板根据实际内容渲染成网页。这部分我们不需要考虑,并没有用任何渲染引擎,就是单纯返回一段数据而已
  2. 业务逻辑部分。显示内容之前做的预处理,对应配套的缓存,连接池等等内容。这部分理论上是需要考虑的,但是在具体的测试中,影响不算特别大(和后面相比)
  3. 数据库与网络传输部分。这部分是主要的瓶颈所在,接下来会细说。

网络部分优化,其实是比较简单粗暴的,因为是只读操作,所以不需要考虑一致性问题,努力增加并发数即可,另一个角度则是减少每次传输所需要的带宽,综合来看,有下面的策略:

  • 使用 ELB 增加多台前端,多台机器并发请求
  • 每台机器增加线程数(当然要在内存的允许范围内),但是加到一定程度也就足够了(毕竟带宽是有限的)
  • 在后端对数据进行压缩,在前端进行解压缩,这样就减少了需要网络传输的数据

(这部分策略我还没有具体尝试,因为用下面的方法已经满足要求了)

后台数据库和前台缓存实际上类似于 Memory Hierarchy,需要利用看似不大存在的 Locality 来获得最快的访问速度(经过测试如果缓存命中基本上可以认为是无延迟)。这里的 Locality,可以认为是具体流量模式的 Locality,而并非是在数据库中顺序访问。

有缓存,那么肯定就有预热,预热的重要性在于,把常用的记录缓存下来,具体缓存要多大呢?我也不知道,反正可能情况下,越大是越好的(这就是为啥最好开一个内存优化的机器,比其他系列多一倍内存)

最后说一下数据库的参数优化,不知道是不是 Amazon EMR 本身根据不同的配置会进行一定的优化,我并没有改动 HBase 的任何设置。这里的问题在于,因为刚接触 HBase,很多内容不熟悉,所以看着网上的教程瞎折腾很容易弄巧成拙,在优化的时候,一定要确定每一步都清楚自己在干嘛,不然就会出现自己以为正确的错误,而这种错误往往是最难解决的(因为自己压根不知道错了)

总结

总体来说,这次的任务还是很有趣的,我也已经意识到了优化真心是一个牵一发动全身的问题,还是要有更加清晰的大局观和思路,才不至于迷失方向。不过话说回来,遇到不懂的问题,最好的方法是停下来,把相关的概念都捋一遍(比方说官方文档就不错),思考具体的问题所在,大胆假设小心验证,才更能找到令自己满意的答案。

另外,对于分析 web 服务的各类工具一头雾水(甚至都不知道有啥),还是得抽空研究一下,不然依靠手动输出计算时间效率太低,得到的数据可能也不准确。

捧个钱场?