最近的工作我在做一个有关于消息发送和接受封装工作。大概流程是这样的,消息中间件是采用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输出。然而,我们其实很需要一个可读性很强的输出模式。

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

本篇文章要介绍的是有关于这个补偿程序的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 { getset; }
    /// <summary>
    /// 接受消息ID。
    /// </summary>
    public string ReceiveMessageId { getset; }
}

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

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 { getset; }
    /// <summary>
    /// 接受消息ID
    /// </summary>
    public string ReceiveMessageId { getset; }
    /// <summary>
    /// 处理成功消息ID
    /// </summary>
    public string SuccessMessageId { getset; }
}

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

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

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

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

需要定义一种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 { getset; }
           public object JsonObject { getset; }
           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是不是真的缺少了一个可视化模式。

出处:http://www.cnblogs.com/wangiqngpei557/

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

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

    最近的工作我在做一个有关于消息发送和接受封装工作.大概流程是这样的,消息中间件是采用rabbitmq,为了保证消息的绝对无丢失,我们需要在发送和接受前对消息进行DB落地.在发送前我会先进行DB的插入, ...

  2. RabbitMQ消息队列(十三)-VirtualHost与权限管理

    像mysql有数据库的概念并且可以指定用户对库和表等操作的权限.那RabbitMQ呢?RabbitMQ也有类似的权限管理.在RabbitMQ中可以虚拟消息服务器VirtualHost,每个Virtua ...

  3. RabbitMQ的消息补偿机制

    目录 前言: 常见问题及解决思路 一.消息防丢方案 二.消息防堆积方案 三.消息发送失败补偿方案 3.1 消息发送失败处理方案 3.2 消息发送失败补偿方案 3.3 confirm方案对比 四. 消息 ...

  4. rabbitmq消息队列 ack机制(消息确认机制)和消息补偿机制

    参考:https://blog.csdn.net/pan_junbiao/article/details/112956537 ack 机制就是消息在 生产者在发布消息以后,消息存在内存中,如果消息被确 ...

  5. RabbitMQ消息队列(一)《Java-2021面试谈资系列》

    RabbitMQ RabbitMQ消息队列 一.中间件 1.什么是中间件 2.中间件技术及架构概述 3.消息中间件 1.消息中间件的分布式架构 2.消息中间件使用场景 3.常见的消息中间件 4.消息中 ...

  6. 初探 RabbitMQ 消息队列

    初探 RabbitMQ 消息队列 rabbitmq基础概念常见应用场景导入依赖属性配置具体编码定义队列实体类控制器消息消费者主函数测试总结说点什么 SpringBoot 是为了简化 Spring 应用 ...

  7. 详解SpringCloud中RabbitMQ消息队列原理及配置,一篇就够!

    作者:kosamino cnblogs.com/jing99/p/11679426.html 一.MQ用途 1.同步变异步消息 场景:用户下单完成后,发送邮件和短信通知. 运用消息队列之后,用户下单完 ...

  8. 异步处理需要消息补偿闭环

    使用类似 RabbitMQ.RocketMQ 等 MQ 系统来做消息队列实现异步处理,虽然说消息可 以落地到磁盘保存,即使 MQ 出现问题消息数据也不会丢失,但是异步流程在消息发送. 传输.处理等环节 ...

  9. RabbitMQ(消息队列)浅记

    消息队列 PS:大二下学习RabbitMQ的随手小记 一.什么是 MQ MQ(message queue),从字面意思上看,本质是个队列,FIFO 先入先出,只不过队列中存放的内容是message 而 ...

最新文章

  1. React Ways1——函数即组件
  2. Linux疑难杂症解决方案100篇(十五)-万字长文带你深入Linux 内核学习:环境搭建和内核编译
  3. 【Python】手把手教你用Python做一个图像融合demo,小白可上手!
  4. 你不会知道,一个小小电阻也很奇妙!
  5. react实现多行文本超出加省略号
  6. Python笔记-获取某百科页面所有URL(提取某百科所有URL)
  7. 设计模式8(享元模式,解释器模式)
  8. 洛谷 P1208 [USACO1.3]混合牛奶 Mixing Milk
  9. 一步一步使用阿里云容器服务部署基于.NET的JEXUS网站 (转)
  10. php正则 替换div标签内容,PHP 正则匹配标签内容,根据字符串长度进行替换
  11. 硕思闪客精灵怎么导出flash(gif)动画,flash游戏源文件疑难问题解答(注册码)
  12. Linux创建.txt文件
  13. Power BI 中文版下载方式
  14. Golang程序调试 -- 内存泄漏pprof工具
  15. \int_0^{+\infty} \frac{\sin x}{x}\mathop{}\!\mathrm{d}{x}
  16. C++ 快速学习(一)
  17. Android DOM解析xml
  18. 网络服务器系统管理实训报告,网络系统管理与维护实训报告-20210726103142.docx-原创力文档...
  19. arduino串口接收和发送
  20. shell 字体颜色代码

热门文章

  1. Windows版Qt
  2. C++判断一个数是否为回文数palindrome的算法(附完整源码)
  3. c++ 预处理命令 #error 用法
  4. redis重启命令_这可能是你见过最全面的Redis主从复制原理
  5. 该功能仅支持Android5.0,Android 5.0 android:elevation适用于View,但不适用于Button?
  6. 30.jvm.gc(GC之详解CMS收集过程和日志分析)
  7. Hadoop-rpc调用案例,服务端,客户端代码案例
  8. 3.游戏优化(CCSpriteBatchNode)
  9. Android中访问通讯录,数据的增删改查
  10. 处理数字_3_计算表的行数