【Kafka 消息队列深度解析与应用】

Kafka 消息队列深度解析与应用

一、Kafka 概述

(一)产生背景

  • Kafka 最初是由 LinkedIn 开发,旨在解决其内部海量数据的实时传输问题。在现代大数据环境下,企业需要处理海量的数据流入和流出,包括用户的行为数据、系统日志、业务数据等,传统的消息队列系统在处理这些大数据量、高并发的数据时,面临着诸多挑战,如性能瓶颈、扩展性差、数据一致性难以保证等。Kafka 应运而生,它为大规模数据处理和实时数据传输提供了一个高性能、高可靠的分布式消息队列解决方案。

(二)特点

1. 高吞吐量
  • Kafka 能够处理海量的数据,支持每秒百万级别的消息传输,这得益于其高效的存储和网络 I/O 设计。从源码角度来看,在 Kafka 的存储层,使用了日志追加的存储方式,将消息顺序追加到磁盘上,避免了随机写操作,减少了磁盘寻道时间。例如,在 Log 类中,append() 方法负责将消息追加到日志文件中,其实现利用了操作系统的页缓存机制,使得写入操作可以在内存中完成,之后再由操作系统将数据异步刷到磁盘,提高了写入性能。在网络 I/O 方面,通过使用 Selector 类进行网络通信,采用了非阻塞式的 I/O 操作,结合零拷贝技术(FileChannel.transferTo() 方法的使用),减少了数据在用户态和内核态之间的拷贝次数,提高了数据传输效率,使 Kafka 可以高效地处理大量并发的生产者和消费者请求。
2. 可扩展性
  • Kafka 是分布式的,通过增加 Kafka 集群中的 Broker 节点可以轻松扩展系统的存储和处理能力。在源码中,KafkaController 类负责集群的管理和协调,当新节点加入时,会触发相应的负载均衡操作,如 onBrokerStartup() 方法会根据新节点的加入重新分配分区和副本,将部分分区的数据迁移到新节点上,确保数据分布的均匀性和负载的均衡,使 Kafka 可以灵活应对数据量的增长和并发的提高。
3. 持久性
  • Kafka 会将消息持久化存储在磁盘上,这确保了消息的可靠性,即使在消息被消费后,也可以根据配置的保留时间进行存储,以备后续的分析或重新消费。LogSegment 类负责存储消息的逻辑片段,它将消息存储在磁盘上的文件中,同时会根据配置的日志段大小和保留时间对消息进行清理或滚动,保证了消息存储的有序性和持久性。
4. 高可用性
  • Kafka 通过多副本机制来保证高可用性,每个主题的分区可以有多个副本,分布在不同的 Broker 节点上。在 ReplicaManager 类中,会对副本进行管理,通过 makeFollowers() 和 makeLeaders() 等方法实现副本的角色转换,当一个 Broker 出现故障时,其副本可以继续提供服务,保证了数据的可用性。

(三)核心架构

1. 生产者(Producer)
  • 生产者负责将消息发送到 Kafka 主题中。在 KafkaProducer 类中,会使用 RecordAccumulator 类来缓存消息,根据分区策略(如轮询、按关键字等)将消息分配到不同的分区,使用 Sender 类将消息发送到相应的 Broker。生产者可以配置一些重要的参数,如 acks 用于确定消息的确认机制(表示需要多少个副本确认收到消息才认为发送成功),batch.size 用于设置消息的批次大小,linger.ms 用于设置发送消息的延迟时间,以优化发送性能。
2. 消费者(Consumer)
  • 消费者从 Kafka 主题中订阅消息。在 KafkaConsumer 类中,使用 ConsumerCoordinator 类来协调消费者组内的消费者,使用 Fetcher 类从 Broker 中拉取消息。消费者可以配置 group.id 表示其所属的消费者组,通过 subscribe() 方法订阅主题,使用 poll() 方法拉取消息,还可以使用 commitSync() 或 commitAsync() 方法来提交消费偏移量,以便在下次消费时从正确的位置开始。
