分布式 - 消息队列Kafka:Kafka生产者架构和配置参数

news2024/11/25 2:12:02

文章目录

    • 1. kafka 生产者发送消息整体架构
    • 2. Kafka 生产者重要参数配置
      • 01. acks
      • 02. 消息传递时间
      • 03. linger.ms
      • 04. buffer.memory
      • 05. batch.size
      • 06. max.in.flight.requests.per.connection
      • 07. compression.type
      • 08. max.request.size
      • 09. receive.buffer.bytes和 send.buffer.bytes
      • 10. enable.idempotence

1. kafka 生产者发送消息整体架构

生产者发送消息流程参考图1:

img

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

接下来,如果没有显式地指定分区,那么数据将被传给分区器。分区器通常会基于ProducerRecord对象的键选择一个分区。选好分区以后,生产者就知道该往哪个主题和分区发送这条消息了。紧接着,该消息会被添加到一个消息批次里,这个批次里的所有消息都将被发送给同一个主题和分区。有一个独立的线程负责把这些消息批次发送给目标broker。

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

生产者发送消息流程参考图2:

在这里插入图片描述

① 主线程和Sender 线程:

整个生产者客户端由两个线程协调运行,这两个线程分别为主线程和Sender线程(发送线程)。在主线程中由KafkaProducer创建消息,然后通过可能的拦截器、序列化器和分区器的作用之后缓存到消息累加器(RecordAccumulator,也称为消息收集器)中。Sender 线程负责从RecordAccumulator中获取消息并将其发送到Kafka中。

② 消息累加器 RecordAccumulator :

RecordAccumulator 主要用来缓存消息以便 Sender 线程可以批量发送,进而减少网络传输的资源消耗以提升性能。RecordAccumulator 缓存的大小可以通过生产者客户端参数buffer.memory 配置,默认值为 33554432B,即 32MB。如果生产者发送消息的速度超过发送到服务器的速度,则会导致生产者空间不足,这个时候KafkaProducer的send()方法调用要么被阻塞,要么抛出异常,这个取决于参数max.block.ms的配置,此参数的默认值为60000,即60秒。

③ 双端队列 Deque<ProducerBatch>:

主线程中发送过来的消息都会被追加到RecordAccumulator的某个双端队列(Deque)中,在 RecordAccumulator 的内部为每个分区都维护了一个双端队列,队列中的内容就是ProducerBatch,即 Deque<ProducerBatch>。消息写入缓存时,追加到双端队列的尾部;Sender读取消息时,从双端队列的头部读取。

④ 消息批次 ProducerBatch:

注意ProducerBatch不是ProducerRecord,ProducerBatch中可以包含一至多个 ProducerRecord。通俗地说,ProducerRecord 是生产者中创建的消息,而ProducerBatch是指一个消息批次,ProducerRecord会被包含在ProducerBatch中,这样可以使字节的使用更加紧凑。与此同时,将较小的ProducerRecord拼凑成一个较大的ProducerBatch,也可以减少网络请求的次数以提升整体的吞吐量。如果生产者客户端需要向很多分区发送消息,则可以将buffer.memory参数适当调大以增加整体的吞吐量。

⑤ BufferPool 和 ByteBuffer:

消息在网络上都是以字节(Byte)的形式传输的,在发送之前需要创建一块内存区域来保存对应的消息。在Kafka生产者客户端中,通过java.io.ByteBuffer实现消息内存的创建和释放。不过频繁的创建和释放是比较耗费资源的,在RecordAccumulator的内部还有一个BufferPool,它主要用来实现ByteBuffer的复用,以实现缓存的高效利用。不过BufferPool只针对特定大小的ByteBuffer进行管理,而其他大小的ByteBuffer不会缓存进BufferPool中,这个特定的大小由batch.size参数来指定,默认值为16384B,即16KB。我们可以适当地调大batch.size参数以便多缓存一些消息。

为什么使用 BufferPool 呢?

