Flink 数据传输及反压详解

【报文数据流中的反压处理】 Verilog FIFO 反压 阅读详情

 

 

 

IntermediateDataset

IntermediateDataset 是在 JobGraph 中对中间结果的抽象。我们知道,JobGraph 是对 StreamGraph 进一步进行优化后得到的逻辑图,它尽量把可以 chain 到一起 operator 合并为一个 JobVertex,而 IntermediateDataset 就表示一个 JobVertex 的输出结果。JobVertex 的输入是 JobEdge,而 JobEdge 可以看作是 IntermediateDataset 的消费者。一个 JobVertex 也可能产生多个 IntermediateDataset。需要说明的一点是,目前一个 IntermediateDataset 实际上只会有一个 JobEdge 作为消费者,也就是说,一个 JobVertex 的下游有多少 JobVertex 需要依赖当前节点的数据,那么当前节点就有对应数量的 IntermediateDataset。

19-幻灯片26-1568x882.png

 

这时候还没有向集群去提交任务,在 Client 端会将 StreamGraph 生成 JobGraph,JobGraph 就是做为向集群提交的最基本的单元。在生成 JobGrap 的时候会做一些优化,将一些没有 Shuffle 机制的节点进行合并。有了 JobGraph 后就会向集群进行提交,进入运行阶段。

Jobvertex->Intermedia Dateset->JobEage

20-幻灯片27-1-1568x882.png

 

然后我们概念化这样一张物理执行图,可以看到每个 Task 在接收数据时都会通过这样一个InputGate 可以认为是负责接收数据的,再往前有这样一个 ResultPartition 负责发送数据,在 ResultPartition 又会去做分区跟下游的 Task 保持一致,就形成了 ResultSubPartition 和 InputChannel 的对应关系。这就是从逻辑层上来看的网络传输的通道,基于这么一个概念我们可以将反压的问题进行拆解。
ExecutionGraph -> Intermedia ATA
task ->ResultPartion->InputGate
ResultSubParition-->InputChannel 一一对应

问题拆解:反压传播两个阶段

image.png

假设最下游的 Task (Sink)出现了问题,处理速度降了下来这时候是如何将这个压力反向传播回去呢?这时候就分为两种情况:

跨 TaskManager ,反压如何从 InputGate 传播到 ResultPartition

TaskManager 内,反压如何从 ResultPartition 传播到 InputGate

TaskManager 只有一个 Network BufferPool 被所有的 Task 共享,初始化时会从 Off-heap Memory 中申请内存,申请后内存管理通过 Network BufferPool 来进行,不需要依赖 JVM GC 的机制去释放。有了 Network BufferPool 之后可以为每一个 ResultSubPartition 创建 Local BufferPool

反压过程:

  1. 首先InputChannel 的 Buffer 被用尽于
  2. 会向 Local BufferPool 申请新的 Buffer
  3. 如果 Local BufferPool没有可用的,或是 Local BufferPool 的最大可用 Buffer 到了上限 无法向 Network BufferPool 申请,没有办法去读取新的数据
  4. 这时 Netty AutoRead 就会被禁掉,Netty 就不会从 Socket 的 Buffer 中读取数据了。
  5. 导致消费端的Socket的buffer也被用尽,这时就会将 Window = 0 发送给发送端(前文提到的 TCP 滑动窗口的机制)。
  6. 这时发送端的 Socket 就会停止发送。导致 Socket 的 Buffer 也被用尽,发送端的Netty 检测到 Socket 无法写了之后就会停止向 Socket 写数据。
  7. Netty 停止写了之后,所有的数据就会阻塞在 Netty 的 Buffer 当中了,但是 Netty 的 Buffer 是无界的,可以通过 Netty 的水位机制中的 high watermark 控制他的上界。当超过了 high watermark,Netty 就会将其 channel 置为不可写,ResultSubPartition 在写之前都会检测 Netty 是否可写,发现不可写就会停止向 Netty 写数据。
    8.这时候所有的压力都来到了 ResultSubPartition,和接收端一样他会不断的向 Local BufferPool 和 Network BufferPool 申请内存直至用尽buffer
    9.record write写阻塞,Operator 就会停止写数据,达到跨 TaskManager 的反压。
  • 跨 TaskManager 数据传输

     

    image.png

  • TaskManager 内反压过程

     

    image.png

下游的 TaskManager 反压导致本 TaskManager 的 ResultSubPartition 无法继续写入数据,于是 Record Writer 的写也被阻塞住了,因为 Operator 需要有输入才能有计算后的输出,输入跟输出都是在同一线程执行, Record Writer 阻塞了,Record Reader 也停止从 InputChannel 读数据,这时上游的 TaskManager 还在不断地发送数据,最终将这个 TaskManager 的 Buffer 耗尽。具体流程可以参考下图,这就是 TaskManager 内的反压过程。