3. Broker
  • Broker 是 Kafka 集群中的服务节点,负责存储和处理消息。KafkaServer 类是 Broker 的核心,它包含多个组件,如 LogManager 负责日志存储管理,ReplicaManager 负责副本管理,SocketServer 负责网络通信,KafkaApis 类处理来自生产者和消费者的请求。
4. 主题(Topic)
  • 主题是消息的类别,生产者将消息发送到特定的主题,消费者从主题中消费消息。每个主题可以划分为多个分区,分区可以分布在不同的 Broker 上,这样可以提高并行处理能力。在 TopicConfig 类中可以对主题的各种属性进行配置,如分区数量、副本数量、消息保留时间等。

(四)应用场景

  • 大数据流处理:Kafka 可以作为大数据处理的数据源,将实时的数据流(如用户的点击流、传感器数据等)发送给下游的处理系统,如 Apache Spark 或 Apache Flink。这些大数据处理系统可以通过 Kafka 的消费者 API 实时消费数据,进行数据清洗、转换和分析。例如,在实时推荐系统中,用户的行为数据通过 Kafka 持续流入,Spark Streaming 可以实时消费这些数据,为用户提供实时的推荐内容。
  • 日志收集:在分布式系统中,不同的服务可以将日志信息发送到 Kafka,通过 Kafka 作为日志收集的中央枢纽,然后再将日志发送给日志存储和分析系统(如 Elasticsearch 和 Kibana 组合)。多个服务作为生产者将日志信息发送到 Kafka 主题,日志存储和分析系统作为消费者从 Kafka 中拉取日志信息进行存储和分析,实现了日志的集中管理和分析。

二、Kafka 的安装与配置

(一)安装过程

  • 下载 Kafka 软件包:
    首先,从 Kafka 官方网站下载适合你系统的 Kafka 软件包。
  • 解压和配置文件修改:
    解压后,进入 Kafka 的配置文件目录,主要修改 server.properties 文件。需要设置 broker.id 为每个 Broker 节点分配唯一的 ID,设置 listeners 以确定 Kafka 监听的网络地址和端口,设置 log.dirs 确定日志存储的目录,设置 zookeeper.connect 来指定 ZooKeeper 的连接地址(Kafka 依赖 ZooKeeper 进行集群管理)。

详细安装过程请参考这篇文章 Kafka实战

(二)代码示例:消息的生产和消费

1. 生产者代码示例
import org.apache.kafka.clients.producer.KafkaProducer;
import org.apache.kafka.clients.producer.Producer;
import org.apache.kafka.clients.producer.ProducerRecord;
import java.util.Properties;

public class KafkaProducerExample {
    public static void main(String[] args) {
        Properties properties = new Properties();
        properties.put("bootstrap.servers", "localhost:9092");
        properties.put("acks", "all");
        properties.put("retries", 0);
        properties.put("batch.size", 16384);
        properties.put("linger.ms", 1);
        properties.put("buffer.memory", 33554432);
        properties.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer");
        properties.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer");

        Producer<String, String> producer = new KafkaProducer<>(properties);
        for (int i = 0; i < 100; i++) {
            ProducerRecord<String, String> record = new ProducerRecord<>("test-topic", Integer.toString(i), "message " + i);
            producer.send(record);
        }
        producer.close();
    }
}

代码解释:

  • properties 中设置了生产者的各种配置,包括 bootstrap.servers 指定 Kafka 集群的地址,acks 确定消息确认机制,batch.size 决定消息的批次大小,linger.ms 决定消息的延迟发送时间,buffer.memory 是消息缓冲区的大小。

KafkaProducer 类是 Kafka 的生产者类,通过 send() 方法发送 ProducerRecord 消息,消息包含主题、键和值。这里将消息发送到 test-topic 主题,键为 i 的字符串表示,值为 message + i。

2. 消费者代码示例
import org.apache.kafka.clients.consumer.Consumer;
import org.apache.kafka.clients.consumer.ConsumerRecords;
import org.apache.kafka.clients.consumer.KafkaConsumer;
import java.util.Collections;
import java.util.Properties;

