四种消息队列,如何选型
这篇文章,主要讲述 Kafka、RabbitMQ、RocketMQ 和 ActiveMQ 这 4 种消息队列的异同,无论是面试,还是用于技术选型,都有非常强的参考价值。
01 消息队列基础
1.1 什么是消息队列?
消息队列是在消息的传输过程中保存消息的容器,用于接收消息并以文件的方式存储,一个消息队列可以被一个也可以被多个消费者消费,包含以下 3 元素:
-
Producer:消息生产者,负责产生和发送消息到 Broker;
-
Broker:消息处理中心,负责消息存储、确认、重试等,一般其中会包含多个 Queue;
-
Consumer:消息消费者,负责从 Broker 中获取消息,并进行相应处理。
1.2 消息队列模式
-
点对点模式:多个生产者可以向同一个消息队列发送消息,一个具体的消息只能由一个消费者消费。
-
发布/订阅模式:单个消息可以被多个订阅者并发的获取和处理。
1.3 消息队列应用场景
-
应用解耦:消息队列减少了服务之间的耦合性,不同的服务可以通过消息队列进行通信,而不用关心彼此的实现细节。
-
异步处理:消息队列本身是异步的,它允许接收者在消息发送很长时间后再取回消息。
-
流量削锋:当上下游系统处理能力存在差距的时候,利用消息队列做一个通用的”载体”,在下游有能力处理的时候,再进行分发与处理。
-
日志处理:日志处理是指将消息队列用在日志处理中,比如 Kafka 的应用,解决大量日志传输的问题。
-
消息通讯:消息队列一般都内置了高效的通信机制,因此也可以用在纯的消息通讯,比如实现点对点消息队列,或者聊天室等。
-
消息广播:如果没有消息队列,每当一个新的业务方接入,我们都要接入一次新接口。有了消息队列,我们只需要关心消息是否送达了队列,至于谁希望订阅,是下游的事情,无疑极大地减少了开发和联调的工作量。
02 常用消息队列
由于官方社区现在对 ActiveMQ 5.x 维护越来越少,较少在大规模吞吐的场景中使用,所以我们主要讲解 Kafka、RabbitMQ 和 RocketMQ。
2.1 Kafka
Apache Kafka 最初由 LinkedIn 公司基于独特的设计实现为一个分布式的提交日志系统,之后成为 Apache 项目的一部分,号称大数据的杀手锏,在数据采集、传输、存储的过程中发挥着举足轻重的作用。
它是一个分布式的,支持多分区、多副本,基于 Zookeeper 的分布式消息流平台,它同时也是一款开源的基于发布订阅模式的消息引擎系统。
重要概念
-
主题(Topic):消息的种类称为主题,可以说一个主题代表了一类消息,相当于是对消息进行分类,主题就像是数据库中的表。
-
分区(partition):主题可以被分为若干个分区,同一个主题中的分区可以不在一个机器上,有可能会部署在多个机器上,由此来实现 kafka 的伸缩性。
-
批次:为了提高效率, 消息会分批次写入 Kafka,批次就代指的是一组消息。
-
消费者群组(Consumer Group):消费者群组指的就是由一个或多个消费者组成的群体。
-
Broker: 一个独立的 Kafka 服务器就被称为 broker,broker 接收来自生产者的消息,为消息设置偏移量,并提交消息到磁盘保存。
-
Broker 集群:broker 集群由一个或多个 broker 组成。
-
重平衡(Rebalance):消费者组内某个消费者实例挂掉后,其他消费者实例自动重新分配订阅主题分区的过程。
Kafka 架构
一个典型的 Kafka 集群中包含 Producer、broker、Consumer Group、Zookeeper 集群。
Kafka 通过 Zookeeper 管理集群配置,选举 leader,以及在 Consumer Group 发生变化时进行 rebalance。Producer 使用 push 模式将消息发布到 broker,Consumer 使用 pull 模式从 broker 订阅并消费消息。
Kafka 工作原理
消息经过序列化后,通过不同的分区策略,找到对应的分区。
相同主题和分区的消息,会被存放在同一个批次里,然后由一个独立的线程负责把它们发到 Kafka Broker 上。
分区的策略包括顺序轮询、随机轮询和 key hash 这 3 种方式,那什么是分区呢?
分区是 Kafka 读写数据的最小粒度,比如主题 A 有 15 条消息,有 5 个分区,如果采用顺序轮询的方式,15 条消息会顺序分配给这 5 个分区,后续消费的时候,也是按照分区粒度消费。
由于分区可以部署在多个不同的机器上,所以可以通过分区实现 Kafka 的伸缩性,比如主题 A 的 5 个分区,分别部署在 5 台机器上,如果下线一台,分区就变为 4。
Kafka 消费是通过消费群组完成,同一个消费者群组,一个消费者可以消费多个分区,但是一个分区,只能被一个消费者消费。
如果消费者增加,会触发 Rebalance,也就是分区和消费者需要重新配对。
不同的消费群组互不干涉,比如下图的 2 个消费群组,可以分别消费这 4 个分区的消息,互不影响。
2.2 RocketMQ
RocketMQ 是阿里开源的消息中间件,它是纯 Java 开发,具有高性能、高可靠、高实时、适合大规模分布式系统应用的特点。
RocketMQ 思路起源于 Kafka,但并不是 Kafka 的一个 Copy,它对消息的可靠传输及事务性做了优化,目前在阿里集团被广泛应用于交易、充值、流计算、消息推送、日志流式处理、binglog 分发等场景。
重要概念
-
Name 服务器(NameServer):充当注册中心,类似 Kafka 中的 Zookeeper。
-
Broker: 一个独立的 RocketMQ 服务器就被称为 broker,broker 接收来自生产者的消息,为消息设置偏移量。
-
主题(Topic):消息的第一级类型,一条消息必须有一个 Topic。
-
子主题(Tag):消息的第二级类型,同一业务模块不同目的的消息就可以用相同 Topic 和不同的 Tag 来标识。
-
分组(Group):一个组可以订阅多个 Topic,包括生产者组(Producer Group)和消费者组(Consumer Group)。
-
队列(Queue):可以类比 Kafka 的分区 Partition。
RocketMQ 工作原理
RockerMQ 中的消息模型就是按照主题模型所实现的,包括 Producer Group、Topic、Consumer Group 三个角色。
为了提高并发能力,一个 Topic 包含多个 Queue,生产者组根据主题将消息放入对应的 Topic,下图是采用轮询的方式找到里面的 Queue。
RockerMQ 中的消费群组和 Queue,可以类比 Kafka 中的消费群组和 Partition:不同的消费者组互不干扰,一个 Queue 只能被一个消费者消费,一个消费者可以消费多个 Queue。
消费 Queue 的过程中,通过偏移量记录消费的位置。
RocketMQ 架构
RocketMQ 技术架构中有四大角色 NameServer、Broker、Producer 和 Consumer,下面主要介绍 Broker。
Broker 用于存放 Queue,一个 Broker 可以配置多个 Topic,一个 Topic 中存在多个 Queue。
如果某个 Topic 消息量很大,应该给它多配置几个 Queue,并且尽量多分布在不同 broker 上,以减轻某个 broker 的压力。Topic 消息量都比较均匀的情况下,如果某个 broker 上的队列越多,则该 broker 压力越大。
简单提一下,Broker 通过集群部署,并且提供了 master/slave 的结构,salve 定时从 master 同步数据(同步刷盘或者异步刷盘),如果 master 宕机,则 slave 提供消费服务,但是不能写入消息。
看到这里,大家应该可以发现,RocketMQ 的设计和 Kafka 真的很像!
2.3 RabbitMQ
RabbitMQ 2007 年发布,是使用 Erlang 语言开发的开源消息队列系统,基于 AMQP 协议来实现。
AMQP 的主要特征是面向消息、队列、路由、可靠性、安全。AMQP 协议更多用在企业系统内,对数据一致性、稳定性和可靠性要求很高的场景,对性能和吞吐量的要求还在其次。
重要概念
-
信道(Channel):消息读写等操作在信道中进行,客户端可以建立多个信道,每个信道代表一个会话任务。
-
交换器(Exchange):接收消息,按照路由规则将消息路由到一个或者多个队列;如果路由不到,或者返回给生产者,或者直接丢弃。
-
路由键(RoutingKey):生产者将消息发送给交换器的时候,会发送一个 RoutingKey,用来指定路由规则,这样交换器就知道把消息发送到哪个队列。
-
绑定(Binding):交换器和消息队列之间的虚拟连接,绑定中可以包含一个或者多个 RoutingKey。
RabbitMQ 工作原理
AMQP 协议模型由三部分组成:生产者、消费者和服务端,执行流程如下:
-
生产者是连接到 Server,建立一个连接,开启一个信道。
-
生产者声明交换器和队列,设置相关属性,并通过路由键将交换器和队列进行绑定。
-
消费者也需要进行建立连接,开启信道等操作,便于接收消息。
-
生产者发送消息,发送到服务端中的虚拟主机。
-
虚拟主机中的交换器根据路由键选择路由规则,发送到不同的消息队列中。
-
订阅了消息队列的消费者就可以获取到消息,进行消费。
常用交换器
RabbitMQ 常用的交换器类型有 direct、topic、fanout、headers 四种,具体的使用方法,可以参考官网:
官网入口:https://www.rabbitmq.com/getstarted.html
03 消息队列对比
3.1 Kafka
优点:
-
高吞吐、低延迟:Kafka 最大的特点就是收发消息非常快,Kafka 每秒可以处理几十万条消息,它的最低延迟只有几毫秒;
-
高伸缩性:每个主题(topic)包含多个分区(partition),主题中的分区可以分布在不同的主机(broker)中;
-
高稳定性:Kafka 是分布式的,一个数据多个副本,某个节点宕机,Kafka 集群能够正常工作;
-
持久性、可靠性、可回溯:Kafka 能够允许数据的持久化存储,消息被持久化到磁盘,并支持数据备份防止数据丢失,支持消息回溯;
-
消息有序:通过控制能够保证所有消息被消费且仅被消费一次;
-
有优秀的第三方 Kafka Web 管理界面 Kafka-Manager,在日志领域比较成熟,被多家公司和多个开源项目使用。
缺点:
-
Kafka 单机超过 64 个队列/分区,Load 会发生明显的飙高现象,队列越多,load 越高,发送消息响应时间变长;
-
不支持消息路由,不支持延迟发送,不支持消息重试;
-
社区更新较慢。
3.2 RocketMQ
优点:
-
高吞吐:借鉴 Kafka 的设计,单一队列百万消息的堆积能力;
-
高伸缩性:灵活的分布式横向扩展部署架构,整体架构其实和 kafka 很像;
-
高容错性:通过ACK机制,保证消息一定能正常消费;
-
持久化、可回溯:消息可以持久化到磁盘中,支持消息回溯;
-
消息有序:在一个队列中可靠的先进先出(FIFO)和严格的顺序传递;
-
支持发布/订阅和点对点消息模型,支持拉、推两种消息模式;
-
提供 docker 镜像用于隔离测试和云集群部署,提供配置、指标和监控等功能丰富的 Dashboard。
缺点:
-
不支持消息路由,支持的客户端语言不多,目前是 java 及 c++,其中 c++ 不成熟;
-
部分支持消息有序:需要将同一类的消息 hash 到同一个队列 Queue 中,才能支持消息的顺序,如果同一类消息散落到不同的 Queue中,就不能支持消息的顺序。
-
社区活跃度一般。
3.3 RabbitMQ
优点:
-
支持几乎所有最受欢迎的编程语言:Java,C,C ++,C#,Ruby,Perl,Python,PHP等等;
-
支持消息路由:RabbitMQ 可以通过不同的交换器支持不同种类的消息路由;
-
消息时序:通过延时队列,可以指定消息的延时时间,过期时间TTL等;
-
支持容错处理:通过交付重试和死信交换器(DLX)来处理消息处理故障;
-
提供了一个易用的用户界面,使得用户可以监控和管理消息 Broker;
-
社区活跃度高。
缺点:
-
Erlang 开发,很难去看懂源码,不利于做二次开发和维护,基本职能依赖于开源社区的快速维护和修复 bug;
-
RabbitMQ 吞吐量会低一些,这是因为他做的实现机制比较重;
-
不支持消息有序、持久化不好、不支持消息回溯、伸缩性一般。
04 消息队列选型
Kafka:追求高吞吐量,一开始的目的就是用于日志收集和传输,适合产生大量数据的互联网服务的数据收集业务,大型公司建议可以选用,如果有日志采集功能,肯定是首选 kafka。
RocketMQ:天生为金融互联网领域而生,对于可靠性要求很高的场景,尤其是电商里面的订单扣款,以及业务削峰,在大量交易涌入时,后端可能无法及时处理的情况。RoketMQ 在稳定性上可能更值得信赖,这些业务场景在阿里双 11 已经经历了多次考验,如果你的业务有上述并发场景,建议可以选择 RocketMQ。
RabbitMQ:结合 erlang 语言本身的并发优势,性能较好,社区活跃度也比较高,但是不利于做二次开发和维护,不过 RabbitMQ 的社区十分活跃,可以解决开发过程中遇到的 bug。如果你的数据量没有那么大,小公司优先选择功能比较完备的 RabbitMQ。
ActiveMQ:官方社区现在对 ActiveMQ 5.x 维护越来越少,较少在大规模吞吐的场景中使用。
今天就聊到这里,我们下一篇见~
相关文章:
四种消息队列,如何选型
这篇文章,主要讲述 Kafka、RabbitMQ、RocketMQ 和 ActiveMQ 这 4 种消息队列的异同,无论是面试,还是用于技术选型,都有非常强的参考价值。 01 消息队列基础 1.1 什么是消息队列? 消息队列是在消息的传输过程中保存消…...
flutter开发windows应用的库
一、window_manager 这个插件允许 Flutter 桌面应用调整窗口的大小和位置 地址:https://github.com/leanflutter/window_manager二、win32 一个包,它使用FFI包装了一些最常见的Win32 API调用,使Dart代码可以访问这些调用,而不需…...
机器学习--线性回归
目录 监督学习算法 线性回归 损失函数 梯度下降 目标函数 更新参数 批量梯度下降 随机梯度下降 小批量梯度下降法 数据预处理 特征标准化 正弦函数特征 多项式特征的函数 数据预处理步骤 线性回归代码实现 初始化步骤 实现梯度下降优化模块 损失与预测模块 …...
【Spring Boot】面试题汇总,带答案的那种
继上次的文章【MySQL连环炮,你抗的住嘛?】爆火之后,越来越多的小伙伴后台留言,要求阿Q总结下其他的“连环炮”知识点,想在金九银十的面试黄金期轻松对线面试官。 同样为了节省大家的时间,阿Q最近对【Sprin…...
【大模型】快速体验百度智能云千帆AppBuilder搭建知识库与小助手
文章目录 前言千帆AppBuilder什么是千帆AppBuilderAppBuilder能做什么 体验千帆AppBuilderJava知识库高考作文小助手 总结 前言 前天,在【百度智能云智算大会】上,百度智能云千帆AppBuilder正式开放服务。这是一个AI原生应用开发工作台,可以…...
字符串压缩
...
MsSQL中的索引到底长啥样,查找过程怎么进行
参考文章一 参考文章二 建表 mysql> create table user(-> id int(10) auto_increment,-> name varchar(30),-> age tinyint(4),-> primary key (id),-> index idx_age (age)-> )engineinnodb charsetutf8mb4;insert into user(name,age) values(张三,…...
WPF 全局异常处理
在Application中存在三种异常事件EventHandler DispatcherUnhandledExceptionAppDomain.CurrentDomain.UnhandledExceptionTaskScheduler.UnobservedTaskException 其中 DispatcherUnhandledException 是在异常由应用程序引发但未进行处理时发生,但无法捕获多线程…...
Flink系列之:Elasticsearch SQL 连接器
Flink系列之:Elasticsearch SQL 连接器 一、Elasticsearch SQL 连接器二、创建 Elasticsearch表三、连接器参数四、Key 处理五、动态索引六、数据类型映射 一、Elasticsearch SQL 连接器 Sink: BatchSink: Streaming Append & Upsert ModeElasticsearch 连接器…...
java中将Map集合、对象、字符串转换为JSON对象
1、Map集合转JSON对象 创建一个Map集合; 新建json对象,并将Map引入json中。 public void demo1(){ //创建一个Map集合Map<String, String> map new HashMap<>();map.put("1729210001","zhangsan");map.put("17292…...
理解Spring中bean的作用域
singleton:Spring Ioc容器中只会存在一个共享的Bean实例,无论有多少个Bean引用它,始终指向同一个对象,作用域为Spring中的缺省(同一package)作用域 prototype:每次通过Spring容器获取prototype定义的bean时,…...
edge中以右键“打印”的方式“保存”当前页面的pdf形式,下载过程中卡进度的问题
目录 问题描述: 可能的问题: 解决: 问题描述: 特殊情况下需要保存网页的pdf形式,但页面没有类似“导出pdf”的功能按钮,可以通过页面右键“打印”的方式“保存”当前页面的pdf形式。在pdf文件下载过程中出…...
c# 使用OpenCV
C#和OpenCV的结合主要通过一个名为OpenCVSharp的库实现。OpenCVSharp是一个C#包装器,它提供了对OpenCV(一个开源的计算机视觉和机器学习库)功能的访问。 安装OpenCVSharp NuGet包: 在Visual Studio中,右键点击你的项目…...
数据库连接问题 - ChatGPT对自身的定位
1.一段关于数据库连接的技术性对话 sweetie,连接数据库的时候,需要在每次读写数据后就把连接释放吗? 亲爱的,连接数据库后,通常会在每次读写数据后将连接释放。这是为了确保数据库连接的及时释放和有效管理。如果不及…...
常见可视化大屏编辑器有哪些?
前言: 在当今数字化时代,可视化大屏编辑器成为了数据展示和决策支持的重要工具。大屏编辑器不仅仅是数据的呈现,更是数据背后的故事的讲述者。它通过图表、图形和实时数据的呈现,为用户提供了全面的信息视图,帮助用户更…...
利用ffmpeg cv2取h265码流视频(转换图片灰屏问题解决)
利用海康威视相机拍出来的视频是H265格式的,相比于常规的H264编码,压缩率更高,但因此如果直接用正常取流方法读取,会出现无法读取的情况 1. 如图h265码流取出图片为灰屏 2 、解决灰屏问题 import subprocess import cv2# 将h265流…...
Android Uri scheme协议file转content
一、Uri的介绍 在Android开发中,Uri(Uniform Resource Identifier)是用于标识和访问各种资源的核心概念。这些资源可能包括文件、网络URL、数据库记录等。在处理这些资源时,我们可能会遇到不同的Uri协议,如file和conte…...
【Jenkins】远程API接口:Java 包装接口使用示例
jenkins-rest 库是一个面向对象的 Java 项目,它通过编程方式提供对 Jenkins REST API 的访问,以访问 Jenkins 提供的一些远程 API。它使用 jclouds 工具包构建,可以轻松扩展以支持更多 REST 端点。其功能集不断发展,用户可以通过拉…...
未能加载工具箱项问题的解决
解决办法是项目属性要设置成any cpu 在解决方案里的所有项目上右键,属性,生成,看目标平台是不是都设置成了any cpu...
算法模板之栈图文详解
🌈个人主页:聆风吟 🔥系列专栏:算法模板、数据结构 🔖少年有梦不应止于心动,更要付诸行动。 文章目录 📋前言一. ⛳️模拟栈1.1 🔔用数组模拟实现栈1.1.1 👻栈的定义1.1.…...
Ajax Search Pro Live WordPress网站内容实时搜索插件
点击阅读Ajax Search Pro Live WordPress网站内容实时搜索插件原文 Ajax Search Pro Live WordPress网站内容实时搜索插件是 WordPress 最好的实时搜索引擎插件。高度可定制,具有许多功能和选项,可提供最佳结果!用更美观、更高效的搜索引擎替…...
mysql SQL执行超时问题
show variables like max_execution_time 使用这个命令查看了,没有设置sql执行超时时间,那么大概率问题就出在阿里的Druid数据库连接池出了问题 尝试着socketTimeout由60000毫秒改成10000毫秒,果然执行了十几秒就超时报错了 socketTime…...
51单片机基于时间片轮转的简单rtos
早就想写写这个了,正好赶上有点时间,写了一下基于51单片机的时间片轮转调度系统,简单的rtos,呵呵。直接上代码。 //基于51单片机时间片轮转的简单rtos。 #include"reg52.h" sbit led1 P2^7; sbit led2 P2^0; sbit key…...
python pycurl 安装使用
python pycurl 安装使用 本文主要讲下pycurl 安装使用. 1.安装 首先使用 pip 命令安装. pip install pycurl 输出如下: Collecting pycurlUsing cached pycurl-7.45.2.tar.gz (234 kB)ERROR: Command errored out with exit status 1:command: /usr/bin/python3 -c impor…...
C语言数据结构-排序
文章目录 1 排序的概念及运用1.1 排序的概念1.2 排序的应用 2 插入排序2.1 直接插入排序2.2 希尔排序2.3 直接排序和希尔排序对比 3 选择排序3.1 堆排序3.2 直接选择排序 4 交换排序4.1 冒泡排序4.2 快速排序4.2.1 挖坑法14.2.2 挖坑法24.2.3 挖坑法3 5 并归排序6 十万级别数据…...
Spring AOP入门指南:轻松掌握面向切面编程的基础知识
面向切面编程 1,AOP简介1.1 什么是AOP?1.2 AOP作用1.3 AOP核心概念 2,AOP入门案例2.1 需求分析2.2 思路分析2.3 环境准备2.4 AOP实现步骤步骤1:添加依赖步骤2:定义接口与实现类步骤3:定义通知类和通知步骤4:定义切入点步骤5:制作切面步骤6:将通知类配给…...
【顶级快刊】IEEE(Trans),审稿快仅2个月录用,入选CCF-B,现在投最快!
计算机类 • 好刊解读 今天小编带来IEEE旗下计算机领域顶刊,顶级快刊,CCF-B类推荐,如您有投稿需求,可作为重点关注!后文有相关领域真实发表案例,供您投稿参考~ 01 期刊简介 IEEE Transactions on Affect…...
深入浅出堆排序: 高效算法背后的原理与性能
🎬 鸽芷咕:个人主页 🔥 个人专栏: 《linux深造日志》 《高效算法》 ⛺️生活的理想,就是为了理想的生活! 📋 前言 🌈堆排序一个基于二叉堆数据结构的排序算法,其稳定性和排序效率在八大排序中也…...
Golang实践录:gin绑定解析json的两种方法
本文介绍 Golang 的 gin 框架接收json数据并解析的2种方法。 起因及排查 某微服务工程,最近测试发现请求超时,由于特殊原因超时较短,如果请求处理耗时超过1秒则认为失败。排查发现,可能是gin接收解析json数据存在耗时,…...
Hypervisor Display架构
Hypervisor Display架构部分 1,所有LA侧的APP与显示相关的调用最终都会交由SurfaceFlinger处理 2,SurfaceFlinger会最终调用android.hardware.graphics.composer2.4-service服务 3,android.hardware.graphics.composer2.4-service服务会调用G…...
建设电商网站/培训机构不退费最有效方式
linux shell命令下我们可以通过相关命令关闭和重启计算机,下面由学习啦小编为大家搜集整理了linux shell的关机命令是什么的相关知识,希望对大家有帮助!linux shell的关机命令问题描述对于Linux系统而言,许多时候是用于服务器之类的ÿ…...
阿里云备案成功怎么建设网站/seo推广优化平台
转载于:https://www.cnblogs.com/ycxyyzw/archive/2012/07/04/2576148.html...
网站建设 石景山/大数据分析培训机构
nginx的location配置 使用的版本是nginx1.18.0。 nginx各个版本差别不大,可以通用。 简介 nginx的location配置是为了让不同的url访问指向不同的资源文件位置,例如下面的配置: server {listen 8080;server_name localhost;#chars…...
做美国市场哪个网站好/百度影音在线电影
【问题】 在进入docker镜像后,我们一般缺少vim,需要安装,但是在更新的过程中往往会卡在working 的进度为0上。 【解决方法】 mv /etc/apt/sources.list /etc/apt/sources.list.bak echo "deb http://mirrors.163.com/debian/ jessie …...
深圳网站建设10086/qq群引流推广平台免费
我们踩着的只是两个脚印,我们看到的只是四角的天空。究竟是什么决定了我们能不能找到工作,找到什么样的工作。以下引用的文献,皆来自《社会学与中国社会》中的收录。这些被收录在这里的文献,好像是作者专门为收集到此书时加工的&a…...
广州自助企业建站模板/免费制作网站平台
GCD里就有三种queue(分派队列)来处理. 1. Main queue:(主队列) 顾名思义,运行在主线程,由dispatch_get_main_queue获得.和ui相关的就要使用Main Queue. dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ // 耗时的操作 dispatch_…...