长沙的网站建设公司/曹操seo博客

长沙的网站建设公司,曹操seo博客,如何提升网站流量,地方门户网站系统有哪些Flink系列知识之:深入了解 Flink 的网络协议栈 Flink 的网络协议栈是组成 flink-runtime 模块的核心组件之一,也是每个 Flink 任务的核心。它连接着来自所有任务管理器的各个工作单元(子任务)。这是流数据流过的地方,…

Flink系列知识之:深入了解 Flink 的网络协议栈

Flink 的网络协议栈是组成 flink-runtime 模块的核心组件之一,也是每个 Flink 任务的核心。它连接着来自所有任务管理器的各个工作单元(子任务)。这是流数据流过的地方,因此对 Flink 作业的吞吐量和延迟性能都至关重要。与通过 Akka 使用 RPC 的任务管理器和工作管理器之间的协调通道不同,任务管理器之间的网络堆栈依赖于使用 Netty 的低级应用程序接口。

本文初步介绍Flink的网络协议栈实现原理和各种优化策略,以及Flink在吞吐量和延迟之间的权衡。

网络协议栈-逻辑视角

Flink 的网络协议栈在子任务之间进行通信时,例如在 keyBy() 表示的网络shuffle过程中,为子任务提供了以下逻辑视图。
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
Flink会将整个数据流DAG切分成多个subtask子任务的拓扑结构来表示。上图显示了上下游子任务间的网络shuffle逻辑图,它对以下三个概念的不同设置进行了抽象:

  • 子任务输出类型(ResultPartitionType)
    • 流水线(有界或无界):数据产生后立即向下游发送,可能是逐一发送,可以是有界记录流,也可以是无界记录流。
    • 阻塞:只在产生完整结果时才向下游发送数据。
  • 子任务调度类型:
    • 同时部署(急迫): 同时部署作业的所有子任务(用于流式应用)。
    • 在首次输出的下一阶段部署(懒惰): 一旦下游任务中的任何一个生产者产生了输出,就立即部署下游任务。
    • 完整输出后的下一阶段部署: 当任何或所有下游任务的生产者都生成了完整的输出数据集时,再部署下游任务。
  • 吞吐:
    • 高吞吐量: Flink 不会逐一发送每条记录,而是将大量记录缓冲到网络缓冲区,然后一起发送。这降低了每条记录的成本,提高了吞吐量。
    • 通过缓冲区超时降低延迟: 通过缩短发送未完全填满缓冲区的超时时间,可以牺牲吞吐量来换取低延迟。

我们将在下面介绍网络协议栈物理层的章节中了解吞吐量和低延迟优化。在这一部分,让我们再详细介绍一下输出和调度类型。首先,我们必须知道,子任务输出类型和调度类型密切相关,只有两者的特定组合才有效。

流水线式结果分区(result partitions)是一种流式输出,需要一个实时的下游目标子任务来发送数据。该下游子任务可以在上游子任务产生结果之前或首次输出时被调度启动。批处理任务会产生有界的结果分区,而流水作业则会产生无界的结果。

批处理任务也可能以阻塞方式生成结果,这取决于所使用的操作符和连接模式。在这种情况下,必须先生成完整结果,然后才能调度起下游的接收任务。这样,批处理任务就能以更低的资源使用率更高效地工作。

下表总结了有效的组合:

Output TypeScheduling TypeApplies to…
pipelined, unboundedall at once
next stage on first output
Streaming jobs
n/a¹
pipelined, boundedall at once
next stage on first output
n/a²
Batch jobs
blockingnext stage on complete outputBatch jobs

¹ 目前Flink还未使用。
² 批处理/流处理统一完成后,这可能会适用于流作业。

网路协议栈-物理传输

为了理解数据的物理传输,请记住,在 Flink 中,不同的子任务可以通过插槽共享组(slot sharing groups)共享同一个插槽。TaskManager也可以提供多个插槽,以便将同一任务的多个子任务调度到同一个TaskManager上。