public class KafkaConsumerExample {
    public static void main(String[] args) {
        Properties properties = new org.apache.kafka.clients.consumer.Properties();
        properties.put("bootstrap.servers", "localhost:9092");
        properties.put("group.id", "test-group");
        properties.put("enable.auto.commit", "true");
        properties.put("auto.commit.interval.ms", "1000");
        properties.put("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
        properties.put("value.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");

        Consumer<String, String> consumer = new KafkaConsumer<>(properties);
        consumer.subscribe(Collections.singletonList("test-topic"));

        while (true) {
            ConsumerRecords<String, String> records = consumer.poll(100);
            records.forEach(record -> System.out.printf("offset = %d, key = %s, value = %s%n", record.offset(), record.key(), record.value()));
        }
    }
}

代码解释:

  • properties 中设置了消费者的各种配置,包括 bootstrap.servers 用于连接 Kafka 集群,group.id 表示消费者组的 ID,enable.auto.commit 表示是否自动提交消费偏移量,auto.commit.interval.ms 表示自动提交的时间间隔。

KafkaConsumer 类是消费者类,通过 subscribe() 方法订阅主题,使用 poll() 方法拉取消息,拉取到的消息存储在 ConsumerRecords 中,然后遍历并打印消息的偏移量、键和值。

(三)分区机制

1. 概念

分区是 Kafka对主题的进一步划分,将主题的数据分布在多个分区中,提高了并行处理能力。每个分区内的消息是有序的,但不同分区之间的消息顺序不保证。在DefaultPartitioner 类中,会根据不同的分区策略(如轮询、按消息键的哈希值等)将消息分配到不同的分区。

2. 实现原理

  • 在 ProducerRecord 中,如果没有指定分区,会使用 partitioner 类进行分区分配,例如,在 DefaultPartitioner 中,当使用轮询策略时,会根据递增的计数器将消息分配到不同分区;当使用哈希策略时,会根据消息键的哈希值对分区数取模来分配分区。

3. 性能

  • 分区可以提高 Kafka 的并行处理能力,多个生产者可以同时向不同的分区发送消息,多个消费者可以同时从不同的分区消费消息,提高了系统的吞吐量。在性能测试中,增加分区数可以在一定程度上提高系统的并发处理能力,但也会增加管理成本,过多的分区可能导致性能下降,需要根据实际情况进行调整。

(四)副本机制

1. 概念

  • 副本是为了保证数据的高可用性,每个分区可以有多个副本,分布在不同的 Broker上,其中一个是领导者(Leader),其余为跟随者(Follower)。

2. 实现原理

  • 在 ReplicaManager 类中,当消息发送到 Leader 副本时,Leader 会将消息复制给 Follower 副本,Follower 副本会不断从 Leader 副本同步消息。当 Leader 副本不可用时,会从 Follower 副本中选举出一个新的 Leader 副本。在 Partition 类中,makeLeader() 和 makeFollower() 方法负责角色的转换,确保消息的一致性和可用性。

3. 性能

