转载自:https://www.zhihu.com/question/384102981
微服务架构深度解析与最佳实践:https://gitbook.cn/books/5dd4d0d27ed8a775381945fe/index.html
要达到什么样的规模才适合分布式/微服务架构? - 图1

程墨Morgan

简单说就一句话:当规模大到了『每一次部署都是全部部署』这事让你们感觉到『痛』的时候。
所谓『痛』,无外乎三种情况:

不同功能的发布时间羁绊:功能A做好了可以被部署了,但是功能B还在开发中,而且功能A和功能B还有千丝万缕联系,还必须要让功能A等到功能B做好之后才能上线;功能X出了bug,要fix,但是发现必须要功能Y和Z也要跟着一起改,但是他们还有其他问题,依赖于A和B……
资源使用的浪费:比如你的应用一部分花费大量CPU,另一个部分做大量IO,这个应用一起部署,就需要每个机器既要配备大量CPU资源,也要准备好IO资源,多花很多钱,如果分开就没这麻烦了。
开发人员为了赶时髦高喊着要做微服务和分布式:反正他们觉得不做分布式和微服务的话,将来找不到工作,不搞微服务和分布式的话,他们下周就辞职走人。
我还要特别指出来一点哈,『分布式』和『微服务』是两个不同概念,一个系统完全可以是『分布式』的却不是『微服务』的,比如,应用就一个代码库,一起部署,但是部署到不同节点上,你不能说这不是『分布式』系统。

越是复杂的问题,越要抽丝剥茧,把它剥成简单的问题来看。

kimmking

微服务架构首先是一个分布式系统架构。分布式系统的发展由来已久,但是近年来产生了理论和实现的大爆发。

究其原因:分布式系统的发展得益于廉价 pc 硬件使得堆机器成为可能,而单机的成本/容量是非线性的,所以分布式的核心是线性的水平扩展整个集群的功能,以及带来的协调机制,管理复杂度,数据和状态一致性,容错和故障恢复,容量与弹性伸缩,这些通用性的基础能力建设。

简单的翻译一下:单个机器堆资源,升级 CPU 内存加大一倍,想要增加一倍的处理能力且成本不超过一倍,不仅很难、而且不现实了。这样,我们就需要思考怎么通过进一步对于系统里不同功能的部分,拆解开,单独扩展这些能水平扩展的部分,从而在控制成本的前提下,提升整个系统的处理能力。

另外,我们现在都知道,设计系统如果对可靠性,可用性有非常高的要求,那么需要先假设上下游都是不可靠的,依赖的基础设施和网络也是不可靠的,这样就考虑分布式后的分片、复制、故障转移、灾难恢复等,分布式系统下,我们可以对系统的不同性质的节点、不同可靠性可用性要求的组件,做针对性的单独处理。

很多系统看起来是分布式的,其实是一个大单机。 很多系统看起来是微服务的,其实是一个大单体。
就像人月神话里说的,往已经延期的项目,加人手,可能会导致更延期。问题不是出现在应不应该加人,或者应不应该使用分布式上。而是实施的人,没搞清楚关键。比如系统拆成分布式或微服务,然后某个关键地方依然卡住了业务流程,可能整体还不如单机的,扩展性失效,多加机器还不如单机。

为什么?

因为如果希望用多个机器来扩展业务,最后发现各个机器上运行的程序没有划清楚边界职责,多个机器合起来并不比单个机器有更大处理能力,这就是一个大单机。

同样的,如果我们拆分了很多更小独立的服务,但是一个业务请求进来,还是在一些地方被卡住,导致有一些瓶颈使得整个拆分后并不比之前有整体的改进,那么其实是费劲的做了一个大单体系统。

所以合理的拆分微服务,使得我们能够更好的扩展系统是关键,同时如果业务简单,流量不大,不扩展也可以很好的应对,系统对于可用性和一致性要求也不是特别高,那么分布式和微服务,也不是必须的。

微服务系统适合的场景

以下几类系统,比较适合使用微服务架构,或者使用微服务架构改造:

  • 大型的前后分离的复杂业务系统后端,业务越复杂,越需要我们合理的设计和划分,长期的维护成本会非常高,历史包袱也很重,这个问题后面会详谈。
  • 变化发展特别快的创新业务系统,业务快,就意味着天天要“拥抱变化”,每一块的业务研发都要被业务方压的喘不过气,不做拆分、自动化,一方面研发资源永远不够用,活永远干不完,另一方面不停的在给系统打补丁,越来质量越低,出错的可能性也越来越大。
  • 规划中的新大型业务系统,如果有能力一开始就应该考虑做微服务,而不是先做单体,还是发展到一定的阶段再做改造,改造一定是伤筋动骨的大手术,虽然我们可以采取一些策略做得更平滑,但是成本还是比较高的。
  • 敏捷自驱的小研发团队,拥抱新技术,可以直接用微服务做系统,不但的通过快速迭代、持续交付,经过一定时间的尝试和调整,形成自己的微服务实践经验,这样在团队扩大时可以把好的经验复制到更大的团队。