TCP-based 反压的弊端

  • 在一个 TaskManager 中可能要执行多个 Task,如果多个 Task 的数据最终都要传输到下游的同一个 TaskManager 就会复用同一个 Socket 进行传输,这个时候如果单个 Task 产生反压,就会导致复用的 Socket 阻塞,其余的 Task 也无法使用传输,checkpoint barrier 也无法发出导致下游执行 checkpoint 的延迟增大。

  • 依赖最底层的 TCP 去做流控,会导致反压传播路径太长,导致生效的延迟比较大。

Credit-based 反压(SINCE FLINK1.5)

这个机制简单的理解起来就是在 Flink 层面实现类似 TCP 流控的反压机制来解决上述的弊端,Credit 可以类比为 TCP 的 Window 机制。

反压过程

Flink 层面实现反压机制,就是每一次 ResultSubPartition 向 InputChannel 发送消息的时候都会发送一个 backlog size 告诉下游准备发送多少消息,下游就会去计算有多少的 Buffer 去接收消息,算完之后如果有充足的 Buffer 就会返还给上游一个 Credit 告知他可以发送消息(图上两个 ResultSubPartition 和 InputChannel 之间是虚线是因为最终还是要通过 Netty 和 Socket 去通信)

 


过了一段时间后,由于上游的发送速率要大于下游的接受速率,下游的 TaskManager 的 Buffer 已经到达了申请上限,这时候下游就会向上游返回 Credit = 0,ResultSubPartition 接收到之后就不会向 Netty 去传输数据,上游 TaskManager 的 Buffer 也很快耗尽,达到反压的效果,这样在 ResultSubPartition 层就能感知到反压,不用通过 Socket 和 Netty 一层层地向上反馈,降低了反压生效的延迟。同时也不会将 Socket 去阻塞,解决了由于一个 Task 反压导致 TaskManager 和 TaskManager 之间的 Socket 阻塞的问题

 

总结

  1. 网络流控是为了在上下游速度不匹配的情况下,防止下游出现过载
  2. 网络流控有静态限速和动态反压两种手段
  3. Flink 1.5 之前是基于 TCP 流控 + bounded buffer 实现反压
  4. Flink 1.5 之后实现了自己托管的 credit – based 流控机制,在应用层模拟 TCP 的流控机制
    有了动态反压,静态限速是不是完全没有作用了?

    image.png


    我们流计算的结果最终是要输出到一个外部的存储(Storage),外部数据存储到 Sink 端的反压是不一定会触发的,这要取决于外部存储的实现,像 Kafka 这样是实现了限流限速的消息中间件可以通过协议将反压反馈给 Sink 端,但是像 ES 无法将反压进行传播反馈给 Sink 端*(极端情况导致job failover,es端socket发生 time out),这种情况下为了防止外部存储在大的数据量下被打爆,我们就可以通过静态限速的方式在 Source 端去做限流。

    image.png

网络上传输的数据会写到 Task 的 InputGate(IG) 中,经过 Task 的处理后,再由 Task 写到 ResultPartition(RS) 中。每个 Task 都包括了输入和输入,输入和输出的数据存在 Buffer 中(都是字节数据)。Buffer是 MemorySegment 的包装类。

根据配置,Flink 会在 NetworkBufferPool 中生成一定数量(默认2048)的内存块 MemorySegment,内存块的总数量就代表了网络传输中所有可用的内存。NetworkEnvironment 和 NetworkBufferPool 是 Task 之间共享的,每个 TM 只会实例化一个

Task 线程启动时,会为 Task 的 InputGate(IG)和 ResultPartition(RP) 分别创建一个 LocalBufferPool(缓冲池)并设置可申请的 MemorySegment(内存块)数量。IG 对应的缓冲池初始的内存块数量与 IG 中 InputChannel 数量一致,RP 对应的缓冲池初始的内存块数量与 RP 中的 ResultSubpartition 数量一致。不过,每当创建或销毁缓冲池时,NetworkBufferPool 会计算剩余空闲的内存块数量,并平均分配给已创建的缓冲池。

在 Task 线程执行过程中,当 Netty 接收端收到数据时,为了将 Netty 中的数据拷贝到 Task 中,InputChannel(实际是 RemoteInputChannel)会向其对应的缓冲池申请内存块(上图中的①)。如果缓冲池中也没有可用的内存块且已申请的数量还没到池子上限,则会向 NetworkBufferPool 申请内存块(上图中的②)并交给 InputChannel 填上数据(上图中的③和④)。

  1. 当一个内存块被消费完成之后(在输入端是指内存块中的字节被反序列化成对象了,在输出端是指内存块中的字节写入到 Netty Channel 了),会调用 Buffer.recycle() 方法,会将内存块还给 LocalBufferPool (上图中的⑤)。如果LocalBufferPool中当前申请的数量超过了池子容量(由于上文提到的动态容量,由于新注册的 Task 导致该池子容量变小),则LocalBufferPool会将该内存块回收给 NetworkBufferPool(上图中的⑥)。如果没超过池子容量,则会继续留在池子中,减少反复申请的开销

