在这篇文章里,我将简要地介绍在设计微服务架构时需要注意的问题。如果实施得当,就会获得自治能力和灵活性,但同时也会带来通信延迟和部署及托管成本。这篇文章并不是一个高级指南,我只是希望能够在你们决定采用微服务架构时帮你们做出更好的判断。
映射服务
在我看来,映射服务是一种很糟糕的想法。
如果你走到了这一步,很可能是因为你需要在服务 A 和服务 B 之间映射 DTO,因为服务 A 和服务 B 需要不同的 DTO,但它们之间又相互依赖。出于对微服务的“热爱”,你尝试着解耦这两个服务,于是你创建了服务 C。服务 C 接收 JSON 数据,并把稍微处理后的数据返回,其他什么事也不做。
现在,你的三个服务都耦合在一起了。DTO 到 DTO 的映射应该发生在进程内部,否则的话,可能会有人创建出新的服务来映射服务 A 和服务 C 之间的 DTO。除非服务 C 不会往实体中添加新数据,否则它的存在就不是必要的。一个服务应该只返回它所拥有的数据。
同样,你会为了给一组数字排序而专门创建一个服务吗?
2. 静态内容的映射服务
并不是所有东西都需要被包装成微服务,网站的静态资源,比如脚本、样式表或图像,要么把它们放在主服务器上,要么放在 CDN 上。
对于后端服务,如果需要在初始化的时候读取一些简单的字符串,而这些字符串很少发生变化,可能几个月或者几天才会修改一次,那么可以考虑使用冷存储,比如亚马逊的 S3 或者微软的 BlogStorage。需要访问控制?可以考虑基于 IP 或域名的访问限制。所以,在考虑是否需要创建新的微服务时,要十分谨慎,因为它可能会给你带来巨大的维护和托管成本。
另外请注意,持久存储必须是分布式可伸缩的。出于简单起见,数据应该采用键值对的形式,否则就会遇到与“多个服务共享一个数据库”一样的问题。
3. 将应用程序的配置托管在远程服务上
线程池该配置多少个线程?重试策略该怎么配?本地内存缓存的有效时间设置多久合适?需要通过一个远程服务来配置这些东西吗?在很多情况下,把这些东西放在配置文件或者环境变量里是完全可以的,所以可以先考虑这种方式。如果不行,可以尝试一些已有的配置工具,比如 Consul,尽量避免自己开发浪费时间和精力。
4. 多个服务共享一个数据库
如果架构过于简单,很快也会遇到问题。如果多个服务共享一个数据库,数据库的连接、存储空间和计算能力很快就会不够用。接下来就会出现一些不太好的局面——一些服务使用的表被删掉了。或者,有两个客户端使用了同一张表,其中一个客户单要求对表结构做出修改,这个时候就需要做一些适配才能不影响另一个客户端。在我看来,现在的系统变成了一个分布式单体。
这样做有悖微服务架构的原则,因为微服务应该是独立且自包含的。它们应该拥有自己的数据,并可以完全自由决定该怎么持久化数据。它们存在的目的是为了解耦,为了获得这种灵活性,需要付出一定的代价,但追求灵活性应该成为你的目标。
微服务之间应该通过公开暴露的 API 进行交互。基于 HTTP 的通信可以选择 REST、GraphQL、gRPC,或者也可以使用消息队列,比如 RabbitMQ、Apache Kafka。
5. 结论
希望你们大部分人都很清楚上述的这些问题,不过肯定会有一些人犯下这些错误,也许看了本文后你能学到一些。不管怎样,在微服务这个新奇和多变的世界里犯点错误是在所难免的。