RabbitMQ学习记录

news2024/9/24 1:22:00

核心概念

Brocker:消息队列服务器实体

Exchange(消息交换机):它指定消息按什么规则,路由到哪个队列。

Queue(消息队列载体):每个消息都会被投入到一个或多个队列。

Binding(绑定):它的作用就是把exchange和queue按照路由规则绑定起来。

Routing Key(路由关键字):exchange根据这个关键字进行消息投递;

vhost:权限数据隔离。

Producer(消息生产者):就是投递消息的程序。

Consumer(消息消费者):就是接受消息的程序;

工作模式

simple模式

简单收发模式,其中一个生产者一个消费者,一个队列。也称为点对点模式

img

work模式

一个消息生产者,一个交换机,一个消息队列,多个消费者。

生产者P发送消息到队列,多个消费者C消费队列的数据。

工作流队列也被称为公平性队列模式,RabbitMQ将按顺序将每条消息发送给笑一个消费者,每个消费者将获得相同数量的消息。

img

publish/subscribe发布订阅

无选择接收消息,一个生产者,一个Fanout交换机,多个队列,多个消费者。

在应用中,需要将队列绑定到交换机上,一个发送到交换机的消息都会被转发到与该交换机绑定的所有队列上。

生产者P只需吧消息发送到交换机X上,绑定这个交换机的队列都会获得一份一样的数据。

Routing路由模式

在发布订阅模式的基础上,有选择的接收消息,也是通过routing理由进行匹配条件是否满足接收消息,Direct交换机。

生产者P发送数据是要指定交换机(X)和routing发送消息 ,指定的routingKey=error,则队列Q1和队列Q2都会有一份数据,如果指定routingKey=into,或=warning,交换机(X)只会把消息发到Q2队列。

img

Topic主题模式

topics(主题)模式跟routing路由模式类似,只不过路由模式是指定固定的路由键 routingKey,而主题模式是可以模糊匹配路由键 routingKey,类似于SQL中 = 和 like 的关系。

没匹配routingKey的消息将会被丢弃。

* 代表一个词,# 代表零个或多个

img

RPC模式

与上面其他5种所不同之处,该模式是拥有请求/回复的。也就是有响应的,上面5种都没有。

RPC是指远程过程调用,也就是说两台服务器A,B,一个应用部署在A服务器上,想要调用B服务器上应用提供的处理业务,处理完后然后在A服务器继续执行下去,把异步的消息以同步的方式执行。

一般都不会选用 RabbitMQ 的 RPC 模式,因为有专门进行远程调用的框架如 Dubbo,用起来会更加方便。

img

常见命令

  • rabbitmqctl list_queues:查看所有队列信息
  • rabbitmqctl stop_app:关闭应用
  • rabbitmqctl start_app:启动应用
  • rabbitmqctl reset:从管理数据库中移除所有数据,例如配置过的用户和vhost,删除所有持久化信息
  • rabbitmqctl force_reset:作用和rabbitmqctl reset一样,区别是无条件重置节点,不管当前管理数据库状态以及集群的配置。如果数据库或者集群配置发生错误才使用这个最后的手段
  • rabbitmqctl status:节点状态
  • rabbitmqctl add_user username password:添加用户
  • rabbitmqctl list_users:列出所有用户
  • rabbitmqctl list_user_permissions username:列出用户权限
  • rabbitmqctl change_password username newpassword:修改密码
  • rabbitmqctl add_vhost vhostpath:创建虚拟主机
  • rabbitmqctl list_vhosts:列出所有虚拟主机
  • rabbitmqctl set_user_tags username administrator : 设置管理员角色
  • rabbitmqctl set_permissions -p vhostpath username “." ".” “.*”:设置用户权限
  • rabbitmqctl list_permissions -p vhostpath:列出虚拟主机上的所有权限
  • rabbitmqctl clear_permissions -p vhostpath username:清除用户权限
  • rabbitmqctl -p vhostpath purge_queue blue:清除队列里的消息
  • rabbitmqctl delete_user username:删除用户
  • rabbitmqctl delete_vhost vhostpath:删除虚拟主机

