[WARN] Network error when fetching messages:storm-kafka-0.8导致kafka读取数据丢失

本文深入探讨了Kafka网络错误时数据丢失的问题,通过源码分析,解释了数据丢失的原因,并提供了可能的解决方案。重点在于网络异常处理及数据一致性维护。
2015-01-09T16:17:10.090+0800 s.k.KafkaUtils [WARN] Network error when fetching messages:
java.net.ConnectException: Connection refused
        at sun.nio.ch.Net.connect0(Native Method) ~[na:1.7.0_51]
        at sun.nio.ch.Net.connect(Net.java:465) ~[na:1.7.0_51]
        at sun.nio.ch.Net.connect(Net.java:457) ~[na:1.7.0_51]
        at sun.nio.ch.SocketChannelImpl.connect(SocketChannelImpl.java:670) ~[na:1.7.0_51]
        at kafka.network.BlockingChannel.connect(BlockingChannel.scala:57) ~[stormjar.jar:na]
        at kafka.consumer.SimpleConsumer.connect(SimpleConsumer.scala:44) ~[stormjar.jar:na]
        at kafka.consumer.SimpleConsumer.reconnect(SimpleConsumer.scala:57) ~[stormjar.jar:na]
        at kafka.consumer.SimpleConsumer.liftedTree1$1(SimpleConsumer.scala:79) ~[stormjar.jar:na]
        at kafka.consumer.SimpleConsumer.kafka$consumer$SimpleConsumer$$sendRequest(SimpleConsumer.scala:71) ~[stormjar.jar:na]
        at kafka.consumer.SimpleConsumer$$anonfun$fetch$1$$anonfun$apply$mcV$sp$1.apply$mcV$sp(SimpleConsumer.scala:109) ~[stormjar.jar:na]
        at kafka.consumer.SimpleConsumer$$anonfun$fetch$1$$anonfun$apply$mcV$sp$1.apply(SimpleConsumer.scala:109) ~[stormjar.jar:na]
        at kafka.consumer.SimpleConsumer$$anonfun$fetch$1$$anonfun$apply$mcV$sp$1.apply(SimpleConsumer.scala:109) ~[stormjar.jar:na]
        at kafka.metrics.KafkaTimer.time(KafkaTimer.scala:33) ~[stormjar.jar:na]
        at kafka.consumer.SimpleConsumer$$anonfun$fetch$1.apply$mcV$sp(SimpleConsumer.scala:108) ~[stormjar.jar:na]
        at kafka.consumer.SimpleConsumer$$anonfun$fetch$1.apply(SimpleConsumer.scala:108) ~[stormjar.jar:na]
        at kafka.consumer.SimpleConsumer$$anonfun$fetch$1.apply(SimpleConsumer.scala:108) ~[stormjar.jar:na]
        at kafka.metrics.KafkaTimer.time(KafkaTimer.scala:33) ~[stormjar.jar:na]
                                                                                 


 2015-01-09T16:17:10.091+0800 s.k.KafkaSpout [WARN] Fetch failed
storm.kafka.FailedFetchException: java.net.ConnectException: Connection refused
        at storm.kafka.KafkaUtils.fetchMessages(KafkaUtils.java:176) ~[stormjar.jar:na]
        at storm.kafka.PartitionManager.fill(PartitionManager.java:159) ~[stormjar.jar:na]
        at storm.kafka.PartitionManager.next(PartitionManager.java:123) ~[stormjar.jar:na]
        at storm.kafka.KafkaSpout.nextTuple(KafkaSpout.java:141) ~[stormjar.jar:na]
        at backtype.storm.daemon.executor$fn__3373$fn__3388$fn__3417.invoke(executor.clj:565) [storm-core-0.9.3.jar:0.9.3]
        at backtype.storm.util$async_loop$fn__464.invoke(util.clj:463) [storm-core-0.9.3.jar:0.9.3]
        at clojure.lang.AFn.run(AFn.java:24) [clojure-1.5.1.jar:na]
        at java.lang.Thread.run(Thread.java:744) [na:1.7.0_51]

