什么是RabbitMQ?

news2025/3/1 23:54:52

RabbitMQ是一个由erlang开发的消息队列。消息队列用于应用间的异步协作。

在这里插入图片描述

2.RabbitMQ的组件
Message:由消息头和消息体组成。消息体是不透明的,而消息头则由一系列的可选属性组成,这些属性包括routing-key、priority、delivery-mode(是否持久性存储)等。

Publisher:消息的生产者。

Exchange:接收消息并将消息路由到一个或多个Queue。default exchange 是默认的直连交换机,名字为空字符串,每个新建队列都会自动绑定到默认交换机上,绑定的路由键名称与队列名称相同。

Binding:通过Binding将Exchange和Queue关联,这样Exchange就知道将消息路由到哪个Queue中。

Queue:存储消息,队列的特性是先进先出。一个消息可分发到一个或多个队列。

Virtual host:每个 vhost 本质上就是一个 mini 版的 RabbitMQ 服务器,拥有自己的队列、交换器、绑定和权限机制。vhost 是 AMQP 概念的基础,必须在连接时指定,RabbitMQ 默认的 vhost 是 / 。当多个不同的用户使用同一个RabbitMQ server提供的服务时,可以划分出多个vhost,每个用户在自己的vhost创建exchange和queue。

Broker:消息队列服务器实体。

3.什么时候使用MQ
对于一些不需要立即生效的操作,可以拆分出来,异步执行,使用消息队列实现。

以常见的订单系统为例,用户点击下单按钮之后的业务逻辑可能包括:扣减库存、生成相应单据、发短信通知。这种场景下就可以用 MQ 。将短信通知放到 MQ 异步执行,在下单的主流程(比如扣减库存、生成相应单据)完成之后发送一条消息到 MQ, 让主流程快速完结,而由另外的线程消费MQ的消息。

4.RabbitMQ的优缺点
缺点:使用erlang实现,不利于二次开发和维护;性能较kafka差,持久化消息和ACK确认的情况下生产和消费消息单机吞吐量大约在1-2万左右,kafka单机吞吐量在十万级别。

优点:有管理界面,方便使用;可靠性高;功能丰富,支持消息持久化、消息确认机制、多种消息分发机制。

5.RabbitMQ 有哪些重要的角色?
RabbitMQ 中重要的角色有:生产者、消费者和代理。

1、生产者:消息的创建者,负责创建和推送数据到消息服务器;

2、消费者:消息的接收方,用于处理数据和确认消息;

3、代理:就是 RabbitMQ 本身,用于扮演“快递”的角色,本身不生产消息,只是扮演“快递”的角色。

6.Exchange 类型
Exchange分发消息时根据类型的不同分发策略不同,目前共四种类型:direct、fanout、topic、headers 。headers 模式根据消息的headers进行路由,此外 headers 交换器和 direct 交换器完全一致,但性能差很多。

Exchange规则。

direct

direct交换机会将消息路由到binding key 和 routing key完全匹配的队列中。它是完全匹配、单播的模式。
在这里插入图片描述

fanout

所有发到 fanout 类型交换机的消息都会路由到所有与该交换机绑定的队列上去。fanout 类型转发消息是最快的。
在这里插入图片描述

topic

topic交换机使用routing key和binding key进行模糊匹配,匹配成功则将消息发送到相应的队列。routing key和binding key都是句点号“. ”分隔的字符串,binding key中可以存在两种特殊字符“”与“##”,用于做模糊匹配,其中“”用于匹配一个单词,“##”用于匹配多个单词。

在这里插入图片描述

headers

headers交换机是根据发送的消息内容中的headers属性进行路由的。在绑定Queue与Exchange时指定一组键值对;当消息发送到Exchange时,RabbitMQ会取到该消息的headers(也是一个键值对的形式),对比其中的键值对是否完全匹配Queue与Exchange绑定时指定的键值对;如果完全匹配则消息会路由到该Queue,否则不会路由到该Queue。

7.消息丢失
消息丢失场景:生产者生产消息到RabbitMQ Server消息丢失、RabbitMQ Server存储的消息丢失和RabbitMQ Server到消费者消息丢失。

消息丢失从三个方面来解决:生产者确认机制、消费者手动确认消息和持久化。