集群方面:

  • rabbitmqctl cluster_status:查看集群状态
  • rabbitmqctl forget_cluster_node rabbit@node1:移除指定节点,注意移除的节点必须是从节点,在移除前必须要关掉从节点
  • rabbitmqctl join_cluster rabbit@node3:将节点加入到指定集群中
  • rabbitmqctl change_cluster_node_type ram:修改node1节点的节点类型从dist改为ram
  • rabbitmqctl rename_cluster_node ‘rabbit@node1’ ‘rabbit@node1update’:重命名节点
  • rabbitmqctl update_cluster_nodes rabbit@node1:更新节点数据,指定与哪个节点同步
  • rabbitmqctl force_boot:强制启动节点

启动

  • rabbitmq-server -detached 后台启动

集群搭建

RabbitMQ 集群对延迟非常敏感,应当只在本地局域网内使用。在广域网中不应该使用集群。

普通集群

普通集群,又称为标准集群,具备以下特征:

  • 在集群的各个节点间共享部分数据,包括交换机、队列元信息,但不包括队列中的消息
  • 当访问集群某节点时,如果队列不在该节点,会从数据所在节点传递到当前节点并返回
  • 队列所在节点如果宕机,队列中的消息就会丢失,因此普通集群只是提高了并发能力,并未实现高可用

使用docker搭建rabbitmq集群

docker pull rabbitmq:3.9.15-management
# 运行5672
docker run -d --name rabbitmq5672 \
-p 5672:5672 -p 15672:15672 \
-v /Users/lzq/docker/rabbitmq5672/data:/var/lib/rabbitmq \
-v /Users/lzq/docker/rabbitmq5672/log:/var/log/rabbitmq \
-v /Users/lzq/docker/rabbitmq5672/rabbitmq_delayed_message_exchange-3.9.0.ez:/opt/rabbitmq/plugins/rabbitmq_delayed_message_exchange-3.9.0.ez \
--hostname rabbitmq5672 \
-e RABBITMQ_DEFAULT_VHOST=localhost \
-e RABBITMQ_DEFAULT_USER=root \
-e RABBITMQ_DEFAULT_PASS=root \
-e RABBITMQ_LOGS=/var/log/rabbitmq/rabbitmq.log \
--net=my_net \
-v /etc/localtime:/etc/localtime \
rabbitmq:3.9.29-management

# 运行5673
docker run -d --name rabbitmq5673 \
-p 5673:5672 -p 15673:15672 \
-v /Users/lzq/docker/rabbitmq5673/data:/var/lib/rabbitmq \
-v /Users/lzq/docker/rabbitmq5673/log:/var/log/rabbitmq \
-v /Users/lzq/docker/rabbitmq5673/rabbitmq_delayed_message_exchange-3.9.0.ez:/opt/rabbitmq/plugins/rabbitmq_delayed_message_exchange-3.9.0.ez \
--hostname rabbitmq5673 \
-e RABBITMQ_DEFAULT_VHOST=localhost  \
-e RABBITMQ_DEFAULT_USER=root \
-e RABBITMQ_DEFAULT_PASS=root \
-e RABBITMQ_LOGS=/var/log/rabbitmq/rabbitmq.log \
--net=my_net \
-v /etc/localtime:/etc/localtime \
rabbitmq:3.9.29-management

# 运行5674
docker run -d --name rabbitmq5674 \
-p 5674:5672 -p 15674:15672 \
-v /Users/lzq/docker/rabbitmq5674/data:/var/lib/rabbitmq \
-v /Users/lzq/docker/rabbitmq5674/log:/var/log/rabbitmq \
-v /Users/lzq/docker/rabbitmq5674/rabbitmq_delayed_message_exchange-3.9.0.ez:/opt/rabbitmq/plugins/rabbitmq_delayed_message_exchange-3.9.0.ez \
--hostname rabbitmq5674 \
-e RABBITMQ_DEFAULT_VHOST=localhost  \
-e RABBITMQ_DEFAULT_USER=root \
-e RABBITMQ_DEFAULT_PASS=root \
-e RABBITMQ_LOGS=/var/log/rabbitmq/rabbitmq.log \
--net=my_net \
-v /etc/localtime:/etc/localtime \
rabbitmq:3.9.29-management

进入第一个节点

docker exec -it rabbitmq5672 bash

rabbitmqctl stop_app
rabbitmqctl reset
rabbitmqctl start_app
exit

进入第二个节点

