微服务设计读书笔记 (第五章 分解单块系统)
单块系统的形成非一日之功。开发人员每天都对系统添加新功能和新代码。一段时间之后,它变成了组织中一个恐怖而巨大的存在,没人想去修改它。但别担心,它并不是无可救药。只要使用了正确的工具,我们就可以手刃这个怪兽。
关键是接缝
接缝的概念,从接缝处可以抽取出相对独立的一部分代码,对这部分代码进行修改不会影响系统的其他部分。识别出接缝不仅仅能够清理代码库,更重要的是,这些被识别出的接缝可以成为服务的边界。
限界上下文就是一个非常好的接缝,因为它的定义就是组织内高内聚和低耦合的边界。所以第一步是开始识别出代码中的这些边界。
分解单块系统的原因
把单块系统想象成为一块大理石,我们可以把整块石头炸开,但这样做的结果通常不好。增量开凿的方式更合理。分解时最好考虑一下把哪部分代码抽取出去得到的收益最大,而不是为了抽取而抽取。
杂乱的依赖
当你已经识别出了一些备选接缝,另一个需要考虑的点是,这部分代码与系统剩余部分之间的依赖有多乱。我们想要拉取出来的接缝应该尽量少地被其他组件所依赖。如果你识别出来的几个接缝之间可以形成一个有向无环图(前面提到的包建模工具可以对此提供帮助),就能够看出来哪些接缝会比较难处理。通常经过这样的分析就会发现,数据库是所有杂乱依赖的源头。
数据库
前面详细讨论了使用数据库作为服务之间集成方式的做法。而且我已经非常明确地表示我不喜欢这么做!这意味着需要找到数据库中的接缝,这样就可以把它们分离干净。然而数据库是一个棘手的怪物。
分解数据库
你想要在一次发布中把单块服务直接变成两个服务,并且每个服务有各自的数据库结构吗?事实上,我会推荐你先分离数据库结构,暂时不对服务进行分离。先分离数据库结构但不分离服务的好处在于,可以随时选择回退这些修改或是继续做,而不影响服务的任何消费者。我们对数据库分离感到满意之后,就可以考虑对整个应用程序的分离了。
事务边界
简单地说,一个事务可以帮助我们的系统从一个一致的状态迁移到另一个一致的状态:要么全部做完,要么什么都不变。
再试一次
相对于使用事务来保证系统处于一致的状态,最终一致性可以接受系统在未来的某个时间达到一致。这种方法对于长时间的操作来说尤其管用。
终止整个操作
再发起一个补偿事务来抵消之前的操作。
报表数据库
所有的数据存储在同一个地方,可以使用非常简单的工具来做查询。但也存在一些缺点。首先,数据库结构成了单块服务和报表系统之间的共享API,所以对表结构的修改需要非常小心。事实上,这也会阻碍所有人去做类似的修改。其次,无论是在线上系统还是报表系统的数据库中,可用的优化手段都比较有限。最后,来看看有哪些数据库可供选择,显然近几年来这个选择的范围得到了极大的扩展。
事件数据导出
这个方法主要的缺点是,所有需要的信息都必须以事件的形式广播出去,所以在数据量比较大时,不容易像数据导出方式那样直接在数据库级别进行扩展。不管怎样,如果你已经暴露出了合适的事件,我还是建议你考虑这种方式,因为它能够带来低耦合及更好的数据时效性。
修改的代价
贯穿本书,你会看到我一直在强调做小的、增量修改的各种原因,但其中一个关键的好处是,能够理解做出的那些改变会造成什么影响。这会帮助我们更好地消除错误的代价,但不会完全避免错误的产生。我们可以,也一定会犯错误,需要接受这个事实。但是另外一件我们应该做的事情是,理解如何降低这些错误所造成的影响。
理解根本原因
服务一定会慢慢变大,直至大到需要拆分。我们希望系统的架构随着时间的推移增量地进行变化。关键是要在拆分这件事情变得太过昂贵之前,意识到你需要做这个拆分。
小结
我们通过寻找服务边界把系统分解开来,且这可以是一个增量的过程。在最开始就要养成及时寻找接缝的好习惯,从而减少分割服务的代价,这样才能够在未来遇到新需求时继续演化我们的系统。如你所见,有些工作是很艰难的。但由于可以增量进行,所以也没什么好怕的。