WebAPi的可视化输出模式(RabbitMQ、消息补偿相关)所有webapi似乎都缺失的一个功能

简介:

最近的工作我在做一个有关于消息发送和接受封装工作。大概流程是这样的,消息中间件是采用rabbitmq,为了保证消息的绝对无丢失,我们需要在发送和接受前对消息进行DB落地。在发送前我会先进行DB的插入,单表插入,所以在性能上也是能接受的,单表插入做了压测基本上是一到两毫秒的时间,加上消息的发送(有ACK)再加上集群是两个节点的高可用(一个磁盘持久化节点),单台TPS基本上是在2000-3000左右。这对于我们的业务场景来说是够用了。一旦当消息丢失或者由于网络问题、集群问题业务不会中断,消息就算发不出去也没关系,我们会进行消息的补偿或者同步api调用补偿。这是架构设计的必须要考虑的A计划、B计划、C计划,这是敬畏或者危机意识。

你可能又要说两个节点或者三个节点的集群怎么会有问题,那你就错了,大错特错。只能说明你并不了解什么叫分布式系统及分布式系统的特性。你也许不会知道网络抖动、网络闪断导致socket断开如何进行心跳重试已保持有效的Rabbitmq Connection。当你的网络极不稳定,你的linux keepalived VIP 来回漂移,导致你的ARP根本无法成效,可能就连广播都传不出去,而客户端则在一直使用一个无用的IP地址。当你的集群节点之间无法连接成一个整体的时候各种奇葩的问题又来了。这些都是可能导致你的集群出问题的原因,所以不要大意。

(后面我会整理一篇专门讲解“rabbitmq高可用、故障转移集群架构“文章,所以这里我们就不继续介绍了)

这是一个铺垫,本文的重点是介绍下我在尝试使用可视化webapi的输出模式,这比原本json的输出模式看起来会方便许多。如果你的api提供两种输出模式,人性化绝对很好。现在很多后端api都是没有界面的都是只提供了一个json输出。然而,我们其实很需要一个可读性很强的输出模式。

我在开发消息补偿程序的时候,我借鉴了这一思想进行了尝试。先来看下整体架构蓝图:

1

本篇文章要介绍的是有关于这个补偿程序的api的可视化输出内容。不涉及到消息相关太多的东西,只是为了让这个可视化输出看起来容易理解点。这个补偿程序需要对发送的消息和接受的消息进行查询和比较然后输出,用来确定消息的发送是失败了还是成功的。简单逻辑就是比较某个时间段内的消息发送表和接受表,然后进行消息id的匹配。

我在想这个数据反馈到api上是个什么样子的,按照常规设计就是两个字段:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/// <summary>
     /// 接受的消息对象。
     /// </summary>
     public  class  ReceiveMessage
     {
         /// <summary>
         /// 发送消息ID。
         /// </summary>
         public  string  SendMessageId {  get set ; }
 
         /// <summary>
         /// 接受消息ID。
         /// </summary>
         public  string  ReceiveMessageId {  get set ; }
     }

这表示一个消息从发送到接受的一个过程。如果失败了,可能是只有SendMessageId而没有ReceiveMessageId。然后我才会针对没有ReceiveMessageId的消息进行自动补偿。在开发的时候只有几十条消息,输出到postman中的看起来也还行,但是不直观。

2

GetReceiveMessage是获取接受消息列表,就是查看当前消息发送到接受是个什么状态。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/// <summary>
     /// 处理成功消息对象。
     /// </summary>
     public  class  SuccessMessage
     {
         /// <summary>
         /// 发送消息ID
         /// </summary>
         public  string  SendMessageId {  get set ; }
 
         /// <summary>
         /// 接受消息ID
         /// </summary>
         public  string  ReceiveMessageId {  get set ; }
 
         /// <summary>
         /// 处理成功消息ID
         /// </summary>
         public  string  SuccessMessageId {  get set ; }
     }


SuccessMessage表示处理成功消息情况。此时有可能是有SendMessageId,ReceiveMessageId消息,但是SuccessMessageId可能是没有的。就会针对处理成功的消息进行发送。

3

突然受到ElasticSearch的_cat endpoint 启发。似乎这里我可以尝试下,webapi带有两种输出模式,一种是针对程序使用的json输出模式,另外一种是针对人可以阅读的模式text/plain模式,而第二种模式可以简单的理解为是行列转换缺省模式。

