Android MessageQueue消息队列主要作用详解

目录
  • 定义
  • 模型关系
  • 内部属性
  • 行为约束
  • 使用建议
  • 消息队列相关概念
  • 消息队列的消费场景
    • 消息至多被消费一次
    • 消息至少被消费一次
    • 消息仅被消费一次
  • 实践Hello World
  • 消息队列好处或功能

定义

队列是 Apache RocketMQ 中消息存储和传输的实际容器,也是 Apache RocketMQ 消息的最小存储单元。 Apache RocketMQ 的所有主题都是由多个队列组成,以此实现队列数量的水平拆分和队列内部的流式存储。

队列的主要作用如下:

  • 存储顺序性 队列天然具备顺序性,即消息按照进入队列的顺序写入存储,同一队列间的消息天然存在顺序关系,队列头部为最早写入的消息,队列尾部为最新写入的消息。消息在队列中的位置和消息之间的顺序通过位点(Offset)进行标记管理。
  • 流式操作语义 Apache RocketMQ 基于队列的存储模型可确保消息从任意位点读取任意数量的消息,以此实现类似聚合读取、回溯读取等特性,这些特性是RabbitMQ、ActiveMQ等非队列存储模型不具备的。

模型关系

在整个 Apache RocketMQ 的领域模型中,队列所处的流程和位置如下:

Apache RocketMQ 默认提供消息可靠存储机制,所有发送成功的消息都被持久化存储到队列中,配合生产者和消费者客户端的调用可实现至少投递一次的可靠性语义。

Apache RocketMQ 队列模型和Kafka的分区(Partition)模型类似。在 Apache RocketMQ 消息收发模型中,队列属于主题的一部分,虽然所有的消息资源以主题粒度管理,但实际的操作实现是面向队列。例如,生产者指定某个主题,向主题内发送消息,但实际消息发送到该主题下的某个队列中。

Apache RocketMQ 中通过修改队列数量,以此实现横向的水平扩容和缩容。

内部属性

读写权限

  • 定义:当前队列是否可以读写数据。
  • 取值:由服务端定义,枚举值如下
  • 6:读写状态,当前队列允许读取消息和写入消息。
  • 4:只读状态,当前队列只允许读取消息,不允许写入消息。
  • 2:只写状态,当前队列只允许写入消息,不允许读取消息。
  • 0:不可读写状态,当前队列不允许读取消息和写入消息。
  • 约束:队列的读写权限属于运维侧操作,不建议频繁修改。

行为约束

每个主题下会由一到多个队列来存储消息,每个主题对应的队列数与消息类型以及实例所处地域(Region)相关,队列数暂不支持修改。

版本兼容性

队列的名称属性在 Apache RocketMQ 服务端的不同版本中有如下差异:

  • 服务端3.x/4.x版本:队列名称由{主题名称}+{BrokerID}+{QueueID}三元组组成,和物理节点绑定。
  • 服务端5.x版本:队列名称为一个集群分配的全局唯一的字符串组成,和物理节点解耦。

因此,在开发过程中,建议不要对队列名称做任何假设和绑定。如果您在代码中自定义拼接队列名称并和其他操作进行绑定,一旦服务端版本升级,可能会出现队列名称无法解析的兼容性问题。

使用建议

按照实际业务消耗设置队列数

Apache RocketMQ 的队列数可在创建主题或变更主题时设置修改,队列数量的设置应遵循少用够用原则,避免随意增加队列数量。

主题内队列数过多可能对导致如下问题:

  • 集群元数据膨胀 Apache RocketMQ 会以队列粒度采集指标和监控数据,队列过多容易造成管控元数据膨胀。
  • 客户端压力过大 Apache RocketMQ 的消息读写都是针对队列进行操作,队列过多容易产生空轮询请求,增加系统负荷。

常见队列增加场景

需要增加队列实现物理节点负载均衡 Apache RocketMQ 每个主题的多个队列可以分布在不同的服务节点上,在集群水平扩容增加节点后,为了保证集群流量的负载均衡,建议在新的服务节点上新增队列,或将旧的队列迁移到新的服务节点上。

需要增加队列实现顺序消息性能扩展 在 Apache RocketMQ 服务端4.x版本中,顺序消息的顺序性在队列内生效的,因此顺序消息的并发度会在一定程度上受队列数量的影响,因此建议仅在系统性能瓶颈时再增加队列。

消息队列相关概念

生产者(Producer): 负责产生消息;