  • 副本机制提高了 Kafka 的可用性,但也会增加网络和存储的开销,因为需要将消息复制到多个副本上。不过,在实际使用中,合理设置副本数可以在性能和可用性之间取得平衡,一般副本数为 2 或 3 比较常见。
    (五)消息的顺序性和高可用性
1. 消息顺序性
  • 在同一个分区内,Kafka 可以保证消息的顺序性,因为消息是按顺序追加存储的。生产者发送消息时,尽量将有顺序要求的消息发送到同一个分区,例如,在日志收集场景中,同一个服务的日志可以发送到同一个分区,保证日志的时间顺序。
  • 从源码角度,在 RecordBatch 类中,会将同一批次的消息存储在一个逻辑单元中,在发送到分区时会按顺序存储,保证了分区内消息的顺序性。
2. 高可用性
  • 高可用性通过副本机制、Broker 的故障转移和 ZooKeeper 的协调来保证。当 Broker 出现故障时,ZooKeeper 会通知 Kafka 集群,Kafka 会从 Follower 副本中选举新的 Leader,在 KafkaController 类中,onBrokerFailure() 方法会触发故障处理流程,确保服务的正常运行。

三、Kafka 的性能优化

(一)调整参数

1. 生产者参数优化
batch.size 和 linger.ms:
  • 增大 batch.size 可以将更多的消息打包成批次发送,减少网络请求次数,提高网络 I/O 效率;增加 linger.ms 可以延迟发送消息,让生产者有更多的时间收集消息形成批次。但如果设置过大,会增加消息的延迟,需要根据消息的流量和实时性要求进行调整。在 RecordAccumulator 类中,会根据这些参数来决定何时发送消息批次。
acks 和 retries:
  • acks 决定了消息发送的确认机制,设置为 all 可以保证消息的可靠性,但会增加发送延迟,可根据对消息可靠性的要求进行调整;retries 决定了发送失败时的重试次数,可根据网络状况和服务器的稳定性设置。
2. 消费者参数优化
fetch.min.bytes 和 fetch.max.wait.ms:
  • fetch.min.bytes 规定了消费者每次拉取的最小字节数,fetch.max.wait.ms 规定了消费者拉取消息的最大等待时间,合理设置可以提高消费者的拉取效率。在 Fetcher 类中,会根据这些参数来拉取消息,平衡消息的延迟和吞吐量。
3. Broker 参数优化
num.io.threads 和 num.replica.fetchers:
  • num.io.threads 决定了 Broker 处理网络 I/O 请求的线程数量,num.replica.fetchers 决定了副本同步的线程数量,根据服务器的 CPU 核心数和负载,可以调整这些参数以优化性能。在 KafkaServer 类中,会根据这些参数启动相应的线程。

(二)优化网络

