RabbitMQ基本原理

news2024/11/23 15:35:32

一、基本结构

工作原理
所有中间件技术都是基于 TCP/IP 协议基础之上进行构建新的协议规范,RabbitMQ遵循的是AMQP协议(Advanced Message Queuing Protocol - 高级消息队列协议)。
生产者发送消息流程:

  • 1、生产者和Broker建立TCP连接;
  • 2、生产者和Broker建立通道;
  • 3、生产者通过通道消息发送给Broker,由Exchange将消息进行转发;
  • 4、Exchange将消息转发到指定的Queue(队列)。

【详细】

1、消息生产者连接到`RabbitMQ Broker`,建立链接(Connection),在链接(Connection)上开启一个信道(Channel);
2、声明一个交换机(Exchange),并设置相关属性,比如交换机类型、是否持久化等;
3、声明一个队列(Queue),并设置相关属性,比如是否排他、是否持久化、是否自动删除等;
4、使用路由键(RoutingKey)将队列(Queue)和交换机(Exchange)绑定起来;
5、生产者发送消息至 RabbitMQ Broker,其中包含路由键、交换器等信息,根据路由键(RoutingKey)发送消息到交换机(Exchange);
6、相应的交换器(Exchange)根据接收到的路由键(RoutingKey)查找相匹配的队列如果找到 ,则将从生产者发送过来的消息存入相应的队列中;
7、如果没有找到 ,则根据生产者配置的属性选择丢弃还是回退给生产者;
8、关闭信道(Channel);
9、关闭链接(Connection);

消费者接收消息流程:

  • 1、消费者和Broker建立TCP连接;
  • 2、消费者和Broker建立通道;
  • 3、消费者监听指定的Queue(队列);
  • 4、当有消息到达QueueBroker默认将消息推送给消费者;
  • 5、消费者接收到消息;
  • 6、ack回复。

【详细】

- 1、建立链接(Connection);
- 2、在链接(Connection)上开启一个信道(Channel);
- 3、请求消费指定队列(Queue)的消息,并设置回调函数(onMessage);
- 4、[MQ]将消息推送给消费者,消费者接收消息;
- 5、消费者发送消息确定(Ack[acknowledge]);
- 6、[MQ]删除被确认的消息;
- 7、关闭信道(Channel);
- 8、关闭链接(Connection);

MQ消费消息分发原理

1)一种是Pull模式,对应的方法是basicGet。
消息存放在服务端,只有消费者主动获取才能拿到消息。如果每搁一段时间获取一次消息,消息的实时性会降低。
但是好处是可以根据自己的消费能力决定消息的频率。

2)另一种是push,对应的方法是BasicConsume,只要生产者发消息到服务器,就马上推送给消费者,
消息保存客户端,实时性很高,如果消费不过来有可能会造成消息积压。Spring AMQP是push方式,
通过事件机制对队列进行监听,只要有消息到达队列,就会触发消费消息的方法。