反过来,以下几类系统,不太适合一开始就做微服务:

  • 小团队,技术基础较薄弱,创业初期或者团队新做的快速原型,这个时候做微服务的收益明显比单体要低,快速把原型做出来怎么方便怎么来,用团队最熟悉的技术栈。
  • 流量不高,压力小,业务变化也不大,单体能简单搞定的,就可以先不考虑微服务,不考虑分布式,因为分布式和微服务带来的好处,可能还不足以抵消复杂性增加带来的成本。
  • 对延迟很敏感的低延迟高并发系统,低延迟的秘诀就是离 io 能多远就多远,离 cpu 能多近就多近,分布式和微服务,导致增加了网络跳数,延迟就没法降低。
  • 技术导向性的系统,技术产品,这类产品跟业务系统不同,常规的业务系统研发方法不是太适合。

微服务带来的一些问题

  1. 如何合理拆分微服务,粒度如何控制:对业务按粒度和边界拆解的问题,这决定了我们的服务是不是合理,开发和维护是不是方便。核心思路是深入了解业务。
  2. 遗留系统应该如何改造,从哪儿下手,如何推动:改造遗留系统一般来说比重新做一个新系统更复杂,如何平滑的、最大代价的将老系统改造成微服务,也是一个巨大挑战。
  3. 拆分后的性能应该如何保障:性能有两个指标,关键是区分出来如何处理不同特性的数据,关注不同的指标,做好优化和选型,针对具体细节具体对待。
  4. 怎么考虑拆分后的数据一致性,分布式事务的选取和取舍:多个服务间的业务数据一致性的问题,事务是个需要重点考虑的问题,主要是考虑强一致性的分布式事务还是可以使用最终一致的弱一致性。对于一般的业务,可能使用补偿冲正类的做法,在业务允许的一定时间内数据达到一致状态即可,比如 30s,或者 10 分钟。
  5. 系统和服务的高可用可伸缩如何实现:高可用意味着系统稳定健壮,可伸缩意味着弹性,资源有效使用,如何做到无状态、不共享,是实现可高用可伸缩的关键。
  6. 拆分过程的测试和部署如何处理,怎么提升管理能力,降低风险:跨系统的协作问题、测试的问题,这对于技术能力和研发成熟度较低的团队,会带来很大麻烦。核心思路定义好业务边界、系统间接口与数据标准,提升自动化测试水平。微服务架构由于拆分粒度较细,测试是个大问题。在保持每块职责单一的同时,关键是保证接口稳定,做好自动化测试(特别是 UT 和接口的自动化)和持续集成,尽量少全流程的人工回归测试。部署单元太多导致维护成本上升的问题,要管理的点多了,问题自然复杂了,核心思路是自动化部署与运维。
  7. 拆分后的运维和监控如何处理:怎么应对系统的故障,关键是保障核心技术的指标,以及业务指标,做好预警报警,积累问题、寻找根因,控制和杜绝低级失误。

如何合理拆分微服务

  • 业务所处领域的市场性质:对市场比较敏感的项目,创业初期粒度应该尽量划分的粗一些,先提供充足的弹药去占领市场,然后再去考虑对系统进行重构和优化;
  • 与原有系统之间的关系:对于历史遗留的系统,需要做好新旧系统之间的边界划分,避免过于激进、过大幅度的改造,应该采取小步快跑的方式,有节奏的对老系统进行服务化改造;
  • 开发团队的成熟度:服务化带来的技术风险应该提前进行评估,要考虑团队的承受度,用合适的人做适合的事,考虑团队需要有包括敏捷,包括 Devops,包括基础设施,运维和测试的自动化等基础能力;
  • 基础设施的搭建能力:在进行细粒度的服务划分时,要考虑团队是否有足够的能力来支撑大量服务实例运行的运维复杂度,是否可以做好分布式的日志追踪和服务的监控;
  • 测试团队的测试执行效率:过于细粒度的服务划分,如果测试团队不能通过自动化测试、自动回归、压力测试、极限测试等手段来提高测试执行效率,必然会带来测试工作量的大幅度上升,进而影响整个项目的上线周期;

至于拆分的基本原则,我推荐:
高内聚低耦合:这个已经提了很多了,简单说一下,就是要把强相关的部分,总是会一起改动的部分,聚合到一起,相关性不大的部分拆开,可以参考 DDD 中的一些办法。
粗粒度服务:服务的粒度要稍微的抽象和粗粒度一些,因为服务是基于业务场景的抽象和设计,不能做成是直接把数据库的增删改查暴露出来成接口和方法,而是应该隐藏这些细节,考虑清楚从业务和客户角度来看,哪些步骤和过程,是必须封装起来的,细节隐藏掉,然后对外提供的就是粗粒度的服务,而在单体系统的时候,我们可以直接调用这些细节,无需过多考虑。