Pulsar官方文档学习笔记——消息机制
pulsar
基于3.x最新官方文档学习记录
概念与架构
典型的推送订阅模式。生产者发送消息,消费者订阅topic消费信息并回应ACK。订阅创建后,Pulsar会保留所有消息。仅消息被所有订阅 成功消费了才会丢弃(可以配置消息保留机制保留一定量) 而且还可以重新给broker投递重新消费
消息
消息是pulsar传递的基本单元。有如下元素组成
组成成分 | 描述 |
---|---|
value/data payload | 消息携带的数据 |
key | 消息的键或分区键。消息可以用键标记,对于topic压缩有用 |
properties | 消息属性。key-value对的map组成 |
producer name | 生产者名 |
topic name | topic名称 |
schema version | 生产消息所用的schema版本 |
sequence ID | 每个消息在自己的topic里都有一个有序的序列id,由生产者赋值。ID可以用于去重。如果brokerDeduplicationEnabled设置为true。那么每个消息的sequencee id在主题里是唯一的 |
message id | bookies赋值的,持久化的消息id。在pulsar集群中是唯一的 |
publish time | 消息发布时间戳,生产者自动赋值的 |
event time | 一个应用程序附加到消息的可选时间戳信息。(业务一半也很少用,自己在消息里用一个字段就完了) |
消息有默认大小5MB。可以通过配置修改
-
In the
broker.conf
file.# The max size of a message (in bytes). maxMessageSize=5242880
-
In the
bookkeeper.conf
file.# The max size of the netty frame (in bytes). Any messages received larger than this value are rejected. The default value is 5 MB. nettyMaxFrameSizeBytes=5253120
响应
当应用消费并处理完消息后应该回复一个ack代表改消息消费成功。消息会在所有订阅消费完后删除。当然可以配置消息保留策略保留一定量的消息。对于批量的信息,也可以批量ACK
ack方式
- 单独确认
仅确认选择的消息
consumer.acknowledge(msg);
-
累计确认
确认后,该消息之前的消息不会再消费到。但是注意 这个不能用再shared和key_shared 订阅类型。因为这种订阅类型下有多个消费者
consumer.acknowledgeCumulative(msg);
NACK
NACK机制,消费者可以通知broker自己没有处理该消息,需要重新消费。broker会将该消息重新投递给consumer消费
- 在独占和故障转移订阅下,只能nack最近一条消息
- 在share和key_shared下可以选择nack某一条消息
对有序订阅类型的订阅(独占,key_shared) nack会导致乱序
可以设置重新投递次数以及投递延迟
例如配置延时在1s~60s
Consumer<byte[]> consumer = pulsarClient.newConsumer().topic(topic).subscriptionName("sub-negative-ack").subscriptionInitialPosition(SubscriptionInitialPosition.Earliest).negativeAckRedeliveryBackoff(MultiplierRedeliveryBackoff.builder().minDelayMs(1000).maxDelayMs(60 * 1000).multiplier(2) // 重试延迟乘数.build()).subscribe();
消息重新投递和投递延迟如下
Redelivery count | Redelivery delay |
---|---|
1 | 1 seconds |
2 | 2 seconds |
3 | 4 seconds |
4 | 8 seconds |
5 | 16 seconds |
6 | 32 seconds |
7 | 60 seconds |
8 | 60 seconds |
如果启用了批处理,那么一批数据都会重新投递
ack timeout
默认关闭。超时机制,设置客户端跟踪 消费的时间,如果超过时间限制,会给broker回nack触发重新 投递
可以配合重新投递的设置使用
consumer.ackTimeout(10, TimeUnit.SECOND).ackTimeoutRedeliveryBackoff(MultiplierRedeliveryBackoff.builder().minDelayMs(1000).maxDelayMs(60 * 1000).multiplier(2).build());
The message redelivery behavior should be as follows.
Redelivery count | Redelivery delay |
---|---|
1 | 10 + 1 seconds |
2 | 10 + 2 seconds |
3 | 10 + 4 seconds |
4 | 10 + 8 seconds |
5 | 10 + 16 seconds |
6 | 10 + 32 seconds |
7 | 10 + 60 seconds |
8 | 10 + 60 seconds |
注意:
-
如果启用批处理,那么一批数据都会重新投递
-
自己单独NACK比超时NACK更可取。超时值不好设置,容易重复消费不需要的消息
Retry letter topic
重试队列 用来存储消费失败的消息,并且稍后重试消费。用户可以自定义重试延迟时间。重试队列重试次数超过阈值后,消息就回到死信队列了。
重试队列消息有一些特殊proerties
REAL_TOPIC = persistent://public/default/my-topic # 源topic
ORIGIN_MESSAGE_ID = 1:0:-1:0 # 原始Message ID
RECONSUMETIMES = 6 # 重试次数
DELAY_TIME = 3000 # 重试间隔
重试队列与延迟投递目的是不一样的,重试队列主要是为了处理失败的消息。延迟投递则是想要在指定时间消费消息
重试队列默认名字<subscriptionname>-RETRY
,官方不推荐用。因为如果同一命名空间下的topicx消费有多相同订阅名,那么不同topic他的重试队列名字会是一样的。会导致互相消费
重试队列操作
Map<String, String> customProperties = new HashMap<String, String>();
customProperties.put("custom-key-1", "custom-value-1");
customProperties.put("custom-key-2", "custom-value-2");
consumer.reconsumeLater(msg, customProperties, 3, TimeUnit.SECONDS);
比起nack。重试队列更适合大量重新消费的场景 。重试丢列的消费会持久化到bookie,而nack只会缓存到客户端
dead letter topic
死信队列里一般存储了消费失败的消息。客户可以自定义如何处理这些失败的消息。例如存储到ES里供后面查询,指标监控等
Consumer<byte[]> consumer = pulsarClient.newConsumer(Schema.BYTES).topic("my-topic").subscriptionName("my-subscription").subscriptionType(SubscriptionType.Shared).deadLetterPolicy(DeadLetterPolicy.builder().maxRedeliverCount(maxRedeliveryCount).deadLetterTopic("my-dead-letter-topic-name").build()).subscribe();
死信队列默认格式为<subscriptionname>-DLQ
与重试队列一样,建议是自定义topic名字
压缩
pulsar支持消息压缩。lz4 zlib zstd snappy都行。比较推荐启用
batching
批处理开启后,生产者会累计发送 。此时backlog siez 代表该批次总数而不是消息总数。批次也会作为一个单元进行存储。
一般来说,该批次所有消息被确认成功则该批次 确认成功,否则认为失败进行重新投。但pulsar 2.6后就有批量确认。可以将当前索引之前的消息 都Ack了。
chunking
分块,Pulsar可以通过分块来处理大消息。当消息分块启用(对持久化topic才生效),当消息超过指定大小 maxMessageSize
消息将会被如下处理。消息结尾默认为OFF
- 将源消息拆分,并将他们与分块元数据(chunked metadata)按顺序发送
- broker会将分块的消息存储在一个ledgere中。并用chunkedMessageRate参数来记录该主题分块消息速率。
- 消费者会缓存所有消息的分块并聚合到接收队列中
- 从接受队列消费消息
注意:
分块和批处理不能同时开启
消费示例
单个消费者消费连续 分块的消息
单个消费者消费乱序分块的消息
Topic
pulsar主题是将数据组织成流的单元。名称为一个特定结构的url
{persistent|non-persistent}://tenant/namespace/topic
Topic name component | Description |
---|---|
persistent / non-persistent | 标识主题类型,pulsar支持两种主题,持久化的和非持久化的。默认是持久化的 |
tenant | 租户名,pulsar多租户概念 |
namespace | 命名空间,每个租户都有多个命名空间 |
topic | topic名字,没什么别的含义 |
pulsar客户端如果生产或消费一个不存在的topic。pulsar会尝试建立。 但一般不推荐,Pulsar会变得不好维护。最好是部署脚本啥的提前键好,方便统计维护topic
namespace
命名空间是租户下对topic的逻辑分组
Subscriptions
订阅名。每个消费者去订阅topic的时候都需要有个订阅名(如果没有puslar也会默认创建一个)
订阅类型
-
独占exclusive
默认的消费方式。消费者独占该订阅名的消费
-
共享shared
多个消费者可以使用一个订阅名消费该topic。适合需要动态扩容的消费业务
-
灾备failover
主消费者断开后,消息的消费会交给队列中下一个消费者。对于分区的topic。新消费者可能会消费乱序
对于分区的topic.broker会按照优先级和消费者name字典序进行排序。代理尝试将分区平均分给具有最高优先级的消费者。
如果分区数小于消费者数,有如下情况。例如2个分区四个消费者。那么每个分区都会有一个激活的消费者消费和三个待消费的消费者
如果分区数大于消费者数。例如九个分区三个消费者。如下图,A负责P0 P3 P6 那么BC就是P0 P3 P6 候选消费的消费者。其余同理
对于未分区的topic。
topic比消费者少
topic比消费者多。例如 A消费 topic1和topic4 那么B就是topic1和topic4的候选
-
key共享key_shared
几个消费者共享消费,但是根据哈希key(可以自己指定,有几种)分流。相同key或ordering key只会 投递给同一个消费者无论如何重新投递。那么当有新消费者加入时,pulsar会记录当前已经读取的消息位置,只有当该位置前的消息都被ack了,才会给新消费者投递消息。那万一其他消费者卡住了怎么办,可以开启allowOutOfOrderDelivery放松下条件,只会有短暂的不符合key_shared的消费情况
key_shared 形势下得批处理。如果启用key_shared,要么关闭批处理,要么shengchanzhe 需要启用 key-based batching .起始就是给批次打key。给单条消息打key没啥用,默认得处理方法可能没办法将相同Key的数据打包到相同批次。而消费者消费时,会将第一条数据的key当作该批数据的key从而导致上下文错误
大致消费形式总结如下
订阅模式
按游标是否是持久型来划分
Subscription mode | Description | Note |
---|---|---|
Durable | 持久型游标,订阅重启,broker重启后会从最近消费的消息消费 | 默认的订阅模式 |
NonDurable | 非持久型游标,broker重启后游标会丢失 | 读者的订阅模式本质上是非持久的,因为他无法阻止topic数据的删除 |
多topic订阅
- 正则形式
persistent://public/default/finance-.*
- 列表形式
topic分区
单分区的topic只会被一个broker持有,这限制了该topic的吞吐量。 分区可以将topic分布给多个broker。从而提高吞吐量
topic分区会均匀分布在集群broker上。分区topic(只能由admin api创建。分区数需要在创建topic时指定)和普通topic工作方式没啥区别。
路由方式
当推送消息给分区的topic时,必须指定路由模式,这决定了该消息推给哪个分区
当前有三种消息路由方式
Mode | Description |
---|---|
RoundRobinPartition | 如果没有提供key,那么生产者以轮询 的方式在分区上发布消息。但这个轮询不是指针对单个消息。而是设置成一个相同 的批处理延迟边界,一批一批的发给不同分区,确保批处理有效。如果消息有key,那么就会按key散列给不同分区 |
SinglePartition | 如果消息没key,那么就随机一个分区发送。如果指定key,那么就会散列到特定分区 |
CustomPartition | 自定义路由分区,通过重写客户端接口实现(java的话是MessageRouter) |
顺序保证
消息的顺序和路由方式以及msg的key有关,通常情况下,用户希望每个分区保持顺序
如果msg有key,那么 在使用RoundRobin和single模式时候,消息 都会根据哈希(JavaStringHash, murmur3_32Hash,推荐是用后者)路由到特定分区
消息顺序
rdering guarantee | Description | Routing Mode and Key |
---|---|---|
Per-key-partition | 所有 相同key的消息 会在一个分区按顺序排列 | 使用RoundRobin和single模式并提供key |
Per-producer | 从同一个生产者出来的消息会按序排列 | 需要使用single模式并且消息不附加key |
非持久topic
默认情况下,Pulsar会持久化所有没ack的消息。消息 会交给BookKeeper bookies存储。 但pulsar也提供非持久化的 topic。一旦broker挂了或者订阅挂了,期间的消息都找不回来
格式
*non-persistent*://tenant/namespace/topic
非持久化topic一系列行为都只基于内存。非持久化的topic也不会持久化到zk,意味着该元数据zk是不知道的。如果对应broker挂了,非持久化的topic不会分给新的broker。解决方案是将allowAUtoTopicCreation
设置为true,allowAutoTOpicCreationTYpe
设置为non-partitioned
性能
因为持久化topic需要存磁盘,存状态等操作,总之会比非持久化的topic性能差一些
client api
PulsarClient client = PulsarClient.builder().serviceUrl("pulsar://localhost:6650").build();
String npTopic = "non-persistent://public/default/my-topic";
String subscriptionName = "my-subscription-name";Consumer<byte[]> consumer = client.newConsumer().topic(npTopic).subscriptionName(subscriptionName).subscribe();
system topic
system topic 主要用于实现某些功能并消除对第三方组件的依赖。例如心跳检测,事务,主题策略,资源组服务等。以心跳检测为例子 ,系统主题进行健康检查 ,可以让生产者,消费者生产/读取heartberat ns下的消息来探测服务是否存活
Namespace | TopicName | Domain | Count | Usage |
---|---|---|---|---|
pulsar/system | transaction_coordinator_assign_${id} | Persistent | Default 16 | 事务协调 |
pulsar/system | __transaction_log_${tc_id} | Persistent | Default 16 | 事务日志 |
pulsar/system | resource-usage | Non-persistent | Default 4 | 资源组服务 |
host/port | heartbeat | Persistent | 1 | 心跳检测 |
User-defined-ns | __change_events | Persistent | Default 4 | topic相关事件 |
User-defined-ns | __transaction_buffer_snapshot | Persistent | One per namespace | 事务缓存快照 |
User-defined-ns | ${topicName}__transaction_pending_ack | Persistent | 每个订阅有事务的都会有一个 | 事务ack管理 |
消息重新投递
看前面ack、nack、ack timeout 和重试队列
消息保留和过期
默认情况情况下会立即删除消费者已确认过的消息,并将未确认的消息持久化在消息积压中。不过puslar可以设置更改这种行为。pulsar中的消息保留有两种定义,一种用于非积压消息的持久化。一种用于积压的消息
在puslar中 ,可以设置两种 方式进行消息保留(命名空间级)
- 进行消息的持久化存储,可以存储 已经ack的消息(针对已ack数据,保留X小时Y大小的数据)
- 设置消息TTL,过期数据丢弃(针对未ack的数据,ACK)
消息保留策略
看这两张图就知道了 。深蓝色是还在保留范围内的数据。浅蓝是不在保留范围内的数据,可以删除的 。白色是 未ack积压的数据
开启消息保留 的时候,必须设置默认的大小限制(defaultRetentionSizeInMB)和时间限制(defaultRetentionTimeInMinutes)
Time limit | Size limit | Message retention |
---|---|---|
-1 | -1 | 无限制 保留 |
-1 | >0 | 在范围内保留 |
>0 | -1 | 在范围内保留 |
0 | 0 | 不开启消息保留(默认 ) |
0 | >0 | Invalid |
>0 | 0 | Invalid |
>0 | >0 | 超过一个就丢 |
当然也可以手动设置 topic下消息的保留期限和大小
int retentionTime = 10; // 10 minutes
int retentionSize = 500; // 500 megabytes
RetentionPolicies policies = new RetentionPolicies(retentionTime, retentionSize);
admin.namespaces().setRetention(namespace, policies);
积压配额
backlogs是用来存未ACK数据的。pulsar默认会存储所有 未ACK数据。你也可以控制存储数据的大小和时间。pulsar用配额来限制backlog
该图展示了pulsar如何限制backlog的数据。超过backlog配额的会启用一定消息保留策略。策略如下
Policy | Action |
---|---|
producer_request_hold | 超出配额时生产者会保留消息重试直到超出客户端配置的sendTimeoutMs |
producer_exception | 发消息时抛异常,告知已经超出配额 |
consumer_backlog_eviction | 超出配额时broker开始丢弃积压数据 |
设置积压配额
admin.namespaces().setBacklogQuota(namespace, BacklogQuota.builder().retentionPolicy(RetentionPolicy.producer_request_hold).limitSize(2147483648L).limitTime(60 * 60).build());
TTL
默认情况下,puslar会持久化所有未ack的数据。但可以设置TTL来决定什么时候丢弃未ack的数据
pulsar-admin namespaces set-message-ttl my-tenant/my-ns \
--messageTTL 120 # TTL of 2 minutes
admin.namespaces().setNamespaceMessageTTL(namespace, ttlInSeconds);
消息去重
当消息被持久化多次时会进行去重。确保消息在磁盘只存一次,即使该消息被生产者重复发送。
前两个图是没开启去重,后两个图是开启去重。消息去重有broker层级,ns层级和topic层级
该功能默认是关闭的。如果启用,建议生产者无限尝试发送消息。将sendTImeout配置为0
生产者幂等性
该方式也是消息去重的一种。意味着每条消息仅生成一次。缺点是会将重复数据删除的工作推到应用程序。
重复数据删除和effectively-once语义
消息 重复数据删除使pulsar成为理想的消息传递系统,可以与流处理引擎和其他要提供一次有效处理语义的系统结合使用
消息延迟传递
消息延迟传递可以让消费者延迟一定时间 再消费到消息 。在这个机制中 ,消息存在bookkeeper中,消息发到broker后,DelayedDeliveryTracker在内存中维护时间索引。(timemessageId) 一旦指定延迟结束,消息就会传递给消费者(只能在shared可key-shared订阅使用)。该机制默认启用
注意:
- 在消息保留机制下,pulsar会 删除 topic前面的ledger(可以理解为一个存储单元), 但不会删除中间的ledgere。意味着如果你发了一条延迟很长的消息。即使该消息后面的消息都被消费了(到期被消费)。由于这条消息卡在中间,那么后面的消息对应的ledger都不会被删除
- 在启用积压配额的机制下,如果超过配额依旧会触发对应的消息保留策略
- 在启用TTL机制下,消息到期时,即使是延迟消息也会被删除
相关文章:

Pulsar官方文档学习笔记——消息机制
pulsar 基于3.x最新官方文档学习记录 概念与架构 典型的推送订阅模式。生产者发送消息,消费者订阅topic消费信息并回应ACK。订阅创建后,Pulsar会保留所有消息。仅消息被所有订阅 成功消费了才会丢弃(可以配置消息保留机制保留一定量&#…...

PyTorch--残差网络(ResNet)在CIFAR-10数据集进行图像分类
完整代码 import torch import torch.nn as nn import torchvision import torchvision.transforms as transforms# Device configuration device torch.device(cuda if torch.cuda.is_available() else cpu)# Hyper-parameters num_epochs 80 batch_size 100 learning_rate…...

ETAS工具链自动化实战指南<一>
----自动化不仅是一种技术,更是一种思维方式,它将帮助我们在快节奏的工作环境中保持领先! 目录 往期推荐 场景一:SWC 之间 port自动连接 命令示例 参数说明 场景二:SWC与ECU 自动映射 命令示例 参数说明 场景三&…...

疫情期间我面试了13家企业软件测试岗位,一些面试题整理
项目的测试流程 拿到需求文档后,写测试用例 审核测试用例 等待开发包 部署测试环境 冒烟测试(网页架构图) 页面初始化测试(查看数据库中的数据内容和页面展示的内容是否一致,并且是否按照某些顺序排列)…...

PINCE——Linux 原生游戏内存修改器,一款替代 Cheat Engine 的强大游戏修改器,Linux 游戏玩家必备神器!
PINCE——Linux 原生游戏内存修改器,一款替代 Cheat Engine 的强大游戏修改器,Linux 游戏玩家必备神器! PINCE 是 GNU Project Debugger(GDB) 的前端/反向工程工具,常用作程序调试器,主要用于游戏领域,修改…...

为IntelliJ IDEA安装插件
安装插件 插件是开发工具的扩展程序,通常由第三方提供,当安装了插件后,原开发工作的菜单、按钮等开发环境可能会发生变化,例如出现了新的菜单项,或出现了新的按钮,甚至一些全新的编码方式,通常…...

ES6 Promise
ES6 Promise 对象 一、概述 是异步编程的一种解决方案。 从语法上说,Promise 是一个对象,从它可以获取异步操作的消息。 Promise 状态 状态的特点 Promise 异步操作有三种状态:pending(进行中)、fulfilled(…...

html+css 实现hover 凹陷按钮
前言:哈喽,大家好,今天给大家分享html+css 绚丽效果!并提供具体代码帮助大家深入理解,彻底掌握!创作不易,如果能帮助到大家或者给大家一些灵感和启发,欢迎收藏+关注哦 💕 目录 📚一、效果📚二、原理解析💡1.这是一个,hover时凹陷的效果。每个按钮是一个button…...

什么是负载均衡?负载均衡器如何运作?
往期文章 负载均衡器:LVS、Nginx、HAproxy如何选择? 目录 往期文章什么是负载均衡?为什么需要负载均衡?负载均衡工作原理?静态负载均衡算法动态负载均衡算法 参考 什么是负载均衡? 负载均衡是一种网络技术…...

(Arxiv-2023)潜在一致性模型:通过少步推理合成高分辨率图像
潜在一致性模型:通过少步推理合成高分辨率图像 Paper Title: Latent Consistency Models: Synthesizing High-Resolution Images with Few-Step Inference Paper是清华发表在Arxiv 2023的工作 Paper地址 Code地址 ABSTRACT 潜在扩散模型 (LDM) 在合成高分辨率图像方…...

Unity与UE,哪种游戏引擎适合你?
PlayStation vs Xbox,Mario vs Sonic,Unreal vs Unity?无论是游戏主机、角色还是游戏引擎,人们总是热衷于捍卫他们在游戏行业中的偏爱。 专注于游戏引擎,Unity和Unreal Engine(简称UE4)是目前市…...

这五本大模型书籍,把大模型讲的非常详细,收藏我这一篇就够了
当然可以。在当前的大模型时代,随着自然语言处理(NLP)技术的迅速发展,出现了许多优秀的书籍来帮助读者理解这些复杂的技术。以下是几本值得推荐的大模型书籍,它们涵盖了从基础理论到高级实践的内容,可以帮助…...

伊朗通过 ChatGPT 试图影响美国大选, OpenAI 封禁多个账户|TodayAI
OpenAI 近日宣布,他们已经封禁了一系列与伊朗影响行动有关的 ChatGPT 账户,这些账户涉嫌利用该 AI 工具生成并传播与美国总统选举、以色列 – 哈马斯战争以及奥运会等相关的内容。 OpenAI 表示,这些账户与一个名为 “Storm-2035” 的秘密伊朗…...

windows系统如何走后面之windows系统隐藏账户
系统隐藏账户是一种最为简单有效的权限维持方式,其做法就是让攻击者创建一个新的具有管理员权限的隐藏账户,因为是隐藏账户,所以防守方是无法通过控制面板或命令行看到这个账户的。 自然我们需要一些前提条件,比如说有一个网站&am…...
Elasticsearch(ES)(版本7.x)数据更新后刷新策略RefreshPolicy
Elasticsearch(ES)(版本7.x)数据更新后刷新策略RefreshPolicy 介绍 ES数据写入后,默认1s后才会被搜索到(refresh_interval为1); 这样可能是考虑到性能问题,毕竟实时IO 消耗较多资源 造成的问题 例如一个索引现在有…...

【运维】从一个git库迁移到另一个库
工作目录: /home/java/hosts 10.60.100.194 脚本 hosts / hostsShell GitLab (gbcom.com.cn) 核心代码...

and design vue表格列宽度拖拽,vue-draggable-resizable插件使用
and design vue2版的table表格不能拖拽列的宽度,通过vue-draggable-resizable插件实现 我用的是and design 1.7.8的版本,先下插件 yarn add vue-draggable-resizable2.1.0我这版本的and design用最新3.0.0以上的插件会有问题,实现不了效果&a…...
使用hexo搭建个人博客
很早之前使用hexo和github建了个人博客。搭建的流程一直没有梳理,中间换过几次机器,每次都得重新配置一遍,需要重新学些。最近电脑坏了,原始的数据没有导出来,先把以前文章写个文件占个位置,后面慢慢补吧&a…...
java geotool构建地理点线面
哈喽,各位小伙伴们,你们好呀,我是喵手。运营社区:C站/掘金/腾讯云/阿里云/华为云/51CTO;欢迎大家常来逛逛 今天我要给大家分享一些自己日常学习到的一些知识点,并以文字的形式跟大家一起交流,互…...
C# 中 Grpc服务端调用客户端方法
在 gRPC 中,服务端通常不直接调用客户端的方法,因为 gRPC 的设计模型是服务端提供服务,客户端调用服务。通常情况下,服务端和客户端之间是解耦的,服务端只提供服务端点,客户端通过这些端点发起请求。 不过…...
AI编程--插件对比分析:CodeRider、GitHub Copilot及其他
AI编程插件对比分析:CodeRider、GitHub Copilot及其他 随着人工智能技术的快速发展,AI编程插件已成为提升开发者生产力的重要工具。CodeRider和GitHub Copilot作为市场上的领先者,分别以其独特的特性和生态系统吸引了大量开发者。本文将从功…...
Unit 1 深度强化学习简介
Deep RL Course ——Unit 1 Introduction 从理论和实践层面深入学习深度强化学习。学会使用知名的深度强化学习库,例如 Stable Baselines3、RL Baselines3 Zoo、Sample Factory 和 CleanRL。在独特的环境中训练智能体,比如 SnowballFight、Huggy the Do…...

在WSL2的Ubuntu镜像中安装Docker
Docker官网链接: https://docs.docker.com/engine/install/ubuntu/ 1、运行以下命令卸载所有冲突的软件包: for pkg in docker.io docker-doc docker-compose docker-compose-v2 podman-docker containerd runc; do sudo apt-get remove $pkg; done2、设置Docker…...
Typeerror: cannot read properties of undefined (reading ‘XXX‘)
最近需要在离线机器上运行软件,所以得把软件用docker打包起来,大部分功能都没问题,出了一个奇怪的事情。同样的代码,在本机上用vscode可以运行起来,但是打包之后在docker里出现了问题。使用的是dialog组件,…...

如何在网页里填写 PDF 表格?
有时候,你可能希望用户能在你的网站上填写 PDF 表单。然而,这件事并不简单,因为 PDF 并不是一种原生的网页格式。虽然浏览器可以显示 PDF 文件,但原生并不支持编辑或填写它们。更糟的是,如果你想收集表单数据ÿ…...

Linux 内存管理实战精讲:核心原理与面试常考点全解析
Linux 内存管理实战精讲:核心原理与面试常考点全解析 Linux 内核内存管理是系统设计中最复杂但也最核心的模块之一。它不仅支撑着虚拟内存机制、物理内存分配、进程隔离与资源复用,还直接决定系统运行的性能与稳定性。无论你是嵌入式开发者、内核调试工…...

人工智能(大型语言模型 LLMs)对不同学科的影响以及由此产生的新学习方式
今天是关于AI如何在教学中增强学生的学习体验,我把重要信息标红了。人文学科的价值被低估了 ⬇️ 转型与必要性 人工智能正在深刻地改变教育,这并非炒作,而是已经发生的巨大变革。教育机构和教育者不能忽视它,试图简单地禁止学生使…...
【Android】Android 开发 ADB 常用指令
查看当前连接的设备 adb devices 连接设备 adb connect 设备IP 断开已连接的设备 adb disconnect 设备IP 安装应用 adb install 安装包的路径 卸载应用 adb uninstall 应用包名 查看已安装的应用包名 adb shell pm list packages 查看已安装的第三方应用包名 adb shell pm list…...
用鸿蒙HarmonyOS5实现中国象棋小游戏的过程
下面是一个基于鸿蒙OS (HarmonyOS) 的中国象棋小游戏的实现代码。这个实现使用Java语言和鸿蒙的Ability框架。 1. 项目结构 /src/main/java/com/example/chinesechess/├── MainAbilitySlice.java // 主界面逻辑├── ChessView.java // 游戏视图和逻辑├──…...

消防一体化安全管控平台:构建消防“一张图”和APP统一管理
在城市的某个角落,一场突如其来的火灾打破了平静。熊熊烈火迅速蔓延,滚滚浓烟弥漫开来,周围群众的生命财产安全受到严重威胁。就在这千钧一发之际,消防救援队伍迅速行动,而豪越科技消防一体化安全管控平台构建的消防“…...