组合式应用新利器,事件网格“出圈”!

业界 作者:CSDN 2022-04-18 17:09:37


作者 | Alex Luo、钟鸣拓、吕广林
出品 | CSDN(ID:CSDNnews)

在SaaS新时代下,业务适应性需求引导企业向快速、安全和高效应用的技术架构转变。组合式应用作为加速数字化的关键技术是Gartner提出的2022年重要战略技术之一,它由以业务为中心的模块化组件构建而成,使技术和业务团队可以更敏捷、更有效地重用代码。

组合式应用需要面临的一个难题是如何解决各个应用之间的集成标准问题,比如应用可能仅支持HTTP、TCP等协议中的一种,而缺乏统一的通讯标准就给业务落地该架构带来了困难。下面本文将分享如何基于事件网格(EventGrid)来解决这一问题。

事件网格是华为云中间件在云原生时代推出的新一代无服务器事件总线,承载和管理来自传统应用、云服务应用和SaaS合作伙伴应用的各类事件,帮助应用开发者轻松搭建高可用、松耦合、分布式的事件驱动架构。

作为Serverless架构下事件驱动架构的关键一环,它提供弹性、异步、去中心化的事件治理服务,对事件提供汇聚、模型校验、过滤、路由、转换和推送等核心功能,还包括容错重试、死信储存、事件查询跟踪、事件工作流等增强特性。

EventGrid总体架构图

从上图可以看出,EventGrid对接了一系列云服务作为事件源。

这些云服务包括分布式消息服务(如RocketMQ、Kafka和Pulsar)、对象存储服务(OBS)和分布式缓存服务(Redis) 。事件源会产生管理类、数据类和自定义事件,然后通过EventGrid SDK推送到EventGrid事件总线(Bus Runtime)的事件通道中。事件总线为EventGrid用户以租户为单位配置事件通道,一个租户下允许有多个事件通道,承载来自不同事件源的事件。比如默认事件通道存储华为云产生的事件,而自定义事件通道存储应用和微服务的事件。EventGrid用户通过订阅的方式消费事件,通过在订阅的配置项里定义事件源、事件目标、事件过滤和转换规则,EventGrid就能从事件总线里提取相关事件,然后实时推送到所定义的事件目标中。推送方式可以是同步和异步:同步推送一般是以HTTP协议,适合应用和微服务;异步推送一般是推动到SaaS伙伴应用的消息队列中。

所以,EventGrid通过事件驱动的方式联动周边的云服务、云原生应用和SaaS伙伴应用,实现服务和应用之间解耦,专注发挥自己服务的优势,通过各种事件模型连接,为华为云创造更多的应用场景,也进一步丰富了开发者生态。


以EventMesh为引擎


我们在EventGrid中引入了开源明星项目Apache EventMesh,作为运行时引擎。Apache EventMesh是云原生的事件驱动架构中间件,用于分离应用程序和后端事件存储(Event Store),支持广泛的应用场景,包括混合云和传统数据中心,以及不同技术栈的分布式架构。

Apache EventMesh的理念和EventGrid很类似。它也是连接事件源,聚集事件,然后把事件推送到客户端。它的亮点是其内核可以支持插件化。根据不同的事件应用场景,可以接入不同的插件来匹配。比如在事件接器(Event Connector)方面,可以对接RocketMQ Connector或者Kafka Connector。在HTTP授权(Http-Auth)方面,可以引用BasicAuth或者TokenAuth。这样灵活的架构有助于打造生态系统,对接不同的产品和服务。


EventMesh gRPC特性


Apache EventMesh最新发布的v1.4.0版本相比之前的版本又增加了多个重要特性和架构优化,其中一个亮点是对于gRPC的支持

gRPC是由谷歌开源的基于HTTP/2的现代高性能RPC(Remote Procedure Call)框架。相比HTTP协议,gRPC支持Client 和 Server双向异步通讯,通过Protobuf 定义API接口数据模型,支持多语言SDK。通过实现gRPC协议,Apache EventMesh可以整合原有的TCP和HTTP协议,让当前运行时轻量化。同时其SDK可以扩展到多语言支持,比如Java、Go、JavaScript等等。


Protobuf设计


