降低应用latency方法谈

上个月发的谈团队每周技术交流引起不少同行感兴趣,如果那篇文章能起到促进业界公司内部技术交流那就是最大的贡献了。

上周五我们继续内部技术讨论,对某Java Web应用进行了latency分析。Latency主要是分析一个URL高并发请求下消耗时间的分布,比如ab(ApacheBench)输出结果最后一段

Percentage of the requests served within a certain time (ms)
  50%      5
  66%      6
  75%      6
  80%      6
  90%      7
  95%      8
  98%     10
  99%     18
 100%     92 (longest request)

表示99%的调用是在18ms返回的,从结果来看latency比较低,反映相应URL的性能是比较理想。

这次技术讨论首先是情况介绍,测试工程师介绍了主要URL从本地IDC到全国的latency的分布图。另外DBA也从数据库的角度介绍了DB层面常见的latency来源。这样会后我们可以对最明显的问题进行优化和改进。

除去通用的问题之后当然是讨论方法,程序员关注的重心大部分还是从应用层面怎么降低latency。

压力测试

很多Web开发的朋友也经常讨论Web应用如何有效的进行压力测试,目前也没有万能的方法。可以使用的工具有loadrunner, 或者Erlang语言开发的tsung等,很多公司也有自己的内部工具。HTTP/Memcache/MySQL等协议压力测试其实相对简单,通常用自己脚本或者高级语言开发的工具比起通用工具来说效果会更佳。

profiling

对接口进行Profiling是发现瓶颈最直观的方法,Google据说就有很完善的内部profiler工具(当然Google内部什么工具都有)。我们讨论了目前不同开发人员使用的profiling方法的优缺点。

  1. 直接使用专业工具,比如JProfiler, 还有Java自带的JVisualVM等。
  2. AOP(Aspect-oriented programming)的方式,优点是对程序没有污染,在外部配置需要profiling的方法。
  3. 工具类的方法,需要在service方法前后加入小量关键点,优点是纯Java的实现,可以运行时动态打开或关闭profiler。比如通过给进程发signals的方法(见Signals and Java)动态让程序输出当前运行情况,起到了能够动态profiling服务器但在正常情况下又不影响服务器性能的作用。

从讨论情况来看大部分开发人员还是倾向于方法3,我们也希望团队能逐步建立类似Google内部profiler之类自己的工具。

Memcache mutex设计模式

周六的S2 Web 2.0技术沙龙上介绍了memcache中使用mutex场景(文后要演讲稿),有网友对详情感兴趣,简单介绍如下。

场景

Mutex主要用于有大量并发访问并存在cache过期的场合,如

  • 首页top 10, 由数据库加载到memcache缓存n分钟
  • 微博中名人的content cache, 一旦不存在会大量请求不能命中并加载数据库
  • 需要执行多个IO操作生成的数据存在cache中, 比如查询db多次

问题

在大并发的场合,当cache失效时,大量并发同时取不到cache,会同一瞬间去访问db并回设cache,可能会给系统带来潜在的超负荷风险。我们曾经在线上系统出现过类似故障

解决方法

方法一
在load db之前先add一个mutex key, mutex key add成功之后再去做加载db, 如果add失败则sleep之后重试读取原cache数据。为了防止死锁,mutex key也需要设置过期时间。伪代码如下
(注:下文伪代码仅供了解思路,可能存在bug,欢迎随时指出。)

if (memcache.get(key) == null) {
    // 3 min timeout to avoid mutex holder crash
    if (memcache.add(key_mutex, 3 * 60 * 1000) == true) {
        value = db.get(key);
        memcache.set(key, value);
        memcache.delete(key_mutex);
    } else {
        sleep(50);
        retry();
    }
}

方法二
在value内部设置1个超时值(timeout1), timeout1比实际的memcache timeout(timeout2)小。当从cache读取到timeout1发现它已经过期时候,马上延长timeout1并重新设置到cache。然后再从数据库加载数据并设置到cache中。伪代码如下

v = memcache.get(key);
if (v == null) {
    if (memcache.add(key_mutex, 3 * 60 * 1000) == true) {
        value = db.get(key);
        memcache.set(key, value);
        memcache.delete(key_mutex);
    } else {
        sleep(50);
        retry();
    }
} else {
    if (v.timeout <= now()) {
        if (memcache.add(key_mutex, 3 * 60 * 1000) == true) {
            // extend the timeout for other threads
            v.timeout += 3 * 60 * 1000;
            memcache.set(key, v, KEY_TIMEOUT * 2);

            // load the latest value from db
            v = db.get(key);
            v.timeout = KEY_TIMEOUT;
            memcache.set(key, value, KEY_TIMEOUT * 2);
            memcache.delete(key_mutex);
        } else {
            sleep(50);
            retry();
        }
    }
}

相对于方案一
优点:避免cache失效时刻大量请求获取不到mutex并进行sleep
缺点:代码复杂性增大,因此一般场合用方案一也已经足够。

方案二在Memcached FAQ中也有详细介绍 How to prevent clobbering updates, stampeding requests,并且Brad还介绍了用他另外一个得意的工具 Gearman 来实现单实例设置cache的方法,见 Cache miss stampedes,不过用Gearman来解决就感觉就有点奇技淫巧了。

附:本次Web2.0技术沙龙演讲主题:微博Cache设计谈,需下载请点击演讲稿下menu/download (需登录slideshare)。

谈团队每周技术交流

最近在微博上提到了每周五进行一次内部的技术交流,方法也在不断的改进中,目前情况分享如下。希望也能听到一些更好的建议。

内容选取

大部分都是接近工作的,比如应用层如何访问cache及db、当前项目的重构或某个复杂的算法等。比如一个重构的话题让大家找出项目中目前不合理的若干问题,并分析这些问题存在的历史原因。然后大家分别发表自己认为合适的解决方案并进行讨论。

可以取得的成效

  • 团队成员取长补短,获得更全面的技术
  • 分享经验,避免成员步入已知的雷区
  • 提高分析技术问题的能力
  • 认识不足,找到自己需要提高的方向
  • 达成团队更多共识,比如什么是好的做法什么是不推荐的做法

后续主题

以后可以进一步考虑的讨论主题,最大的原则是考虑跟近期项目有相关性,比如

  • 互联网应用合适的压力测试方式
  • profiler 系统性能分析,热点调用的主要消耗点并提出解决方案。
  • 工具介绍,可以提高效率或者对工作有帮助
  • 某个算法,如粉丝排序

与code review的区别

code review关注代码细节, 团队讨论更关注宏观抽象层面的问题,但部分时候团队讨论也进行一些有代表意义的code改进。

与主题演讲区别

倾向于圆桌式的讨论,需要大家参与的开放式问题。以前也尝试过主题式的,但是由于团队内的主题演讲空间有限,演讲者可能要先精通某个领域才适合讲,如果每周一轮不太可行,比如Facebook Engineering tech talks也是精英演讲的方式,结果也不是非常活跃。因此每周一次更合适讨论一些跟工作相关未达成共识的话题,这样更敏捷,也更容易给参与者带来成效。

-EOF-

广告:我们团队招收各层次技术人才,包括Java后端工程师,数据架构师(MySQL),PHP工程师, 数据挖掘工程师(如精通Hadoop)等,工作地点是北京,有兴趣可以直接给我邮件。

上次提到的Web 2.0技术沙龙已经与CSDN顺利举行了第一期,由于之前报名的已经非常多,就未在博客上宣传了,第一期活动今天已经结束。