Dapr微服务应用开发系列5:发布订阅构建块

题记:这篇介绍发布订阅构建块,这是对事件驱动架构设计的一种实现落地。

注:对于“Building Blocks”这个词组的翻译,我之前使用了“构件块”,现在和官方文档(Dapr中文社区的贡献)保持一致,采用“构建块”。

原理

发布订阅的概念来自于事件驱动架构(EDA)的设计思想,这是一种让程序(应用、服务)之间解耦的主要方式,通过发布订阅的思想也可以实现服务之间的异步调用。而大部分分布式应用都会依赖这样的发布订阅解耦模式。

整个发布订阅的思想其实是比较简单的:

如上图所示,把需要解耦的程序分别设定为事件发布者或者事件订阅者(理论上,对于某个事件,一个程序仅能作为一种角色;对于不同事件,一个程序可以既作为发布者又可以作为订阅者)。同时利用消息代理(Message Broker)中间件把两者对接起来,消息代理即作为事件消息的传输通道。

在Dapr中对这种发布订阅模式进行了高度抽象的实现,并提供了自由替换消息代理中间件的特性,如下图所示:

Dapr的发布订阅构建块也可以被看作一种事件总线(Event Bus)的实现,只是你不需要使用特殊的协议,在发布端和订阅端仅使用HTTP/gRPC即可。

在事件总线中,把发布订阅两者关联在一起的是事件类型,那么在Dapr中也引入了一个类似的概念——主题(Topic)。如果对消息队列中间件熟悉的人对于这个概念不会陌生。由此发布端和订阅端的处理过程和针对Dapr的接口也就是围绕主题来展开的。

能力

消息发送

既然Dapr的PubSub是一种事件总线,那么要发送消息,必然需要对代表主题(事件类型)的消息进行封装。Dapr并没有去创造一种独有的格式,而是采用了目前业界比较流行的开放协议——云事件(CloudEvents)规范。这种格式把事件消息封装为如下JSON数据:

{"specversion" : "1.0","type" : "xml.message","source" : "https://example.com/message","subject" : "Test XML Message","id" : "id-1234-5678-9101","time" : "2020-09-23T06:23:21Z","datacontenttype" : "text/xml","data" : "<note><to>User1</to><from>user2</from><message>hi</message></note>"
}

当然对消息的封装不需要应用程序本身去关心,你只需要给Dapr传递data的字符串即可,而这个字符串本身是以什么格式(不管xml还是json)去承载内容都是由应用程序确定。具体如何发送消息,下面规范部分会介绍。

消息传递

Dapr会自动根据主题把消息发送给所有订阅者,传递过程保证“至少一次”送达。送达的判断标准是基于订阅者的响应是否成功(即HTTP状态码为20X)。

当然,订阅者也可以在响应体中设置 status 属性来给出更为精细的处理指令,比如 RETRY  告知Dapr之前处理失败了,现在是重试成功了;或者 DROP 告知Dapr应用程序对这个消息处理出现问题,已经记录了告警日志,但是不打算继续处理它了。

消息传递还有一个重要的特性需要理解,就是消息的生存期(Time-to-Live,TTL)。TTL规定了消息在Dapr(实际上是在消息代理中间件)里面的存活时间,如果TTL过期,那么消息就不会再被传递(即变成死信)。所有目前支持的发布订阅组件都支持TTL的特性,Dapr会帮助你处理这方面的逻辑。

消息消费

为了消费消息,需要对主题进行注册,可以通过声明式和编程式来进行注册。声明式通过外部的yaml文件定义一个K8S的CRD,来描述服务需要订阅什么主题,接收事件的HTTP API路由地址。编程式通过暴露特定的HTTP API路由地址或者特定的gRPC方法来让Dapr运行时进行访问,从而注册需要订阅什么主题和接收事件的地址。

发布订阅构建块采用的是所谓竞争者消费模式,即同一个应用(AppId相同)的多个实例,只会有一个实例获得消息,这些同个应用的多个实例称之为一个消费组。如果你希望消息被多个应用得到,那么就需要使用多个消费组,也即多个AppId。

