当前位置: 首页 > news >正文

RabbitMQ八股文

RabbitMQ 核心概念与组件

1. RabbitMQ 核心组件及其作用

1.1 生产者(Producer)

  • 作用:创建并发送消息到交换机。
  • 特点:不直接将消息发送到队列,而是通过交换机路由。

1.2 交换机(Exchange)

  • 作用:接收生产者发送的消息,并根据其类型和绑定规则,将消息路由到一个或多个队列。
  • 关键作用:解耦生产者和消费者,实现灵活的消息路由。

1.3 队列(Queue)

  • 作用:消息的存储容器,消费者从队列中获取消息。
  • 特性
    • 支持持久化(durable)和临时存储(auto-delete)。
    • 具有先进先出(FIFO)特性。

1.4 绑定(Binding)

  • 作用:定义交换机和队列之间的路由规则。
  • 示例:在Topic交换机中,绑定通过通配符(如*.order)确定哪些消息应路由到队列。

1.5 消费者(Consumer)

  • 作用:从队列中拉取消息并进行处理。
  • 特点:可以手动确认(ACK)消息是否处理成功,确保可靠性。

1.6 信道(Channel)

  • 作用:复用TCP连接的轻量级虚拟连接,用于减少资源开销。
  • 特点:生产者和消费者通过信道与RabbitMQ通信。

1.7 虚拟主机(Virtual Host)

  • 作用:逻辑隔离单元,类似于命名空间。
  • 特点:不同虚拟主机的交换机、队列等资源相互隔离。

2. 交换机(Exchange)的类型及其路由规则

2.1 直连交换机(Direct Exchange)

  • 路由规则:精确匹配Routing Key。
  • 示例:生产者发送消息时指定Routing Key=payments,队列绑定到交换机时设置Binding Key=payments,则消息仅路由到该队列。
  • 适用场景:点对点通信(如订单支付通知)。

2.2 扇出交换机(Fanout Exchange)

  • 路由规则:忽略Routing Key,将消息广播到所有绑定的队列。
  • 示例:日志系统需要将同一日志消息发送到存储队列、分析队列和报警队列。
  • 适用场景:发布-订阅模式(如新闻推送)。

2.3 主题交换机(Topic Exchange)

  • 路由规则:通过通配符匹配Routing Key,支持多级模糊匹配。
    • *:匹配一个单词(如user.*匹配user.create但不匹配user.create.order)。
    • #:匹配零或多个单词(如order.#匹配orderorder.paid等)。
  • 示例:绑定规则为order.*的队列会接收Routing Key=order.createorder.cancel的消息。
  • 适用场景:按规则分发消息(如分类事件处理)。

2.4 头交换机(Headers Exchange)

  • 路由规则:基于消息头(Headers)而非Routing Key匹配,通过x-match参数指定匹配条件(all需所有头匹配,any只需部分匹配)。
  • 示例:消息头包含type=reportformat=pdf,队列绑定条件为x-match=all且头信息相同。
  • 适用场景:复杂条件路由(如多维度过滤消息)。

3. Binding Key 和 Routing Key 的协作方式

3.1 Routing Key

  • 定义:由生产者在发送消息时指定,用于标识消息的目的地。
  • 示例:发送订单消息时可能设置Routing Key=order.create

3.2 Binding Key

  • 定义:在队列绑定到交换机时定义,用于告诉交换机哪些消息应路由到该队列。
  • 示例:队列绑定到Topic交换机时设置Binding Key=order.*

3.3 协作逻辑

  • Direct交换机:Routing Key必须与Binding Key完全一致。
  • Topic交换机:Routing Key需符合Binding Key的通配符模式。
  • Fanout/Headers交换机:忽略Routing Key,仅通过广播或头信息匹配。

4. RabbitMQ 基于 AMQP 协议的原因及 AMQP 核心模型

4.1 为什么选择 AMQP 协议?

  • 标准化:AMQP是开放标准的应用层协议,确保不同系统间的互操作性。
  • 可靠性:支持消息确认、持久化、事务等机制,适合企业级应用。
  • 灵活性:通过交换机、队列、绑定等组件实现复杂路由逻辑。

4.2 AMQP 的核心模型

  • 生产者(Publisher):发送消息到交换机。
  • 交换机(Exchange):根据规则路由消息。
  • 队列(Queue):存储消息直至被消费。
  • 消费者(Consumer):从队列获取消息。
  • 绑定(Binding):定义交换机和队列的关系。
  • 消息属性:包括Routing Key、Headers、持久化标志等。
  • 信道(Channel):复用连接的轻量级通信单元。

5. 消息可靠性保障

5.1 如何保证消息从生产者到消费者全程不丢失?

5.1.1 生产者到交换机的可靠性
  • 生产者确认机制(Publisher Confirm):生产者发送消息后,等待RabbitMQ的确认(ConfirmCallback)。确认消息到达交换机(ack)。如果消息无法路由到队列,触发ReturnCallback。
  • 事务机制:通过事务(txSelect、txCommit)确保消息发送的原子性,但性能较低,推荐使用Confirm模式。
5.1.2 交换机到队列的可靠性
  • 持久化队列:声明队列时设置durable=true,确保队列在RabbitMQ重启后仍存在。
  • 持久化消息:发送消息时设置delivery_mode=2,确保消息写入磁盘。
  • 备份交换机(Alternate Exchange):当消息无法路由到队列时,转发到备份交换机,避免消息丢失。
5.1.3 队列到消费者的可靠性
  • 消费者手动确认(ACK):消费者处理完消息后手动发送ACK,RabbitMQ才会从队列中删除消息。如果消费者未发送ACK或发送NACK,消息会重新入队或进入死信队列。
  • 镜像队列(Mirrored Queues):在集群模式下,通过镜像队列将消息复制到多个节点,避免单点故障。

5.2 消费者手动确认(ACK)的作用是什么?与自动确认的区别?

5.2.1 手动确认(ACK)的作用
  • 确保消息处理成功:消费者处理完消息后手动发送ACK,RabbitMQ才会从队列中删除消息。
  • 防止消息丢失:如果消费者在处理消息时崩溃,未ACK的消息会重新入队,确保消息不丢失。
5.2.2 手动确认与自动确认的区别
特性手动确认(Manual ACK)自动确认(Auto ACK)
确认时机消费者显式调用basicAck确认。消息发送给消费者后立即确认。
可靠性高,确保消息处理成功后才删除。低,消息可能丢失(消费者崩溃时)。
性能较低,需等待消费者处理完成。较高,无需等待。
适用场景需要高可靠性的场景(如订单处理)。允许消息丢失的场景(如日志收集)。

