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

RocketMQ5.0.0消息消费<二> _ 消息队列负载均衡机制

目录

一、消费队列负载均衡概览

二、消费队列负载均衡实现

1. 负载均衡UML

2. 启动RebalanceService线程

3. PUSH模式负载均衡

三、负载均衡策略

四、参考资料


一、消费队列负载均衡概览

        RocketMQ默认一个主题下有4个消费队列,集群模式下同一消费组内要求每个消费队列在同一时刻只能被一个消费者消费。那么集群模式下多个消费者是如何负载主题的多个消费队列呢?并且如果有新的消费者加入时,消费队列又会如何重新分布呢?

        RocketMQ消费端每20s周期执行一次消费队列重新负载,每次进行队列重新负载时会从Broker实时查询当前消费组内所有消费者,并且对消息队列、消费者列表进行排序,这样新加入的消费者就会在队列重新分布时分配到消费队列从而消费消息。如下所示,是消息拉取与消费队列负载均衡的交互图。

消息拉取与消费队列负载均衡的交互流程

二、消费队列负载均衡实现

1. 负载均衡UML

2. 启动RebalanceService线程

        参考《RocketMQ5.0.0消息消费<一> _ PUSH模式的消息拉取》
章节,消费者启动时,当前消费者添加到MQClientInstance#consumerTable属性中,并启动MQClientInstance实例。启动MQClientInstance实例时,会启动org.apache.rocketmq.client.impl.consumer.RebalanceService消费队列负载均衡服务线程。下图所示是该线程run()调用链。

        以下代码是MQClientInstance维护整个JVM的所有生产者和消费者的属性。

// 生产者容器
private final ConcurrentMap<String/* 生产组 */, MQProducerInner> producerTable = new ConcurrentHashMap<>();
// 消费者容器
private final ConcurrentMap<String/* 消费组 */, MQConsumerInner> consumerTable = new ConcurrentHashMap<>();

        org.apache.rocketmq.client.impl.consumer.RebalanceService#run()周期20s执行负载均衡任务。-Drocketmq.client.rebalance. waitlnterval参数修改执行周期,默认20s