EventMesh引入gRPC,首先从设计Protobuf定义(eventmesh-client.proto) 开始。我们在eventmesh-client.proto文件里定义EventMesh事件发送和订阅服务的方法和事件模型。由于篇幅原因,以下仅介绍定义的重点部分,完整的文档请见:

  • https://github.com/apache/incubator-eventmesh/blob/master/eventmesh-protocol-plugin/eventmesh-protocol-grpc/src/main/proto/eventmesh-client.proto

1.事件发送服务提供以下接口:

service PublisherService {

   rpc publish(SimpleMessage) returns (Response);

   rpc requestReply(SimpleMessage) returns (SimpleMessage);

   rpc batchPublish(BatchMessage) returns (Response);
}

事件是以SimpleMessage的数据模型呈现。事件发送支持同步发送、异步发送和批量发送三种模式。

  • 同步发送是指事件生产者发送事件到EventMesh,并等待事件成功推送到事件消费者,并收到事件消费者的返回,才算完成整个端到端的事件发送过程;

  • 异步发送是指事件生产者发送事件到EventMesh即可,无需等待事件被成功推送到事件消费者;

  • 批量发送是指异步发送一批事件到EventMesh。

2.事件模型如下:

 message RequestHeader {
    string env = 1;
    string region = 2;
    string idc = 3;
    string ip = 4;
    string pid = 5;
    string sys = 6;
    string username = 7;
    string password = 8;
    string language = 9;
    string protocolType = 10;
    string protocolVersion = 11;
    string protocolDesc = 12;
}

message SimpleMessage {
   RequestHeader header = 1;
   string producerGroup = 2;
   string topic = 3;
   string content = 4;
   string ttl = 5;
   string uniqueId = 6;
   string seqNum = 7;
   string tag = 8;
   map<stringstring> properties = 9;
}

事件模型可以支持多种协议,包括CNCF CloudEvents、OpenMessenging和EventMesh原生事件协议,这些协议都在SimpleMessage的protocol相关字段中体现。另外模型中带有producerGroup和topic用于事件的路由;ttl、uniqueId和seqNum则是用于事件的管理。请求头里带有事件生产者的基本信息:env、region、idc、ip和sys。

3. 事件订阅服务提供以下接口:

service ConsumerService {

   rpc subscribe(Subscription) returns (Response);

   rpc subscribeStream(stream Subscription) returns (stream SimpleMessage);

   rpc unsubscribe(Subscription) returns (Response);
}

事件订阅支持两种方式:集群(cluster) 和广播(broadcast)

  • 集群模式中,事件消费者集群里只有一个实例能消费到事件;

  • 广播模式让集群里每一个实例都消费到事件。

这些订阅模式是在订阅数据模型里定义的。另外订阅服务提供两种订阅接口:subscribe API和subscribeStream API

  • Subscribe API是通过url方式推送事件到消费者,这里url又叫webhook。这种场景适合云原生微服务和自定义应用及函数。

  • subscribeStream API是通过gRPC 双向流(Bidirectional Streaming) 推送事件到消费者 ,同时可以让事件消费者返回确认信息 (Ack) 给事件生产者。这就满足了生产者RequestReply同步事件发送的需求。


服务端的多线程并发


为了提高事件生产和消费的性能,EventMesh服务端(EventMesh Runtime) 在gRPC的服务里定义了线程池(ThreadPool),而且针对事件生产和消费的对性能要求的不同,配置独立的参数。这些参数都可以在EventMesh配置文件(eventmesh.properties)里找到。

比如以下分别是事件生产,订阅和推送的线程数。

eventMesh.server.sendmsg.threads.num=50
eventMesh.server.clientmanage.threads.num=30
eventMesh.server.pushmsg.threads.num=50

当gRPC服务启动后,它会监听客户端的请求,一旦有新请求进来,它会分发到对应服务的线程池,然后让对应的处理器(Processor)处理,这样就不会阻塞下一个请求的处理,从而提高了并发量。