在下图示例中,我们假设并行度为 4,部署两个TaskManager,每个TaskManager提供 2 个插槽(slot)。TaskManager 1 执行子任务 A.1、A.2、B.1 和 B.2,TaskManager 2 执行子任务 A.3、A.4、B.3 和 B.4。在任务 A 和任务 B 之间的网络shuffle连接中,例如利用 keyBy() 进行的连接,每个TaskManager需要处理 2x4 个逻辑连接,其中有些是本地连接,有些是远程连接:
在这里插入图片描述

在 Flink 的网络协议栈中,不同任务之间的每个(远程)网络连接都有自己的 TCP 通道。但是,如果同一任务的不同子任务被调度到同一个TaskManager上,它们与下游的网络连接将被多路复用,共享一个 TCP 通道,以减少资源使用。因此,需要注意在Flink中,网络数据交换是发生在TaskManager之间的,而不是task之间,在同一个TaskManager中的不同task会复用同一个TCP网络连接。
在我们的示例中,这将适用于 A.1 → B.3、A.1 → B.4,以及 A.2 → B.3 和 A.2 → B.4,如下图所示:

在这里插入图片描述

每个子任务的输出结果被称为结果分区(ResultPartition),每个分区又被分成不同的结果子分区(ResultSubpartition)— 每个逻辑通道一个。此时,Flink 不再处理单个记录,而是将一组序列化记录放入到网络缓冲区中。 每个子任务在其本地缓冲池(发送端和接收端各一个)中可使用的缓冲区数量最多限制为:

#channels * buffers-per-channel + floating-buffers-per-gate

单个 TaskManager 上的缓冲区总数通常不需要配置。如有需要,请参阅配置网络缓冲区文档,了解如何进行配置。

反压(一)

每当子任务的发送缓冲区池用完时(缓冲区位于结果子分区的缓冲区队列或下层 Netty 支持的网络堆栈内),生产者就会受阻,无法继续工作,并承受反向压力(Backpressure)。接收器的工作方式与此类似:下层网络堆栈中任何传入的 Netty 缓冲区都需要通过网络缓冲区提供给 Flink。如果相应子任务的缓冲池中没有可用的网络缓冲区,Flink 将停止从该通道读取数据,直到有可用的缓冲区为止。 这将对该子任务上的所有上游发送子任务造成有效的反向压力,因此也会扼杀其他接收子任务。下图说明了子任务 B.4 的反压情况,它将对上游任务造成反向压力,并阻止子任务 B.3 接收和处理更多缓冲区,即使它仍有容量。
在这里插入图片描述

为了防止这种情况发生,Flink 1.5 引入了自己的流量控制机制。

基于Credit-based的流控

基于Credit-based的流量控制可确保接收方有能力处理接收到的任何内容。它基于网络缓冲区的可用性。在这种流控机制下,每个远程输入通道都有自己的一组专属缓冲区(exclusive buffers),而不是只有一个共享的本地缓冲池。相反,本地缓冲池中的缓冲区被称为浮动缓冲区(floating buffers),因为它们会四处浮动,每个输入通道都可以使用。

接收方将向发送方发送基于credit的缓冲区可用性(1 buffer = 1 credit)。每个结果子分区(ResultSubPartition)都将跟踪其信道credit(channel credits)。当接收方将自己的可用credit值发给上游的输出方时,输出方会判断该credit值,只有在credit可用的情况下(credit > 0)才会被转发到下层网络协议栈尝试往下游发送。同时,每发送一个缓冲区的数据,credit值就会减少一个。在发送端,除了发送缓冲区的数据外,还会发送有关当前积压大小的信息,其中z说明上游有多少缓冲区正在该子分区的队列中等待被消费。接收方根据该积压信息会去请求适当数量的浮动缓冲区(Floating Buffers),以加快积压处理速度。它将尝试获取与积压大小一样多的浮动缓冲区,但这并不总是可能的,我们可能会只得到一些缓冲区或根本没有缓冲区。接收器将使用已获取的缓冲区,并等待有更多缓冲区可用时再继续申请使用。
在这里插入图片描述