5.3 什么是死信队列(DLX)?它的典型应用场景有哪些?

5.3.1 死信队列(DLX)的定义
  • 死信消息(Dead Letter):当消息无法被消费者正常处理时,会被标记为死信。死信消息会被转发到死信交换机(DLX),进而路由到死信队列。
  • 触发条件
    • 消息被消费者拒绝(NACK)且未重新入队。
    • 消息在队列中存活时间超过TTL(Time-To-Live)。
    • 队列达到最大长度,无法接收新消息。
5.3.2 典型应用场景
  • 失败消息重试:将处理失败的消息转移到死信队列,后续进行重试或人工处理。
  • 延迟队列:通过TTL + 死信队列实现延迟消息(如30分钟后关闭未支付订单)。
  • 日志记录:将无法处理的消息记录到死信队列,用于后续分析。

5.4 如何实现消息的延迟投递(如30分钟后执行任务)?

5.4.1 方案1:TTL + 死信队列
  • 步骤
    1. 创建普通队列(normal_queue)并设置TTL(如30分钟)。
    2. 创建死信交换机(dlx_exchange)和死信队列(dlx_queue)。
    3. normal_queue绑定到死信交换机,并设置死信路由键。
    4. 生产者发送消息到normal_queue,消息在TTL到期后自动转发到dlx_queue
    5. 消费者从dlx_queue中消费延迟消息。
5.4.2 方案2:RabbitMQ延迟消息插件
  • 步骤
    1. 使用官方插件rabbitmq-delayed-message-exchange,直接发送延迟消息。
    2. 创建延迟交换机,发送消息时设置x-delay参数(如x-delay=1800000表示30分钟)。
  • 优点:无需额外队列,实现更简单。

5.5 如何处理消息的重复消费问题?

5.5.1 重复消费的原因
  • 消费者未及时ACK:消费者处理消息后未发送ACK,导致消息重新入队。
  • 网络抖动或消费者崩溃:消费者在处理消息时崩溃,消息重新入队。
  • 生产者重复发送:生产者因网络问题重复发送消息。
5.5.2 解决方案
  • 业务层幂等性设计:每条消息携带唯一业务ID(如订单号)。在处理消息前,检查该ID是否已处理(如通过数据库唯一约束或Redis缓存)。
  • 消息去重:使用Redis记录已处理消息的ID,避免重复消费。设置消息TTL,确保重复消息在一定时间后失效。
  • 消费者逻辑优化:确保消费者处理逻辑是幂等的(如更新操作使用UPDATE而非INSERT)。使用分布式锁(如Redis锁)确保同一消息仅被一个消费者处理。

RabbitMQ 高可用性与集群

1. RabbitMQ 如何实现高可用?镜像队列的原理是什么?

1.1 RabbitMQ 高可用的实现方式

  • 集群模式:多个RabbitMQ节点组成集群,共享元数据(如交换机、队列定义),但默认情况下队列数据仅存储在一个节点上。

    • 优点:扩展性强,支持水平扩展。
    • 缺点:单节点故障可能导致队列不可用。
  • 镜像队列(Mirrored Queues)

    • 原理:队列的主节点(Master)负责处理所有读写操作。队列的镜像节点(Mirrors)从主节点同步数据。如果主节点故障,RabbitMQ会自动选举一个镜像节点作为新的主节点。
    • 作用:通过将队列复制到多个节点,确保即使某个节点故障,队列数据仍可从其他节点访问。

1.2 磁盘节点(Disc Node)和内存节点(RAM Node)的区别

特性磁盘节点(Disc Node)内存节点(RAM Node)
数据存储元数据(队列、交换机定义)存储在磁盘。元数据存储在内存。
持久化支持消息和队列的持久化。不支持持久化,节点重启后数据丢失。
性能较低,受磁盘I/O限制。较高,数据操作在内存中进行。
适用场景需要高可靠性和持久化的场景。临时数据或高性能需求的场景。
依赖关系内存节点依赖磁盘节点存储元数据。必须与磁盘节点配合使用。

1.3 集群模式下,队列数据默认存储在哪里?如何跨节点同步?

  • 队列数据的默认存储:在集群模式下,队列数据默认仅存储在创建队列的节点上(即主节点)。其他节点仅存储元数据(如队列定义),不存储实际消息数据。
  • 跨节点同步
    • 镜像队列:通过镜像队列机制,将队列数据复制到多个节点。主节点处理所有读写操作,镜像节点从主节点同步数据。如果主节点故障,镜像节点会接管成为新的主节点。
    • 同步方式:消息写入主节点后,异步复制到镜像节点。镜像节点的数据与主节点保持一致,但可能存在短暂延迟。

1.4 如何设计一个RabbitMQ集群以应对节点故障?

  • 设计原则
    • 多节点部署:至少部署3个节点(1个磁盘节点 + 2个内存节点),确保高可用性和性能平衡。节点分布在不同的物理机或可用区,避免单点故障。
    • 镜像队列配置:使用镜像队列将队列数据复制到多个节点。根据业务需求选择ha-mode
      • all:队列镜像到所有节点,适合高可靠性场景。
      • exactly:队列镜像到指定数量的节点(如2个),平衡性能和可靠性。
    • 磁盘节点与内存节点的搭配:至少部署1个磁盘节点,确保元数据的持久化。内存节点用于提升性能,但需依赖磁盘节点。
    • 监控与自动故障转移:使用RabbitMQ Management插件监控集群状态(如节点健康、队列深度)。配置负载均衡器(如HAProxy)实现客户端连接的自动故障转移。
    • 网络与硬件优化:确保节点间网络延迟低、带宽高。使用高性能磁盘(如SSD)提升持久化队列的读写性能。

2. 如何提升 RabbitMQ 的吞吐量?

2.1 提升 RabbitMQ 吞吐量的核心方法

  • 增加消费者数量:通过增加消费者实例或使用多线程消费,提升消息处理能力。
  • 优化网络与硬件:确保生产者和消费者与RabbitMQ节点之间的网络延迟低、带宽高。使用高性能磁盘(如SSD)提升持久化队列的读写性能。
  • 调整预取数量(Prefetch Count):控制消费者从队列中预取的消息数量,避免单个消费者占用过多消息。
  • 批量发送消息:将多条消息打包发送,减少网络开销和RabbitMQ的处理压力。
  • 使用异步Confirm模式:生产者异步确认消息是否成功到达RabbitMQ,避免阻塞。
  • 优化队列设计:使用多个队列分散消息负载。根据业务需求选择合适的交换机类型(如Direct、Topic)。