在Kafka中,RecordAccumulator是用来将生产者发送的消息缓存起来,以便批量发送到Kafka集群。在RecordAccumulator的内部,还有一个BufferPool,它主要用来实现ByteBuffer的复用,以实现缓存的高效利用。

BufferPool是一个ByteBuffer的池子,它维护了一组ByteBuffer,这些ByteBuffer可以被多个线程共享。当一个线程需要一个ByteBuffer时,它可以从BufferPool中获取一个可用的ByteBuffer,使用完后再将它归还给BufferPool。这样可以避免频繁地创建和销毁ByteBuffer,提高了内存的利用率和性能。

⑥ ProducerBatch的大小和batch.size参数的关系:

ProducerBatch的大小和batch.size参数也有着密切的关系。当一条消息(ProducerRecord)流入RecordAccumulator时,会先寻找与消息分区所对应的双端队列(如果没有则新建),再从这个双端队列的尾部获取一个ProducerBatch(如果没有则新建),查看 ProducerBatch 中是否还可以写入这个 ProducerRecord,如果可以则写入,如果不可以则需要创建一个新的ProducerBatch。在新建ProducerBatch时评估这条消息的大小是否超过batch.size参数的大小,如果不超过,那么就以 batch.size 参数的大小来创建ProducerBatch,这样在使用完这段内存区域之后,可以通过BufferPool 的管理来进行复用;如果超过,那么就以评估的大小来创建ProducerBatch,这段内存区域不会被复用。

batch.size参数是Producer的一个配置参数,用于控制ProducerBatch的大小。它指定了一批消息的最大大小,单位是字节。当Producer发送的消息数量达到batch.size或者等待时间超过linger.ms时,Producer会将这一批消息打包成一个ProducerBatch并发送到Kafka集群中的Broker。

因此,batch.size参数的大小会直接影响ProducerBatch的大小。如果batch.size设置得太小,会导致ProducerBatch的大小也很小,这样会增加网络传输的开销,降低消息发送的效率。如果batch.size设置得太大,会导致ProducerBatch的大小过大,可能会占用过多的内存,甚至会导致消息发送超时或失败。

⑦ 创建 ProduceRequest:

Sender 从 RecordAccumulator 中获取缓存的消息之后,会进一步将原本<分区,Deque<ProducerBatch>>的保存形式转变成<Node,List<ProducerBatch>的形式,其中Node表示Kafka集群的broker节点。对于网络连接来说,生产者客户端是与具体的broker节点建立的连接,也就是向具体的broker 节点发送消息,而并不关心消息属于哪一个分区;而对于 KafkaProducer的应用逻辑而言,我们只关注向哪个分区中发送哪些消息,所以在这里需要做一个应用逻辑层面到网络I/O层面的转换。在转换成<Node,List<ProducerBatch>>的形式之后,Sender 还会进一步封装成<Node,Request>的形式,这样就可以将Request请求发往各个Node了,这里的Request是指Kafka的各种协议请求,对于消息发送而言就是指具体的ProduceRequest。

⑧ 正在处理的请求 InFlightRequests:

请求在从Sender线程发往Kafka之前还会保存到InFlightRequests中。InFlightRequests保存对象的具体形式为 Map<NodeId,Deque<Request>>,它的主要作用是缓存了已经发出去但还没有收到响应的请求(NodeId 是一个 String 类型,表示节点的 id 编号)。与此同时,InFlightRequests还提供了许多管理类的方法,并且通过配置参数还可以限制每个连接(也就是客户端与Node之间的连接)最多缓存的请求数。这个配置参数为max.in.flight.requests.per.connection,默认值为 5,即每个连接最多只能缓存 5个未响应的请求,超过该数值之后就不能再向这个连接发送更多的请求了,除非有缓存的请求收到了响应(Response)。通过比较Deque<Request>的size与这个参数的大小来判断对应的Node中是否已经堆积了很多未响应的消息,如果真是如此,那么说明这个 Node 节点负载较大或网络连接有问题,再继续向其发送请求会增大请求超时的可能。