docker exec -it rabbitmq5673 bash

rabbitmqctl stop_app
rabbitmqctl reset
rabbitmqctl join_cluster rabbit@rabbitmq5672
rabbitmqctl start_app
exit

进入第三个节点

docker exec -it rabbitmq5674 bash

rabbitmqctl stop_app
rabbitmqctl reset
rabbitmqctl join_cluster rabbit@rabbitmq5672
rabbitmqctl start_app
exit

**rabbitmqctl join_cluster {cluster_node} [–ram]**表示将节点加入指定集群中。在这个命令执行前需要停止RabbitMQ应用并重置节点。参数“–ram”表示同步 rabbit@rabbitmq01的内存节点,忽略此参数默认为磁盘节点。

rabbitmqctl join_cluster rabbit@rabbitmq5672

移除节点

rabbitmqctl stop_app
rabbitmqctl reset
rabbitmqctl start_app

rabbitmqctl forget_cluster_node rabbit@rabbitmq5674


rabbitmqctl join_cluster rabbit@rabbitmq5672
rabbitmqctl forget_cluster_node --offline rabbit@rabbitmq5672

负载均衡

docker pull haproxy 

docker run -d \
-p 5671:5671 \
-p 15671:15671 \
-p 5670:5670 \
-p 15670:15670 \
--net=my_net \
--hostname haproxy \
--name haproxy \
-v /Users/lzq/docker/haproxy/haproxy.cfg:/usr/local/etc/haproxy/haproxy.cfg:ro haproxy 

在docker的宿主机上编写haproxy.cfg文件如下

# 全局配置
global
   #定义全局的syslog服务器
    log 127.0.0.1 local0 info
   #每个haproxy进程可以接受的最多并发数
    maxconn 4096
   #让haproxy以守护进程的方式工作于后台 
    daemon
#默认参数的配置部分
defaults
        log global
        #工作模式 http ,tcp 是 4 层,http是 7 层
        mode tcp
        option tcplog
        option dontlognull
        #健康检查。3次连接失败就认为服务器不可用,主要通过后面的check检查
        retries 3
        maxconn 2000
        #ha服务器与后端服务器连接超时时间
        timeout connect 5s
        #客户端超时
        timeout client 120s
        #服务端超时
        timeout server 120s

listen rabbitmq_cluster
		#监听地址
        bind :5671
        #工作模式
        mode tcp
        #负载均衡方法轮询
        balance roundrobin
        server rabbit-node01 10.60.57.62:5672 check inter 5000 rise 2 fall 3 weight 1
        server rabbit-node02 10.60.57.62:5673 check inter 5000 rise 2 fall 3 weight 1
        server rabbit-node03 10.60.57.62:5674 check inter 5000 rise 2 fall 3 weight 1

listen rabbitmq_manager
		#监听地址
        bind :15671
        #工作模式
        mode tcp
        #负载均衡方法轮询
        balance roundrobin
        server rabbit-node01 10.60.57.62:15672 check inter 5000 rise 2 fall 3 weight 1
        server rabbit-node02 10.60.57.62:15673 check inter 5000 rise 2 fall 3 weight 1
        server rabbit-node03 10.60.57.62:15674 check inter 5000 rise 2 fall 3 weight 1

镜像集群

跟普通集群模式相比,该模式加入镜像队列 ,镜像模式有以下特征:

  • 镜像队列结构是一主多从,即一个主节点和多个镜像节点。
  • 所有操作都由主节点完成,然后同步到镜像节点。
  • 如果主节点宕机,镜像节点可以接替成为新的主节点,确保高可用性。但在主从同步完成之前,宕机可能导致数据丢失。
  • 镜像模式不具备负载均衡功能,因为所有操作都由主节点完成。然而,不同队列可以有不同的主节点,这可以提高系统的吞吐量。

镜像模式通过数据同步和主节点切换提供了更高的可用性和数据冗余,适合对数据可用性有要求较高的应用场景

镜像模式配置

有三种模式,使用不同的参数来定义镜像策略

exactly 模式

可以精确控制队列在集群中的副本数量。例如:如果将ha-params设置为2,表示每个队列将有2个副本,启动一个是主节点,另一个是镜像节点。如果集群中的节点数不足以维护所需的副本数,队列将被镜像到所有节点。如果有足够多的节点,但其中某些节点出现故障,将在其他节点上创建新的镜像。

