Flink/Blink 原理漫谈(三)state 有状态计算机制 详解

本文深入探讨Flink/Blink的有状态计算机制,包括State存储实现(HeapStateBackend、FsStateBackend、RocksDBStateBackend、NiagaraStateBackend)和分类(OperatorState、KeyedState)。讲解了状态一致性(at-most-once、at-least-once、exactly-once)以及端到端一致性,强调了Flink在保证一致性的前提下实现低延迟和高吞吐。

系列文章目录

Flink/Blink 原理漫谈(零)运行时的组件

Flink/Blink 原理漫谈(一)时间,watermark详解

Flink/Blink 原理漫谈(二)流表对偶性和distinct详解

Flink/Blink 原理漫谈(三)state 有状态计算机制 详解

Flink/Blink 原理漫谈(四)window机制详解

Flink/Blink 原理漫谈(五)流式计算的持续查询实现 详解

Flink/Blink 原理漫谈(六)容错机制(fault tolerance)详解



State

首先,blink是有状态计算的,State是流计算特有的,流计算在 大多数场景 下是增量计算,数据逐条处理(大多数场景),每次计算是在上一次计算结果之上进行处理的,这样的机制势必要将上一次的计算结果进行存储(生产模式要持久化),另外由于 机器,网络,脏数据等原因导致的程序错误,在重启job时候需要从成功的检查点(checkpoint,后面篇章会专门介绍)进行state的恢复。增量计算,Failover这些机制都需要state的支撑。
除此外,状态也可以理解为是一个本地变量,可以被业务逻辑所访问。

State存储实现

Blink内部有四种state的存储实现,具体如下:
• 基于内存的HeapStateBackend - 在debug模式使用,不 建议在生产模式下应用;
• 基于HDFS的FsStateBackend - 分布式文件持久化,每次读写都产生网络IO,整体性能不佳;checkpoint存在远程的持久化文件系统上,本地状态存在taskmanager的JVM堆上。
• 基于RocksDB的RocksDBStateBackend - 本地文件+异步HDFS持久化,blink-1.x版本生产应用;将所有状态序列化,存入RocksDB中
• 还有一个是基于Niagara(blink2.x)NiagaraStateBackend - 分布式持久化,blink-2.x版本生产应用;
Blink-1.x版本选择用RocksDB+HDFS的方式进行State的存储,State存储分两个阶段,首先本地存储到RocksDB,然后异步的同步到远程的HDFS。 这样的而设计既消除了HeapStateBackend的局限(内存大小,机器坏掉丢失等),也减少了纯分布式存储的网络IO开销。