2. Kafka 生产者重要参数配置

01. acks

acks 指定了生产者在多少个分区副本收到消息的情况下才会认为消息写入成功。在默认情况下,Kafka会在leader副本收到消息后向客户端回应消息写入成功。acks 是生产者客户端中一个非常重要的参数,它涉及消息的可靠性和吞吐量之间的权衡。acks参数有3种类型的值(都是字符串类型)。

① acks=0: 生产者在成功写入消息之前不会等待任何来自服务器的相应。如果在消息从发送到写入Kafka的过程中出现某些异常,导致Kafka并没有收到这条消息,那么生产者也无从得知,消息也就丢失了。不过因为生产者不需要等待服务器响应,所以它可以以网络能够支持的最大速度发送消息,从而达到很高的吞吐量(每秒钟传输的数据量)。

② acks=1:默认值即为1。生产者发送消息之后,只要分区的leader副本成功写入消息,那么它就会收到来自服务端的成功响应。如果消息无法写入leader副本,比如在leader 副本崩溃、重新选举新的 leader 副本的过程中,那么生产者就会收到一个错误的响应,为了避免消息丢失,生产者可以选择重发消息。如果消息写入leader副本并返回成功响应给生产者,且在被其他follower副本拉取之前leader副本崩溃,那么此时消息还是会丢失,因为新选举的leader副本中并没有这条对应的消息。acks设置为1,是消息可靠性和吞吐量之间的折中方案。

③ acks=all:生产者在消息发送之后,需要等待ISR中的所有副本都成功写入消息之后才能够收到来自服务端的成功响应。在其他配置环境相同的情况下,acks 设置为all(或者-1)可以达到最强的可靠性。但这并不意味着消息就一定可靠,因为ISR中可能只有leader副本,这样就退化成了acks=1的情况。

分区中的所有副本统称为AR 。所有与leader副本保持一定程度同步的副本(包括leader副本在内)组成ISR,ISR集合是AR集合中的一个子集。消息会先发送到leader副本,然后follower副本才能从leader副本中拉取消息进行同步,同步期间内follower副本相对于leader副本而言会有一定程度的滞后。前面所说的“一定程度的同步”是指可忍受的滞后范围,这个范围可以通过参数进行配置。与leader副本同步滞后过多的副本(不包括leader副本)组成OSR,由此可见,AR=ISR+OSR。在正常情况下,所有的 follower 副本都应该与 leader 副本保持一定程度的同步,即AR=ISR,OSR集合为空。

注意:acks参数配置的是一个字符串类型,而不是整数类型,如果配置为整数类型会抛出异常

// 设置 acks=1
properties.put(ProducerConfig.ACKS_CONFIG,"1");

你会发现,为acks设置的值越小,生产者发送消息的速度就越快。也就是说,我们通过牺牲可靠性来换取较低的生产者延迟。过,端到端延迟是指从消息生成到可供消费者读取的时间,这对3种配置来说都是一样的。这是因为为了保持一致性,在消息被写入所有同步副本之前,Kafka不允许消费者读取它们。因此,如果你关心的是端到端延迟,而不是生产者延迟,那么就不需要在可靠性和低延迟之间做权衡了:你可以选择最可靠的配置,但仍然可以获得相同的端到端延迟。

02. 消息传递时间

有几个参数可用来控制开发人员最感兴趣的生产者行为:在调用send()方法后多长时间可以知道消息发送成功与否。这也是等待Kafka返回成功响应或放弃重试并承认发送失败的时间。

从Kafka 2.1开始,我们将ProduceRecord的发送时间分成如下两个时间间隔,它们是被分开处理的。

  • 异步调用send()所花费的时间。在此期间,调用send()的线程将被阻塞。
  • 从异步调用send()返回到触发回调(不管是成功还是失败)的时间,也就是从ProduceRecord被放到批次中直到Kafka成功响应、出现不可恢复异常或发送超时的时间。

