spark错误记录:Container on host: was preempted(没有彻底解决,只是理解这个问题)

本文探讨了Spark SQL任务中遇到的Container被抢占问题,深入解析YARN的公平调度机制,包括资源分配原则及抢占机制。提出了优化Spark任务的策略,如代码优化、资源管理调整及任务类型选择,以避免资源冲突。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

(作者:陈玓玏 data-master)

spark-sql任务跑着跑着,碰到一个bug:

Container  on host:  was preempted

在这里插入图片描述

又是一个新鲜的bug呢!!

一通查资料,得出一个初步结论:因为我的任务,其中有task占用的内存太大,而我们的yarn又是使用的公平调度机制,当有新任务来的时候,我的task对应的容器就会被别的任务抢占。

于是就简单了解下yarn的公平调度机制。yarn有先入先出调度器,容量调度器,公平调度器三种调度器。

先入先出调度器,先来的任务先执行,任务非常多,或者有的任务非常大的情况下,其他任务就苦了。

容量调度器,专门为小任务开辟了队列,不会抢占容器,因此任务非常多的时候,还是first in first out。

公平调度器,允许抢占容器。资源比较充足的情况下,新任务启动时,会等之前的任务阶段性使用资源释放出来,才会分老任务的资源。但是在资源不足的情况下,占用资源超过公平份额的容器,就可能被强制中断,把容器分配给占用资源未超过公平份额的容器。这个公平份额和使用份额,在spark web ui上可以看到。
在这里插入图片描述

至于解决的办法,我自己觉得,
1)要么就是资源紧张的时候,别挂任务,或者挂任务别挂spark任务,挂hive,嫌慢的话就多开些并发,hive就算多开并发也不会像spark一样自己互相抢占资源。

2)要么就是,好好看看自己的代码,看是不是能有些方法优化一下,减少不必要的数据,或者减少不必要的关联/操作,避免一个task中数据过多。

3)再不然,就只能改yarn的参数了,让资源抢占的门限值变高些。

这个错误也不一定会使得任务失败,有时候只是告警,会重启别的容器来执行失败的任务。

参考资料:

  1. 牵扯到yarn调度:https://blog.csdn.net/zhanyuanlin/article/details/71516286;
  2. 调度中的抢占机制,https://blog.csdn.net/bujiujie8/article/details/86713115(这篇写得比较好)
  3. https://www.mail-archive.com/issues@spark.apache.org/msg101196.html
  4. https://blog.csdn.net/m0_37885286/article/details/106674721
