论文原本结构,个人感觉有些不符合中文阅读习惯,所以在保持原文翻译的基础,分阶段做了目录。这个版本是一个更新和缩写版的论文,在2007年使用同样的名字首次发表在CIDR(数据库研究创新会议)上,内容和原版基本相同。不同于第一版本,在这个版本中作者首次提出了TCC(Tentative Operations, Confirmation,and Cancellation)的概念。译文全文3万字左右,还是耐心看几遍吧,作者提出的一下假设,发表的观点,做出的推论细看其实很有价值。
PAT HELLAND
本文是一个更新和缩写版的论文,在2007年使用同样的名字首次发表在CIDR(数据库研究创新会议)上。
一、介绍
事务是非常强大的机制,在我将近40年的职业生涯中,我把大部分时间都花在了这上面。1982年,我第一次尝试在串行系统上支持事务特性。这个系统的平均故障间隔时间以年为单位,并且地理分布的两阶段提交为强一致性事务提供了优秀的可用性。
新的创新,包括谷歌的Spaner,在高可用超大规模环境下提供强一致性事务。 构建分步式事务来支持高可用应用是一个巨大的调整,它需要卓越的创新和顶端的技术。不幸的是大部分研发人员都没有这样的条件。
在大多数分布式事务系统中,单节点失败会导致整个事务停止提交,反过来会导致应用程序阻塞。这样的系统中,系统规模越大,就越有可能崩溃。 例如,当你驾驶一架需要它的所有发动机工作,但是添加引擎会降低飞机的可用性。如果没有特殊的终端容忍机制,要想在一个拥有超过千个阶段的系统上运行分布式系统是不切实际的。当应用程序开发人员使用非高可用性分布式事务构建系统时,这个结局方案非常脆弱,并且必须被丢弃。取而代之的是,应用程序应该重点关注业务需求是否得到满足,而不是保证事务。
本文探索并列举了一些实用的方法用于在不需要提供分布式事务环境下的任务关键型下的大规模系统实现。讨论包括随着应用增长需要重新分区的细粒度应用程序数据块的管理,以及支持在这些可重新划分的数据块之间发送消息的设计模式。
目标是减少研发人员构建大型可扩展系统所面临的挑战,另一方面,通过了解这些模式,希望业界能够构建这样的平台简化这些大型应用的构建工作。
二、目标
本文的重点是应用程序开发人员如何在只有本地数据库事务系统可用的情况下成功的构建可伸缩的企业级应用程序。 本文没有关注可用性的解决方案,重点是关注应用系统的可伸缩性和正确性。
*关于可伸缩应用程序的讨论
大多数可伸缩应用程序的设计者都能理解业务需求,问题是对这些事务交互和可伸缩系统的问题、概念、总结等,没有命名没有清晰的理解。当这些信息不一致时,有时甚至还会反咬设计师一口。这篇文章的目的之一就是发起一个讨论,加强对这些概念的了解,希望促成一系列的共识和一致的实现方案。
*考虑应用无限伸缩性 Think about Almost-Infinite Scaling of Applications
为了勾画这个伸缩方面的讨论,文章提出了一个非正式的(informal)实现无限伸缩的思考方案(thought experiment)。我假设客户、可采购实体(purchasable entities)、订单、发货(shipments)、保健病人、纳税人、银行账户,以及应用程序中使用到的其它所有业务概念,他们的数量都随着时间高速增长,但单个数据块并不会变得太大,我们只是获得了越来越多的数据块而已。计算机的哪种资源会首先过载真的不重要,需求的增长只是促使我们一开始使用少量机器运行转而使用大量机器来运行。
无限伸缩是一种随意、含糊、笼统的说法,在不清楚什么时候一台机器足够,如果不确定一台机器是否足够时该如何处理的情况下,使得我们的需求变得非常明确。当然,以N-log-N的速度伸缩,再加上一个大的log,那就太棒了。
*介绍可伸缩应用程序的常见模式
无限伸缩对业务逻辑有什么影响?我假设实现伸缩时我们在程序中需要使用一个叫做"实体"的新概念。实体在某个时刻位于单一机器上,应用程序同一时刻只能操作一个实体。无限伸缩的结论是这个编程概念必须暴露给应用逻辑的开发者。
提出和讨论这个目前还没有正式命名的概念,是希望我们达成一致的程序实现方式,以及对构建可伸缩系统涉及的问题达成一致的理解。
此外,实体的使用涉及连接实体的消息模式,应用程序开发者试图为业务问题构建可伸缩解决方案时必须处理消息分发的一致性问题,我们创建状态机来处理这些方面。
三、提出假设
这部分我们考虑以下三个假设,它们是正确的,但是还没有被证明,我们基于经验假设它们是正确的。
*应用程序的层次和规模不可知
让我们首先假设每个可伸缩的应用程序至少有两层(如图1所示)。这些层的可扩展性在感知上是不同的,当然他们可能有其他的差异,但这些与我们的讨论无关。应用程序的底层可以理解为通过添加更多的计算机以使系统具有可伸缩性。
声明:图片均为论文中的原图,水印为系统自加的。
除此之外,它管理上层的代码到物理机器和位置的映射关系,底层是伸缩相关(scale-aware)的即它们了解这个映射关系。我们假设底层为上层提供了一个伸缩无关的(scale-agnostic)编程抽象,使用它编写应用程序上层代码时无需考虑伸缩问题。遵守伸缩无关的编程抽象我们就能编写应用程序代码,而不用担心将应用程序部署在前所未有的负载增长环境下带来更改。
随着时间推移,这些应用程序底层可能发展为新的平台或中间件,简化伸缩无关应用程序的创建。
*事务作用域
关于在分布式系统提供事务强一致性这个概念已经做了大量的学术工作,例如2PC(两阶段提交)在某节点不可用时容易阻塞,而其它协议例如Paxos算法,在节点失败时不会阻塞。这些算法可以被描述为提供分布式系统上的强一致事务。他们的目标是对数据更新的任意原子操作可以跨机器传播。 更新存在于跨越多台机器的单个事务范围中。
不幸地是,在许多情况下,这不是一个应用程序开发人员的能选择的。应用程序可能需要跨越信任界限,不同的平台,不同的操作和部署区域。怎么办呢,难道您对分布式事务“说不”吗?
即使在今天,在这篇论文发表10年之后,真正的系统开发人员很少尝试去在超过一台机器的系统上实现强一致性的事务。相反,他们假设多个独立的事务作用域。每台计算机是一个包含本地事务单独的作用域。
*大部分应用使用"至少一次"的消息方式
TCP-IP对于象Unix形式的短周期(short-lived)进程非常好(译注: 连接建立过程有询问、应答),但我们看一下一个需要处理消息,修改磁盘上一些持久化数据(SQL数据库或其它持久化仓库中)的应用开发者面临的问题。消息接收后不会立即应答,需要等待数据库处理完毕。如果失败,这个过程需要重新开始,再次处理这个消息。
问题产生的原因是消息分发与持久化数据的更新不是直接结合在一起,中间有应用程序的行为。虽然有可能将消息处理与持久化数据更新结合起来,但通常做不到。缺乏这种结合在消息重复分发多次时会导致错误窗口的出现,因为其它资源可能造成消息偶然丢失(指"最多一次, at-most-once"的消息方式),这种情况也很难处理。
这种行为的后果是应用程序必须容忍消息重试和无序传递。
四、提出观点
撰写立场论文(position paper)的好处是可以表达疯狂的想法,以下是本文尝试来证明的几个方面观点。
*可伸缩应用程序使用唯一标识的实体
这篇文章将会讨论到每个应用程序的上层代码必须操作单一一个我们称作"实体"(entity)的数据集合。对实体大小没有限制但它必须位于单一序列化范围中(例如一台机器或一个群集上)。
每个实体有一个唯一标识(identifier)或键值(key),键值可以是任何形式,但必须能唯一的标识一个实体以及实体中包含的数据。
声明:图片均为论文中的原图,水印为系统自加的。
对实体的表示没有严格的限制,它可以是SQL记录,XML文档,文件,文件系统中包含的数据,例如二进制数据块(blobs),或其它任何对应用程序方便、适合的表现方式。一种可能的表现形式是SQL记录集(可能位于很多表中),它们的主键都以实体键值开始。
实体代表了分离的数据系列(disjoint sets of data),每个数据项(datum)只位于一个实体中,实体中的数据决不与其它实体的数据交叉(overlap)。
应用程序包括很多实体,例如一个"订单处理"程序会有很多订单,每个订单通过一个唯一订单ID标识,为了成为可伸缩的"订单处理"程序,单个订单数据必须与其它订单数据分离。
*原子事务不能跨实体
假设每台计算机都是一个单独的事务范围,然后,本文提出的论点是原子事务不能跨实体。程序员必须始终坚持数据至包含在单一实体的事务中。
从程序员的角度来看,独特的标识的实体就是事务作用域。这个概念对设计可扩展应用程序的行为有强大的影响力。我们将探讨的一个推论是无限伸缩设计无法保证辅助索引(alternate indices)的事务一致性。
*消息发送到实体
绝大部分消息传递系统并不考虑数据的分区键值(partitioning key),只是将消息发送到一个消费队列,然后通过无状态进程进行处理。标准实践包括消息中的一些数据,实体的数据取自数据库或应用程序的其他持久存储中。
业界中出现了很多有意思的趋势。首先应用程序中实体系列(sets of entities)的大小已经增长到无法在一个数据仓库中存放,每个实体存放在一个数据仓库,但整个实体系列却不一定,无状态应用程序基于某些分区描述(partitioning scheme)获取实体。其次分区信息被分离到应用程序的底层,特意与负责业务逻辑的应用程序上层分离。
这极大的促成了使用实体键值标识消息目的地,Unix风格的无状态进程以及应用程序的底层都是业务逻辑伸缩无关API的实现,上层伸缩无关的业务逻辑只是根据实体键值发送消息,实体键值则标识了持久化状态即实体。
*实体管理每个协作伙伴状态(活动)
伸缩无关的消息就是实体对实体的消息,发送方实体(反映了持久化状态,通过实体键值标识)将消息发送给另一个实体,接收方实体既包含上层(伸缩无关的)业务逻辑,也包含使用实体键值存取,反映了其状态的持久化数据。
前面假设消息至少分发一次,这意味着接收方实体必须能够忽略掉多余无效的消息。实际上消息分为两种类型,会影响接收方实体状态的和不会影响的。不会给实体状态带来变化的消息很容易处理,它们一般是幂等的(idempotent)。
为了确保幂等性(idempotence,例如确保重试的消息不会带来副作用),通常设计实体接收方让它们记住已经处理过的消息。这样做之后重复的消息一般产生一个新的响应(即回发的消息),它与早先被处理过的消息结果一样。
根据收到的消息创建的状态基于每个协作伙伴进行封装,这里的关键思想是按照协作伙伴组织状态,协作伙伴也是一个实体。
我们使用"活动"这个术语表示状态,它在两方关系(two-party relationship)之间管理每一方的消息。每个"活动"位于一个实体中,实体对每一个会向他们发送消息的协作伙伴都有一个"活动"。
除了管理消息混乱外,活动还管理松散关联(loosely-coupled)的协议。在这个不能使用原子事务的地方通常使用尝试性操作协商结果,这在实体之间进行由活动进行管理。
这篇文章并不假定活动能够解决各种已知的难题,以达成在工作流的讨论中描述的那样详细的协议。但我们指出无限伸缩会令人惊讶的带来细粒度工作流风格的解决方案,其中参与者是实体,每个实体使用涉及其它实体的特定知识管理自己的工作流,这个在实体内部维护的协作双方的知识正是我们称作活动的东西。
关于活动的示例有时候显得很微妙。订单应用会向发货应用发送消息,消息中包含发货ID和订单ID,消息类型将触发发货应用中的状态发生改变,将相关订单记录为等待发货的状态。通常实现者不会设计消息重试,直到出现bug,少数情况下应用程序设计者考虑和打算设计活动。
五、观点阐述
实体
本节在更大的范围内深入研究实体的本质。
*分离事务作用域
实体定义为拥有一个唯一键值的存在于单个事务范围内的数据集合,所以原子事务总是可以在单个实体的事务中完成。
*唯一标识的实体,
应用程序的上层代码很自然围绕具有唯一键的数据集合设计。客户id、社会安全号码、产品sku和在应用程序中可以看到其他惟一标识符。它们被用作定位应用程序数据的键。事务原子性的保证只出现在由唯一键标识的实体。
*重新分区和实体
前面提到的一个假设是上层伸缩性是不可知的,底层决定规模的变化。 特定实体的位置可能会随着部署的发展发生变化。
应用程序的上层无法对实体的位置做出假设,因为他对规模是不可知的。如下图3所示,实体通过哈希值或者动态主键进行跨事务访问。
声明:图片均为论文中的原图,水印为系统自加的。
*原子事务和实体
在可伸缩系统中不能跨越不同实体使用更新事务。每个实体拥有一个唯一键值,可以方便的将它们放入一个序列化范围中,怎样才能确认多个独立的实体一定位于相同的序列化范围中(因此可以自动完成更新事务)?只有这些实体都统一具有相同键值时才可以,这时它们已经是一个实体了!
如果对实体键值使用哈希进行分区,没有什么可以表明具有不同键值的实体会落在相同的哈希桶中(译注:即意味着位于同一个序列化范围)。如果对实体键值使用键值范围进行分区,绝大部分时候相同键值将位于同一台机器上,但很不幸有时相邻键值会位于不同机器。对键值范围的分区使用相邻键值进行原子性测试的简单测试用例,在测试布署环境下可能通过,但以后重新布署时在不同的序列化范围中移动实体,会遇到潜伏的bug,因为(跨越序列化范围的,译注)更新不再具备原子性。永远也不要指望不同的实体键值会位于同一个地方。
简而言之,应用程序底层将确保每个实体键值(和实体)位于单一的机器(或群集)上,而不同实体则可能分布在任何地方。
伸缩无关的设计必须具有实体概念,作为原子性的边界。把对实体存在(译注:所处位置)的认知作为一个设计抽象,使用实体键值,以及明确的声明在跨越实体时缺乏原子性,这些是为应用程序提供伸缩无关的上层的关键所在。
现在行业中的高伸缩性应用无疑都是这样做的,我们只是对实体概念没有一个正式的名字而已。对上层应用程序而言,它必须明确实体是序列化的范围,更进一步的假设在布署发生改变时会被打破。
*考虑辅助索引
我们经常使用多个键值或索引查找数据,例如有时使用社会安全号引用客户,有时使用信用卡号,有时使用街道地址。极端情况下这些索引无法位于同一台机器或一个大型群集中,此时一个客户相关的数据(译注:例如索引数据)无法保证位于单一的序列化范围中!实体本身位于单一的序列化范围中,麻烦的是那些构成辅助索引的数据副本必须考虑位于不同的序列化范围!
考虑辅助索引位于相同序列化范围中这样一种假设。在需要使用无限伸缩而实体系列(set of entities)分布在大量机器上时,主索引和辅助索引数据必须位于相同的序列化范围中,怎样确保这一点?唯一的方法就是使用主索引查找辅助索引,这使得它们可以位于相同的序列化范围中!当没有主索引键值但必须在整个序列化范围中进行查找时,每个辅助索引搜索必须检查无限数量的序列化范围以匹配辅助索引键值!这始终是不可行的。
唯一的替代方案是使用两步搜索,首先查找辅助索引得到实体键值,然后使用实体键值存取实体(译注:这种方案需要建立辅助索引结构,使用辅助索引可以查找到主索引的键值)。这跟关系型数据库中的辅助索引使用两个步骤存取纪录非常相似,但无限伸缩的前提是无法保证两个索引(主索引和辅助索引)位于相同的序列化范围中。
伸缩无关的应用程序将无法自动更新实体和它的辅助索引!上层伸缩无关的应用必须设计为能够处理这样的情况:辅助索引可能与使用主索引(例如实体键值)存取的实体失去同步的情况。 以前可以自动维护的辅助索引,现在必须由应用程序手动维护,使用异步消息进行更新的工作流也都是这样,需要无限伸缩的应用程序自己处理。以前使用辅助索引读取数据,现在就必须清楚它们可能与实体的主要呈现窗口失去了同步,因此基于辅助索引实现的功能现在变得麻烦了。这就是大型系统残酷世界中的真实生活。
*跨越实体的消息通讯
这一节中我们讨论使用消息连接不同实体的方法,包括事务和消息,看一下消息分发的语义,以及讨论一下对实体位置重新分区给消息分发带来的影响。
声明:图片均为论文中的原图,水印为系统自加的。
*异步发送事务
消息是跨越实体的,待发送消息位于一个实体中,消息终端是另一个实体。根据实体定义,我们必须清楚它们无法自动完成。应用开发者通过发送消息的方式使用事务可能是异常复杂的,将消息发送出去,然后事务可能被中断,你可能对这不以为然但它确实可能发生。由于这些原因,必须迎难而上使事务消息入队。
如果发送事务(sending transactions)提交之后无法立即接收到目的地的回馈,我们看到相对于发送事务(sending transactions)消息是异步的。实体在事务中会转化到新的状态,而消息是触发器,它来自于一个事物(transaction)到达另一个实体并引发新的事务。
*确定消息终端
在开发应用程序伸缩无关的部分时,一个实体需要向另一个实体发送消息,伸缩无关的代码并不知道目标实体的位置,即实体键值。这由应用程序伸缩相关的部分来处理,它将实体键值和实体位置关联起来。
声明:图片均为论文中的原图,水印为系统自加的。
*重分区和消息分发
应用程序伸缩无关的部分发送消息时,底层伸缩相关部分捕获到目标地址,将消息至少分发一次。
系统伸缩时会移动实体,这通常叫做重新分区。实体数据的位置即消息的目的地可能发生变化,有时消息仍将发送到旧地址,只是发现该死的实体已经被移到其它地方,这时消息需要路由。
移动实体有时会中断发送方和目的地之间先进先出队列的通路,这时消息被重发(retry),后来的消息会比先前的更早到达,世界变得更混乱。
由于这些原因,我们看到伸缩无关的应用程序对应用程序可见的消息支持幂等处理,这也意味着重新订阅(reorder)消息分发。
活动
活动:处理凌乱的信息
本节讨论如何应对消息重试和重新排序这些挑战。我们引入了活动这一概念作为必要的本地信息管理协作伙伴实体的关系(relationship)。
*重试和幂等性
因为任何消息都可能被多次传递,应用程序需要一个规范来处理重复消息。虽然可以构建底层支持,用于消除重复消息。在几乎无限扩展的环境中,这个底层支持需要了解实体。由于重新分区的原因,在消息移动时,发送给实体的消息必须和实体一起移动。事实上,这种知识的底层管理很少发生,消息可以传递多次。
通常情况,应用程序伸缩无关(上层)部分必须实现一些机制,确保接收的消息是幂等的。这对问题的本质不是必须的,当然也可以采用在应用程序伸缩相关部分构建消除重复的机制来解决。不过目前还没有这方面的应用,因此我们讨论可怜的伸缩无关应用开发者必须采用的方式。
*定义本质行为的幂等性
如果后续对消息处理的重复执行不会给实体带来本质变化,这个消息处理就是幂等的。这不是一个严谨的定义,关于什么才是本质变化留待应用程序确定。
如果消息不会改变调用实体而只是读取信息,这个消息处理是幂等的。即使写入了一条描述本次读取的日志记录我们也认为是幂等的,因为日志记录不会对实体行为造成本质影响。本质的定义是应用程序相关的。
*自然幂等性
消息不会造成本质副作用是实现幂等性的关键,有些消息任何时候都不会造成本质影响,他们就是自然幂等的。
只从实体读取数据的消息是自然幂等的。如果消息处理确实改变了实体但并不带来本质影响,那也是自然幂等的。
接下来是更麻烦的,有些消息带来了本质变化因此他们不是自然幂等的,而应用程序必须引入一些机制确保这些消息也是幂等的,这意味着采用某种方式记录已处理过的消息,以使后续重复的调用不会造成本质变化。
这就是接下来我们要讨论的非自然幂等的消息处理。
*将消息记录为状态
为了确保非自然幂等消息的幂等处理,实体必须记住哪些消息已经处理过了,这就是状态,状态随着消息处理不断记录下来。
除了记录消息已经处理过之外,如果消息需要回复则必须返回相同的回复内容,因为我们无法确定原发送者是否已经收到了这个回复。
*管理每个协作伙伴的状态
跟踪关系和接收到的消息,每一个与规模无关的应用程序中的实体必须以某种方式记住其合作伙伴的状态信息,并且必须针对每个协作伙伴分别记录。让我们将此状态命名为活动。参考 图6,一个实体如果它与许多其他实体交互,那么它可能有很多活动。每个实体由一组活动,有时候还会有其他一些跨越活动的数据。在一个几乎无限扩展的应用程序中,你必须非常清楚这些关系,因为无法简单的看一下就描述出是怎样关联的。
*确保最多接受一次消息
非自然自然幂等的进度消息需要确保每个消息至少被消费一次。
声明:图片均为论文中的原图,水印为系统自加的。
声明:图片均为论文中的原图,水印为系统自加的。
可以这样做,我们可以将一些信息的独特的特征记住下来,以确保它不会被多次消费。实体必须将等待处理的消息转换 持久化记录到状态中,以使重复的消息处理不会造成本质影响。通常,实体通过它的活动来实现状态管理。很明显,因为有的时候一个实体会支持许多不同的合作伙伴,而且每一个都将通过一个关联关系的消息模式,通过每个合作伙伴的搜集是它成为可能。
六、推论
活动: ACTIVITIES: COPING WITHOUT ATOMICITY
本节讨论在没有分布式事务的情况下,可伸缩系统的决策范围。管理分布式协议是一项艰苦的工作。在无限伸缩这样一个环境中,不确定性的表示必须以细粒度的方式进行。而且这是面向每一个参与者的。此数据在实体中使用活动的概念进行管理。
*目的地的不确定性
没有分布式事务意味着跨越不同实体的决策必须考虑不确定性,目前跨越分布式系统的决策仍无法规避不确定性这一问题。使用分布式事务时,这些不确定性发生在数据锁上,由事务管理器管理。
不能使用分布式事务的系统必须在业务逻辑中管理不确定性,使用业务语义(business semantics)而不是记录锁(record lock)控制不确定性的影响,这就是工作流了。没什么玄乎的,只是由于不能使用分布式事务而必须采用工作流而已。
这些因素使得我们使用实体和消息,使我们明白如果伸缩无关的应用需要跨越多个实体达成协议,就必须自己使用工作流管理不确定性。这仅仅是工作流程,这不是魔术,你不能使用分布式事务,然后你就只能使用工作流,这需要在多个实体之间达成协议。
*活动与不确定性管理
实体在与其它实体交互时可能出现不确定性,这种不确定性必须基于每个协作伙伴进行管理,即在具体的协作伙伴活动状态中实现。这种不确定性必须基于每个合作伙伴进行管理,并且在被其他对象引用时能够被可视化。大多数时候,不确定性可以通过关系表示,而且有必要由合作伙伴对它进行跟踪。活动跟踪每一个合作伙伴直到他进入一个新的状态。
*处理尝试性业务操作
为了达成跨实体的协议,一个实体要求另一个实体接受不确定性。因为一个实体向另一个实体发送一个请求后,这个请求以后可能会被取消。这被称为试探性操作。在这一步的末尾,一个实体同意遵守另一个实体的意愿。
*TCC (Tentative Operations, Confirmation,and Cancellation)
对试探性操作至关重要的是取消操作的权限。如果请求实体决定不向前移动,它发出一个取消操作。如果它决定继续前进,它会发布一个确认操作。
当一个实体同意执行试探性操作时,它同意让另一个实体来决定结果。因为它接受不确定性,所以这又增加了它的混乱。当确认和取消到达操作到达后,不确定性消除,混乱性消除。随着时间增长。这种混乱在一生中都不会停歇,因为时刻增长或者降低的不确定性,会导致在你的系统中旧的问题还没解决,新的问题就已经到达了。
然后,再次确认一下,这只是一个工作流,区别是它是基于实体精细设计的工作流。
*不确定性和无限伸缩
这种无限伸缩方案有意思的方面是围绕两方协议(two-party agreement)管理不确定性。经常会存在多个两方协议,我们还是使用实体键值作为连接器,使用活动跟踪远方协作伙伴的当前状态,这样这些两方协议就被连结成一个细粒度的两方协议网。
当考虑无限扩展性,思考两段式关系是很有趣的。通过两段协议构建尝试-确认/取消(tentative/cancel/confirm)(就像一个事务工作流)关系。你可以清楚看到达成分布式协议的基础。
相对而言,对试探性工作不确定性的管理,交给可伸缩系统的研发人员。但是对于信贷额度拨款,以及其他特定于应用程序的概念,试探性操作必须被保存下来。
七、总结
像往常一样,计算机行业也在不断变化。
今天,新的设计压力正在不断的被强加给那些只想实现业务需求的研发人员身上。现实正在把他们带入一个无限扩展系统的世界,并且迫使他们设计解决大量与手头工作无关的功能上。而且不管在今天还是这篇文章首次发布的2007年,这个问题都是正确的。不幸的是,那些努力解决业务目标程序员,如电子商务、供应链管理、金融和医疗保健应用程序。越来越需要考虑没有分布式事务下实现可伸缩性。而实际上,大多数开发人员根本无法访问提供可伸缩分布式事务的健壮系统。
我们正处于可以看到构建这些应用程序的模式的关键时刻,但是,还没有人能够始终如一地应用这些模式。本文认为,这些新出现的模式可以更一致地应用于为几乎无限扩展而设计的应用程序的手工开发中。
现在,许多应用程序都是隐式地使用实体和活动来设计的。它们只是没有形式化,也没有被一致地使用。在使用不一致的地方,会发现bug并最终修复。通过讨论和一致地使用这些模式。作为一个行业,可以构建更好的大规模应用程序。我们也可以让程序员更接近处理直接的业务逻辑而不是话费大量精力去考虑系统可扩展性。