主题范围限制

从上面所知,在发送消息和消费消息的时候,都需要针对某个主题。为了对消息的传递进行更加精细的控制,在发布订阅构建块中可以对主题范围进行限制,即某些主题只能由某些应用来发布,某些主题只能由某些应用来订阅。

要进行范围限制,需要对发布订阅组件的配置yaml进行配置,设置 spec.metadata 下面的 publishingScopessubscriptionScopesallowedTopics 配置。(详细说明见未来的关于组件的文章)。

规范

Dapr给PubSub这一构建块提供了两方面的规范:消息生产端和消息消费端。

消息生产端

通过POST如下地址,来发送消息到特定主题:

POST http://localhost:<daprPort>/v1.0/publish/<pubsubname>/<topic>[?<metadata>]

其中pubsubname代表了PubSub组件的名称;topic代表了目标主题名称。

Content-Type 请求头中设置请求体的格式,比如 application/json

请求体根据请求头里面的设置格式,传入JSON或者XML,Dapr会自动把请求体封装为CloudEvent格式。

如果是直接调用gRPC的接口的话,是调用 PublishEvent 接口并传递 PublishEventRequest 实体。

消息消费端

如果你的消费端是通过声明式来向Dapr注册需要订阅什么主题的消息,那么在如下格式的yaml文件中进行定义:

apiVersion: dapr.io/v1alpha1
kind: Subscription
metadata:name: myevent-subscription
spec:topic: deathStarStatusroute: /dsstatuspubsubname: pubsub
scopes:
- app1
- app2

其中 spec.topic 代表了要订阅的主题名称,spec.route 代表了接收订阅消息的HTTP路由地址,spec.route 代表了针对的PubSub组件是那个。尤为关键是 scopes 里面设置了这样的订阅声明是针对那个(或那几个)应用起作用(填入appid)。

如果你的消费端是通过编程式来向Dapr注册需要订阅什么主题的消息,那么暴露一个如下特殊HTTP路由地址的接口:

GET http://localhost:<appPort>/dapr/subscribe

并返回如下格式的响应体,让Dapr知道你的应用需要订阅什么主题,接收消息的接口路由地址是什么:

[{"pubsubname": "pubsub","topic": "newOrder","route": "/orders"}
]

当然你的应用需要暴露注册的接收路由接口,并支持POST谓词,接口收到请求后返回2xx状态码告诉Dapr消息处理成功了,或者404告诉Dapr出现错误且消息已经丢弃,或者其他状态码让Dapr进行重试。

两种订阅注册方式各有优缺,声明式方便一个主题注册多个应用,编程式方便一个应用注册多个主题。

注意:如果是使用gRPC来注册和暴露消费接口,那么规范有所不同,做法见下面。

DOTNET SDK

Dapr的.NET SDK同样针对消息生产端和消费端提供相关的函数库。

在DaprClient这个客户端类中提供了 PublishEventAsync 这个方法来用于发送事件消息到特定PubSub的特定主题上 (底层是请求了gRPC的接口)。比如:

using var client = new DaprClientBuilder().Build();var eventData = new { Id = "17", Amount = 10m, };
await client.PublishEventAsync(pubsubName, "deposit", eventData, cancellationToken);

在消费端,目前针对ASP.NET Core提供了一个特殊的属性标记 TopicAttribute 来简化编程式订阅注册的过程。比如:

[Topic("pubsub", "deposit")]
[HttpPost("deposit")]
public async Task<ActionResult<Account>> Deposit(Transaction transaction, [FromServices] DaprClient daprClient)

如果你是使用gRPC来实现消费端,那么目前并没有一个简化方式来注册(未来我会补上这个坑),只能遵循如下规范:

首先用ListTopicSubscriptions注册:

public override Task<ListTopicSubscriptionsResponse> ListTopicSubscriptions(Empty request, ServerCallContext context)
{var result = new ListTopicSubscriptionsResponse();result.Subscriptions.Add(new TopicSubscription{PubsubName = "pubsub",Topic = "deposit"});result.Subscriptions.Add(new TopicSubscription{PubsubName = "pubsub",Topic = "withdraw"});return Task.FromResult(result);
}

接着用OnTopicEvent接收:

public override async Task<TopicEventResponse> OnTopicEvent(TopicEventRequest request, ServerCallContext context)
{if (request.PubsubName == "pubsub"){var input = JsonSerializer.Deserialize<Models.Transaction>(request.Data.ToStringUtf8(), this.jsonOptions);var transaction = new GrpcServiceSample.Generated.Transaction() { Id = input.Id, Amount = (int)input.Amount, };if (request.Topic == "deposit"){await Deposit(transaction, context);}else{await Withdraw(transaction, context);}}return await Task.FromResult(default(TopicEventResponse));
}

具体见SDK的examples:https://github.com/heavenwing/dapr-dotnet-sdk/blob/master/examples/AspNetCore/GrpcServiceSample/Services/BankingService.cs

用法与例子

使用SDK来进行事件消息的发布和订阅,可以直接参考SDK的examples中的消费端例子 ControllerSample 和生产端例子 PublishSubscribe。

如果是非SDK的用法,可以参考我的quickstarts,消费端 PubSubConsumer和生产端 PubSubProducer。

我的quickstarts的消费端同时使用声明式和编程式两种注册方式。大致代码如下:

[Route("dapr/subscribe")]
[ApiController]
public class DaprSubscribeController : ControllerBase
{public ActionResult<DaprSubscribeOutput[]> Get(){return Ok(new DaprSubscribeOutput[]{new DaprSubscribeOutput{PubSubName="pubsub",Topic="quickstarts/wakeup",Route="/api/wakeup"}});}
}public async Task<IActionResult> PostAsync(TinyCloudEvent<MessageInput> model)
{_logger.LogInformation(model.Data.Name);return Ok();
}using var httpClient = new HttpClient();
httpClient.BaseAddress = new Uri(pubsubUrl);Console.WriteLine($"To {topicName1} ...");
var request1 = new HttpRequestMessage(HttpMethod.Post, topicName1);
request1.Content = new StringContent(JsonSerializer.Serialize(new { name = "Jack" }), Encoding.UTF8, "application/json");
await httpClient.SendAsync(request1);
apiVersion: dapr.io/v1alpha1
kind: Subscription
metadata:name: quickstarts-subscription
spec:topic: quickstarts/sleeproute: /api/sleeppubsubname: pubsub
scopes:
- quickstarts-pbc

相关文章:

  • Dapr能否引领云原生中间件的未来?

  • 云原生 | 阿里巴巴的Dapr实践与探索

  • Dapr 可视化指南

  • Dapr 知多少 | 分布式应用运行时

  • Dapr 正式发布 1.0

  • Dapr 交通流量控制示例

  • Dapr是如何简化微服务的开发和部署

  • 微软开源微服务运行时Dapr,赋能云原生应用开发

  • Dapr微服务应用开发系列0:概述

  • Dapr微服务应用开发系列1:环境配置

  • Dapr微服务应用开发系列2:Hello World与SDK初接触

  • Dapr微服务应用开发系列3:服务调用构件块

  • Dapr微服务应用开发系列4:状态管理构件块

  • Dapr微服务应用开发系列5:发布订阅构建块

  • Windows环境下Dapr入门

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/303466.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【资源】机器学习资料包来袭

近几年&#xff0c;机器学习一直很火&#xff0c;小编也有意识地收集了机器学习相关的资源&#xff0c;经过长时间的积累和沉淀&#xff0c;已经拥有将近17G的吴恩达老师、李宏毅老师和王保明老师机器学习资料和视频。现在&#xff0c;小编准备将这些资料免费分享给大家&#x…

java 字符串 去除_java 字符串中去除特定的字符

