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输出。然而,我们其实很需要一个可读性很强的输出模式。
我在开发消息补偿程序的时候,我借鉴了这一思想进行了尝试。先来看下整体架构蓝图:
本篇文章要介绍的是有关于这个补偿程序的api的可视化输出内容。不涉及到消息相关太多的东西,只是为了让这个可视化输出看起来容易理解点。这个补偿程序需要对发送的消息和接受的消息进行查询和比较然后输出,用来确定消息的发送是失败了还是成功的。简单逻辑就是比较某个时间段内的消息发送表和接受表,然后进行消息id的匹配。
我在想这个数据反馈到api上是个什么样子的,按照常规设计就是两个字段:
/// <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中的看起来也还行,但是不直观。
GetReceiveMessage是获取接受消息列表,就是查看当前消息发送到接受是个什么状态。
/// <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可能是没有的。就会针对处理成功的消息进行发送。
突然受到ElasticSearch的_cat endpoint 启发。似乎这里我可以尝试下,webapi带有两种输出模式,一种是针对程序使用的json输出模式,另外一种是针对人可以阅读的模式text/plain模式,而第二种模式可以简单的理解为是行列转换缺省模式。
是不是看起来会很舒服。这在进行消息的时间段查看非常有帮助,如果还按照原本的json输出模式可能看起来会比较吃力。
来看下基本的api的设计,为了保证你的所有api支持?v可视化模式,需要一定的抽象:
需要定义一种ViewModel,所有的数据都输出这种对象,当然我这里也只是简单地封装。如果可以,其实可以专门提取出一个库出来,包括对文本的输出自动化。
我们看下BaseApiController:
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是不是真的缺少了一个可视化模式。
WebAPi的可视化输出模式(RabbitMQ、消息补偿相关)——所有webapi似乎都缺失的一个功能的更多相关文章
- RabbitMQ原理与相关操作(三)消息持久化
现在聊一下RabbitMQ消息持久化: 问题及方案描述 1.当有多个消费者同时收取消息,且每个消费者在接收消息的同时,还要处理其它的事情,且会消耗很长的时间.在此过程中可能会出现一些意外,比如消息接收 ...
- 快速了解RabbitMQ消息队列
MQ 是什么?队列是什么,MQ 我们可以理解为消息队列,队列我们可以理解为管道.以管道的方式做消息传递. 场景: 1.其实我们在双11的时候,当我们凌晨大量的秒杀和抢购商品,然后去结算的时候,就会发现 ...
- Spring Boot (25) RabbitMQ消息队列
MQ全程(Message Queue)又名消息队列,是一种异步通讯的中间件.可以理解为邮局,发送者将消息投递到邮局,然后邮局帮我们发送给具体的接收者,具体发送过程和时间与我们无关,常见的MQ又kafk ...
- SpringCloud之RabbitMQ消息队列原理及配置
本篇章讲解RabbitMQ的用途.原理以及配置,RabbitMQ的安装请查看SpringCloud之RabbitMQ安装 一.MQ用途 1.同步变异步消息 场景:用户下单完成后,发送邮件和短信通知. ...
- .net core使用rabbitmq消息队列 (二)
之前有写过.net core集成使用rabbitmq的博文,见.net core使用rabbitmq消息队列,但是里面的使用很简单,而且还有几个bug,想改下,但是后来想了想,还是算了,之前使用的是. ...
- RabbitMQ消息队列(一): Detailed Introduction 详细介绍
http://blog.csdn.net/anzhsoft/article/details/19563091 RabbitMQ消息队列(一): Detailed Introduction 详细介绍 ...
- RabbitMQ消息队列1: Detailed Introduction 详细介绍
1. 历史 RabbitMQ是一个由erlang开发的AMQP(Advanced Message Queue )的开源实现.AMQP 的出现其实也是应了广大人民群众的需求,虽然在同步消息通讯的世界里有 ...
- Net分布式系统之四:RabbitMQ消息队列应用
消息通信组件Net分布式系统的核心中间件之一,应用与系统高并发,各个组件之间解耦的依赖的场景.本框架采用消息队列中间件主要应用于两方面:一是解决部分高并发的业务处理:二是通过消息队列传输系统日志.目前 ...
- rabbitmq消息队列——"Hello World!"
RabbitMQ 一."Hello World!" 1.简介: RabbitMQ是一种消息中间件,主要思想很简单:接收消息并转发.你可以将它设想为一个邮局:你往里面发送邮件并确保邮 ...
随机推荐
- c3p0数据库连接池的使用详解
首先,什么是c3p0?下面是百度百科的解释: C3P0是一个开源的JDBC连接池,它实现了数据源和JNDI绑定,支持JDBC3规范和JDBC2的标准扩展.目前使用它的开源项目有Hibernate,Sp ...
- Angularjs CURD
前言 基于一个手机端的项目使用了angularjs,硬着头皮去用,有很多的疑问还需要一一去验证,刚开始总是感觉找不到北,总是感觉有很多概念,而且似乎ng既夹杂MVC又夹杂MVVM的思想, 忙里偷闲敲了 ...
- jquery动画,基础以及我发现的新大陆
$.animate()在jquery官方介绍有2中方式,其实我发现的新大陆也是第二种方式的扩展! 一.$.animate( properties [, duration ] [, easing ] [ ...
- Android Lint Checks
Android Lint Checks Here are the current list of checks that lint performs as of Android Studio 2.3 ...
- 关于异步执行(Async/await)的理解(转发)
原文地址: http://blog.jobbole.com/85787/ 同步编程与异步编程 通常情况下,我们写的C#代码就是同步的,运行在同一个线程中,从程序的第一行代码到最后一句代码顺序执行.而异 ...
- 模仿36。杀毒~button
<Style x:Key="360btn" TargetType="{x:Type Button}"> <Setter Property=&q ...
- [WCF编程]5.绑定概述
一.绑定概述 WCF提供了一个编程框架,可以抽象化服务创建的复杂过程.绑定允许开发人员将精力集中在问题本身上,而无需考虑如何创建允许系统运行的架构,因为WCF已经创建了架构. 绑定类型是开发人员控制W ...
- 关于SQL Server 安装程序在运行 Windows Installer 文件时遇到错误
前几日安装sql server2008r2 的时候碰到这个问题: 出现以下错误: SQL Server 安装程序在运行 Windows Installer 文件时遇到错误. Windows Insta ...
- de4dot3.14更新文件打包下载
刚发现de4dot更新了,虽然只是10月份的文件更新,并未发布新的release,但好多人还不会编译... 关于de4dot有何功能就不再讲了. 本文主要提供编译通过后的打包文件下载. 首先下载de4 ...
- Oracle内置函数:时间函数,转换函数,字符串函数,数值函数,替换函数
dual单行单列的隐藏表,看不见 但是可以用,经常用来调内置函数.不用新建表 时间函数 sysdate 系统当前时间 add_months 作用:对日期的月份进行加减 写法:add_months(日期 ...