Date

作为一个码农,不能理解程序员口中的

  • 微服务化是趋势
  • 区块链开创未来
  • 前后端分离是历史的选择

Microservices

Martin Fowler 所写,此文有两个版本的中译。建议全文阅读。

Microservices: The Good, the Bad, and the Ugly

这篇文章被转的到处都是

The Good

  • 能以高效的方式轻松扩展
  • 不存在单点故障
  • 在不影响整个应用程序完整性的情况下下线,重构或重写
  • 针对不同服务的需求,选择最佳的语言和框架
  • 简单且离散
  • 轻松满足现代 PaaS 和 SaaS 环境的需求

对于第二条说的就跟 monolithic 应用存在单点故障一样,有没有单点和微服务好像没有什么关系吧

The Bad

  • 由于需要维护基于微服务的应用及组件所需的专业知识,因此变得更复杂
  • 如果应用不需要扩展或者不是 cloud-based,基于微服务的架构可能不会带来任何有意义的好处
  • No greenfield options because microservices need to connect to existing (and possibly monolithic) systems
  • 通过 API 进行通信需要更强大的测试方法以及整个团队的支持
  • 需要增加团队管理和沟通,以确保每个人(而不仅仅是某些工程师)了解每个服务和整个系统。

The Ugly

不要跟风。Netflix 及一些热门的硅谷新宠已经接受微服务并不意味着它是所有应用的正确架构风格。应用架构不仅应该基于当前流行的东西,还更应该基于实际功效和是否适用。

  • 分布式系统的开发、部署、运营管理需要比较高的启动资金
  • 为不同的组件选择不同的技术栈会导致不统一的应用设计和体系架构
  • 更新文档比较麻烦(如果用 ProtoBuf 的话,proto 文件可以充当接口文档)
  • 维护成本,运营成本和生产监控成本要高得多,后者也缺乏可用的工具(可用的工具就现在来说已经很多了)
  • Increased resource and memory consumption from all the independently running components which need their own runtime containers with more memory and CPU
  • 微服务如果实施不当,可能翻车

作者鼓励理智思考,因为它是一把双刃剑

Microservices – Please, don’t

中文翻译 Microservices – Please, don’t

并非是真理,也可能是谬论

  • It keeps the code cleaner

它通过减少所涉及的部分来对你进行约束,这不是在解决最根本的问题。可以定义内部边界,而不一定要引入网络边界。

  • It’s easy to write things that only have one purpose

涉及多个远程服务会引入额外的复杂性。需要和其他部分进行协作来完成数据的变更,这会让你陷入分布式事务之中。

  • They’re faster than monoliths

将应用缩小,减少依赖本身便可以更快。引入了网络间调用,这肯定比 co-resident code calls 慢。对于一个新的项目来说,CPU 和 内存并不是瓶颈,反而网络 I/O 的影响更为突出

  • It’s easy for engineers to not all work in the same codebase

测试麻烦,需要部署所有依赖的服务才能运行。使用 Docker 可以解决部署环境问题。不同服务可能由不同团队进行维护,增加了解决 Bug 时的交流成本

  • It’s the simplest way to handle autoscaling, plus Docker is in here somewhere

将服务打包成离散的单元,然后通过 Docker 来横向伸缩是没有错的。但不能说这是微服务的专属手段,monolithic 应用也可以这样做。

作者给出的建议:

理解你的 domin,合理划分服务边界,理清依赖关系。这些是微服务化的前提。

Microservices - Not a free lunch!

好处

  • 服务本身是简单的,侧重于做好一件事
  • 可以使用最佳和最合适的工具来构建每个服务
  • 松耦合
  • 在这个模型下,多个开发人员和团队可以相互独立地交付
  • 支持频繁地发布,同时保持系统的其余部分可用且稳定

服务变得简单了,但是管理和发布这些服务变得复杂了。

运维开销

从单个 monolithic 应用转为 N 个服务的构建,测试,部署和运行。而且他们可能不是同一个技术栈。如果考虑故障转移和弹性伸缩的话,可能维护的数量会更多。Kubernetes 解决了这个问题,但是引入了 Kubernetes 的维护开销

隐式接口

将系统分解为互相协作的组件,便会引入接口这种概念。接口用作契约,双方需要交换相同的消息格式,并且对这些消息具有相同的语义理解,例如 ProtoBuf。更改契约某一侧的语法或语义,并且所有其他服务都需要了解该更改。在微服务环境中,这可能意味着简单的更改会导致对许多不同组件进行更改,然后以某种顺序将他们依次发布。

重复努力

作者举了一个例子

Imagine that there is a new business requirement to calculate tax differently for a certain product line. We have a few choices in how to deliver this. We could introduce a new service and allow the other services to call into this where needed. That does however introduce more potentially synchronous coupling into the system, so is not a decision we would take lightly. We could duplicate the effort, adding the tax calculation into all of the services that need it. Besides the duplicated development effort, repeating ourselves in this way is generally considered a bad idea as every instance of the code will need to be tested and maintained going forward. The final option is to share resources such as a tax calculating library between the services. This can be useful, but it won't always work in a polyglot environment and introduces coupling which may mean that services have to be released in parallel to maintain the implicit interface between them. This coupling essentially mitigates a lot of the benefits of Microservices approaches. It seems to me that all three of these options are sub-optimal as opposed to writing the piece of code once and making it available throughout the monolithic application. The teams I have seen working in this style tend towards option 2, duplicating of business logic, which goes against many principles of good software engineering. And yes, this even takes place in well decomposed and designed systems - it's not always a sign of bad service boundaries.

分布式系统的复杂性

微服务意味着分布式系统。先前我们可能使用方法调用来跨越系统的边界,而现在我们需要引入远程调用,来将不同服务器上不同进程的组件进行粘合。我们需要考虑一些以前未曾想过的问题,比如:网络延迟,容错,消息序列化,网络不可用,异步性,版本控制

异步的困难

以微服务风格构建的系统可能会比单一应用程序更加异步。当我们可以将工作分解成真正独立的独立任务时,异步系统是个好的主意。然而,当事件必须在异步架构中同步或事务性地发生时,将变得非常复杂。

为测试带来新挑战

With so many services all evolving at different paces and different services rolling out canary releases internally, it can be difficult to recreate environments in a consistent way for either manual or automated testing. When we add in asynchronicity and dynamic message loads, it becomes much harder to test systems built in this style and gain confidence in the set of services that we are about to release into production. We can test the individual service, but in this dynamic environment, very subtle behaviours can emerge from the interactions of the services which are hard to visualise and speculate on, let alone comprehensively test for.