5.1关键是接缝
高内聚,低耦合。这两点在单块系统中,往往都会被破坏。
从接缝处可以抽取出相对独立的一部分代码,识别出接缝不仅仅能理清代码库,这些识别出的接缝还可以成为服务的边界。
限界上下文就是一个非常好的接缝,因为它就是组织能高内聚和低耦合的边界。
很多变成语言都提供了命名空间的概念,来帮助我们把相似的代码组织到一起。
5.2分解MusicCorp
5.3分解单块系统的原因
强烈建议你慢慢开凿这些系统,增量的方式可以让你在进行的过程中学习微服务,同时可以限制出错的影响。如果把单块系统想象成为一块大理石,我们可以选择一次炸开,也可以选择增量开凿。明显第二种方式会更安全。
5.3.1改变的速度
为了敏捷。
5.3.2团队结构
全能型微团队(康威定律)
5.3.3安全
不同代码部分安全程度不同,分离安全系统不同的代码,针对安全系数高的模块采用更安全的策略。
5.3.4技术
前边的分享也提到过,不同的场景可能需要使用不同的技术,这样可以在简洁,效率等方面得到很好的提升,分拆后的服务因为很小,容易针对新技术采用和试错,采用和回滚都非常敏捷。
5.3.5 个人补充
对硬件(CPU/内存/磁盘等)的需求不同,例如目前的MRP/LRP运算
5.4杂乱的依赖
如果你识别出来的接缝之间可以形成一个有向无环图(光是这一点就很困难了,尤其对于巨无霸系统,在没有足够认知的情况下,敢拆就敢坏,没有赞,只有批),就能够看出来哪些接缝会比较难处理。
通常经过这样的分析就会发现,数据库是所有杂乱依赖的源头。
5.5数据库
不要使用数据库作为服务之间集成的方式,这意味着要找到数据库中的接缝,把他们分离干净。
就像咱们现在的微服务,大家都将各自领域的数据放在各自领域的数据库下,以后分离部署,互不影响(手动改数据/直接操作跨领域表/不同领域对数据服务器的要求可能也不一样)
5.6找到问题的关键
找到限界上下文,然后可以把它们分解开来,使其成为相互协作的服务。接下来看可能会遇到哪些问题以及如何处理?
5.7例子:打破外键关系
image.pngimage.png
去除外键,通过API调用后,你需要通过做两次数据库调用来生成报告。做成两个微服务之后就是这样,很多人会对性能问题表示担忧。你的系统需要多块?现在系统多快?可以做一个测试,知道了期望值和现在的实际值,就可以放心的修改了,尤其是在这个“慢”事实上还在可接受的范围内时。
外键关联怎么办?---引用检查。
5.8例子:共享静态数据
image.png第一种方法:共享数据库表(每个服务都有一个副本,变化基本很小)
第二种方法:共享的静态数据放入代码,比如放在属性文件中,或者简单放在一个枚举中。会有一致性问题,但修改配置文件吧修改数据库要简单的多,通常这是比较合理的做法。
第三种方法:比较极端,把这些静态数据放入一个单独的服务中。当数据量和复杂性及相关的规则值得我们这样做,但如果仅仅是国家代码的话就不必了。
5.9例子:共享数据
image.pngimage.png
5.10例子:共享表
最开始的时候,把这两个东西放在同一个地方,即比较通用的行条目表。分拆服务后, 应该把这两种数据放在不同的表中。
image.png
image.png
5.11重构数据库
image.png坏处:对数据库的访问次数可能回变多,之前见到那一个select语句就能得到的所有数据,现在需要分别从不同的地方拿到数据,然后在内存中聚合。
好处:先分离数据库结构但不分离服务,这样可以随时选择回退修改或者继续,而不影响任何消费者。当对数据库的分离感到满意之后,就可以考虑对整个应用程序分离了。
5.12事务边界
一句话:要么全部做完,要么什么都不变。
image.png
image.png
5.12.1再试一次
将失败的操作放在要给队列或者日志文件中,之后再尝试对其进行触发。(最终一致性---即可以接受系统再未来的某个时间达到一致;相对的还有强一致性)
5.12.2终止整个操作
发起补偿事务来抵消之前的操作,回到之前的状态。
这个方法就是不是太好,为什么呢?补偿这个事儿说起来好说,做起来没那么容易,尤其是当有“很多”不同的操作需要保持事务。
5.12.3分布式事务
分布式事务会跨越多个事务,然后适用于给叫做事务管理器的工具来统一编配其他底层系统中运行的事务。
两阶段提交:投票阶段,提交阶段。
缺点:所有的参与者暂停并等待中央协调进程的指令,从而很容易导致系统中段。如果事务管理器宕机了,处于等待状态的事务就永远无法完成。
5.12.4应该怎么办呢
所有这些方案都会增加复杂性。分布式事务很容易出错,而且不利于扩展。一致性的场景,尽量避免把它们放在不同的地方。实在不行,可以按照实际业务,看能否通过类似补偿事务这样操作。例如,创建一个交出“处理中的订单”的概念。
5.13报告(报表)
你们全分离了,我咋办?-----报表
5.14报告数据库
image.png虽然这样做不完美,但至少它是可以工作的。
5.15通过服务调用来获取数据
通过API来获取其他服务中的数据,这种方式对于简单场景是非常好用的。
对于复杂场景,尽量不要在本地保留其他服务获取到的数据的副本,因为数据随时可能变更,即使是历史数据,如果要保持同步,需要在各个微服务变更的时候通知到你,这无形中增加了系统的复杂度。但如果不存数据,又会增加每次交互的数据量的大小。
5.16数据导出(定时)
image.png数据库集成确实是不好的,但报表这个场景可以是一个例外,因为它使得报表这件事变得足够简单。
5.17事件数据导出(主动触发)
image.png订阅事件,接受通知,增量更新。
缺点:相比数据导出方式,这种方式让做报表的每个业务系统都需要了解这套机制,以及做相应的事件订阅,还同时需要考虑分布式事务的问题。(肖老板不怎么赞同这种方案)
5.18数据导出的备份
5.19走向实时
5.20修改的代价
修改,一定要做小的,增量的,渐进式的修改。一个关键的好处在于:能够完全理解做出的改变会造成什么影响,更好的消除错误修改带来的代价。
(这件事很难,比所有事都难)
5.21理解根本原因
本章一直讨论的问题是:如何把大服务分拆成一些小的服务,但也同时需要明确以下两点:
- 服务一定会慢慢变大
- 拆分服务不是银弹,带来好处的同时也带来了复杂性和其他需要解决的问题。
网友评论