public void publish(SimpleMessage request, StreamObserver<Response> responseObserver){
    cmdLogger.info("cmd={}|{}|client2eventMesh|from={}|to={}""AsyncPublish",
        EventMeshConstants.PROTOCOL_GRPC, request.getHeader().getIp(),
        eventMeshGrpcServer.getEventMeshGrpcConfiguration().eventMeshIp);

    EventEmitter<Response> emitter = new EventEmitter<>(responseObserver);

    threadPoolExecutor.submit(() -> {
        SendAsyncMessageProcessor sendAsyncMessageProcessor = new SendAsyncMessageProcessor(eventMeshGrpcServer);
        try {
            sendAsyncMessageProcessor.process(request, emitter);
        } catch (Exception e) {
            logger.error("Error code {}, error message {}", StatusCode.EVENTMESH_SEND_ASYNC_MSG_ERR.getRetCode(),
                StatusCode.EVENTMESH_SEND_ASYNC_MSG_ERR.getErrMsg(), e);
            ServiceUtils.sendRespAndDone(StatusCode.EVENTMESH_SEND_ASYNC_MSG_ERR, e.getMessage(), emitter);
        }
    });
}

比如以上代码是事件发送服务(publish service) 的实现。它使用了threadPoolExecutor把事件发送到线程池让下游SendAsyncMessageProcessor处理。


事件消费者的负载均衡和重试


在事件消费者方面,EventMesh支持负载均衡。用户可以在事件订阅里指定多个事件消费者来消费事件。每个消费者会是一个URL(Webhook)或者gRPC客户端 (stream),这些消费者可以是集群或者是主备方式部署。

那么EventMesh会通过算法计算选择其中一个消费者去推送事件。如果当前消费者无法消费事件,那么EventMesh会选下一个消费者。EventMesh默认以轮询方式选择消费者推送事件,来达到消费者的负载均衡。开发者可以通过插件提供其他算法来选择消费者。

事件推送失败,可能是网络原因,当前消费者繁忙或下线。EventMesh先尝试重试,每次重试会间隔几秒钟,最多重试3次。如果3次重试失败了,EventMesh才会选择下一个消费者。重试间隔时间可以在配置文件里定义。


gRPC non-Blocking和Blocking Stub


为了提高客户端性能,gRPC提供了非阻塞存根(non-Blocking Stub)。使用non-Blocking Stub客户端发送请求后不需要等待服务器回复,继续进行执行下一步操作。这很适合在大量事件生产的场景。但是在事件RequestReply场景下,客户端需要同步的等待事件成功推送到事件消费者,我们就需要gRPC的阻塞存根(Blocking Stub)。

通过给客户端提供的两种选择,可以更灵活的满足不同的事件生产和消费场景。目前EventMesh SDK使用了Blocking Stub,下一步是使用non-Bocking Stub 提高客户端高并发性能。


 

支持多语言SDK


Apache EventMesh v1.3.0之前只提供Java SDK。这对于接入其他云原生的应用场景有局限。因为很多云服务都是用Go、Python和JavaScript(NodeJS 框架) 语言开发的 。一些云原生的开源项目,比如KNative、Dapr也是用Go作为开发语言。所以EventMesh对支持多语言SDK有迫切需求,以继续丰富应用开发者的生态。

gRPC的开发工具带有多语言代码生成工具,包括Java、Go、NodeJS、PHP、Python、C#和C++等。EventMesh实现gRPC协议后可以借助该工具,快速提供多语言的SDK。后续对于通信API的改动只需要同步修改Protobuf模型定义,重新生成代码即可。迭代快速,维护简单。


整合TCP和HTTP协议


gRPC支持4种Client和Server通信RPC机制:Unary RPC、Server Streaming RPC、Client Streaming RPC和 Bidirectional Streaming RPC。EventMesh v1.4.0版本整合了v1.3.0版本的TCP 和 HTTP的SDK API,利用Unary RPC和 Bidirectional Streaming RPC,提供了Event Publish、Broadcast、Request-Reply、Webhook Subscription和Event Stream Subscription五种SDK API。

Protocol

Supported Use Case

Supported Version

gRPC

Send Async Message

Send Sync Message

Request and Reply

Send Broadcast Message

Send Batch Messages

Webhook Subscribe

Event Stream Subscribe

Unsubscribe

Heartbeat

v1.4.0+

HTTP

Send Async Message

