❶ 微服务之间的最佳调用方式
在微服务架构中,服务之间如何互相调用是一个关键问题。服务调用主要有两种方式:RPC方式和事件驱动(Event-driven)方式,也就是发消息方式。消息方式通常被认为是松耦合方式,比紧耦合的RPC方式更优越,但RPC方式在适当场景下也有其价值。
耦合是衡量服务之间依赖关系的一个指标。主要的耦合类型包括时间耦合、容量耦合、接口耦合和发送方式耦合。时间耦合指的是客户端和服务端必须同时在线才能工作;容量耦合指客户端和服务端的处理能力必须匹配,消息队列可以缓冲不足;接口耦合指的是RPC调用有函数标签,而消息队列仅传递消息;发送方式耦合则是RPC是点对点方式,而消息队列支持点对点和广播,减少耦合但使返回值较困难。
事件驱动方式分为事件通知(Event Notification)和事件溯源(Event Sourcing)。事件通知是松耦合的集成方式,微服务之间通过发送消息进行合作;事件溯源则是一种存储数据的方式,将所有事件记录下来作为永久存储层,构建应用程序。事件通知是微服务调用方式,事件溯源是数据存储方法。
事件通知方式在创建“Order”时需要读取“Customer”和“Proct”数据,通过消息同步完成。写数据时,如创建“Customer”或修改信息,通过用户创建页面跳转,创建用户后发送消息通知“Order Service”更新本地“Customer”表。然而,由于“Order”和“Customer”逻辑上紧密相关,事件通知在紧耦合情况下可能效果有限。为了解决紧耦合问题,可以使用RPC或引入上层管理程序。尽管这样并未解除耦合,但可以避免服务之间的直接依赖,提高系统的灵活性。
对于购物流程这样的应用,事件驱动是一个不错的选择。例如,在“Checkout”服务完成后发送“Order Placed”消息,然后“Payment”服务收到消息后处理付款,发送“Payment received”消息,“Inventory”服务收到消息后处理取货,最后“Shipment”服务处理发货。这种方式降低了耦合度,但需要在程序中处理消息,而不是直接跟踪整个流程。
当业务逻辑有固定流程时,RPC或业务流程管理(BPM)可能更方便管理。选择事件驱动还是RPC依赖于技术优势和业务需求。事件驱动方式逐渐成为微服务之间集成的标准调用方式,特别是在大多数情况下。
事件溯源是一种颠覆性的设计方法,将系统中的数据以事件的方式记录下来,并提供操作事件的接口,如事件的读写和查询。事件溯源适用于领域驱动设计(DDD)中,通过有界上下文(Bounded Context)划分微服务。在不同的有界上下文中,共享成员如“Customer”和“Proct”需要在各自的上下文中分别建立类,以确保一致性。
事件溯源作为一种存储方式,可以单独应用于某些微服务,而不必所有服务都采用。Event Store用于存储事件,不同微服务通过向Event Store发送和接受消息进行通信。事件溯源的不足在于数据查询,但可以通过直接查询stream或建立只读数据库来解决。事件溯源的程序实现复杂,且修改事件格式较为困难,但其优势在于可以回放历史状态。
事件通知和事件溯源表面上相似,但它们实际上属于不同的概念。事件通知是集成方式,而事件溯源是存储方法。在集成时使用事件通知,而在内部实现时,事件驱动通常结合数据库使用。
尽管事件溯源的使用正在增长,但它对现有体系结构的颠覆性影响较大,需要对数据存储结构和程序工作方式进行调整。微服务已经形成了一套体系,包括程序部署、服务发现与注册、监控、服务韧性等,这些主要针对RPC方式。因此,在实施事件溯源时,可能需要自己解决一些问题。
服务网关(API Gateway)可以简化客户端工作,减少函数间的耦合度。借鉴API Gateway的思路,可以将多个微服务组织成一个提供统一服务接口的完整功能服务组合,降低RPC调用的耦合度。
降低紧耦合的影响主要有两种方法:同时支持多个版本和服务端向后兼容。前者工作量较大,大多数公司不会采用,后者是更通用的方法,允许新旧客户在不修改程序的情况下使用服务。
微服务的数量不应过多,一般规模的公司可以承受十几个到几十个微服务。然而,如果微服务数量超过几百个甚至上千个,将难以管理。虽然工具已经自动化大部分流程,但工作量仍然较大。从单体程序开始,逐步拆分为微服务是一种推荐做法,但应根据团队情况和管理需求灵活调整。
微服务之间调用方式的选择应基于业务需求和技术优势。事件驱动方式通常被认为更佳,因为它能降低服务间的耦合度。然而,在紧耦合的业务逻辑中,RPC方式仍然有其适用场景,特别是当使用合适的协议如Protobuf gRPC时,可以降低紧耦合的影响。内部微服务设计是一个折中的方案,它将单体程序设计为多个微服务,以减少部署和运维的复杂性。