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

Kafka分区分配策略详解

Kafka分区分配策略详解

Kafka作为当前最流行的分布式消息队列系统,其分区分配策略直接影响着系统的性能、可靠性和可扩展性。合理的分区分配不仅能够提高数据处理的效率,还能确保系统负载的均衡。

Kafka提供了多种内置的分区分配策略,包括RoundRobin(轮询)、Range(范围)和Sticky(粘性)等,同时还支持自定义分配策略的实现。每种策略都有其特定的应用场景和优势。

1 均衡性:确保分区尽可能均匀地分配给消费者,避免出现某些消费者负载过重而其他消费者闲置的情况。

2 稳定性:在消费者加入或离开组时,尽量减少分区的重新分配,以降低对消费过程的影响。

3 可用性:当消费者发生故障时,能够快速进行分区重分配,确保数据能够继续被消费。

4 扩展性:支持动态增减消费者,能够自动调整分区分配。

RoundRobin轮询分配策略

RoundRobin(轮询)是最简单也是最常用的分区分配策略之一。该策略按照分区和消费者的字典序排序后,通过轮询方式逐个将分区分配给消费者。这种策略的主要优点是实现简单,分配均匀,但在某些场景下可能会导致分配不够优化。
轮询策略的工作流程如下:
1 收集所有可用的分区和消费者
2 对分区和消费者进行排序,确保分配的确定性
3 按照轮询方式将分区依次分配给消费者
4 当出现消费者变化时,重新进行完整的分配

以下是RoundRobin策略的具体实现:

/*** 轮询分区分配策略实现*/
public class RoundRobinAssignor implements PartitionAssignor {private static final Logger log = LoggerFactory.getLogger(RoundRobinAssignor.class);@Overridepublic Map<String, Assignment> assign(Cluster metadata,Map<String, Subscription> subscriptions) {// 构建消费者订阅的主题集合Map<String, List<String>> consumerTopics = new HashMap<>();for (Map.Entry<String, Subscription> entry : subscriptions.entrySet()) {consumerTopics.put(entry.getKey(), entry.getValue().getTopics());}// 收集所有订阅的主题分区List<TopicPartition> allPartitions = new ArrayList<>();for (String topic : getAllSubscribedTopics(consumerTopics)) {for (PartitionInfo partition : metadata.partitionsForTopic(topic)) {allPartitions.add(new TopicPartition(topic, partition.partition()));}}// 对分区进行排序Collections.sort(allPartitions, Comparator.comparing(TopicPartition::toString));// 对消费者进行排序List<String> consumers = new ArrayList<>(subscriptions.keySet());Collections.sort(consumers);// 执行分配Map<String, List<TopicPartition>> assignment = new HashMap<>();for (String consumer : consumers) {assignment.put(consumer, new ArrayList<>());}int currentPartitionIndex = 0;int currentConsumerIndex = 0;int remainingPartitions = allPartitions.size();// 轮询分配分区while (remainingPartitions > 0) {String consumer = consumers.get(currentConsumerIndex);TopicPartition partition = allPartitions.get(currentPartitionIndex);// 检查消费者是否订阅了该主题if (consumerTopics.get(consumer).contains(partition.topic())) {assignment.get(consumer).add(partition);remainingPartitions--;}currentPartitionIndex = (currentPartitionIndex + 1) % allPartitions.size();currentConsumerIndex = (currentConsumerIndex + 1) % consumers.size();}// 构建返回结果Map<String, Assignment> result = new HashMap<>();for (Map.Entry<String, List<TopicPartition>> entry : assignment.entrySet()) {result.put(entry.getKey(), new Assignment(entry.getValue(), null));}// 打印分配结果logAssignment(result);return result;}/*** 获取所有订阅的主题*/private Set<String> getAllSubscribedTopics(Map<String, List<String>> consumerTopics) {Set<String> topics = new HashSet<>();for (List<String> subscribed : consumerTopics.values()) {topics.addAll(subscribed);}return topics;}/*** 记录分配结果*/private void logAssignment(Map<String, Assignment> assignment) {StringBuilder builder = new StringBuilder();builder.append("Assignment results:\n");for (Map.Entry<String, Assignment> entry : assignment.entrySet()) {builder.append(String.format("\tConsumer %s -> Partitions %s\n",entry.getKey(),entry.getValue().getPartitions()));}log.info(builder.toString());}@Overridepublic String name() {return "roundrobin";}
}

这个实现包含了以下特点:

1 确定性:通过对分区和消费者进行排序,确保相同的输入产生相同的分配结果

2 公平性:通过轮询方式保证分区分配的均匀性

3 订阅感知:只将分区分配给订阅了相应主题的消费者

4 可追踪性:通过日志记录分配结果,便于问题排查

Range范围分配策略

Range策略是Kafka的默认分区分配策略,它对每个主题单独进行分区分配。该策略首先对同一个主题的分区按照分区ID进行排序,然后将消费者按照消费者ID排序,最后根据分区数量和消费者数量计算每个消费者应该分配的分区范围。这种策略的优势在于可以保证同一个主题的相邻分区尽可能地分配给同一个消费者,这在某些场景下能够提供更好的数据局部性。

Range策略的核心思想是:
按主题进行分组处理
确保分区的连续性分配
尽可能平均分配分区数量
保持分配的稳定性

以下是Range策略的实现代码:

/*** 范围分区分配策略实现*/
public class RangeAssignor implements PartitionAssignor {private static final Logger log = LoggerFactory.getLogger(RangeAssignor.class);@Overridepublic Map<String, Assignment> assign(Cluster metadata,Map<String, Subscription> subscriptions) {// 构建每个主题的消费者列表Map<String, List<String>> consumersPerTopic = new HashMap<>();for (Map.Entry<String, Subscription> entry : subscriptions.entrySet()) {String consumerId = entry.getKey();for (String topic : entry.getValue().getTopics()) {consumersPerTopic.computeIfAbsent(topic, t -> new ArrayList<>()).add(consumerId);}}// 对每个主题的消费者进行排序for (List<String> consumers : consumersPerTopic.values()) {Collections.sort(consumers);}// 为每个消费者初始化分配结果Map<String, List<TopicPartition>> assignment = new HashMap<>();for (String consumerId : subscriptions.keySet()) {assignment.put(consumerId, new ArrayList<>());}// 对每个主题进行分区分配for (Map.Entry<String, List<String>> topicEntry : consumersPerTopic.entrySet()) {String topic = topicEntry.getKey();List<String> consumers = topicEntry.getValue();// 获取主题的分区数Integer numPartitionsForTopic = metadata.partitionCountForTopic(topic);if (numPartitionsForTopic == null) {continue;}// 计算每个消费者应该分配的分区数量int numPartitionsPerConsumer = numPartitionsForTopic / consumers.size();int consumersWithExtraPartition = numPartitionsForTopic % consumers.size();// 为每个消费者分配分区for (int i = 0; i < consumers.size(); i++) {String consumer = consumers.get(i);int start = numPartitionsPerConsumer * i + Math.min(i, consumersWithExtraPartition);int length = numPartitionsPerConsumer + (i < consumersWithExtraPartition ? 1 : 0);// 分配分区范围for (int partition = start; partition < start + length; partition++) {assignment.get(consumer).add(new TopicPartition(topic, partition));}}}// 构建返回结果Map<String, Assignment> result = new HashMap<>();for (Map.Entry<String, List<TopicPartition>> entry : assignment.entrySet()) {result.put(entry.getKey(), new Assignment(entry.getValue(), null));}// 记录分配结果logAssignment(result);return result;}/*** 记录分配结果*/private void logAssignment(Map<String, Assignment> assignment) {StringBuilder builder = new StringBuilder();builder.append("Range assignment results:\n");for (Map.Entry<String, Assignment> entry : assignment.entrySet()) {builder.append(String.format("\tConsumer %s -> Partitions %s\n",entry.getKey(),entry.getValue().getPartitions().stream().sorted(Comparator.comparing(TopicPartition::toString)).collect(Collectors.toList())));}log.info(builder.toString());}@Overridepublic String name() {return "range";}/*** 计算分区分配的统计信息*/private void calculateAssignmentStats(Map<String, Assignment> assignment) {Map<String, Integer> partitionsPerConsumer = new HashMap<>();for (Map.Entry<String, Assignment> entry : assignment.entrySet()) {partitionsPerConsumer.put(entry.getKey(), entry.getValue().getPartitions().size());}int min = Collections.min(partitionsPerConsumer.values());int max = Collections.max(partitionsPerConsumer.values());double avg = partitionsPerConsumer.values().stream().mapToInt(Integer::intValue).average().orElse(0.0);log.info("Assignment stats - Min: {}, Max: {}, Avg: {:.2f}", min, max, avg);}
}

Sticky粘性分配策略

Sticky(粘性)分配策略是Kafka在0.11.0版本中引入的新策略,它的主要目标是在保证分区均匀分配的同时,尽可能地维持现有的分区分配,减少分区的移动。这种策略特别适合那些对分区迁移敏感的场景,例如维护了大量本地状态的消费者。
粘性分配策略的核心原则是:

  1. 分区分配尽量均匀
  2. 每次重分配时,尽量保持已有的分配关系
  3. 必要时才进行分区移动
  4. 当消费者离开时,其分区尽量平均分配给其他消费者

以下是Sticky策略的实现代码:

/*** 粘性分区分配策略实现*/
public class StickyAssignor implements PartitionAssignor {private static final Logger log = LoggerFactory.getLogger(StickyAssignor.class);// 记录当前的分配方案private Map<String, List<TopicPartition>> currentAssignment;public StickyAssignor() {this.currentAssignment = new HashMap<>();}@Overridepublic Map<String, Assignment> assign(Cluster metadata,Map<String, Subscription> subscriptions) {// 获取所有待分配的分区Set<TopicPartition> allPartitions = getAllPartitions(metadata, subscriptions);// 获取当前活跃的消费者Set<String> consumers = subscriptions.keySet();// 构建新的分配方案Map<String, List<TopicPartition>> newAssignment = new HashMap<>();// 如果是首次分配,直接使用平均分配if (currentAssignment.isEmpty()) {newAssignment = assignPartitionsEvenly(allPartitions, consumers);} else {// 否则尝试保持现有分配newAssignment = reassignPartitions(allPartitions, consumers);}// 更新当前分配方案currentAssignment = newAssignment;// 构建返回结果Map<String, Assignment> result = new HashMap<>();for (Map.Entry<String, List<TopicPartition>> entry : newAssignment.entrySet()) {result.put(entry.getKey(), new Assignment(entry.getValue(), null));}// 记录分配结果logAssignment(result);return result;}/*** 重新分配分区,尽量保持现有分配*/private Map<String, List<TopicPartition>> reassignPartitions(Set<TopicPartition> allPartitions, Set<String> consumers) {Map<String, List<TopicPartition>> assignment = new HashMap<>();// 初始化消费者的分配列表for (String consumer : consumers) {assignment.put(consumer, new ArrayList<>());}// 找出需要重新分配的分区Set<TopicPartition> partitionsToReassign = new HashSet<>(allPartitions);// 保留现有的有效分配for (Map.Entry<String, List<TopicPartition>> entry : currentAssignment.entrySet()) {String consumer = entry.getKey();if (consumers.contains(consumer)) {List<TopicPartition> partitions = entry.getValue();for (TopicPartition partition : partitions) {if (allPartitions.contains(partition)) {assignment.get(consumer).add(partition);partitionsToReassign.remove(partition);}}}}// 计算目标分配数量int targetPartitionsPerConsumer = allPartitions.size() / consumers.size();int consumersWithExtraPartition = allPartitions.size() % consumers.size();// 重新分配剩余分区List<String> sortedConsumers = new ArrayList<>(consumers);Collections.sort(sortedConsumers);for (TopicPartition partition : partitionsToReassign) {// 找到分配数量最少的消费者String selectedConsumer = findConsumerWithLeastPartitions(assignment, targetPartitionsPerConsumer, consumersWithExtraPartition);assignment.get(selectedConsumer).add(partition);}return assignment;}/*** 查找分配数量最少的消费者*/private String findConsumerWithLeastPartitions(Map<String, List<TopicPartition>> assignment,int targetPartitionsPerConsumer,int consumersWithExtraPartition) {String selectedConsumer = null;int minPartitions = Integer.MAX_VALUE;for (Map.Entry<String, List<TopicPartition>> entry : assignment.entrySet()) {int currentPartitions = entry.getValue().size();if (currentPartitions < minPartitions) {minPartitions = currentPartitions;selectedConsumer = entry.getKey();}}return selectedConsumer;}/*** 平均分配分区(用于首次分配)*/private Map<String, List<TopicPartition>> assignPartitionsEvenly(Set<TopicPartition> allPartitions, Set<String> consumers) {Map<String, List<TopicPartition>> assignment = new HashMap<>();List<TopicPartition> partitionList = new ArrayList<>(allPartitions);Collections.sort(partitionList, Comparator.comparing(TopicPartition::toString));List<String> consumerList = new ArrayList<>(consumers);Collections.sort(consumerList);for (String consumer : consumerList) {assignment.put(consumer, new ArrayList<>());}int currentConsumerIndex = 0;for (TopicPartition partition : partitionList) {String consumer = consumerList.get(currentConsumerIndex);assignment.get(consumer).add(partition);currentConsumerIndex = (currentConsumerIndex + 1) % consumerList.size();}return assignment;}@Overridepublic String name() {return "sticky";}
}

自定义分配策略实现

在某些特定场景下,Kafka内置的分配策略可能无法满足业务需求,这时我们需要实现自定义的分区分配策略。例如,我们可能需要考虑消费者的机器配置、网络带宽、地理位置等因素,或者需要实现特定的业务逻辑。

以下是一个考虑消费者权重的自定义分配策略实现:

/*** 基于权重的自定义分区分配策略*/
public class WeightedAssignor implements PartitionAssignor {private static final Logger log = LoggerFactory.getLogger(WeightedAssignor.class);// 消费者权重配置private final Map<String, Integer> consumerWeights;public WeightedAssignor(Map<String, Integer> weights) {this.consumerWeights = weights;}@Overridepublic Map<String, Assignment> assign(Cluster metadata,Map<String, Subscription> subscriptions) {// 收集所有分区Set<TopicPartition> allPartitions = getAllPartitions(metadata, subscriptions);// 计算总权重int totalWeight = calculateTotalWeight(subscriptions.keySet());// 按权重分配分区Map<String, List<TopicPartition>> assignment = assignByWeight(allPartitions, subscriptions.keySet(), totalWeight);// 构建返回结果Map<String, Assignment> result = new HashMap<>();for (Map.Entry<String, List<TopicPartition>> entry : assignment.entrySet()) {result.put(entry.getKey(), new Assignment(entry.getValue(), null));}// 记录分配结果logAssignment(result);return result;}/*** 按权重分配分区*/private Map<String, List<TopicPartition>> assignByWeight(Set<TopicPartition> partitions,Set<String> consumers,int totalWeight) {Map<String, List<TopicPartition>> assignment = new HashMap<>();List<TopicPartition> sortedPartitions = new ArrayList<>(partitions);Collections.sort(sortedPartitions, Comparator.comparing(TopicPartition::toString));// 初始化分配结果for (String consumer : consumers) {assignment.put(consumer, new ArrayList<>());}// 计算每个消费者应该分配的分区数量Map<String, Integer> targetAssignments = calculateTargetAssignments(consumers, totalWeight, partitions.size());// 执行分配int currentIndex = 0;for (String consumer : consumers) {int targetCount = targetAssignments.get(consumer);for (int i = 0; i < targetCount && currentIndex < sortedPartitions.size(); i++) {assignment.get(consumer).add(sortedPartitions.get(currentIndex++));}}return assignment;}/*** 计算目标分配数量*/private Map<String, Integer> calculateTargetAssignments(Set<String> consumers,int totalWeight,int totalPartitions) {Map<String, Integer> targets = new HashMap<>();int remainingPartitions = totalPartitions;// 按权重比例计算基本分配数量for (String consumer : consumers) {int weight = consumerWeights.getOrDefault(consumer, 1);int target = (int) Math.floor((double) totalPartitions * weight / totalWeight);targets.put(consumer, target);remainingPartitions -= target;}// 分配剩余的分区List<String> sortedConsumers = new ArrayList<>(consumers);Collections.sort(sortedConsumers, (c1, c2) -> {int w1 = consumerWeights.getOrDefault(c1, 1);int w2 = consumerWeights.getOrDefault(c2, 1);return w2 - w1;  // 权重大的优先获得剩余分区});int index = 0;while (remainingPartitions > 0) {String consumer = sortedConsumers.get(index);targets.put(consumer, targets.get(consumer) + 1);remainingPartitions--;index = (index + 1) % sortedConsumers.size();}return targets;}/*** 计算总权重*/private int calculateTotalWeight(Set<String> consumers) {return consumers.stream().mapToInt(c -> consumerWeights.getOrDefault(c, 1)).sum();}/*** 记录分配结果和权重信息*/private void logAssignment(Map<String, Assignment> assignment) {StringBuilder builder = new StringBuilder();builder.append("Weighted assignment results:\n");for (Map.Entry<String, Assignment> entry : assignment.entrySet()) {String consumer = entry.getKey();int weight = consumerWeights.getOrDefault(consumer, 1);builder.append(String.format("\tConsumer %s (weight=%d) -> Partitions %s\n",consumer,weight,entry.getValue().getPartitions()));}log.info(builder.toString());}@Overridepublic String name() {return "weighted";}
}

通过对Kafka分区分配策略的深入分析,我们可以看到不同策略在不同场景下的优势和局限。Range策略适合需要保持分区连续性的场景,RoundRobin策略在追求绝对均衡时表现出色,Sticky策略则在减少分区迁移方面具有明显优势。而自定义策略的灵活性,则为特定业务场景提供了更多可能性。

相关文章:

Kafka分区分配策略详解

Kafka分区分配策略详解 Kafka作为当前最流行的分布式消息队列系统&#xff0c;其分区分配策略直接影响着系统的性能、可靠性和可扩展性。合理的分区分配不仅能够提高数据处理的效率&#xff0c;还能确保系统负载的均衡。 Kafka提供了多种内置的分区分配策略&#xff0c;包括R…...

Vs code搭建uniapp-vue项目

安装vue环境npm install -g vue/clinode版本建议18或者18以上 vue create -p dcloudio/uni-preset-vue 项目名称----正式版vue create -p dcloudio/uni-preset-vue#alpha 项目名称----alpha版Vue3/Vite版 npx degit dcloudio/uni-preset-vue#vite 项目名称---js-正式版npx degi…...

cursor常用快捷键(JetBrains Darcula主题风格)

一、基础操作速查 打开/创建项目 打开项目&#xff1a;Ctrl Shift O&#xff08;选择文件夹&#xff09;新建文件&#xff1a;Ctrl N保存文件&#xff1a;Ctrl S关闭当前标签页&#xff1a;Ctrl F4 代码编辑 复制当前行&#xff1a;Ctrl D删除当前行&#xff1a;Ctrl …...

easyExcel2.2.10中为0数据显示为空

在 EasyExcel 2.2.10 中&#xff0c;如果希望将数值为 0 的数据在 Excel 中显示为空&#xff08;即不显示 0&#xff09;&#xff0c;可以通过以下方法实现&#xff1a; 1. 使用 ExcelProperty 的 format 参数 通过设置单元格格式为 #&#xff08;# 会忽略 0&#xff09;&…...

Walrus 经济模型 101

本文作者&#xff1a;Steve_4P&#xff0c;文章仅代表作者观点。 要点总结 2025 年 3 月 20 日&#xff0c;Walrus 基金会宣布成功融资 约 1.4 亿美元&#xff0c;投资方包括 Standard Crypto、a16z 等机构。Walrus 当前估值约 20 亿美元&#xff0c;其中 7% 代币供应量分配给…...

WordPress二次开发中常用到的一些变量和函数

WordPress是一个开源的博客软件平台&#xff0c;由于其强大的功能和灵活性&#xff0c;被广泛用于各种网站的建设。对于开发者来说&#xff0c;了解并掌握WordPress中的常用变量和函数是非常重要的。在WordPress二次开发中&#xff0c;以下是一些常用的变量和函数&#xff1a; …...

【视频】OpenCV:色彩空间转换、灰度转伪彩

1、颜色空间转换 使用OpenCV的函数 cv::applyColorMap 可以将灰度或者正常的RGB格式图片,转换成其它伪彩色,代码很简单: 1)使用 cv::imread 加载图片; 2)使用 std::vector<cv::Mat> matrices 暂存转换后的所有图像; 3)使用 cv::applyColorMap 转换图片颜色; 4)…...