2.2 什么是预取数量(Prefetch Count)?如何设置合理值?

  • 预取数量(Prefetch Count)的定义

    • 作用:控制消费者从队列中预取的消息数量。
    • 机制:消费者在处理完当前消息后,才会从队列中拉取新的消息。
    • 默认值:RabbitMQ默认无限制(prefetch count=0),可能导致单个消费者占用过多消息。
  • 如何设置合理值

    • 原则:避免单个消费者占用过多消息,导致其他消费者空闲。根据消费者的处理能力和消息大小动态调整。
    • 方法
      • 如果消费者处理一条消息需要较长时间,适当增加prefetch count,确保消费者始终有消息处理。
      • 如果消息处理时间较短,减少prefetch count,避免消息积压在消费者端。

2.3 消息堆积(积压)的常见原因及解决方案?

  • 常见原因

    • 消费者处理能力不足:消费者处理速度慢,无法及时消费消息。
    • 生产者发送速率过高:生产者发送消息的速度远高于消费者处理速度。
    • 消费者宕机或网络故障:消费者无法连接RabbitMQ,导致消息积压。
    • 队列设计不合理:单队列负载过高,未分散消息到多个队列。
  • 解决方案

    • 增加消费者数量:部署更多消费者实例,提升消费能力。
    • 优化消费者处理逻辑:使用多线程或异步处理消息,提升消费速度。
    • 设置消息TTL和死信队列:为消息设置TTL(Time-To-Live),超时后转移到死信队列,避免队列无限增长。
    • 限流与降级:生产者限流,控制消息发送速率。对非核心消息进行降级处理(如丢弃或延迟处理)。
    • 监控与报警:使用RabbitMQ Management插件监控队列深度,设置报警阈值。
    • 队列拆分:将单队列拆分为多个队列,分散消息负载。

2.4 生产者批量发送消息的优化方法有哪些?

  • 批量发送
    • 原理:将多条消息打包发送,减少网络开销和RabbitMQ的处理压力。
    • 方法:生产者在发送消息时,将多条消息合并为一批发送,并等待批量确认。
  • 异步Confirm模式
    • 原理:生产者异步确认消息是否成功到达RabbitMQ,避免阻塞。
    • 方法:启用Confirm模式,通过回调机制处理消息确认和失败重试。
  • 消息压缩
    • 原理:对消息体进行压缩,减少网络传输量。
    • 方法:在发送消息前,使用压缩算法(如GZIP)压缩消息体。
  • 连接复用
    • 原理:复用TCP连接,减少连接建立和销毁的开销。
    • 方法:使用Channel(信道)复用连接,避免频繁创建新连接。
  • 消息合并
    • 原理:将多条小消息合并为一条大消息发送,减少消息头开销。
    • 方法:在发送消息前,将多条小消息合并为一条大消息。

3. RabbitMQ 的监控与故障处理

3.1 消费者宕机时,如何避免消息丢失?

  • 问题原因:消费者在处理消息时宕机,可能导致消息未被确认(ACK),从而重新入队或被丢弃。
  • 解决方案
    • 启用手动确认(Manual ACK):消费者在处理完消息后,手动发送ACK确认消息已成功处理。如果消费者宕机,未ACK的消息会重新入队,供其他消费者处理。
    • 设置消息持久化:队列声明为持久化(durable=true)。消息设置为持久化(delivery_mode=2),确保消息在RabbitMQ重启后不丢失。
    • 使用死信队列(DLX):当消息被拒绝(NACK)或超时(TTL过期)时,转发到死信队列,避免消息丢失。死信队列可用于重试或人工处理失败消息。
    • 监控消费者状态:使用RabbitMQ Management插件监控消费者连接状态,及时发现宕机情况。配置报警机制,当消费者断开连接时触发报警。

3.2 RabbitMQ 出现内存告警(Memory Alarm)的可能原因及解决方法?

  • 可能原因

    • 消息堆积:生产者发送速率过高,消费者处理能力不足,导致消息在队列中积压。
    • 队列未消费:队列中的消息未被及时消费,占用大量内存。
    • 未设置消息TTL:消息未设置TTL(Time-To-Live),长期堆积在队列中。
    • 内存泄漏:RabbitMQ本身或插件存在内存泄漏问题。
    • 资源不足:服务器内存资源不足,无法满足RabbitMQ的运行需求。
  • 解决方法

    • 增加消费者数量:部署更多消费者实例,提升消息处理能力。
    • 设置消息TTL和死信队列:为消息设置TTL,超时后转移到死信队列,避免队列无限增长。
    • 优化队列设计:将单队列拆分为多个队列,分散消息负载。
    • 调整内存阈值:修改RabbitMQ的内存阈值配置(如vm_memory_high_watermark),避免频繁触发告警。
    • 监控与报警:使用RabbitMQ Management插件监控内存使用情况,设置报警阈值。
    • 升级硬件资源:增加服务器内存资源,满足RabbitMQ的运行需求。

3.3 如何监控 RabbitMQ 的运行状态和关键指标?

  • 监控工具

    • RabbitMQ Management插件:提供Web UI,实时监控队列深度、连接数、消息速率等关键指标。支持导出监控数据,用于进一步分析。
    • Prometheus + Grafana:使用Prometheus采集RabbitMQ的监控数据,通过Grafana展示可视化图表。监控指标包括:队列深度、消费者数量、消息吞吐量、节点资源使用率等。
    • 命令行工具(rabbitmqctl):使用rabbitmqctl命令查看节点状态、集群配置、队列信息等。
  • 关键监控指标

    • 队列深度:队列中未消费的消息数量,反映消息积压情况。
    • 消费者数量:当前连接的消费者数量,反映消费能力。
    • 消息吞吐量:生产者发送速率和消费者处理速率,反映系统负载。
    • 节点资源使用率:CPU、内存、磁盘使用率,反映服务器资源状况。
    • 连接数:当前与RabbitMQ建立的连接数,反映系统负载。

