凡科建站容易吗/广州seo推广优化

凡科建站容易吗,广州seo推广优化,图片网站 代码,深圳建设公司网站Kafka分区分配策略详解 Kafka作为当前最流行的分布式消息队列系统,其分区分配策略直接影响着系统的性能、可靠性和可扩展性。合理的分区分配不仅能够提高数据处理的效率,还能确保系统负载的均衡。 Kafka提供了多种内置的分区分配策略,包括R…

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策略则在减少分区迁移方面具有明显优势。而自定义策略的灵活性,则为特定业务场景提供了更多可能性。

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

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

相关文章

DeepSeek 助力 Vue3 开发:打造丝滑的表格(Table)之添加导出数据功能

前言:哈喽,大家好,今天给大家分享一篇文章!并提供具体代码帮助大家深入理解,彻底掌握!创作不易,如果能帮助到大家或者给大家一些灵感和启发,欢迎收藏+关注哦 💕 目录 DeepSeek 助力 Vue3 开发:打造丝滑的表格(Table)之添加导出数据功能📚页面效果📚指令输入�…

《Python实战进阶》第31集:特征工程:特征选择与降维技术

第31集&#xff1a;特征工程&#xff1a;特征选择与降维技术 摘要 特征工程是机器学习和数据科学中不可或缺的一环&#xff0c;其核心目标是通过选择重要特征和降低维度来提升模型性能并减少计算复杂度。本集聚焦于特征选择与降维技术&#xff0c;涵盖过滤法、包裹法、嵌入法等…

Excel第41套全国人口普查

2. 导入网页中的表格&#xff1a;数据-现有链接-考生文件夹&#xff1a;网页-找到表格-点击→变为√-导入删除外部链接关系&#xff1a;数据-点击链接-选中连接-删除-确定&#xff08;套用表格格式-也会是删除外部链接&#xff09;数值缩小10000倍&#xff08;除以10000即可&am…

WPS宏开发手册——使用、工程、模块介绍

目录 系列文章前言1、开始1.1、宏编辑器使用步骤1.2、工程1.3、工程 系列文章 使用、工程、模块介绍 JSA语法 第三篇练习练习题&#xff0c;持续更新中… 前言 如果你是开发人员&#xff0c;那么wps宏开发对你来说手拿把切。反之还挺吃力&#xff0c;需要嘻嘻&#xf…

EtherCAT转CANopen配置CANopen侧的PDO映射

EtherCAT转CANopen配置CANopen侧的PDO映射 在工业自动化领域&#xff0c;EtherCAT和CANopen是两种广泛应用的通信协议。它们各自具有独特的优势&#xff0c;但在某些应用场景下&#xff0c;需要将这两种协议进行转换以实现设备间的高效数据交换。本文将详细介绍如何在使用Ethe…

【QT】Qt creator快捷键

Qt creator可以通过以下步骤快捷键査看调用关系&#xff1a; 1.打开代码文件。 2.将光标放在你想要查看调用关系的函数名上。 3.按下键盘快捷键 CtrlshiftU。 4.弹出菜单中选择“调用路径”或“被调用路径” 5.在弹出的窗口中可以查看函数的调用关系 折叠或展开代码快捷键&…

【RHCE】LVS-NAT模式负载均衡实验

目录 题目 IP规划 配置IP RS1 RS2 RS3 LVS client 配置RS 配置LVS 安装lvs软件 启动ipvsadm服务 lvs规则匹配 ipvsadm部分选项 客户端测试 总结 题目 使用LVS的 NAT 模式实现 3 台RS的轮询访问&#xff0c;IP地址和主机自己规划。 IP规划 主机IP地址RS1-nat模…

排序算法(插入,希尔,选择,冒泡,堆,快排,归并)

1.插入排序 插入排序的主要思想是额外申请一个空间cur&#xff0c;让cur一开始等于数组的第1号位置,设置i1&#xff0c;让i-1的元素与其比较&#xff0c;如果arr[i-1]>arr[i]&#xff0c;就让arr[i1] arr[i]&#xff0c;当进行到最后一次对比结束&#xff0c;i-1,再让arr[…

LiteIDE中配置golang编译生成无CMD窗口EXE的步骤