4

是不是看起来会很舒服。这在进行消息的时间段查看非常有帮助,如果还按照原本的json输出模式可能看起来会比较吃力。

来看下基本的api的设计,为了保证你的所有api支持?v可视化模式,需要一定的抽象:

5

需要定义一种ViewModel,所有的数据都输出这种对象,当然我这里也只是简单地封装。如果可以,其实可以专门提取出一个库出来,包括对文本的输出自动化。

我们看下BaseApiController:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
public  class  BaseApiController : ApiController
     {
         public  class  ViewModel
         {
             public  string  Content {  get set ; }
             public  object  JsonObject {  get set ; }
             public  bool  Success =  true ;
         }
 
         protected  bool  IsView;
         private  const  string  ViewQuerystring =  "?v" ;
         public  ViewModel ResultModel;
         private  const  string  CheckToken =  "CheckToken" ;
         private  const  string  Token =  "49BBD022-CDBF-4F94-80E4-5BCACB1192EC" ;
         private  bool  _checkStatus;
 
         public  override  Task<HttpResponseMessage> ExecuteAsync(HttpControllerContext controllerContext, CancellationToken cancellationToken)
         {
             //验证token
             if  (controllerContext.Request.Headers !=  null  && controllerContext.Request.Headers.Contains(CheckToken))
             {
                 var  requestToken = controllerContext.Request.Headers.GetValues(CheckToken).FirstOrDefault();
                 if  (requestToken !=  null  && requestToken.Equals(Token))
                 {
                     this ._checkStatus =  true ;
                 }
             }
 
             if  (!_checkStatus)
             {
                 var  checkResult =  new  Task<HttpResponseMessage>(() =>  new  HttpResponseMessage
                 {
                     Content =  new  StringContent( "非法访问,缺少token" , Encoding.UTF8,  "text/plain" )
                 }, cancellationToken);
 
                 checkResult.Start();
                 return  checkResult;
             }
 
             if  (controllerContext.Request.RequestUri.Query.Equals(ViewQuerystring))
                 this .IsView =  true ;
 
             base .ExecuteAsync(controllerContext, cancellationToken);
 
             //text模式
             if  ( this .IsView)
             {
                 var  textResult =  new  Task<HttpResponseMessage>(() =>  new  HttpResponseMessage
                 {
                     Content =  new  StringContent( this .ResultModel.Content, Encoding.UTF8,  "text/plain" )
                 }, cancellationToken);
 
                 textResult.Start();
                 return  textResult;
             }
 
             //json模式
             var  resultData =  new  Result< object >
             {
                 Data =  this .ResultModel.JsonObject,
                 Type =  this .ResultModel.Success ? ResultType.Successfully : ResultType.Failure
             };
 
             var  jsonResult =  new  Task<HttpResponseMessage>(() =>  new  HttpResponseMessage
             {
                 Content =  new  ObjectContent( typeof (Result), resultData,  new  JsonMediaTypeFormatter(),  "application/json" )
             }, cancellationToken);
 
             jsonResult.Start();
 
             return  jsonResult;
         }
     }

代码很简单,这里给我们一个启发,webapi是不是真的缺少了一个可视化模式。




 本文转自 王清培 51CTO博客,原文链接:http://blog.51cto.com/wangqingpei557/1877098,如需转载请自行联系原作者