3.4 消息无法路由到队列时会发生什么?如何避免消息丢失?

  • 消息无法路由的原因

    • 未绑定队列:交换机未绑定任何队列,消息无法路由。
    • Routing Key不匹配:消息的Routing Key与绑定规则不匹配,无法路由到队列。
    • 队列不存在:绑定的队列已被删除或未创建。
  • 默认行为

    • 如果消息无法路由到队列,RabbitMQ会丢弃该消息(除非启用了备用交换机)。
  • 避免消息丢失的方法

    • 启用备用交换机(Alternate Exchange):当消息无法路由时,转发到备用交换机,避免消息丢失。备用交换机可将消息路由到特定队列,用于记录或处理无法路由的消息。
    • 使用死信队列(DLX):当消息被拒绝(NACK)或无法路由时,转发到死信队列。死信队列可用于重试或人工处理失败消息。
    • 监控与报警:使用RabbitMQ Management插件监控无法路由的消息数量,设置报警阈值。及时发现并处理路由异常。
    • 生产者确认机制(Publisher Confirm):生产者启用Confirm模式,确认消息是否成功到达队列。如果消息无法路由,触发ReturnCallback,生产者可进行重试或记录。

4. RabbitMQ 与其他消息队列的对比

4.1 RabbitMQ 和 Kafka 的核心区别是什么?各自的适用场景?

  • 核心区别

    维度RabbitMQKafka
    设计目标消息可靠传输、复杂路由高吞吐、日志流处理
    协议AMQP自定义协议
    吞吐量中等(万级/秒)高(百万级/秒)
    消息存储消费后删除(可持久化)长期存储(按时间或大小保留)
    顺序性单队列单消费者保证分区内有序
    延迟低延迟(毫秒级)较高延迟(依赖批处理)
    可靠性高(支持消息确认、持久化、事务)高(支持副本机制、持久化)
    适用场景实时通信、业务解耦日志采集、流式计算
  • 适用场景

    • RabbitMQ
      • 实时通信(如订单处理、通知系统)。
      • 复杂路由(如按规则分发消息)。
      • 需要高可靠性和低延迟的场景。
    • Kafka
      • 日志收集与分析(如用户行为日志)。
      • 流式计算(如实时数据分析)。
      • 大数据量、高吞吐的场景。

4.2 为什么说 RabbitMQ 不适合大数据量日志传输场景?

  • 原因分析

    • 吞吐量限制:RabbitMQ的吞吐量通常在万级/秒,而Kafka可以达到百万级/秒。对于大数据量日志传输场景,RabbitMQ可能成为性能瓶颈。
    • 存储机制:RabbitMQ默认在消息被消费后删除,不适合长期存储大量日志数据。Kafka支持长期存储和批量消费,更适合日志场景。
    • 分区与扩展性:RabbitMQ的队列不支持分区,扩展性受限。Kafka通过分区机制,支持水平扩展和高吞吐。
    • 延迟与批处理:RabbitMQ设计目标是低延迟实时通信,而日志场景更注重高吞吐和批量处理。Kafka通过批处理机制,更适合大数据量日志传输。
  • 适用场景对比

    • RabbitMQ:适合实时通信、业务解耦、复杂路由场景。不适合大数据量、高吞吐的日志传输。
    • Kafka:适合日志收集、流式计算、大数据量传输场景。不适合低延迟、复杂路由的实时通信。

5. RabbitMQ 的高级特性与插件

5.1 如何通过插件(如 rabbitmq-delayed-message-exchange)实现延迟消息?

  • 延迟消息的实现方式

    • 方案1:TTL + 死信队列

      1. 创建普通队列:设置消息的TTL(Time-To-Live),例如30分钟。绑定死信交换机(DLX)和死信队列(DLQ)。
      2. 发送消息:生产者发送消息到普通队列,消息在TTL到期后自动转发到死信队列。
      3. 消费延迟消息:消费者从死信队列中消费延迟消息。
    • 方案2:使用延迟消息插件

      1. 安装插件:下载并启用rabbitmq-delayed-message-exchange插件。
      2. 创建延迟交换机:声明一个延迟交换机,类型为x-delayed-message
      3. 发送延迟消息:生产者发送消息时,设置x-delay参数(如x-delay=1800000表示30分钟)。
      4. 消费延迟消息:消费者从绑定到延迟交换机的队列中消费消息。
  • 插件方案的优势

    • 无需额外队列,实现更简单。
    • 支持更灵活的延迟时间设置。

5.2 RabbitMQ 的事务机制与 Confirm 模式的区别?如何选择?

  • 事务机制

    • 原理:生产者开启事务后,发送的消息会进入事务缓冲区,直到提交事务(txCommit)后才真正发送到RabbitMQ。
    • 特点:强一致性,确保消息发送的原子性。性能较低,适合对可靠性要求极高的场景。
  • Confirm 模式

    • 原理:生产者发送消息后,RabbitMQ异步返回确认(ack)或失败(nack)。
    • 特点:高性能,适合高并发场景。弱一致性,可能存在消息未确认的情况。
  • 如何选择

    • 事务机制:适合对可靠性要求极高的场景(如金融交易),但性能较低。
    • Confirm 模式:适合高并发场景(如日志收集、通知系统),性能较高。

5.3 Headers 交换机的使用场景是什么?

  • Headers 交换机的特点

    • 路由规则:基于消息头(Headers)而非Routing Key匹配。
    • 匹配条件:通过x-match参数指定匹配方式:
      • all:所有头信息必须匹配。
      • any:任意头信息匹配即可。
  • 使用场景

    • 多维度过滤:根据多个头信息(如type=reportformat=pdf)过滤消息。
    • 复杂路由:当路由规则无法通过Routing Key表达时,使用Headers交换机。
    • 动态路由:根据消息头的动态属性(如用户ID、设备类型)路由消息。
  • 示例

    • 绑定规则:x-match=alltype=reportformat=pdf
    • 消息头:type=reportformat=pdfpriority=high
    • 结果:消息匹配并路由到队列。

5.4 什么是备用交换机(Alternate Exchange)?它的作用是什么?

5.4.1 备用交换机的定义
  • 作用:当消息无法路由到任何队列时,转发到备用交换机,避免消息丢失。
  • 机制:备用交换机是一个普通交换机,绑定到特定队列,用于处理无法路由的消息。
5.4.2 使用场景
  • 消息备份:将无法路由的消息存储到备份队列,用于后续分析或重试。
  • 错误处理:当路由规则配置错误时,备用交换机确保消息不丢失。
  • 日志记录:将无法路由的消息记录到日志队列,用于监控和报警。
