《微服务设计》书摘(二):部署 & 测试

第五章:分解单块系统

事务边界

事务可以保证一些事件要么都发生,要么都不发生。在插入数据库时,这一点非常有用。

服务一定会慢慢变大,直至大到需要拆分。关键是要在拆分这件事变得太过昂贵之前,意识到你需要做这个拆分。

第六章:部署

本章主要讨论持续集成 & 持续交付。

6.1 持续集成 & 微服务

CI(Continuous Integration,持续集成)保证新提交的代码与已有代码进行集成,从而让所有人保持同步。如果没有 CI,向微服务架构进行转型会非常痛苦。关于 CI,要理解以下三个问题:

  • 是否频繁的进行代码 merge:如果你的代码和别人的代码没被频繁的 merge,那将来的集成就会很困难
  • 是否有单元测试来验证修改:由于微服务强调灵活修改,快速集成,所以需要保证修改代码的质量
  • 当构建失败后,团队是否把修复 CI 当作第一优先级的事

每个微服务都应该有自己独立的代码库,并分别与对应的 CI 绑定。当对代码库进行修改时,可以只运行相关的构建及测试。

6.2 构建 Pipeline

把一个构建过程分成多个阶段是很有价值的。构建流水线可以可视化整个构建流程。

CD(Continuous Delivery,持续交付)

第七章:测试

如何高效且有效地测试分布式系统的功能是一个挑战。它能帮助我们在尽早交付软件与保证软件高质量之间保持平衡。

测试类型包括:

  1. 单元测试:测单个方法
  2. 接口测试:测单个服务接口
  3. 性能测试
  4. 界面测试:测单个功能

其中,单元测试、接口测试、性能测试属于自动化测试。放弃大规模的手工测试,尽可能多地使用自动化测试是近年来业界的一种趋势。而微服务架构尤其需要自动化测试。

7.1 单元测试

单元测试通常只测试一个函数和方法,它不会启动服务,通常情况下一个服务需要大量的单元测试。
通过 TDD(Test-Driven Design,测试驱动开发)写的测试就属于这一类。单元测试对于代码重构非常重要,它允许你肆意的重构而不必担心引入 bug。

7.2 接口测试(服务测试)

只测试为用户界面提供服务的一些类。接口测试只覆盖单个服务接口,为了达到隔离性,需要给外部合作者打桩(or mock)。接口测试比单元测试覆盖的范围更大。

对于每一个下游合作者,我们都需要一个打桩服务,然后在运行接口测试的时候启动它们,还需要配置被测服务,在测试过程中连接这些打桩服务。接着,为了模仿真实服务,需要配置打桩服务为被测服务的请求发回响应。

7.3 界面测试

在微服务系统中,界面展示的一个功能往往涉及多个服务。

7.4 蓝/绿部署 vs 金丝雀部署

7.4.1 蓝/绿部署

使用蓝/绿部署时,我们会部署两份软件,但只有一个接受真正的请求,这也就是我们说的不停机部署。

发布的时候:

  1. 将所有的请求全部交给A处理
  2. 在B上发布新应用
  3. B上内部测试
  4. 测试通过后,所有请求转向B
  5. 在A上发布新应用
  6. A上内部测试
  7. 测试通过后,A和B同时提供服务

实施蓝/绿部署的整个过程可以完全自动化,它有几个前提条件:

  1. 需要能够切换生产流量到不同的主机。切换时,可通过改变 DNS /更改负载均衡策略
  2. 提过足够多的主机,以支持并行运行两个版本

带来的好处:

  1. 在切换流量前,可以测试
  2. 遇到问题时及时回滚
  3. 在用户无感知的情况下零宕机部署

7.4.2 金丝雀部署

金丝雀发布和蓝/绿部署容易混淆,因为它们会使用一些相似的技术。两者的不同之处在于:金丝雀新旧版本共存的时间更长,而且经常会调整流量,它需要更复杂的请求配置。

金丝雀发布强调将部分生产流量引到新部署的系统,来验证系统是否按预期执行。按预期执行包括:功能性 & 性能性 & 其它各种场景(如:新系统的推荐算法的点击率是否比旧系统高)等。
如果没有达到预期,可以迅速回滚到旧版本,如果达到预期,可以全部引流。

向新服务引流分两种:直接引流生产请求 or 复制一份请求,复制请求比较复杂,尤其是在请求不是幂等的情况下。

7.5 性能测试

将系统拆分成较小的微服务后,跨网络边界调用次数明显增加了,之前可能只涉及一次数据库调用,现在可能涉及三四次跨网络调用,还有匹配数量的数据库调用,所有这些调用都可能减缓系统操作的速度。因此,追踪延迟的根源显得尤为重要。

7.6 总结

比较来说,单元测试粒度更细,测试所用时间更短,出现bug后也更好定位。为不同的目的选择不同的测试来覆盖。

一般来说,单元测试要比接口测试大一个数量级,接口测试比界面测试大一个数量级。一种常见的测试反模式:很少甚至没有单元测试。这意味着当提交有错误时,需要很长时间才能发现这个问题。

包含在测试中的服务数量越多,测试就会越脆弱,不确定性也就越强。如果测试失败以后,只是想重新运行一遍测试,然后希望可能通过,那么这种测试是脆弱的。

涉及多个服务的测试很脆弱,涉及多线程的测试通常也会有问题。测试失败有时是因为资源竞争、超时等。当发现脆弱的测试时,要及时解决,否则随着时间的推移,人们会对出错习以为常。

同时测试case要精细的管理,不能盲目的覆盖、堆砌,要想办法让测试变快。

测试结果的反馈周期过长,会影响开发人员的效率,同时会间接影响服务部署。所以要及时反馈 bug,及时修复 bug,尽可能频繁发布小范围改变。

把测试的重心放到少量核心场景中。

你可能感兴趣的:(《微服务设计》书摘(二):部署 & 测试)