配置命令如下:

#进入任意一个rabbitmq节点,执行
rabbitmqctl set_policy ha-two "^two\." '{"ha-mode":"exactly","ha-params":2,"ha-sync-mode":"automatic"}'
  • rabbitmqctl set_policy:用于设置策略的RabbitMQ命令。
  • ha-two:策略的名称,可以自定义。
  • “^two.”:用正则表达式匹配队列的名称,这个策略将应用于所有以 “two.” 开头的队列。
  • ‘{“ha-mode”:“exactly”,“ha-params”:2,“ha-sync-mode”:“automatic”}’:策略的具体配置,包括:
    • “ha-mode”:“exactly”:指定策略的模式,这里是 “exactly”,表示要设置队列的副本数量。
    • “ha-params”:2:指定副本的数量,这里设置为2,表示一个主副本和一个镜像副本。
    • “ha-sync-mode”:“automatic”:同步策略,这里设置为 “automatic”,表示新加入的镜像节点会同步主节点中的所有消息,以确保消息的一致性。
all 模式

队列将在集群中的所有节点之间进行镜像,队列将镜像到任何新加入的节点。

将队列镜像到所有的节点会增加额外的压力,包括网络I/O、磁盘I/O和磁盘空间的使用。因此,不建议使用all模式

配置命令如下:

#进入任意一个rabbitmq节点,执行
rabbitmqctl set_policy ha-all "^all\." '{"ha-mode":"all"}'
  • ha-all:策略的名称,可以自定义。
  • “^all.”:用正则表达式匹配队列的名称,这个策略将应用于所有以 “all.” 开头的队列。
  • ‘{“ha-mode”:“all”}’:策略的具体配置,包括:
    • “ha-mode”:“all”:指定策略的模式,这里是 “all”,表示要将队列镜像到集群中的所有节点。
nodes 模式

可以明确指定队列应该创建在哪些节点上。如果执行的节点全部存在,队列将在这些节点说上创建。如果指定的节点在集群中存在,但是某些节点不可用,队列将在当前客户端连接到的节点上创建。如果指定的节点在集群中不存在,可能会引发异常。

配置命令如下:

#进入任意一个rabbitmq节点,执行
rabbitmqctl set_policy ha-nodes "^nodes\." '{"ha-mode":"nodes","ha-params":["rabbit@rabbitmq5672", "rabbit@rabbitmq5673"]}'
  • rabbitmqctl set_policy:用于设置策略的RabbitMQ命令。
  • ha-nodes:策略的名称,可以自定义。
  • “^nodes.”:用正则表达式匹配队列的名称,这个策略将应用于所有以 “nodes.” 开头的队列。
  • ‘{“ha-mode”:“nodes”,“ha-params”:[“rabbit@nodeA”, “rabbit@nodeB”]}’:策略的具体配置,包括:
    • “ha-mode”:“nodes”:指定策略的模式,这里是 “nodes”,表示要指定队列创建在哪些节点上。
    • “ha-params”:[“rabbit@rabbitmq5672”, “rabbit@rabbitmq5673”]:指定了队列应该创建在哪些节点上

进入任意一个rabbitmq节点,执行

rabbitmqctl set_policy -p localhost ha "^" '{"ha-mode":"all","ha-sync-mode":"automatic"}'
rabbitmqctl set_policy -p /study ha "^" '{"ha-mode":"all","ha-sync-mode":"automatic"}'

可以设置镜像队列,"^"表示匹配所有队列,-p表示针对当前vhost,即所有队列在各个节点上都会有备份。在集群中,只需要在一个节点上设置镜像队列,设置操作会同步到其他节点。

注意:例如:队列A存在主节点rabbit5672,镜像节点rabbit5673、rabbit5674。如果rabbit5672下线,rabbit5673和rabbit5674会升成主节点,当rabbit5672节点重新上线后,会变为镜像节点。

仲裁队列集群

尽管镜像模式能够做到主从复制,但是并不是强一致的,因此可能还是会导致数据的丢失。

仲裁队列是 3.8 版本以后才有的新功能,用来替代镜像队列,属于主从模式,支持基于 Raft 协议强一致的主从数据同步。