淘宝历史价格数据获取指南:API 与爬虫方案的合法性与效率对比

引言 在淘宝平台的购物生态中&#xff0c;消费者希望通过了解商品历史价格来判断当前价格是否实惠&#xff0c;商家也需要借助历史价格数据制定合理的营销策略、分析市场趋势。获取淘宝商品历史价格数据主要有 API 和爬虫两种方案&#xff0c;它们在合法性与效率上存在显著差异…...

【Redis】高性能内存数据库的多场景应用

在现代互联网应用的开发版图中&#xff0c;Redis 凭借其卓越的性能和丰富的数据结构&#xff0c;成为了众多开发者不可或缺的技术利器。作为一款基于内存的高性能数据库&#xff0c;Redis 不仅能提供快速的数据读写操作&#xff0c;还能在多种复杂的应用场景中发挥关键作用。本…...

Pycharm社区版创建Flask项目详解

一、创建工程项目 二、配置工程目录 新建的空项目下创建目录。 1、新建app.py文件 2、app.py代码如下&#xff1a; from flask import Flask, render_templateapp Flask(__name__)app.route("/") def root():"""主页:return: Index.html"&qu…...

鸿蒙NEXT开发案例:程序员计算器

【环境准备】 • 操作系统&#xff1a;Windows 10 • 开发工具&#xff1a;DevEco Studio 5.0.1 Release Build Version: 5.0.5.306 • 目标设备&#xff1a;华为Mate60 Pro • 开发语言&#xff1a;ArkTS • 框架&#xff1a;ArkUI • API版本&#xff1a;API 13 【项目…...