反压的过程
这里我们需要注意两个场景:

  • 本地传输:如果 Task 1 和 Task 2 运行在同一个 worker 节点(TaskManager),该 buffer 可以直接交给下一个 Task。一旦 Task 2 消费了该 buffer,则该 buffer 会被缓冲池1回收。如果 Task 2 的速度比 1 慢,那么 buffer 回收的速度就会赶不上 Task 1 取 buffer 的速度,导致缓冲池1无可用的 buffer,Task 1 等待在可用的 buffer 上。最终形成 Task 1 的降速。
  • 远程传输:在输出端,通过 Netty 的水位值机制来保证不往网络中写入太多数据。如果网络中的数据(Netty输出缓冲中的字节数)超过了高水位值,我们会等到其降到低水位值以下才继续写入数据。

Netty 水位值机制

初始化 NettyServer 时配置的水位值参数。

bootstrap.childOption(ChannelOption.WRITE_BUFFER_LOW_WATER_MARK, config.getMemorySegmentSize() + 1);
bootstrap.childOption(ChannelOption.WRITE_BUFFER_HIGH_WATER_MARK, 2 * config.getMemorySegmentSize());

当输出缓冲中的字节数超过了高水位值, 则 Channel.isWritable() 会返回false。当输出缓存中的字节数又掉到了低水位值以下, 则 Channel.isWritable() 会重新返回true。Flink 中发送数据的核心代码在 PartitionRequestQueue 中

private void writeAndFlushNextMessageIfPossible(final Channel channel) throws IOException {
  if (fatalError) {
    return;
  }

  Buffer buffer = null;

  try {
    // channel.isWritable() 配合 WRITE_BUFFER_LOW_WATER_MARK 
    // 和 WRITE_BUFFER_HIGH_WATER_MARK 实现发送端的流量控制
    if (channel.isWritable()) {
      // 注意: 一个while循环也就最多只发送一个BufferResponse, 连续发送BufferResponse是通过writeListener回调实现的
      while (true) {
        if (currentPartitionQueue == null && (currentPartitionQueue = queue.poll()) == null) {
          return;
        }

        buffer = currentPartitionQueue.getNextBuffer();

        if (buffer == null) {
          // 跳过这部分代码
          ...
        }
        else {
          // 构造一个response返回给客户端
          BufferResponse resp = new BufferResponse(buffer, currentPartitionQueue.getSequenceNumber(), currentPartitionQueue.getReceiverId());

          if (!buffer.isBuffer() &&
              EventSerializer.fromBuffer(buffer, getClass().getClassLoader()).getClass() == EndOfPartitionEvent.class) {
            // 跳过这部分代码。batch 模式中 subpartition 的数据准备就绪,通知下游消费者。
            ...
          }

          // 将该response发到netty channel, 当写成功后, 
          // 通过注册的writeListener又会回调进来, 从而不断地消费 queue 中的请求
          channel.writeAndFlush(resp).addListener(writeListener);

          return;
        }
      }
    }
  }
  catch (Throwable t) {
    if (buffer != null) {
      buffer.recycle();
    }

    throw new IOException(t.getMessage(), t);
  }
}

// 当水位值降下来后(channel 再次可写),会重新触发发送函数
@Override
public void channelWritabilityChanged(ChannelHandlerContext ctx) throws Exception {
  writeAndFlushNextMessageIfPossible(ctx.channel());
}

反压监控

Flink 在使用了一个 trick 来实现对反压的监控。如果一个 Task 因为反压而降速了,那么它会卡在向 LocalBufferPool 申请内存块上。那么这时候,该 Task 的 stack trace 就会长下面这样:

java.lang.Object.wait(Native Method)
o.a.f.[...].LocalBufferPool.requestBuffer(LocalBufferPool.java:163)
o.a.f.[...].LocalBufferPool.requestBufferBlocking(LocalBufferPool.java:133) <--- BLOCKING request
[...]

那么事情就简单了。通过不断地采样每个 task 的 stack trace(线程堆栈) 就可以实现反压监控。

image.png