具有以下特点:

  • 与镜像队列一样,都是主从模式,支持主从数据同步
  • 使用非常简单,没有复杂的配置
  • 主从同步基于Raft协议,强一致

添加仲裁队列的方式非常简单,只需要在创建队列的使用指定队列的类型为 Quorum 即可

生产者确认

confirm模式

此模式是作用在生产者端的,开启了这个模式就可以知道消息有没有发送到交换机上,不管有没有发送到都会触发回调方法。

publisher-confirm-type: correlated
		rabbitTemplate.setConfirmCallback((correlationData, ack, cause) -> {
			System.out.println("confirm,correlationData:" + correlationData);
			System.out.println("confirm,ack:" + ack);
			System.out.println("confirm,cause:" + cause);
		});

returns模式

作用于生产者端的,这个模式iuu是知道消息有没有发送到对应的队列上,如果没有发送到了对接的队列才会触发回调方法

#设置交换机确认发布模式,默认为禁用
publisher-confirm-type: correlated
#退回消息
publisher-returns: true
		rabbitTemplate.setReturnsCallback(returned -> {
			System.out.println("returnedMessage,getMessage:" + returned.getMessage());
			System.out.println("returnedMessage,getExchange:" + returned.getExchange());
			System.out.println("returnedMessage,getRoutingKey:" + returned.getRoutingKey());
			System.out.println("returnedMessage,getReplyCode:" + returned.getReplyCode());
			System.out.println("returnedMessage,getReplyText:" + returned.getReplyText());
		});

死信队列

死信队列,英文缩写:DLX 。DeadLetter Exchange(死信交换机),当消息成为Dead message后,可以被重新发送到另一个交换机,这个交换机就是DLX。

消息成为死信的三种情况

  • 队列消息数量达到限制,比如队列最大只能存储10条消息,但是发送了11条消息,根据先进先出,最先发送的消息会进入死信队列
  • 消费者拒绝消费消息,basicNack/basicReject,并且不把消息重新放入原目标队列,requeue=false;
  • 原队列存在消息过期设置,消息达到超时时间未被消费

死信消息的三种处理方式

  • 丢弃。如果不是很重要,可以选择丢弃
  • 记录死信入库。然后做后续要业务的分析或处理
  • 通过死信队列也有负责监听死信的应用程序进行处理

队列绑定死信交换机:

给队列设置参数: x-dead-letter-exchange 和 x-dead-letter-routing-key

Map<String, Object> arguments = new HashMap<>();
arguments.put("x-dead-letter-exchange", exchange_dead);
arguments.put("x-dead-letter-routing-key", routing_dead_routing_key);
return new Queue(queue_dead, true, false, false, arguments);

延迟队列

延迟队列存储的对象肯定是对应的延时消息,所谓”延时消息”是指当消息被发送以后,并不想让消费者立即拿到消息,而是等待指定时间后,消费者才拿到这个消息进行消费。

在RabbitMQ中并未提供延迟队列功能,但是可以使用:TTL+死信队列 组合实现延迟队列的效果。

延迟插件

没有安装延迟插件报错如下:

Caused by: com.rabbitmq.client.ShutdownSignalException: connection error; protocol method: #method<connection.close>(reply-code=503, reply-text=COMMAND_INVALID - invalid exchange type 'x-delayed-message', class-id=40, method-id=10)
	at com.rabbitmq.utility.ValueOrException.getValue(ValueOrException.java:66)
	at com.rabbitmq.utility.BlockingValueOrException.uninterruptibleGetValue(BlockingValueOrException.java:36)
	at com.rabbitmq.client.impl.AMQChannel$BlockingRpcContinuation.getReply(AMQChannel.java:505)
	at com.rabbitmq.client.impl.AMQChannel.privateRpc(AMQChannel.java:296)
	at com.rabbitmq.client.impl.AMQChannel.exnWrappingRpc(AMQChannel.java:144)
	... 133 common frames omitted

先确定docker中rabbitmq的版本号,如果镜像中没有版本号,使用命令docker inspect rabbitmq:management查看RABBITMQ_VERSION字段。根据当前版本下载延迟队列插件。

下载RabbitMQ延迟插件:https://github.com/rabbitmq/rabbitmq-delayed-message-exchange/releases

rabbitmq-delayed-message-exchange插件为交换机提供了新的类型:x-delayed-message