5.4.3 配置方法
  1. 声明备用交换机:创建一个普通交换机(如ae_exchange)和队列(如ae_queue)。
  2. 绑定备用交换机:在主交换机上设置alternate-exchange参数,指向备用交换机。
  3. 处理无法路由的消息:消费者从ae_queue中消费无法路由的消息。
5.4.4 示例
  • 主交换机main_exchangealternate-exchange=ae_exchange
  • 备用交换机ae_exchange,绑定队列ae_queue
  • 当消息无法路由到main_exchange,转发到ae_exchange并存储到ae_queue

6. RabbitMQ 的底层存储与 Erlang 语言

6.1 RabbitMQ 的底层存储机制是什么?消息如何持久化到磁盘?

6.1.1 底层存储机制
  • 消息存储(Message Store):消息体(Payload)存储在磁盘上的消息存储文件中(msg_store)。
    • 持久化消息:写入磁盘,确保RabbitMQ重启后不丢失。
    • 非持久化消息:仅存储在内存中,重启后丢失。
  • 队列索引(Queue Index):记录消息在队列中的位置和状态(如是否已消费)。索引文件(.idx)存储在磁盘上,确保消息的顺序性和可靠性。
6.1.2 消息持久化到磁盘的过程
  1. 生产者发送消息:如果消息设置为持久化(delivery_mode=2),RabbitMQ会将消息写入磁盘。
  2. 消息存储:消息体写入消息存储文件(msg_store)。队列索引更新,记录消息的位置和状态。
  3. 消费者确认:消费者处理完消息后发送ACK,RabbitMQ从队列索引中标记消息为已消费。持久化消息在确认后从磁盘删除。
6.1.3 性能优化
  • 批量写入:RabbitMQ将多条消息批量写入磁盘,减少I/O开销。
  • 内存缓存:消息在写入磁盘前先缓存到内存,提升写入效率。

6.2 Erlang 语言对 RabbitMQ 的设计有何影响?

6.2.1 Erlang 语言的特点
  • 并发模型:基于Actor模型,每个进程独立运行,通过消息传递通信。适合高并发场景,RabbitMQ利用这一特性实现高效的消息传递。
  • 容错性:支持“任其崩溃”的设计哲学,进程崩溃不会影响其他进程。RabbitMQ利用这一特性实现高可用性和故障恢复。
  • 热代码升级:支持在不停止系统的情况下升级代码。RabbitMQ可以在运行时更新,确保服务不中断。
  • 分布式支持:天生支持分布式计算,RabbitMQ利用这一特性实现集群和镜像队列。
6.2.2 对 RabbitMQ 设计的影响
  • 高并发:Erlang的轻量级进程模型使RabbitMQ能够高效处理大量并发连接。
  • 高可用:Erlang的容错机制使RabbitMQ在节点故障时仍能正常运行。
  • 分布式:Erlang的分布式特性使RabbitMQ支持集群和镜像队列,实现高可用性。
  • 可扩展性:Erlang的热代码升级和动态加载特性使RabbitMQ易于扩展和维护。

6.3 消息在队列中的生命周期是怎样的?

6.3.1 消息生命周期的阶段
  1. 生产者发送消息:生产者创建消息并发送到交换机。如果消息设置为持久化,RabbitMQ将消息写入磁盘。
  2. 交换机路由消息:交换机根据类型和绑定规则将消息路由到一个或多个队列。如果消息无法路由,可能被丢弃或转发到备用交换机。
  3. 消息进入队列:消息存储在队列中,等待消费者拉取。如果队列已满,可能触发流控或拒绝新消息。
  4. 消费者拉取消息:消费者从队列中拉取消息并处理。如果启用手动确认(Manual ACK),消费者处理完后发送ACK。
  5. 消息确认与删除:RabbitMQ收到ACK后,从队列中删除消息。如果消息未确认或消费者宕机,消息可能重新入队或进入死信队列。
  6. 消息过期或丢弃:如果消息设置了TTL(Time-To-Live),超时后可能被丢弃或转发到死信队列。如果队列达到最大长度,新消息可能被丢弃或替换旧消息。
6.3.2 生命周期的关键点
  • 持久化:确保消息在RabbitMQ重启后不丢失。
  • 确认机制:确保消息被消费者成功处理。
  • 死信队列:处理无法正常消费的消息。
  • TTL:控制消息的生命周期,避免队列无限增长。

7. RabbitMQ 的最佳实践与设计模式

7.1 如何用 RabbitMQ 设计一个秒杀系统解决超卖问题?

7.1.1 设计目标
  • 解决高并发下的超卖问题,确保库存准确性。
  • 通过消息队列削峰填谷,避免数据库被打垮。
7.1.2 设计方案
  1. 预扣库存:用户请求秒杀时,先在Redis中预减库存。如果库存充足,生成秒杀订单并发送消息到RabbitMQ。
  2. 异步下单:消费者从RabbitMQ中消费秒杀订单消息,生成最终订单。通过数据库唯一约束或业务逻辑保证幂等性,避免重复下单。
  3. 队列削峰:使用RabbitMQ缓冲瞬时高并发请求,避免直接冲击数据库。根据系统处理能力,动态调整消费者数量。
  4. 失败处理:如果下单失败,将消息转移到死信队列,后续进行重试或人工处理。
7.1.3 优点
  • 通过Redis预减库存,避免超卖。
  • 通过RabbitMQ削峰填谷,提升系统稳定性。
  • 异步下单提高响应速度,提升用户体验。

7.2 如何保证消息的顺序性?多消费者场景下如何处理?

7.2.1 保证顺序性的方法
  • 单队列单消费者:将消息发送到单个队列,并由单个消费者处理,严格保证顺序性。
  • 业务逻辑分组:根据业务属性(如订单ID)将消息分组,确保同一组消息由同一消费者处理。
    • 示例:将订单ID哈希到特定队列,保证同一订单的消息顺序性。
  • 全局序列号:为每条消息分配全局序列号,消费者根据序列号处理消息。
    • 示例:使用数据库或Redis生成全局唯一ID。
7.2.2 多消费者场景下的处理
  • 分区队列:将消息分散到多个队列,每个队列由单个消费者处理,确保分区内有序。
  • 顺序锁:消费者在处理消息时,对关键资源加锁,确保同一资源的消息顺序处理。

7.3 RabbitMQ 的最佳实践总结

  • 合理设计交换机与队列:根据业务需求选择合适的交换机类型(如Direct、Topic、Fanout)。
  • 启用持久化与确认机制:确保消息的可靠性和一致性。
  • 使用死信队列与备用交换机:处理无法正常消费或路由的消息。
  • 监控与报警:实时监控RabbitMQ的运行状态,及时发现并处理异常。
  • 优化性能:通过批量发送、异步Confirm、调整预取数量等方式提升吞吐量。

