spark streaming kafka OffsetOutOfRangeException 异常分析与解决

在将Spark从1.3升级到1.6后,遇到Kafka Streaming的OffsetOutOfRangeException异常。此异常通常发生在Zookeeper中保存的offset超出Kafka topic的范围。文章分析了异常可能是由于Kafka Broker清理了旧数据,导致offset无效。解决方案包括及时消费数据以避免延迟超过log.retention.hours,以及在异常发生时自动矫正Zookeeper中的offset。
摘要由CSDN通过智能技术生成

spark streaming kafka OffsetOutOfRangeException 异常分析与解决

自从把spark 从1.3升级到1.6之后,kafka Streaming相关问题频出。最近又遇到了一个。
job中使用Kafka DirectStream 读取topic中数据,然后做处理。其中有个测试job,停止了几天,再次启动时爆出了kafka.common.OffsetOutOfRangeException。下文记录下异常分析与解决过程。

异常分析

从字面意思上,说是kafka topic的offset越界异常;在job中使用的是Kafka DirectStream,每成功处理一批数据,就把对应的offset更新到zookeeper中;和数组越界异常一样,offset越界应该分为头越界尾越界,如下图所示。
越界示意图

  • 头部越界: zookeeper中保存的offset在topic中仍然存在的最老message的offset之前时(zk_offset < earliest_offset);
  • 尾部越界: zookeeper中保存的offset在topic中最新message的offset之后时(zk_offset > last_offset)

因为代码中采用了之前文章的方法,因此不可能是尾部越界,因此猜测是头部越界。
是什么导致头部越界呢?
考虑到kafka broker配置中修改了message的保持时间为24小时:

log.retention.hours=24(The minimum age of a log file to be eligible for deletion)

因此,应该是kafka 中未被消费的数据被broker清除了,使得zk中的offset落在仍存在的最老message offset的左侧,本来合法的offset变得不非法了。

验证猜测

  1. 改kafka broker 的retention time 为2分钟
    配置文件
    kafka/config/server.properties
    log.retention.hours=168 -> log.retention.minutes=2
    修改完成后重启kafka。
  2. 使用zk shell 命令得到解析器所保存的zk_offset
  3. 停止spark streaming kafka DirectStream job
  4. 发送数据到kafka topic,等待一段时间(超过两分钟)
  5. 启动streaming job,复现该异常。

通过异常验证可以导致异常的原因为:kafka broker因为log.retention.hours的配置,导致topic中有些数据被清除,而在retention时间范围内streaming job都没有把将要被清除的message消费掉,因此zk中offset落在了earliest_offset的左侧,引发异常。

解决方法

首先想到的方法就是 streaming job要及时消费掉topic中的数据,消费延迟不得大于log.retention.time的配置。
但是更好的办法是在遇到该问题时,依然能让job正常运行,因此就需要在发现zk_offset<earliest_offset时矫正zk_offset为合法值。
同样使用Spark Streaming ‘numRecords must not be negative’问题解决,解决思路的方法。
代码:

package com.frey.v1.utils.kafka;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import kafka.api.PartitionOffsetRequestInfo;
import kafka.cluster.Broker;
import kafka.common.TopicAndPartition;
import kafka.javaapi.*;
import kafka.javaapi.consumer.SimpleConsumer;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * KafkaOffsetTool
 *
 * @author FREY
 * @date 2016/4/11
 */
public class KafkaOffsetTool {
   </
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值