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是不是真的缺少了一个可视化模式。

作者:王清培

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

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面

时间: 2024-10-13 12:01:41

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

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

最近的工作我在做一个有关于消息发送和接受封装工作.大概流程是这样的,消息中间件是采用rabbitmq,为了保证消息的绝对无丢失,我们需要在发送和接受前对消息进行DB落地.在发送前我会先进行DB的插入,单表插入,所以在性能上也是能接受的,单表插入做了压测基本上是一到两毫秒的时间,加上消息的发送(有ACK)再加上集群是两个节点的高可用(一个磁盘持久化节点),单台TPS基本上是在2000-3000左右.这对于我们的业务场景来说是够用了.一旦当消息丢失或者由于网络问题.集群问题业务不会中断,消息就算发不

RabbitMQ原理与相关操作(三)消息持久化

现在聊一下RabbitMQ消息持久化: 问题及方案描述 1.当有多个消费者同时收取消息,且每个消费者在接收消息的同时,还要处理其它的事情,且会消耗很长的时间.在此过程中可能会出现一些意外,比如消息接收到一半的时候,一个消费者死掉了. 这种情况要使用消息接收确认机制,可以执行上次宕机的消费者没有完成的事情. 2.在默认情况下,我们程序创建的消息队列以及存放在队列里面的消息,都是非持久化的.当RabbitMQ死掉了或者重启了,上次创建的队列.消息都不会保存. 这种情况可以使用RabbitMQ提供的消

Spring Boot (25) RabbitMQ消息队列

MQ全程(Message Queue)又名消息队列,是一种异步通讯的中间件.可以理解为邮局,发送者将消息投递到邮局,然后邮局帮我们发送给具体的接收者,具体发送过程和时间与我们无关,常见的MQ又kafka.activemq.zeromq.rabbitmq等等. RabbitMQ RabbitMQ是一个遵循AMQP协议,由面向高并发的erlang语言开发而成,用在实时的对可靠性要求比较高的消息传递上,支持多种语言客户端,支持延迟队列. 基础概念 Broker:消息队列的服务器实体 Exchange:

(转)RabbitMQ消息队列(七):适用于云计算集群的远程调用(RPC)

在云计算环境中,很多时候需要用它其他机器的计算资源,我们有可能会在接收到Message进行处理时,会把一部分计算任务分配到其他节点来完成.那么,RabbitMQ如何使用RPC呢?在本篇文章中,我们将会通过其它节点求来斐波纳契完成示例. 1. 客户端接口 Client interface 为了展示一个RPC服务是如何使用的,我们将创建一段很简单的客户端class. 它将会向外提供名字为call的函数,这个call会发送RPC请求并且阻塞知道收到RPC运算的结果.代码如下: [python] vie

Python并发编程-RabbitMq消息队列

消息中间件 --->就是消息队列 异步方式:不需要立马得到结果,需要排队 同步方式:需要实时获得数据,坚决不能排队 subprocess 的Q也提供不同进程之间的沟通 应用场景: 买票,抢购 堡垒机批量发送文件 Centos6.x系统编译安装RabbitMQ 一.系统环境 [[email protected] ~]# cat /etc/redhat-release CentOS release 6.6 (Final) [[email protected] ~]# uname -r 2.6.32-

RabbitMQ消息队列1: Detailed Introduction 详细介绍

1. 历史 RabbitMQ是一个由erlang开发的AMQP(Advanced Message Queue )的开源实现.AMQP 的出现其实也是应了广大人民群众的需求,虽然在同步消息通讯的世界里有很多公开标准(如 COBAR的 IIOP ,或者是 SOAP 等),但是在异步消息处理中却不是这样,只有大企业有一些商业实现(如微软的 MSMQ ,IBM 的 Websphere MQ 等),因此,在 2006 年的 6 月,Cisco .Redhat.iMatix 等联合制定了 AMQP 的公开标

RabbitMQ消息队列应用

RabbitMQ消息队列应用 消息通信组件Net分布式系统的核心中间件之一,应用与系统高并发,各个组件之间解耦的依赖的场景.本框架采用消息队列中间件主要应用于两方面:一是解决部分高并发的业务处理:二是通过消息队列传输系统日志.目前业界使用较多的消息队列组件有RabbitMQ.ActiveMQ.MSMQ.kafka.zeroMQ等,本文对系统架构之MQ Component诠释,并采用RabbitMQ作为消息队列中间件. 图1- 消息队列组件示意图 一.RabbitMQ介绍 RabbitMQ是一款基

Net分布式系统之四:RabbitMQ消息队列应用

消息通信组件Net分布式系统的核心中间件之一,应用与系统高并发,各个组件之间解耦的依赖的场景.本框架采用消息队列中间件主要应用于两方面:一是解决部分高并发的业务处理:二是通过消息队列传输系统日志.目前业界使用较多的消息队列组件有RabbitMQ.ActiveMQ.MSMQ.kafka.zeroMQ等,本文对系统架构之MQ Component诠释,并采用RabbitMQ作为消息队列中间件. 图1- 消息队列组件示意图 一.RabbitMQ介绍 RabbitMQ是一款基于AMQP(消息队列协议),由

Nginx通过LUA脚本访问RabbitMQ消息队列

发现了一个Nginx的LUA脚本:lua-resty-rabbitmqstomp,可以让Nginx通过LUA脚本访问RabbitMQ消息队列,这个脚本是通过stomp协议连接RabbitMQ的stomp适配器,来pub/sub消息的 关于RabbitMQ-STOMP安装使用相关内容可以参见:RabbitMQ STOMP Adapter 关于Nginx-LUA模块安装使用参见:LAMP架构演进到LAMPGC,再演进到LNMLGC 关于STOMP协议相关资料参见这里: STOMP官方英文协议1.1版