GCP PubSub-数据流-如何执行确认?

时间:2019-04-19 00:48:52

标签: kotlin google-cloud-platform google-cloud-dataflow google-cloud-pubsub

我正在尝试从PubSub订阅中读取消息,进行处理(通过使JSON扁平化以撤消某些数组),然后将它们插入具有PubsubIO和JdbcIO的Postgres和BigQuery数据库中。

问题

我在两个数据库中都看到很多重复项,我的意思是:在一天中,单个设备(我们正在从IoT设备接收数据)的操作中,有200万行中的重复项约为140K。

目标

PubsubIO收到消息后,立即执行确认。或者至少在下面的接收器中,它现在是一个简单的ParDo,可以打印消息(实际上只是消息的内存ID)

事实

通过整天检查NodeJs App Engine ingestor 中的请求正文,我们验证了设备没有发送重复的消息。 因此,我们知道问题在于,转换器没有及时确认PubSub的消息(即使最后期限在300秒内确定),因此PubSub重新插入了消息,我们再次对其进行处理。

尝试

我们的第一个流程非常简单:PubsubIO可以读取-> PTransform函数,将消息分为两个不同的PCollectionTuple.TuppleTags中的两个对象(用于Postgress和BigQuery)-> 2个并行转换器(BigQueryIO和JdbcIO)插入数据库

在第二个消息中,我们向消息添加了两个属性:时间戳记和唯一ID,以遵循我们在网上找到的许多建议以避免重复。然后我们的PubsubIO使用了 withTimestampAttribute withIdAttribute 函数。没有成功,我们添加了一个简单的ParDo来像接收器一样工作,从而强制执行了确认,但是没有成功。

管道的主要变压器:

val transform =
  pipeline
    .apply("ReadPubSubMessages",
      PubsubIO.readMessagesWithAttributes()
        .withIdAttribute("uniqueID")
        .withTimestampAttribute("timestamp")
        .fromSubscription(options.pubSubInput)
    )
    .apply("LogPubSubMessages", ParDo.of(object: DoFn<PubsubMessage, PubsubMessage>() {
      @ProcessElement
      fun processElement(context: ProcessContext) {
        LOG.info(context.element().toString())
        context.output(context.element())
      }
    }))
    .apply("ConvertMessageToTableRow&Postgres", 
DisarmPubsubMessage(tableRowMapper, postgresMapper))

来自Ingestor的一些代码:

...
const customAttributes: Publisher.Attributes = {
  device_id: validationResult.value.device_id.toString(),
  timestamp: Date.now().toString(),
  uniqueID: validationResult.value.device_id.toString() + "-" + uuidv1()
}
...
const publishReadings = async (readingRequest: ReadingRequest, customAttributes: Publisher.Attributes): Promise<any> => {
  const pubsub = PubSub()
  const payload = JSON.stringify(readingRequest)
  const dataBuffer = Buffer.from(payload)
  return pubsub
    .topic(process.env.NEW_READINGS_TOPIC as string)
    .publisher()
    .publish(dataBuffer, customAttributes)
}
...

我知道由于其他原因可能会有重复,并且拥有清除守护程序将是一个合适的解决方案,但是这里的问题是ack花费的时间太长。我看到了一些有关使用Windowing和Reshuffle的帖子,但是我不知道如何为我的案例实现它们。这些是一些帖子:

-> Google Dataflow and Pubsub - can not achieve exactly-once delivery

-> How to deduplicate messages from GCP PubSub in DataFlow using Apache Beam's PubSubIO withIdAttribute

-> Why is GroupByKey in beam pipeline duplicating elements (when run on Google Dataflow)?

谢谢!

0 个答案:

没有答案