(微服务)不就是写一堆小的程序么?
某一天,你正在寻找一种新的方式来重构整个代码库。您考虑过使用一种新的语言,或者在另一个云服务商上进行部署,又或者是使用一种更好的编程模式。之后您找到了它 - 微服务。突然,你发现你可以同时实现这三种方式。
对于初学者来说,“微服务”是一种架构模式,其中,一个应用程序是由多个松散耦合的服务组成,这些服务都可以独立部署。
依你所见,这个架构可以解决你所有的麻烦:
-
设计新产品或者新功能将变得十分容易,你可以创建一个代码库,这个代码库专门用来解决特定的问题。这简直是开发模块化的最理想化实现。 -
具有大量依赖关系的大型应用程序可以进行分解,从而可以更快,更轻松地运行测试套件以及梳理清楚每个域的逻辑 -
你会感觉这就像Google一样 -
微服务使用RESTful API或gRPC之类的工具处理API调用。如果您的单页应用(SPA, Single Page Application)与后台是通过类似方式进行通信的,那么微服务架构将发挥更大的作用。 -
您会感觉就像支付宝(可以使用各种银行卡进行消费)。 -
您可以在每种服务中使用不同的语言和技术栈,以便“使用最佳工具集来完成任务”。
那么可能会出现什么问题呢?
下面我将给出三个论点,为什么微服务不是一件容易的事。我确实认为它们对于构建大型和可扩展的系统很有用,但是必须认识到采用它们的时候会产生的操作和技术上的债务。
标准化问题
一般开始编写微服务的方式就是采用标准的应用程序框架,并使用这个框架来编写一些实用的服务。使用Django,Rails,.Net Core和Spring Boot这些技术的团队,并且肯定不会将其视为反模式。您可能需要针对诸如推送通知,图像大小调整以及域逻辑隔离位之类的功能的服务。
但是问题就出在,有一些元素是需要在多个代码库中标准化的。例如:
- 指标
- 管理云相关的逻辑,例如使用对象村相互或者密匙管理服务
- 密码管理以及任何对环境变量的使用。
- API 约定的Schema定义。
- 服务端逻辑,例如验证,授权,日志记录以及限制.
- 抽象化数据库
您可以通过创建共享库或者一次次重复实现来实现这些逻辑的标准化,但是这存在两个问题:
1. 如果对共享库进行更改,你所有的服务不会自动更新共享库的版本。这使得一些安全性的修复可能变的很难覆盖到所有的服务。这也使得大家不愿意去优化这些共享库。
2. 采用新技术或者新语言,将会导致在开始之前,你便需要为新技术创建或者维护新的库
本·克里斯滕森(Ben Christensen)的演讲中也提出了类似的论据,他在演讲中讨论了创建“分布式整体”的风险。这是一个不公开的视频,已链接到Monzo的博客文章。
我认为Monzo的博客也提示了一个解决思路。他们正在考虑为所有的“共享基础设施”例如数据库和消息队列构建服务。这使得所有跨领域服务依赖关系都可以用API来解决而不是使用共享代码库。这的确很整洁,但是显然需要很多工作。
Devops问题
不需要多说,当你需要部署一大堆服务的时候,持续集成和部署将会令人头痛,这里有两个例子:
- 你需要进行复杂的端到端测试来确保所有的服务服从API约定。但是,如果你有一个服务,比如一个邮件发送器,当众多服务被测试时,需要模拟出特定的测试条件,你该怎么办?你是替换掉整个服务,还是在服务本身有一些逻辑来识别它是否在端到端的测试场景?
- 服务越多,你将花费更多的时间来配置你的部署。例如,如果你有一个架构,每个服务都有自己的数据库,那么可能需要为每个服务配置不同的密码。这就加大了生产中的配置错误的可能性,也增加了自动化创建新环境的难度。
对于以上问题,一个微服务工程师可能会配置一大堆
.yaml
文件,或者使用一个容器编排框架,例如Kubernetes,但是我不会使用Kubernetes,除非我能请一个专门的工程师来管理Kubernetes。
- 网络非常复杂。分布式系统预设了服务之间的联网,但要安全、可靠地做到这一点,需要花费一些心思。如果出现服务超时怎么办?我们要重定向失败的HTTP请求吗?我们需要对流量进行加密吗?
- 设置一个编排框架`并不容易。云提供商仍然会要求你来考虑需要配置什么硬件,这往往会让人感觉与市场上的无服务器(serverless)解决方案相去甚远。在某些情况下,对于早期初创企业, 如果寻求少量部署配置,无服务器架构可能是一个更好的选择。
- 定义服务,尽管我很喜欢manifest文件来声明方式,但是这并不简单。我们需要定义资源限制以及扩展策略,这些都不能很明显的知道,需要在生产版发布之前,进行实验,才能很好的去定义这些。
这些问题都不是不可克服的。事实上,我很期待Knative产品(如Google Cloud的Cloud Run)能将无服务器范式的元素带到更传统的微服务部署中。同样,CI/CD的问题也可以由一个聪明开发团队来解决。
但是,同样,这并不容易,需要合理规划。
开发问题
如果采用微服务架构,那么在写代码的思路上做出重大改变。
下面是一些例子:
- 微服务通常预设每个服务都应该被编写成可以通过编排框架来自动进行水平扩展。这可能需要那些来自单例应用的人考虑一些问题,比如管理共享资源连接池,以及共享内存内信息等问题。
- 像Kubernetes这样的编排框架也可能会频繁地关闭或启动服务,并期望任何服务都能处理好。尽管如此,优雅的关机并不容易,而且--根据你的技术栈--可能需要思考如何记录日志和确保完成任何正在进行的计算。
- 最后,许多微服务架构将利用消息队列来构建的基于事件的架构。有些消息队列技术会保证至少一次交付,这就要求处理程序在消息重复的情况下,必须是幂等性的。在一个大型系统中,实现、测试和维护方面会相当头疼。
公平地说,以上三点可能是大多数架构中部署时需要考虑的事情。然而,微服务可能意味着你的每个服务都需要无数次面对这些问题。
结论
微服务有其适用的时机和地方,但其进入门槛比许多人认为的要高得多。这种架构是可以逐步采用的,但是在设计和规划阶段需要付出大量的努力和专业知识就才能开始采用。
-----
【原文链接】
Why Microservices Should Scare You More
译者介绍 Grace,程序员,研究生毕业于SUNY at Stony Brook,目前供职于Linktime Cloud Company,对大数据技术以及数据可视化技术感兴趣。