二、RabbitMQ组成部分说明

  • Producer: 消息生产者,即生产方客户端,生产方客户端将消息发送;

  • Connection: TCP连接,生产者或消费者与消息队列RabbitMQ版间的物理TCP连接;

    1)Connection会执行认证、IP解析、路由等底层网络任务。
    2)应用与消息队列RabbitMQ版完成Connection建立大约需要15个TCP报文交互,因而会消耗大量的网络资源和消息队列RabbitMQ版资源。
    3)一个进程对应一个Connection,一个进程中的多个线程则分别对应一个Connection中的多个Channel。
    4)Producer和Consumer分别使用不同的Connection进行消息发送和消费;

  • Channel: 在客户端的每个物理TCP连接里,可建立多个Channel,每个Channel代表一个会话任务。

    1)Channel是物理TCP连接中的虚拟连接。
    2)当应用通过Connection与消息队列RabbitMQ版建立连接后,所有的AMQP协议操作(例如创建队列、发送消息、接收消息等)都会通过Connection中的Channel完成。
    3) Channel可以复用Connection,即一个Connection下可以建立多个Channel。
    4) Channel不能脱离Connection独立存在,而必须存活在Connection中。
    5) 当某个Connection断开时,该Connection下的所有Channel都会断开。

  • Broker: 消息队列服务进程,此进程包括两个部分:Exchange和Queue;

  • Exchange(交换器): 生产者将消息发送到Exchange,由Exchange将消息路由到一个或多个Queue中。Exchange根据消息的属性或内容路由消息。

  • Queue: 消息队列,存储消息的队列,每个消息都会被投入到一个或多个Queue里;

  • Consumer: 消息消费者,即消费方客户端,接收MQ转发的消息;

  • Routing Key(路由键): 生产者在向Exchange发送消息时,需要指定一个Routing Key来设定该消息的路由规则。 Routing Key需要与Exchange类型及Binding Key联合使用才能生效。一般情况下,生产者在向Exchange发送消息时,可以通过指定Routing Key来决定消息被路由到哪个或哪些Queue;

  • Binding: 一套绑定规则,用于告诉Exchange消息应该被存储到哪个Queue。它的作用是把Exchange和Queue按照路由规则绑定起来。

  • Binding Key(绑定键): 用于告知Exchange应该将消息投递到哪些Queue中(生产者将消息发送给哪个Exchange是需要由RoutingKey决定的,生产者需要将Exchange与哪个队列绑定时需要由BindingKey决定的);

  • Virtual Host: 虚拟主机,本质上是一个mini版的RabbitMQ服务器,拥有自己的队列、交换机、绑定和权限机制,vhost是共享相同的身份认证和加密环境的独立服务器域。vhost是AMQP的基础,必须在连接时指定,RabbitMQ默认的vhost是/。

三、交换模式

Direct Exchange(直连模式)

【路由规则】 Direct Exchange根据Binding Key和Routing Key完全匹配的规则路由消息。
【使用场景】 Direct Exchange适用于通过简单字符标识符区分消息的场景。
Direct Exchange常用于单播路由。
Direct

Fanout Exchange(广播模式)

【路由规则】 Fanout Exchange忽略Routing Key和Binding Key的匹配规则,将消息路由到所有绑定的Queue。
【使用场景】 Fanout Exchange适用于广播消息的场景。例如,分发系统使用Fanout Exchange来广播各种状态和配置更新。
广播模式

Topic Exchange(主题模式)

【路由规则】 Topic Exchange根据Binding Key和Routing Key通配符匹配的规则路由消息。
Topic Exchange支持的通配符包括星号(*)和井号(#)。 星号(*)代表一个英文单词(例如cn)。 井号(#)代表零个、一个或多个英文单词,英文单词间通过英文句号(.)分隔,例如cn.zj.hz。
【使用场景】 Topic Exchange适用于通过通配符区分消息的场景。
Topic Exchange常用于多播路由。例如,使用Topic Exchange分发有关于特定地理位置的数据。
主题模式

Headers Exchange (头部交换机)

【路由规则】 Headers Exchange可以被视为Direct Exchange的另一种表现形式。
Headers Exchange可以像Direct Exchange一样工作,不同之处在于Headers Exchange使用Headers属性代替Routing Key进行路由匹配。
在绑定Headers Exchange和Queue时,可以设置绑定属性的键值对。然后,在向Headers Exchange发送消息时,设置消息的Headers属性键值对。
Headers Exchange将根据消息Headers属性键值对和绑定属性键值对的匹配情况路由消息。
匹配算法由一个特殊的绑定属性键值对控制。该属性为x-match,只有以下两种取值:

  • 1)all:所有除x-match以外的绑定属性键值对必须和消息Headers属性键值对匹配才会路由消息。
  • 2)any:只要有一组除x-match以外的绑定属性键值对和消息Headers属性键值对匹配就会路由消息。
    以下两种情况下,认为消息Headers属性键值对和绑定属性键值对匹配:
    • 1、 消息Headers属性的键和值与绑定属性的键和值完全相同;
    • 2、 消息Headers属性的键和绑定属性的键完全相同,但绑定属性的值为空。

【使用场景】 Headers Exchange适用于通过多组Headers属性区分消息的场景。Headers Exchange常用于多播路由。例如,涉及到分类或者标签的新闻更新。

生产者确认机制

