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

Kafka MQ 生产者

Kafka MQ 生产者

生产者概览

尽管生产者 API 使用起来很简单,但消息的发送过程还是有点复杂的。图 3-1 展示了向
Kafka 发送消息的主要步骤。

在这里插入图片描述

我们从创建一个 ProducerRecord 对象开始,ProducerRecord 对象需要包含目标主题和要发送的内容。我们还可以指定键或分区。在发送 ProducerRecord 对象时,生产者要先把键和值对象序列化成字节数组,这样它们才能够在网络上传输。

接下来,数据被传给分区器。如果之前在 ProducerRecord 对象里指定了分区,那么分区器就不会再做任何事情,直接把指定的分区返回。如果没有指定分区,那么分区器会根据 ProducerRecord 对象的键来选择一个分区。选好分区以后,生产者就知道该往哪个主题和分区发送这条记录了。紧接着,这条记录被添加到一个记录批次里,这个批次里的所有消 息会被发送到相同的主题和分区上。有一个独立的线程负责把这些记录批次发送到相应的 broker 上。

服务器在收到这些消息时会返回一个响应。如果消息成功写入 Kafka,就返回一个 RecordMetaData 对象,它包含了主题和分区信息,以及记录在分区里的偏移量。如果写入失败,则会返回一个错误。生产者在收到错误之后会尝试重新发送消息,几次之后如果还是失败,就返回错误信息。

创建Kafka生产者

要往 Kafka 写入消息,首先要创建一个生产者对象,并设置一些属性。Kafka 生产者有 3 个必选的属性。

bootstrap.servers

该属性指定 broker 的地址清单,地址的格式为 host:port。清单里不需要包含所有的 broker 地址,生产者会从给定的 broker 里查找到其他 broker 的信息。不过建议至少要提供两个 broker 的信息,一旦其中一个宕机,生产者仍然能够连接到集群上。

key.serializer

broker 希望接收到的消息的键和值都是字节数组。生产者接口允许使用参数化类型,因 此可以把 Java 对象作为键和值发送给 broker。这样的代码具有良好的可读性,不过生产者需要知道如何把这些 Java 对象转换成字节数组。key.serializer 必须被设置为一个实现了 org.apache.kafka.common.serialization.Serializer 接口的类,生产者会使 用这个类把键对象序列化成字节数组。Kafka 客户端默认提供了 ByteArraySerializer
(这个只做很少的事情)、StringSerializer 和 IntegerSerializer,因此,如果你只 使用常见的几种 Java 对象类型,那么就没必要实现自己的序列化器。要注意,key. serializer 是必须设置的,就算你打算只发送值内容。

value.serializer

与 key.serializer 一样,value.serializer 指定的类会将值序列化。如果键和值都是字符串,可以使用与 key.serializer 一样的序列化器。如果键是整数类型而值是字符串, 那么需要使用不同的序列化器。
下面的代码片段演示了如何创建一个新的生产者,这里只指定了必要的属性,其他使用默认设置。


// ➊
private Properties kafkaProps = new Properties(); 
kafkaProps.put("bootstrap.servers", "broker1:9092,broker2:9092");
// ➋
kafkaProps.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer"); 
kafkaProps.put("value.serializer","org.apache.kafka.common.serialization.StringSerializer");// ➌
producer = new KafkaProducer<String, String>(kafkaProps); 
  • ➊ 新建一个 Properties 对象。
  • ➋ 因为我们打算把键和值定义成字符串类型,所以使用内置的 StringSerializer。
  • ➌ 在这里我们创建了一个新的生产者对象,并为键和值设置了恰当的类型,然后把 Properties 对象传给它。

这个接口很简单,通过配置生产者的不同属性就可以很大程度地控制它的行为。Kafka 的文档涵盖了所有的配置参数,我们将在这一章的后面部分介绍其中几个比较重要的参数。

实例化生产者对象后,接下来就可以开始发送消息了。发送消息主要有以下 3 种方式。