<think>我们正在讨论NuttX中TCB的flinkblink指针如何用于实现优先级继承机。优先级继承是一种解决优先级反转问题的技术,当高优先级任务因低优先级任务持有共享资源而阻塞时,临时提升低优先级任务的优先级至与高优先级任务相同,使其尽快执行并释放资源。 在NuttX中,优先级继承机(Priority Inheritance)主要通过互斥锁(mutex)实现。当任务尝试获取已被持有的互斥锁时,如果持有者优先级低于当前任务,系统会提升持有者优先级以避免优先级反转。而flinkblink指针作为双向链表的连接件,在就绪任务队列中用于快速调整任务的位置(因为就绪队列是按优先级排序的)。 具体实现步骤: 1. **检测优先级反转**:当高优先级任务(H)尝试获取低优先级任务(L)持有的互斥锁时,内核发现L的优先级低于H。 2. **提升持有者优先级**:系统临时将L的优先级提升到与H相同(或略低,具体取决于策略)。 3. **调整就绪队列**:由于L的优先级提升,需要将其在就绪队列中的位置前移(因为就绪队列是按优先级从高到低排序的双向链表)。这里就用到`flink`和`blink`指针: - 将L从当前链表中移除(通过修改相邻节点的`flink`和`blink`指针) - 根据新优先级将L插入到就绪队列的合适位置(同样通过调整链表指针) 4. **任务调度**:调度器下一次调度时,由于L的优先级已提升,会优先执行L,使其尽快释放互斥锁。 5. **恢复原优先级**:当L释放互斥锁后,系统将其优先级恢复为原值,并调整其在就绪队列中的位置。 关键代码逻辑(以互斥锁获取为例): ```c // 当任务H尝试获取已被L持有的互斥锁时 if (H->priority > L->priority) { // 提升L的优先级至H的优先级 nxsched_set_priority(L, H->priority); // 调整L在就绪队列中的位置(使用flink/blink指针) sched_remove_readytorun(L); // 从原位置移除 sched_add_readytorun(L); // 按新优先级插入 } ``` 在调整链表位置时,`sched_remove_readytorun`和`sched_add_readytorun`函数内部会操作`flink`和`blink`指针,实现$O(1)$复杂度的链表节点删除和插入。例如: ```c void sched_remove_readytorun(FAR struct tcb_s *tcb) { // 获取前驱和后继 FAR struct tcb_s *prev = tcb->blink; FAR struct tcb_s *next = tcb->flink; // 更新前驱的后继指针 if (prev != NULL) { prev->flink = next; } // 更新后继的前驱指针 if (next != NULL) { next->blink = prev; } } ``` **总结**:`flink`和`blink`指针在优先级继承中的作用是**动态调整任务在就绪队列中的位置**,确保因优先级提升而需要提前执行的任务能被快速调度。这种机有效缓解了优先级反转问题,提高了系统的实时性。</think>### NuttX中如何利用`flink/blink`实现优先级继承机 在NuttX中,`flink`和`blink`指针通过**动态调整任务在就绪队列中的位置**来实现优先级继承机。该机主要用于解决优先级反转问题,具体实现过程如下: #### 1. **优先级继承触发条件** 当高优先级任务($T_{high}$)因等待低优先级任务($T_{low}$)持有的资源(如互斥锁)而阻塞时,系统触发优先级继承: ```c /* 互斥锁获取函数片段 */ if (mutex->holder && mutex->holder->sched_priority < current->sched_priority) { nxsched_priority_inherit(mutex->holder, current->sched_priority); // 触发继承[^1] } ``` #### 2. **优先级提升的核心操作** 通过`flink/blink`动态调整任务在就绪队列中的位置: ```mermaid graph LR A[检测优先级反转] --> B{提升持有者优先级} B --> C[从就绪队列移除T_low] C --> D[按新优先级插入队列] D --> E[更新调度指针] ``` 具体实现步骤: 1. **移除原优先级位置** 通过`flink/blink`将$T_{low}$从当前队列位置移除: ```c void sched_remove_readytorun(FAR struct tcb_s *tcb) { // 更新前驱节点的flink if (tcb->blink) tcb->blink->flink = tcb->flink; // 更新后继节点的blink if (tcb->flink) tcb->flink->blink = tcb->blink; } ``` 2. **插入新优先级位置** 使用优先级排序算法重新插入: ```c void sched_add_readytorun(FAR struct tcb_s *tcb) { // 遍历就绪队列(g_readytorun) FAR struct tcb_s *prev = NULL; FAR struct tcb_s *next = g_readytorun.head; // 按优先级查找插入点 while (next && next->sched_priority > tcb->sched_priority) { prev = next; next = next->flink; // 通过flink遍历 } // 更新flink/blink指针 tcb->flink = next; tcb->blink = prev; if (next) next->blink = tcb; if (prev) prev->flink = tcb; } ``` #### 3. **调度器行为变化** 优先级提升后: 1. 就绪队列头部`g_readytorun.head`指向$T_{low}$(因其临时拥有最高优先级) 2. 调度器通过`flink`遍历时优先执行$T_{low}$: ```c FAR struct tcb_s *next = g_readytorun.head; // 获取最高优先级任务 while (next->flink && !ready_to_run(next)) { // 通过flink遍历 next = next->flink; } up_switchcontext(current, next); // 切换到继承优先级的任务 ``` #### 4. **优先级恢复机** 当$T_{low}$释放资源后: 1. 通过`flink/blink`将其移出当前队列位置 2. 按原始优先级重新插入队列 3. 恢复$T_{high}$到就绪队列头部 #### 设计优势 1. **$O(1)$时间复杂度**:指针操作确保优先级调整高效完成 2. **无锁设计**:单核环境下通过开关中断保证原子性 3. **动态响应**:实时调整`g_readytorun.head`指向当前最高优先级任务 4. **资源优化**:复用TCB现有指针,无需额外存储 > 示例:当I²C驱动(HPWORK)持有资源时,其优先级可临时提升至与等待任务相同,确保实时性要求[^1]。 #### 总结 NuttX通过`flink/blink`实现: 1. **动态队列重组**:快速调整任务在双向链表中的位置 2. **优先级提升**:使资源持有者获得请求者的优先级 3. **实时调度**:确保高优先级任务最小化等待时间 4. **自动恢复**:资源释放后优先级自动回退 这种机有效解决了嵌入式系统中的优先级反转问题,同时保持调度器的高效性(平均$O(1)$操作复杂度)。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值