1、确认原理
生产者将消息发送到exchange,exchange根据路由规则将消息投递到了queue。

  • 1)Confirm确认:生产者发送消息到交换机时会存在消息丢失的情景,开启事务会导致吞吐量下降,Confirm机制就是消息发送到交换机(Exchange)时会触发Confirm回调。通过 publisher confirm (发送方确认机制)可以确定消息是否被成功路由到MQ broker从而选择是否重发等步骤。当生产者开启 publisher confirm 消息发送到MQ端之后,MQ会回一个ack给生产者,ack是个boolean值,为true消息成功发送到MQ。反之发送失败。
  • 2)Return确认:从交换机到队列也有可能出现路由失败导致消息丢失情景(可能是MQ出问题导致queue和exchange绑定丢失,或者失误删除了绑定关系等),Return机制可解决这个问题,路由失败时可以通过Return回调来将路由失败的消息记录下来。

消费者确认机制

1、消费者确认原理
消费者确认是指当一条消息投递到消费者处理后,消费者发送给MQ broker的确认
(通俗的说就是 告知服务器这条消息已经被我消费了,可以在队列删掉 ,这样以后就不会再发了, 否则消息服务器以为这条消息没处理掉 重启应用后还会在发)。

有auto和manual两种

  • 1)auto则由broker自行选择时机,一般可认为消息发送到消费者后就直接被ack,也即消息会被从队列中移除掉而不顾消息的处理逻辑是否成功;

  • 2)manual则是需要消费者显式的去手动ack后消息才会被从队列中移除掉,通过这个机制可以限制在消息处理完之后再Ack或者nack; 开启手动确认模式,即由消费方自行决定何时应该ack,通过设置autoAck=false开启手动确认模式;

消息持久化

消息发送并保存到队列之后如果不做特殊处理是保存在内存中,当节点宕机重启或者内存故障等,会导致消息丢失,通过对消息进行持久化到磁盘可以降低这种风险, 除了对消息进行持久化还是不够,还需要对queue、exchange进行持久化。

RabbitMQ解决消息丢失问题

消息确认机制

RabbitMQ提供了消息确认机制,即生产者在发送消息后,可以等待RabbitMQ服务器返回确认信息,以确保消息已经被正确地接收和处理。如果RabbitMQ服务器没有返回确认信息,生产者可以选择重新发送消息或者采取其他的补救措施。

生产者确认消息和重试
  1. 使用缓存:在confirmCallback中,将ackfalse的消息存到缓存中。然后,可以使用另外的线程或者定时任务来处理这些失败的消息,进行重试。

  2. 设置重试次数:为了避免无限重试,我们可以设置一个重试次数的上限。当达到这个上限后,我们可以选择将消息发送到死信队列,或者进行其他的错误处理。

  3. 使用死信队列:在RabbitMQ中,我们可以设置一个死信队列来存储那些无法被正常处理的消息。当消息在主队列中被拒绝或者过期后,它们会被发送到死信队列。然后,我们可以对死信队列中的消息进行人工处理,或者在一段时间后再次进行处理。

事务机制

1.首先需要配置一个事务管理器

 @Bean
 PlatformTransactionManager platformTransactionManager(ConnectionFactory connectionFactory) {
      return new RabbitTransactionManager(connectionFactory);
  }

2.然后在生产者上添加事务注解以及设置通信通道为事务模式。

@Transactional

  1. 开启事务机制就三步:
  • 配置事务管理器
  • 使用 @Transactional 注解开启事务
  • 调用 setChannelTransacted 方法设置消息通道为事务模式,即设置为 true

4.当我们开启事务模式之后,RabbitMQ 生产者发送消息会有这样几个步骤:

  • (1) 客服端发出请求,将通信管道设置为事务模式
  • (2) 服务端给出回复,同意将通信管道设置为事务模式
  • (3) 客户端发送消息
  • (4) 客户端提交事务
  • (5) 服务端给出响应,确认事务提交

6.两步 RabbitMQ 都有提供解决的方案。那么,如果确保消息成功到达 RabbitMQ 呢?

  • (1) 开启事务机制

  • (2) 发送方确认机制
    注意:这是两种不同的方案,不可以同时开启,只能二选其一。如果同时开启,则会报错

消息持久化

RabbitMQ支持将消息持久化到磁盘,即使RabbitMQ服务器宕机或重启,消息也不会丢失。在发布消息时,可以设置消息的持久化标志,这样消息就会被写入磁盘中,而不是仅仅保存在内存中。
其中我们交换机和队列都要设置对应的持久化,在创建时,我们会设置持久化参数。同时为了避免单点故障,RabbitMQ应该做成集群模式,以免一台机器损坏,出现数据丢失的问题。