TCP 三次握手与四次挥手过程

TCP 作为一种面向连接的、可靠的传输层协议&#xff0c;其连接管理机制对于保障数据的可靠传输至关重要。 三次握手&#xff08;建立连接&#xff09; 三次握手是 TCP 建立连接时所采用的机制&#xff0c;其目的在于确保客户端和服务器双方都具备发送和接收数据的能力&#x…...

仿新浪微博typecho主题源码

源码介绍 仿新浪微博typecho主题源码&#xff0c;简约美观&#xff0c;适合做个人博客&#xff0c;该源码为主题模板&#xff0c;需要先搭建typecho&#xff0c;然后吧源码放到对应的模板目录下&#xff0c;后台启用即可 源码特点 支持自适应 个性化程度高 可设置背景图、顶…...

python面试高频考点(深度学习大模型方向)

1. python中yeild和return的区别&#xff1f; 2. 介绍一下pytohn中的上下文管理器&#xff1f; 在Python中&#xff0c;上下文管理器&#xff08;Context Manager&#xff09; 是一种通过 with 语句管理资源的协议&#xff0c;确保资源&#xff08;如文件、数据库连接、线程锁…...

【网络层协议】NAT技术内网穿透

IP地址数量限制 我们知道&#xff0c;IP地址&#xff08;IPv4&#xff09;是一个4字节32位的整数&#xff0c;那么一共只有2^32也就是接近43亿个IP地址&#xff0c;而TCP/IP协议栈规定&#xff0c;每台主机只能有一个IP地址&#xff0c;这就意味着&#xff0c;一共只有不到43亿…...