LiteIDE中配置golang编译生成无CMD窗口EXE的步骤 一、环境配置1、设置GOROOT‌2、配置GOPATH‌ 二、项目编译参数设置1、新建/打开项目‌2、修改编译配置‌3、其他优化选项&#xff08;可选&#xff09;‌ 三、构建与验证1、编译生成EXE‌2、验证无窗口效果‌ 四、注意事项 一、…

Maya基本操作

基本操作 按住ALT键&#xff0c;左键旋转视角&#xff0c;中键平移视角&#xff0c;右键放大缩小视角。 按空格键切换4格视图。 导入FBX格式文件后&#xff0c;无贴图显示。 按6键开启。着色纹理显示 坐标轴相关 修改菜单-左键最上面的虚线。固定修改选项窗口。 选中物体…

Windows打开ftp局域网共享

前提是windows已经设置好开机账号密码了&#xff0c;否则教程不适用 第一先打开电脑ftp共享配置 点击保存即可 2.设置要共享到其他电脑的文件路径&#xff08;如果你要共享整个盘你就设置整个盘&#xff0c;如果是共享盘中某文件就设置某文件&#xff0c;这里是某文件&#x…

overleaf中会议参考文献使用什么标签:inproceedings

overleaf中会议参考文献使用什么标签 会议论文在LaTeX文献条目中应使用 @inproceedings 标签,而非 @article。根据你提供的内容,修正后的格式如下: @inproceedings{asai2023self, author = {Asai, Akari and Wu, Zeqiu and Wang, Yizhong and Sil, Avirup and Hajishirzi,…

一文详解redis

redis 5种数据类型 string 字符串是 Redis 里最基础的数据类型&#xff0c;一个键对应一个值。 设置值 SET key value例如&#xff1a; SET name "John"获取值 GET key例如&#xff1a; GET namelist 列表是简单的字符串列表&#xff0c;按插入顺序排序。 在列…

第16章:基于CNN和Transformer对心脏左心室的实验分析及改进策略

目录 1. 项目需求 2. 网络选择 2.1 UNet模块 2.2 TransUnet 2.2.1 SE模块 2.2.2 CBAM 2.3 关键代码 3 对比试验 3.1 unet 3.2 transformerSE 3.3 transformerCBAM 4. 结果分析 5. 推理 6. 下载 1. 项目需求 本文需要做的工作是基于CNN和Transformer的心脏左心室…

【AI】知识蒸馏-简单易懂版

1 缘起 最近要准备升级材料&#xff0c;里面有一骨碌是介绍LLM相关技术的&#xff0c;知识蒸馏就是其中一个点&#xff0c; 不过&#xff0c;只分享了蒸馏过程&#xff0c;没有讲述来龙去脉&#xff0c;比如没有讲解Softmax为什么引入T、损失函数为什么使用KL散度&#xff0c;…

2024年数维杯数学建模B题生物质和煤共热解问题的研究解题全过程论文及程序

2024年数维杯数学建模 B题 生物质和煤共热解问题的研究 原题再现&#xff1a; 随着全球能源需求的不断增长和对可再生能源的追求&#xff0c;生物质和煤共热解作为一种潜在的能源转化技术备受关注。生物质是指可再生能源&#xff0c;源自植物和动物的有机物质&#xff0c;而煤…

Spring相关API

1是相对路径 2 是绝对路径 3 在注解时使用

Netty源码—客户端接入流程

1.关于Netty客户端连接接入问题整理 一.Netty是在哪里检测有新连接接入的&#xff1f; 答&#xff1a;boss线程第一个过程轮询出ACCEPT事件&#xff0c;然后boss线程第二个过程通过JDK底层Channel的accept()方法创建一条连接。 二.新连接是怎样注册到NioEventLoop线程的&#x…

领域驱动设计(DDD)实践入门

文章目录 1.认识领域驱动设计1.1 简介1.2 发展历史1.3 DDD 的兴起 2.从一个简单案例2.1 转账需求2.2 设计的问题2.3 违反的设计原则 3.使用 DDD 进行重构抽象数据存储层抽象第三方服务抽象中间件封装业务逻辑重构后的架构 4.小结参考文献 1.认识领域驱动设计 1.1 简介 领域驱…

nuxt3网站文章分享微信 ,QQ功能

1.安装 npm install qrcode --save-dev 2.组件使用 <div class"share"><div style"line-height: 69px; color: #fff;width: 100px;"><p style"text-align: center;">分享:</p></div><div click"shareToMi…