开启延迟插件命令:

#进入容器中执行
rabbitmq-plugins enable rabbitmq_delayed_message_exchange

在管理页面上Exchanges新增页面能够看到x-delayed-message类型后即可

插件的禁用要慎重,以下方式可以实现将插件禁用,但是注意如果此时还有延迟消息未消费,那么禁掉此插件后所有的未消费的延迟消息将丢失。

rabbitmq-plugins disable rabbitmq_delayed_message_exchange

RabbitMQ脑裂

所谓的脑裂问题,就是在多集群中节点与节点之间失联,都认为对方出现故障,而自身裂变为独立的个体,那么久出现了抢夺对方的资源,争抢启动,至此就发生了事故,RabbitMQ

Spring-RabbitMQ并发消费

RabbitListenerContainerFactory的代码如下:

	@Bean
	public RabbitListenerContainerFactory<?> rabbitListenerContainerFactory(ConnectionFactory connectionFactory) {
		SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
		factory.setConnectionFactory(connectionFactory);
		factory.setMessageConverter(new Jackson2JsonMessageConverter());
		factory.setAcknowledgeMode(AcknowledgeMode.MANUAL);

		//设置线程并发数,默认1
		factory.setConcurrentConsumers(2);
		//最大线程数,默认null
		factory.setMaxConcurrentConsumers(5);
		//设置本地缓存消息数,默认250
		factory.setPrefetchCount(1);
		//连续成功处理消息数,进行扩容,默认10
		factory.setConsecutiveActiveTrigger(3);
		//连续空闲数,进行缩容,默认10
		factory.setConsecutiveIdleTrigger(3);
		//默认等待队列超时时间,默认1000ms
		factory.setReceiveTimeout(1000L);
		return factory;
	}

concurrentConsumers

concurrentConsumers默认为1,即每个Listener容器静静开启一个线程去处理消息