如果同步调用send(),那么发送线程将持续阻塞,也就无法知道每个时间间隔是多长。

在这里插入图片描述

① max.block.ms

这个参数用于控制在调用send()或通过partitionsFor()显式地请求元数据时生产者可以发生阻塞的时间。当生产者的发送缓冲区被填满或元数据不可用时,这些方法就可能发生阻塞。当达到max.block.ms配置的时间时,就会抛出一个超时异常。

RecordAccumulator 主要用来缓存消息以便 Sender 线程可以批量发送,进而减少网络传输的资源消耗以提升性能。RecordAccumulator 缓存的大小可以通过生产者客户端参数buffer.memory 配置,默认值为 33554432B,即 32MB。如果生产者发送消息的速度超过发送到服务器的速度,则会导致生产者空间不足,这个时候KafkaProducer的send()方法调用要么被阻塞,要么抛出异常,这个取决于参数max.block.ms的配置,此参数的默认值为60000,即60秒。

// 设置 max.block.ms 为 60s
properties.put(ProducerConfig.MAX_BLOCK_MS_CONFIG,60);

② delivery.timeout.ms

这个参数用于控制从消息准备好发送(send()方法成功返回并将消息放入批次中)到broker响应或客户端放弃发送(包括重试)所花费的时间。这个时间应该大于linger.ms和request.timeout.ms。如果配置的时间不满足这一点,则会抛出异常。通常,成功发送消息的速度要比delivery.timeout.ms快得多。

如果生产者在重试时超出了delivery.timeout.ms,那么将执行回调,并会将broker之前返回的错误传给它。如果消息批次还没有发送完毕就超出了delivery.timeout.ms,那么也将执行回调,并会将超时异常传给它。

可以将这个参数配置成你愿意等待的最长时间,通常是几分钟,并使用默认的重试次数(几乎无限制)。基于这样的配置,只要生产者还有时间(或者在发送成功之前),它都会持续重试。这是一种合理的重试方式。我们的重试策略通常是:“在broker发生崩溃的情况下,首领选举通常需要30秒才能完成,因此为了以防万一,我们会持续重试120秒。”为了避免烦琐地配置重试次数和重试时间间隔,只需将delivery.timeout.ms设置为120。

// 设置 delivery.timeout.ms 为 120s
properties.put(ProducerConfig.DELIVERY_TIMEOUT_MS_CONFIG,120);

③ request.timeout.ms

这个参数用于控制生产者在发送消息时等待服务器响应的时间。需要注意的是,这是指生产者在放弃之前等待每个请求的时间,不包括重试、发送之前所花费的时间等。如果设置的值已触及,但服务器没有响应,那么生产者将重试发送,或者执行回调,并传给它一个TimeoutException。

④ retries 和 retry.backoff.ms

当生产者收到来自服务器的错误消息时,这个错误有可能是暂时的(例如,一个分区没有首领)。在这种情况下,retries参数可用于控制生产者在放弃发送并向客户端宣告失败之前可以重试多少次。在默认情况下,重试时间间隔是100毫秒,但可以通过retry.backoff.ms参数来控制重试时间间隔。

⑤ 总结:

并不建议在当前版本的Kafka中使用这些参数。相反,你可以测试一下broker在发生崩溃之后需要多长时间恢复(也就是直到所有分区都有了首领副本),并设置合理的delivery.timeout.ms,让重试时间大于Kafka集群从崩溃中恢复的时间,以免生产者过早放弃重试。

生产者并不会重试所有的错误。有些错误不是暂时的,生产者就不会进行重试(例如,“消息太大”错误)。通常,对于可重试的错误,生产者会自动进行重试,所以不需要在应用程序中处理重试逻辑。你要做的是集中精力处理不可重试的错误或者当重试次数达到上限时的情况。

03. linger.ms

