花了一个月的时间,终于把《微服务设计》这本书读完了。
这本书的作者是Sam Newman,是ThoughtWorks的技术专家。书的英文版叫《Building Microservices》,在技术圈里很有名,被很多人称为微服务领域的"圣经"。
我之前对微服务的理解,停留在"把一个大系统拆成很多小服务"这个层面。读完这本书之后,我发现微服务远不止拆分这么简单。这篇文章,我想分享一下读完这本书的收获,以及它如何改变了我对微服务的认识。
微服务不是银弹
这本书给我的第一个冲击是,作者在一开始就强调:微服务不是银弹。
很多人觉得,微服务是解决所有架构问题的万能药。系统慢了,拆微服务;团队协作不好,拆微服务;技术栈老旧,拆微服务。但作者明确指出,微服务有它的适用场景,也有它的代价。
微服务的好处很多:独立部署、技术栈灵活、故障隔离、团队自治。但微服务的代价也很大:分布式系统的复杂性、网络延迟、数据一致性、运维成本、服务间通信的开销。
作者说,很多团队在没有搞清楚这些代价的情况下,就盲目地采用微服务,最后搞得比单体应用还糟糕。这一点我深有体会。我之前待过的一家公司,本来一个好好的单体应用,为了"追潮流"拆成了几十个微服务,结果部署复杂了,排查问题困难了,性能反而下降了。
这本书让我明白,架构选择是一种权衡。没有最好的架构,只有最合适的架构。在决定采用微服务之前,一定要想清楚:你的问题是不是微服务能解决的?你能不能承受微服务带来的复杂性?
什么是真正的微服务
这本书给我的第二个收获是,搞清楚了什么是真正的微服务。
很多人以为,微服务就是把代码拆成多个模块,每个模块单独部署。但作者说,这只是表面。真正的微服务,有几个核心特征。
第一个特征是,每个微服务都是独立的业务能力。不是按照技术层拆分(比如把数据访问层拆成一个服务),而是按照业务领域拆分(比如用户服务、订单服务、支付服务)。每个服务都应该有明确的业务边界,能够独立完成一个完整的业务功能。
第二个特征是,每个微服务都可以独立部署。你可以只部署其中一个服务,而不需要部署整个系统。这意味着,服务之间必须是松耦合的,一个服务的修改不应该影响其他服务。
第三个特征是,每个微服务都有自己的数据存储。这一点很多人做不到。很多所谓的微服务,其实是共享同一个数据库的。作者说,共享数据库是微服务最大的反模式。因为共享数据库会导致服务之间紧耦合,一个服务修改了表结构,其他服务都可能受影响。
第四个特征是,每个微服务都可以用不同的技术栈。你可以用Java写用户服务,用Go写订单服务,用Python写推荐服务。因为服务之间通过API通信,技术栈不影响。
读完这部分之后,我回头看之前接触过的一些"微服务"项目,发现很多都不符合这些特征。它们只是把一个单体应用拆成了多个部署单元,但业务边界不清晰,数据还是共享的,本质上还是一个分布式单体。
服务拆分的原则
这本书花了很大的篇幅讲服务拆分,这也是我最有收获的部分。
作者提出了几个拆分的原则。
第一个原则是,按照业务领域拆分。用领域驱动设计(DDD)的方法,先找出业务中的限界上下文,然后每个限界上下文对应一个微服务。这样拆分出来的服务,业务边界清晰,内聚性高。
第二个原则是,服务应该足够小,但不能太小。作者用了一个很形象的比喻:微服务应该小到可以被一个团队"持有",也就是一个团队可以负责一个或多个微服务的开发、测试、部署和运维。但也不能太小,太小了会导致服务数量过多,运维成本剧增。
第三个原则是,先从单体开始,然后逐步拆分。作者不建议一开始就做微服务。他建议先做一个设计良好的单体应用,在模块之间建立清晰的边界。等业务发展到一定程度,确实需要拆分的时候,再把模块拆成独立的服务。
这个观点对我影响很大。我之前一直觉得,新项目就应该直接上微服务。但作者说,大部分项目在初期都不需要微服务。微服务的复杂性在项目初期是负担,而不是优势。等用户量上来了,团队变大了,再拆分也不迟。
第四个原则是,拆分要渐进式进行。不要想着一次性把整个系统拆完,那样风险太大。应该先拆一个服务,跑通整个流程,积累经验,然后再拆第二个、第三个。
服务间通信
服务间通信是微服务中最容易出问题的地方,这本书讲得很详细。
作者把服务间通信分成两种:同步和异步。
同步通信就是HTTP REST或者gRPC。优点是简单直观,请求响应模式容易理解。缺点是耦合度高,一个服务挂了,调用它的服务也会受影响。而且,同步调用会增加延迟,因为调用方要等待响应。
异步通信就是消息队列。优点是解耦,调用方发完消息就不用管了,被调用方什么时候处理都行。缺点是复杂,需要处理消息丢失、重复消费、顺序保证等问题。
作者的建议是,尽量使用异步通信,只有在需要立即得到响应的时候才用同步通信。而且,不管用哪种通信方式,都要处理好失败的情况。
关于失败处理,作者强调了几个关键点:超时、重试、熔断、降级。这些概念现在已经很普及了,但在这本书出版的时候(2015年),还是比较前沿的。
还有一个很重要的点是,服务之间的契约。作者建议使用消费者驱动的契约测试。也就是由服务的消费者来定义契约,提供者必须满足这些契约。这样可以确保服务的修改不会破坏消费者的使用。
数据管理
数据管理是微服务中最难的部分,这本书也花了很多篇幅来讲。
第一个问题是,每个服务有自己的数据库之后,跨服务的查询怎么做?比如,你要查询一个用户的所有订单,用户信息在用户服务,订单信息在订单服务,怎么联合查询?
作者的建议是,不要做跨服务的数据库查询。应该通过API调用,或者在查询服务中做数据冗余。比如,可以建一个专门的查询服务,把用户和订单的数据同步过来,专门用于查询。
第二个问题是,分布式事务。在单体应用中,一个事务可以同时操作多个表。但在微服务中,一个业务操作可能涉及多个服务,每个服务有自己的数据库,怎么保证数据一致性?
作者说,不要用分布式事务(比如两阶段提交),因为性能太差,而且复杂。应该用最终一致性。比如,用事件驱动的方式,一个服务完成操作之后发事件,其他服务订阅事件做相应的操作。如果中间有失败,通过补偿机制来处理。
第三个问题是,数据的迁移和演进。服务拆分之后,数据库也拆分了。原来的一个大表,可能要拆到多个服务的数据库里。这个迁移过程很复杂,需要仔细规划。
作者建议用"绞杀者模式"来做迁移。也就是,新的请求走新的服务,旧的请求还走旧的系统。逐步把功能从旧系统迁移到新服务,最后旧系统完全被"绞杀"。
部署和运维
微服务的部署和运维,比单体应用复杂得多。
作者强调了自动化的重要性。微服务数量多,如果手动部署,根本忙不过来。必须有自动化的部署流水线,从代码提交到测试到部署,全部自动化。
作者还提到了容器化。这本书出版的时候,Docker刚出来不久,作者就已经预见到容器会成为微服务部署的标准方式。现在看来,这个预测非常准确。现在的微服务,基本上都是跑在Docker和Kubernetes上的。
关于监控,作者说,微服务的监控比单体应用重要得多。因为服务多了,出问题的概率也大了。必须有完善的监控体系,包括日志收集、指标监控、链路追踪。这样出了问题才能快速定位。
这一点我深有体会。之前在一个微服务项目里,有一次用户反馈下单失败。我们查了半天,才发现是支付服务的一个接口超时了。如果有链路追踪,几秒钟就能定位到问题。
我的一些思考
读完这本书,我对微服务有了一些新的思考。
第一,微服务是组织架构的反映。康威定律说,系统的架构会反映组织的沟通结构。如果你的团队是按业务领域划分的,那微服务就很自然。如果你的团队是按技术职能划分的(前端组、后端组、DBA组),那微服务会很痛苦,因为一个服务的修改需要多个团队协作。
第二,微服务的前提是DevOps文化。微服务要求开发团队对服务的整个生命周期负责,从开发到测试到部署到运维。如果还是开发写完代码就扔给运维,那微服务是做不好的。
第三,不是所有系统都适合微服务。如果你的系统业务逻辑简单,用户量不大,团队也小,那单体应用可能是更好的选择。微服务的复杂性,只有在系统足够大、团队足够多的时候,才能体现出优势。
第四,微服务是一个持续演进的过程。不是说拆完了就完事了。随着业务的发展,服务的边界可能需要调整,有的服务可能要合并,有的可能要再拆分。架构是不断演进的,不是一劳永逸的。
写在最后
《微服务设计》是一本非常好的书。它不只是讲技术,更重要的是讲权衡和思考方式。
读完这本书,我最大的收获不是学会了多少微服务的技术细节,而是明白了:架构选择没有标准答案,一切都要根据实际情况来。微服务不是目的,解决问题才是目的。
如果你正在考虑采用微服务,或者已经在做微服务但遇到了很多问题,我强烈推荐你读一读这本书。它可能不会给你直接的答案,但会帮你建立正确的思考框架,让你少走很多弯路。
技术书籍很多,但真正能改变你思维方式的不多。《微服务设计》就是其中一本。
评论(0)
暂无评论,快来抢沙发~
评论功能仅对会员开放,请先登录
登录