消费者(Consumer): 负责消费消息;

消息(Message): 在应用间传送的数据。消息可以非常简单,比如只包含文本字符串,也可以更复杂,可能包含嵌入对象;

消息队列(Message Queue): 一种应用间的通信方式,消息发送后可以立即返回,由消息系统来确保消息的可靠传递。消息发布者只管把消息发布到 MQ 中而不用管谁来取,消息使用者只管从 MQ 中取消息而不管是谁发布的。这样发布者和使用者都不用知道对方的存在。

消息代理(Message Broker): 负责存储/转发消息,转发分为推和拉两种。

  • 拉是指Consumer主动从Message Broker获取消息;
  • 推是指Message Broker主动将Consumer感兴趣的消息推送给Consumer。

消息队列的消费场景

消息至多被消费一次

该场景是最容易满足的,特点是整个消息队列吞吐量大,实现简单。适合能容忍丢消息,消息重复消费的任务。

a)Producer发送消息到Message Broker阶段:

Producer发消息给Message Broker,不要求Message Broker对接收到的消息响应确认,Producer也不用关心Message Broker是否收到消息了。

b)Message Broker存储/转发阶段:

对Message Broker的存储不要求持久性,转发消息时也不用关心Consumer是否真的收到了。

c)Consumer消费阶段:

Consumer从Message Broker中获取到消息后,可以从Message Broker删除消息,或Message Broker在消息被Consumer拿去消费时删除消息,不用关心Consumer最后对消息的处理结果。

消息至少被消费一次

适合不能容忍丢消息,但允许重复消费的任务。

a)Producer发送消息到Message Broker阶段:

Producer发消息给Message Broker,Message Broker必须响应对消息的确认。

b)Message Broker存储/转发阶段:

Message Broker必须提供持久性保障,转发消息时,Message Broker需要Consumer通知删除消息,才能将消息删除。

c)Consumer消费阶段:

Consumer从Message Broker中获取到消息,必须在消费完成后,Message Broker上的消息才能被删除。

消息仅被消费一次

适合对消息消费情况要求非常高的任务,实现较为复杂,这里的“仅被消费一次”包含如下两种场景:

1)Message Broker上存储的消息被Consumer仅消费一次,场景要求: a)Producer发送消息到Message Broker阶段:

Producer发消息给Message Broker,不要求Message Broker对接收到的消息响应确认,Producer也不用关心Message Broker是否收到消息了。

b)Message Broker存储/转发阶段:

Message Broker必须提供持久性保障,并且每条消息在其消费队列里有唯一标识(这个唯一标识可以由Producer产生,也可以由Message Broker产生)。

c)Consumer消费阶段:

Consumer从Message Broker中获取到消息后,需要记录下消费的消息标识,以便在后续消费中防止对某个消息重复消费。比如Consumer获取到消息,消费完后,还没来得及从Message Broker删除消息,就挂了,这样Message Broker如果把消息重新加入待消费队列的话,那么这条消息就会被重复消费了。

2)Producer上产生的消息被Consumer仅消费一次,场景要求: a)Producer发送消息到Message Broker阶段:

Producer发消息给Message Broker,Message Broker必须响应对消息的确认,并且Producer负责为该消息产生唯一标识,以防止Consumer重复消费(因为Producer发消息给Message Broker后,由于网络问题没收到Message Broker的响应,可能会重发消息给到Message Broker)。

b)Message Broker存储/转发阶段:

Message Broker必须提供持久性保障,并且每条消息在其消费队列里有唯一标识(这个唯一标识需要由Producer产生)。

c)Consumer消费阶段:

Consumer从Message Broker中获取到消息后,需要记录下消费的消息标识,以便在后续消费中防止对某个消息重复消费。比如Consumer获取到消息,消费完后,还没来得及从Message Broker删除消息,就挂了,这样Message Broker如果把消息重新加入待消费队列的话,那么这条消息就会被重复消费了。

实践Hello World

/// <summary>
/// 发送按钮事件
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void button1_Click(object sender, EventArgs e)
{
    if (!string.IsNullOrEmpty(textBox1.Text.Trim()))
    {
        try
        {
            //判断私有队列是否存在
            if (!MessageQueue.Exists(@".\Private$\MyPrivateQueue"))
            {
                //创建一个私有队列
                MessageQueue.Create(@".\Private$\MyPrivateQueue");
            }
            //实例一个队列
            var queue = new MessageQueue(@".\Private$\MyPrivateQueue");
            //发送消息(第一个参数为消息内容,第二个参数为消息标签或名称)
            queue.Send(textBox1.Text.Trim(), "TestLable");
        }
        catch (MessageQueueException ex)
        {
            MessageBox.Show(ex.Message, "异常消息", MessageBoxButtons.OK, MessageBoxIcon.Error);
        }
    }
}

