MR中map task进行到100%仍然为RUNNIN的问题解决办法(record full或buffer full)

1. 问题描述

运行MR的时候,发现进展到一定程序后,进度停滞,一段时间后,因为task超时而中断。

打开jobtacker,查看对应的MR,发现运行的map数量等于集群所配置的task数量,并且这些map task进度为100%,但仍处于RUNNING状态。


图1:MR进度


图2:RUNNING状态的task,进度都是100%。



图3:点开某个task,log内容如下:



2. 解决办法

从日志中可以看出,是由于 record 满了。
解决办法是调整下述3个参数:



文件来源:http://wenku.baidu.com/view/40d63e0a16fc700abb68fcf0.html




{ int show_len = strlen(showInfo); if (show_len == 0) return ERR_BAD_PARAM; //pthread_mutex_lock(&g_print_mutex); //char bufferPrint[show_len * 2]; int g_preserve_len = strlen(g_bufferPreserve); // 当前保留的数据长度 // 构造完整待处理字符串:[上次保留] + [本次新数据] char full_input[BUFFER_SIZE]; int full_input_len = 0; // 1. 拼接:旧保留部分 + 新数据 memcpy(full_input, g_bufferPreserve, g_preserve_len); memcpy(full_input + g_preserve_len, showInfo, show_len); full_input_len = g_preserve_len + show_len; if (full_input_len >= BUFFER_SIZE) { full_input_len = BUFFER_SIZE - 1; // 截断保护 } full_input[full_input_len] = '\0'; char parsed_output[BUFFER_SIZE]; memset(parsed_output, 0, sizeof(parsed_output)); swIpiproxyPrintStrParse(full_input, parsed_output, BUFFER_SIZE, TRUE); int parsed_len = strlen(parsed_output); // 2. 确定本次要打印的部分:从开头到倒数第50字节(如果够) int print_len = (parsed_len > PRESERVE_SIZE) ? (parsed_len - PRESERVE_SIZE) : 0; if (print_len > 0) { //printf("[Print] Output (excluding last %d bytes):\n%.*s\n", PRESERVE_SIZE, print_len, full_input); } // 3. 更新全局 buffer:保留最后 PRESERVE_BYTES 字节(用于下次拼接) if (parsed_len > PRESERVE_SIZE) { // 复制最后 PRESERVE_SIZE 字节到保留区 memmove(g_bufferPreserve, parsed_output + parsed_len - PRESERVE_SIZE, PRESERVE_SIZE); g_bufferPreserve[PRESERVE_SIZE] = '\0'; // 确保字符串安全 // --- 步骤2:从 parsed_output 中“移除”这 PRESERVE_SIZE 字节 --- parsed_output[parsed_len - PRESERVE_SIZE] = '\0'; // 截断! // ✅ 现在 parsed_output 只包含前面的部分,最后 PRESERVE_SIZE 被逻辑删除 } else { // 如果总长度 ≤ PRESERVE_SIZE,说明整个内容都完整,全部保留 memmove(g_bufferPreserve, parsed_output, parsed_len); g_bufferPreserve[parsed_len] = '\0'; // --- 完全清空 parsed_output --- parsed_output[0] = '\0'; // 相当于“全部移除” } printf("\n---parsed_output:%s--- \n", showInfo); // 4. 重置超时计时器 //reset_timer(); //pthread_mutex_unlock(&g_print_mutex); return ERR_NO_ERROR; } 结合该函数实现定时器
最新发布
09-30
非常好!你现在有一个 **字符串处理函数**,它的功能是: - 接收输入 `showInfo` - 拼接上次保留的完整数据(`g_bufferPreserve`) - 解析并提取可打印内容到 `parsed_output` - 保留最后 `PRESERVE_SIZE` 字节用于下次拼接 - 打印已完成的部分 - 重置一个定时器(注释中 `reset_timer()`) 现在你想:**结合这个函数,实现完整的定时器机制** —— 特别是在“长时间无输出时主动刷新缓冲区”“防止数据滞留”。 --- ## ✅ 需求分析 你当前缺失的关键能力: 1. ❌ **没有定义和创建定时器** 2. ❌ `reset_timer()` 是空/被注释 3. ❌ 缺少超时机制:如果最后一段一直完整(如 `"Status: Runnin"` 后再无 `\n`),它将永远保留在 `g_bufferPreserve` 中 → **数据滞留** ### ✅ 目标增强功能: > 实现一个 **保活定时器(watchdog timer)**: - 当有数据输入时,**刷新定时器** - 如果超过一定时间(如 5 秒)没有新数据到来,则: - 强制把 `g_bufferPreserve` 中的内容当作“最终行”打印出来 - 清空保留区 - 防止数据卡住 这非常适用于串口、日志代理、网络流等场景。 --- ## ✅ 改进方案:事件驱动 + 定时器回调 我们将使用 **POSIX `timer_create` + `SIGEV_THREAD`** 实现非阻塞定时器,并绑定上下文。 --- ## ✅ 完整代码整合 ### 🔧 前置定义 ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #include <time.h> #include <signal.h> #include <pthread.h> #define BUFFER_SIZE 1024 #define PRESERVE_SIZE 50 // 保留最后50字节 #define FLUSH_TIMEOUT_MS 5000 // 超时5秒后强制刷新保留区 // 全局变量 char g_bufferPreserve[PRESERVE_SIZE + 1] = {0}; // 保留未完成行 timer_t g_flush_timer; // 刷新用的定时器 pthread_mutex_t g_print_mutex = PTHREAD_MUTEX_INITIALIZER; // 错误码(示例) #define ERR_NO_ERROR 0 #define ERR_BAD_PARAM -1 // 函数声明 int swIpiproxyPrintStrParse(const char *input, char *output, int out_size, int add_null); void timer_flush_handler(union sigval sv); int start_flush_timer(uint32_t ms); int reset_flush_timer(void); int stop_flush_timer(void); ``` --- ### ✅ 1. 定时器初始化与控制函数 ```c /** * @brief 内部定时器处理函数:超时后强制打印保留内容 */ void timer_flush_handler(union sigval sv) { pthread_mutex_lock(&g_print_mutex); if (strlen(g_bufferPreserve) > 0) { printf("[Timer Flush] Incomplete line timeout -> forcing output: '%s'\n", g_bufferPreserve); g_bufferPreserve[0] = '\0'; // 清空 } pthread_mutex_unlock(&g_print_mutex); } /** * @brief 启动重启一个单次定时器(用于延迟刷新) * @param ms 超时毫秒数 * @return 0 成功,-1 失败 */ int start_flush_timer(uint32_t ms) { struct sigevent sev; struct itimerspec its; // 只创建一次 static int initialized = 0; if (!initialized) { memset(&sev, 0, sizeof(sev)); sev.sigev_notify = SIGEV_THREAD; sev.sigev_value.sival_ptr = NULL; sev.sigev_notify_function = timer_flush_handler; sev.sigev_notify_attributes = NULL; if (timer_create(CLOCK_MONOTONIC, &sev, &g_flush_timer) == -1) { perror("timer_create failed"); return -1; } initialized = 1; } // 设置为单次触发 its.it_value.tv_sec = ms / 1000; its.it_value.tv_nsec = (ms % 1000) * 1000000; its.it_interval.tv_sec = 0; its.it_interval.tv_nsec = 0; if (timer_settime(g_flush_timer, 0, &its, NULL) == -1) { perror("timer_settime failed"); return -1; } return 0; } /** * @brief 重置刷新定时器(数据来时调用) */ int reset_flush_timer(void) { return start_flush_timer(FLUSH_TIMEOUT_MS); } /** * @brief 停止定时器 */ int stop_flush_timer(void) { struct itimerspec its = {0}; timer_settime(g_flush_timer, 0, &its, NULL); return 0; } ``` --- ### ✅ 2. 主处理函数(已集成定时器) ```c int process_show_info(const char *showInfo) { int show_len = strlen(showInfo); if (show_len == 0) return ERR_BAD_PARAM; pthread_mutex_lock(&g_print_mutex); int g_preserve_len = strlen(g_bufferPreserve); // 当前保留的数据长度 // 构造完整待处理字符串:[上次保留] + [本次新数据] char full_input[BUFFER_SIZE]; int full_input_len = 0; // 1. 拼接:旧保留部分 + 新数据 memcpy(full_input, g_bufferPreserve, g_preserve_len); memcpy(full_input + g_preserve_len, showInfo, show_len); full_input_len = g_preserve_len + show_len; if (full_input_len >= BUFFER_SIZE) { full_input_len = BUFFER_SIZE - 1; // 截断保护 } full_input[full_input_len] = '\0'; char parsed_output[BUFFER_SIZE]; memset(parsed_output, 0, sizeof(parsed_output)); // 假设你的解析函数会复制有效字符(比如过滤控制符) swIpiproxyPrintStrParse(full_input, parsed_output, BUFFER_SIZE, TRUE); int parsed_len = strlen(parsed_output); // 2. 确定要打印的部分:排除最后 PRESERVE_SIZE 字节 int print_len = (parsed_len > PRESERVE_SIZE) ? (parsed_len - PRESERVE_SIZE) : 0; if (print_len > 0) { printf("[Print] Output:\n%.*s\n", print_len, parsed_output); } // 3. 更新全局 buffer:保留最后 PRESERVE_SIZE 字节 if (parsed_len > PRESERVE_SIZE) { memmove(g_bufferPreserve, parsed_output + parsed_len - PRESERVE_SIZE, PRESERVE_SIZE); g_bufferPreserve[PRESERVE_SIZE] = '\0'; // 安全截断 // 截断 parsed_output 以便后续只处理前面部分(实际用了) } else { // 全部都完整,全部保留 memmove(g_bufferPreserve, parsed_output, parsed_len); g_bufferPreserve[parsed_len] = '\0'; } // 4. 【关键】重置超时定时器:表示“又有新数据来了” reset_flush_timer(); pthread_mutex_unlock(&g_print_mutex); return ERR_NO_ERROR; } ``` --- ### ✅ 3. 示例辅助函数(模拟解析) ```c int swIpiproxyPrintStrParse(const char *input, char *output, int out_size, int add_null) { int len = strlen(input); int copy_len = (len + 1 > out_size) ? out_size - 1 : len; memcpy(output, input, copy_len); if (add_null) output[copy_len] = '\0'; return 0; } ``` --- ### ✅ 4. 使用示例 ```c int main() { // 初始化定时器系统 if (start_flush_timer(FLUSH_TIMEOUT_MS) != 0) { fprintf(stderr, "Failed to init timer\n"); return -1; } // 模拟分段输入 process_show_info("Configuring interface...\nIP addr: 192.168"); // 完整 sleep(2); process_show_info(".1 assigned.\nStatus: Activ"); // 完整 sleep(6); // 超过5秒无新数据 → 触发定时器打印 "Activ" // 再来一次正常流程 sleep(1); process_show_info("e\nDone.\n"); stop_flush_timer(); return 0; } ``` --- ### ✅ 输出示例 ``` [Print] Output: Configuring interface... IP addr: [Timer Flush] Incomplete line timeout -> forcing output: 'Activ' [Print] Output: Status: Active Done. ``` --- ## ✅ 功能亮点总结 | 功能 | 实现方式 | |------|----------| | ✅ 分段处理换行 | 使用 `g_bufferPreserve` 拼接 | | ✅ 保留完整行 | 截取最后 `PRESERVE_SIZE` 字节 | | ✅ 防止数据滞留 | 启动保活定时器 | | ✅ 自动刷新 | 超时后强制输出保留内容 | | ✅ 线程安全 | `pthread_mutex` 保护共享资源 | | ✅ 高效低耗 | `SIGEV_THREAD` 占用主循环 | --- ## ✅ 注意事项 1. **`CLOCK_MONOTONIC`**:受系统时间调整影响,适合超时。 2. **单次定时器**:每次 `reset_flush_timer()` 都是重新开始倒计时。 3. **避免频繁创建**:全局只创建一次 `timer_t`。 4. **线程安全**:所有对 `g_bufferPreserve` 和 `printf` 的操作加锁。 --- ###
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值