从kafka传入influxdb的数据时间戳相同,导致数据缺失问题的解决

数据接入的流程大致为:通过NiFi将数据传入kafka,再通过confluent的connector将数据从kafka传入influxdb。

由于NiFi传输数据很快,对于一些数据所产生的时间戳会出现相同的情况,类似如下:

time                      waveValue
----                      ---------
2019-04-22T13:59:28.934Z  0.6229748725891113
2019-04-22T13:59:28.934Z  0.5437749028205872
2019-04-22T13:59:28.934Z  0.21141430735588074
2019-04-22T13:59:28.934Z  0.11528569459915161

在InfluxDB中,主键是由time和tag组成的。在这里我没有tag,因此如果time相同,后面的记录将会覆盖前面的,因此实际传到InfluxDB的数据只有一条:

time                      waveValue
----                      --------- 
2019-04-22T13:59:28.934Z  0.11528569459915161

一开始我以为将时间精度提高到ns级别,应该就能解决这个问题。

由于我用的connector是confluent自带的Kafka Connect InfluxDB ,因此我去翻了下confluent的influxDB sink文档,还真的找到了设置时间精度的选项。因此,我的InfluxDBSinkConnector的配置为:

name=InfluxDBSinkConnector
connector.class=io.confluent.influxdb.InfluxDBSinkConnector
topics=test
tasks.max=1
influxdb.url=myurl
influxdb.timeunit=NANOSECONDS

但是NiFi的传输速度实在太快,数据还是存在时间戳相同的情况:

time                     	   waveValue
----                      	   ---------
2019-04-22T14:06:05.833993334Z 0.3754749000072479
2019-04-22T14:06:05.833993334Z 0.5437749028205872
2019-04-22T14:06:05.833993334Z 0.7219749093055725

因此现在只能考虑如何传入tag。但是confluent自带的InfluxDBSinkConnector功能太差劲,不能传入tag。因此找了半天,鬼使神差,找到了另外一个很强大的Influx Sink,完美的解决了问题。

Confluent安装这个connector,步骤就是直接将压缩包放到plugin.path下面,解压,然后重启Confluent。plugin.path在下面几个文件中都有出现,最好设置成相同的值:

#单机版
/path/to/confluent-5.1.0/etc/schema-registry/connect-avro-standalone.properties
/path/to/confluent-5.1.0/etc/kafka/connect-standalone.properties
#集群版
/path/to/confluent-5.1.0/etc/schema-registry/connect-avro-distributed.properties
/path/to/confluent-5.1.0/etc/kafka/connect-distributed.properties

plugin.path的值默认为share/java,那么就将下载的压缩包放到/path/to/confluent-5.1.0/share/java,解压,然后重启Confluent就安装完成了。

于是,我现在connector的配置为:

name=InfluxSinkConnector
connector.class=com.datamountaineer.streamreactor.connect.influx.InfluxSinkConnector
connect.influx.url=http://myurl
connect.influx.db=test
topics=test
tasks.max=1
connect.influx.kcql=INSERT INTO emwave SELECT * FROM emwave WITHTIMESTAMP sys_time() WITHTAG (tagnum)

在源数据那里加多一项tagnum数据,并且值进行递增取余。
在NiFi中这个递增的方法为:增加一个UpdateAttribute processor,然后设置如下图:

最终传到InfluxDB的数据如下:

time                           waveValue           tagnum
----                           ---------           ------
2019-04-22T14:45:51.297156875Z 0.3033857047557831  1
2019-04-22T14:45:51.297156875Z 0.5409857034683228  2
2019-04-22T14:45:51.297156875Z 0.4122856855392456  3

问题解决。

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
好的,下面是一个使用 Spring Boot 和 Kafka 消费指定时间戳数据的简单示例: 首先,在 pom.xml 中添加 Kafka 和 Spring Kafka 的依赖: ```xml <dependency> <groupId>org.springframework.kafka</groupId> <artifactId>spring-kafka</artifactId> <version>2.8.0</version> </dependency> <dependency> <groupId>org.apache.kafka</groupId> <artifactId>kafka-clients</artifactId> <version>2.8.0</version> </dependency> ``` 然后,在 application.properties 中配置 Kafka 的连接信息: ```properties spring.kafka.bootstrap-servers=localhost:9092 spring.kafka.consumer.group-id=my-group ``` 接下来,编写一个 Kafka 消费者,用于消费指定时间戳之后的消息。示例代码如下: ```java import org.apache.kafka.clients.consumer.ConsumerRecord; import org.apache.kafka.clients.consumer.ConsumerRecords; import org.apache.kafka.clients.consumer.KafkaConsumer; import org.apache.kafka.common.TopicPartition; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.kafka.core.KafkaTemplate; import org.springframework.stereotype.Component; import javax.annotation.PostConstruct; import java.time.Duration; import java.util.Arrays; import java.util.Collections; import java.util.Properties; @Component public class MyKafkaConsumer { @Autowired private KafkaTemplate<String, String> kafkaTemplate; @PostConstruct public void consume() { Properties props = new Properties(); props.put("bootstrap.servers", "localhost:9092"); props.put("group.id", "my-group"); props.put("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer"); props.put("value.deserializer", "org.apache.kafka.common.serialization.StringDeserializer"); KafkaConsumer<String, String> consumer = new KafkaConsumer<>(props); TopicPartition partition = new TopicPartition("my-topic", 0); long timestamp = System.currentTimeMillis() - 3600000; // 1 hour ago consumer.assign(Collections.singletonList(partition)); consumer.seek(partition, timestamp); while (true) { ConsumerRecords<String, String> records = consumer.poll(Duration.ofMillis(100)); for (ConsumerRecord<String, String> record : records) { System.out.printf("offset = %d, key = %s, value = %s%n", record.offset(), record.key(), record.value()); } } } } ``` 在上面的示例代码中,我们使用 KafkaConsumer 类创建一个消费者,并指定要消费的主题和分区。然后,我们通过 seek() 方法设置消费者的起始偏移量为指定时间戳之后的消息。最后,我们使用 poll() 方法从 Kafka 中消费消息,并对消息进行处理。 需要注意的是,上面的示例代码是一个简单的示例,实际应用中还需要考虑一些其他的问题,比如消息的重复消费、数据的并发处理等等。 希望这个示例能够对你有所帮助!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值