消息队列好处或功能

1、消息可以在断开连接的环境下发送。不需要同时运行正在发送和正在接收的应用程序。

2、使用快捷模式,消息可以非常快地发送。在快捷模式下,消息存储在内存中。

3、对于可恢复的机制,消息可以使用有保证的交付方式发送。可恢复的消`息存储在文件中。在服务器重新启动时发送它们。

4、用访问控制列表来保护消息队列,可以确定哪些用户可以发送或接收队列中的消息。消息还可以加密,避免网络嗅探器读取其中的数据。消息在发送时可以指定优先级,这样可以更快地处理高优先级的项。

5、Message Queuing 3.0支持多播消息的发送。

6、Message queuing 4.0支持病毒消息。病毒消息不能解析。可以定义病毒队列中不能解析的消息是可以移动的。例如,如果从正常的队列中读取消息后,对应作业要把消息插入数据库中,但消息不能插入数据库,因此该作业失败,该消息就会发送到病毒队列中。有人负责处理病毒队列,这个人应以能解析病毒消息的方式来处理该消息。

7、Message Queuing 5.0支持更安全学身份验证算法,可以处理大量队列(Message queuing 4.0在处理几千个队列时有性能问题)。

到此这篇关于Android MessageQueue消息队列主要作用详解的文章就介绍到这了,更多相关Android MessageQueue消息队列内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Android7.0 MessageQueue详解

    Android中的消息处理机制大量依赖于Handler.每个Handler都有对应的Looper,用于不断地从对应的MessageQueue中取出消息处理. 一直以来,觉得MessageQueue应该是Java层的抽象,然而事实上MessageQueue的主要部分在Native层中. 自己对MessageQueue在Native层的工作不太熟悉,借此机会分析一下. 一.MessageQueue的创建 当需要使用Looper时,我们会调用Looper的prepare函数: public stati

  • 深入Android Handler,MessageQueue与Looper关系

    关联篇:HandlerThread 使用及其源码完全解析 关联篇:Handler内存泄漏详解及其解决方案 一说到Android的消息机制,自然就会联想到Handler,我们知道Handler是Android消息机制的上层接口,因此我们在开发过程中也只需要和Handler交互即可,很多人认为Handler的作用就是更新UI,这也确实没错,但除了更新UI,Handler其实还有很多其他用途,比如我们需要在子线程进行耗时的I/O操作,可能是读取某些文件或者去访问网络等,当耗时操作完成后我们可能需要在U

  • 详细分析android的MessageQueue.IdleHandler

    我们知道android是基于Looper消息循环的系统,我们通过Handler向Looper包含的MessageQueue投递Message, 不过我们常见的用法是这样吧? 一般我们比较少接触MessageQueue, 其实它内部的IdleHandler接口有很多有趣的用法,首先看看它的定义: 简而言之,就是在looper里面的message暂时处理完了,这个时候会回调这个接口,返回false,那么就会移除它,返回true就会在下次message处理完了的时候继续回调,让我们看看它有哪些有趣的用

  • Android Handler,Message,MessageQueue,Loper源码解析详解

    本文主要是对Handler和消息循环的实现原理进行源码分析,如果不熟悉Handler可以参见博文< Android中Handler的使用>,里面对Android为何以引入Handler机制以及如何使用Handler做了讲解. 概括来说,Handler是Android中引入的一种让开发者参与处理线程中消息循环的机制.我们在使用Handler的时候与Message打交道最多,Message是Hanlder机制向开发人员暴露出来的相关类,可以通过Message类完成大部分操作Handler的功能.但

  • C++ 中消息队列函数实例详解

    C++ 中消息队列函数实例详解 1.消息队列结构体的定义 typedef struct{ uid_t uid; /* owner`s user id */ gid_t gid; /* owner`s group id */ udi_t cuid; /* creator`s user id */ gid_t cgid; /* creator`s group id */ mode_t mode; /* read-write permissions 0400 MSG_R 0200 MSG_W*/ ul

  • android线程消息机制之Handler详解

    android线程消息机制主要由Handler,Looper,Message和MessageQuene四个部分组成.平常在开发中,我们常用来在子线程中通知主线程来更新,其实整个安卓生命周期的驱动都是通过Handler(ActivityThread.H)来实现的. 首先我们先介绍这四个类的作用: Handler:消息的发送者.负责将Message消息发送到MessageQueue中.以及通过Runnable,Callback或者handleMessage()来实现消息的回调处理 Looper:是消

  • PHP使用ActiveMQ实现消息队列的方法详解

    本文实例讲述了PHP使用ActiveMQ实现消息队列的方法.分享给大家供大家参考,具体如下: 前面我们已经学了如何部署ActiveMQ, 我们知道通过ActiveMQ的一个管理后台可以查看任务队列. 今天 用PHP来操作ActiveMQ,我们可以借助一个第三方扩展. 下载: composer require fusesource/stomp-php:2.0.* 然后新建test.php: <?php require __DIR__.'/vendor/autoload.php'; //引入自动加载

  • 使用MQ消息队列的优缺点详解

    前言 公司的项目一直都是在使用MQ的,但是由于使用的功能很简单,所以一直都是知其然不知其所以然,作为一个程序猿有必要了解每一个使用的技术,为什么使用它?它的优点是什么?缺点是什么?等等... 使用mq的好处 解耦与复用 系统A要发送一个消息到多个系统,如果此时每增加一个系统,系统A都需要通过修改源码来增加接口,此时耦合非常高,但是如果中间使用消息队列的话,系统只需要发送一次到消息队列,别的系统就能复用该信息,当增加或删除系统调用接口的时候,不需要额外的更新代码. 异步 用户调用一个接口的时候,可

  • 在Android中使用WebSocket实现消息通信的方法详解

    前言 消息推送功能可以说移动APP不可缺少的功能之一,一般简单的推送我们可以使用第三方推送的SDK,比如极光推送.信鸽推送等,但是对于消息聊天这种及时性有要求的或者三方推送不满足业务需求的,我们就需要使用WebSocket实现消息推送功能. 基本流程 WebSocket是什么,这里就不做介绍了,我们这里使用的开源框架是https://github.com/TakahikoKawasaki/nv-websocket-client 基于开源协议我们封装实现WebSocket的连接.注册.心跳.消息分

  • Android项目中实体类entity的作用详解

    估计很多入门安卓的朋友对entity很困惑,为什么要写实体类?有什么用?写来干什么? 对于实体类的理解我入门的时候也是困惑了好久,后面用多了才慢慢理解,这篇博客就当复习和笔记. Java中entity(实体类)的写法规范 在日常的Java项目开发中,entity(实体类)是必不可少的,它们一般都有很多的属性,并有相应的setter和getter方法.entity(实体类)的作用一般是和数据表做映射.所以快速写出规范的entity(实体类)是java开发中一项必不可少的技能. 在项目中写实体类一般

  • Android事件处理的两种方式详解

    安卓提供了两种方式的事件处理:基于回调的事件处理和基于监听的事件处理. 基于监听的事件处理 基于监听的事件处理一般包含三个要素,分别是: Event Source(事件源):事件发生的场所,通常是各个组件 Event(事件):事件封装了界面组件上发生的特定事件(通常就是用户的一次操作) Event Listener(事件监听器):负责监听事件源发生的事件,并对各种事件作出相应的响应 下面使用一个简单的案例介绍按钮事件监听器 布局文件就是简单的线性布局器,上面是一个EditText,下面是一个Bu

  • Android线程间通信 Handler使用详解

    目录 前言 01.定义 02.使用 第一步.创建 第二步.发送消息 第一种是 post(Runnable) 第二种是 sendMessage(Message) 第三步.处理消息 03.结语 前言 Handler,可谓是面试题中的一个霸主了.在我<面试回忆录>中,几乎没有哪家公司,在面试的时候是不问这个问题的.简单一点,问问使用流程,内存泄漏等问题.复杂一点,纠其源码细节和底层 epoll 机制来盘你.所以其重要性,不言而喻了吧. 那么今天让我们来揭开 Handler 的神秘面纱.为了读者轻松易

  • Android 控制ScrollView滚动的实例详解

    Android 控制ScrollView滚动的实例详解 在开发中,我们经常需要更新列表,并将列表拉倒最底部,比如发表微博,聊天界面等等, 这里有两种办法,第一种,使用scrollTo(): public static void scrollToBottom(final View scroll, final View inner) { Handler mHandler = new Handler(); mHandler.post(new Runnable() { public void run()

随机推荐