Send Batch Messages

Webhook Subscribe

Unsubscribe

Heartbeat

v1.0.0+

TCP

Send Sync Message

Send Async Message

Send Batch Messages

Request and Reply

Send Broadcast Message

Event Stream Subscribe

Unsubscribe

Heartbeat

v1.0.0+

通过整合TCP和HTTP协议,EventMesh Runtime和SDK架构更加轻量化,减少了代码维护。同时用户使用SDK就不需要考虑使用场景要选哪一种协议。用户不需要学习和感知SDK层面的通讯协议,gRPC就能满足他们事件生产和消费的所有场景。


开箱即用的gRPC样例


为了让EventMesh开发者更好体验gRPC新特性,社区提供了完善的使用文档和多个Event Publisher、Event Subscriber代码样例。以下是相关文档:

  • https://github.com/apache/incubator-eventmesh/blob/master/docs/en/instructions/eventmesh-runtime-quickstart.md

  • https://github.com/apache/incubator-eventmesh/blob/master/docs/en/instructions/eventmesh-sdk-java-quickstart.md

第一个文档介绍如何部署和启动EventMesh服务器。文档里第一部分介绍如何远程部署EventMesh在虚拟机里,适合测试和生产环境的部署;第二部分介绍如何在本地开发环境里部署EventMesh,适合常用的本地开发和调试场景。

以下命令行是展示如何在Linux环境里部署和启动EventMesh Runtime:

> tar -zxvf Eventmesh_1.3.0-release.tar.gz

>
 cd bin

>
 sh start.sh

> tail -f ./logs/eventmesh.out

第二个文档介绍如何使用EventMesh SDK开发应用生产和消费事件,包含了TCP、HTTP和gRPC三部分。EventMesh工程项目里带有客户端的代码样例 (eventmesh-example),包括了gRPC Event Publisher、Event Subscriber的代码。比如,我们可以把EventMesh工程项目导入Java IDE里(比如Intellij IDEA)。按照以下步骤启动gRPC Event Publisher and Subscriber。

1.修改eventmesh-examples/src/main/resources/application.properties指向已经部署的EventMesh Runtime。

 

2.启动Event Publisher,运行:

Eventmesh-example/src/main/java/

org.apache.eventmesh.grpc.pub.eventmeshmessage.AsyncPublishInstance 

3.启动Event Subscriber,运行:

Eventmesh-example/src/main/java/

org.apache.eventmesh.grpc.sub.app.SpringBootDemoApplication

作为组合式应用新利器,gRPC的引入无疑是集成标准化的一大助力。当然,除了通讯标准外,还有schema、governance等集成标准需要统一,事件网格会在这些领域继续做出自己的探索。

作者介绍:

Alex Luo,华为云中间件技术专家,Apache EventMesh Committer。过去十年致力于研究下一代云原生中间件架构和打造SaaS应用开发者生态;目前主要研究方向为事件驱动架构与相关技术,包括EventMesh、RocketMQ、Serverless Workflow 等。

钟鸣拓,华为云中间件技术专家,主要研究方向为中间件开发,致力于研究和打造下一代云原生中间件技术,热衷于分布式架构设计等领域技术。

吕广林,华为云EventGrid云服务架构师,主要研究方向为云中间件架设开发,致力于为用户提供云原生中间件的极简使用体验。

END



《新程序员001-004》全面上市,对话世界级大师,报道中国IT行业创新创造


— 推荐阅读 —
突发!GitHub封禁受美国制裁的俄罗斯开发者账号
“在 GitHub 用十年攒的 54k+ Star,一个误操全没了”
主动出击!马斯克欲用 430 亿美元拿下 Twitter

点这里↓↓↓记得关注标星哦~ 

一键三连 「分享」「点赞」「在看」

成就一亿技术人

关注公众号:拾黑(shiheibook)了解更多

赞助链接:

关注数据与安全,洞悉企业级服务市场:https://www.ijiandao.com/
四季很好,只要有你,文娱排行榜:https://www.yaopaiming.com/
让资讯触达的更精准有趣:https://www.0xu.cn/

公众号 关注网络尖刀微信公众号
随时掌握互联网精彩
赞助链接