相关文章:

RabbitMQ八股文

RabbitMQ 核心概念与组件 1. RabbitMQ 核心组件及其作用 1.1 生产者(Producer) 作用:创建并发送消息到交换机。特点:不直接将消息发送到队列,而是通过交换机路由。 1.2 交换机(Exchange) 作…...

运维面试题(七)

1.statefulset用来管理有状态的应用程序,有状态是什么意思? 每一个pod都有一个固定的网络标识符,在整个生命周期中不会改变。每个实例都可以拥有自己的持久化存储卷,即使容器被删除并重新创建,存储卷仍然存在。Statef…...

【项目设计】网页版五子棋

文章目录 一、项目介绍1.项目简介2.开发环境3.核心技术4.开发阶段 二、Centos-7.6环境搭建1.安装wget工具2.更换软件源(yum源)3.安装scl工具4.安装epel软件源5.安装lrzsz传输工具6.安装高版本gcc/g编译器7.安装gdb调试器8.安装git9.安装cmake10.安装boost库11.安装Jsoncpp库12.…...

Netty——BIO、NIO 与 Netty

文章目录 1. 介绍1.1 BIO1.1.1 概念1.1.2 工作原理1.1.3 优缺点 1.2 NIO1.2.1 概念1.2.2 工作原理1.2.3 优缺点 1.3 Netty1.3.1 概念1.3.2 工作原理1.3.3 优点 2. Netty 与 Java NIO 的区别2.1 抽象层次2.2 API 易用性2.3 性能优化2.4 功能扩展性2.5 线程模型2.6 适用场景 3. 总…...

Docker 安装 Mysql

以下是安装Docker版MySQL 8.0.25并实现目录挂载的步骤: docker仓库:https://hub.docker.com/_/mysql 1. 拉取Mysql镜像文件 docker pull mysql:8.0.252. 创建mysql临时容器服务 docker run -d \--name mysql \-p 3306:3306 \-e MYSQL_ROOT_PASSWORD123…...

Electron打包文件生成.exe文件打开即可使用

1 、Electron 打包,包括需要下载的内容和环境配置步骤 注意:Electron 是一个使用 JavaScript、HTML 和 CSS 构建跨平台桌面应用程序的框架 首先需要电脑环境有Node.js 和 npm我之前的文章有关nvm下载node的说明也可以去官网下载 检查是否有node和npm环…...

线程和协程的区别了解

1.资源消耗 调度方式:线程由操作系统内核调度(抢占式),协程由程序自己控制调度(协作式)。切换开销:线程切换涉及内核态与用户态的转换,开销大;协程只在用户态切换上下文…...

楼宇自控系统的结构密码:总线与分布式结构方式的差异与应用

在现代建筑中,为了实现高效、智能的管理,楼宇自控系统变得越来越重要。它就像建筑的 智能管家,可自动控制照明、空调、通风等各种机电设备,让建筑运行更顺畅,还能节省能源成本。而在楼宇自控系统里,有两种关…...

算法及数据结构系列 - 滑动窗口

系列文章目录 算法及数据结构系列 - 二分查找 算法及数据结构系列 - BFS算法 算法及数据结构系列 - 动态规划 算法及数据结构系列 - 双指针 算法及数据结构系列 - 回溯算法 算法及数据结构系列 - 树 文章目录 滑动窗口框架思路经典题型76. 最小覆盖子串567. 字符串的排列438. …...

【江协科技STM32】软件SPI读写W25Q64芯片(学习笔记)

SPI通信协议及S为5Q64简介:【STM32】SPI通信协议&W25Q64Flash存储器芯片(学习笔记)-CSDN博客 STM32与W25Q64模块接线: SPI初始化: 片选SS、始终SCK、MOSI都是主机输出引脚,输出引脚配置为推挽输出&…...

2025.3.23机器学习笔记:文献阅读

2025.3.23周报 题目信息摘要Abstract创新点网络架构实验不足以及展望 题目信息 题目: Enhancement of Hydrological Time Series Prediction with Real-World Time Series Generative Adversarial Network-Based Synthetic Data and Deep Learning Models期刊&…...

Day20-前端Web案例——部门管理

目录 部门管理1. 前后端分离开发2. 准备工作2.1 创建Vue项目2.2 安装依赖2.3 精简项目 3. 页面布局3.1 介绍3.2 整体布局3.3 左侧菜单 4. Vue Router4.1 介绍4.2 入门4.3 案例4.4 首页制作 5. 部门管理5.1部门列表5.1.1. 基本布局5.1.2 加载数据5.1.3 程序优化 5.2 新增部门5.3…...

实验3 以太坊交易周期的需求分析

区块链技术 实验报告 实验名称 实验3 以太坊交易周期的需求分析 一、实验目的 1、学习并掌握以太坊交易的内容; 2、学习并掌握以太坊交易周期的四个阶段; 3、学习并掌握结构化需求分析方法; 4、学习并掌握面向对象的需求分析方法&…...

Linux 通过压缩包安装 MySQL 并设置远程连接教程

一、引言 在 Linux 系统中,有时候我们需要通过压缩包的方式手动安装 MySQL 数据库,并且为了方便在其他设备上对数据库进行管理和操作,还需要设置允许远程连接。本文将详细介绍在 Linux(以 CentOS 为例)系统中通过压缩包安装 MySQL 8 并设置远程连接的步骤。 二、安装前准…...

【商城实战(56)】商城数据生命线:恢复流程与演练全解析

【商城实战】专栏重磅来袭!这是一份专为开发者与电商从业者打造的超详细指南。从项目基础搭建,运用 uniapp、Element Plus、SpringBoot 搭建商城框架,到用户、商品、订单等核心模块开发,再到性能优化、安全加固、多端适配&#xf…...

Java学习笔记-XXH3哈希算法

XXH3是由Yann Collet设计的非加密哈希算法,属于XXHash系列的最新变种,专注于极速性能与低碰撞率,适用于对计算效率要求极高的场景。 极速性能 在RAM速度限制下运行,小数据(如 1-128 字节)处理可达纳秒级&…...

同旺科技USB to SPI 适配器 ---- 指令循环发送功能

所需设备: 内附链接 1、同旺科技USB to SPI 适配器 1、周期性的指令一次输入,即可以使用 “单次发送” 功能,也可以使用 “循环发送” 功能,大大减轻发送指令的编辑效率; 2、 “单次发送” 功能,“发送数据…...

