微服务实战中的那些“坑”

Richard Clayton分享了自己在微服务实践中的失败经历,避免更多人犯同样的错误。这些问题主要有以下几点:

1.开发人员之间的哲学观点的差异
我们团队对微服务分为以下三个派别:
a.喜爱微服务
b.讨厌微服务
c.冷漠 无足够准备建立维护微服务

开始我们会预期到这样的架构会遭遇到不同意见,但是也许是受到了“人月神话”的影响,团队民主平等的气氛虽然很活跃,但是会让我们实现微服务每一步都会遭受质疑以至于陷入大量讨论,耗费了大量时间。

因为存在这三种开发人员,导致微服务实现方式不正确,一个工程师在一个主机包装了一个微服务,而另外一个工程师不知道位于不同进程或主机上服务之间如何通讯,这些工程师也很难搞懂如何测试 部署和健康微服务,因为他们都是使用传统方式,让服务跨越不同主机的栅栏放在一个主机内,实现统一管理和部署,基础共识的缺乏导致整个团队的低效生产力。

2.服务边界带来障碍
传统的开发边界是区分为前端 后端和数据库,但是在微服务下,这个边界是大量的独立的服务。这就给我们带来可怕的障碍。

我们决定将后端划分为8个独立的服务,并作了一个坏的决定:将服务分配给人,这加强了开发人员对其开发的服务的所有权,但是开发人员又开始抱怨,自己的服务A被另外一个人的服务B中的任务堵塞住了。这好像很可笑,因为编译时服务之间已经没有了依赖,但是它确实发生了,那么只能为开发服务B的开发者提供帮助,或者将那个堵塞的任务从服务B中迁移到另外一个服务,开发人员增加了沟通的成本。

3.有效的服务分离
首先是构建抽象依赖,比如有人定义了一个抽象通用的数据库访问库包,但是这个库包并没有很好被封装,它依赖Jetty的一个旧版本,这导致我们花了一周时间来重构这个库包,以便让其成为共享的基础代码。

其次是服务和模型合约,我们没有定义服务的API,特别是服务之间传递的模型,开发人员便试图构建一个跨服务接口的共享模型库包,这对于Java环境是OK的,但是不适合我们的前端开发人员,只能使用JSON。这就需要在对象和JSON之间序列号,其实我们一直遭遇前后端开发之间的序列化问题,当微服务数量增加时,这个问题变得突出(banq注:这里体现微服务提出者Node.js的优点,Javascript跨前后端,对象与JSON无需序列化和反序列化)。我们现在还没有解决这个问题,正在研究Avro和JSON schema来进行模型的检验。

最后是服务之间通讯的模式问题,服务之间的通讯方式需要显式定义的。这包括序列化、安全性要求的选项,错误处理和列表的预期响应等。我也建议不要尝试使用一种机制能适应所有用例。我们最初试图使用消息传递(AMQP)作为服务之间唯一通信形式,但是它并不管用。我们最终决定采用CQRS作为服务通信模式,通过消息异步发送命令和同步用于查询的web服务,但是没有时间去完全实现该模式。

4.服务的粒度。
因为每个microservice都有它自己的可配置和可部署的单位,这意味着你的每个团队会增加更多的负担。其中是性能的影响,因为远程通信会导致你的服务出现额外的延迟。

5.项目管理。
我们花费了大量时间在实现CI/CD流水线来构建 配置和部署我们的微服务架构。

服务配置越动态,维护越困难,这可能需要大量独立的代码库...

Microservices应该提供允许更细粒度的更新和部署能力。这是有代价的。CI / CD过程需要设置处理single-service或group-of-services构建和部署。这个过程可能会非常棘手,特别是你可能有更多的可移动部件时。

你不会有一个Tomcat运行四个WAR应用。你现在有许多独立的进程或主机机器需要管理(基于microservice部署策略)。每一个这些流程需要监视和维护。

维护负担,随着微服务增加,我们发现一个对服务部署配置小变化会引起一连串的改变,进而迫使我们去做大量的测试部署过程本身。(banq注:Docker可以帮助简化这些部署维护困难)

参考:
Docker微容器+微服务将颠覆传统的软件架构

使用Docker建立一个动态负载平衡的分布式Web系统