1,由于网络异常,导致数据丢失:分析源码原因:

  //returns false if it's reached the end of current batch
    public EmitState next(SpoutOutputCollector collector) {
        if (_waitingToEmit.isEmpty()) {

          //fill是fetch message的方法
            fill();
        }
        while (true) {
            MessageAndRealOffset toEmit = _waitingToEmit.pollFirst();
            if (toEmit == null) {
                return EmitState.NO_EMITTED;
            }
            Iterable<List<Object>> tups = KafkaUtils.generateTuples(_spoutConfig, toEmit.msg);
            if (tups != null) {
                for (List<Object> tup : tups) {
                    collector.emit(tup, new KafkaMessageId(_partition, toEmit.offset));
                }
                break;
            } else {
                ack(toEmit.offset);
            }
        }
        if (!_waitingToEmit.isEmpty()) {
            return EmitState.EMITTED_MORE_LEFT;
        } else {
            return EmitState.EMITTED_END;
        }
    }


2,进入fill方法:

 private void fill() {
        long start = System.nanoTime();
        long offset;
        final boolean had_failed = !failed.isEmpty();

        // Are there failed tuples? If so, fetch those first.
        if (had_failed) {
            offset = failed.first();
        } else {
            offset = _emittedToOffset;
        }

        ByteBufferMessageSet msgs = KafkaUtils.fetchMessages(_spoutConfig, _consumer, _partition, offset);

从上面的代码中看出,由于偏移量
emittedToOffset已经复制给offset,所以<pre name="code" class="java">fetchMessages异常的时候,下次读数据就从<pre name="code" class="java">emittedToOffset开始读取,所以导致数据丢失






WARN [Consumer clientId=consumer-1, groupId=console-consumer-22925] Error while fetching metadata with correlation id 68514 : {TCP_1111=UNKNOWN_TOPIC_OR_PARTITION} (org.apache.kafka.clients.NetworkClient) 的翻译如下: 消费者客户端标识为 consumer-1,消费者组标识为 console-consumer-22925 的警告:在获取元数据时发生错误,关联 ID 为 68514。错误信息指出主题 TCP_1111 不存在或对应分区不可用(org.apache.kafka.clients.NetworkClient)[^1]。 ### 错误分析 该日志表明消费者尝试从 Kafka 集群获取主题 `TCP_1111` 的元数据信息时失败,因为该主题不存在或者未被正确识别。Kafka 客户端会通过元数据请求与 Broker 通信以了解主题的分区分布和 Leader 信息,如果目标主题尚未创建或名称拼写有误,则返回 `UNKNOWN_TOPIC_OR_PARTITION` 错误。 此类问题可能由多种原因引起: - 消费者命令中指定的主题名称存在拼写错误。 - Kafka 集群中尚未创建该主题。 - Kafka Broker 或 Zookeeper 存在网络连接问题,导致元数据同步失败。 可以通过以下方式排查并解决此问题: #### 确认主题是否存在 使用 `kafka-topics.sh` 工具列出 Kafka 集群中的所有主题,检查目标主题是否已经创建: ```bash bin/kafka-topics.sh --zookeeper <zk_host>:2181 --list ``` 若主题不在列表中,则需要先创建它: ```bash bin/kafka-topics.sh --create --topic TCP_1111 --partitions 3 --replication-factor 1 --zookeeper localhost:2181 --config "min.insync.replicas=2" ``` #### 核对消费者命令配置 确保控制台消费者命令中使用的 `--bootstrap-server` 参数指向正确的 Kafka Broker 地址,并且主题名称拼写无误: ```bash bin/kafka-console-consumer.sh --bootstrap-server bsa29:9092,bsa28:9092 --topic TCP_1111 --from-beginning ``` 此外,可以添加 `--from-beginning` 参数,从最早的消息开始读取,避免因偏移量问题导致的数据不可见情况。 #### 查看主题详细信息 使用 `kafka-topics.sh` 的 `--describe` 功能,检查目标主题的分区数、副本因子等信息是否符合预期: ```bash bin/kafka-topics.sh --zookeeper <zk_host>:2181 --describe --topic TCP_1111 ``` 若输出为空或提示主题不存在,则说明该主题尚未创建或存在配置问题。 #### 调整消费者的元数据刷新策略 在某些情况下,消费者可能因为未能及时更新元数据而导致错误。可以在消费者配置中增加元数据刷新间隔,例如设置 `metadata.max.age.ms=30000`,以提高元数据同步频率。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值