精华内容
下载资源
问答
  • 互联网那些事 |MQ数据丢失

    千次阅读 2020-01-23 16:51:52
    小王和小明分别维护分布式系统中A、b两个服务,有一个场景是 A服务会向B服务通过MQ发送事件并且推送用户信息,然后B服务保存用户信息。 有一天,小王和小明因为一件事讨论得热火朝天、互不相让,事情由来如下: ...

    互联网那些事 | MQ数据丢失

    本系列故事的所有案例和解决方案只是笔者以前在互联网工作期间的一些事例,仅供大家参考,实际操作应该根据业务和项目情况设计,欢迎大家留言提出宝贵的意见

    背景

    小王和小明分别维护分布式系统中A、b两个服务,有一个场景是 A服务会向B服务通过MQ发送事件并且推送用户信息,然后B服务保存用户信息。
    在这里插入图片描述

    有一天,小王和小明因为一件事讨论得热火朝天、互不相让,事情由来如下:

    • 风控部的童鞋找小明说在B服务的数据库找不到一些用户资料
    • 小明经过排查,B服务表里确实没有这批用户的数据,在日志里偶尔看到了一些Redis连接超时异常,小明想小王手动帮忙重推试试
    • 小王经过排查,确保自己已经成功推送了那几个用户的数据,并且推送的时候A服务并没有发现MQ异常,觉得自己没有义务去帮忙重推,应该小明自己解决

    这时候,在一旁扫地的清洁工老梁过来调解,并帮忙排查分析,导致这个问题的主要原因如下:

    • B服务在接受MQ的处理类捕获了异常,因为异常并没有抛出,所以框架默认自动回复了ACK,MQ认为已经消费者处理成功,就不再重复投放到队列,但此时方法体内因为工具包出现Redis连接超时,抛出异常,导致消息并没有被正常处理

    伪代码如下:

        @RabbitHandler
        public void handle(byte[] message) {
            try {
                t = parseBody(messageStr);
            } catch (Exception e) {
                log.error("消费消息失败", e.getCause());
            }
        }
    
        private void handleMessage(T t) throws MQHandleException {
    	    //唯一标识
            String key = t.getLockedId();
            //获取锁
            DistributedLock lock = DistributedLockFactory.getLock(key);
            try {
                // 解决分布式服务提交相同资料并发问题
                lock.lock(CacheConstants.LOCK_WAIT_TIME, CacheConstants.LOCK_LEASE_TIME, CacheConstants.DEFAULT_CACHE_UNIT);
                // 处理业务逻辑
                handleBusinessLogic(t);
            } catch (LockException e) {
                throw new MQHandleException(e);
            } finally {
                // 释放锁
                lock.unLock();
            }
        }
    

    • 频繁Redis超时是因为A、B服务共用一个Redis,A服务Key太多把Redis内存资源占满了(也可能连接占满),导致了B服务经常出现连接超时(该故障不是本章主要关注目标)

    • B服务在已经成功接受到消息后,没有把消息先保存起来,所以也导致了自身并没有能力重跑

    清洁工老梁跟小王和小明进行一番详谈后,了解到他们主要需求有两个:

    • B服务尽可能自己重新消费信息,而不是一昧依赖A服务手动重推
    • B服务对已接收到的消息,能自己重新消费,当然,这里指的是有意义的消息,如果一些本身A服务推送过来的消息就是有问题的,例如格式错误之类的,这些B服务可以要求A重推

    解决思路

    经过上面的分析,老梁的解题思路主要分为两个方向:

    • B服务建立自己的本地异常消息事件表。
    • B服务做异常分类,只对可以重跑的消息事件进行重跑

    本地异常消息事件表

    一般来说,常见的微服务架构实现最终一致性有三种模式:可靠事件模式、业务补偿模式、TCC模式。这里AB服务是通过业务补偿模式实现最终一致性,但这里又跟我们一般的分布式架构的事务问题不同,这里我们只需要保证B服务能最终把正常消息事件消费成功即可。

    实现思路:

    • 建立一张本地异常消息事件表,为了避免太多数据库IO操作,这里只会记录异常事件
    • 提取一个通用消息处理层,统一保存异常消息事件,并进行状态更新
    • 提取一个事件恢复模块,统一对失败事件进行追踪
    • 对于重跑仍失败消息事件,设置一个重跑次数上限,进行自动重跑,可以通过调度任务去做(事件恢复模块),当重跑多次仍然失败(像网络异常和数据库异常之类,短时间不会被修复),则后期进行人工重跑

    表设计


    针对于B服务,对于收到的MQ信息没有进行有效的记录,而且MQ信息处理之后,存在修改错误,没法进行对应信息补充修复的功能,增加通用消息处理层,进行消息体的记录和回溯。 在获取消息之后进行一次记录,进行幂等操作和对应的状态更新, 消息状态在业务相关操作完成后,标记为处理完成,认为对应消息状态结束。

    这里hash_value是对请求体进行hash计算得出来的一个值,例如:MD5、SHA-2,保证每个不同请求的hash码不一样,相同的请求hash码相同,可以用于幂等控制。

    表大致操作流程:

    异常消息状态设计

    异常消息有4个状态

    • 待处理 当系统消费失败时,会对特定的异常插入异常事件表,初始状态为 待处理
    • 处理中 当失败恢复模块开始执行任务时会把当前异常事件状态设置为 处理中
    • 处理完成 当失败事件重跑成功后,会把当前异常事件状态设置为 处理完成
    • 异常 当失败事件重跑超过上限次数后,会把当前异常事件状态设置为 异常,等待后期人工重跑

    事件恢复模块

    失败事件队列在这里是采用数据库表代替


    异常分类

    因为并非所有的异常都能重跑就能解决问题,我们只能针对可以修复的异常进行重试,这里把异常分为两大类:

    • 可修复异常:可修复异常指的是可以通过重跑解决的异常,如:数据库超时、数据库缺少字段、Redis获取锁失败、处理逻辑有问题导致信息缺失、系统升级导致消费失败、网络问题、服务器不稳定等引起。
      • 可立即修复异常:指一些可以通过立即重试就能恢复的异常。例如短暂的网络中断引起的异常,一般可以在功能代码级进行立即重试,可以使用spring-retry等组件
      • 延迟修复异常:指一些短时间内不能立即恢复的异常,需要延迟执行,等待故障修复。例如依赖的下游系统正在升级,导致一段时间服务接口中断不可以用,需要等待服务启动才能使用,一般通过定时任务设定一定时间间隔或者重跑次数去解决
      • 人工修复异常:指系统没办法直接修复,出现了一些未知异常或者短时间内不可解决的异常,例如Redis宕掉无法预知修复时间、上线时脚本遗漏导致表里缺少字段等,需要人工干预进行重跑,一般通过后台管理页面操作
    • 不可修复异常:不可修复异常指不能通过重跑就能解决的异常。如:上游系统传输格式有问题、消息事件内容本身有误等引起的异常,这些即使重跑也解决不了问题,应该要从上游系统或者根源去解决。

    B服务异常处理流程

    最后小明负责的B服务按照老梁的思路,重新调整了代码,异常处理流程如下:

    展开全文
  • 财经资讯实时数据处理-设计方案 1.如何解决获取同步mongo数据 爬虫程序在存数据时判断数据是否为新数据 确定为新存数据需要通过redis打个标记, 确定存入数据含有新数据 爬虫程序结束时需要在结束调用函数查询redis...

    设计方案

    1.如何解决获取同步mongo数据
    1. 爬虫程序在存数据时判断数据是否为新数据
    2. 确定为新存数据需要通过redis打个标记, 确定存入数据含有新数据
    3. 爬虫程序结束时需要在结束调用函数查询redis是否含有标记, 如果标记存在调用生产者通知MQ上游程序执行完让下游程序开始获取并处理数据
    2.如何解决MQ实时获取数据

    1. 使用MQ的发布/订阅一对一获取队列
    2. 初步定为消费者判断获取增量数据并存储一个处理的时间日期节点

    1. 将之前的一对一获取队列改为按网站行业/类型/媒体创建多个队列, 提高并发
    2. 获取增量数据改为爬虫每次调用生产者发送给队列中
      消息结构:{“start_time”:xxxx, “end_time”:xxxx, ''makr":xxx, "sort ":xxxxx}

    start_time: 爬虫开始存入开始时间戳
    end_time: 爬虫结束存入开始时间戳
    makr: 标识
    sort: 分类 (这个暂定, 需要在生产者之前去确认, MQ通过生产者在将消息发送给Exchange的时候,一般会指定一个routing key,来指定这个消息的路由规则)

    3. 大体流程图:

    在这里插入图片描述

    4. 采用direct队列Queue:
    • direct类型的Exchange路由规则也很简单,它会把消息路由到那些binding key与routing key完全匹配的Queue中
      在这里插入图片描述

    以routingKey=”error”发送消息到Exchange,则消息会路由到Queue1(amqp.gen-S9b…,这是由RabbitMQ自动生成的Queue名称)和Queue2(amqp.gen-Agl…)如果我们以routingKey=”info”或routingKey=”warning”来发送消息,则消息只会路由到Queue2。routingKey发送消息,则消息不会路由到这两个Queue中。

    5. rebbitmq 管理和监视
    1. rebbitmq搭建采用docker容器部署在128服务器
    2. 外网采用docker安装nginx容器反向代理转发128服务器MQ管理页面
    6. 消费者确认和发布者确认

    消费者确认:

    • MQ 消费消息的机制:在消费者收到消息的时候,会发送一个 ACK 给 MQ,告诉 MQ 这条消息被消费到了,这样 MQ 就会把消息删除
    • 默认情况下这个发送 ACK 的操作是自动提交的, 自动提交会存在消费者数据丢失或者没有消费
    • 针对这个问题的解决方案就是:关闭 MQ 消费者的自动提交 ACK,在消费者处理完这条消息之后再手动提交 ACK (手写代码确认)

    发布者确认:

    • 事务方式:在生产者发送消息之前,通过channel.txSelect开启一个事务,接着发送消息。如果消息没有成功被 RabbitMQ 接收到,生产者会收到异常,此时就可以进行事务回滚channel.txRollback,然后重新发送。假如 RabbitMQ 收到了这个消息,就可以提交事务channel.txCommit。但是这样一来,生产者的吞吐量和性能都会降低很多.
    • Confirm 机制: 是在生产者那里设置, 每次写消息的时候会分配一个唯一的 ID,然后 RabbitMQ 收到之后会回传一个 ACK,告诉生产者这个消息 OK 了。如果 RabbitMQ 没有处理到这个消息,那么就回调一个 Nack 的接口,这个时候生产者就可以重发。
    展开全文
  • MQ 消息队列中的数据丢失处理办法 2.丢消息。 这得从java的java.net.SocketException异常说起。简单点说就是当网络发送方发送一堆数据,然后调用close关闭连接之后。这些发送的数据都在接收者的缓存里,接收者如果...

    MQ 消息队列中的数据丢失处理办法
    img
    2.丢消息。

    这得从java的java.net.SocketException异常说起。简单点说就是当网络发送方发送一堆数据,然后调用close关闭连接之后。这些发送的数据都在接收者的缓存里,接收者如果调用read方法仍旧能从缓存中读取这些数据,尽管对方已经关闭了连接。但是当接收者尝试发送数据时,由于此时连接已关闭,所以会发生异常,这个很好理解。不过需要注意的是,当发生SocketException后,原本缓存区中数据也作废了,此时接收者再次调用read方法去读取缓存中的数据,就会报Software caused connection abort: recv failed错误。

    通过抓包得知,ActiveMQ会每隔10秒发送一个心跳包,这个心跳包是服务器发送给客户端的,用来判断客户端死没死。如果你看过上面第一条,就会知道非持久化消息堆积到一定程度会写到文件里,这个写的过程会阻塞所有动作,而且会持续20到30秒,并且随着内存的增大而增大。当客户端发完消息调用connection.close()时,会期待服务器对于关闭连接的回答,如果超过15秒没回答就直接调用socket层的close关闭tcp连接了。这时客户端发出的消息其实还在服务器的缓存里等待处理,不过由于服务器心跳包的设置,导致发生了java.net.SocketException异常,把缓存里的数据作废了,没处理的消息全部丢失。

    解决方案:用持久化消息,或者非持久化消息及时处理不要堆积,或者启动事务,启动事务后,commit()方法会负责任的等待服务器的返回,也就不会关闭连接导致消息丢失了。

    一种是用MQ的事务,但是有个缺点,是阻塞的,影响性能

    另一种是用confirm模式(优点,就是执行效率高,不需要等待消息执行完,只需要监听消息即可)

    ​ 方式一:channel.waitForConfirms()普通发送方确认模式;

    ​ 方式二:channel.waitForConfirmsOrDie()批量确认模式;

    ​ 方式三:channel.addConfirmListener()异步监听发送方确认模式;另一种是用confirm模式(优点,就是执行效率高,不需要等待消息执行完,只需要监听消息即可)

    ​ 方式一:channel.waitForConfirms()普通发送方确认模式;

    ​ 方式二:channel.waitForConfirmsOrDie()批量确认模式;

    ​ 方式三:channel.addConfirmListener()异步监听发送方确认模式;

    1.1.1、生产者弄丢了数据

    生产者将数据发送到 ActiveMQ的时候,可能因为网络问题等原因,在生成的过程中数据丢失。

    解决方案

    ​ 基于生成者发送消息自己不知道是否发送成功的情况,有如下两种解决方式。

    事务机制:可以选择用 activeMQ提供的事务功能,就是生产者发送数据之前开启 activeMQ事务。Session session = connection.createSession(true, Session.AUTO_ACKNOWLEDGE); 但是问题来了,如果使用activeMQ事务机制(同步)一搞,基本上吞吐量会下来,因为太耗性能

    非事务机制(消息持久化,confirm 机制):事务机制和 confirm 机制最大的不同在于,事务机制是同步的,你提交一个事务之后会阻塞在那儿,但是 confirm 机制是异步的,你发送个消息之后就可以发送下一个消息,然后那个消息 RabbitMQ 接收了之后会异步回调你的一个接口通知你这个消息接收到了。

    Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);

    producer.setDeliveryMode(factory.getDeliveryMode())

    所以一般在生产者这块避免数据丢失,都是用 confirm 机制的。

    1.1.2、ActiveMQ弄丢了数据

    当生产者发送消息到ActiveMQ,Active没进行消失持久化时挂掉了,此时ActiveMQ重启的时候发送过来的数据就丢失了。解决方案是要将接收到的消息进行持久化操作

    producer.setDeliveryMode(DeliveryMode.PERSISTENT);

    ActiveMQ不设置,默认就是持久的.

    虽然都保存到了文件里,但它和持久化消息的区别是,重启后持久化消息会从文件中恢复,非持久化的临时文件会直接删除。

    1.1.3、消费者弄丢了数据

    ​ activeMQ如果丢失了数据,主要是因为你消费的时候,刚消费到,还没处理,结果进程挂了,比如重启了,那么就尴尬了,RabbitMQ 认为你都消费了,这数据就丢了。

    自动重试机制:自动确认,收到消息以后,自动应答并且消费成功了。 如果有异常不会自动应答,并且会重发6次。Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);

    吞吐量:联想到机场吞吐量,表示的是一定时间飞机的起降架次和旅客的运输数量。在系统就表示一定时间内请求获得响应的数量,反应的是系统的处理性能。

    展开全文
  • 实时性的数据,一般业务管理数据都是基本上不发生变化的,而发生随时不停发生变化的数据我们将之称之为实时性高的数据叫实时数据。实时数据很难保证在不同数据源下的一致性,除非查看的是某一时刻的数据快照(历史...

    目录

    预设场景

    问题分析

    流程设计

    实践验证

    问题结论


    实时性的数据,一般业务管理数据都是基本上不发生变化的,而发生随时不停发生变化的数据我们将之称之为实时性高的数据叫实时数据。实时数据很难保证在不同数据源下的一致性,除非查看的是某一时刻的数据快照(历史快照),否则很难保持不同数据源数据之间没有差异。所以,从实践中得出的结论是:异构多数据源保证实时数据一致性是一个伪命题,缓存的使用具有不可逆的特性,大多数情况下缓存不能当作真实数据源。

    预设场景

    欲实现移动App人员位置管理,要求:

    1、展示用户总数和在线数量,MQ数据交互到REDIS。

    2、保留用户在线情况,MQ数据同步到DB保留在线、离线和位置信息。

    3、验证两边的在线数量是否能保持一致。

    问题分析

    1、从MQ同步数据到REDIS管理用户在线状态数据,网络状态未知的情况下,用户频繁上线、离线。

    • a.用户REDIS高效缓存位置数据
    • b.存在网络抖动(不确定性因素)

    2、从MQ同步数据到DB。

    • a.MQ做了二次消费,无论是先放redis还是先放DB都会造成数据延时
    • b.DB和REDIS不能放在同一个事务进行管理
    • c.DB读写和REDIS读写存在效率上的差距

    3、推测结论:MQ二次消费到不同数据源不能保证数据实时一致性,既要实时性又要准确性只能使用单一数据源。

    流程设计

    下面是一幅App心跳上传的位置分发到RabbitMQ进行位置管理的服务,位置保存在REDIS中,DB是PG(Postgresql)。

    • MQ分发逻辑:在OnlineMQ、KeepLiveMQ和OfflineMQ进行消费的时候加了二级队列进行处理,RabbitMQ是异步执行消费。
    • 在二级队列:Java程序并发队列批量处理用户状态位置数据,线程批量处理,是为了提升MQ本身消费的效率问题。
    • 数据维护:Quality Service 和网格聚合都是为了维护用户在线时间过期的辅助服务。
    • 用户30分钟内无位置和心跳上来即离线。
    • 在线有心跳但没有位置的系统进行保活。
    • 用户有心跳有位置的为在线。
    • 真实批量处理线程消费必须要有休眠时间,防止空转调度CPU,这里设置的是50ms(无论设多小都是一个时间差)。
    • 在正常情况下,离线、上线、保活队列数据应该是互斥的。

    实践验证

    redis统计结果

    pg统计结果

     

    问题结论

    • 异步的操作实时性不可控。
    • 多个数据源非主从和集群模式要同步实时数据结果是不可信的。
    • 缓存的主要功能是辅助数据库数据服务而非反过来使用。
    • 异构数据库数据同步实时数据一致性性没法保证。

    另一个不容忽视的问题就是在取redis实时位置数据的时候尽量把scores作为过滤条件,这样取出来的数据用户有效数据才是比较准确的,可参考如下代码:

      /**
         * 根据组织机构ID查询REDIS【用户在线汇总总数】
         *
         * @param orgId
         * @return
         */
        public Long getOrgOnlineUserFromRedis(String orgId) {
            long now = System.currentTimeMillis();
            long minScores = now - Constants.MOBILE_POSITION_TIME_OUT.longValue() * 1000;
            long maxScores = now + Constants.MOBILE_POSITION_TIME_OUT.longValue() * 1000;
            if (("" + Constants.DB_ORG_ROOT_ID).equals(orgId)) {
                String key = new StringBuffer(Constants.MOBILE_POSITION_ZSET_QG_KEY).toString();
                //return redisTemplate.opsForZSet().zCard(key);// 总数
                return redisTemplate.opsForZSet().count(key, minScores, maxScores); // 得分条件汇总
            } else {
                String key = new StringBuffer(Constants.MOBILE_POSITION_ZSET_DW_INCLUDE_CHILDREN_ORG_KEY).append(orgId).toString();
                // return redisTemplate.opsForZSet().zCard(key);// 总数
                return redisTemplate.opsForZSet().count(key, minScores, maxScores);// 得分条件汇总
            }
        }

     

    展开全文
  • 关于mq重复数据问题

    2019-03-12 16:46:55
    mq都会有重复消费数据的可能,需要自己保持幂等性 (1)比如你拿个数据要写库,你先根据主键查一下,如果这数据都有了,你就别插入了,update一下好吧 (2)比如你是写redis,那没问题了,反正每次都是set,天然幂...
  • 本文将描述如何使用数据处理程序基于MQ标头更改转换逻辑,同时确保处理程序保持协议独立性。涵盖的主题包括:  数据处理程序的解释  从数据处理程序访问MQ标头  基于标头改变数据处理程序的行为  确保...
  • MQ

    千次阅读 2016-06-24 20:41:16
  • MQ消息数据同步解决方案

    千次阅读 2019-12-10 23:45:35
    首先配置MQ消息 消息通过之后 进行消息设计 1.接受消息之后首先要做的是消息落地,将消息数据存入数据库 2.进行业务逻辑处理 3.因为版本发布或者其他异常中断,需要对消息进行补偿 4.消息补偿需要根据业务需要...
  • CHMPX-一致的散列Mq处理数据交换 概述 MQMP具有一致的哈希系统,CHMPX是进程内数据交换,而Yahoo!则为客户端提供库。 日本。 CHMPX的目的是构建原始消息传递系统和提供客户端库。 CHMPX在客户端和服务器/从服务器...
  • RPC,MQ,数据同步

    千次阅读 2017-08-15 11:09:20
    RPC,MQ,数据同步三大基础组件服务使用说明 转至元数据结尾 Created by 李江, last modified on 五月 22, 2015 转至元数据起始 概述 这个文档的目的是想更清楚的展示RPC...
  • MQ消息队列详解、四大MQ的优缺点分析

    万次阅读 多人点赞 2020-03-07 16:05:28
    MQ消息队列详解 近期有了想跳槽的打算,所以自己想巩固一下自己的技术,想了解一些面试比较容易加分的项,近期准备深入研究一下redis和mq这两样,这总体上都是为了解决服务器并发的原因,刚翻到了一篇有关于mq的,...
  • MQ消息处理感悟

    2015-08-02 10:40:58
    MQ消息处理感悟项目需要获取MQ消息,之后用xml工具进行解析,再把解析后的数据插入数据库。本来几天做完的项目,期间遇到了各种坑,拖了一个多星期才预发布。 遇到的第一个坑就是收不到MQ消息,后来又只能能收到队列...
  • Mq处理业务逻辑

    2021-09-08 17:25:53
    先向数据库中插入一条会员数据,让后再向MQ中投递一个消息,MQ服务器端在将消息推送给消费者异步解耦处理发送短信和优惠券。
  • MQ的性能测试数据

    2017-04-20 09:29:00
  • 这个是肯定的,用mq有个基本原则,就是数据不能多一条,也不能少一条,不能多,就是刚才说的重复消费和幂等性问题。不能少,就是说这数据别搞丢了。那这个问题你必须得考虑一下。 如果说你这个是用mq来传递非常核心...
  • 1、数据丢失的原因及解决办法 2、针对丢失原因1的解决方式有两种 2.1一种是用MQ的事务,但是有个缺点,是阻塞的,影响性能 try { channel.txSelect(); // 声明事务 // 发送消息 channel.basicPublish("", ...
  • MQ消息太快导致的异步数据查询问题

    千次阅读 2017-10-12 10:38:26
    先说问题:系统用到mq发送消息,实际运行时发现mq的接收端程序在接收到消息之后,去查询业务数据的状态时发现仍然是老的状态,导致程序处理数据异常;手动去数据查询时发现是新的状态。 经分析,应该是mqserver和...
  • 比如我们将DB里面的数据持久化到REDIS里面去,就是一种数据异构的方式。如果要下个定义的话:把数据按需(数据结构、存取方式、存取形式)异地构建存储。 2、常见应用场景 分库分表中有一个最为常见的场景,为了...
  • mq处理消息丢失

    2017-07-06 10:33:00
    1、客户端丢失 可以使用mq消息确认机制 2、服务端丢失 可以使用mq持久化机制 转载于:https://www.cnblogs.com/hy87/p/7125037.html
  • 背景在数据中台建设过程中,一个典型的数据集成场景是将 MQ (Message Queue,例如 Kafka、RocketMQ 等)的数据导入到 Hive 中,以供下游数仓建设以及指标统计...
  • MQ概念

    2016-12-07 21:02:48
    MQ中,我们把应用程序交由MQ传输的数据定义为消息,我们可以定义消息的内容并对消息进行广义的理解,比如:用户的各种类型的数据文件,某个应用向其它应用发出的处理请求等都可以作为消息。消息有两部分组成:  ...
  • 最近做了个项目,碰到一个问题,目前已经解决,解决过程共享...方案1:打标,就是在生产消息的时候把最后一条数据打标,从而在消费的时候能知道哪一条数最后一条数据,当执行完该条数据时,就可以进行数据落地操作,但
  • 数据异构的武器 - BINLOG+MQ 1、定义 何谓数据异构,上周交易部门商品的同事过来做分享,又看到这个词,他的PPT里面是 数据库异构。其实我们以前做的事情,也是可以成为数据异构。比如我们将DB里面的数据...
  • MQ概述

    2021-03-04 14:01:41
    消息队列的好处? 解耦、异步、削峰 不用MQ的系统耦合场景 ...通过一个MQ,发布和订阅消息的这么一个模型,Pub/Sub模型,需要发送数据的模块就和其他的模块彻底解耦 不用MQ的同步高延迟场景 使用MQ
  • MQ 理论

    2019-06-15 15:03:53
    今天带大家简单的了解一下MQ(消息队列 Message Queue)的简单理论知识。 什么是MQ 消息队列(Message Queue,简称MQ),从字面意思上看,本质是个队列,FIFO先入先出,只不过队列中存放的内容是message而已。 其...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 66,811
精华内容 26,724
关键字:

mq数据排序