发送并忘记(fire-and-forget)

我们把消息发送给服务器,但并不关心它是否正常到达。大多数情况下,消息会正常到 达,因为 Kafka 是高可用的,而且生产者会自动尝试重发。不过,使用这种方式有时候也会丢失一些消息。

同步发送

我们使用 send() 方法发送消息,它会返回一个 Future 对象,调用 get() 方法进行等待, 就可以知道消息是否发送成功。

异步发送

我们调用 send() 方法,并指定一个回调函数,服务器在返回响应时调用该函数。

在下面的几个例子中,我们会介绍如何使用上述几种方式来发送消息,以及如何处理可能发生的异常情况。

本章的所有例子都使用单线程,但其实生产者是可以使用多线程来发送消息的。刚开始的 时候可以使用单个消费者和单个线程。如果需要更高的吞吐量,可以在生产者数量不变的 前提下增加线程数量。如果这样做还不够,可以增加生产者数量。

发送消息到Kafka

// ➊
ProducerRecord<String, String> record =new ProducerRecord<>("CustomerCountry", "Precision Products", "France");
try { // ➋producer.send(record);
} catch (Exception e) { // ➌e.printStackTrace();
}
  • ➊ 生产者的 send() 方法将 ProducerRecord 对象作为参数,所以我们要先创建一个 ProducerRecord 对象。ProducerRecord 有多个构造函数,稍后我们会详细讨论。这里使 用其中一个构造函数,它需要目标主题的名字和要发送的键和值对象,它们都是字符串。键和值对象的类型必须与序列化器和生产者对象相匹配。
  • ➋ 我们使用生产者的 send() 方法发送 ProducerRecord 对象。从生产者的架构图里可以看到,消息先是被放进缓冲区,然后使用单独的线程发送到服务器端。send() 方法会返 回一个包含 RecordMetadata 的 Future 对象,不过因为我们会忽略返回值,所以无法知 道消息是否发送成功。如果不关心发送结果,那么可以使用这种发送方式。比如,记录 Twitter 消息日志,或记录不太重要的应用程序日志。
  • ➌ 我们可以忽略发送消息时可能发生的错误或在服务器端可能发生的错误,但在发送消息之前,生产者还是有可能发生其他的异常。这些异常有可能是 SerializationException (说明序列化消息失败)、BufferExhaustedException 或 TimeoutException(说明缓冲区已满),又或者是 InterruptException(说明发送线程被中断)。

同步发送消息

最简单的同步发送消息方式如下所示。

 ProducerRecord<String, String> record =new ProducerRecord<>("CustomerCountry", "Precision Products", "France");
try {// ➊producer.send(record).get();
} catch (Exception e) { // ➋e.printStackTrace();
}
  • ➊ 在这里,producer.send() 方法先返回一个 Future 对象,然后调用 Future 对象的 get() 方法等待 Kafka 响应。如果服务器返回错误,get() 方法会抛出异常。如果没有发生错 误,我们会得到一个 RecordMetadata 对象,可以用它获取消息的偏移量。
  • ➋ 如果在发送数据之前或者在发送过程中发生了任何错误,比如 broker 返回了一个不允 许重发消息的异常或者已经超过了重发的次数,那么就会抛出异常。我们只是简单地把异常信息打印出来。

KafkaProducer 一般会发生两类错误。其中一类是可重试错误,这类错误可以通过重发消息 来解决。比如对于连接错误,可以通过再次建立连接来解决,“无主(no leader)”错误则可 以通过重新为分区选举首领来解决。KafkaProducer 可以被配置成自动重试,如果在多次重 试后仍无法解决问题,应用程序会收到一个重试异常。另一类错误无法通过重试解决,比如“消息太大”异常。对于这类错误,KafkaProducer 不会进行任何重试,直接抛出异常。

异步发送消息