  • 调整网络缓冲区:
    可以调整 Kafka 的网络缓冲区大小,在 SocketServer 类中,通过设置 socket.send.buffer.bytes 和 socket.receive.buffer.bytes 来优化网络发送和接收缓冲区的大小,提高网络传输效率。
  • 使用压缩:
    可以使用压缩算法(如 GZIP、Snappy 等)对消息进行压缩,在 ProducerConfig 中设置 compression.type 参数,减少网络传输的数据量,提高性能。

(三)与其他大数据组件的集成

1. 与 Spark 的集成

可以使用 Spark Streaming 从 Kafka 中消费数据,以下是一个简单的代码示例:

import org.apache.spark.SparkConf;
import org.apache.spark.streaming.Durations;
import org.apache.spark.streaming.api.java.JavaDStream;
import org.apache.spark.streaming.api.java.JavaStreamingContext;
import org.apache.spark.streaming.kafka010.ConsumerStrategies;
import org.apache.spark.streaming.kafka010.KafkaUtils;
import org.apache.spark.streaming.kafka010.LocationStrategies;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

public class SparkKafkaIntegration {
    public static void main(String[] args) {
        SparkConf conf = new SparkConf().setAppName("SparkKafkaIntegration").setMaster("local[2]");
        JavaStreamingContext jssc = new JavaStreamingContext(conf, Durations.seconds(1));

        Map<String, Object> kafkaParams = new HashMap<>();
        kafkaParams.put("bootstrap.servers", "localhost:9092");
        kafkaParams.put("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
        kafkaParams.put("value.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
        kafkaParams.put("group.id", "spark-group");
        kafkaParams.put("auto.offset.reset", "latest");
        kafkaParams.put("enable.auto.commit", false);

        JavaDStream<String> stream = KafkaUtils.createDirectStream(
                jssc,
                LocationStrategies.PreferConsistent(),
                ConsumerStrategies.Subscribe(Collections.singletonList("test-topic"), kafkaParams)
        ).map(record -> record.value());

        stream.foreachRDD(rdd -> {
            rdd.foreach(record -> {
                // 在这里对从 Kafka 中获取的数据进行处理,例如打印或其他计算操作
                System.out.println(record);
            });
        });

        jssc.start();
        try {
            jssc.awaitTermination();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

代码解释:

  • SparkConf 用于配置 Spark 应用程序,这里设置了应用程序名称和运行模式(local[2] 表示本地模式,使用 2 个线程)。
  • JavaStreamingContext 是 Spark Streaming 的上下文,设置了批处理的时间间隔为 1 秒。
  • kafkaParams 包含了连接 Kafka 所需的参数,如 Kafka 集群地址、键和值的反序列化器、消费者组 ID 等。
  • KafkaUtils.createDirectStream 方法创建了一个直接从 Kafka 接收数据的流,使用LocationStrategies.PreferConsistent() 表示数据在可用执行器之间均匀分配,使用 ConsumerStrategies.Subscribe 方法订阅 test-topic 主题。
  • map 操作将从 Kafka 获取的 ConsumerRecord 转换为消息的值。
  • foreachRDD 操作在每个 RDD 上执行操作,这里简单地将消息打印出来。
2. 与 Fluentd 的集成

Fluentd 是一个日志收集工具,可以将收集到的日志发送给 Kafka。

首先需要在 Fluentd 的配置文件中添加 Kafka 的输出插件,如下是一个简单的配置示例:

<source>
  @type forward
  port 24224
</source>

<match kafka.**>
  @type kafka
  brokers localhost:9092
  topic_key topic
  default_topic logs
  output_data_type json
  required_acks 1
  <buffer>
    flush_interval 5s
  </buffer>
</match>

解释:

  • 部分配置了 Fluentd 接收日志的源,这里使用 forward 类型接收来自其他服务的日志。
  • <match kafka.**> 部分配置了将日志发送到 Kafka,指定了 Kafka 的 brokers 地址,default_topic 为 logs,表示将日志发送到 logs 主题,output_data_type 为 json 表示日志以 JSON 格式发送,required_acks 表示消息的确认机制, 部分设置了消息的刷新间隔。

四、实际项目案例演示 Kafka 在大规模数据处理场景中的应用

(一)案例背景

假设我们有一个大型电商平台,需要处理大量的用户行为数据,包括用户的浏览、点击、购买等行为。这些数据需要实时处理和分析,以便为用户提供个性化推荐、统计分析等功能。

(二)架构设计

  • 数据采集:在电商平台的各个服务中,使用 Kafka 的生产者将用户行为数据发送到 Kafka 的 user-behavior 主题,根据用户的 ID 或行为类型将数据发送到不同的分区,以保证同一用户或同一类型的行为数据在同一分区内,保证数据的局部顺序性。
  • 数据处理:使用 Spark Streaming 从 Kafka 中消费数据,将数据进行清洗、转换和分析。对于用户的浏览数据,可以计算用户的浏览偏好;对于购买数据,可以更新库存和统计销售额等。
  • 数据存储和展示:处理后的数据存储在数据库(如 HBase 或 Cassandra)中,同时使用可视化工具(如 Grafana)展示统计结果。

(三)代码示例

1. 生产者(在电商服务中)
import org.apache.kafka.clients.producer.KafkaProducer;
import org.apache.kafka.clients.producer.Producer;
import org.apache.kafka.clients.producer.ProducerRecord;
import java.util.Properties;

public class EcommerceProducer {
    private static final String TOPIC = "user-behavior";
    private Producer<String, String> producer;

    public EcommerceProducer() {
        Properties properties = new Properties();
        properties.put("bootstrap.servers", "kafka-broker1:9092,kafka-broker2:9092");
        properties.put("acks", "all");
        properties.put("retries", 0);
        properties.put("batch.size", 16384);
        properties.put("linger.ms", 1);
        properties.put("buffer.memory", 33554432);
        properties.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer");
        properties.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer");
        producer = new KafkaProducer<>(properties);
    }

    public void sendUserBehavior(String userId, String behavior, String data) {
        String key = userId; 
        String value = behavior + ":" + data;
        ProducerRecord<String, String> record = new ProducerRecord<>(TOPIC, key, value);
        producer.send(record);
    }

    public void close() {
        producer.close();
    }
}

代码解释:
该生产者类将用户行为数据发送到 user-behavior 主题,根据用户 ID 作为键,将用户行为和相关数据作为值发送消息。
配置参数同之前的生产者示例,确保消息的可靠性和发送性能。

2. 消费者(Spark Streaming)
import org.apache.spark.SparkConf;
import org.apache.spark.streaming.Durations;
import org.apache.spark.streaming.api.java.JavaDStream;
import org.apache.spark.streaming.api.java.JavaStreamingContext;
import org.apache.spark.streaming.kafka010.ConsumerStrategies;
import org.apache.spark.streaming.kafka010.KafkaUtils;
import org.apache.spark.streaming.kafka010.LocationStrategies;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

public class EcommerceConsumer {
    public static void main(String[] args) {
        SparkConf conf = new SparkConf().setAppName("EcommerceConsumer").setMaster("local[4]");
        JavaStreamingContext jssc = new JavaStreamingContext(conf, Durations.seconds(5));

        Map<String, Object> kafkaParams = new HashMap<>();
        kafkaParams.put("bootstrap.servers", "kafka-broker1:9092,kafka-broker2:9092");
        kafkaParams.put("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
        kafkaParams.put("value.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
        kafkaParams.put("group.id", "ecommerce-group");
        kafkaParams.put("auto.offset.reset", "latest");
        kafkaParams.put("enable.auto.commit", false);

        JavaDStream<String> stream = KafkaUtils.createDirectStream(
                jssc,
                LocationStrategies.PreferConsistent(),
                ConsumerStrategies.Subscribe(Collections.singletonList("user-behavior"), kafkaParams)
        ).map(record -> record.value());

        stream.foreachRDD(rdd -> {
            rdd.foreachPartition(partition -> {
                while (partition.hasNext()) {
                    String behaviorData = partition.next();
                    // 对用户行为数据进行处理,例如解析数据,进行统计分析等
                    processBehaviorData(behaviorData);
                }
            });
        });

        jssc.start();
        try {
            jssc.awaitTermination();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    private static void processBehaviorData(String behaviorData) {
        // 这里可以根据具体业务需求进行数据的处理,例如解析数据,更新库存,计算用户偏好等
        System.out.println("Processing behavior data: " + behaviorData);
    }
}

代码解释:

  • EcommerceConsumer 从 user-behavior 主题中消费数据,使用 Spark Streaming 进行处理。
  • kafkaParams 包含了连接 Kafka 的参数,包括集群地址、反序列化器、消费者组等。
  • KafkaUtils.createDirectStream 创建了直接从 Kafka 接收数据的流,订阅了 user-behavior 主题。
  • foreachRDD 操作在每个 RDD 上进行处理,这里使用 foreachPartition 对每个分区的数据进行处理,processBehaviorData 方法可以根据具体业务需求进行用户行为数据的处理,如解析数据、更新库存、计算用户偏好等。

(四)性能优化和测试

性能测试:
  • 使用 JMeter 等工具模拟大量的用户行为数据发送,测试 Kafka 的生产者性能,观察消息发送的延迟和吞吐量。使用 Spark 的性能测试工具测试 Spark Streaming 的处理性能,观察数据处理的延迟和吞吐量。
性能优化:
  • 根据测试结果调整 Kafka 的生产者和消费者参数,如增加 batch.size 或 linger.ms 提高生产者性能,调整 fetch.min.bytes 等参数提高消费者性能。
  • 调整 Spark 的参数,如增加 spark.executor.instances 和 spark.executor.cores 提高 Spark 的处理能力。
(五)总结

通过上述的架构设计和代码实现,我们展示了 Kafka 在大规模数据处理场景中的应用。Kafka 作为一个强大的消息队列系统,通过其高吞吐量、可扩展性、高可用性等特点,结合 Spark 等大数据处理组件,可以有效地处理海量的实时数据。在实际应用中,需要根据具体的业务需求和性能测试结果,不断优化 Kafka 的参数和与其他组件的集成方式,以达到最佳的性能和数据处理效果。同时,需要关注 Kafka 的核心架构,如分区机制、副本机制,以保证数据的顺序性和可用性。

相关资料已更新
关注公众号:搜 架构研究站,回复:资料领取,即可获取全部面试题以及1000+份学习资料
在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【无线传感网】无线传感器网络覆盖技术

文章目录 覆盖算法设计思路及性能评价标准覆盖感知模型布尔感知模型概率感知模型 无线传感网络覆盖算法分类按照配置方式确定性覆盖随机性覆盖 根据覆盖目标面覆盖点覆盖栅栏覆盖 典型的WSN覆盖算法与协议基于网格的覆盖定位传感器配置算法圆周覆盖连通传感器覆盖轮换活跃/休眠…

canvas+fabric实现时间刻度尺(二)

前言 我们前面实现了时间刻度尺&#xff0c;鼠标移动显示时间&#xff0c;接下来我们实现鼠标点击某个时间进行弹框。 效果 实现 1.监听鼠标按下事件 2.编写弹框页面 3.时间转换 <template><div><canvas id"rulerCanvas" width"1200"…

Python-MNE-源空间和正模型04:头模型和前向计算

我们知道&#xff0c;在MNE分析中坐标是很重要的&#xff0c;这个前面也提及过了配准的一些方法&#xff0c;总的来说&#xff0c;MNE和freesurfer中使用的配准系统以及他们之间的关系如下图所示&#xff1a;除了传感器坐标之外&#xff0c;所有的坐标系都是笛卡尔坐标系&#…

Linux 内核调试

系列文章目录 Linux内核学习 Linux 知识 QEMU 虚拟机 Linux 调试视频 近阶段补充知识 WSL Ubuntu 文章目录 系列文章目录一、WSL二、QEMU1、安装2、退出 三、构建根文件系统1、下载 BusyBox2、编译3、构建文件目录&#xff1a;Makefileinit 四、内核编译1、下载2、构建 五、调试…

SpringBoot 事务

前情提要 飞书的文档不好转移,可以直接看我的飞书:Docs 什么是事务 是一组操作的集合,是一个不可分割的操作 事物会将所有操作当作一个整体,同时对数据库进行操作请求,这些操作要么全部成功,要么全部失败 总会有一些操作,需要同步进行,这个时候就需要使用事务 数据库中,自…

汇川Easy系列正弦信号发生器(ST源代码)

正弦余弦信号发生器CODESYS和MATLAB实现请参考下面文章链接: 正弦余弦信号发生器应用(CODESYS ST源代码+MATLAB仿真)_st语言根据输入值,形成正弦点-CSDN博客文章浏览阅读410次。本文介绍了如何在CODESYS编程环境中创建正弦和余弦信号发生器。通过详细的PLC梯形图和SCL语言代码…

【JMeter详解】

JMeter详解 Apache JMeter 是一个开源的、100%纯Java应用程序&#xff0c;设计用于负载测试和性能测量。它最初是为测试Web应用程序而设计的&#xff0c;但后来扩展到其他测试功能。JMeter可以用来对静态和动态资源&#xff08;如静态文件、Servlets、Perl脚本、Java对象、数据…

uniapp:微信小程序文本长按无法出现复制菜单

一、问题描述 在集成腾讯TUI后&#xff0c;为了能让聊天文本可以复制&#xff0c;对消息组件的样式进行修改&#xff0c;主要是移除下面的user-select属性限制&#xff1a; user-select: none;-webkit-user-select: none;-khtml-user-select: none;-moz-user-select: none;-ms…

查看 GitHub 仓库的创建时间

查看 GitHub 仓库的创建时间 1. https://api.github.com/repos/{owner}/{repository}2. curl -s https://api.github.com/repos/{owner}/{repository} | jq .created_atReferences 1. https://api.github.com/repos/{owner}/{repository} REST API endpoints for repositories…

VScode怎么重启

原文链接&#xff1a;【vscode】vscode重新启动 键盘按下 Ctrl Shift p 打开命令行&#xff0c;如下图&#xff1a; 输入Reload Window&#xff0c;如下图&#xff1a;

【无线传感网】WSN数据管理技术

文章目录 WSN数据管理的基本概念以数据为中心的WSN数据库与分布式数据库相比具有的特殊性WSN数据管理技术的研究热点 WSN数据管理的关键技术无线传感器网络数据存储结构网外集中式存储方案网内分层存储方案网内本地存储方案以数据为中心的网内存储方案 数据查询处理技术查询类型…

python调用gemini2.0接口识别图片文字

import os import base64 import google.generativeai as genai# 配置 Google API Key # 可以在系统环境变量设置 GOOGLE_API_KEY GOOGLE_API_KEY os.getenv("GOOGLE_API_KEY", "AIzaSXXXXXXXXXXXXXX") # 替换成你的 API Key# 设置 Gemini 模型名称 mode…

Linux Debian安装ClamAV和命令行扫描病毒方法,以及用Linux Shell编写了一个批量扫描病毒的脚本

ClamAV是一个开源的跨平台病毒扫描引擎&#xff0c;用于检测恶意软件、病毒、木马等安全威胁。 一、Linux Debian安装ClamAV 在Linux Debian系统上安装ClamAV&#xff0c;你可以按照以下步骤进行&#xff1a; 更新软件包列表&#xff1a; 打开终端并更新你的软件包列表&#…

【机器学习篇】穿越数字迷雾:机器深度学习的智慧领航

引言&#xff1a; 在当今科技飞速发展的时代&#xff0c;机器深度学习已成为推动众多领域变革的核心力量&#xff0c;从语音识别到图像分类&#xff0c;从自然语言处理到自动驾驶&#xff0c;其影响力无处不在。深度学习模拟人类大脑的神经网络结构&#xff0c;使计算机能够自…

CAN总线波形中最后一位电平偏高或ACK电平偏高问题分析

参考&#xff1a;https://zhuanlan.zhihu.com/p/689336144 有时候看到CAN总线H和L的差值波形的最后一位电平会变高很多&#xff0c;这是什么原因呢&#xff1f; 实际上这是正常的现象&#xff0c;最后一位是ACK位。问题描述为&#xff1a;CAN总线ACK电平偏高。 下面分析下原因…

B2B营销的新篇章:开源AI智能名片S2B2C商城小程序的应用探索

摘要&#xff1a; B2B营销&#xff0c;作为企业间营销活动的总称&#xff0c;因其独特的业务特性而呈现出不同于B2C营销的显著特征。在数字化转型的大潮中&#xff0c;B2B企业正积极探索新的营销手段以提高效率和竞争力。本文旨在探讨B2B营销的基本特性&#xff0c;并重点引入…

Kotlin在医疗大健康域的应用实例探究与编程剖析(上)

一、引言 1.1 研究背景与意义 在当今数字化时代,医疗行业正经历着深刻的变革。随着信息技术的飞速发展,尤其是人工智能、大数据、物联网等新兴技术的广泛应用,医疗行业数字化转型已成为必然趋势。这种转型旨在提升医疗服务的效率和质量,优化医疗资源配置,为患者提供更加…

【电机控制】基于STC8H1K28的六步换向——方波驱动(软件篇)

【电机控制】基于STC8H1K28的六步换向——方波驱动&#xff08;软件篇&#xff09; 文章目录 [TOC](文章目录) 前言一、main.c二、GPIO.c三、PWMA.c四、ADC.c五、CMP.c六、Timer.c七、PMSM.c八、参考资料总结 前言 【电机控制】STC8H无感方波驱动—反电动势过零检测六步换向法 …

一个在ios当中采用ObjectC和opencv来显示图片的实例

前言 在ios中采用ObjectC编程利用opencv来显示一张图片&#xff0c;并简单绘图。听上去似乎不难&#xff0c;但是实际操作下来&#xff0c;却不是非常的容易的。本文较为详细的描述了这个过程&#xff0c;供后续参考。 一、创建ios工程 1.1、选择ios工程类型 1.2、选择接口模…

arcgis模版空库怎么用(一)

这里以某个项目的数据为例&#xff1a; 可以看到&#xff0c;属性表中全部只有列标题&#xff0c;无数据内容 可能有些人会认为空库是用来往里面加入信息的&#xff0c;其实不是&#xff0c;正确的用法如下&#xff1a; 一、下图是我演示用的数据&#xff0c;我们可以看到其中…