Flink 的实现中,只有当 Web 页面切换到某个 Job 的 Backpressure 页面,才会对这个 Job 触发反压检测,因为反压检测还是挺昂贵的。JobManager的StackTraceSampleCoordinator( A coordinator for triggering and collecting stack traces of running tasks)会通过 Akka 给每个 TaskManager 发送TriggerStackTraceSample消息。默认情况下,TaskManager 会触发100次 stack trace 采样,每次间隔 50ms(也就是说一次反压检测至少要等待5秒钟)。并将这 100 次采样的结果返回给 JobManager,由 JobManager 来计算反压比率(反压出现的次数/采样的次数),最终展现在 UI 上。UI 刷新的默认周期是一分钟,目的是不对 TaskManager 造成太大的负担。

 

Flink 如何在吞吐量和延迟之间做权衡?

我们分析了上述的网络传输后,知道每个 SubTask 输出的数据并不是直接输出到下游,而是在 ResultSubPartition 中有一个 Buffer 用来缓存一批数据后,再 Flush 到 Netty 发送到下游 SubTask。那到底哪些情况会触发 Buffer Flush 到 Netty 呢?

  • Buffer 变满时

  • Buffer timeout 时

  • 特殊事件来临时,例如:CheckPoint 的 barrier 来临时

Flink 在数据传输时,会把数据序列化成二进制然后写到 Buffer 中,当 Buffer 满了,需要 Flush(默认为32KiB,通过taskmanager.memory.segment-size设置)。但是当流量低峰或者测试环节,可能1分钟都没有 32 KB的数据,就会导致1分钟内的数据都积攒在 Buffer 中不会发送到下游 Task 去处理,从而导致数据出现延迟,这并不是我们想看到的。所以 Flink 有一个 Buffer timeout 的策略,意思是当数据量比较少,Buffer 一直没有变满时,后台的 Output flusher 线程会强制地将 Buffer 中的数据 Flush 到下游。Flink 中默认 timeout 时间是 100ms,即:Buffer 中的数据要么变满时 Flush,要么最多等 100ms 也会 Flush 来保证数据不会出现很大的延迟。当然这个可以通过 env.setBufferTimeout(timeoutMillis) 来控制超时时间。

  • timeoutMillis > 0 表示最长等待 timeoutMillis 时间,就会flush
  • timeoutMillis = 0 表示每条数据都会触发 flush,直接将数据发送到下游,相当于没有Buffer了(避免设置为0,可能导致性能下降)
  • timeoutMillis = -1 表示只有等到 buffer满了或 CheckPoint的时候,才会flush。相当于取消了 timeout 策略
    严格来讲,Output flusher 不提供任何保证——它只向 Netty 发送通知,而 Netty 线程会按照能力与意愿进行处理。这也意味着如果存在反压,则 Output flusher 是无效的。言外之意,如果反压很严重,下游 Buffer 都满了,当然不能强制一直往下游发数据。

一些特殊的消息如果通过 RecordWriter 发送,也会触发立即 Flush 缓存的数据。其中最重要的消息包括 Checkpoint barrier 以及 end-of-partition 事件,这些事件应该尽快被发送,而不应该等待 Buffer 被填满或者 Output flusher 的下一次 Flush。当然如果出现反压,CheckPoint barrier 也会等待,不能发送到下游。

引入 Network buffers 以获得更高的资源利用率和更高的吞吐量,代价是让一些记录在 Buffer 中等待一段时间。虽然可以通过缓冲区超时给出此等待时间的上限,但你可能知道有关这两个维度(延迟和吞吐量)之间权衡的更多信息:显然,无法同时获得这两者