【数据分享】2000—2024年我国省市县三级逐年归一化植被指数(NDVI)数据(年平均值/Shp/Excel格式)

之前我们分享过2000-2024年我国逐年的归一化植被指数&#xff08;NDVI&#xff09;栅格数据&#xff0c;该逐年数据是取的当年月归一化植被指数&#xff08;NDVI&#xff09;的年平均值。&#xff01;该数据来源于NASA定期发布的MOD13A3数据集&#xff01;很多小伙伴拿到数据后…...

鸿蒙harmonyOS:笔记 正则表达式

从给出的文本中&#xff0c;按照既定的相关规则&#xff0c;匹配出符合的数据&#xff0c;其中的规则就是正则表达式&#xff0c;使用正则表达式&#xff0c;可以使得我们用简洁的代码就能实现一定复杂的逻辑&#xff0c;比如判断一个邮箱账号是否符合正常的邮箱账号&#xff0…...

centos7.9镜像源及Python引入ssl问题处理

一、镜像源修改 1. 备份原有的镜像源配置文件 在修改之前,先备份现有的 CentOS-Base.repo 文件: sudo cp /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.backup 2. 编辑镜像源配置文件 使用文本编辑器(如 nano 或 vi)打开 /etc/yum.repos.d/Ce…...

【学Rust写CAD】11 2D CAD可用rust库

使用 Rust 开发 2D CAD 应用时&#xff0c;选择合适的库是关键。以下是一些适合用于 2D CAD 开发的 Rust 库和工具&#xff0c;涵盖图形渲染、几何计算、用户界面等方面&#xff1a; 图形渲染 lyon 简介: lyon 是一个用于 2D 图形渲染的 Rust 库&#xff0c;支持路径填充、描边…...

C#中值类型与引用类型是直观使用示例

一、值类型与引用类型区分 正确理解值类型与引用类型&#xff0c;可以更好的帮助软件开发人员写出性能更好且正确稳定运行的程序&#xff1a; C#值类型与引用类型区别 区别值类型引用类型定义所有继承自【System.ValueType】类型的都是值类型&#xff08;valueType继承自Syste…...

Spring Cloud之负载均衡之LoadBalance

目录 负载均衡 问题 步骤 现象 什么是负载均衡&#xff1f; 负载均衡的一些实现 服务端负载均衡 客户端负载均衡 使用Spring Cloud LoadBalance实现负载均衡 负载均衡策略 ​编辑 ​编辑LoadBalancer原理 服务部署 准备环境和数据 服务构建打包 启动服务 上传J…...

MySQL的数据文件

MySQL的数据文件 mysql的数据都存放在datadir所指的位置&#xff0c;其中包含了mysql中创建的数据库&#xff0c;数据库中包含了表结构(frm文件)、表数据(myd文件)、表索引(myi文件) show variables like %datadir%.frm 存放和表相关的数据信息&#xff0c;主要包括表结构的定…...

【RabbitMQ高级特性】消息确认机制、持久化、发送方确认、TTL和死信队列

&#x1f525;个人主页&#xff1a; 中草药 &#x1f525;专栏&#xff1a;【中间件】企业级中间件剖析 一、消息确认机制 消费者确认机制确保消息被正确处理后才从队列中删除。如果消费者处理失败&#xff08;如业务异常或宕机&#xff09;&#xff0c;Broker 会重新投递消息…...

C# 正则表达式

C# 正则表达式 引言 正则表达式&#xff08;Regular Expression&#xff0c;简称Regex&#xff09;是一种用于处理字符串的强大工具&#xff0c;在编程领域有着广泛的应用。C# 作为一种流行的编程语言&#xff0c;也内置了对正则表达式的支持。本文将详细介绍 C# 中的正则表达…...

第十四届蓝桥杯省赛电子类单片机学习记录(客观题)

01.一个8位的DAC转换器&#xff0c;供电电压为3.3V&#xff0c;参考电压2.4V&#xff0c;其ILSB产生的输出电压增量是&#xff08;D&#xff09;V。 A. 0.0129 B. 0.0047 C. 0.0064 D. 0.0094 解析&#xff1a; ILSB&#xff08;最低有效位&#xff09;的电压增量计算公式…...

23种设计模式-桥接(Bridge)设计模式

桥接设计模式 &#x1f6a9;什么是桥接设计模式&#xff1f;&#x1f6a9;桥接设计模式的特点&#x1f6a9;桥接设计模式的结构&#x1f6a9;桥接设计模式的优缺点&#x1f6a9;桥接设计模式的Java实现&#x1f6a9;代码总结&#x1f6a9;总结 &#x1f6a9;什么是桥接设计模式…...

AI重塑视觉艺术:DeepSeek与蓝耘通义万相2.1的图生视频奇迹

云边有个稻草人-CSDN博客 近年来&#xff0c;深度学习、计算机视觉和生成模型在多个领域取得了突破性进展。其中&#xff0c;DeepSeek与蓝耘通义万相2.1图生视频的结合为图像生成与视频生成技术提供了新的发展方向。DeepSeek作为一个图像和视频生成的工具&#xff0c;能够利用深…...