java String字符串 去除特定的字符 程序如下package com.xing.test;import java.util.regex.Matcher;import java.util.regex.Pattern;/**** author Yinxing**/public class NotString {public static void main(String[] args) {// TODO Auto-generated method stubString st…

深度学习了40万个表情,一大波AI 表情包来了

自从有了表情包&#xff0c;跟人聊天时的第一反应&#xff0c;就是去找找看有什么适合的表情。有一类表情包&#xff0c;形式是文字图&#xff0c;尤其能够精妙地抒发和传递感情。在这一点上&#xff0c;可能全世界的网友都一样。好用的表情永远不嫌多&#xff0c;而且似乎总是…

网关Ocelot功能演示安排的明明白白~~~

前言网关(Gateway)在微服务架构中至关重要&#xff0c;可以将其理解为是外部客户端(前端、MVC后台等调用方)与后台服务的连接点&#xff0c;通过这层可以做统一的处理&#xff0c;比如路由、身份认证和授权、服务治理等&#xff1b;网关的好处&#xff1a;统一入口&#xff0c;…

通过Dapr实现一个简单的基于.net的微服务电商系统

本来想在Dpar 1.0GA时发布这篇文章&#xff0c;由于其他事情耽搁了放到现在。时下微服务和云原生技术如何如荼&#xff0c;微软也不甘示弱的和阿里一起适时推出了Dapr&#xff08;https://dapr.io/&#xff09;&#xff0c;园子里关于dapr的文章不太多&#xff0c;所以今天就借…

基于 Python 自建分布式高并发 RPC 服务

RPC&#xff08;Remote Procedure Call&#xff09;服务&#xff0c;也即远程过程调用&#xff0c;在互联网企业技术架构中占据了举足轻重的地位&#xff0c;尤其在当下微服务化逐步成为大中型分布式系统架构的主流背景下&#xff0c;RPC 更扮演了重要角色。Google 开源了 gRPC…

程序员江湖鄙视链大全,看看你处于链条的哪一级?

有人的地方就有江湖。程序员&#xff0c;是一个知识、智商、都异于常人的 群体&#xff0c;有人总结了程序员江湖等级鄙视链的方法和流程。老婆漂亮的程序员鄙视老婆不漂亮的程序员鄙视有女友的程序员鄙视单身狗程序员而在单身狗之间&#xff0c;才有了语言&#xff0c;编辑器和…

java什么是静态_什么是java静态

什么是java静态java静态包括静态变量、静态方法、静态初始化块&#xff0c;以下是静态的详解。(推荐教程&#xff1a;java教程)1. 什么是静态变量大家都知道&#xff0c;我们可以基于一个类创建多个该类的对象&#xff0c;每个对象都拥有自己的成员&#xff0c;互相独立。然而在…

如何在 .NET 程序万种死法中有效的生成 Dump (上)

一&#xff1a;背景相信很多人都知道通过 任务管理器 抓取dump&#xff0c;虽然简单粗暴&#xff0c;但无法满足程序的无数种死法&#xff0c;比如&#xff1a;内存膨胀&#xff0c;程序爆炸CPU爆高&#xff0c;程序累死应用无响应&#xff0c;用户气死意外退出&#xff0c;和人…

74款app源码,值得你拥有的干货

最近&#xff0c;小编一直在整理一些app的源码&#xff0c;如&#xff1a;BiliClient&#xff08;仿bilibili客户端&#xff09;、WeChat高仿微信、知乎专栏App、Compass&#xff08;MIUI指南针的社区开源版&#xff09;等。现在小编打算将这些资料免费分享给大家&#xff01;&…

监控系统简介:使用 Prometheus 与 Grafana

注&#xff1a;本文虽以 Docker 进行演示&#xff0c;但 Docker 并不是必须的&#xff0c;相关软件也可以直接安装到计算机上背景如果我们是Web应用的开发者&#xff0c;会对响应时间、接口的稳定性等比较敏感&#xff0c;在站点尚未部署到生产环境时&#xff0c;我们有充足的时…

7500 cpuz跑分 i5_核心硬盘 i5 7500性能测试_DIY攒机酷品测试-中关村在线

下面我们进入CPU测试环节。为保测试性准确可靠&#xff0c;以下测试均采用Windows 10 1周年版 64位正版系统&#xff0c;且不对操作系统进行任何优化&#xff0c;用以获取最大的系统稳定性与兼容性。Intel 酷睿i5 7500i5 7500 CPU-ZFritz Chess BenchmarkFritz Chess Benchmark…

Android Ap 开发 设计模式第七篇:生成器模式

Builder Pattern 模式解读 生活在深圳这所高速发展的城市&#xff0c;高楼大厦林立。所谓万丈高楼平地起&#xff0c;在我们感慨楼层的高耸之外&#xff0c;更要配服楼层的建造者和设计者。大楼首先得打稳地基、搭建骨架&#xff0c;再由下往上一层层盖上去。而这样的架构从程序…

MySQL 创始人:写代码比打游戏还爽,程序员应该多泡开源社区

编者按&#xff1a;根据StackOverflow的最新调查&#xff0c;MySQL仍然是全世界最流行的数据库&#xff0c;受访的开发者中有44.3%的人在使用&#xff0c;超过了第二位的SQL Server 10多个百分点。可是你知道MySQL是怎么诞生的吗&#xff1f;openocean 的一篇有关MySQL开发者Mi…

tomcat如何修改java版本_Java程序员必备——Tomcat配置技巧Top10

一、配置系统管理(Admin Web Application)大多数商业化的J2EE服务器都提供一个功能强大的管理界面&#xff0c;且大都采用易于理解的Web应用界面。Tomcat按照自己的方式&#xff0c;同样提供一个成熟的管理工具&#xff0c;并且丝毫不逊于那些商业化的竞争对手。Tomcat的Admin …

祝福!微软 46 周年生日快乐!

46 年前的今天&#xff0c;即 1975 年 4 月 4 日&#xff0c;比尔盖茨&#xff08;Bill Gates&#xff09;和保罗艾伦&#xff08;Paul Allen&#xff09;共同创立了微软公司。他们是小时候认识的朋友及高中同学&#xff0c;并对电脑编程充满激情。1975 年 1 月&#xff0c;MIT…

荐书 | 没有数学思维的程序员不是好的问题解决者

今天小木给大家推荐以下五本关于数学历史或数学思维的名家著作。读者推荐&#xff1a;01《这才是最好的数学书》[日] 笹部贞市郎55.00赠&#xff1a;《谁谋杀了希尔伯特教授》数学漫画随机一本《神笔涂绘》内容简介&#xff1a;有人曾请教笹部贞士郎&#xff0c;是如何引领近代…

java反射sethaha_Java反射深度测试

通过反射API构造对象&#xff0c;并使用反射调用方式访问对象的public/private方法和字段。package lavasoft.test;/*** 测试的业务类** author leizhimin 2010-5-6 20:16:10*/public class MyService {private String msg;public MyService() {System.out.println("log: …

监控系统简介(二):使用 App Metrics 在 ASP.NET Web API 中记录指标

回顾在《监控系统简介&#xff1a;使用 Prometheus 与 Grafana》一文中&#xff0c;我们了解了什么是监控系统&#xff0c;Prometheus 这一监控工具及它提供的数据类型、PromQL 以及 Grafana 可视化工具的基本用法。今天这一篇我们将在 ASP.NET Web API 项目中进行实战&#xf…

剧透人生!你什么时候结婚换工作甚至狗带,Facebook都知道

来源&#xff1a;大数据文摘即将换工作&#xff1f;要结婚了&#xff1f;有亲人朋友要去世了&#xff1f;你关心的这些人生重大节点&#xff0c;有人希望比你提前知道它们何时发生&#xff0c;并基于此对你精准投放广告。惊悚&#xff1f;这是Facebook在2010年以来提交的一系列…