这个参数指定了生产者在发送消息批次之前等待更多消息加入批次的时间。生产者会在批次被填满或等待时间达到linger.ms时把消息批次发送出去。在默认情况下,只要有可用的发送者线程,生产者都会直接把批次发送出去,就算批次中只有一条消息。

把linger.ms设置成比0大的数,可以让生产者在将批次发送给服务器之前等待一会儿,以使更多的消息加入批次中。虽然这样会增加一点儿延迟,但也极大地提升了吞吐量。这是因为一次性发送的消息越多,每条消息的开销就越小,如果启用了压缩,则计算量也更少了。

04. buffer.memory

这个参数用来设置生产者要发送给服务器的消息的内存缓冲区大小。如果应用程序调用send()方法的速度超过生产者将消息发送给服务器的速度,那么生产者的缓冲空间可能会被耗尽,后续的send()方法调用会等待内存空间被释放,如果在max.block.ms之后还没有可用空间,就抛出异常。需要注意的是,这个异常与其他异常不一样,它是send()方法而不是Future对象抛出来的。

05. batch.size

当有多条消息被发送给同一个分区时,生产者会把它们放在同一个批次里。这个参数指定了一个批次可以使用的内存大小。需要注意的是,该参数是按照字节数而不是消息条数来计算的。当批次被填满时,批次里所有的消息都将被发送出去。但是生产者并不一定都会等到批次被填满时才将其发送出去。那些未填满的批次,甚至只包含一条消息的批次也有可能被发送出去。所以,就算把批次大小设置得很大,也不会导致延迟,只是会占用更多的内存而已。但如果把批次大小设置得太小,则会增加一些额外的开销,因为生产者需要更频繁地发送消息。

06. max.in.flight.requests.per.connection

这个参数指定了生产者在收到服务器响应之前可以发送多少个消息批次。它的值越大,占用的内存就越多,不过吞吐量也会得到提升。Apache wiki页面上的实验数据表明,在单数据中心环境中,该参数被设置为2时可以获得最佳的吞吐量,但使用默认值5也可以获得差不多的性能。

07. compression.type

在默认情况下,生产者发送的消息是未经压缩的。这个参数可以被设置为snappy、gzip、lz4或zstd,这指定了消息被发送给broker之前使用哪一种压缩算法。snappy压缩算法由谷歌发明,虽然占用较少的CPU时间,但能提供较好的性能和相当可观的压缩比。如果同时有性能和网络带宽方面的考虑,那么可以使用这种算法。gzip压缩算法通常会占用较多的CPU时间,但提供了更高的压缩比。如果网络带宽比较有限,则可以使用这种算法。使用压缩可以降低网络传输和存储开销,而这些往往是向Kafka发送消息的瓶颈所在。

08. max.request.size

这个参数用于控制生产者发送的请求的大小。它限制了可发送的单条最大消息的大小和单个请求的消息总量的大小。假设这个参数的值为1 MB,那么可发送的单条最大消息就是1 MB,或者生产者最多可以在单个请求里发送一条包含1024个大小为1 KB的消息。另外,broker对可接收的最大消息也有限制(message.max.bytes),其两边的配置最好是匹配的,以免生产者发送的消息被broker拒绝。

09. receive.buffer.bytes和 send.buffer.bytes

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

10. enable.idempotence

从0.11版本开始,Kafka支持精确一次性语义。

假设为了最大限度地提升可靠性,你将生产者的acks设置为all,并将delivery.timeout.ms设置为一个比较大的数,允许进行尽可能多的重试。这些配置可以确保每条消息被写入Kafka至少一次。但在某些情况下,消息有可能被写入Kafka不止一次。假设一个broker收到了生产者发送的消息,然后消息被写入本地磁盘并成功复制给了其他broker。此时,这个broker还没有向生产者发送响应就发生了崩溃。而生产者将一直等待,直到达到request.timeout.ms,然后进行重试。重试发送的消息将被发送给新的首领,而这个首领已经有这条消息的副本,因为之前写入的消息已经被成功复制给它了。现在,你就有了一条重复的消息。

