单块系统把所有不相关的代码放在一起,修改一行代码无法保证对其他部分造成影响。而且为了发布一个小的功能需要整个系统重新部署。
1. 识别系统中的高层限界上下文,比如业务边界。
2. 创建包结构来表示这些上下文,把代码移动到相应的位置
3. 分析包之间的依赖。代码之间的依赖关系应该跟组织(比如按照业务区分包结构,组织应该是业务)中不同部分的实际交互方式一致。如果不一致分析为什么这样并解决。
4. 增量改造单块系统
5. 边界确定,代码也分离完成,接下来需要抽取某个包中的全部代码,创建单独系统,抽取哪个部分要考虑获得的收益是否最大。收益可以考虑如下几个因素:
改变速度:后期可能对某个方面进行大量修改,如果抽取出来作为一个服务的,使其成为一个自治的单元,对后期的开发速度将大大加快
团队结构:交付团队分布在两个不同地区,谁维护的分离给谁
安全:某个服务拥有敏感信息,需要做更加严密的保护,如果把这个服务分离出去可以对这个单独的服务做监控。传输数据的保护和静态数据的保护
技术:特定的服务需要特定的技术,比如其他语言,能够大大改善我们的服务,那么可以分离出去作为一个单独的服务
6. 抽取出来的服务应该尽量少地被其他组件所依赖
7. 对dao层进行划分,把数据库映射相关的代码和功能代码放在同一个上下文中
8. 不同模块提供API方式进行数据访问,不能通过数据库集成方式。然后去除数据库外键关联约束,通过代码来实现这个约束。
9. 共享静态资源的处理:
a 每个包复制一份该表的内容,未来每个服务也会保存这样一份副本,如果增加一个属性,后期维护困难
b 共享静态数据放入代码,比如属性文件,枚举类,也会出现a中的问题,不过操作简单的多
c 作为单独服务,如果值得我们这么做的话可以考虑
10. 共享数据的处理:共享数据意味着一个表被多个模块共享,读写数据。领域概念不是在代码汇总进行建模,相反是在数据库中隐式建模。共享数据表可能是我们缺失的领域概念,意味着共享数据表可以具象话,作为一个新的包,最终可以得到一个清晰的客户服务
11. 共享表的处理:由于两种实体字段类似,最初处于方便把他们放在了同一个地方,即比较通用的行条目表。当把代码全部放在一起时,事实上很难意识到我们把不同的关注点放在了一起。解决方案就是按照两种实体分成两个表。
12. 先分离数据库结构后分离服务。好处在于可以随时选择回退这些修改或是继续做,而不影响服务的任何消费者。我们队数据库分离感到满意之后,就可以考虑对整个应用程序的分离了。
13. 事务处理:分离服务后两个写操作可能不在一个事务里,解决一致性方案有:
a 最终一致性 :第一个写成功后,第二个写操作可以放入队列、日志文件中,或者其他方式,之后尝试对其进行处罚,确保在未来的某个时间达到一致
b 拒绝整个操作:第二个操作失败后发起一个补偿事务来抵消之前的操作,比如一个DELETE操作把之前的操作记录删除,然后向用户报告该操作失败了
c 分布式事务:横跨多个事务,然后使用一个叫做事务管理器的工具来统一编配其他底层系统中运行的事务。这里的事务会运行在不同系统的不同进程汇总,通常他们之间使用网络进行通信。常用的算法是两阶段提交
参考《微服务设计》