在Mac M1/M2芯片上完美安装DeepCTR库:避坑指南与实战验证

让推荐算法在Apple Silicon上全速运行 概述 作为推荐系统领域的最经常用的明星库,DeepCTR集成了CTR预估、多任务学习等前沿模型实现。但在Apple Silicon架构的Mac设备上,安装过程常因ARM架构适配、依赖库版本冲突等问题受阻。本文通过20次环境搭建实测…...

【CXX-Qt】2.5 继承

某些 Qt API 要求你从抽象基类中重写某些方法,例如 QAbstractItemModel。 为了支持直接从 Rust 中创建这样的子类,CXX-Qt 提供了多种辅助工具。 某些基类可能需要特殊的构造参数。这可以通过使用自定义构造函数来实现。 访问基类方法 要在 Rust 中访…...

Linux系统之美:环境变量的概念以及基本操作

本节重点 理解环境变量的基本概念学会在指令和代码操作上查询更改环境变量环境变量表的基本概念父子进程间环境变量的继承与隔离 一、引入 1.1 自定义命令(我们的exe) 我们以往的Linux编程经验告诉我们,我们在对一段代码编译形成可执行文件后…...

【nnUnetv2】推理+评估+测试

在 Windows 系统下设置环境变量 之前训练和推理的时候开着AutoDL的服务器,是在 Linux 系统下设置的环境变量。 但是现在开始研究具体代码了,就在本地跑(一直开着服务器有点费钱),所以就在Windows 系统下设置环境变量。 ①右键点击 “此电脑”,选择 “属性”。 ②在左侧…...

损失函数理解(一)——极大似然估计

本博客内容来自B站up主【王木头学科学】的视频内容 习惯看视频的小伙伴可移至视频链接[待补充]:~~~ 首先通俗地解释一下极大似然估计(Maximum Likelihood Estimation,MLE)的思想:通过结果寻找使该结果发生的最可能的原…...

ios端使用TCplayer直播播放三秒直接卡顿bug

