第五章:分解单块系统
事务边界
事务可以保证一些事件要么都发生,要么都不发生。在插入数据库时,这一点非常有用。
服务一定会慢慢变大,直至大到需要拆分。关键是要在拆分这件事变得太过昂贵之前,意识到你需要做这个拆分。
第六章:部署
本章主要讨论持续集成 & 持续交付。
6.1 持续集成 & 微服务
CI(Continuous Integration,持续集成)保证新提交的代码与已有代码进行集成,从而让所有人保持同步。如果没有 CI,向微服务架构进行转型会非常痛苦。关于 CI,要理解以下三个问题:
- 是否频繁的进行代码 merge:如果你的代码和别人的代码没被频繁的 merge,那将来的集成就会很困难
- 是否有单元测试来验证修改:由于微服务强调灵活修改,快速集成,所以需要保证修改代码的质量
- 当构建失败后,团队是否把修复 CI 当作第一优先级的事
每个微服务都应该有自己独立的代码库,并分别与对应的 CI 绑定。当对代码库进行修改时,可以只运行相关的构建及测试。
6.2 构建 Pipeline
把一个构建过程分成多个阶段是很有价值的。构建流水线可以可视化整个构建流程。
CD(Continuous Delivery,持续交付)
第七章:测试
如何高效且有效地测试分布式系统的功能是一个挑战。它能帮助我们在尽早交付软件与保证软件高质量之间保持平衡。
测试类型包括:
- 单元测试:测单个方法
- 接口测试:测单个服务接口
- 性能测试
- 界面测试:测单个功能
其中,单元测试、接口测试、性能测试属于自动化测试。放弃大规模的手工测试,尽可能多地使用自动化测试是近年来业界的一种趋势。而微服务架构尤其需要自动化测试。
7.1 单元测试
单元测试通常只测试一个函数和方法,它不会启动服务,通常情况下一个服务需要大量的单元测试。
通过 TDD(Test-Driven Design,测试驱动开发)写的测试就属于这一类。单元测试对于代码重构非常重要,它允许你肆意的重构而不必担心引入 bug。
7.2 接口测试(服务测试)
只测试为用户界面提供服务的一些类。接口测试只覆盖单个服务接口,为了达到隔离性,需要给外部合作者打桩(or mock)。接口测试比单元测试覆盖的范围更大。
对于每一个下游合作者,我们都需要一个打桩服务,然后在运行接口测试的时候启动它们,还需要配置被测服务,在测试过程中连接这些打桩服务。接着,为了模仿真实服务,需要配置打桩服务为被测服务的请求发回响应。
7.3 界面测试
在微服务系统中,界面展示的一个功能往往涉及多个服务。
7.4 蓝/绿部署 vs 金丝雀部署
7.4.1 蓝/绿部署
使用蓝/绿部署时,我们会部署两份软件,但只有一个接受真正的请求
,这也就是我们说的不停机部署。
发布的时候:
- 将所有的请求全部交给A处理
- 在B上发布新应用
- B上内部测试
- 测试通过后,所有请求转向B
- 在A上发布新应用
- A上内部测试
- 测试通过后,A和B同时提供服务
实施蓝/绿部署的整个过程可以完全自动化,它有几个前提条件:
- 需要能够切换生产流量到不同的主机。切换时,可通过改变 DNS /更改负载均衡策略
- 提过足够多的主机,以支持并行运行两个版本
带来的好处:
- 在切换流量前,可以测试
- 遇到问题时及时回滚
- 在用户无感知的情况下零宕机部署
7.4.2 金丝雀部署
金丝雀发布和蓝/绿部署容易混淆,因为它们会使用一些相似的技术。两者的不同之处在于:金丝雀新旧版本共存的时间更长,而且经常会调整流量
,它需要更复杂的请求配置。
金丝雀发布强调将部分生产流量引到新部署的系统
,来验证系统是否按预期执行。按预期执行包括:功能性 & 性能性 & 其它各种场景(如:新系统的推荐算法的点击率是否比旧系统高)等。
如果没有达到预期,可以迅速回滚到旧版本,如果达到预期,可以全部引流。
向新服务引流分两种:直接引流生产请求
or 复制一份请求,复制请求比较复杂,尤其是在请求不是幂等的情况下。
7.5 性能测试
将系统拆分成较小的微服务后,跨网络边界调用次数明显增加了,之前可能只涉及一次数据库调用,现在可能涉及三四次跨网络调用,还有匹配数量的数据库调用,所有这些调用都可能减缓系统操作的速度。因此,追踪延迟的根源显得尤为重要。
7.6 总结
比较来说,单元测试粒度更细,测试所用时间更短,出现bug后也更好定位。为不同的目的选择不同的测试来覆盖。
一般来说,单元测试要比接口测试大一个数量级,接口测试比界面测试大一个数量级。一种常见的测试反模式:很少甚至没有单元测试。
这意味着当提交有错误时,需要很长时间才能发现这个问题。
包含在测试中的服务数量越多,测试就会越脆弱,不确定性也就越强。如果测试失败以后,只是想重新运行一遍测试,然后希望可能通过,那么这种测试是脆弱的。
涉及多个服务的测试很脆弱,涉及多线程的测试通常也会有问题。测试失败有时是因为资源竞争、超时等。当发现脆弱的测试时,要及时解决,否则随着时间的推移,人们会对出错习以为常。
同时测试case要精细的管理,不能盲目的覆盖、堆砌,要想办法让测试变快。
测试结果的反馈周期过长,会影响开发人员的效率,同时会间接影响服务部署。所以要及时反馈 bug,及时修复 bug,尽可能频繁发布小范围改变。
把测试的重心放到少量核心场景中。