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

在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<string, string> 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。

通过整合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等集成标准需要统一,事件网格会在这些领域继续做出自己的探索。

点击关注,第一时间了解华为云新鲜技术~

组合式应用新利器?SaaS新时代事件网格如何解决集成标准化问题的更多相关文章

  1. SparkR:数据科学家的新利器

    摘要:R是数据科学家中最流行的编程语言和环境之一,在Spark中加入对R的支持是社区中较受关注的话题.作为增强Spark对数据科学家群体吸引力的最新举措,最近发布的Spark 1.4版本在现有的Sca ...

  2. 微信变声器(WeChat Voice)会是营销新利器吗

    微信变声器(WeChat Voice)2.0 Android版开始内测了,时间从2015年5月20日 - 2015年6月20日,使用微信变声器改变你的声音,并分享给好友! 无论你是想装可爱还是恶搞,微 ...

  3. 关于JQ中,新生成的节点on绑定事件失效的解决

    老旧的JQ库在做新生成DIV的click事件绑定,需要先绑定其现有的父元素,在追踪到需要事件绑定的子节点上 如以下这段代码$(".t_in").on("click&quo ...

  4. Sketch插件新利器——使用Mockplus DS制作设计规范

    Sketch,作为一款专为图标和界面设计而打造的优质矢量绘图工具,也是设计师们制作和完善公司企业内部设计规范系统不可或缺的设计工具. 然而,逐个导出和上传Sketch编辑优化的设计系统资源费时而费力. ...

  5. 新IT运维时代 | Docker运维之最佳实践-下篇

    上篇针对操作系统.主机配置.容器镜像.容器运行时四大方面分享一些Docker的运维经验,本篇将着重在Docker Daemon参数和权限两个方面进一步分享.(阅读上篇请点击右侧:新IT运维时代 | D ...

  6. zepto | 用事件委托去解决无法给新增添的DOM添加事件的问题

    前段时间在做一个任务的时候,碰见了一个问题:zepto无法用on事件去监听新增加的dom事件.这个问题用live可解决, 但是live在ios下失效,为了解决这个问题,我采用了暴力的方法去解决,每次添 ...

  7. 郑晔谈 Java 开发:新工具、新框架、新思维【转载】【整理】

    原文地址 导语:"我很惊讶地发现,现在许多程序员讨论的内容几乎和我十多年前刚开始做 Java 时几乎完全一样.要知道,我们生存的这个行业号称是变化飞快的.其实,这十几年时间,在开发领域已经有 ...

  8. 使用 pjax 载入的新页面,新页面上 类方法 无法被触发?

    在父页面上有定义类似 $(".class").click(function(){ ... }) 经过pjax 载入后的新页面 点击后没有触发事件 在segmentfault 上提问 ...

  9. CentOS添加新硬盘到新的分区(xfs/ext4) 或者添加新分区

    CentOs添加新硬盘到新的分区(xfs/ext4)  添加新分区 转载请注明:http://www.cnblogs.com/juandx/p/5618162.html 这篇文章介绍怎么添加一块新的硬 ...

随机推荐

  1. case 函数语法与使用

    case 函数是聚合函数的一种,为统计函数. case表达式: CASE selector WHEN value1 THEN action1; WHEN value2 THEN action2; WH ...

  2. Spring核心思想:IOC(控制反转)、DI(依赖注入)和AOP(面向切面编程)

    Spring有三大核心思想,分别是控制反转(IOC,Inversion Of Controller),依赖注入(DI,Dependency Injection)和面向切面编程(AOP,Aspect O ...

  3. url斜杠问题——重定向

    path('hello',hello), path('hello/',hello), 有什么区别? 没有斜杠:只能访问hello 有斜杠:可以访问hello和hello/ 分析有斜杠的: hello- ...

  4. 数据库篇:mysql锁详解

    前言 sql事务的执行,如果需要锁定数据进行更新操作,则必定离不开锁 共享锁和排他锁 表锁 行锁 Record Lock 间隙锁 Gap Lock 行锁+间隙锁 Next-Key Lock 加锁场景( ...

  5. [源码解析] TensorFlow 分布式环境(6) --- Master 动态逻辑

    [源码解析] TensorFlow 分布式环境(6) --- Master 动态逻辑 目录 [源码解析] TensorFlow 分布式环境(6) --- Master 动态逻辑 1. GrpcSess ...

  6. Hadoop的安装配置(一)

    一.Hadoop的安装①Hadoop运行的前提是本机已经安装了JDK,配置JAVA_HOME变量②在Hadoop中启动多种不同类型的进程        例如NN,DN,RM,NM,这些进程需要进行通信 ...

  7. (转载)JSON对象使用变量作为键名

    转载链接:https://blog.csdn.net/lihefei_coder/article/details/82499520 //第一种方式 var key = 'name'; var json ...

  8. 学习zabbix(七)

    zabbix自定义监控项 1.创建主机组,可以根据redis.mysql.web等创建对于的主机组 2.创建主机 3.创建Screens 4.自定义监控项 zabbix_agentd.conf配置文件 ...

  9. 速看,ElasticSearch如何处理空值

    大家好,我是咔咔 不期速成,日拱一卒 在MySQL中,十分不建议大家给表的默认值设置为Null,这个后期咔咔也会单独出一期文章来说明这个事情. 但你进入一家新公司之前的业务中存在大量的字段默认值为Nu ...

  10. C语言之关键字(知识点2)

    关键字又叫保留字,这些关键字不可以再次定义 解析