mac怎么安装pycharm?

安装步骤&#xff1a;1、打开PyCharm官网&#xff0c;在官网首页点击“下载”按钮&#xff0c;选择“MacOS”版本进行下载&#xff1b;2、双击打开安装包&#xff0c;将PyCharm拖动到应用程序文件夹中&#xff1b;3、根据提示进行安装&#xff0c;在第一次运行PyCharm时&#x…...

HTML应用指南:利用POST请求获取城市肯德基门店位置信息

随着新零售业态的快速发展&#xff0c;门店位置信息的获取变得越来越重要。作为快餐服务行业的先锋&#xff0c;肯德基不仅在服务质量上持续领先&#xff0c;还积极构建广泛的门店网络&#xff0c;以支持其不断增长的用户群体。为了更好地理解和利用这些数据&#xff0c;本篇文…...

Java主流开发框架之请求响应常用注释

1.RestController 标记一个类为 REST 控制器&#xff0c;处理 HTTP 请求并直接返回数据&#xff08;如 JSON/XML&#xff09;&#xff0c;而不是视图&#xff08;如 HTML&#xff09;&#xff0c;一般是放在类的上边 RestController public class UserController {GetMapping…...

go的参数传递都是值传递,但切片需要注意

根据之前学习python和java的经验&#xff0c;每次学习一门新语言时&#xff0c;一定要搞清楚方法的参数传递是值传递&#xff0c;引用传递还是指针传递。 主要原因就是需要知道&#xff0c;某种类型的数据传递给某个方法后&#xff0c;方法里面对它的修改是否会影响到这个数据本…...

C++菜鸟教程 - 从入门到精通 第五节

一.各种排序 接下来,让我们开始学习排序! 1.选择排序 a.原理简介 选择排序&#xff08;Selection Sort&#xff09;是一种简单直观的排序算法。它的基本思想是每次从未排序的部分中选择最小&#xff08;或最大&#xff09;的元素&#xff0c;将其放到已排序部分的末尾&#xff…...

同一个局域网的话 如何访问另一台电脑的ip

在局域网内访问另一台电脑&#xff0c;可以通过以下几种常见的方法来实现&#xff1a; ‌直接通过IP地址访问‌&#xff1a; 首先&#xff0c;确保两台电脑都连接在同一个局域网内。获取目标电脑的IP地址&#xff0c;这可以通过在目标电脑上打开命令提示符&#xff08;Windows系…...

[学习笔记]攻防世界-bug

打开场景&#xff0c;提示我们需要登陆 我们先注册一下 注册成功 我们登陆进去 我们点击Manage他提示我们admin才能进入 我们刷新抓包一下试试 Cookie里面除了PHPSESSID&#xff0c;多出来了一个user&#xff0c;看上去是md5加密的&#xff0c;我们尝试解密 这里尝试了好几个网…...

[250324] Kafka 4.0.0 版本发布:告别 ZooKeeper,拥抱 KRaft!| Wine 10.4 发布!

目录 Kafka 4.0.0 版本发布&#xff1a;告别 ZooKeeper&#xff0c;拥抱 KRaft&#xff01;Wine 10.4 发布&#xff01; Kafka 4.0.0 版本发布&#xff1a;告别 ZooKeeper&#xff0c;拥抱 KRaft&#xff01; 近日&#xff0c;Apache Kafka 4.0.0 正式发布&#xff01;这是一个…...

【赵渝强老师】达梦数据库MPP集群的架构

为了支持海量数据存储和处理等方面的需求&#xff0c;为高端数据仓库提供解决方案&#xff0c;达梦数据库提供了大规模并行处理MPP架构&#xff0c;以极低的成本代价&#xff0c;提供高性能的并行计算。通过使用MPP可以解决以下问题&#xff1a; 需要较高的系统性能支持以支持…...

JWT 鉴权常见知识点及参考答案

JWT 鉴权常见知识点及参考答案 最近在 Go Web 项目当中使用到了 JWT 进行鉴权&#xff0c;因此通过这篇文章对 JWT 的原理及相关的知识点进行总结。 文章目录 JWT 鉴权常见知识点及参考答案JWT 签名算法的详细工作流程一. 签名的生成过程二. 签名的验证过程 1. 什么是 JWT&am…...

洛谷题单入门4-P5729 【深基5.例7】工艺品制作-python

输入格式 第一行三个正整数 w,x,h。 第二行一个正整数 q。 接下来 q 行&#xff0c;每行六个整数 输出格式 输出一个整数表示答案。 三维数组直接标记 class Solution:staticmethoddef oi_input():"""从标准输入读取数据"""w, x, h map(…...

【C语言】内存函数详解