1. 查看配置项没问题 setTcPlayer() {let that this;player new TcPlayer("videoPlayer", {live: this.activatPlayType "livePlay" ? true : false,x5_type: "h5",x5_fullscreen: true,systemFullscreen: true,x5_orientation: 1,x5_player…...

大模型-提示词工程与架构

什么是提示工程 提示工程(Prompt Engineering)是一门新兴的技术领域,专注于研究如何设计、构建和优化提示词,以充分发挥大模型的潜力 。它涉及到对语言结构、任务需求、模型特性等多方面因素的综合考量。提示工程的目标是通过精心…...

高斯数据库-WDR Snapshot生成性能报告

docker 安装高斯数据库: docker pull opengauss/opengauss:latestdocker run --name opengauss --privilegedtrue -d -e GS_PASSWORDopenGauss123 -p 8090:5432 -v /opengauss:/var/lib/opengauss/data opengauss/opengauss:latest 进入容器设置用户权限&#xff…...

损失函数理解(二)——交叉熵损失

损失函数的目的是为了定量描述不同模型(例如神经网络模型和人脑模型)的差异。 交叉熵,顾名思义,与熵有关,先把模型换成熵这么一个数值,然后用这个数值比较不同模型之间的差异。 为什么要做这一步转换&…...

CSS学习笔记

【1】CSS样式规则 【2】CSS样式表引入方式 1、行内式 <!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge"/><meta name"vi…...

AI比人脑更强,因为被植入思维模型【15】马斯洛需求层次理论

马斯洛需求层次模型思维模型 定义 马斯洛需求层次模型是由美国心理学家亚伯拉罕马斯洛&#xff08;Abraham Maslow&#xff09;于1943年提出的一种心理学理论&#xff0c;用于描述人类动机的层次结构。该模型将人类的需求从低到高分为五个层次&#xff0c;分别是生理需求、安…...

cartographer中地图转换

文章目录 地图种类栅格地图 坐标系种类ros坐标系像素坐标系物理坐标系(世界坐标系) 地图种类 栅格地图 地图的初始化 在Cartographer中&#xff0c;栅格地图通过概率值来表示每个栅格的状态。每个栅格的初始概率值通常设置为0.5&#xff0c;表示未知状态。这种初始化方式允许…...

关于MTU的使用(TCP/IP网络下载慢可能与此有关)

参考链接&#xff1a;告诉你mtu值怎么设置才能网速最好&#xff01; -Win7系统之家 出现网络速度被限制&#xff0c;可能与MTU值相关&#xff0c;先查看下本机的MTU winR,然后输入&#xff1a;netsh interface ipv4 show subinterfaces &#xff0c;查看自己网络中的MTU&…...

【AI解题】Cache直接映射地址划分解析

一、问题背景 某32位总线处理器的Cache采用直接映射方式&#xff0c;已知 Cache总容量为16KB&#xff0c;每个Cache块大小为16字节。需要确定内存地址中 Offset&#xff08;块内偏移&#xff09;、Index&#xff08;块索引&#xff09;、Tag&#xff08;标签&#xff09; 三部…...

android音频概念解析

音频硬件接口&#xff08;我们可以理解为ASOC的声卡&#xff09; 官方代码里叫audio hardware interface 也称为module&#xff0c;定义在services/audiopolicy/config/audio_policy_configuration.xml&#xff1a; 分别有primary&#xff0c;a2dp&#xff0c;usb&#xff0…...

项目生命周期 和 项目管理生命周期的差异

在项目管理中,明确区分 项目生命周期 和 项目管理生命周期 是理解项目运作的关键。以下从定义、阶段划分到实际应用进行系统性分析: 一、项目生命周期(Project Life Cycle) 定义 项目生命周期是项目从 启动到结束 的自然演进过程,描述项目交付成果的 技术性阶段,通常与…...

UDP 协议

文章目录 UDP 协议简介数据包格式UDP 通信流程抓包分析参考 本文为笔者学习以太网对网上资料归纳整理所做的笔记&#xff0c;文末均附有参考链接&#xff0c;如侵权&#xff0c;请联系删除。 UDP 协议 UDP 是一种面向无连接的传输层协议&#xff0c;属于 TCP/IP 协议簇的一种。…...

[已解决]jupyter notebook报错 500 : Internal Server Error及notebook闪退

jupyter notebook出现如上图的报错&#xff0c;可以在黑色窗口中检查是为什么报错。 我检查发现是nbconvert导致的问题&#xff0c;卸载重装nbconvert。 但是这时候出现&#xff0c;jupyter notebook闪退问题。jupyter的黑色窗口出现一秒钟就没了。 在Anaconda Prompt中检查ju…...

APM 仿真遥控指南

地面站开发了一段时间了&#xff0c;由于没有硬件&#xff0c;所以一直在 APM 模拟器中验证。我们已经实现了 MAVLink 消息接收和解析&#xff0c;显示无人机状态&#xff0c;给无人机发送消息&#xff0c;实现一键起飞&#xff0c;飞往指定地点&#xff0c;降落&#xff0c;返…...

使用 ncurses 库创建文本用户界面:基础函数详解

简介 ncurses 是一个功能强大的库&#xff0c;用于在 Unix-like 系统中创建文本用户界面。它提供了丰富的函数来控制屏幕上的文本显示、处理键盘输入、绘制图形元素等。本文将详细介绍 ncurses 库中的一些基础函数&#xff0c;包括 printw、wrefresh、获取用户信息、键盘输入、…...

dify创建第一个Agent

1、首先LLM模型必须支持 Function Calling 由于deepseek-R1本地化部署时还不支持&#xff0c;所以使用 qwq模型。 2、创建空白 Agent 3、为Agent添加工具 4、测试 当未添加时间工具时 询问 时间 如下 5、开启时间工具 询问如下...

nebula graph传统使用Docker进行项目发版

nebula graph传统使用Docker进行项目发版 1. nebula graph服务2. 搭建ES集群3. 注意事项3.1 图数据库的启动顺序3.2 模糊查询失效 1. nebula graph服务 1.在测试服务器中执行如下命令 docker commit 85b6e2b8xxx xxx_nebula_es:1.0.0.2执行docker images之后能看到新的镜像 x…...

OpenCV vs MediaPipe:哪种方案更适合实时手势识别?

引言 手势识别是计算机视觉的重要应用&#xff0c;在人机交互&#xff08;HCI&#xff09;、增强现实&#xff08;AR&#xff09;、虚拟现实&#xff08;VR&#xff09;、智能家居控制、游戏等领域有广泛的应用。实现实时手势识别的技术方案主要有基于传统计算机视觉的方法&am…...

PRODIGY: “不折腾人”的蛋白-蛋白/蛋白-小分子结合能计算工具

PRODIGY&#xff08;全称为 PROtein binDIng enerGY prediction&#xff09;是一种蛋白质结合能预测工具&#xff0c;可利用蛋白质-蛋白质复合物的三维结构来预测其结合亲和力。PRODIGY 利用一种高效的基于接触的方法&#xff0c;在估计结合自由能和解离常数的同时&#xff0c;…...

IDEA修改默认作者名称

User: IDEA提示注释缺少author信息&#xff0c;但自动设置后&#xff0c;名称不是我想要的默认名称&#xff0c;应该如何修改IDEA里默认的作者名称&#xff1f; Kimi: 以下是几种修改IntelliJ IDEA中默认作者名称的方法&#xff1a; ### 方法一&#xff1a;修改File and Code …...

【嵌入式学习2】C语言 - VScode环境搭建

目录 ## 语言分类 ## c语言编译器 ## VScode相关配置 ## 语言分类 编译型语言&#xff1a;C&#xff0c;C解释型语言&#xff1a;python&#xff0c;JS ## c语言编译器 分类GCC 系列MinGWCygwinMSVC系列一套编程语言编译器将GCC编译器和GNU Binutils移植到Win32平台下的产物…...

【TI MSPM0】Timer学习

一、计数器 加法计数器&#xff1a;每进入一个脉冲&#xff0c;就加一减法计算器&#xff1a;每进入一个脉冲&#xff0c;就减一 当计数器减到0&#xff0c;触发中断 1.最短计时时间 当时钟周期为1khz时&#xff0c;最短计时时间为1ms&#xff0c;最长计时时间为65535ms 当时…...

SQL Server数据库慢SQL调优

SQL Server中慢SQL会显著降低系统性能并引发级联效应。首先&#xff0c;用户直接体验响应时间延长&#xff0c;核心业务操作&#xff08;如交易处理、报表生成&#xff09;效率下降&#xff0c;导致客户满意度降低甚至业务中断。其次&#xff0c;资源利用率失衡&#xff0c;CPU…...

大数据平台上的数据建模与分析:从数据到决策的跃迁

大数据平台上的数据建模与分析:从数据到决策的跃迁 随着数字化转型的深入,大数据平台成为了企业实现智能决策和创新的核心技术基础。大量结构化、半结构化和非结构化数据的生成和存储,促使企业需要更高效的方式来管理、分析、以及从中提取有价值的信息。在这一过程中,数据…...

C++ --- 多态

1 多态的概念 多态(polymorphism)的概念&#xff1a;通俗来说&#xff0c;就是多种形态。多态分为编译时多态(静态多态)和运⾏时多 态(动态多态)&#xff0c;这⾥我们重点讲运⾏时多态&#xff0c;编译时多态(静态多态)和运⾏时多态(动态多态)。编译时 多态(静态多态)主要就是我…...

细说卫星导航:测距定位原理

测距定位原理 1. 伪距测量技术 核心原理&#xff1a;卫星发射信号&#xff0c;用户接收并记录传播时间&#xff0c;乘以光速得到距离&#xff08;伪距&#xff09;。 技术细节&#xff1a; 信号传播路径分析 信号结构&#xff1a; 卫星信号包含三部分&#xff1a; 载波&…...

【AI News | 20250322】每日AI进展

AI Repos 1、DeTikZify 可以把草图或图形转换成TikZ代码的模型&#xff0c;可用来绘制复杂的科学图表&#xff0c;输入草图或文字描述即可转换成TikZ代码。DeTikZify强大的地方在于它能理解图表的语义信息&#xff0c; 能识别图表中的不同组成部分及其含义&#xff0c;比如坐标…...

【js逆向入门】图灵爬虫练习平台 第九题

地址&#xff1a;aHR0cHM6Ly9zdHUudHVsaW5ncHl0b24uY24vcHJvYmxlbS1kZXRhaWwvOS8 f12进入了debugger&#xff0c;右击选择一律不在此处暂停&#xff0c; 点击继续执行 查看请求信息 查看载荷&#xff0c;2个加密参数&#xff0c;m和tt 查看启动器&#xff0c;打上断点 进来 往…...