比如,上图显示了credit-based的流控机制流程:

  • TaskManager 2的子任务B.4的独占缓冲区(exclustion buffers)只包含了两个buffer缓冲池,因此会通知给上游TaskManager 1的子任务A.2,告知其channel credit = 2。
  • Subtask A.2发送端根据下游接收端发送的credit值,选择发送2个buffer缓冲区的数据到下游,同时还会发送当前输出队列中积压的大小信息,比如这里的Backlog size = 5。
  • Subtask B.4接收端的独占缓冲区接收Subtask A.2发送的2个buffer缓冲区的数据,此时独占缓冲区中没有额外的可用缓冲区可以使用,因此更新其channel credit = 0。
  • Subtask B.4接收端接收到Backlog size的积压大小后,向共享的浮动缓冲区申请可用的buffer缓冲池,以此来加快处理上游的积压数据。
  • 如果能申请到额外的可用缓冲池,则可以继续处理上游的积压数据。否则,会将新的channel credit=0发送给Subtask A.2,从而使用Subtask A.2无法继续发送上游数据,从而产生反压。

credit-based的流量控制将使用`buffers-per-channel来指定独占缓冲区的数量(必选),并使用 floating-buffers-per-gate来指定本地缓冲区池的数量(可选),从而达到与无流量控制时相同的缓冲区限制。选择这两个参数的默认值,是为了在网络健康、延迟正常的情况下,使用流量控制时的最大(理论)吞吐量至少与不使用流量控制时相同。您可能需要根据实际的往返时间和带宽来调整这些参数。

对于本地缓冲池的数量设置来说,如果没有足够的可用缓冲区,每个缓冲池将获得相同份额的全局可用缓冲区(± 1)。

反压(二)

与没有流量控制的接收方反压机制相比,credit值提供了更直接的控制:如果接收方的消费速度无法跟上上游的生成速度,其可用credit值最终将为 0,从而阻止发送方将缓冲区转发到下层网络协议栈。同时,只有这个逻辑通道存在向上的反压,不需要阻止其他接收端从复用的 TCP 通道读取数据。因此,其他接收方在处理可用缓冲区时不会受到影响。

流控机制的作用

有了流量控制,相比与之前的没有流量机制方案,TaskManager间的TCP连接通道不会被过多的数据量所阻塞,从而能够实现多个子任务在复用同一个TCP连接时,一个逻辑通道不会阻塞另一个逻辑通道的处理,以此实现整体资源利用率的提高。
此外,通过对网络中传输数据量的完全控制,我们还能改进检查点对齐(checkpoint alignments):如果没有流量控制,发送端是无法感知到下游接收端的处理能力的,只会源源不断的将数据转发到下层网络协议栈然后发往下游。当一段时间后,接收端的处理速度跟不上数据生产速度,接收端缓冲区已满,源源不断的数据被堆积在网络连接通道中,这种情况下,任何的checkpoint barrier都需要在发送端的缓冲区后面排队,必须等待前面的所有缓冲区都处理完毕后才能开始(“障碍永远不会超过记录!”)。

不过,接收方需要发送的额外的credit信息可能会带来一些额外成本,尤其是在使用 SSL 加密通道的设置中。此外,单个输入通道无法使用缓冲池中的所有缓冲区,因为独占缓冲区不是共享的。同时,由于存在流控机制,发送端无法立即开始发送尽可能多的可用数据,因此如果上游任务产生数据的速度快于接收到的credit值代表的下游可用缓冲区大小,可能需要更长的时间来发送数据。

虽然这可能会影响任务的性能,但由于流量控制的所有优点,它通常是更好的选择。可能会希望通过增加每个输入通道的独占缓冲区的数量,但代价是使用更多内存。不过,与之前的实现相比,总体内存使用量可能仍然较低,因为较低的网络协议栈不再需要缓冲大量数据,因为总是可以立即将数据传输到 Flink。

在使用credit-based的流量控制时,可能还会注意到一件事:当在发送方和接收方之间的缓冲池设置的较小时,可能会更早地遇到反压。不过,这也是人们所希望的,毕竟缓冲更多数据并不会带来任何好处。如果想缓冲更多数据,但又想保持流量控制,可以考虑通过每门浮动缓冲区(floating-buffers-per-gate)来增加浮动缓冲区的数量。

AdvantagesDisadvantages
• 多个子任务在复用同一个TCP连接时,一个逻辑通道不会阻塞另一个逻辑通道的处理,提高资源利用率

• 改进了检查点对齐

• 减少内存使用量(减少低层网络中的数据量)
• 额外的credit信息

• 额外的积压信息(与缓冲信息捎带,几乎没有开销)

• 潜在的往返延迟

• 反压可能会出现较早

注意 如果需要关闭基于credit-based的流量控制,可将此添加到 flink-conf.yaml 中:

taskmanager.network.credit-model: false

不过,该参数已被弃用,最终将与非credit-based流量控制代码一起被删除。

网络协议栈内部原理详解

下图进一步详细介绍了从发送操作符算子收集记录到接收操作符算子获取记录的网络堆栈及其周边组件:
在这里插入图片描述

发送端算子创建记录并将其传递(例如通过 Collector#collect())后,记录将被交给 RecordWriter类,RecordWriter 会将记录从 Java 对象序列化为字节序列,最终进入网络缓冲区,如上所述进行传递。RecordWriter 首先使用 SpanningRecordSerializer 将记录序列化为灵活的堆上字节数组。然后,它会尝试将这些字节写入目标网络通道的相关网络缓冲区。我们将在下面的章节中讨论最后一部分。

在接收端,下层网络堆栈(netty)会将接收到的缓冲区记录写入相应的输入通道。接收端任务的线程最终会从这些队列中读取数据,并尝试在RecordReader的帮助下,通过 SpillingAdaptiveSpanningRecordDeserializer 将累积的字节反序列化为 Java 对象。与序列化器类似,该反序列化器也必须处理跨越多个网络缓冲区的记录等特殊情况,这可能是因为记录大于网络缓冲区(默认为 32KiB,通过 taskmanager.memory.segment-size 设置),也可能是因为序列化的记录被添加到了网络缓冲区,而该缓冲区没有足够的剩余字节。不过,Flink 会使用这些字节,并继续将其余字节写入新的网络缓冲区。

将缓冲区刷新到 Netty

在上图中,基于credit-based的流量控制机制实际上位于 “Netty 服务器”(和 “Netty 客户端”)组件中,RecordWriter 正在写入的缓冲区总是以空的状态(empty state)添加到结果子分区中,然后逐渐填入(序列化的)记录。但 Netty 到底什么时候才能获得缓冲区呢?显然,它不能在字节可用时就获取它们,因为这不仅会因跨线程通信和同步而增加大量成本(需要线程通信频繁地从缓冲区获取字节数据),还会使整个缓冲区过时。

在Flink中,有三种情况可以使缓冲区可供Netty服务器使用:

  • 向缓冲区写入记录时,缓冲区已满
  • 缓冲区超时
  • 发送checkpoint barrier之类的特殊事件。
缓冲区满后刷新

RecordWriter 使用本地序列化缓冲区处理当前记录,并逐步将这些字节写入相应结果子分区队列中的一个或多个网络缓冲区。尽管一个 RecordWriter 可以在多个子分区上工作,但每个子分区只有一个 RecordWriter 在向其写入数据。另一方面,Netty 服务器会从多个结果子分区读取数据,并如上所述将相应的结果子分区复用到一个通道中。这是一种经典的生产者-消费者模式,网络缓冲区位于中间,如下图所示。
在这里插入图片描述

  • 在(1)将数据序列化和(2)将数据写入缓冲区后,RecordWriter 会相应地更新缓冲区的writer index。
  • 一旦缓冲区完全填满,RecordWriter将 (3) 从本地缓冲区中获取一个新缓冲区,用于当前记录的剩余字节或下一条记录,并将新缓冲区添加到子分区队列中。
  • 这将 (4) 通知 Netty 服务器数据可用。只要 Netty 有能力处理该通知,它就会 (5) 提取缓冲区并通过适当的 TCP 通道发送。
缓冲区超时后刷新

为了支持低延迟使用场景,我们不能仅仅依靠缓冲区满来向下游发送数据。在某些情况下,某个通信通道可能没有太多记录流过,从而不必要地增加了实际拥有的少量记录的延迟。因此,存在一个周期性的进程(the output flusher),它会周期性地尝试将缓冲区中等待的可用数据发往下游。周期性间隔可通过 StreamExecutionEnvironment#setBufferTimeout 进行配置,并作为延迟的上限(适用于低吞吐量通道)。但是严格来说,output fluster不提供任何保证–它只向 Netty 发送通知,而 Netty 可以随意/按容量接收。这也意味着,如果通道被反压,即使满足了超时条件,也无法将缓冲区数据flush到下游。

下图显示了它与其他组件的交互方式:

  • RecordWriter 会像之前一样序列化并写入网络缓冲区。
  • 与此同时,如果 Netty 尚未意识到数据可用,Output Flusher可能会(3,4)通知 Netty 服务器数据可用(类似于上述 "缓冲区已满 "的情况)。
  • Netty 处理该通知 (5) 时,会从缓冲区中读取可用数据,并更新缓冲区的writer index。缓冲区将保留在队列中–Netty 服务器端对该缓冲区的任何进一步操作都将在下一次继续从reader index中读取数据。
    在这里插入图片描述
特殊事件后刷新

如果通过 RecordWriter 发送了一些特殊事件后也会立即触发缓冲区刷新。最重要的事件是checkpoint barrier或分区结束事件(end-of-partition events),这些事件显然应该快速处理,而不是等待Output Flusher启动。

字节缓冲区在两个Task之间的传输

在这里插入图片描述

上面这张图展示了一个细节更加丰富的流程,描述了一条数据记录从生产者传输到消费者的完整生命周期如下:

  1. 最初,MapDriver生成数据记录(通过Collector收集)并传递给RecordWriter对象。RecordWriter包含一组序列化器,每个消费数据的Task分别对应一个。ChannelSelector会选择一个或多个序列化器处理记录。例如,如果记录需要被广播,那么就会被交给每一个序列化器进行处理;如果记录是按照hash进行分区的,ChannelSelector会计算记录的哈希值,然后选择对应的序列化器。
  2. 序列化器会将记录序列化为二进制数据,并将其存放在固定大小的buffer中(一条记录可能需要跨越多个buffer)。这些buffer被交给BufferWriter处理,写入到ResulePartition(RP)中。RP有多个子分区(ResultSubpartitions-RSs)构成,每一个子分区都只收集特定消费者需要的数据。在上图中,需要被第二个reducer(在TaskManager2中)消费的记录被放在RS2中。由于第一个Buffer已经生成,RS2就变成可被消费的状态了(注意,这个行为实现了一个streaming shuffle),接着它通知JobManager。
  3. JobManager查找RS2的消费者,然后通知TaskManager2一个数据块已经可以访问了。通知TM2的消息会被发送到InputChannel,该inputchannel被认为是接收这个buffer的,接着通知RS2可以初始化一个网络传输了。然后,RS2通过TM1的网络栈请求该buffer,然后双方基于Netty准备进行数据传输。网络连接是在TaskManager(而非特定的task)之间长时间存在的。
  4. 一旦Buffer被TM2接收,它同样会经过一个类似的结构,起始于InputChannel,进入InputGate(它包含多个IC),最终进入一个反序列化器(RecordDeserializer),它会从buffer中将记录还原成指定类型的对象,然后将其传递给接收数据的Task。

数据交换机制的具体实现

数据交换从本质上来说就是一个典型的生产者-消费者模型,上游算子生产数据到ResultPartition中,下游算子通过InputGate消费数据。由于不同的Task可能在同一个TaskManager中运行,也可能在不同的TaskManager中运行:对于前者,不同的Task其实就是同一个TaskManager进程中的不同的线程,它们的数据交换就是在本地不同线程间进行的;对于后者,必须要通过网络进行通信。下图所示分别为数据在一个taskmanager内的流转、以及在不同的taskmanager之间的流转:
在这里插入图片描述

在这里插入图片描述

缓冲区生成器和缓冲区消费者

如果您想深入了解 Flink 是如何实现生产者-消费者机制的,请仔细研究一下 Flink 1.5 中引入的 BufferBuilder 和 BufferConsumer类。虽然读取可能只针对每个缓冲区,但写入则是针对每条记录,因此在 Flink 中,所有网络通信都是在热路径(hot path)上进行的。因此,我们很清楚,我们需要在任务线程和 Netty 线程之间建立一个轻量级连接,这样就不会产生太多同步开销。如需了解更多详情,建议查看源代码。

延迟与吞吐量

引入网络缓冲区是为了提高资源利用率和吞吐量,但代价是某些记录在缓冲区等待的时间会更长一些。虽然可以通过缓冲区超时给出等待时间的上限,但您可能想知道更多关于延迟和吞吐量这两个维度之间的权衡,因为很明显,两者是不可兼得的。
下图显示了缓冲区超时的各种值,从 0(每条记录刷新一次)到 100ms(默认值)不等,并显示了在一个有 100 个节点、每个节点有 8 个插槽(slot)的集群上运行一项没有业务逻辑、因此只测试网络协议栈的作业时产生的吞吐率。为便于比较,我们还绘制了 Flink 1.4 在添加低延迟改进(如上所述)之前的情况。
在这里插入图片描述

正如上图所示,在 Flink 1.5 以上版本中,即使缓冲超时时间设置的很低,如 1 毫秒(用于低延迟场景),也能提供高达默认超时 75% 的最大吞吐量。

总结

现在我们已经了解了结果分区(ResultPartition)、不同的网络连接以及批处理和流式处理的调度类型。还了解了基于credit-based的流量控制和网络协议栈的内部工作原理,从而可以推理出与网络相关的调优参数和某些作业行为。本系列未来的博文将以这些知识为基础,深入探讨更多操作细节,包括需要关注的相关指标、进一步的网络协议栈调整以及需要避免的常见反模式。

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

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

相关文章

基于深度学习的视觉检测小项目(六) 项目的信号和变量的规划

• 关于前后端分离 当前流行的一种常见的前后端分离模式是vueflask,vueflask模式的前端和后端之间进行数据的传递通常是借助 API(应用程序编程接口)来完成的。vue通过调用后端提供的 API 来获取或提交数据。例如,前端可能通过发送…

党员学习交流平台

本文结尾处获取源码。 本文结尾处获取源码。 本文结尾处获取源码。 一、相关技术 后端:Java、JavaWeb / Springboot。前端:Vue、HTML / CSS / Javascript 等。数据库:MySQL 二、相关软件(列出的软件其一均可运行) I…

web实操9——session

概念 数据保存在服务器HttpSession对象里。 session也是域对象,有setAttribute和getAttribute方法 快速入门 代码 获取session和塞入数据: 获取session获取数据: 请求存储: 请求获取: 数据正常打印&#xff1a…

面向对象分析和设计OOA/D,UML,GRASP

目录 什么是分析和设计? 什么是面向对象的分析和设计? 迭代开发 UML 用例图 交互图 基于职责驱动设计 GRASP 常见设计原则 什么是分析和设计? 分析,强调是对问题和需求的调查研究,不是解决方案。例如&#x…

Nginx:限流限速

1. 什么是限流限速? 限流限速是Nginx运维中一个非常重要的功能,用于防止服务器过载和保护资源免受滥用。它可以通过限制客户端的请求速率或上传/下载速度来实现。 限流:控制单位时间内允许处理的请求数量。这有助于防止过多的并发请求导致服务器性能下降或崩溃。限速:限制…

探索 JMeter While Controller:循环测试的奇妙世界

嘿,宝子们!今天咱们就来聊聊 JMeter 里超级厉害的 While 控制器,它就像是一把神奇的钥匙,能帮我们打开循环测试的大门,模拟出各种各样复杂又有趣的场景哦! 一、While 控制器初印象 想象一下,你…

迈向AGI,3、2、1,2025上链接!

点击蓝字 关注我们 AI TIME欢迎每一位AI爱好者的加入! 往期精彩文章推荐 关于AI TIME AI TIME源起于2019年,旨在发扬科学思辨精神,邀请各界人士对人工智能理论、算法和场景应用的本质问题进行探索,加强思想碰撞,链接全…

JVM对象内存分配

1 栈上分配 栈空间随着方法执行完毕而回收通过栈上分配对象内存空间的方式,减少对堆空间的使用,从而减少gc的压力,提升程序性能 逃逸分析:分析对象的作用域,判断对象所需内存是否可以在栈上分配当对象没有被外部方法或…

计算机网络--路由器问题

一、路由器问题 1.计算下一跳 计算机网络--根据IP地址和路由表计算下一跳-CSDN博客 2.更新路由表 计算机网络--路由表的更新-CSDN博客 3.根据题目要求给出路由表 4.路由器收到某个分组,解释这个分组是如何被转发的 5.转发分组之路由器的选择 二、举个例子 …

vue 项目集成 electron 和 electron 打包及环境配置

vue electron 开发桌面端应用 安装 electron npm i electron -D记得加上-D,electron 需添加到devDependencies,如果添加到dependencies后面运行可能会报错 根目录创建electron文件夹,在electron文件夹创建main.js(或者backgrou…

leecode1143.最长公共子序列

这道题目和最长重复子数组是一个类型的不同之处在于text1[i]!text2[j]时dp[i][j]时他的值是继承上一行或上一列的最大值,二者dp数组的含义也不一样,这里的dp[i][j]表示的是以text[i]和text2[j]为结尾的子序列最大长度,这也是导致两种问题当判…

通过 4 种方式快速将音乐从 iPod 传输到 Android

概括 在 iPod 上听音乐很酷,但是当您拥有最新的 Android 手机时,也许您想在新手机上欣赏 iPod 音乐。那么,你的计划是什么?如何将音乐从 iPod 传输到 Android? 如果您担心这个问题,请看看下面的方法。他们…

flutter在windows平台中运行报错

PS D:\F\luichun> flutter run当运行flutter项目时,【解决如下报错】 /C:/flutter/packages/flutter/lib/src/painting/star_border.dart:530:27: Error: The getter Matrix4 isnt defined for the class _StarGenerator.- _StarGenerator is from package:flut…

Docker Compose编排

什么是 Docker Compose? Docker Compose 是 Docker 官方推出的开源项目,用于快速编排和管理多个 Docker 容器的应用程序。它允许用户通过一个 YAML 格式的配置文件 docker-compose.yml 来定义和运行多个相关联的应用容器,从而实现对容器的统一管理和编…

你已经分清JAVA中JVM、JDK与JRE的作用和关系了吗?

你已经分清JAVA中JVM、JDK与JRE的作用和关系了吗? 一. JVM、JDK与JRE的关系二. JVM、JDK与JRE的作用2.1 什么是JVM?2.2 什么是JDK?2.3 什么是JRE? 前言 点个免费的赞和关注,有错误的地方请指出,看个人主页有…

RP2K:一个面向细粒度图像的大规模零售商品数据集

这是一种用于细粒度图像分类的新的大规模零售产品数据集。与以往专注于相对较少产品的数据集不同,我们收集了2000多种不同零售产品的35万张图像,这些图像直接在真实的零售商店的货架上拍摄。我们的数据集旨在推进零售对象识别的研究,该研究具…

Spark大数据处理引擎详解

一、概念 Spark是一种快速、通用、可扩展的大数据分析引擎,它基于内存计算的大数据并行计算框架,能够显著提高大数据环境下数据处理的实时性,同时保证高容错性和高可伸缩性。Spark于2009年诞生于加州大学伯克利分校AMPLab,2010年…

服务器数据恢复—离线盘数超过热备盘数导致raidz阵列崩溃的数据恢复

服务器数据恢复环境&故障: 一台配有32块硬盘的服务器在运行过程中突然崩溃不可用。经过初步检测,基本上确定服务器硬件不存在物理故障。管理员重启服务器后问题依旧。需要恢复该服务器中的数据。 服务器数据恢复环境: 1、将服务器中硬盘…

安装教程:慧集通集成平台(DataLinkX)智能体客户端安装操作(Linux/windows/mac)

1.下载客户端 使用提供的账号登录集成平台后台(https://www.datalinkx.cn/),点击左侧菜单栏【智能体】→【智能体】进入到智能体列表界面,在该界面我们找到功能栏中的下载按钮点击则会弹出下载界面,在该界面我们可以选择不同的系统操作系统来下载对应版…

067B-基于R语言平台Biomod2模型的物种分布建模与数据可视化-高阶课程【2025】

课程培训包含:发票全套软件脚本学习数据视频文件导师答疑 本教程旨在通过系统的培训学习,学员可以掌握Biomod2模型最新版本的使用方法,最新版包含12个模型(ANN, CTA, FDA, GAM, GBM, GLM, MARS, MAXENT, MAXNET, RF, SRE, XGBOOST…