分区
EBay的首席构架师Randy Shoup提出的EBay构架的三大战略,第一个就是在系统所有层次全面分区(其他两个是全面使用异步调用,全面自动化)
将问题分解成可以解决的小块,是实际生活中常用的策略。对相同事务的分区在大型项目中必不可少。比如世界上最长的京沪高铁,总长度2240公里,土建工程施工中分区为六个标段,由不同公司同时承建。分区的另一种表现是对不同服务的分区;比如你去车管所办理驾照手续,车管所根据换证,新证等不同业务设立不同窗口,提高了事务处理效率。对相同事务的复制,也是分区的一个策略。比如为了进一步提高业务处理能力, 车管所同时给业务量比较大的工作分配更多的窗口。 业界有一个流行的说法: 不能分解的问题 , 是没有可扩展性可能的问题。
2000年左右, 我在位于硅谷的一家生物信息的先驱公司做基因库的序列分析。公司租用超级计算机的费用占据了公司整个运行成本很大部分。为了处理越来越大的计算量,同时控制计算成本,生物信息及计算生物学领域开始使用普通计算机的集群来出来大规模计算问题。这种廉价的获得更高的计算能力的策略在工业界也非常明显。有一个很形象的叫法: 向外扩展(Scale Out,Not Scale Up)。分区技术是横向扩展的实现。
将任务分散处理,是系统获得可扩展性的关键。 Shoup指出在EBay使用的分区的模式分两种 : 对不同事务的功能细分和对相同事务的水平横向分割。Abbot和Fisher 加入了对相同事务的复制的策略, 提出 将任务分散处理的AKF扩展方块的概念。
|
对不同事务的功能细分 |
对相同事务的水平横向分割 |
对相同事务的复制 |
无扩展性的单一系统 |
无 |
无 |
无 |
|
|
|
|
近无限可扩展性系统 |
有 |
有 |
有 |
系统分区在很多方面提高了系统的质量。在提高系统可用性一节中,我们讨论了将系统分区在传统软件工程学上的意义:降低了系统内部的全局的关联性,从而降低了系统的复杂度。对不同事务的功能细分,降低不同功能区之间的依赖性后, 也便于程序代码的分区,有利于开发小组之间的独立和程序员开发的效率(不需要成为
系统各个组件的专家), 提高了系统的可管理性。同时分区可以防止出错危害扩大,避免SPOF,提高了系统的可用性。
对于可扩展性而言,分区的优点是系统可以不断加入相对便宜的硬件,独立水平扩展(Scale Out)。
(一) 对不同的数据按照功能细分(功能细分)
无论是基于服务的SOA还是基于资源的ROA,构架设计的理念是提供用户各种操作以获得用户需要的结果。无论操作的对象是服务还是资源,各种操作之间具有相互的独立性。
对于电子商务而言,可以把系统功能细分为用户帐户管理,商品库存管理,交易管理等,与之对应的在数据库水平把把数据库细分为不同的功能区(用户,商品,交易,帐户等), 这样就可以用户对特定功能区的使用模式,负载来决定各个功能去的资源分配。
各个功能区的数据是相互独立的,这就要求在数据库的数据模式设计时,使用用标准数据库的建模技术(数据基数,数据关系 )把数据库表分离。那么如何处理需要涉及到不同功能区的请求呢? 首先,在设计上要尽可能的避免这种需要,在技术实现上的困难和满足商业价值之间平衡; 如果是一些具有很高商业意义的要求呢? 比如零售网站上基于用户购买/浏览历史记录而推荐的商品名录, 涉及到交易记录 和商品两个不同功能分区,和一定的计算量;好在推荐内容本身就不是严格精确,并且没有严格的实时要求,可以将推荐的商品名录的计算任务放在后台的批处理,异步执行得到答案,并储存在特定的数据库中。当用户登录时, 客户端可以直接从数据库中查询已经计算好的推荐结果。
(二) 对相同的数据主要的查询路径细分(水平横向分割)
对于业务发展迅速的公司,客户,交易记录增加非常快。而数据库表过于庞大直接影响查询更新的效率。尤其是直接面对用户Web请求的服务,请求处理的速度很大程序取决于缓存命中率的大小,而缓存的大小有限,数据库表的数据越多, 可以装入缓存的数据的百分比越小,缓存命中率越低。
对相同的数据的分区又叫做碎片化(Sharding)。 碎片化策略基于不同的用例而各有不同。比如可以对主关键字(商 品ID,用户ID)取模 , 如果主键是自动增量,可以保证数据在各个分区的均衡的分布; 博客网站往往提供基于日历的浏览界面,用户对博客文章的查询模式往往是基于时间段。可以按时间段对数据分区,每个分区包括一个月的数据, 每个月加入一个新的分区碎片。
对于用户交易记录而言, 简单的对用户ID取模虽然可以保证用户数目在各个分区的均衡分布,但是各个用户的交易活跃程度不同,交易记录量差别很大, 不能保证不同分区碎片的交易记录的均衡。基于80/20法则,也许20%的用户产生80 %的交易记录。 一种方式是希望把最活跃的用户(往往也是最有商业价值)映射到高性能硬件支持的分区上,这就需要对分区映射有更多的控制。方法是使用一个查询表(Master Lookup)。Abbott和Fisher提到过另一个策略:把最活跃的用户平均分配到所有分区。
数据分区中还有一个特例, 就是对于一些相对变化不大,却经常使用的数据,(比如商品代码等)放入一个全局表,每个分区碎片都保存全局表的一份拷贝。这样可以提高避免一些跨碎片的查询,提高效率。
上面提到的分区策略是在数据库/服务层的。在应用程序层的构架中,因为一场对话的流程可能涉及几种不同的服务,流经多个应用程序池, 如果每个服务需要记住对话的中间结果,将增加服务之间的偶联。为了实现分区,就需要无对话状态的应用程序层。 分区的策略包括: 将程序按不同功能分离在不同的程序池,这样可以减少资源依赖, 同时支持并行的开发,部署 和 监测。 而在在同一个程序池中,所有的应用服务器提供的服务都相同。
模式名称: 对不同事务的功能细分
描述: 对不同的数据按照功能细分(功能细分)
动机/试图解决问题: 分区策略
原理: 基于服务/功能的不同,数据之间往往相互独立。分区降低了系统复杂度,便于开发管理,提供了可扩展性。
使用:
相关模式:
模式名称: 对相同事务的水平横向分割
描述: 对相同的数据主要的查询路径细分(水平横向分割)
动机/试图解决问题: 分区策略
原理: 对于相似的数据按照查询路径碎片化,减少了每个数据分区碎片的大小,进而提供了高可扩展性。
使用:
相关模式:
总结:
将任务分散处理,是系统获得可扩展性的关键。分区的基本模式有两种 : 对不同事务的功能细分和对相同事务的水平横向分割。
本文出自 “静水流深” 博客,转载请与作者联系!