为了避免这种情况,可以将enable.idempotence设置为true。当幂等生产者被启用时,生产者将给发送的每一条消息都加上一个序列号。如果broker收到具有相同序列号的消息,那么它就会拒绝第二个副本,而生产者则会收到DuplicateSequenceException,这个异常对生产者来说是无害的。

如果要启用幂等性,那么max.in.flight.requests.per.connection应小于或等于5、retries应大于0,并且acks被设置为all。如果设置了不恰当的值,则会抛出ConfigException异常。

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

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

相关文章

如何使用appuploader制作apple证书​

转载:如何使用appuploader制作apple证书​ 如何使用appuploader制作apple证书​ 一.证书管理​ 点击首页的证书管理 二.新建证书​ 点击“添加”,新建一个证书文件 免费账号制作证书只有7天有效期,没有推送消息功能,推送证书…

anaconda 基本指令

1.anaconda创建环境 例如我们创建一个名称为img2word,python版本为3.9的环境 conda create -n img2word python3.9在这个命令中: create 是告诉 Conda 你要创建一个新的环境。-n img2word 是设置新环境的名称为 img2word。python3.9 是告诉 Conda 在这…

PS AI版本安装教程

好久没写博客了,今天更新一下子吧! 随着chatGPT的提出,各种软件逐渐开始镶嵌人工智能,为我们的生活带来了极大的便利!话不多说,开始介绍今天的主角,PS的AI版本。 安装教程: 1.安装…

Linux学习之sed删除、追加、插入、更改、读写文件、下一行、打印、退出和seq命令

cat /etc/redhat-release看到操作系统是CentOS Linux release 7.6.1810,uname -r看到内核版本是3.10.0-957.el7.x86_64,sed --version可以看到sed版本是4.2.2。 echo a : 1 : good : g >> sed_daicpnrwq.txt echo b : 2 : well : w >> sed…

LC-删除排序链表中的重复元素

LC-删除排序链表中的重复元素 链接:https://leetcode.cn/problems/remove-duplicates-from-sorted-list/description/ 思路:这题其实不难,链表已经排序,我们只要把相邻的两个节点的值进行比较,如果相同,删…

基于SpringBoot的社区团购系统设计【附开题|万字文档(LW)和搭建文档】

主要功能 前台界面: ①首页、商品信息推荐、社区信息、商品信息展示、查看更多等 ②商品信息、名称类型查询、添加购物车、立即购买、积分兑换、点我收藏、赞一下、踩一下、评论等 ③团购信息、社区信息、购物车等 ④个人中心、我的订单、我的地址、我的收藏等 后台…

VBA技术资料MF42:VBA_从Excel中上面的单元格复制公式

【分享成果,随喜正能量】唯有梦想才配让你不安,唯有行动才能解除你的不安.绳锯木断,水滴石穿。也许你现在做的事情很小,只要你能日积月累的坚持下去,才会发现意义非凡。所谓的成功,便是别人失败的时候你还在…

matplotlib FormatStrFormatter设置坐标轴的标注为整数和小数【设置小数点的数目】

利用FormatStrFormatter 进行设置 1 设置为整数 import matplotlib.pyplot as plt from matplotlib.ticker import FormatStrFormatter# 创建一个图表 fig, ax plt.subplots()# 生成一些示例数据 x [1, 2, 3, 4, 5] y [1000, 2000, 3000, 4000, 5000]# 在 x 轴上设置刻度标…

MATLAB计算一组坐标点的相互距离(pdist、squareform、pdist2函数)

如果有一组坐标P(X,Y),包含多个点的X和Y坐标,计算其坐标点之间的相互距离 一、坐标点 P[1 1;5 2;3 6;8 8;4 5;5 1; 6 9];二、pdist函数 输出的结果是一维数组,获得任意两个坐标之间的距离,但没有对应关系 Dpdist(P)三、square…

