技术头条 - 一个快速在微博传播文章的方式     搜索本站
您现在的位置首页 --> 系统架构 --> 有损服务-不完美主义者的胜利

有损服务-不完美主义者的胜利

浏览:3798次  出处信息

    前言:这是我最近在公司内部分享的一篇文章,大家反响比较强烈,所以也分享到博客里来。

    一转眼,来公司已经三年多了。

    这三年里,所属部门在变,地理位置在变,技术也日新月异,但是有很多设计原则却是一直不曾改变的,而这次就是我用自身的实践来谈谈我对其中的一个的理解---有损服务。

    记得当年qwang用一个很形象的比喻来解释有损(原话记不太清楚了):

    比如一个人在沙漠里迷失了寻找水源,那么在他还能走的时候,就尽量走;实在走不动了,用爬的;最后爬也爬不了了,起码要保证自己活着。

    所以我们从这个比喻中起码可以获得如下几个信息:

  • 问题时,优先保证关键功能
  • 非关键功能不可以影响关键功能
  • 在条件允许的情况下,损失越少越好
  •     接下来就从自己印象比较深刻的有损服务项目讲起吧。

        

         一、空间应用列表有损服务优化

        

        想当年,苍井空还是处女,玛利亚还姓圣母。好吧,扯远了,想当年第一款国民级应用《QQ农场》横空出世,其空前的火爆导致空间个人中心应用列表的农场图标变得如此重要。

        然而由于各种网络等各种原因,这个列表的展现总是会有一定的失败率,而且只要稍微失败就会招来大批用户的投诉。

        我们分析一下这个模块的功能:

  • 正常功能:正常展示用户已经安装的应用列表
  • 关键功能:正常展示用户最关心的基础应用(如日志)、火爆游戏(农场)等的应用列表
  •     于是优化开始了……

        

         Step1. 应用信息本地cache

        

        由于应用列表第一个要获取的就是应用自身的信息(包括URL,名称等),而这部分数据本身又是较为固定的,所以就直接cache在了webserver本地。一旦当网络拉取应用信息失败时,就会使用本地的存储。

        这样做了之后,其实严格来说体验上并没有任何损失,但这才是第一步。

        

         Step2. 忽略过滤已安装应用列表失败

        

        接着我们发现过滤已安装应用列表接口也存在一定的失败,之前采取了简单而粗暴的方式,一旦报错则直接返回。

        然而后来我们考虑到,如果这个时候我们返回一个默认应用列表,同时在这个默认列表中加入那些平台基础应用和火爆应用(农场),是不是体验会更好呢?

        再然后我们尝试了,确实证明了这样带来的效果更好。对比一下:一个是想玩农场找不到入口;一个是没装过农场,但是看到了农场的应用图标。高下立分。

        这是体验的第一次降级,我们尝到了甜头。

        

         Step3. 前台协助

        

        但是我们很快发现,只有上面的方案是不行的。

  • CGI在调用后端接口时,如果接口超时,很可能会导致CGI超时,而前台JS此时很可能还没有等到CGI的默认应用列表返回就已经向用户报错了。
  • 由于网络问题、webserver异常等原因,CGI没有接收到请求,也会导致默认应用列表获取失败。
  •     所以我们马上联系前台同学优化了两个逻辑:

  • JS调用CGI的等待超时,与CGI调用后台接口的超时对应
  • 一旦CGI超时返回,则在前台也会存储有一份默认的应用列表,直接展示给用户
  •     在这里,我们把有损的设计从后台延伸到了前台,并再次证明好的设计一定是前后台共同实现的~再次感谢当年鼎力相助的晓晓同学~

        

         Step4. 闭环

        

        然而,有损服务毕竟是对体验有影响的,此时如果不对用户做好提示和限制,就会导致用户使用很多功能报错,反而还会增加投诉的数量。

        比如用户如果在有损的情况下去编辑应用列表,或者添加应用都会报错,如果没有限制又没有合适的提示,用户很可能会认为自己数据丢失,招来投诉。

        所以我们又做了几件事:

  • 有损时优化对用户的提示,告知数据可能不准确
  • 限制写操作,如编辑,添加应用,都被禁止,并明确提示原因
  •     OK,到了这里,应用列表的整个有损服务优化就基本告一段落了。虽然后来我们优化了server,提高了成功率,但这里的有损逻辑却被永远的保存了下来,毕竟,什么样的系统能完全没有错误呢?

        也正因为有这个项目的铺垫,为我后来做OpenAPI设计时的有损奠定了根基。

        

         二、OpenAPI有损服务优化

        

        OpenAPI是平台与应用之间沟通的桥梁,因此对可用性的要求极高,因此当部分功能出现问题时,保证有损服务,也就是必然的事情。

        先来简单看一下OpenAPI的架构图吧(这个之前在QCon已经分享,所以不算泄密~):

        1

        当请求进入OpenAPI接口机的时候,接口机会根据参数、URL分别将请求转发到对应的业务CGI,之后再经由接口机返回给调用方。

        所以我们再次开始有损优化之旅:

        

         Step1. 业务之间互相屏蔽

        

        从描述可以看出,由于不同业务的CGI都挂载在接口机上,所以一旦某一个业务出现问题时,势必会影响到其他业务。

        所以我们对每个业务都分配了单独的L5 ID,当失败量或者超时量太高时,webserver的IP分配就会失败,从而保证业务之间不会受到相互影响。

        

         Step2. CGI运行最长超时设置

        

        刚才提到OpenAPI对性能的要求极高,所以要求CGI都能尽快的返回,否则就会被Step1里面的技术打击到。

        但是具体怎么做呢?

        我们将有损服务具体化为一个CGI设计原则:

        在能容忍的最长时间内,将最重要的事做完

        比如下图:

        1

        当我们执行到3的时候,发现CGI的运行时间已经太长了(比如超过1秒),那么为了避免其他请求被堵死,我们就直接直接返回给调用方了。

        这个时候虽然数据不是完整的(丢了4的数据),但是我们在数据完整和快速响应之间做了一个平衡。

        这样就保证了在服务出现问题的时候,大部分的应用还是可以正常使用,只是体验上稍微差一点。

        

         Step3. 智能调整最长超时时间-EMA算法

        

        但是我们很快发现,仅仅做到这里还是不够的,我们刚才提到了能容忍的最长响应时间,但是这个最长响应时间的值怎么指定呢?

        如果指定的很长,比如1秒,那么一旦出现问题的时候,相当于每个进程每秒钟只能处理一个请求,根本没有达到我们预期的容灾的效果。

        但如果指定的很短,比如20毫秒,那么一旦出现一次偶然的网络波动,即使很快会恢复也会导致我们的OpenAPI大面积失败。

        这两种设置方法都不完美,那么还有什么办法呢?

        那就是EMA算法,公司之前将预测股票走势的EMA算法引入来预测CGI运行时间的变化,而EMA的一个核心原则就是:

        当CGI运行时间越短的时候,给CGI设置的最长超时时间越长;当CGI运行时间越长的时候,给CGI设置的最长超时时间越短。

        如下图所示:

        1

        可以看出平均响应时间和动态超时时间基本是沿响应时间上限 对称的关系,很直观的描述了这两者之间的关系。

        所以到此为止,有损服务才能真正的发挥作用。

    建议继续学习:

    1. WEB系统需要关注的一些点    (阅读:14109)
    2. 30分钟3300%性能提升――python+memcached网页优化小记    (阅读:12129)
    3. 基于SSD的数据库性能优化    (阅读:7412)
    4. jQuery性能优化指南    (阅读:7325)
    5. 一次简单C程序的性能优化    (阅读:5598)
    6. mysql sql 百万级数据库优化方案    (阅读:5058)
    7. 一次神奇的MySQL优化    (阅读:4895)
    8. PHP最佳实践    (阅读:4955)
    9. Linux 64位, MySQL, Swap & Memory 优化    (阅读:4482)
    10. PHP 性能优化技巧-google    (阅读:4416)
    QQ技术交流群:445447336,欢迎加入!
    扫一扫订阅我的微信号:IT技术博客大学习
    © 2009 - 2024 by blogread.cn 微博:@IT技术博客大学习

    京ICP备15002552号-1