个人主页 文章目录 &#x1f3e0;一、memcpy函数1.函数形式以及功能介绍2.函数的使用3.模拟实现 &#x1f680;二、memmove函数1.函数形式以及功能介绍2.函数的使用3.模拟实现 &#x1f3a1;三、memset函数1.函数形式以及功能介绍2.函数的使用 &#x1f389;四、memcmp1.函数形…...

使用Python开发自动驾驶技术:车道线检测模型

友友们好! 我是Echo_Wish,我的的新专栏《Python进阶》以及《Python!实战!》正式启动啦!这是专为那些渴望提升Python技能的朋友们量身打造的专栏,无论你是已经有一定基础的开发者,还是希望深入挖掘Python潜力的爱好者,这里都将是你不可错过的宝藏。 在这个专栏中,你将会…...

HTTP代理的全面解读:什么是HTTP代理?HTTP代理的工作原理

在互联网大潮中&#xff0c;每一个请求和返回数据的背后&#xff0c;都离不开传输协议的支持&#xff0c;而HTTP协议无疑是最熟悉的网络通信基础之一。当我们谈到HTTP代理时&#xff0c;它不仅让浏览网络变得更高效&#xff0c;也为数据采集以及全球性远程任务提供了解决方案。…...

DeepSeek底层揭秘——deepEP

1. 什么是 deepEP&#xff1f; (1) 定义 deepEP (DeepSeek EndPoint) 是 DeepSeek 开源的一款高性能、低延迟的分布式通信库&#xff0c;专为大规模深度学习训练和推理场景设计。它旨在优化分布式计算环境中的通信效率&#xff0c;特别是在节点间数据交换、梯度同步、模型分发…...

内网渗透(CSMSF) 构建内网代理的全面指南:Cobalt Strike 与 Metasploit Framework 深度解析

目录 1. Cobalt Strike 在什么情况下会构建内网代理&#xff1f; 2. Cobalt Strike 构建内网代理的主要作用和目的是什么&#xff1f; 3. Cobalt Strike 如何构建内网代理&#xff1f;需要什么条件和参数&#xff1f; 条件 步骤 参数 4. Cobalt Strike 内网代理能获取什…...

【redis】哨兵:人工恢复主节点故障和哨兵自动恢复主节点故障

文章目录 基本概念人工恢复主节点故障操作流程 哨兵自动恢复主节点故障哨兵集 Redis 的主从复制模式下&#xff0c;⼀旦主节点由于故障不能提供服务&#xff0c;需要⼈⼯进⾏主从切换&#xff0c;同时⼤量的客⼾端需要被通知切换到新的主节点上&#xff0c;对于上了⼀定规模的应…...

【Go 】异常处理

1. Go 语言错误处理基础 Go 语言尽量避免使用异常&#xff0c;推荐使用 返回错误 让调用者处理。Go 语言标准库提供 error 接口&#xff1a;type error interface {Error() string }errors.New("错误信息") 创建错误对象。 package mainimport ("errors"…...

微软纳德拉最新一期访谈

萨提亚纳德拉&#xff1a; 微软的AGI计划与量子突破| 2025.2.20 【文章核心预览&#xff1a;】 1、纳德拉回应AI价格战&#xff1a;效率提升将重塑需求&#xff0c;但关键是能否带动GDP增长至10% 2、微软AI收入130亿美元&#xff0c;4年后目标1300亿&#xff0c;但提醒"…...

WebSocket接入SSL证书

目录 碎碎念解决方法创建 HTTPS WebSocket 服务器创建系统服务启动服务 碎碎念 在访问网站时&#xff0c;使用 HTTPS 非常重要。HTTPS 协议不仅可以确保数据传输的安全性&#xff0c;还可以防止中间人攻击和数据篡改等安全问题。任何没有 SSL 证书的内容都可能会被拒绝访问。因…...

蓝桥杯——嵌入式学习日记

因为lED和LCD共用PC8~PC15引脚&#xff0c;要通过锁存&#xff08;LE&#xff09;和&#xff08;GPIOC->ODR&#xff09;来避免LED和LCD引脚冲突 修改点: main.c中&#xff0c;GPIO初始化引脚后&#xff0c;LE&#xff08;PD2引脚低电平锁存&#xff0c;退出透明模式&…...

第七课:Python基础排序算法与比较排序原理深度解析

比较排序算法是算法领域中的经典内容&#xff0c;其核心思想通过元素间的比较操作确定相对顺序。本文将深入探讨冒泡排序的优化策略、选择排序的变种实现、插入排序的典型应用场景&#xff0c;并通过统计比较次数直观展示算法效率差异。 一、冒泡排序的优化策略 传统冒泡排序存…...

项目流程中关键节点的测试类型

一、全流程测试框架图 #mermaid-svg-LmUdhLObstSpThwP {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-LmUdhLObstSpThwP .error-icon{fill:#552222;}#mermaid-svg-LmUdhLObstSpThwP .error-text{fill:#552222;strok…...