maxConcurrentConsumers

	private final class AsyncMessageProcessingConsumer implements Runnable {
	
    @Override // NOSONAR - complexity - many catch blocks
		public void run() { // NOSONAR - line count
			if (!isActive()) {
				this.start.countDown();
				return;
			}
      
      try {
				initialize();
				while (isActive(this.consumer) || this.consumer.hasDelivery() || !this.consumer.cancelled()) {
					mainLoop();
				}
			}
      
    }
private void mainLoop() throws Exception { // NOSONAR Exception
			try {
				if (SimpleMessageListenerContainer.this.stopNow.get()) {
					this.consumer.forceCloseAndClearQueue();
					return;
				}
				boolean receivedOk = receiveAndExecute(this.consumer); // At least one message received
				if (SimpleMessageListenerContainer.this.maxConcurrentConsumers != null) {
					checkAdjust(receivedOk);
				}
				long idleEventInterval = getIdleEventInterval();
				if (idleEventInterval > 0) {
					if (receivedOk) {
						updateLastReceive();
					}
					else {
						long now = System.currentTimeMillis();
						long lastAlertAt = SimpleMessageListenerContainer.this.lastNoMessageAlert.get();
						long lastReceive = getLastReceive();
						if (now > lastReceive + idleEventInterval
								&& now > lastAlertAt + idleEventInterval
								&& SimpleMessageListenerContainer.this.lastNoMessageAlert
								.compareAndSet(lastAlertAt, now)) {
							publishIdleContainerEvent(now - lastReceive);
						}
					}
				}
			}

prefetchCount

每个消费者会在MQ预取一些消息放入内存的LinkedBlockingQueue中进行消费,这个值越高,消息传递的越快,单非顺序处理消息的风险更高。如果ack模式为none,则忽略。将增加此值以匹配txSize或messagePerAck。从2.0开始默认为250;设置为1将还原为以前的行为。

不过在在有些情况下,尤其是处理速度比较慢的大消息,消息可能在内存中大量堆积,消耗大量内存,以及对于一些严格要求顺序的消息,prefetchCount应当设置为1

搭建环境常用命令

linux中以守护程序的形式在后台启动

rabbitmq-server -detached

新建一个用户

rabbitmqctl add_user root root

创建一个虚拟环境

rabbitmqctl add_vhost /study

设置管理员角色

rabbitmqctl set_user_tags root administrator

设置权限

rabbitmqctl set_permissions -p /study root “." ".” “.*”

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

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

相关文章

心学从0开始学习rust-十万个为什么篇章(持续更新篇章)

问答环节 1.const x 1;和let x 1有何区别呢&#xff0c;const申请的是全局变量所以会一直有效对吗&#xff1f; const 声明的常量具有全局作用域&#xff0c;但它们不能直接在函数内部声明。常量通常用于定义整个程序中使用的值&#xff0c;如配置常量或数学常量。 let 声明…

并发执行一定比串行执行快吗?

一、多线程的两个主要方向 并发:多线程之间各自执行各自的互不影响 并行:多线程之间互相竞争资源&#xff0c;进行读写的时候可能会产生相互覆盖 二、上下文切换 1.什么是上下文切换 在多线程编程中一般线程的个数都大于cpu的核心数,而一个cpu核心在任意时刻都只能被一个线…

ElasticSearch实战之项目搜索高亮

文章目录 1. 前情配置2、数据操作2.1 操作API2.2 数据入库 3. 高亮搜索3.1 方法封装3.2 高亮搜索 1. 前情配置 为满足ElasticSearch可在项目中实现搜索高亮&#xff0c;我们需要先做一些前情配置 导入ElasticSearch依赖 <dependency><groupId>org.springframewor…

怎么设置启用远程桌面? 如何让外网电脑远程本地内网?

如何远程控制电脑&#xff1f;最简单实用的方案是开启电脑系统自带的远程桌面功能&#xff0c;如果涉及跨网、内外网互通&#xff0c;可以同时用快解析内网映射外网。下面是方案的具体实施步骤&#xff0c;供大家参考。 怎么打开设置启用远程桌面&#xff1f; 1.在目标需要远…

【详细讲解CentOS常用的命令】

&#x1f308;个人主页: 程序员不想敲代码啊 &#x1f3c6;CSDN优质创作者&#xff0c;CSDN实力新星&#xff0c;CSDN博客专家 &#x1f44d;点赞⭐评论⭐收藏 &#x1f91d;希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出指正&#xff0c;让我们共…

android 创建module

文章目的&#xff1a; 快速创建module并使用 创建步骤&#xff1a; 1 创建module 2 修改module下的build.gradle文件 3 修改清单文件中MainActivity属性&#xff0c;否则APP会因为有多个启动界面而崩溃 4 在主项目build.gradle引用该object Module 至此&#xff0c;可在APP中…

排序(五)——非比较排序+排序总结

1.非比较排序 我们前面讲的排序算法都是通过比较大小来进行排序的&#xff0c;他们都是比较排序。 像基数排序、计数排序和桶排序等都不是通过比较大小来排序的&#xff0c;是非比较排序&#xff0c;在这里我们讲一下其中的计数排序和基数排序&#xff0c;而桶排序实现起来太…

在k8s 中部署有状态服务MongoDB高可用集群详解(附带镜像)

&#x1f407;明明跟你说过&#xff1a;个人主页 &#x1f3c5;个人专栏&#xff1a;《Kubernetes航线图&#xff1a;从船长到K8s掌舵者》 &#x1f3c5; &#x1f516;行路有良友&#xff0c;便是天堂&#x1f516; 目录 一、前言 1、k8s简介 2、MongoDB介绍 3、为什么要…

网络爬虫软件学习

1 什么是爬虫软件 爬虫软件&#xff0c;也称为网络爬虫或网络蜘蛛&#xff0c;是一种自动抓取万维网信息的程序或脚本。它基于一定的规则&#xff0c;自动地访问网页并抓取需要的信息。爬虫软件可以应用于大规模数据采集和分析&#xff0c;广泛应用于舆情监测、品牌竞争分析、…

【 书生·浦语大模型实战营】作业(五):LMDeploy 量化部署

【 书生浦语大模型实战营】作业&#xff08;五&#xff09;&#xff1a;LMDeploy 量化部署 &#x1f389;AI学习星球推荐&#xff1a; GoAI的学习社区 知识星球是一个致力于提供《机器学习 | 深度学习 | CV | NLP | 大模型 | 多模态 | AIGC 》各个最新AI方向综述、论文等成体系…

Vue2之组件通信(爆肝)

大家有什么想看的可以在评论区留言&#xff0c;我尽量满足&#xff0c;感谢大家&#xff01; 组件通信是vue中一个非常重要的内容&#xff0c;我们需要掌握好组件通信&#xff0c;那么让我为大家介绍几种组件通信的方式吧&#xff01; 一、props 这是父传子的方式&#xff0…

FFmpeg合并音视频文件操作备忘(mac版)

利用NDM嗅探插件从B站下载下来的文件是音视频分开的&#xff0c;用剪辑软件合并时发现导出时文件都特别大&#xff0c;于是使用FFmpeg处理 环境&#xff1a; MBP M1芯片版 系统 macOS Sonama 14.4.1 操作步骤&#xff1a; 一、官方下载链接&#xff1a;https://evermeet.cx/…

MySQL 锁机制全面解析

目录 1. MySQL的锁类型1.1 全局锁1.2 表锁1.3 行锁1.4 共享锁&#xff08;读锁&#xff09;1.5 排它锁&#xff08;写锁&#xff09;1.6 死锁 2 乐观锁和悲观锁2.1 乐观锁2.2 悲观锁 3 意向锁4 间隙锁5 临键锁6. 事务隔离级别对锁的影响6.1 读未提交&#xff08;Read Uncommitt…

npm内部机制与核心原理

npm 的核心目标&#xff1a; Bring the best of open source to you, your team and your company. npm 最重要的任务是安装和维护开源库。 npm 安装机制与背后思想 npm 的安装机制非常值得探究。Ruby 的 Gem&#xff0c;Python的pip都是全局安装机制&#xff0c;但是npm的安装…

️️️Vue3+Element-Plus二次封装一个可定制化的table组件

前言 为什么需要二次封装 开发后台管理系统,会接触到很多表格和表单,一但表格表单多起来,仅仅只需要一小部分改变&#xff0c;都需要在中重写一大堆代码,许多重复逻辑,我们可以把重复逻辑抽离出来二次封装一个组件 使用,减少在开发中需要编写的代码。 为什么需要定制化 每个…

【AI工具之Prezo如何自动生成PPT操作步骤】

先说优缺点&#xff1a; 最大的优点就是免费&#xff08;但说实话功能和体验方面很弱&#xff09;支持中文提问&#xff08;最好用英文&#xff09;&#xff0c;智能生成图文&#xff08;但是只能生成英文内容&#xff09;可以AI生成图片&#xff0c;图片很精美酷炫&#xff0…

数据可视化(四):Pandas技术的高级操作案例,豆瓣电影数据也能轻松分析!

Tips&#xff1a;"分享是快乐的源泉&#x1f4a7;&#xff0c;在我的博客里&#xff0c;不仅有知识的海洋&#x1f30a;&#xff0c;还有满满的正能量加持&#x1f4aa;&#xff0c;快来和我一起分享这份快乐吧&#x1f60a;&#xff01; 喜欢我的博客的话&#xff0c;记得…

(八)Pandas窗口数据与数据读写 学习简要笔记 #Python #CDA学习打卡

一. 窗口数据(Window Functions) Pandas提供了窗口函数(Window Functions)用于在数据上执行滑动窗口操作&#xff0c;可以对数据进行滚动计算、滑动统计等操作。需要注意的是&#xff0c;在使用窗口函数时&#xff0c;需要根据实际需求选择合适的窗口大小和窗口函数&#xff0…

硬件设备杂记——12G SDI及 AES67/EBU

常见的 SDI线缆规格&#xff0c;HD-SDI又被称为1.5G-SDI&#xff0c;具体参数以秋叶原的参数为例 AES67/EBU 目前音频网络标准主要集中在OSI网络体系的第二层和第三层。 第二层音频标准的弊端在于构建音频网络时需要专用的交换机&#xff0c;无法利用现有的以太网络&#xff0c…

布局香港之零售中小企篇 | 传承之味,迈向数字化经营的时代

随着内地与香港两地经贸合作日渐紧密&#xff0c;越来越多内地消费品牌将目光投向香港这片充满机遇的热土&#xff0c;纷纷入驻香港市场。「北店南下」蔚然成风&#xff0c;其中不乏已在内地市场深耕多年的传统老字号。数字化经营时代&#xff0c;老字号焕新刻不容缓&#xff0…