消费端确认和重试

对于消费者来说,该配置不仅起到了连接作用,同时也启动了重试机制,默认重试 2 次。

spring.rabbitmq.host=127.0.0.1
spring.rabbitmq.port=5672
spring.rabbitmq.username=admin
spring.rabbitmq.password=admin
spring.rabbitmq.listener.simple.retry.enabled=true # 开启消费者重试机制
spring.rabbitmq.listener.simple.retry.max-attempts=3 # 最大重试次数
spring.rabbitmq.listener.simple.retry.initial-interval=3000 # 重试时间间隔

确认的话需要我们做签收操作

 channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);

死信队列配置

被拒收的消息,或者是过期的消息,或者是队列已经满了的消息,都会进入死信队列,死信队列有一个默认的生效时间,如果没有做任务配置,到了时间会自动删除消息。
java中配置死信队列

    /**
     * 延迟队列,又叫死信队列 “
     *
     * @return
     */
    @Bean
    public Queue delayQueue() {
        HashMap<String, Object> arguments = new HashMap<>();
        arguments.put("x-dead-letter-exchange", "test_ex");
        arguments.put("x-dead-letter-routing-key", "test_ex.dead");
        // 消息过期时间 2分钟
        arguments.put("x-message-ttl", 60000);
        return new Queue("delayQueue", true, false, false, arguments);
    }

以上参数说明:

  • x-dead-letter-exchange:死信队列过期以后往指定交换机发
  • x-dead-letter-routing-key:死信队列过期指定路由键
  • x-message-ttl: 死信队列过期时间,单位是毫秒

RabbitMQ解决消息积压问题

RabbitMQ消息积压问题通常是由于消费者无法及时消费消息或消费速度过慢或发送者流量太大导致的。以下是一些解决方法:

1.增加消费者数量: 可以通过增加消费者的数量来提高消费速度,减少消息积压。可以通过添加更多的消费者进程或者增加消费者的线程数来实现。

2.调整消费者的QoS参数: 消费者的QoS参数可以控制消费者每次从RabbitMQ服务器获取的消息数量,以及未确认消息的最大数量。可以适当调整这些参数,以减少消息积压。

3.设置消费者的超时时间: 可以设置消费者的超时时间,如果消费者在指定的时间内没有消费消息,就将消息重新投递到队列中,以便其他消费者消费。

4.增加队列的容量: 可以增加队列的容量,以便存储更多的消息。但是,如果队列容量过大,可能会导致内存占用过高,影响系统的性能。

5.使用死信队列: 可以将未能及时消费的消息转移到死信队列中,以便后续处理。可以设置死信队列的超时时间,以便在一定时间内处理这些消息。

6.监控和调整: 可以使用RabbitMQ的监控工具来监控队列的状态和消费者的消费速度,及时发现并解决消息积压问题。

RabbitMQ解决消息重复消费问题

RabbitMQ提供了消息去重的机制来解决消息重复消费的问题。具体来说,可以使用以下两种方式来实现:

1.消息去重插件
RabbitMQ提供了一个消息去重插件,可以通过在RabbitMQ节点上安装该插件来实现消息去重。该插件会在消息传输之前对消息进行唯一性校验,如果消息已经被消费过,那么该消息将被丢弃。该插件的实现原理是将已经消费过的消息ID保存在内存中,当新消息到达时,会检查该消息ID是否已经存在,如果存在则丢弃该消息。

2.消息幂等性设计
消息幂等性是指对于同一条消息,无论消费多少次,最终的结果都是一致的。因此,可以通过在消息的生产者或消费者端实现消息幂等性来解决消息重复消费的问题。具体实现方式包括:

  • 在消息生产者端,为每条消息生成唯一的ID,将该ID与消息一起发送到RabbitMQ,消费者在消费消息时根据该ID进行幂等性校验;
  • 在消息消费者端,记录已经消费过的消息ID,当重复消费同一条消息时,直接忽略该消息。

需要注意的是,实现消息幂等性需要考虑业务逻辑的复杂性和消息处理的性能。如果业务逻辑比较简单,可以通过对消息进行去重来解决问题;如果业务逻辑比较复杂,可以通过实现消息幂等性来保证消息的正确性。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2182094.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

国庆同欢,祖国昌盛!肌肉纤维启发,水凝胶如何重构聚合物