@Override
public void run() {log.info(this.getServiceName() + " service started");while (!this.isStopped()) {// 线程等待20sthis.waitForRunning(waitInterval);// topic下消费队列的负载均衡this.mqClientFactory.doRebalance();}log.info(this.getServiceName() + " service end");
}

        org.apache.rocketmq.client.impl.factory.MQClientInstance#doRebalance方法遍历MQClientInstance实例中所有消费组下消费者。每一个消费者DefaultMQPushConsumerImpl拥有一个org.apache.rocketmq.client.impl.consumer.RebalanceImpl对象(实现负载均衡),给每个消费者找到一个消费队列(重新负载)

// 消费队列负载均衡
public void doRebalance() {for (Map.Entry<String/* 消费组 */, MQConsumerInner> entry : this.consumerTable.entrySet()) {// 获取消费者MQConsumerInner impl = entry.getValue();if (impl != null) {try {// 消费者负载均衡impl.doRebalance();} catch (Throwable e) {log.error("doRebalance exception", e);}}}
}

3. PUSH模式负载均衡

        org.apache.rocketmq.client.impl.consumer.DefaultMQPushConsumerImpl#doRebalance是PUSH模式的负载均衡的入口方法,其调用链如下。

        每个消费者DefaultMQPushConsumerImpl拥有一个RebalanceImpl对象,其中org.apache.rocketmq.client.impl.consumer.RebalanceImpl#doRebalance方法是对消费者的所有订阅主题进行负载均衡,即:消费者的所有订阅主题重新分配一个或多个消费队列来进行消费。其代码如下。注意事项:

  • Map<String/* topic */, SubscriptionData> subTable:获取当前消费者订阅的主题信息;
  • rebalanceByTopic():每个主题进行重新负载均衡
/*** 对消费者订阅的每个topic进行消费队列重新负载* step1:获取消费者订阅的主题信息,注意:消费者可以订阅多个主题* step2:遍历消费者的每个topic* step3:消费者订阅的topic进行消费队列重新负载*        {@link RebalanceImpl#rebalanceByTopic(String, boolean)}* @param isOrder 是否顺序消息* @return true所有topic重新负载成功*/
public boolean doRebalance(final boolean isOrder) {boolean balanced = true;// 获取消费者订阅的主题信息,注意:消费者可以订阅多个主题Map<String/* topic */, SubscriptionData> subTable = this.getSubscriptionInner();if (subTable != null) {// 遍历消费者的每个topicfor (final Map.Entry<String, SubscriptionData> entry : subTable.entrySet()) {final String topic = entry.getKey();try {if (!clientRebalance(topic) && tryQueryAssignment(topic)) {balanced = this.getRebalanceResultFromBroker(topic, isOrder);} else {// 消费者订阅的topic进行消费队列重新负载balanced = this.rebalanceByTopic(topic, isOrder);}} catch (Throwable e) {if (!topic.startsWith(MixAll.RETRY_GROUP_TOPIC_PREFIX)) {log.warn("rebalance Exception", e);balanced = false;}}}}this.truncateMessageQueueNotMyTopic();return balanced;
}

        org.apache.rocketmq.client.impl.consumer.RebalanceImpl#rebalanceByTopic方法是对每个主题进行重新负载均衡的核心逻辑,如下代码所示。 这里介绍集群模式下负载均衡,注意事项:

  • MQClientInstance#findConsumerIdList():从Broker上获取所有订阅该topic且同属一个消费组的所有消费者ID。
  • 对消费队列、消费者ID集合排序:原因是同一个消费组内视图一致,确保同一个消费队列不会被多个消费者分配
  • AllocateMessageQueueStrategy#allocate:根据均衡策略,获取当前消费者的消息队列。
  • RebalanceImpl#updateProcessQueueTableInRebalance:重新负载后,消费者对应的分配后的消息队列是否变化: 新增、删除(其他消费者占用)
/*** 消费者订阅的topic进行消费队列重新负载* 集群模式下的步骤:* step1:从主题订阅信息缓存表(topicSubscribeInfoTable)中获取当前topic的消费队列* step2:从Broker上获取所有订阅该topic + 同属一个消费组 的所有消费者ID* step3:对消费队列、消费者ID排序,很重要,原因是:同一个消费组内视图一致,确保同一个消费队列不会被多个消费者分配* step4:根据均衡策略,获取当前消费者的消息队列*        {@link AllocateMessageQueueStrategy#allocate}* step5:消费者对应的分配消息队列是否变化: 新增、删除(其他消费者占用)*        {@link RebalanceImpl#updateProcessQueueTableInRebalance}* @param topic 主题* @param isOrder 是否是顺序消息* @return true重新分配消息队列成功*/
private boolean rebalanceByTopic(final String topic, final boolean isOrder) {boolean balanced = true;switch (messageModel) {case BROADCASTING: {Set<MessageQueue> mqSet = this.topicSubscribeInfoTable.get(topic);if (mqSet != null) {boolean changed = this.updateProcessQueueTableInRebalance(topic, mqSet, isOrder);if (changed) {this.messageQueueChanged(topic, mqSet, mqSet);log.info("messageQueueChanged {} {} {} {}", consumerGroup, topic, mqSet, mqSet);}balanced = mqSet.equals(getWorkingMessageQueue(topic));} else {this.messageQueueChanged(topic, Collections.<MessageQueue>emptySet(), Collections.<MessageQueue>emptySet());log.warn("doRebalance, {}, but the topic[{}] not exist.", consumerGroup, topic);}break;}case CLUSTERING: {// 从主题订阅信息缓存表中获取当前topic的消费队列Set<MessageQueue> mqSet = this.topicSubscribeInfoTable.get(topic);// 从Broker上获取所有订阅该topic + 同属一个消费组 的所有消费者IDList<String> cidAll = this.mQClientFactory.findConsumerIdList(topic, consumerGroup);if (null == mqSet) {if (!topic.startsWith(MixAll.RETRY_GROUP_TOPIC_PREFIX)) {this.messageQueueChanged(topic, Collections.<MessageQueue>emptySet(), Collections.<MessageQueue>emptySet());log.warn("doRebalance, {}, but the topic[{}] not exist.", consumerGroup, topic);}}if (null == cidAll) {log.warn("doRebalance, {} {}, get consumer id list failed", consumerGroup, topic);}if (mqSet != null && cidAll != null) {List<MessageQueue> mqAll = new ArrayList<MessageQueue>();mqAll.addAll(mqSet);/*消费队列、消费者ID排序很重要:同一个消费组内视图一致,确保同一个消费队列不会被多个消费者分配*/// 消费队列排序Collections.sort(mqAll);// 消费者ID排序Collections.sort(cidAll);// 均衡策略AllocateMessageQueueStrategy strategy = this.allocateMessageQueueStrategy;List<MessageQueue> allocateResult = null;try {// 根据均衡策略,获取当前消费者的消息队列allocateResult = strategy.allocate(this.consumerGroup,this.mQClientFactory.getClientId(), // 当前消费者IDmqAll,cidAll);} catch (Throwable e) {log.error("allocate message queue exception. strategy name: {}, ex: {}", strategy.getName(), e);return false;}Set<MessageQueue> allocateResultSet = new HashSet<MessageQueue>();if (allocateResult != null) {allocateResultSet.addAll(allocateResult);}// 消费者对应的分配消息队列是否变化: 新增、删除(其他消费者占用)boolean changed = this.updateProcessQueueTableInRebalance(topic, allocateResultSet, isOrder);if (changed) {log.info("client rebalanced result changed. allocateMessageQueueStrategyName={}, group={}, topic={}, clientId={}, mqAllSize={}, cidAllSize={}, rebalanceResultSize={}, rebalanceResultSet={}",strategy.getName(), consumerGroup, topic, this.mQClientFactory.getClientId(), mqSet.size(), cidAll.size(),allocateResultSet.size(), allocateResultSet);this.messageQueueChanged(topic, mqSet, allocateResultSet);}balanced = allocateResultSet.equals(getWorkingMessageQueue(topic));}break;}default:break;}return balanced;
}

        org.apache.rocketmq.client.impl.consumer.RebalanceImpl#updateProcessQueueTableInRebalance重新分配后消费队列集合与上次负载的分配集合是否改变(新增或删除)来重新拉取消息。如下代码所示。

  • 删除(消费队列分配给其他消费者):暂停消费并移除,且持久化待移除消费队列的消费进度。
  • 新增(缓存表没有的消费队列):

                step1:删除内存中该消费队列的消费进度;

                step2:创建broker的消费队列;

                step3:从磁盘中获取该消费队列的消费进度(若进度<0时,则根据配置矫正消费进度),创建拉取消息请求。

  • 新增消费队列:重新创建拉取请求PullRequest加入到PullMessageService线程中,唤醒该线程拉取消息RebalanceImpl#dispatchPullRequest。
  • 若是顺序消息:是局部顺序消息,尝试向Broker请求锁定该消费队列,锁定失败延迟时则重新负载。
/*** 消费者对应的分配消息队列是否变化* step1:消费队列缓存表中不在本次均衡分配的消费队列时,则暂停消费并移除,且持久化待移除消费队列的消费进度;* step2:本次均衡分配的消费队列不在消费队列缓存表中,则新增:*         1):删除内存中该消费队列的消费进度;*         2):创建broker的消费队列;*         3):从磁盘中获取该消费队列的消费进度(若进度<0时,则根据配置矫正消费进度),创建拉取消息请求*              {@link RebalanceImpl#computePullFromWhere}* step3: 新增消费队列,则创建{@link PullRequest}加入到{@link PullMessageService},唤醒该线程拉取消息*              {@link RebalanceImpl#dispatchPullRequest}* step4:顺序消息时,则尝试向Broker请求锁定该消费队列,锁定失败延迟重新负载* @param topic 主题* @param mqSet 本次均衡分配的消费队列* @param isOrder 是否顺序* @return true变化;false未改变*/
private boolean updateProcessQueueTableInRebalance(final String topic, final Set<MessageQueue> mqSet,final boolean isOrder) {boolean changed = false;// drop process queues no longer belong me 当前消费队列不在分配队列中HashMap<MessageQueue, ProcessQueue> removeQueueMap = new HashMap<MessageQueue, ProcessQueue>(this.processQueueTable.size());// 遍历当前消费队列缓存表Iterator<Entry<MessageQueue, ProcessQueue>> it = this.processQueueTable.entrySet().iterator();while (it.hasNext()) {Entry<MessageQueue, ProcessQueue> next = it.next();MessageQueue mq = next.getKey();ProcessQueue pq = next.getValue();// 是该topic的消费队列if (mq.getTopic().equals(topic)) {// 当前消费队列不在现有的分配消息队列中,则暂停消费、废弃当前消费队列并移除(分配给其他消费者)if (!mqSet.contains(mq)) {pq.setDropped(true);removeQueueMap.put(mq, pq);} else if (pq.isPullExpired() && this.consumeType() == ConsumeType.CONSUME_PASSIVELY) {pq.setDropped(true);removeQueueMap.put(mq, pq);log.error("[BUG]doRebalance, {}, try remove unnecessary mq, {}, because pull is pause, so try to fixed it",consumerGroup, mq);}}}// remove message queues no longer belong me 移除不在分配的消费队列for (Entry<MessageQueue, ProcessQueue> entry : removeQueueMap.entrySet()) {MessageQueue mq = entry.getKey();ProcessQueue pq = entry.getValue();/*判断是否将{@link MessageQueue}、{@link ProcessQueue}缓存表中移除a. 持久化待移除的{@link MessageQueue}消费进度;b. 顺序消息时,需先解锁队列*/if (this.removeUnnecessaryMessageQueue(mq, pq)) {this.processQueueTable.remove(mq);changed = true;log.info("doRebalance, {}, remove unnecessary mq, {}", consumerGroup, mq);}}// add new message queue 遍历本次负载均衡分配的消费队列,缓存表中没有,则新增的消费队列boolean allMQLocked = true; // 消费队列是否有锁定(顺序消息使用)List<PullRequest> pullRequestList = new ArrayList<PullRequest>();for (MessageQueue mq : mqSet) {// 新增的消费队列if (!this.processQueueTable.containsKey(mq)) {// 若是顺序消息,则尝试向Broker请求锁定该消费队列,锁定失败延迟重新负载if (isOrder && !this.lock(mq)) {log.warn("doRebalance, {}, add a new mq failed, {}, because lock failed", consumerGroup, mq);allMQLocked = false;continue;}// 删除内存中该消费队列的消费进度this.removeDirtyOffset(mq);// 创建broker的消费队列ProcessQueue pq = createProcessQueue(topic);pq.setLocked(true);// 从磁盘中获取该消费队列的消费进度(若进度<0时,则根据配置矫正消费进度),创建拉取消息请求long nextOffset = this.computePullFromWhere(mq);if (nextOffset >= 0) {ProcessQueue pre = this.processQueueTable.putIfAbsent(mq, pq);if (pre != null) {log.info("doRebalance, {}, mq already exists, {}", consumerGroup, mq);} else {log.info("doRebalance, {}, add a new mq, {}", consumerGroup, mq);// 创建拉取消息请求PullRequest pullRequest = new PullRequest();pullRequest.setConsumerGroup(consumerGroup);pullRequest.setNextOffset(nextOffset);pullRequest.setMessageQueue(mq);pullRequest.setProcessQueue(pq);pullRequestList.add(pullRequest);changed = true;}} else {log.warn("doRebalance, {}, add new mq failed, {}", consumerGroup, mq);}}}// 锁定消费队列失败,延迟重新负载if (!allMQLocked) {mQClientFactory.rebalanceLater(500);}// 将拉取消息对象{@link PullRequest}加入到{@link PullMessageService},唤醒该线程拉取消息this.dispatchPullRequest(pullRequestList, 500);return changed;
}

        根据RebalanceImpl#updateProcessQueueTableInRebalance来判定消费者对应的分配到的消息队列是否变化(新增或删除)时,若是新增,则先删除内存消费进度,再从Broker端获取该消费队列的消费进度;若是删除,持久化消费进度同时删除旧的消费队列。 

a. 删除操作

        org.apache.rocketmq.client.impl.consumer.RebalanceImpl#removeUnnecessaryMessageQueue负载均衡时删除未分配的消费队列,其调用链如下。

b. 新增操作

        先删除该消费队列旧的内存消费进度,执行方法RebalanceImpl#removeDirtyOffset,其调用链如下。

        再从Broker磁盘获取该消费队列消费进度,执行RebalanceImpl#computePullFromWhere,其调用链如下。 

三、负载均衡策略

        org.apache.rocketmq.client.consumer.AllocateMessageQueueStrategy是消费队列负载均衡策略的接口,其有6个实现类,UML图如下。其中:

  • AllocateMessageQueueAveragely:平均分配算法(默认),如:8个消息消费队列q1、q2、q3、q4、q5、q6、q7、q8,有3个消费者c1、c2、c3,则分配如下:

                c1:q1、q2、q3

                c2:q4、q5、q6

                c3:q7、q8

  • AllocateMessageQueueAveragelyByCircle:平均轮询算法,如:8个消息消费队列q1、q2、q3、q4、q5、q6、q7、q8,有3个消费者c1、c2、c3,则分配如下:

                c1:q1、q4、q7

                c2:q2、q5、q8

                c3:q3、q6

四、参考资料

RocketMQ(十三) RocketMQ负载均衡_每天都要进步一点点的博客-CSDN博客

https://www.cnblogs.com/alisystemsoftware/p/16935521.html

消费者负载均衡 | RocketMQ

RocketMQ5.0.0消息消费<一> _ PUSH模式的消息拉取_爱我所爱0505的博客-CSDN博客

相关文章:

RocketMQ5.0.0消息消费<二> _ 消息队列负载均衡机制

目录 一、消费队列负载均衡概览 二、消费队列负载均衡实现 1. 负载均衡UML 2. 启动RebalanceService线程 3. PUSH模式负载均衡 三、负载均衡策略 四、参考资料 一、消费队列负载均衡概览 RocketMQ默认一个主题下有4个消费队列&#xff0c;集群模式下同一消费组内要求每个…...

【数据库】MySQL数据库约束(六大约束)

目录 1.数据库约束 1.1约束类型 1.2 非空约束&#xff08;NOT NULL &#xff09; 1.3 唯一约束&#xff08;UNIQUE&#xff09; 1.4默认值约束&#xff08;DEFAULT &#xff09; 1.5主键约束&#xff08;PRIMARY KEY&#xff09; 1.6外键约束&#xff08;FOREIGN KEY &…...

使用inotify监视文件后台运行收到 SIGTTIN 信号的原因及解决方案

一、起因 由于之前写了个程序要实时监控指定文件的变化状态&#xff0c;所以使用了“inotify”进行监视。但是却发现用了“inotify”之后进程无法手动后台运行了。 也就是 ./process.exe &&#xff0c;这种方法不行了。 原因是&#xff1a; 当使用inotify监视文件变化时&a…...

L3-021 神坛

在古老的迈瑞城&#xff0c;巍然屹立着 n 块神石。长老们商议&#xff0c;选取 3 块神石围成一个神坛。因为神坛的能量强度与它的面积成反比&#xff0c;因此神坛的面积越小越好。特殊地&#xff0c;如果有两块神石坐标相同&#xff0c;或者三块神石共线&#xff0c;神坛的面积…...

ArrayList和LinkedList区别

List<TreeNode> list new ArrayList<TreeNode>(); List<TreeNode> allTrees new LinkedList<TreeNode>(); 这两行代码都是用来创建一个存储多个 TreeNode 对象的列表&#xff0c;但是它们使用的底层实现不同。 ArrayList 是一种数组实现的动态数组&…...

977. 有序数组的平方 1. 两数之和 349. 两个数组的交集

给你一个按 非递减顺序 排序的整数数组 nums&#xff0c;返回 每个数字的平方 组成的新数组&#xff0c;要求也按 非递减顺序 排序。 示例 1&#xff1a; 输入&#xff1a;nums [-4,-1,0,3,10] 输出&#xff1a;[0,1,9,16,100] 解释&#xff1a;平方后&#xff0c;数组变为 …...

Mysql问题:[Err] 1055 - Expression #1 of ORDER BY clause is not in GROUP BY clause

1 问题描述 使用Navicat连接到MySQL(版本&#xff1a;8.0.18)&#xff0c;执行查询&#xff1a; select * from t_user WHERE user_name admin查询结果没有问题&#xff0c;但是报错&#xff1a; [Err] 1055 - Expression #1 of ORDER BY clause is not in GROUP BY claus…...

Idea springboot springCloud热加载热调试常用的两种方式

场景描述 在项目开发的过程中&#xff0c;需要修改调试的时候偶每次都需要重启项目浪费时间&#xff0c;下面是我整理的两种常用的两种方式方式一 修改启动配置方式&#xff08;主要针对debug模式下&#xff09; 点击启动配置》edit configrations… configration下面修改Upd…...

银河麒麟V10SP1高级服务器版本离线RPM方式升级openssl openssh 自动化升级系统补丁实战实例全网唯一

银河麒麟高级服务器操作系统简介&#xff1a; 银河麒麟高级服务器操作系统V10是针对企业级关键业务&#xff0c;适应虚拟化、云计算、大数据、工业互联网时代对主机系统可靠性、安全性、性能、扩展性和实时性等需求&#xff0c;依据CMMI5级标准研制的提供内生本质安全、云原生支…...

2023-3-9-一篇简短的文章把C++左右值关系讲的透透彻彻

目录前言C左值和右值二、右值引用二、右值引用前言 对于C的左值和右值相信很多人都没有一个很透彻的了解,之前我也是不懂的时候查阅了好多文章,但是讲完我还是一头雾水,直到我遇到一篇宝藏文章,讲的左值右值的关系以及Move函数的用法是相当的清楚,文章链接在这,话不多说讲解一…...

Vue3这样子写页面更快更高效

在开发管理后台过程中,一定会遇到不少了增删改查页面,而这些页面的逻辑大多都是相同的,如获取列表数据,分页,筛选功能这些基本功能。而不同的是呈现出来的数据项。还有一些操作按钮。 对于刚开始只有 1,2 个页面的时候大多数开发者可能会直接将之前的页面代码再拷贝多…...

锐捷AP设置限速(胖模式)

基于整个AP限速命令 Ruijie(config)#wlan-qos ap-based { per-user-limit | total-user-limit } { down-streams | up-streams } average-data-rate average-data-rate burst-data-rate burst-data-rate per-user-limit 对AP上的每个用户进行限速 …...

聚势合力,电巢与SDIA协会“战略合作签约仪式”圆满落成

前言&#xff1a; 2023年03月02日下午&#xff0c;电巢科技与深圳市平板显示行业协会齐聚深圳南山电巢XR演播厅&#xff0c;共同举办了隆重的战略合作签约仪式。 双方就数字化建设、品牌赋能、人才培养、技术创新等企业服务深入合作上达成一致&#xff0c;合力为产业赋能&…...

Linux安装后基础配置--网络--ssh--基本软件

安装教程比较多就不写了。 网络配置 设置虚拟网络 修改网络配置文件 vi /etc/sysconfig/network-scripts/ifcfg-ens33将ONBOOT由no改为yes&#xff1a; 修改为静态网络 /etc/sysconfig/network-scripts/ifcfg-eth33 BOOTPROTOstatic IPADDR192.168.1.129 GATEWAY192.168…...

剑指 Offer 66. 构建乘积数组

剑指 Offer 66. 构建乘积数组 难度&#xff1a;middle\color{orange}{middle}middle 题目描述 给定一个数组 A[0,1,…,n−1]A[0,1,…,n-1]A[0,1,…,n−1]&#xff0c;请构建一个数组 B[0,1,…,n−1]B[0,1,…,n-1]B[0,1,…,n−1]&#xff0c;其中 B[i]B[i]B[i] 的值是数组 AAA…...

1.1 误差的来源

不难发现&#xff0c;考察用计算机解决科学计算问题时所经历的几个环节&#xff08;如图1-1所示&#xff09;&#xff0c;其中每一步都可能产生误差&#xff0c;首先,数学模型是通过对实际问题进行抽象与简化得到的&#xff0c;它与实际问题之间有误差&#xff0e;数学模型与实…...

python进程间通信

进程间通信表示进程之间的数据交换。 为了开发并行应用程序&#xff0c;需要在进程间交换数据。 下图显示了多个子过程之间同步的各种通信机制 - 各种通信机制 队列 队列可以用于多进程程序。 多处理模块的Queue类与Queue.Queue类相似。 因此&#xff0c;可以使用相同的API…...

麒麟Linux操作系统磁盘策略永久调整为deadline

1.前言在安装数据库&#xff0c;比如达梦数据库时&#xff0c;为获取磁盘最佳性能&#xff0c;一般要将数据磁盘设置为deadline。2. 修改磁盘调度算法2.1临时修改假设磁盘为sda,echo deadline > /sys/block/sda/queue/scheduler2.2通用机永久修改grubby --update-kernelALL …...

yum安装Docker(CentOS7.9)

目录 一、安装环境 编写yum源(根据系统版本) 二、安装docker-ce 默认安装docker-ce是最新版本 ps&#xff1a;安装不成功则需要安装container-selinux&#xff0c;下载网络yum源,再安装docker-ce即可 #查看dcoker-ce所产生的文件路径 三、启动docker 四、配置镜像加速器…...

c++错误 free(): double free detected

记一次bug调试。。。。 我定义了一个类&#xff0c;测试的时候&#xff0c;调用它的方法出现了free(): double free detected &#xff0c;但是调用其他方法是正常的。这个错误&#xff0c;字面意思就是检测到了双重释放。是指对于同一块内存&#xff0c;释放了两次。 我的类…...

XCTF-web-easyupload

试了试php&#xff0c;php7&#xff0c;pht&#xff0c;phtml等&#xff0c;都没有用 尝试.user.ini 抓包修改将.user.ini修改为jpg图片 在上传一个123.jpg 用蚁剑连接&#xff0c;得到flag...

7.4.分块查找

一.分块查找的算法思想&#xff1a; 1.实例&#xff1a; 以上述图片的顺序表为例&#xff0c; 该顺序表的数据元素从整体来看是乱序的&#xff0c;但如果把这些数据元素分成一块一块的小区间&#xff0c; 第一个区间[0,1]索引上的数据元素都是小于等于10的&#xff0c; 第二…...

日语学习-日语知识点小记-构建基础-JLPT-N4阶段(33):にする

日语学习-日语知识点小记-构建基础-JLPT-N4阶段(33):にする 1、前言(1)情况说明(2)工程师的信仰2、知识点(1) にする1,接续:名词+にする2,接续:疑问词+にする3,(A)は(B)にする。(2)復習:(1)复习句子(2)ために & ように(3)そう(4)にする3、…...

【Java学习笔记】Arrays类

Arrays 类 1. 导入包&#xff1a;import java.util.Arrays 2. 常用方法一览表 方法描述Arrays.toString()返回数组的字符串形式Arrays.sort()排序&#xff08;自然排序和定制排序&#xff09;Arrays.binarySearch()通过二分搜索法进行查找&#xff08;前提&#xff1a;数组是…...

《Playwright:微软的自动化测试工具详解》

Playwright 简介:声明内容来自网络&#xff0c;将内容拼接整理出来的文档 Playwright 是微软开发的自动化测试工具&#xff0c;支持 Chrome、Firefox、Safari 等主流浏览器&#xff0c;提供多语言 API&#xff08;Python、JavaScript、Java、.NET&#xff09;。它的特点包括&a…...

FastAPI 教程:从入门到实践

FastAPI 是一个现代、快速&#xff08;高性能&#xff09;的 Web 框架&#xff0c;用于构建 API&#xff0c;支持 Python 3.6。它基于标准 Python 类型提示&#xff0c;易于学习且功能强大。以下是一个完整的 FastAPI 入门教程&#xff0c;涵盖从环境搭建到创建并运行一个简单的…...

Spring Boot+Neo4j知识图谱实战:3步搭建智能关系网络!

一、引言 在数据驱动的背景下&#xff0c;知识图谱凭借其高效的信息组织能力&#xff0c;正逐步成为各行业应用的关键技术。本文聚焦 Spring Boot与Neo4j图数据库的技术结合&#xff0c;探讨知识图谱开发的实现细节&#xff0c;帮助读者掌握该技术栈在实际项目中的落地方法。 …...

NLP学习路线图(二十三):长短期记忆网络(LSTM)

在自然语言处理(NLP)领域,我们时刻面临着处理序列数据的核心挑战。无论是理解句子的结构、分析文本的情感,还是实现语言的翻译,都需要模型能够捕捉词语之间依时序产生的复杂依赖关系。传统的神经网络结构在处理这种序列依赖时显得力不从心,而循环神经网络(RNN) 曾被视为…...

JDK 17 新特性

#JDK 17 新特性 /**************** 文本块 *****************/ python/scala中早就支持&#xff0c;不稀奇 String json “”" { “name”: “Java”, “version”: 17 } “”"; /**************** Switch 语句 -> 表达式 *****************/ 挺好的&#xff…...

《C++ 模板》

目录 函数模板 类模板 非类型模板参数 模板特化 函数模板特化 类模板的特化 模板&#xff0c;就像一个模具&#xff0c;里面可以将不同类型的材料做成一个形状&#xff0c;其分为函数模板和类模板。 函数模板 函数模板可以简化函数重载的代码。格式&#xff1a;templa…...