@Transactional失效的场景

1. 类没被Spring管理 解决方法: 贴上注解Service、Component 等交由Spring管理 2. private修饰的方法 解决方法: 修改成 public, 只有public才生效 3. try{}catch(){只打印异常信息} 解决方法: 捕获异常,并继续抛出原捕获的异常, 或抛出运行时异常 throw new Runti…

微服务04-elasticsearch

1、es概念 1.1 文档和字段 elasticsearch是面向**文档(Document)**存储的,可以是数据库中的一条商品数据,一个订单信息。文档数据会被序列化为json格式后存储在elasticsearch中: 而Json文档中往往包含很多的字段(Field),类似于数据库中的列。 1.2 索引和映射 索引(…

图像变形之IDW和RBF(附源码)

IDW原理 IDW(Inverse distance weighted interpolation)图像变形算法根据给定的控制点对和控制点对的位移矢量(方向和距离),计算控制点对周围像素的反距离加权权重影响,从而实现图像每一个像素点的位移, 假设输入控制点pi,其对应…

在浏览器中使用javascript打印HTML中指定Div带背景图片内容生成PDF电子证书查询的解决方案

在浏览器中使用javascript打印HTML中指定Div带背景图片内容生成PDF电子证书查询的解决方案 一、指定内容打印二、背景图片打印1.CSS背景图片设置2.div相对定位居中 三、完整案例展示1.CSS样式表2.HTML容器构建 一、指定内容打印 要调用浏览器中的打印功能,并指定需…

62.不同路径

一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为 “Start” )。 机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为 “Finish” )。 问总共有多少条不同的路径? 动态规…

长城汽车正式进军东盟市场,多款智能新能源亮相印尼车展

长城汽车在2023年印尼国际车展(GAIKINDO Indonesia International Auto Show)揭幕GWM品牌系列车型,包括坦克500 HEV、哈弗H6 HEV、哈弗JOLION HEV以及欧拉好猫。这一战略旨在进一步打入印尼市场。 长城汽车宣布将正式进军东盟市场&#xff0c…

Maven安装与配置,Eclipse配置Maven【图文并茂的保姆级教程】

🥳🥳Welcome Huihuis Code World ! !🥳🥳 接下来看看由辉辉所写的关于Maven的相关操作吧 目录 🥳🥳Welcome Huihuis Code World ! !🥳🥳 一.Maven是什么? 二.Maven的下…

AWS 中文入门开发教学 50- S3 - 网关终端节点 - 私有网络访问S3的捷径

知识点 通过设置网关终端节点,使私有网段中的EC2也可以访问到S3服务官网 https://docs.aws.amazon.com/zh_cn/codeartifact/latest/ug/create-s3-gateway-endpoint.html 实战演习 通过网关访问S3 看图说话"> 实战步骤 创建一个可以访问S3的角色 KomaRoleS3FullAcc…

使用docker安装mysql(谷粒商城)

前提准备:已经安装好了centos7 系统和docker容器 1、直接su root使用管理员下载镜像文件; 可以使用docker images查看下载是否成功 docker pull mysql:5.7bug1: 如果出现空间不足,比如报错no space left on device;我…

kafka partition的数据文件(offffset,MessageSize,data)

partition中的每条Message包含了以下三个属性: offset,MessageSize,data,其中offset表示Message在这个partition中的偏移量,offset不是该Message在partition数据文件中的实际存储位置,而是逻辑上一个值&…

docker-compose Install minio

前言 MinIO 是一种高性能、兼容 S3 的对象存储。它专为大规模 AI/ML、数据湖和数据库工作负载而构建。它在本地和任何云(公共或私有云)上运行,从数据中心到边缘。MinIO是GNU AGPL v3下的软件定义和开源。 MinIO是对象存储服务,它基于Apache License 开源协议,兼容Amazon …