假设消息在应用程序和 Kafka 集群之间一个来回需要 10ms。如果在发送完每个消息后都 等待回应,那么发送 100 个消息需要 1 秒。但如果只发送消息而不等待响应,那么发送 100 个消息所需要的时间会少很多。大多数时候,我们并不需要等待响应——尽管 Kafka 会把目标主题、分区信息和消息的偏移量发送回来,但对于发送端的应用程序来说不是必需的。不过在遇到消息发送失败时,我们需要抛出异常、记录错误日志,或者把消息写入 “错误消息”文件以便日后分析。

为了在异步发送消息的同时能够对异常情况进行处理,生产者提供了回调支持。下面是使 用回调的一个例子。

//➊ 
private class DemoProducerCallback implements Callback {@Overridepublic void onCompletion(RecordMetadata recordMetadata, Exception e) {if (e != null) {// ➋ e.printStackTrace();}} 
}// ➌
ProducerRecord<String, String> record =new ProducerRecord<>("CustomerCountry", "Biomedical Materials", "USA");
//➍
producer.send(record, new DemoProducerCallback());
  • ➊ 为了使用回调,需要一个实现了 org.apache.kafka.clients.producer.Callback 接口的 类,这个接口只有一个 onCompletion 方法。
  • ➋ 如果 Kafka 返回一个错误,onCompletion 方法会抛出一个非空(non null)异常。这里 我们只是简单地把它打印出来,但是在生产环境应该有更好的处理方式。
  • ➌ 记录与之前的一样。
  • ➍ 在发送消息时传进去一个回调对象。

生产者的配置

到目前为止,我们只介绍了生产者的几个必要配置参数——bootstrap.servers API 以及序列化器。

生产者还有很多可配置的参数,在 Kafka 文档里都有说明,它们大部分都有合理的默认 值,所以没有必要去修改它们。不过有几个参数在内存使用、性能和可靠性方面对生产者 影响比较大,接下来我们会一一说明。

1. acks

acks 参数指定了必须要有多少个分区副本收到消息,生产者才会认为消息写入是成功的。 这个参数对消息丢失的可能性有重要影响。该参数有如下选项。