在这个国庆佳节&#xff0c;我们共同感受祖国的繁荣昌盛&#xff0c;同时也迎来了知识的探索之旅。今天来了解聚合物架构的重构的研究——《Hydrogel‐Reactive‐Microenvironment Powering Reconfiguration of Polymer Architectures》发表于《Advanced Science》。材料科学不…

【数据结构与算法】算法和算法分析

文章目录 一.算法1.定义2.描述 二.算法与程序三.算法特性四.算法效率的度量4.1算法时间事前分析法算法时间复杂度的渐进表示法分析算法时间复杂度的基本方法 4.2算法空间 数据的逻辑结构映像到内存就是数据的存储结构&#xff0c;针对数据的逻辑结构可以选择多种存储结构。数据…

Kotlin:2.0.0 的新特性

一、概述 kotlin 2.0.0版本英文官方文档 The Kotlin 2.0.0 release is out and the new Kotlin K2 compiler is Stable! Additionally, here are some other highlights: Kotlin 2.0.0发布了&#xff0c;新的Kotlin K2编译器已经稳定了。此外&#xff0c;以下是其他一些亮点: …

Linux操作系统中dubbo

1、简介 dubbo框架是做微服务通信的&#xff0c;是由阿里巴巴开发&#xff0c;后捐赠给阿帕奇基金会。 2、与OpenFeign的区别 dubbo是采用RPC协议实现微服务通信&#xff0c;OpenFeign是采用Http请求的方式实现的。 OpenFeign 最简单的&#xff0c;就是Spring公司开发的&am…

TinyAP:使用TinyML对抗Wi-Fi攻击的智能接入点

论文标题&#xff1a; 英文&#xff1a;TinyAP: An intelligent Access Point to combat Wi-Fi attacks using TinyML中文&#xff1a;TinyAP&#xff1a;使用TinyML对抗Wi-Fi攻击的智能接入点 作者信息&#xff1a; Anand Agrawal 和 Rajib Ranjan Maiti&#xff0c;来自印…

C语言常用标准库 -- 5.<time.h>

目录 引言 5. C标准库--time.h 5.1 简介 5.2 常量与宏 5.3 库变量 5.4 库宏 5.5 库函数 5.6 注意事项 &#x1f308;你好呀&#xff01;我是 程序猿 &#x1f30c; 2024感谢你的陪伴与支持 ~ &#x1f680; 欢迎一起踏上探险之旅&#xff0c;挖掘无限可能&#xff0c;…

线程池面试集

目录 线程池中提交一个任务的流程是怎样的? 线程池有五种状态 如何优雅的停止一个线程? 线程池的核心线程数、最大线程数该如何设置? 如何理解Java并发中的可见性、原子性、有序性? Java死锁如何避免? 线程池中提交一个任务的流程是怎样的? 线程池有五种状态 如何优…

【docker学习】Linux系统离线方式安装docker环境方法

centos7-linux安装docker(离线方式) 下载docker的安装文件 https://download.docker.com/linux/static/stable/x86_64/ 下载的是&#xff1a;docker-18.06.3-ce.tgz 这个压缩文件 将docker-18.06.3-ce.tgz文件上传到centos7-linux系统上&#xff0c;用ftp工具上传即可 解压…

《RabbitMQ篇》基本概念介绍

MQ功能 解耦 MQ允许不同系统或组件之间松散耦合。发送者和接收者不需要直接连接&#xff0c;从而提高了系统的灵活性和可维护性。异步处理 使用MQ可以实现异步消息传递&#xff0c;发送者可以将消息放入队列后立即返回&#xff0c;不必等待接收者处理。这提高了系统的响应速度…

鸿蒙NEXT开发-ArkTS(基于最新api12稳定版)

注意&#xff1a;博主有个鸿蒙专栏&#xff0c;里面从上到下有关于鸿蒙next的教学文档&#xff0c;大家感兴趣可以学习下 如果大家觉得博主文章写的好的话&#xff0c;可以点下关注&#xff0c;博主会一直更新鸿蒙next相关知识 专栏地址: https://blog.csdn.net/qq_56760790/…

Spring IoC笔记

