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

文章目录

    • 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.mzph.cn/news/30812.shtml

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

相关文章

【PyQt5+matplotlib】获取鼠标在canvas上的点击坐标

示例代码: import sys import matplotlib.pyplot as plt from PyQt5.QtWidgets import QApplication, QMainWindow, QVBoxLayout, QWidget from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvasclass MyMainWindow(QMainWindow):de…

UE4 像素流 学习笔记

使用场景: 1、登录服务器,服务器上安装node.js Download | Node.js (nodejs.org) 点击该网址 点击Windows Installer 2、登录服务器,拷贝本地UE Pixel Streaming包到服务器 启用插件后重启该项目 然后打包 打包成功过后创建快捷方式 将该I…

SDU Crypto School - 计算不可区分性1

Encryption: Computational security 1-4 主讲人:李增鹏(山东大学) 参考教材:Jonathan Katz, Yehuda Lindell, Introduction to Modern Cryptography - Principles and Protocols. 什么是加密 首先,加密方案的目的在于…

网络:CISCO、Huawei、H3C命令对照

思科、华为、锐捷命令对照表 编号思科华为锐捷命令解释1 2writesavesave保存3456 如果你所处的视图为非系统视图,需要查看配置的时候,需要在该配置命令前加do。 在特定的视图之下,有对应的特定命令。例如,在接口视图下的ip addre…

Ubuntu18.04使用carla0.9.5联合仿真搭环境报错

Ubuntu18.04使用工程与carla0.9.5联合仿真报错 1 File "/home/cg/Auto_driving/src/ros-bridge/carla_ros_bridge/src/carla_ros_bridge/client.py", line 18, in <module>from carla_ros_bridge.bridge_with_rosbag import CarlaRosBridgeWithBagFile "…

[保研/考研机试] KY180 堆栈的使用 吉林大学复试上机题 C++实现

题目链接&#xff1a; 堆栈的使用_牛客题霸_牛客网 描述 堆栈是一种基本的数据结构。堆栈具有两种基本操作方式&#xff0c;push 和 pop。其中 push一个值会将其压入栈顶&#xff0c;而 pop 则会将栈顶的值弹出。现在我们就来验证一下堆栈的使用。 输入描述&#xff1a; 对于…

Zabbix自动注册服务器及部署代理服务器

文章目录 一.zabbix自动注册1.什么是自动注册2.环境准备3.zabbix客户端配置4.在 Web 页面配置自动注册5.验证自动注册 二.部署 zabbix 代理服务器1.分布式监控的作用&#xff1a;2.环境部署3.代理服务器配置4.客户端配置5.web页面配置5.1 删除原来配置5.2 添加代理5.3 创建主机…

c语言——三子棋

基本框架 三个文件: 其中.cpp文件用于游戏具体函数设计&#xff0c;.h文件为游戏的函数声明&#xff0c;test.cpp文件用于测试游戏运行。 需要用到的头文件&#xff1a; #include <stdio.h> #include <stdlib.h>//rand&srand #include <time.h>//时间相…

[oeasy]python0083_[趣味拓展]字体样式_正常_加亮_变暗_控制序列

字体样式 回忆上次内容 上次了解了 一个新的转义模式 \033 逃逸控制字符 esc esc 让输出 退出 标准输出流进行 控制信息的设置 可以 清屏也可以 设置光标输出的位置 还能做什么呢&#xff1f; 可以 设置 字符的颜色吗&#xff1f;&#xff1f;&#xff1f;&#x1f914; 查…

利用Simulink Test进行模型单元测试 - 1

1.搭建用于测试的简单模型 随手搭建了一个demo模型MilTestModel&#xff0c;模型中不带参数 2.创建测试框架 1.模型空白处右击 测试框架 > 为‘MilTestModel’创建 菜单 2.在创建测试框架对话框中&#xff0c;点击OK&#xff0c;对应的测试框架MilTestMode_Harness1就自动…

第五次作业 运维高级 构建 LVS-DR 集群和配置nginx负载均衡

1、基于 CentOS 7 构建 LVS-DR 群集。 LVS-DR模式工作原理 首先&#xff0c;来自客户端计算机CIP的请求被发送到Director的VIP。然后Director使用相同的VIP目的IP地址将请求发送到集群节点或真实服务器。然后&#xff0c;集群某个节点将回复该数据包&#xff0c;并将该数据包…

Android Jetpack

Jetpack 是一个由多个库组成的套件&#xff0c;可帮助开发者遵循最佳实践、减少样板代码并编写可在各种 Android 版本和设备中一致运行的代码&#xff0c;让开发者可将精力集中于真正重要的编码工作。 1.基础组件 &#xff08;1&#xff09;AppCompat&#xff1a;使得支持较低…

Qt画波浪球(小费力)

画流动波浪 #ifndef WIDGET3_H #define WIDGET3_H#include <QWidget> #include <QtMath> class widget3 : public QWidget {Q_OBJECT public:explicit widget3(QWidget *parent nullptr);void set_value(int v){valuev;}int get_value(){return value;} protecte…

vue中vuex的五个属性和基本用法,另加js-cookie的使用

VueX 是一个专门为 Vue.js 应用设计的状态管理构架&#xff0c;统一管理和维护各个vue组件的可变化状态(你可以理解成 vue 组件里的某些 data )。 Vuex有五个核心概念&#xff1a; state, getters, mutations, actions, modules。 1. state&#xff1a; vuex的基本数据&…

【Linux】-- 进程间通信

目录 一、进程间通信介绍 二、管道 1.什么是管道&#xff08;pipe&#xff09; 2.重定向和管道 &#xff08;1&#xff09;为什么要有管道的存在 &#xff08;2&#xff09;重定向和管道的区别 3.匿名管道 &#xff08;1&#xff09;匿名管道原理 &#xff08;2&…

SpringCloud实用篇5——elasticsearch基础

目录 1.初识elasticsearch1.1 了解ES1.1.1 elasticsearch的作用1.1.2 ELK技术栈1.1.3 elasticsearch和lucene1.1.4 总结 1.2.倒排索引1.2.1.正向索引1.2.2.倒排索引1.2.3.正向和倒排 1.3 es的一些概念1.3.1 文档和字段1.3.2 索引和映射1.3.3 mysql与elasticsearch 1.4 部署单点…

直播招聘小程序解决方案

项目开发愿景 介绍工作拿佣金&#xff0c;Boss直播现真身。做为直播招聘的新平台&#xff0c;让求职和招聘变得更简单&#xff01;企业发布招聘视频&#xff0c;展现公司环境与实力&#xff0c;开通会员可以直播招聘、在线面试功能&#xff1b;求职者刷视频可以刷到工作…

信息安全:访问控制技术原理与应用.

信息安全&#xff1a;访问控制技术原理与应用. 访问控制是网络信息系统的基本安全机制。访问控制是指对资源对象的访问者授权、控制的方法及运行机制。访问者又称为主体&#xff0c;可以是用户、进程、应用程序等&#xff1b;而资源对象又称为客体&#xff0c;即被访问的对象&…

react中hooks分享

一. HOOKS是什么 在计算机程序设计中&#xff0c;钩子一词涵盖了一系列技术&#xff0c;这些技术用来通过拦截函数调用、消息或在软件组件之间传递的事件来改变或增加操作系统、应用程序或其他软件组件的行为。处理这些被截获的函数调用、事件或消息的代码称为“hook”。 在r…