参考:
https://ververica.cn/developers/advanced-tutorial-2-analysis-of-network-flow-control-and-back-pressure/
http://wuchong.me/blog/2016/04/26/flink-internals-how-to-handle-backpressure/
[https://www.cnblogs.com/pengblog2020/p/12161716.html]

 

 

Flink详解系列之九--反压机制和处理 相同的场景,上游生产的速率为2,下游消费的速率为1,这样InputChannel中的内存很快就会耗尽,通信过程中就会返回credit=0给ResultSubPartition告知上游,下游已经没有空间了,上游也就不再继续发送数据给netty,直到下游消费给InputChannel腾出空间了,数据才会继续发送。值得注意的是,反压的根源节点并不一定会在反压监控面板体现出高反压,因为反压面板监控的是发送端,如果某个节点是性能瓶颈并不会导致它本身出现高反压,而是导致它的上游出现高反压。上面几项并不是全部场景。 阅读详情

相关推荐

Flink 反压

Flink反压是一个在实时计算应用中常见的问题,特别是在流式计算场景中。

王小工小工历程 2881

flink的反压机制(源码剖析)

背景 在前文我们对flink早期基于TCP的反压和现在基于信任值的反压机制进行了剖析 Flink反压机制剖析,本文主要从源码的角度对flink基于Credit&BackLog的反压机制从源码的角度剖析其具体实现过程。 基于TCP反压的问题 TaskManager之间会启动一个TCP通道进行数据交互,TaskManager的所有Task通过多路复用使用同一个TCP通道。因此,当下游因一个Task处理能力不足造成反压时,就会导致整个TCP通道阻塞。即使其他Task还有空余的Buffer也无法接受数据

weixin_45626756的博客 1545

flink的反压

Flink 的反压机制是其高吞吐、低延迟、Exactly-Once 语义等特性的重要基石。它通过基于信用的流量控制,以高效、自动化的方式解决了流处理中上下游速度不匹配的问题,确保了系统在负载压力下的稳定性和可靠性。开发者应理解其原理,并善用监控工具来识别和优化作业中的性能瓶颈。

2301_80954266的博客 885

Flink反压原理深入浅出及解决思路

1. 前言Apache Flink 是一个分布式大数据处理引擎,可对有限数据流和无限数据流进行有状态或无状态的计算,能够部署在各种集群环境,对各种规模大小的数据进行快速计算。既然是对流式数据进行处理,那么就要面临数据在流动计算时,上下游数据通信以及数据处理速度不一致所带来的问题。本文先从「生产者-消费者模式」的角度介绍了Flink中的数据传输,从而引出了「反压」的概念。接着介绍了Flink在V1....

1724

2024年最全Flink实战(19):flink反压_什么是flink反压(2)

2. 网络流控有静态限速和动态反压两种手段3. Flink 1.5 之前是基于 TCP 流控 + bounded buffer 实现反压4. Flink 1.5 之后实现了自己托管的 credit – based 流控机制,在应用层模拟 TCP 的流控机制是否有了动态反压,静态限速就没用了?不是的。

2301_76379606的博客 796

Flink反压最经典处理方式之一 基于 Credit 的流量控制机制

另一种经典的反压处理方案是,它在 Flink 1.5 及以后版本中得到了广泛应用。这种机制从应用层直接控制数据传输,避免了传统 TCP 层反压的局限性,能够更灵活、迅速地反馈下游的缓冲状况。下面详细介绍这种方案的原理、流程和实现细节。

weixin_50227709的博客 1475

Flink调优----反压处理

在 Flink 大数据处理架构里,网络流控与反压机制极为关键,如同交通指挥,保障数据与系统运行。数据于节点间流动,反压若现且未妥善处理,将引发 checkpoint 时长增加、状态膨胀、资源耗竭甚至系统崩溃等连锁反应。所以,开发者与运维人员务必深谙其原理,熟练定位反压节点,知晓原因与处理策略。如此,面对复杂数据场景,方能提前预防或快速化解反压,让 Flink 系统高效稳定,为业务持续提供可靠数据支撑,推动业务顺利开展。

天冬忘忧的博客 2369

Flink 反压笔记

参考博客1,参考博客2,参考博客3 这篇博客其实开始写的很简单,但是想到之前阿里在1.5回馈社区的新流控机制就一起记录一下 。 从上游算子产出到下游算子消费数据,基本可用划分了三个模块: 1.上游算子产出的record序列化成buffer数据结构插入到sub partition队列。 2.网络传输:上下游可能调度部署到不同的container中,上游的数据需要经过网络传输到下游,涉及到数据拷贝...

文报的博客 1635

Flink反压机制

​Flink中的反压(Backpressure)是指数据流处理过程中,下游任务的处理速度跟不上上游任务的数据发送速度,导致数据在系统中积压,可能引发系统性能下降、延迟增加,甚至资源耗尽等问题。监控反压状态:​Flink提供了Web UI,可以查看各个任务的反压状态。下游任务处理能力不足:​当下游任务的计算资源配置不足,或处理逻辑复杂度过高,导致其处理速度跟不上数据流入的速度,进而引发反压。优化资源配置:​根据分析结果,适当调整任务的并行度、资源配置,或优化任务的处理逻辑,以提高处理能力,缓解反压。

weixin_50227709的博客 1445

大数据最全Flink实战(19):flink反压_什么是flink反压,月薪30K

flink反压(backpressure),简单来说就是当接收方的接收速率低于发送方的发送速率,这时如果不做处理就会导致接收方的数据积压越来越多直到内存溢出,所以此时需要一个机制来根据接收方的状态反过来限制发送方的发送速率,来达到一个两者速率匹配的状态。

2401_84184729的博客 552

flink实战--反压机制与背压指标计算原理

简介 流处理系统必须能优雅地处理反压(backpressure)问题,因为实时流处理必然会遇到产这样的场景:短时负载高峰导致系统接收数据的速率远高于它处理数据的速率。反压如果不能得到正确的处理,可能会导致资源耗尽甚至系统崩溃,目前主流的流处理系统Storm/Spark Streaming/Flink 都已经提供了反压机制,不过其实现各不相同。spark的反压机制参考...

阿华田的博客 3910

Flink反压排查及解决方案

利用 Flink Web UI 定位,通过查看subtask的反压监控,反压状态为HIGH红色的subtask即处于反压。​ 解决: ​ 方法一:直接聚合。​ 发现二:通过Flink Web UI查看任务的反压情况,如果只有个别Subtask呈现反压情况,有红有绿,可以推断出数据倾斜。​ 设置参数:开启MiniBatch,设置批量输出的间隔时间,设置每个批次最多缓存数据的条数(可以设置为两万条)。如果通过Flink Web UI查看subtask的反压情况有红有绿 ----> 原因:数据倾斜。

weixin_46856219的博客 2313

青藏高原冻土数据实战:如何用QGIS分析1961-2020年冻土退化趋势(附完整操作步骤)

本文详细介绍了如何使用QGIS分析1961-2020年青藏高原冻土退化趋势,包括数据准备、预处理、时空分析和模型验证等全流程操作。通过TTOP模型和Stefan方程,揭示了冻土退化的空间差异和海拔依赖性,为环境研究提供科学依据。

weixin_29276847的博客 128

Flink中的反压与背压:原理、检测与应对

Flink流处理系统中,反压与背压机制对保障系统稳定性至关重要。本文首先辨析二者概念,指出其本质均为处理数据生产与消费速度不匹配问题。随后剖析反压产生的三大根源:数据生成速度过高、操作符处理速度差异及系统资源不足。通过测试程序演示如何模拟反压场景,并介绍利用subtask状态和Buffer使用率等Metrics指标精准定位反压瓶颈的方法。最后强调开发者需掌握反压分析技术,优化系统配置,确保Flink在大数据场景下的高效稳定运行。文章为处理流计算性能问题提供了系统性解决方案。

qq_42773076的博客 1798

[比赛]新冠期间饿了么骑士行为预估-数据理解

写在前面 饿了么的比赛的赛题数据理解。 一、骑士行为数据 courier_id 骑士id wave_index 波次index tracking_id 订单id courier_wave_start_lng 波次起始时刻骑士位置 courier_wave_...

Helslie的博客 2944

立创EDA开源足轮机器人:基于STM32F407与ESP32的LQR自平衡与FOC驱动设计全解析

本文详细解析了基于立创EDA平台的开源足轮机器人项目。该项目采用STM32F407作为主控,ESP32负责无线通信,并应用LQR自平衡算法与FOC驱动技术,实现了机器人的稳定站立、移动转向及复杂地形适应能力。文章深入剖析了其硬件架构、软件设计及调试经验,为机器人运动控制学习提供了宝贵参考。

weixin_42608299的博客 233

Flink反压机制详解与优化策略

Flink 的反压机制从 TCP-Based 到 Credit-Based 的演进,体现了其向低延迟、细粒度控制的发展方向。Credit 机制通过应用层信用交换,将反压转化为精准的流量协商,成为当前大规模流处理的基石。运维中需结合 UI 监控、Metrics 分析和代码优化,形成“监测-定位-调优”闭环,同时注意静态限速与动态反压的互补使用。

走过冬季 1529

ABB机器人姿态与四元数(笔记)

通常使用机器人作业时,机器人的法兰轴(5轴)往往是垂直与作业平面的,此时需要将机器人的姿态调整(示教)到垂直于工作平面的状态,然后记录当前的姿态,作为之后作业的参考标准姿态。不同机器人表示控件姿态的方式不一样,但也无外乎3中:旋转矩阵、欧拉角和四元数。 ABB机器人使用的是四元数(可转欧拉角)作为机器人控件姿态的表示方式。这里主要是记录在不通过示教的方式下,如何定义四元数,使机器人达到垂直于工作平面的姿态。 5轴竖直向下(常用):此时,各轴角度为 [0,0,0,0,9...

Zythonista的博客 1万+

「Flink反压机制」看这一篇就够了

从tcp数据传输,滑动窗口,再到Flink反压机制,一文看懂Flink反压

Peanut的博客 2627

深入Linux网络子系统:STMMAC驱动如何通过MDIO总线与PHY芯片“对话”

本文深入解析了Linux网络子系统中STMMAC驱动通过MDIO总线与PHY芯片的通信机制。详细介绍了MDIO总线的注册流程、PHY设备的绑定机制以及设备树配置,帮助开发者理解MAC控制器与PHY芯片的协作基础,优化网络通信性能。

weixin_26897585的博客 449

【C++】ROS:ROS1环境配置与基础示例

ROS1环境配置与基础示例

DevFrank的博客 2106

Flink的反压机制:底层原理、产生原因、排查思路与解决方案

在解决反压时,应该首先通过 Flink 的监控工具排查具体原因,然后根据实际情况采取针对性的解决方案,如增加并行度、优化算子逻辑、调整分区策略、优化外部系统等。通过合理的反压处理,可以显著提高 Flink 作业的稳定性和处理效率。在 keyBy 操作后,不同的并行子任务(subtask)可能收到的数据量不均衡,某些子任务的数据量远远多于其他任务,这会导致这些任务的处理速度显著下降,进而引发反压。反压的产生通常是因为数据流中的某些算子处理数据的速度低于其上游算子的输出速度,导致下游的缓冲区耗尽,引发反压。

goTsHgo的博客 4202

PPT里文字太多如何排版-一口气教你7种布局瞬间让PPT高大上起来

PPT里全是文字且很拥挤怎么办?本篇教你使用7种不同的排版让你的PPT瞬间变得高大上起来。

打造全国最全的AI Agent开发知识领域的博客 5026

Flink学习笔记:反压

本文介绍了Flink中的反压机制及其监控方法。反压是流式系统中下游对上游的数据处理反馈机制,当上游生产速度超过下游消费速度时触发。Flink数据传输分三种情况:同线程直接共享内存、本地跨线程通过Buffer交互、远程跨节点通过网络传输。反压监控通过Web UI显示状态(OK/LOW/HIGH),分别对应不同的反压程度。文章详细分析了本地和远程场景下反压的感知原理,为Flink运维提供了重要参考。

K_Ohaha的博客 713

【2025年阿里云暑期实习(算法岗)-4月24日-第一题(100分)- 小红听歌】(题目+思路+Java&C++&Python解析+在线测试)

小红正在听歌,屏幕上同时展示着歌词和对应的播放进度条。s1t101ti​0iti​1i小红每次可以操作快进或回退一个歌词(即将播放指针向右或向左移动一个位置),数据初始时和操作过程均保证已经播放的歌词是s的一个前缀(可为空串)。她的目标是:以尽可能少的操作次数,使得字符串s中未播放状态的歌词是"幸运串"。请你计算,为了达到该目标,至少需要多少次操作?(数据保证可以在有限次内完成操作目标)【幸运串】每种字母出现的次数为指定的次数,可为空串,具体可查看输入描述。

m0_73659489的博客 116

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

Flink反压机制剖析

网络流控的概念与背景 1.为什么需要网络流控 如果 Receive Buffer 是有界的,这时候新到达的数据就只能被丢弃掉了。 如果 Receive Buffer 是无界的,Receive Buffer 会持续的扩张,最终会导致 Consumer 的内存耗尽。 2.网络流控的实现:静态限速 我们在Producer端实现一个静态限流,Producer经过限流器流量降低到和Consumer端相同,这样的话 Producer 端的发送速率跟 Consumer 端的处理速率就可以匹配起来了,就不会导致上述问题

weixin_45626756的博客 1441

深度学习工具包 DeepLearningToolbox

深度学习工具包Deprecation notice.-----This toolbox is outdated and no longer maintained.There are much better tools available for deep learning than this toolbox, e.g. [Theano](http://deeplearning.net/software/theano/), [torch](http://torch.ch/) or [tensorflow](http://www.tensorflow.org/)I would suggest you use one of the tools mentioned above rather than use this toolbox.Best, Rasmus.DeepLearnToolbox================A Matlab toolbox for Deep Learning.Deep Learning is a new subfield of machine learning that focuses on learning deep hierarchical models of data.It is inspired by the human brain's apparent deep (layered, hierarchical) architecture.A good overview of the theory of Deep Learning theory is[Learning Deep Architectures for AI](http://www.iro.umontreal.ca/~bengioy/papers/ftml_book.pdf)For a more informal introduction, see the following videos by Geoffrey Hinton and Andrew Ng.* [The Next Generation of Neural Networks](http://www.youtube.com/watch?v=AyzOUbkUf3M) (Hinton, 2007)* [Recent Developments in Deep Learning](http://www.youtube.com/watch?v=VdIURAu1-aU) (Hinton, 2010)* [Unsupervised Feature Learning and Deep Learning](http://www.youtube.com/watch?v=ZmNOAtZIgIk) (Ng, 2011)If you use this toolbox in your research please cite [Prediction as a candidate for learning deep hierarchical models of data](http://www2.imm.dtu.dk/pubdb/views/publication_details.php?id=6284)```@MASTERSTHESIS\{IMM2012-06284, author = "R. B. Palm", title = "Prediction as a candidate for learning deep hierarchical models of data", year = "2012",}```Contact: rasmusbergpalm at gmail dot comDirectories included in the toolbox-----------------------------------`NN/` - A library for Feedforward Backpropagation Neural Networks`CNN/` - A library for Convolutional Neural Networks`DBN/` - A library for Deep Belief Networks`SAE/` - A library for Stacked Auto-Encoders`CAE/` - A library for Convolutional Auto-Encoders`util/` - Utility functions used by the libraries`data/` - Data used by the examples`tests/` - unit tests to verify toolbox is workingFor references on each library check REFS.mdSetup-----1. Download.2. addpath(genpath('DeepLearnToolbox'));Example: Deep Belief Network---------------------```matlabfunction test_example_DBNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit RBM and visualize its weightsrand('state',0)dbn.sizes = [100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);figure; visualize(dbn.rbm{1}.W'); % Visualize the RBM weights%% ex2 train a 100-100 hidden unit DBN and use its weights to initialize a NNrand('state',0)%train dbndbn.sizes = [100 100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);%unfold dbn to nnnn = dbnunfoldtonn(dbn, 10);nn.activation_function = 'sigm';%train nnopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.10, 'Too big error');```Example: Stacked Auto-Encoders---------------------```matlabfunction test_example_SAEload mnist_uint8;train_x = double(train_x)/255;test_x = double(test_x)/255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit SDAE and use it to initialize a FFNN% Setup and train a stacked denoising autoencoder (SDAE)rand('state',0)sae = saesetup([784 100]);sae.ae{1}.activation_function = 'sigm';sae.ae{1}.learningRate = 1;sae.ae{1}.inputZeroMaskedFraction = 0.5;opts.numepochs = 1;opts.batchsize = 100;sae = saetrain(sae, train_x, opts);visualize(sae.ae{1}.W{1}(:,2:end)')% Use the SDAE to initialize a FFNNnn = nnsetup([784 100 10]);nn.activation_function = 'sigm';nn.learningRate = 1;nn.W{1} = sae.ae{1}.W{1};% Train the FFNNopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.16, 'Too big error');```Example: Convolutional Neural Nets---------------------```matlabfunction test_example_CNNload mnist_uint8;train_x = double(reshape(train_x',28,28,60000))/255;test_x = double(reshape(test_x',28,28,10000))/255;train_y = double(train_y');test_y = double(test_y');%% ex1 Train a 6c-2s-12c-2s Convolutional neural network %will run 1 epoch in about 200 second and get around 11% error. %With 100 epochs you'll get around 1.2% errorrand('state',0)cnn.layers = { struct('type', 'i') %input layer struct('type', 'c', 'outputmaps', 6, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %sub sampling layer struct('type', 'c', 'outputmaps', 12, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %subsampling layer};cnn = cnnsetup(cnn, train_x, train_y);opts.alpha = 1;opts.batchsize = 50;opts.numepochs = 1;cnn = cnntrain(cnn, train_x, train_y, opts);[er, bad] = cnntest(cnn, test_x, test_y);%plot mean squared errorfigure; plot(cnn.rL);assert(er<0.12, 'Too big error');```Example: Neural Networks---------------------```matlabfunction test_example_NNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);% normalize[train_x, mu, sigma] = zscore(train_x);test_x = normalize(test_x, mu, sigma);%% ex1 vanilla neural netrand('state',0)nn = nnsetup([784 100 10]);opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samples[nn, L] = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.08, 'Too big error');%% ex2 neural net with L2 weight decayrand('state',0)nn = nnsetup([784 100 10]);nn.weightPenaltyL2 = 1e-4; % L2 weight decayopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex3 neural net with dropoutrand('state',0)nn = nnsetup([784 100 10]);nn.dropoutFraction = 0.5; % Dropout fraction opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex4 neural net with sigmoid activation functionrand('state',0)nn = nnsetup([784 100 10]);nn.activation_function = 'sigm'; % Sigmoid activation functionnn.learningRate = 1; % Sigm require a lower learning rateopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex5 plotting functionalityrand('state',0)nn = nnsetup([784 20 10]);opts.numepochs = 5; % Number of full sweeps through datann.output = 'softmax'; % use softmax outputopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex6 neural net with sigmoid activation and plotting of validation and training error% split training data into training and validation datavx = train_x(1:10000,:);tx = train_x(10001:end,:);vy = train_y(1:10000,:);ty = train_y(10001:end,:);rand('state',0)nn = nnsetup([784 20 10]); nn.output = 'softmax'; % use softmax outputopts.numepochs = 5; % Number of full sweeps through dataopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, tx, ty, opts, vx, vy); % nntrain takes validation set as last two arguments (optionally)[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');```[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/rasmusbergpalm/deeplearntoolbox/trend.png)](https://bitdeli.com/free "Bitdeli Badge")

上一篇: dirty_ratio与dirty_background_ratio参数区别--系统优化必选
下一篇: Protobuf与JSON互相转换
王树民
博客等级 码龄10年 912粉丝 560原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值