Cloud Native (国内译为“云原生”),最早是 Matt Stine 提出的一个概念。与微服务一样,Cloud Native 并不是一种具体的技术,而是一类思想的集合,包括DevOps、持续交付(Continuous Delivery)、微服务(MicroServices)、敏捷基础设施(Agile Infrastructure)、康威定律(Conways Law)等,以及根据商业能力对公司进行重组。Cloud Native 既包含技术(微服务,敏捷基础设施),也包含管理(DevOps,持续交付,康威定律,重组等)。所以,Cloud Native 也可以说是一系列Cloud技术、企业管理方法的集合。 Cloud Native 具备有以下特性:
微服务虽然带来了架构上的优势,但同时也引入了复杂性。我们不得使用一些组件,来解决技术复杂性提高之后带来的问题:
微服务系统的衍生组件还有很多,比如对各个服务进行的配置管理的分布式配置中心、各个服务之间进行消息通讯的消息总线和消息驱动机制(上图中的Message Queue)等。
「微服务」 是业内最近两三年业内很火的 buzzword,迁移到微服务架构,大多强调这些好处:
经过服务的拆分,将复杂到难以移动的单体应用,拆分为多个可以独立部署的服务,单个服务的复杂性远远小于整体,这样不同服务的开发者可以并行开发,从而提高开发效率;因为服务的细粒度,可以 assign 给一个具体的人让他负责,随着业务的增长对服务做定向扩容;同时因为服务的隔离性,可以隔离故障,提高整体的稳定性。
RPC (远程过程调用)是服务化体系中基础的基础,但是慢慢的我们发现 RPC 并非分拆的唯一选择。基于 RPC 的水平分拆会引入中间层次,增加联调的环节,对于快速开发的新业务而言,无法忽视额外的联调成本。
这里我们得到的启发是,服务的分拆并非 RPC 不可。相反,我们希望看到更少的 RPC,更多的内聚。更少的 RPC 接口意味着更小的服务边界,更稳定的接口,更少的 break change。内聚意味着允许功能需求的独立演进,对其他业务的影响降到最低,也意味着内聚的业务模块内部,可以充分利用缓存来优化性能。
理想的世界里,服务边界恰好匹配于业务边界。然而工程师首先要承担业务需求的压力,只能抽时间重构拆分,业务边界也并不总是如新项目那样明晰。
这意味着要考虑优先级,也需要在拆分之前认真地思考业务的边界。排定优先级,考量拆分的收益与风险即可。划分业务的边界,则需要更多的思考拆分后的未来将如何沟通协作,然后再考虑技术因素。目前我们主要有这几个考量:
以 feed 为例,它首先拥有独立团队维护,通过拆分,技术层面上允许 feed 团队重构掉下层服务与上层展现之间的冗余 RPC 调用,且调用模式较 uniform,在产品层面接受数据最终一致性的前提下可以通过 TTL 缓存提升性能,乃至按自己的业务场景做更细致的优化(优化结束后我们的某些接口 P95 性能加快了一倍);更重要的是对协作方式的影响,未来专栏、问答等生产信息的垂直业务,只提供一个 RPC 接口对接 feed 流即可,而不必集成到主站,这一来 「接入 feed」 流程的参与者,从 feed 组、垂直业务、主站三方,简化为 feed 组和垂直业务双方;此外 feed 通过 TTL 缓存,实质上冗余了一份垂直业务的数据,配合断路器的使用,依赖的垂直业务的抖动甚至崩溃在 feed 这边都可以优雅降级且保持正常展现了。将 feed 与主站的变更相隔离,也有助于改进作为一项核心业务的 feed 的稳定性。
在垂直业务之外,也存在多数业务都会重用的公共服务,如用户、话题、网页抓取、多媒体、推送等。业务服务和公共服务在关注点上有所不同: 我们希望业务服务快速迭代,更快、更好地响应多变的业务需求,更多地面向前端工程师; 我们希望公共服务稳定可靠,较少发生改动,但 SLA 要好,更多地为业务重用;
这里会形成一个自然的分层:上层业务求快、下层公共服务求稳。