  • 如果 acks=0,生产者在成功写入消息之前不会等待任何来自服务器的响应。也就是说, 如果当中出现了问题,导致服务器没有收到消息,那么生产者就无从得知,消息也就丢 失了。不过,因为生产者不需要等待服务器的响应,所以它可以以网络能够支持的最大 速度发送消息,从而达到很高的吞吐量。
  • 如果 acks=1,只要集群的首领节点收到消息,生产者就会收到一个来自服务器的成功 响应。如果消息无法到达首领节点(比如首领节点崩溃,新的首领还没有被选举出来), 生产者会收到一个错误响应,为了避免数据丢失,生产者会重发消息。不过,如果一个 没有收到消息的节点成为新首领,消息还是会丢失。这个时候的吞吐量取决于使用的是同步发送还是异步发送。如果让发送客户端等待服务器的响应(通过调用 Future 对象 的 get() 方法),显然会增加延迟(在网络上传输一个来回的延迟)。如果客户端使用回 调,延迟问题就可以得到缓解,不过吞吐量还是会受发送中消息数量的限制(比如,生 产者在收到服务器响应之前可以发送多少个消息)。
  • 如果 acks=all,只有当所有参与复制的节点全部收到消息时,生产者才会收到一个来自服务器的成功响应。这种模式是最安全的,它可以保证不止一个服务器收到消息,就算 有服务器发生崩溃,整个集群仍然可以运行(第 5 章将讨论更多的细节)。不过,它的 延迟比 acks=1 时更高,因为我们要等待不只一个服务器节点接收消息。

2. buffer.memory

该参数用来设置生产者内存缓冲区的大小,生产者用它缓冲要发送到服务器的消息。如果 应用程序发送消息的速度超过发送到服务器的速度,会导致生产者空间不足。这个时候, send() 方法调用要么被阻塞,要么抛出异常,取决于如何设置 block.on.buffer.full 参数
(在 0.9.0.0 版本里被替换成了 max.block.ms,表示在抛出异常之前可以阻塞一段时间)。

3. compression.type

默认情况下,消息发送时不会被压缩。该参数可以设置为 snappy、gzip 或 lz4,它指定了 消息被发送给 broker 之前使用哪一种压缩算法进行压缩。snappy 压缩算法由 Google 发明, 它占用较少的 CPU,却能提供较好的性能和相当可观的压缩比,如果比较关注性能和网 络带宽,可以使用这种算法。gzip 压缩算法一般会占用较多的 CPU,但会提供更高的压缩 比,所以如果网络带宽比较有限,可以使用这种算法。使用压缩可以降低网络传输开销和 存储开销,而这往往是向 Kafka 发送消息的瓶颈所在。

4. retries

生产者从服务器收到的错误有可能是临时性的错误(比如分区找不到首领)。在这种情况 下,retries 参数的值决定了生产者可以重发消息的次数,如果达到这个次数,生产者会 放弃重试并返回错误。默认情况下,生产者会在每次重试之间等待 100ms,不过可以通过 retry.backoff.ms 参数来改变这个时间间隔。建议在设置重试次数和重试时间间隔之前, 先测试一下恢复一个崩溃节点需要多少时间(比如所有分区选举出首领需要多长时间), 让总的重试时间比 Kafka 集群从崩溃中恢复的时间长,否则生产者会过早地放弃重试。不 过有些错误不是临时性错误,没办法通过重试来解决(比如“消息太大”错误)。一般情 况下,因为生产者会自动进行重试,所以就没必要在代码逻辑里处理那些可重试的错误。 你只需要处理那些不可重试的错误或重试次数超出上限的情况。

5. batch.size

当有多个消息需要被发送到同一个分区时,生产者会把它们放在同一个批次里。该参数指 定了一个批次可以使用的内存大小,按照字节数计算(而不是消息个数)。当批次被填满, 批次里的所有消息会被发送出去。不过生产者并不一定都会等到批次被填满才发送,半满 的批次,甚至只包含一个消息的批次也有可能被发送。所以就算把批次大小设置得很大, 也不会造成延迟,只是会占用更多的内存而已。但如果设置得太小,因为生产者需要更频 繁地发送消息,会增加一些额外的开销。
Kafka生产者——向Kafka写入数据 | 37

6. linger.ms

该参数指定了生产者在发送批次之前等待更多消息加入批次的时间。KafkaProducer 会在 批次填满或 linger.ms 达到上限时把批次发送出去。默认情况下,只要有可用的线程,生 产者就会把消息发送出去,就算批次里只有一个消息。把 linger.ms 设置成比 0 大的数, 让生产者在发送批次之前等待一会儿,使更多的消息加入到这个批次。虽然这样会增加延 迟,但也会提升吞吐量(因为一次性发送更多的消息,每个消息的开销就变小了)。

7. client.id

该参数可以是任意的字符串,服务器会用它来识别消息的来源,还可以用在日志和配额指 标里。

8. max.in.flight.requests.per.connection

该参数指定了生产者在收到服务器响应之前可以发送多少个消息。它的值越高,就会占用 越多的内存,不过也会提升吞吐量。把它设为 1 可以保证消息是按照发送的顺序写入服务 器的,即使发生了重试。

9. timeout.msrequest.timeout.msmetadata.fetch.timeout.ms

request.timeout.ms 指定了生产者在发送数据时等待服务器返回响应的时间,metadata. fetch.timeout.ms 指定了生产者在获取元数据(比如目标分区的首领是谁)时等待服务器 返回响应的时间。如果等待响应超时,那么生产者要么重试发送数据,要么返回一个错误 (抛出异常或执行回调)。timeout.ms 指定了 broker 等待同步副本返回消息确认的时间,与 asks 的配置相匹配——如果在指定时间内没有收到同步副本的确认,那么 broker 就会返回 一个错误。

10. max.block.ms

该参数指定了在调用 send() 方法或使用 partitionsFor() 方法获取元数据时生产者的阻塞 时间。当生产者的发送缓冲区已满,或者没有可用的元数据时,这些方法就会阻塞。在阻 塞时间达到 max.block.ms 时,生产者会抛出超时异常。

11. max.request.size

该参数用于控制生产者发送的请求大小。它可以指能发送的单个消息的最大值,也可以指 单个请求里所有消息总的大小。例如,假设这个值为 1MB,那么可以发送的单个最大消 息为 1MB,或者生产者可以在单个请求里发送一个批次,该批次包含了 1000 个消息,每 个消息大小为 1KB。另外,broker 对可接收的消息最大值也有自己的限制(message.max. bytes),所以两边的配置最好可以匹配,避免生产者发送的消息被 broker 拒绝。

12. receive.buffer.bytessend.buffer.bytes

这两个参数分别指定了 TCP socket 接收和发送数据包的缓冲区大小。如果它们被设为 -1, 就使用操作系统的默认值。如果生产者或消费者与 broker 处于不同的数据中心,那么可以 适当增大这些值,因为跨数据中心的网络一般都有比较高的延迟和比较低的带宽。

分区

在之前的例子里,ProducerRecord 对象包含了目标主题、键和值。Kafka 的消息是一个个键值对,ProducerRecord 对象可以只包含目标主题和值,键可以设置为默认的 null,不过大多数应用程序会用到键。键有两个用途:可以作为消息的附加信息,也可以用来决定消息该被写到主题的哪个分区。拥有相同键的消息将被写到同一个分区。也就是说,如果一个进程只从一个主题的分区读取数据(第 4 章会介绍更多细节),那么具有相同键的所有记录都会被该进程读取。要创建一个包含键值的记录,只需像下面这样创建 ProducerRecord 对象:

ProducerRecord<Integer, String> record =new ProducerRecord<>("CustomerCountry", "Laboratory Equipment", USA");

如果要创建键为 null 的消息,不指定键就可以了:

// ➊
ProducerRecord<Integer, String> record =new ProducerRecord<>("CustomerCountry", "USA");
  • ➊ 这里的键被设为 null。

如果键值为 null,并且使用了默认的分区器,那么记录将被随机地发送到主题内各个可用的分区上。分区器使用轮询(Round Robin)算法将消息均衡地分布到各个分区上。

如果键不为空,并且使用了默认的分区器,那么 Kafka 会对键进行散列(使用 Kafka 自己的散列算法,即使升级 Java 版本,散列值也不会发生变化),然后根据散列值把消息映射到特定的分区上。这里的关键之处在于,同一个键总是被映射到同一个分区上,所以在进行映射时,我们会使用主题所有的分区,而不仅仅是可用的分区。这也意味着,如果写入数据的分区是不可用的,那么就会发生错误。但这种情况很少发生。我们将在第 6 章讨论 Kafka 的复制功能和可用性。

只有在不改变主题分区数量的情况下,键与分区之间的映射才能保持不变。举个例子,在分区数量保持不变的情况下,可以保证用户 045189 的记录总是被写到分区 34。在从分区读取数据时,可以进行各种优化。不过,一旦主题增加了新的分区,这些就无法保证 了——旧数据仍然留在分区 34,但新的记录可能被写到其他分区上。如果要使用键来映射分区,那么最好在创建主题的时候就把分区规划好(第 2 章介绍了如何确定合适的分区数 量),而且永远不要增加新分区。

参考

  • 《Kafka权威指南》

相关文章:

Kafka MQ 生产者

Kafka MQ 生产者 生产者概览 尽管生产者 API 使用起来很简单&#xff0c;但消息的发送过程还是有点复杂的。图 3-1 展示了向 Kafka 发送消息的主要步骤。 我们从创建一个 ProducerRecord 对象开始&#xff0c;ProducerRecord 对象需要包含目标主题和要发送的内容。我们还可以…...

​​SQLiteC/C++接口详细介绍之sqlite3类(十)

返回目录&#xff1a;SQLite—免费开源数据库系列文章目录 上一篇&#xff1a;SQLiteC/C接口详细介绍之sqlite3类&#xff08;九&#xff09; 下一篇&#xff1a;​​SQLiteC/C接口详细介绍之sqlite3类&#xff08;十一&#xff09; 30.sqlite3_enable_load_extension&#x…...

Vue中nextTick一文详解

什么是 nextTick&#xff1f; 在 Vue 中&#xff0c;当我们修改数据时&#xff0c;Vue 会自动更新视图。但是&#xff0c;由于 JavaScript 的事件循环机制&#xff0c;我们无法立即得知视图更新完成的时机。这时候&#xff0c;我们就需要使用 nextTick 来获取视图更新完成后的…...

爱奇艺 CTR 场景下的 GPU 推理性能优化

01 背景介绍 GPU 目前大量应用在了爱奇艺深度学习平台上。GPU 拥有成百上千个处理核心&#xff0c;能够并行的执行大量指令&#xff0c;非常适合用来做深度学习相关的计算。在 CV&#xff08;计算机视觉&#xff09;&#xff0c;NLP&#xff08;自然语言处理&#xff09;的模型…...

详解MySql索引

目录 一 、概念 二、使用场景 三、索引使用 四、索引存在问题 五、命中索引问题 六、索引执行原理 一 、概念 索引是一种特殊的文件&#xff0c;包含着对数据表里所有记录的引用指针。暂时可以理解成C语言的指针,文章后面详解 二、使用场景 数据量较大&#xff0c;且…...

struct 和 union 的区别?

struct和union的分对应点总结 存储方式&#xff1a; struct&#xff1a;struct中的每个成员都拥有独立的内存空间。一个struct变量的总长度是其所有成员的长度之和&#xff0c;且通常会根据编译器的内存对齐规则进行适当调整。union&#xff1a;union中的所有成员共享同一段内…...

Linux - 安装 Jenkins(详细教程)

目录 前言一、简介二、安装前准备三、下载与安装四、配置镜像地址五、启动与关闭六、常用插件的安装 前言 虽然说网上有很多关于 Jenkins 安装的教程&#xff0c;但是大部分都不够详细&#xff0c;或者是需要搭配 docker 或者 k8s 等进行安装&#xff0c;对于新手小白而已&…...

【JAVA】JAVA方法的学习和创造

&#x1f308;个人主页: Aileen_0v0 &#x1f525;热门专栏: 华为鸿蒙系统学习|计算机网络|数据结构与算法|MySQL| ​&#x1f4ab;个人格言:“没有罗马,那就自己创造罗马~” 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不…...

Rust写一个wasm入门并在rspack和vite项目中使用(一)

rust打包wasm文档 文档地址 安装cargo-generate cargo install cargo-generate 安装过程中有问题的话手动安装cargo-generate下载地址 根据自己的系统下载压缩包&#xff0c;然后解压到用户/.cargo/bind目录下&#xff0c;将解压后的文件放到该目录下即可。 创建wasm项目 …...

HTTP和HTTPS的区别,HTTPS加密原理是?

HTTP和HTTPS都是网络传输协议&#xff0c;主要用于浏览器和服务器之间的数据传输&#xff0c;但它们在数据传输的安全性、加密方式、端口等方面有所不同。 数据传输的安全性&#xff1a;HTTP是明文传输&#xff0c;数据不加密&#xff0c;容易被黑客窃听、篡改或者伪造&#x…...

基于Spring Boot+Vue的校园二手交易平台

目录 一、 绪论1.1 开发背景1.2 系统开发平台1.3 系统开发环境 二、需求分析2.1 问题分析2.2 系统可行性分析2.2.1 技术可行性2.2.2 操作可行性 2.3 系统需求分析2.3.1 学生功能需求2.3.2 管理员功能需求2.3.3游客功能需求 三、系统设计3.1 功能结构图3.2 E-R模型3.3 数据库设计…...

什么是软件开发?软件开发阶段划分是什么?并以LabVIEW为例进行说明

软件开发是一种创建、设计、编码、测试和维护应用程序、框架或其他软件组件的过程。它涉及从理解需求到设计、实现、测试、部署和最终维护的全过程。软件开发可以用来创建新的软件应用、系统软件、游戏、或开发网络应用等。 软件开发过程通常可以分为以下几个阶段&#xff1a;…...

PTAL1-006 连续因子

c语言中的小小白-CSDN博客c语言中的小小白关注算法,c,c语言,贪心算法,链表,mysql,动态规划,后端,线性回归,数据结构,排序算法领域.https://blog.csdn.net/bhbcdxb123?spm1001.2014.3001.5343 给大家分享一句我很喜欢我话&#xff1a; 知不足而奋进&#xff0c;望远山而前行&am…...

【Java】容器|Set、List、Map及常用API

目录 一、概述 二、List 1、List的常用API 2、ArrayList 3、List遍历 三、Set 1、Set的常用方法: 2、HashSet 3、遍历集合&#xff1a; 四、Map 1、Map常用API 2、HashMap 3、遍历Map 五、迭代器 一、概述 在Java中所有的容器都属于Collection接口下的内容 1…...

Navicat 面试题及答案整理,最新面试题

Navicat 在数据库管理中的主要用途有哪些&#xff1f; Navicat 是一款数据库管理工具&#xff0c;其主要用途包括&#xff1a; 1、多数据库支持&#xff1a; Navicat 支持多种数据库连接&#xff0c;包括 MySQL、Oracle、PostgreSQL、SQLite、SQL Server 等&#xff0c;方便用…...

android studio 连接mumu模拟器调试

1、打开mumu模拟器 2、在Android Studio 中 控制台 cd 到 sdk 目录下 platform-tools 文件夹&#xff0c;有一个adb.exe 可运行程序 一般指令&#xff1a; adb connect 127.0.0.1:7555 但是这个执行在window环境下可能会报错 解决方法是在 adb 之前加 ".\", 问题…...

四连通与八连通的区别 -- 图例讲解

概念 四连通区域&#xff1a;指从某个点出发&#xff0c;只能通过上、下、左、右四个方向的运动到达区域内的其他点&#xff0c;且不能跨越区域的边界。 八连通区域&#xff1a;除了上、下、左、右四个方向&#xff0c;还可以沿对角线方向&#xff08;左上、右上、左下、右下…...

关于分布式微服务数据源加密配置以及取巧方案(含自定义加密配置)

文章目录 前言Spring Cloud 第一代1、创建config server项目并加入加解密key2、启动项目&#xff0c;进行数据加密3、实际项目中的测试server Spring Cloud Alibaba低版本架构不支持&#xff0c;取巧实现无加密配置&#xff0c;联调环境问题加密数据源配置原理探究自定义加密解…...

快速了解JavaScript

1.1 javaScript 历史 创始人 布兰登 艾奇 生于1961年 在1995设计LiveScript后改名为JavaScript 1.2 javaScript 是什么类型的语言 JavaScript是一种在客户端运行的脚本语言&#xff08;不需要编译&#xff0c;由js引擎逐行解释执行&#xff09; 1.3 JavaScript可以做什么 …...

【安全类书籍-3】XSS跨站脚剖析与防御

目录 内容简介 作用 下载地址 内容简介 这本书涵盖以下几点: XSS攻击原理:解释XSS是如何利用Web应用未能有效过滤用户输入的缺陷,将恶意脚本注入到网页中,当其他用户访问时被执行,实现攻击者的目的,例如窃取用户会话凭证、实施钓鱼攻击等。 XSS分类:分为存储型XSS(…...

http postman

地址 &#xff1a; https://oaqas.lingyiitech.com:9800/auth-api/openapi/dingtalk-oa/topapi/message/corpconversation/asyncsend_v2?token40216bf0ceea8e56b778d537b20f5d23 https://oaqas.lingyiitech.com:9800/auth-api/openapi/dingtalk-oa/topapi/message/corpconve…...

[数据集][目标检测]螺丝螺母检测数据集VOC+YOLO格式2100张13类别

数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数)&#xff1a;2100 标注数量(xml文件个数)&#xff1a;2100 标注数量(txt文件个数)&#xff1a;2100 标注…...

华为鲲鹏ARM处理器920、916系列

鲲鹏处理器-鲲鹏社区 (hikunpeng.com) 产品规格 鲲鹏920系列 型号&#xff1a; 7260&#xff08;64核&#xff09;、5250&#xff08;48核&#xff09;、5220&#xff08;32核&#xff09;、3210&#xff08;24核&#xff09;7260核数64核 主频2.6GHz 内存通道8TDP功耗180W 组…...

AG32VF407 应用开发问答1

有工程师想用AG32VF407RGT6来做项目&#xff0c;同时用到CPLD和MCU&#xff0c;MCU中用到AD、DAC、CMP&#xff0c;CMP的输出内部连到CPLD上&#xff0c;因为第一次用。所以一起进行了一些技术交流&#xff0c;在此也分享给大家。 Questions1: 1、关于boot0、boot1相关的说明…...

一站式解决方案:uni-app条件编译及多环境配置,appid动态修改攻略!

前言 这篇文章主要介绍uniapp在Hbuilderx 中&#xff0c;通过工程化&#xff0c;区分不同环境、动态修改小程序appid以及自定义条件编译&#xff0c;解决代码发布和运行时手动切换到问题。 背景 在企业级的应用中&#xff0c;通常会分为&#xff0c;开发、联调、生产等多个环…...

从政府工作报告中的IT热词统计探计算机行业发展(二)人工智能+:3次

政府工作报告作为政府工作的全面总结和未来规划&#xff0c;不仅反映了国家整体的发展态势&#xff0c;也为各行各业提供了发展的指引和参考。随着信息技术的快速发展&#xff0c;计算机行业已经成为推动经济社会发展的重要引擎之一。因此&#xff0c;从政府工作报告中探寻计算…...

Selenium库原代码WebDriver及WebElement方法属性总结

简单示例&#xff1a; from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as ECdriver webdriver.Chrome()try:driver.ge…...

C# 部署ICE框架以及用例(VS2019)

使用Windows 10环境&#xff0c;VS2019进行ICE用例开发 用例结构&#xff1a;客户端和服务端 关键技术&#xff1a;集成ICE环境&#xff0c;可以创建ice文件并自动生成对应的cs文件 1.环境安装 ICE Build插件安装。安装以后&#xff0c;就可以在项目中插入ice文件 2.代码实…...

PostgreSQL 数据加密怎么弄,应该用哪种方案

开头还是介绍一下群&#xff0c;如果感兴趣PolarDB ,MongoDB ,MySQL ,PostgreSQL ,Redis, Oceanbase, Sql Server等有问题&#xff0c;有需求都可以加群群内有各大数据库行业大咖&#xff0c;CTO&#xff0c;可以解决你的问题。加群请联系 liuaustin3 &#xff0c;&#xff08;…...

1.通过AD组策略如何做封禁高危端口的策略?AD域控如何给加域的电脑做指定端口号封禁呢?

目录 (1)高危端口简介 1. 高危端口TCP和UDP类型 2.为什么要做AD组策略封禁加域计算机的一些高危的端口?好处是什么? (2)实战步骤过程 实验环境 第一步:新建计算机策略-编辑 第二步:将策略应用到OU...