面向海量服务的设计原则和策略总结

来源:互联网 发布:尤伦斯艺术商店淘宝 编辑:程序博客网 时间:2024/06/10 05:08

 

      互联网服务的特点就是面向海量级的用户,面向海量级的用户如何提供稳定的服务呢?这里,对这几年的一些经验积累和平时接触的一些理念做一个总结。
      一、原则
      1.Web服务的CAP原理
      CAP指的是三个要素:一致性(Consistency)、可用性(Availability)、分区容忍性(Partition tolerance)。CAP原理指的是这三个要素最多只能同时实现两点,不可能三者兼顾,对于海量级服务,一般这是一条常记心中的基准准则。
      如下是《Web服务的CAP 》关于CAP的定义:

      面向海量级的分布式服务设计,基本上分区容忍性(Partition tolerance)是第一要素,因此根据业务的情况,我们需要在一致性(Consistency)和可用性(Availability)之间做取舍。对于一些业务,譬如支付宝或财付通,一致性会是第一考虑要素,即使是延迟的不一致也是不可接受的,这种时候只能牺牲可用性以保证一致性。对于一些应用,譬如淘宝或拍拍交易中的评价信息,一般用户是可以接受延迟的一致性,这种时候可以优先考虑可用性,而用最终一致性来保证数据一致,譬如通过某种对帐机制。对于一些应用,甚至一致性都并非要求,只需要保证差不多一致性即可,譬如Q-zone中的农场游戏中的偷菜。
      根据我们应用的业务需求,选择合适的一致性级别,以更好地保证系统的分区容忍性和可用性。
      2.柔性可用
      面向海量级的分布式服务设计,我们要意识到,一切都是不可靠的,在不可靠的环境的环境中构建可靠的应用,其中最重要的一点就是保持系统的柔性。
      1)不可靠的环境
      我们可能已经见惯一个远程服务提供不了服务了,运行一段时间后WebServer突然不响应了,数据库随着负载的不断增加再放上一条SQL语句就会垮掉。但是,硬盘坏掉、电源断掉、光纤中断,听起来似乎多么不可思议,然而,当一个海量服务需要成千上万台服务器、需要部署全国各地的数十个数据中心、需要横跨电信网通教育网三大网络的时候,一切听起来不可思议的事情会变成常态。一切都是不可靠的,唯一可靠的就是不可靠本身。
      2)划分服务级别
      我们应该意识到,在这种不可靠的环境中提供完美的服务,本身就是一个神话,即使不是说完全不可能,但至少是代价高昂的,因此,当某些问题发生(环境变地不可靠的时候),我们必须做出取舍,选择为用户提供用户最关心的服务,这种服务虽然听起来是有损的(至少是不完美的),但却能在一定程度上满足用户大部分的需求。譬如,当网络带宽无法为用户提供最好的体验而扩容又不是短期可以达到的时候,选择降低一些非重要服务的体验是一个比较好的选择。
      在面向海量互联网的设计当中,对服务进行分级,当系统变地不可靠的时候,优先提供重要优先级的服务。
      3)尽快响应
      互联网用户的耐心是非常有限的,如果一个页面需要3秒以上才能看到,也许大部分用户的第一选择就是关掉浏览器。在构建柔性可用的互联网服务的时候,响应时间大部分情况下都是需要最优先考虑。还是一句话,环境是不可靠的,当我们无法尽快从远程服务获得数据、当数据库已经慢如蜗牛,也许当后台还在吭哧吭哧干活的时候,用户老早已经关闭了页面,处理返回的数据也只是在浪费表情,面向互联网用户,响应就是生命。
       二、策略
       如何让我们的应用提供更高质量的服务呢,这里是一些在日常开发使用到或者观察到的一些策略的总结:

       1.数据sharding
      海量服务相应也意味着海量的用户和海量的用户数据,大家都知道,即使是再强大的数据库、再强大服务器,在单表上亿规模的数据足够让一条简单的SQL语句慢如蜗牛(甚至于在百万、千万级别上,如果没有采取合适的策略,都无法满足服务要求),一般处理这种千万上亿级数据的大家基本上都会想到的就是数据sharding,将数据切割成多个数据集,分散到多个数据库的多个表中(譬如将用户数据按用户ID切割成4个数据库每个数据库100个表共400个表),由于每个表数据足够小可以让我们的SQL语句快速地执行。而至于如何切割,实际上跟具体的业务策略有关系。
       当然,我们要认识到,这种数据sharding并非全无代价的,这也意味着我们需要做出一些折中,譬如可能很难进行跨表数据集的查询、联表和排序也变地非常困难、同时数据库client程序编写也会变地更加复杂、保证数据一致性在某些情况下会变地困难重重。sharding并非万能药,选择是否sharding、如何sharding、为sharding如何换用一个近似的业务描述方式,这是业务设计需要仔细考虑的问题。
       2.Cache
       经验会告诉我们,基本上大部分系统的瓶颈会集中在IO/数据库上,常识也告诉我们,网络和内存的速度比IO/数据库会提升甚至不止一个数量级。面向海量服务,Cache基本上是一个必选项,分布式Cache更是一个不二选择,根据我们的需要,我们可以选择memcached(非持久化)、memcachedb/Tokyo Tyrant(持久化),甚至构建自己的cache平台。
       在使用Cache上,下面是需要仔细考虑的点:

       3.服务集群
       面向海量服务,系统的横向扩展基本上是第一要素,在我的经验和经历中,服务集群需要考虑如下因素:

      4.灰度发布
      当系统的用户增长到一定的规模,一个小小功能的发布也会产生非常大的影响,这个时候,将功能先对一小部分用户开放,并慢慢扩展到全量用户是一个稳妥的做法,使用灰度化的发布将避免功能的BUG产生大面积的错误。如下是一些常见的灰度控制策略:

      5.设计自己的通信协议:二进制协议、向上/下兼容
      随着系统的稳定运行访问量的上涨,慢慢会发现,一些看起来工作良好的协议性能变地不可接受,譬如基于xml的协议xml-rpc,将会发现xml解析和包体的增大变地不可接受,即便是接近于二进制的hessian协议,多出来的字段描述信息(按我的理解,hessian协议是类似于map结构的,包含字段的名称信息)和基于文本的http头将会使协议效率变地低下。也许,在开始合适的时候而不是到最后不得已的时候,去设计一个良好的基于二进制的高效的内部通信协议是一个好的方式。按我的经验,设计自己的通信协议需要注意如下几点:

      6.设计自己的Application Server
      事情进行到需要自己设计通信协议,自己构建Application Server也变地顺理成章,下面是在自己开发Application Server的时候需要处理的常见的问题:

       7.Client
      很多应用会作为服务的Client,去调用其他的服务,如下是在做为Client应该注意的一些问题:

      8.监控和预警
      基本上我们会见惯了各种网络设备或服务器的监控,譬如网络流量、IO、CPU、内存等监控数据,然而除了这些总体的运行数据,应用的细粒度化的数据也需要被监控,服务的访问压力怎么样、处理速度怎么样、性能瓶颈在哪里、带宽主要是被什么应用占、Java虚拟机的CPU占用情况怎么样、各内存区的内存占用情况如何,这些数据将有利于我们更好的了解系统的运行情况,并对系统的优化和扩容提供数据指导。

      除了应用总体监控,特定业务的监控也是一个可选项,譬如定时检查每个业务的每个具体功能点(url)访问是否正常、访问速度如何、页面访问速度如何(用户角度,包括服务响应时间、页面渲染时间等,即网页测速)、每个页面的PV、每个页面(特别是图片)每天占用的总带宽等等。这些数据将为系统预警和优化提供数据上的支持,例如对于图片,如果我们知道哪些图片占用的带宽非常大(不一定是图片本身比较大,而可能是访问比较大),则一个小小的优化会节省大量的网络带宽开销,当然,这些事情对于小规模的访问是没有意义的,网络带宽开销节省的成本可能都没有人力成本高。
      除了监控,有效的预警机制也是必不可少,应用是否在很好地提供服务、响应时间是否能够达到要求、系统容量是否达到一个阀值。有效的预警机制将让我们尽快地对问题进行处理。
      9.配置中心化
      当系统错误的时候,我们如何尽快地恢复呢,当新增服务节点的时候,如何尽快地让真个系统感知到呢?当系统膨胀之后,如果每次摘除服务节点或者新增节点都需要修改每台应用配置,那么配置和系统的维护将变地越来越困难。
     配置中心化是一个很好的处理这个问题的方案,将所有配置进行统一地存储,而当发生变更的时候(摘除问题节点或者扩量增加服务节点或新增服务),使用一些通知机制让各应用刷新配置。甚至于,我们可以自动地检测出问题节点并进行智能化的切换。
      三、最后
      构建面向海量用户的服务,可以说是困难重重挑战重重,一些原则和前人的设计思路可以让我们获得一些帮助,但是更大的挑战会来源于细节部分,按我们技术老大的说法,原则和思路只要看几本书是个技术人员都会,但决定一个系统架构师能力的,往往却是对细节的处理能力。因此,在掌握原则和前人的设计思路的基础上,更深入地挖掘技术的细节,才是面向海量用户的服务的制胜之道。

原创粉丝点击