相关实践学习
消息队列RocketMQ版:基础消息收发功能体验
本实验场景介绍消息队列RocketMQ版的基础消息收发功能,涵盖实例创建、Topic、Group资源创建以及消息收发体验等基础功能模块。
消息队列 MNS 入门课程
1、消息队列MNS简介 本节课介绍消息队列的MNS的基础概念 2、消息队列MNS特性 本节课介绍消息队列的MNS的主要特性 3、MNS的最佳实践及场景应用 本节课介绍消息队列的MNS的最佳实践及场景应用案例 4、手把手系列:消息队列MNS实操讲 本节课介绍消息队列的MNS的实际操作演示 5、动手实验:基于MNS,0基础轻松构建 Web Client 本节课带您一起基于MNS,0基础轻松构建 Web Client
相关文章
|
2月前
|
消息中间件
RabbitMQ的 RPC 消息模式你会了吗?
【9月更文挑战第11天】RabbitMQ 的 RPC(远程过程调用)消息模式允许客户端向服务器发送请求并接收响应。其基本原理包括:1) 客户端发送请求,创建回调队列并设置关联标识符;2) 服务器接收请求并发送响应至回调队列;3) 客户端根据关联标识符接收并匹配响应。实现步骤涵盖客户端和服务器的连接、信道创建及请求处理。注意事项包括关联标识符唯一性、回调队列管理、错误处理及性能考虑。RPC 模式适用于构建可靠的分布式应用程序,但需根据需求调整优化。
|
3月前
|
消息中间件 开发者
【RabbitMQ深度解析】Topic交换器与模式匹配:掌握消息路由的艺术!
【8月更文挑战第24天】在消息队列(MQ)体系中,交换器作为核心组件之一负责消息路由。特别是`topic`类型的交换器,它通过模式匹配实现消息的精准分发,适用于发布-订阅模式。不同于直接交换器和扇形交换器,`topic`交换器支持更复杂的路由策略,通过带有通配符(如 * 和 #)的模式字符串来定义队列与交换器间的绑定关系。
55 2
|
3月前
|
消息中间件
RabbitMQ广播模式
RabbitMQ广播模式
53 1
|
3月前
|
消息中间件 应用服务中间件 网络安全
rabbitMQ镜像模式搭建
rabbitMQ镜像模式搭建
|
4月前
|
消息中间件 API 开发工具
消息队列 MQ使用问题之如何开启RabbitMQ的MQTT功能
消息队列(MQ)是一种用于异步通信和解耦的应用程序间消息传递的服务,广泛应用于分布式系统中。针对不同的MQ产品,如阿里云的RocketMQ、RabbitMQ等,它们在实现上述场景时可能会有不同的特性和优势,比如RocketMQ强调高吞吐量、低延迟和高可用性,适合大规模分布式系统;而RabbitMQ则以其灵活的路由规则和丰富的协议支持受到青睐。下面是一些常见的消息队列MQ产品的使用场景合集,这些场景涵盖了多种行业和业务需求。
|
4月前
|
消息中间件 传感器 负载均衡
消息队列 MQ使用问题之如何配置一主一从的同步复制模式
消息队列(MQ)是一种用于异步通信和解耦的应用程序间消息传递的服务,广泛应用于分布式系统中。针对不同的MQ产品,如阿里云的RocketMQ、RabbitMQ等,它们在实现上述场景时可能会有不同的特性和优势,比如RocketMQ强调高吞吐量、低延迟和高可用性,适合大规模分布式系统;而RabbitMQ则以其灵活的路由规则和丰富的协议支持受到青睐。下面是一些常见的消息队列MQ产品的使用场景合集,这些场景涵盖了多种行业和业务需求。
消息队列 MQ使用问题之如何配置一主一从的同步复制模式
|
3月前
|
消息中间件 监控 数据安全/隐私保护
就软件研发问题之在RocketMQ的服务端开启认证功能的问题如何解决
就软件研发问题之在RocketMQ的服务端开启认证功能的问题如何解决
|
4月前
|
消息中间件 存储 Kafka
MetaQ/RocketMQ 原理问题之RocketMQ DLedger融合模式的问题如何解决
MetaQ/RocketMQ 原理问题之RocketMQ DLedger融合模式的问题如何解决
|
3月前
|
消息中间件 Java Maven
RabbitMQ通配符模式
RabbitMQ通配符模式
57 0
|
4月前
|
消息中间件 Java Apache
消息队列 MQ使用问题之如何在内外网环境下使用单组节点单副本模式
消息队列(MQ)是一种用于异步通信和解耦的应用程序间消息传递的服务,广泛应用于分布式系统中。针对不同的MQ产品,如阿里云的RocketMQ、RabbitMQ等,它们在实现上述场景时可能会有不同的特性和优势,比如RocketMQ强调高吞吐量、低延迟和高可用性,适合大规模分布式系统;而RabbitMQ则以其灵活的路由规则和丰富的协议支持受到青睐。下面是一些常见的消息队列MQ产品的使用场景合集,这些场景涵盖了多种行业和业务需求。