目录 1.什么是 IoC&#xff1f; 2.IoC类注解&#xff08;五大注解&#xff09; 2.1那为什么要这么多类注解&#xff1f; 2.2五大注解是不是可以混用&#xff1f; 2.3程序被spring管理的条件是&#xff1f; 3.bean对象 3.1Bean 命名约定 3.2获取bean对象 4.⽅法注解 B…

《应急通信产业发展研究报告》蓝皮书解读

近日&#xff0c;中国信通院发布了《应急通信产业发展研究报告》蓝皮书&#xff0c;该报告是对中国应急通信产业现状、发展趋势及其政策环境的综合分析&#xff0c;旨在为行业发展提供参考与指导。以下是小编对该蓝皮书的一些内容解读&#xff1a; 1.应急通信的重要性 应急通信…

2.点位管理|前后端如何交互——帝可得后台管理系统

目录 前言点位管理菜单模块1.需求说明2.库表设计3.生成基础代码0 .使用若依代码生成器最终目标1.创建点位管理2.添加数据字典3.配置代码生成信息4.下载代码并导入项目 4.优化菜单——点位管理1.优化区域管理2.增加点位数3. 合作商4.区域管理中添加查看详情功能5.合作商添加点位…

【拥抱AIGC】通义灵码扩展管理

通义灵码提供了扩展管理&#xff0c;支持自定义指令&#xff0c;满足企业编码场景的扩展诉求。 适用版本 企业标准版、企业专属版 通义灵码管理员、组织内全局管理员&#xff08;专属版&#xff09;在通义灵码控制台-扩展管理中&#xff0c;进行自定义指令的管理、查看自定义…

解锁数据宝藏:AI驱动搜索工具,让非结构化数据“说话

哈哈,说起这个 AI 搜索演示啊,那可真是个有意思的话题!非结构化数据,这家伙虽然难搞,但价值却是杠杠的。今天呢,咱就好好聊聊怎么借助 Fivetran 和 Milvus,快速搭建一个 AI 驱动的搜索工具,让企业能从那些乱七八糟的数据里淘到金子! 一、非结构化数据的挑战与机遇 首…

PCL 点云条件滤波

目录 一、概述 1.1原理 1.2实现步骤 1.3应用场景 二、代码实现 2.1关键函数 2.1.1 条件定义与滤波 2.1.2 可视化函数 2.2完整代码 三、实现效果 PCL点云算法汇总及实战案例汇总的目录地址链接&#xff1a; PCL点云算法与项目实战案例汇总&#xff08;长期更新&#…

Python从入门到高手4.1节-掌握条件控制语句

目录 4.1.1 理解条件控制 4.1.2 if, elif, else 4.1.3 条件表达式 4.1.4 条件控制可以嵌套 4.1.5 if语句的三元运算 4.1.6 国庆节快乐 4.1.1 理解条件控制 在日常生活中&#xff0c;我们常喜欢说如果, "如果怎么样&#xff0c;那么就会怎么样"。"如果&qu…

240930_CycleGAN循环生成对抗网络

240930_CycleGAN循环生成对抗网络 CycleGAN&#xff0c;也算是笔者记录GAN生成对抗网络的第四篇&#xff0c;前三篇可以跳转 240925-GAN生成对抗网络-CSDN博客 240929-DCGAN生成漫画头像-CSDN博客 240929-CGAN条件生成对抗网络-CSDN博客 在第三篇中&#xff0c;我们采用了p…

【Lazy ORM +Netty+DB开发一个内网渗透工具 wu-lazy-cloud-network(1.2.8-JDK17-SNAPSHOT)】

【Lazy ORM NettyDB开发一个内网渗透工具 wu-lazy-cloud-network&#xff08;1.2.8-JDK17-SNAPSHO&#xff09;】 环境 Java 17Spring Boot 3.xLazy ORMNettyMysql、H2 更新日志 版本1.2.8-JDK17-SNAPSHOT [change] 原《内网穿透》更改为服务端渗透客户端 [change] 新增服务…

Unity 代码裁剪(Strip Engine Code)

文章目录 0.IL2CPP 打包运行闪退问题1.什么是代码裁剪2.为什么要使用代码裁剪3.代码裁剪设置与级别4.强制保留代码4.1 使用[Preserve]标签4.2 使用Link.xml文件 5.Strip中遇到的问题及解决方法6.注意事项 0.IL2CPP 打包运行闪退问题 Google Play要求从2019年8月1日起apk必须支…