<think>我们正在处理一个关于ROS(RobotOperatingSystem)的问题,用户遇到了一个状态转换的bug:从SimpleGoalState[DONE]转换到CommState[ACTIVE]。用户希望得到修复这个bug的解决方案。根据用户提供的信息,以及我们之前的引用(引用[2])中提到的关于状态转换的内容,我们可以推断这个问题可能与actionlib(ROS中用于实现动作服务器的库)的状态机有关。在引用[2]中,我们看到一段代码处理了抢断(preempt)的情况,其中提到要确保在抢断时正确设置状态,避免错误的状态转换。在ROS的actionlib中,动作服务器和客户端之间的状态转换遵循一定的协议。通常,一个动作在完成(DONE)后不应该再转换到活跃(ACTIVE)状态,因为DONE表示动作已经结束(可能是成功、失败或被抢断)。所以,出现从DONE到ACTIVE的转换可能是状态机管理上的错误。可能的解决方案包括:1.检查动作服务器的实现,确保在动作完成后不再接受新的目标,除非显式地重置状态。2.确保在动作完成时正确设置状态,并防止在完成状态后意外激活。3.在动作服务器代码中添加状态检查,避免非法的状态转换。参考引用[2]中的代码片段,我们看到在抢断回调(preemptCb)中,他们调用了`group_->stop()`和`server.setPreempted()`。这确保了当抢断发生时,动作服务器会正确地设置状态为被抢断(preempted),并停止执行。针对用户的问题,我们可能需要类似的处理:在动作完成(无论是成功、失败还是抢断)后,确保状态机不会被错误地转移到活跃状态。具体步骤可能包括:-在动作服务器的目标回调(goalcallback)中,检查当前状态。如果当前状态已经是完成状态(DONE),那么应该拒绝新的目标,或者重置状态机后再接受新目标。-确保在完成状态后,动作服务器不会保留任何活跃的目标。由于用户没有提供具体的代码,我们只能给出一般性的建议。以下是一个示例代码片段,展示如何在动作服务器的目标回调中检查状态:```cppvoidgoalCallback(Server&server,Server::GoalHandle&gh){//如果当前已经有活跃的目标,或者服务器处于完成状态,则拒绝新目标if(server.isActive()||server.isPreemptRequested()||isDoneState()){//拒绝目标,并说明原因gh.setRejected("Actionserverisnotinastatetoacceptnewgoals");return;}//否则接受目标并开始处理gh.setAccepted();//...开始处理目标}```另外,在动作完成时(例如在结果回调中),应该确保将状态设置为完成,并清除活跃目标。由于用户提到状态转换是从SimpleGoalState[DONE]到CommState[ACTIVE],这可能意味着在动作已经完成后,又错误地激活了同一个目标。因此,我们还需要确保在动作完成时,将当前目标句柄重置。在ROSactionlib中,当动作完成时,我们需要调用目标句柄的`setSucceeded`、`setAborted`或`setPreempted`来设置最终状态。一旦调用了这些方法,该目标句柄就不再活跃。所以问题可能是在设置完成状态后又错误地激活了同一个目标句柄。因此,检查代码中是否在设置完成状态后,又错误地对同一个目标句柄调用了`setActive()`(这通常是不必要的,因为目标被接受时会自动激活)。总结解决方案:1.在动作服务器中,确保每个目标在完成后(通过`setSucceeded`、`setAborted`或`setPreempted`)不会再次被激活。2.在接收新目标时,检查当前状态,如果服务器尚未准备好(例如,当前有活跃目标或处于完成状态),则拒绝新目标。3.检查状态转换逻辑,确保没有从完成状态到活跃状态的非法转换。如果用户能提供更多代码细节,我们可以给出更具体的建议。相关问题:1.如何正确实现ROSactionlib的状态机?2.在ROS中,如何拒绝一个动作目标?3.动作服务器在完成一个目标后,如何重置以接受新目标?4.ROSactionlib中常见的状态转换错误有哪些?</think>### ROS中从SimpleGoalState [DONE]转换到CommState [ACTIVE]的BUG解决方案 该问题通常发生在ROS actionlib状态机管理异常时,本质是状态转换逻辑违反FSM(有限状态机)规则。以下是系统级解决方案: #### 核心修复方案 1. **状态机完整性检查** 在动作服务器回调中强制校验状态转换合法性: ```cpp void transitionCallback() { if (current_state_ == actionlib::SimpleGoalState::DONE) { ROS_WARN("Illegal transition from DONE to ACTIVE"); return; // 阻止非法状态转换 } // 正常状态转换逻辑 } ``` 2. **资源释放后重置** 在设置DONE状态后立即释放资源并重置状态机: ```cpp void setDoneState() { current_state_ = actionlib::SimpleGoalState::DONE; active_goal_.reset(); // 关键:释放目标句柄 server_.setSucceeded(result_); } ``` 3. **抢占处理强化** 在抢占回调中显式终止状态迁移: ```cpp void preemptCB() { if (server_.isActive()) { server_.setPreempted(); // 正确设置抢占状态 is_active_ = false; // 标志位重置 } } ``` #### 根本原因分析 该BUG通常由以下原因触发: - **目标句柄未释放**:DONE状态后未清除`active_goal_`对象[^1] - **状态机竞争条件**:新目标到达时旧目标仍在清理中 - **回调时序问题**:`setSucceeded()`与`setActive()`调用时序冲突 #### 验证方法 使用`rqt_graph`监控状态转换: ```bash rosrun rqt_graph rqt_graph rosrun actionlib_tools axclient.py /your_action_name ``` 观察状态转换时序是否符合: $$ \text{ACTIVE} \rightarrow \text{SUCCEEDED/ABORTED} \rightarrow \text{DONE} $$ > **重要提示**:若使用MoveIt!等框架,需检查`controller_manager`插件版本,已知v0.2.5存在类似状态机缺陷[^2]。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值