简介 微服务的神秘和背后的知识令我着迷。微服务作为概念,它属于现代最有趣的架构之一。微服务应用广泛,涉及不同的使用场景。但也有很多地方模糊不清,难以定论。 人们在讨论微服务时,我会努力理解他们的真实意图。尽管在上一次演讲中我分享了对微服务的认识,但我很清楚其它公司和我们使用的架构是不一样的。最近我询问了一位同行,了解到他们部署微服务的方式(和我)不同。所以我打算通过比较这两种方式向技术大会的观众介绍微服务。 这篇文章会举两个例子。第一个是我上次演讲中的微服务例子,属于困难模式。第二个例子以流式架构实现微服务,在我了解的为服务使用场景中,它更接近微服务应用的“理想情况”。 微服务基础 我认为微服务作为架构由以下因素演进而来:
伸缩调整、易于获取新硬件、分布式系统与网络,将这些因素结合起来,会发现它们在我提出的“microservice for CRUD”概念中作用巨大。如果你将一家公司拓展到将近成功的水平,但在技术/工程团队拓展上遇到麻烦。将庞大单一的管理拆分成service-style的架构会有很大帮助。这是我的亲身经历。 微服务的要点看起来像这样:
我还准备了一些笔记。人们经常弄混“Monolith”和“monorepo”。一个Monolith风格的应用是指把一组代码编译成单独的服务交付件(过程中可能会产生额外的客户端交付件)。你可以通过配置文件来让交付件做几乎任何你能想象的事情,包括上文所有的service-type,但是如果所有代码没有集中放到一个仓库中,这样做最后会生成很大的镜像,也会导致混乱,因为团队有时会根据不同的构建工具和配置文件编译生成不同的交付版本。我依然认为这种架构是单一架构。 Monorepo或者是monolith repository是一种模型,它指一个单一的代码仓库,包含了你正在编码的系统的所有代码(很可能还不包括OSS/外部依赖的源代码)。代码仓库中的代码由多个独立的应用交付件组成,这些代码都可以独立编译/打包和测试,不需要整个仓库的代码。monorepo的一个优势是,当修改了共享库的版本后,依赖共享库的开发人员可以更容易地开发,而不用去等其他团队更新依赖库的版本后再开发。monorepo模型最大的缺点是,支持它的OSS工具不多,因为大部分OSS工具不是这么构建的。所以需要大量投资开发新的工具来支持monorepo模型。 基于CRUD应用的微服务 在介绍CRUD应用由单一架构到微服务架构演进之前,我会先介绍构建中等规模CRUD平台所需的架构设计。这种平台有一个不错的用例,它涉及“事务”和“元数据”。 事务:指用户做了一个行为,你想把它持久化,这里数据的一致性最有价值。CRUD中的Create,Update,Delete操作频率比Read低得多。 元数据:描述用户的信息,但是只能由内部内容创建者修改,外部用户(比如审查者)很少能修改。通常具有很高的可缓存性。甚至有时能够容忍一定程度的临时不一致性(显示陈旧的数据)。 CRUD依赖型公司还有哪些能做的事呢,尤其是分析领域?当然有,你可能需要根据用户在浏览网站时的行为以及其它个性化的操作来频繁地调整结果。但是做到实时调整结果很困难,因为你不一定总是能从用户那里得到足够的数据来达到最好的效果,所以这(指上文调整结果)不是系统的一级关注点。 这种架构在迁移过程中是相对简单的:
基本上就这些了。你需要做的是收集足够的用户函数、数据和术语,然后改成微服务架构并开发新的功能。 这些服务不是典型的SOA,也不是很小的微服务。拥有数据的服务会更复杂。你可能不想要太多服务,因为你希望在满足用户请求的同时,不需要太多的网络跳转,甚至不需要分布式事务(理想情况)。 可能你不需要每天都开发新的服务,特别是当你有一个五十人的工程团队和一个长期的产品路线图时,你可能不会为了“点一下按钮就动态添加一个新的功能”而投入大量的工程时间到开发编排和工具上。 决定投入多少时间在工具上很简单:开发人员花费在自动添加新服务的时间VS实现和维护自动化程序的时间VS随着时间的推移,你希望添加多少新的服务?比较下它们就可以了。显然,如果你认为让人们能够快速频繁开发微小的服务很重要,你最好投入更多的时间和开发更多的工具。与所有工程优化决策一样,这样做不代表它完全正正确,但是在可预见的未来,它是正确的,而且我们还需要不断地重新评估。 在这个实例中,我发现有许多是微服务必须具备的。比如上文中我提到过很多次的编排。但是如果你不需要自动启动服务或频繁地迁移服务,你则不需要动态服务发现(如果需要的话,负载均衡器是一个不错的选择)。 允许团队为每个服务选择合适的语言、框架和数据存储也不是必须的。事实上,对于你的团队这样做可能是一个令人头疼的问题而不是福音。
这是真实存在的,但是对于较小的团队,可以通过事先约定好规则来禁止共享数据库结构(如果还有顾虑,可以通过代码审查、自动测试和检测来预防)。如果你很仔细地定义数据相关的服务,不太可能发生这样的事情。另一种方法在下一段介绍:
上面这段可能令很多经验丰富的数据检测工程师失望(译者注:因为商业检测服务不支持伸缩,言下之意是要自己开发)。 正是由于数据检测的开销,我鼓励小型组织,在决定使用完全独立的数据存储或个人存储之前,要评估约定数据库共享的方法。决定最终使用何种数据存储服务是可以根据需要来推迟的。 这一版本的微服务架构在扩展CRUD应用方面令人期待,因为这种架构允许你分块重写代码。你可以重写整个系统,或者简单地修改对缩放最敏感的部分。你需要主动参与到涉及到分布式系统复杂性相关问题上,仔细思索数据和基于数据的事务。可能你不需要大量的数据管道,就知道哪里的数据需要修改。 我一定要用微服务来扩展这些吗?答案很可能是no,但是并不意味着使用微服务来扩展系统是一个坏的作法。但是使用极端的微服务模型可能是一个坏主意,因为你很可能不想以分布式事务的方式来切分你的数据。 基于数据处理流的微服务 现在我们讨论一个非常不同的使用案例。这个例子不是你们熟悉的CRUD应用,也不包含臃肿的企业规则和事务更新。相反,这个案例包含大量的数据流。它从不同的数据源接入许多小数据,小数据又汇聚成大量数据。不仅有大量的数据,还有大量的服务来消费、修改数据,或者存储起来以便进一步使用。 主要关注点是接收大量不断变化的数据,以各种方式处理它,并以合适的视图展示给客户。而这些在CRUD应用中是次要的。 我们以一个聚合度量(Metrics)信息的SaaS应用为例。这款应用的客户遍及世界,各种应用、服务、机器都将度量信息发送到聚合器。这些客户只需要查看他们的数据,虽然任何一个客户的数据总数可能非常大。我们的聚合器需要处理这些度量信息,并将它们发送到负责显示给客户的程序。面向客户的应用能够操作实时输入的数据以及来自缓存或者后端存储系统的历史数据。数据的最大价值在于数据在移动窗口内现在/最近都发生了什么。 这种架构从一开始就要考虑数据容量问题,而这在CRUD世界里可能很长时间都不用考虑。另外,数据本身是随着时间不断更新的。“有状态”的数据在事务上最小化更新,最有用的数据是时间序列或者事件日志。事务性的数据,比如存储用户视图、配置等,它们类似CRUD中的“元数据”,与流数据相比很少改变。开发者的时间大部分用于管理输入流、提供新的输入类型、对输入流进行计算或者改变计算方式,而不是处理事务性数据的变更(CRUD)。 本例中,你可以假设一个服务,想要通过对数据流上的特定元素执行不同的计算来进行实验。不修改现有的代码,实验性服务选择一个时间点开始监听数据流,执行新的计算得到新的结果,然后将结果推送回数据流的不同信道上。某一时刻,实验程序从实验客户那提取数据,然后将实验计算结果而不是标准结果返回给客户。你需要记录所有步骤,用于实验完整与调试分析,不要求记录非常详细或者是系统事件甚至用户相关的事务性信息。 本例中,为了更快运行实验程序,编写新的代码可能比更改原有的服务代码更简单。特别是新开发的服务不需要担心调整数据消耗或者与现存服务的计算结果冲突。这就是我所说的“以数据流为中心的微服务”。
Cron job作为微服务 如果没有提到这一点将是我的疏忽。当一切微服务化非常容易时,自然也包括传统的cron job微服务化。 cron job是很好的概念,它没有把一切都视作“服务”。你可以用AWS的CloudWatch Events或者是调度Lambda函数实现这个目的(将cron job微服务化)。也可以使用Gearman调度cron job,它是一个支持队列和异步作业的运行程序。注意你的cron job必须幂等(同一个输入运行两次结果不变)。如果你有更简单的方法运行服务或者是基础的cron job,那没问题(你不需要微服务化)。 【基于Docker的DevOps实战培训 | 南京站】培训内容涉及容器编排框架(应用部署)、Ansible 简介、持续集成常用方式、典型案例分析、容器的选择、架构设计(百万级日活,亿级API 请求)、数据系统构建、持续集成的开发流程等,点击下面图片即可查看具体培训内容。 |