生产者确认机制
生产者发送消息到队列,无法确保发送的消息成功的到达server。

解决方法:

1、事务机制。在一条消息发送之后会使发送端阻塞,等待RabbitMQ的回应,之后才能继续发送下一条消息。性能差。

2、开启生产者确认机制,只要消息成功发送到交换机之后,RabbitMQ就会发送一个ack给生产者(即使消息没有Queue接收,也会发送ack)。如果消息没有成功发送到交换机,就会发送一条nack消息,提示发送失败。

在 Springboot 是通过 publisher-confirms 参数来设置 confirm 模式:

spring:
rabbitmq:
##开启 confirm 确认机制
publisher-confirms: true
Copy to clipboardErrorCopied
在生产端提供一个回调方法,当服务端确认了一条或者多条消息后,生产者会回调这个方法,根据具体的结果对消息进行后续处理,比如重新发送、记录日志等。

// 消息是否成功发送到Exchange
final RabbitTemplate.ConfirmCallback confirmCallback = (CorrelationData correlationData, boolean ack, String cause) -> {
log.info("correlationData: " + correlationData);
log.info("ack: " + ack);
if(!ack) {
log.info(“异常处理…”);
}
};

rabbitTemplate.setConfirmCallback(confirmCallback);
Copy to clipboardErrorCopied
路由不可达消息
生产者确认机制只确保消息正确到达交换机,对于从交换机路由到Queue失败的消息,会被丢弃掉,导致消息丢失。

对于不可路由的消息,有两种处理方式:Return消息机制和备份交换机。

Return消息机制

Return消息机制提供了回调函数 ReturnCallback,当消息从交换机路由到Queue失败才会回调这个方法。需要将mandatory 设置为 true ,才能监听到路由不可达的消息。

spring:
rabbitmq:
##触发ReturnCallback必须设置mandatory=true, 否则Exchange没有找到Queue就会丢弃掉消息, 而不会触发ReturnCallback
template.mandatory: true
Copy to clipboardErrorCopied
通过 ReturnCallback 监听路由不可达消息。

final RabbitTemplate.ReturnCallback returnCallback = (Message message, int replyCode, String replyText, String exchange, String routingKey) ->
        log.info("return exchange: " + exchange + ", routingKey: "
                + routingKey + ", replyCode: " + replyCode + ", replyText: " + replyText);

rabbitTemplate.setReturnCallback(returnCallback);
Copy to clipboardErrorCopied
当消息从交换机路由到Queue失败时,会返回 return exchange: , routingKey: MAIL, replyCode: 312, replyText: NO_ROUTE。

备份交换机

备份交换机alternate-exchange 是一个普通的exchange,当你发送消息到对应的exchange时,没有匹配到queue,就会自动转移到备份交换机对应的queue,这样消息就不会丢失。

消费者手动消息确认
有可能消费者收到消息还没来得及处理MQ服务就宕机了,导致消息丢失。因为消息者默认采用自动ack,一旦消费者收到消息后会通知MQ Server这条消息已经处理好了,MQ 就会移除这条消息。

解决方法:消费者设置为手动确认消息。消费者处理完逻辑之后再给broker回复ack,表示消息已经成功消费,可以从broker中删除。当消息者消费失败的时候,给broker回复nack,根据配置决定重新入队还是从broker移除,或者进入死信队列。只要没收到消费者的 acknowledgment,broker 就会一直保存着这条消息,但不会 requeue,也不会分配给其他 消费者。

消费者设置手动ack:

##设置消费端手动 ack
spring.rabbitmq.listener.simple.acknowledge-mode=manual
Copy to clipboardErrorCopied
消息处理完,手动确认:

@RabbitListener(queues = RabbitMqConfig.MAIL_QUEUE)
public void onMessage(Message message, Channel channel) throws IOException {

    try {
        Thread.sleep(5000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    long deliveryTag = message.getMessageProperties().getDeliveryTag();
    //手工ack;第二个参数是multiple,设置为true,表示deliveryTag序列号之前(包括自身)的消息都已经收到,设为false则表示收到一条消息
    channel.basicAck(deliveryTag, true);
    System.out.println("mail listener receive: " + new String(message.getBody()));
}

Copy to clipboardErrorCopied
当消息消费失败时,消费端给broker回复nack,如果consumer设置了requeue为false,则nack后broker会删除消息或者进入死信队列,否则消息会重新入队。

持久化
如果RabbitMQ服务异常导致重启,将会导致消息丢失。RabbitMQ提供了持久化的机制,将内存中的消息持久化到硬盘上,即使重启RabbitMQ,消息也不会丢失。

消息持久化需要满足以下条件:

1、消息设置持久化。发布消息前,设置投递模式delivery mode为2,表示消息需要持久化。

2、Queue设置持久化。

3、交换机设置持久化。

当发布一条消息到交换机上时,Rabbit会先把消息写入持久化日志,然后才向生产者发送响应。一旦从队列中消费了一条消息的话并且做了确认,RabbitMQ会在持久化日志中移除这条消息。在消费消息前,如果RabbitMQ重启的话,服务器会自动重建交换机和队列,加载持久化日志中的消息到相应的队列或者交换机上,保证消息不会丢失。

镜像队列
当MQ发生故障时,会导致服务不可用。引入RabbitMQ的镜像队列机制,将queue镜像到集群中其他的节点之上。如果集群中的一个节点失效了,能自动地切换到镜像中的另一个节点以保证服务的可用性。

通常每一个镜像队列都包含一个master和多个slave,分别对应于不同的节点。发送到镜像队列的所有消息总是被直接发送到master和所有的slave之上。除了publish外所有动作都只会向master发送,然后由master将命令执行的结果广播给slave,从镜像队列中的消费操作实际上是在master上执行的。

8.消息重复消费怎么处理?
消息重复的原因有两个:1.生产时消息重复,2.消费时消息重复。

生产者发送消息给MQ,在MQ确认的时候出现了网络波动,生产者没有收到确认,这时候生产者就会重新发送这条消息,导致MQ会接收到重复消息。

消费者消费成功后,给MQ确认的时候出现了网络波动,MQ没有接收到确认,为了保证消息不丢失,MQ就会继续给消费者投递之前的消息。这时候消费者就接收到了两条一样的消息。由于重复消息是由于网络原因造成的,无法避免。

解决方法:发送消息时让每个消息携带一个全局的唯一ID,在消费消息时先判断消息是否已经被消费过,保证消息消费逻辑的幂等性。具体消费过程为:

1、消费者获取到消息后先根据id去查询redis/db是否存在该消息

2、如果不存在,则正常消费,消费完毕后写入redis/db

3、如果存在,则证明消息被消费过,直接丢弃

9.消费端怎么进行限流?
当 RabbitMQ 服务器积压大量消息时,队列里的消息会大量涌入消费端,可能导致消费端服务器奔溃。这种情况下需要对消费端限流。

Spring RabbitMQ 提供参数 prefetch 可以设置单个请求处理的消息个数。如果消费者同时处理的消息到达最大值的时候,则该消费者会阻塞,不会消费新的消息,直到有消息 ack 才会消费新的消息。

开启消费端限流:

##在单个请求中处理的消息个数,unack的最大数量
spring.rabbitmq.listener.simple.prefetch=2
Copy to clipboardErrorCopied
原生 RabbitMQ 还提供 prefetchSize 和 global 两个参数。Spring RabbitMQ没有这两个参数。

//单条消息大小限制,0代表不限制
//global:限制限流功能是channel级别的还是consumer级别。当设置为false,consumer级别,限流功能生效,设置为true没有了限流功能,因为channel级别尚未实现。
void basicQos(int prefetchSize, int prefetchCount, boolean global) throws IOException;
Copy to clipboardErrorCopied
10.什么是死信队列?
消费失败的消息存放的队列。

消息消费失败的原因:

消息被拒绝并且消息没有重新入队(requeue=false)
消息超时未消费
达到最大队列长度
设置死信队列的 exchange 和 queue,然后进行绑定:

@Bean
public DirectExchange dlxExchange() {
    return new DirectExchange(RabbitMqConfig.DLX_EXCHANGE);
}

@Bean
public Queue dlxQueue() {
    return new Queue(RabbitMqConfig.DLX_QUEUE, true);
}

@Bean
public Binding bindingDeadExchange(Queue dlxQueue, DirectExchange deadExchange) {
    return BindingBuilder.bind(dlxQueue).to(deadExchange).with(RabbitMqConfig.DLX_QUEUE);
}

Copy to clipboardErrorCopied
在普通队列加上两个参数,绑定普通队列到死信队列。当消息消费失败时,消息会被路由到死信队列。

@Bean
public Queue sendSmsQueue() {
    Map<String,Object> arguments = new HashMap<>(2);
    // 绑定该队列到私信交换机
    arguments.put("x-dead-letter-exchange", RabbitMqConfig.DLX_EXCHANGE);
    arguments.put("x-dead-letter-routing-key", RabbitMqConfig.DLX_QUEUE);
    return new Queue(RabbitMqConfig.MAIL_QUEUE, true, false, false, arguments);
}

Copy to clipboardErrorCopied
生产者完整代码:

@Component
@Slf4j
public class MQProducer {

@Autowired
RabbitTemplate rabbitTemplate;

@Autowired
RandomUtil randomUtil;

@Autowired
UserService userService;

final RabbitTemplate.ConfirmCallback confirmCallback = (CorrelationData correlationData, boolean ack, String cause) -> {
        log.info("correlationData: " + correlationData);
        log.info("ack: " + ack);
        if(!ack) {
            log.info("异常处理....");
        }
};


final RabbitTemplate.ReturnCallback returnCallback = (Message message, int replyCode, String replyText, String exchange, String routingKey) ->
        log.info("return exchange: " + exchange + ", routingKey: "
                + routingKey + ", replyCode: " + replyCode + ", replyText: " + replyText);

public void sendMail(String mail) {
    //貌似线程不安全 范围100000 - 999999
    Integer random = randomUtil.nextInt(100000, 999999);
    Map<String, String> map = new HashMap<>(2);
    String code = random.toString();
    map.put("mail", mail);
    map.put("code", code);

    MessageProperties mp = new MessageProperties();
    //在生产环境中这里不用Message,而是使用 fastJson 等工具将对象转换为 json 格式发送
    Message msg = new Message("tyson".getBytes(), mp);
    msg.getMessageProperties().setExpiration("3000");
    //如果消费端要设置为手工 ACK ,那么生产端发送消息的时候一定发送 correlationData ,并且全局唯一,用以唯一标识消息。
    CorrelationData correlationData = new CorrelationData("1234567890"+new Date());

    rabbitTemplate.setMandatory(true);
    rabbitTemplate.setConfirmCallback(confirmCallback);
    rabbitTemplate.setReturnCallback(returnCallback);
    rabbitTemplate.convertAndSend(RabbitMqConfig.MAIL_QUEUE, msg, correlationData);

    //存入redis
    userService.updateMailSendState(mail, code, MailConfig.MAIL_STATE_WAIT);
}

}
Copy to clipboardErrorCopied
消费者完整代码:

@Slf4j
@Component
public class DeadListener {

@RabbitListener(queues = RabbitMqConfig.DLX_QUEUE)
public void onMessage(Message message, Channel channel) throws IOException {

    try {
        Thread.sleep(5000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    long deliveryTag = message.getMessageProperties().getDeliveryTag();
    //手工ack
    channel.basicAck(deliveryTag,false);
    System.out.println("receive--1: " + new String(message.getBody()));
}

}
Copy to clipboardErrorCopied
当普通队列中有死信时,RabbitMQ 就会自动的将这个消息重新发布到设置的死信交换机去,然后被路由到死信队列。可以监听死信队列中的消息做相应的处理。

11.说说pull模式
pull模式主要是通过channel.basicGet方法来获取消息,示例代码如下:

GetResponse response = channel.basicGet(QUEUE_NAME, false);
System.out.println(new String(response.getBody()));
channel.basicAck(response.getEnvelope().getDeliveryTag(),false);
Copy to clipboardErrorCopied
12.怎么设置消息的过期时间?
在生产端发送消息的时候可以给消息设置过期时间,单位为毫秒(ms)

Message msg = new Message(“tyson”.getBytes(), mp);
msg.getMessageProperties().setExpiration(“3000”);
Copy to clipboardErrorCopied
也可以在创建队列的时候指定队列的ttl,从消息入队列开始计算,超过该时间的消息将会被移除。

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

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

相关文章

ChatGPT与软件架构(2) - 基于Obsidian和GPT实现解决方案架构自动化

磨刀不误砍柴工&#xff0c;良好的工具可以有效提高效率。本文介绍基于Obsidian和GPT打造架构知识库的思路&#xff0c;为架构师提供整理、分享、原文: Solution Architecture Automation With Obsidian and GPT Stas Parechyn Unsplash 本文介绍的ArchVault是一个旨在帮助架构…

【100个 Unity实用技能】 | Unity 的 LOD技术(多细节层次)

&#x1f3ac; 博客主页&#xff1a;https://xiaoy.blog.csdn.net &#x1f3a5; 本文由 呆呆敲代码的小Y 原创&#xff0c;首发于 CSDN&#x1f649; &#x1f384; 学习专栏推荐&#xff1a;Unity系统学习专栏 &#x1f332; 游戏制作专栏推荐&#xff1a;游戏制作 &…

vue3+ts+echarts5基本地图下钻~

依靠本地json文件实现省市下钻&#xff0c;有后台的可以改成服务&#xff0c;样式没有&#xff0c;vue3tsecharts5&#xff0c;一定要设宽高 html&#xff1a; <div click"back">返回</div> <div id"echartsMap" style"width: 58%; h…

【Azure】微软 Azure 基础解析(七)Azure 网络服务中的虚拟网络 VNet、网关、负载均衡器 Load Balancer

本系列博文还在更新中&#xff0c;收录在专栏&#xff1a;「Azure探秘&#xff1a;构建云计算世界」 专栏中。 本系列文章列表如下&#xff1a; 【Azure】微软 Azure 基础解析&#xff08;三&#xff09;描述云计算运营中的 CapEx 与 OpEx&#xff0c;如何区分 CapEx 与 OpEx…

入职字节跳动那一天,我哭了(蘑菇街被裁,奋战7个月拿下offer)

前言 先说一下自己的个人情况&#xff0c;20届应届生&#xff0c;通过校招进入到了蘑菇街&#xff0c;然后一待就待了差不多2年多的时间&#xff0c;可惜的是去年8月份受疫情影响遇到了大裁员&#xff0c;而我也是其中一员。好在之前一直想去字节跳动&#xff0c;年尾就已经在…

wlanapi.dll丢失怎么办?分享多种wlanapi.dll丢失的解决方法

Wlanapi.dll是Windows中的一个重要文件&#xff0c;它是无线局域网API的一部分&#xff0c;负责提供和管理无线网络连接的功能。如果出现wlanapi.dll丢失的情况&#xff0c;会导致无法连接到无线网络&#xff0c;影响电脑的正常使用。下面我们来看看wlanapi.dll丢失怎么办&…

在linux服务器中对R语言中for循环设置多核运行

1 问题 在R中构建了for循环&#xff0c;由于循环过多&#xff0c;运行速度过慢&#xff0c;且不同循环之间是并行关系&#xff0c;拟通过多核运行可以解决此问题。 2 代码设置 2.1 shell脚本中的设置 b.sh export OPENBLAS_NUM_THREADS8Rscript ./..._1.R \2.2 R代码中的设…

程序员必备的10张流程图

随着互联网的发展&#xff0c;现在有越来越多的人想成为程序员。 如果你想成为程序员你可以先问自己这几个问题&#xff1f; •你是一个逻辑和抽象思维能力比较强的人吗&#xff1f; •你是否愿意不断地去学习那些新的东西&#xff0c;并且在大多数时间内你都需要去自学。 …

Midway.js探索与实践

您好&#xff0c;如果喜欢我的文章&#xff0c;可以关注我的公众号「量子前端」&#xff0c;将不定期关注推送前端好文~ 前言 我司的技术基建在Midway之上&#xff0c;主要是面向中后台前后端一体化方案&#xff0c;大白话就是全栈应用解决方案&#xff0c;什么是Midway呢&am…

freeswitch的gateway配置方案优化

概述 freeswitch是一款简单好用的VOIP开源软交换平台。 在之前的文章中&#xff0c;我们简单介绍过gateway的三种配置方案&#xff0c;但是实际应用之后发现&#xff0c;方案中的参数设置有缺陷&#xff0c;会导致一些问题。 本文档中&#xff0c;针对具体的gateway配置问题…

linux第六七天 which find进程等

ctrlF5 //强制刷新 which ifconfig //找到ifconfig的路径 发现在/usr/sbin/ifconfig 目录下 然后 cp /usr/sbin/ifconfig /root/bin/ipconfig 就相当于自己设置了ifconfig的另外一种命令 多个条件可以使用-a(-o)连接&#xff0c;表示而且&#xff08;或者&#xff09…

Django中使用celery实现定时任务和异步任务

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、准备二、配置1.引入库2.代码编写a、在settings.py文件下添加如下代码b、在项目主目录下创建celery.py文件c、在项目的__init__.py里面添加如下代码![在这里…

【期望】Kuangbin 危险的派对 牛客期望专题班 increment of coins

4849. 危险的迷宫 - AcWing题库 题意&#xff1a; 思路&#xff1a; 本来对期望怎么想都想不通&#xff0c;后来看了大佬的题解&#xff0c;自己动手画了画&#xff0c;以及队友说的“拆分”&#xff0c;忽然间就有点懂了.... 这个说的很对&#xff0c;把期望问题看作是DAG上…

Unity中对预制体烘焙光照贴图,在其他Scene中使用或者动态生成带光照贴图的预制体

记录个人开发笔记&#xff0c;如果有大佬有更好的方法或者觉得我这个方法哪里有问题欢迎指正&#xff01; 首先说下为什么会弄预制体烘焙光照贴图&#xff0c;因为项目需求需要动态生成一个房间的&#xff0c;因此是将房间弄成预制体&#xff0c;动态生成就好了&#xff0c;这…

【Datagear】如何给Datagear追加Admin

【背景】 Datagear默认是只设置了一个Admin&#xff0c;这个Admin可以完成用户的各种管理操作&#xff0c;并且对所有数据源&#xff0c;数据集&#xff0c;图表&#xff0c;面板拥有全部编辑权限。 【问题】 只有一个Admin很多场景下不够用。但是应用设置本身没有提供追加A…

【测试人生】测试工程如何去学习接口自动化技术

一、为什么要学习自动化 提高生产力&#xff1a;自动化可以帮助您在短时间内完成重复性工作&#xff0c;从而大大提高生产力。自动化不仅减少了手动执行任务所需的时间和精力&#xff0c;还减少了出错的风险。 质量保证&#xff1a;自动化测试可以确保软件在修改后仍然按预期运…

2023 光亚展|乐鑫将携 AI、Wi-Fi 6、私有云和 Matter 方案精彩亮相

2023 广州国际照明展览会&#xff08;光亚展&#xff09;将于 6 月 9 至 12 日在广州琶洲展馆启幕。本届展会以“光未来”为主题&#xff0c;畅想未来生活方式的无限可能。乐鑫科技 (688018.SH) 将在 B 区 9.2 号厅 D55 展位&#xff0c;带来具有前瞻性的智能照明解决方案和实体…

龙芯2K1000实战开发-以太网/串口设计

文章目录 概要整体架构流程技术名词解释技术细节小结概要 本文主要针对2k1000的以太网及串口的国产化设计 整体架构流程 提示:这里可以添加技术整体架构 整体架构,以太网,使用2k1000自带的以太网mac控制器,外选用国产化PHY,国产化变压器。 整体框架,如下图,主要是器…

2023安卓逆向 -- JNI学习(从开发到反编译)

一、新建native C项目&#xff0c;填写好项目信息&#xff0c;一路下一步即可 二、创建好项目&#xff0c;直接点击运行&#xff0c;出现下面界面&#xff0c;说明我们的环境都没有问题 三、Java层调用java层函数 1、新建一个Java Class&#xff0c;命名为JavaFun 2、编写java…

维宏系统修改端口位置操作说明

1.关闭软件后找到Ncconfig.exe工具并打开 具体操作步骤 (1)桌面上鼠标点到 NcStudio鼠标右键-打开文件所在的位置如下图 (2) 在目录中找到NcConfig.exe的快捷方式&#xff08;黄色图标&#xff09; (3)打开并输入密码&#xff08;密码和软件密码一样默认初始密码ncstudio …