Google cloud dataflow Google Dataflow Python Apache波束窗口延迟问题
我有一个简单的管道,它从PubSub接收数据,打印数据,然后每隔10秒在GroupByKey中启动一个窗口,然后再次打印该消息 然而,这个窗口似乎有时会延迟。这是谷歌的限制还是我的代码有问题:Google cloud dataflow Google Dataflow Python Apache波束窗口延迟问题,google-cloud-dataflow,apache-beam,Google Cloud Dataflow,Apache Beam,我有一个简单的管道,它从PubSub接收数据,打印数据,然后每隔10秒在GroupByKey中启动一个窗口,然后再次打印该消息 然而,这个窗口似乎有时会延迟。这是谷歌的限制还是我的代码有问题: with beam.Pipeline(options=pipeline_options) as pipe: messages = ( pipe | beam.io.ReadFromPubSub(subscription=known_args
with beam.Pipeline(options=pipeline_options) as pipe:
messages = (
pipe
| beam.io.ReadFromPubSub(subscription=known_args.input_subscription).with_output_types(bytes)
| 'decode' >> beam.Map(lambda x: x.decode('utf-8'))
| 'Ex' >> beam.ParDo(ExtractorAndPrinter())
| beam.WindowInto(window.FixedWindows(10), allowed_lateness=0, accumulation_mode=AccumulationMode.DISCARDING, trigger=AfterProcessingTime(10) )
| 'group' >> beam.GroupByKey()
| 'PRINTER' >> beam.ParDo(PrinterWorker()))
编辑最新的代码。我已删除触发器,但问题仍然存在:
class ExtractorAndCounter(beam.DoFn):
def __init__(self):
beam.DoFn.__init__(self)
def process(self, element, *args, **kwargs):
import logging
logging.info(element)
return [("Message", json.loads(element)["Message"])]
class PrinterWorker(beam.DoFn):
def __init__(self):
beam.DoFn.__init__(self)
def process(self, element, *args, **kwargs):
import logging
logging.info(element)
return [str(element)]
class DefineTimestamp(beam.DoFn):
def process(self, element, *args, **kwargs):
from datetime import datetime
return [(str(datetime.now()), element)]
def run(argv=None, save_main_session=True):
"""Build and run the pipeline."""
parser = argparse.ArgumentParser()
parser.add_argument(
'--output_topic',
required=True,
help=(
'Output PubSub topic of the form '
'"projects/<PROJECT>/topics/<TOPIC>".'))
group = parser.add_mutually_exclusive_group(required=True)
group.add_argument(
'--input_topic',
help=(
'Input PubSub topic of the form '
'"projects/<PROJECT>/topics/<TOPIC>".'))
group.add_argument(
'--input_subscription',
help=(
'Input PubSub subscription of the form '
'"projects/<PROJECT>/subscriptions/<SUBSCRIPTION>."'))
known_args, pipeline_args = parser.parse_known_args(argv)
pipeline_options = PipelineOptions(pipeline_args)
pipeline_options.view_as(SetupOptions).save_main_session = save_main_session
pipeline_options.view_as(StandardOptions).streaming = True
with beam.Pipeline(options=pipeline_options) as pipe:
messages = (
pipe
| beam.io.ReadFromPubSub(subscription=known_args.input_subscription).with_output_types(bytes)
| 'decode' >> beam.Map(lambda x: x.decode('utf-8'))
| 'Ex' >> beam.ParDo(ExtractorAndCounter())
| beam.WindowInto(window.FixedWindows(10))
| 'group' >> beam.GroupByKey()
| 'PRINTER' >> beam.ParDo(PrinterWorker())
| 'encode' >> beam.Map(lambda x: x.encode('utf-8'))
| beam.io.WriteToPubSub(known_args.output_topic))
if __name__ == '__main__':
logging.getLogger().setLevel(logging.INFO)
run()
类提取器和计数器(beam.DoFn):
定义初始化(自):
beam.DoFn.\uuuu init\uuuuuu(自)
def流程(自身、元素、*args、**kwargs):
导入日志记录
logging.info(元素)
返回[(“Message”,json.load(元素)[“Message”])]
印刷工等级(beam.DoFn):
定义初始化(自):
beam.DoFn.\uuuu init\uuuuuu(自)
def流程(自身、元素、*args、**kwargs):
导入日志记录
logging.info(元素)
返回[str(元素)]
类别定义夯实(梁.DoFn):
def流程(自身、元素、*args、**kwargs):
从日期时间导入日期时间
return[(str(datetime.now()),元素)]
def运行(argv=None,save_main_session=True):
“”“生成并运行管道。”“”
parser=argparse.ArgumentParser()
parser.add_参数(
“--输出主题”,
必需=真,
帮助=(
“输出表单的子主题”
““项目//topics/”))
组=解析器。添加互斥组(必需=True)
group.add_参数(
“--输入主题”,
帮助=(
“输入表单的子主题”
““项目//topics/”))
group.add_参数(
“--输入订阅”,
帮助=(
'输入表单的订阅'
““项目//订阅/”))
已知参数,管道参数=解析器。解析已知参数(argv)
管道选项=管道选项(管道参数)
管道选项。查看为(设置选项)。保存主会话=保存主会话
管道选项。查看为(标准选项)。流=真
将beam.Pipeline(选项=Pipeline_选项)作为管道:
消息=(
管
|beam.io.ReadFromPubSub(订阅=已知参数输入订阅)。带有输出类型(字节)
|'decode'>>beam.Map(lambda x:x.decode('utf-8'))
|'Ex'>>beam.ParDo(提取器和计数器())
|梁.窗内(窗.固定窗(10))
|'group'>>beam.GroupByKey()
|'PRINTER'>>beam.ParDo(PrinterWorker())
|'encode'>>beam.Map(lambda x:x.encode('utf-8'))
|beam.io.WriteToPubSub(已知参数输出主题))
如果uuuu name uuuuuu='\uuuuuuu main\uuuuuuu':
logging.getLogger().setLevel(logging.INFO)
运行()
因此,这基本上要求管道将元素分组到10秒窗口,并在每个窗口收到第一个元素后10秒后触发每个窗口(并丢弃该窗口的其余数据)。那是你的意图吗
假设是这种情况,请注意触发取决于系统接收元素的时间以及每个窗口接收第一个元素的时间。也许这就是为什么你会在结果中看到一些变化
我认为,如果您需要对元素进行更一致的分组,您应该使用事件时间触发器,而不是处理时间触发器。所有触发器都基于尽力而为,这意味着它们将在指定的持续时间后某个时间触发,在这种情况下为10秒。通常,它发生在规定的时间附近,但可能会延迟几秒钟 此外,还为键+窗口设置了触发器。该窗口是从事件时间派生的。 10:30:04时的第一个GBK品脱可能是由于10:29:52时的第一个元素造成的 10:30:07的第二次GBK打印是由于10:29:56的第一个元素造成的
因此,最好打印每个元素的窗口和事件时间戳,然后将数据关联起来。这可能是一个很好的解决方案。但是,在回答第一个问题时,我们需要的是每10秒有一个触发器,它将在这10秒内接收到的所有数据分组并发送出去。我如何删除该设置?我想让它每10秒发射一次,无论我们是否有数据在其中,因为每10秒它会释放在该窗口内积累的所有数据,如果没有数据,它不会发送任何东西。我如何删除该设置?>>这不是设置,而是系统的行为。在您的管道中,数据将以大约10秒的速度发出。你是对的,如果它们不是数据或键+窗口,那么就不会发出。你是否尝试过不指定触发器?是的,我尝试过,同样的问题。你可以提供完整的代码,以便我可以尝试重现你的问题吗?@rmesteves这里的ya goI重现了你的问题,并得到了类似的结果。你能给我解释一下你到底有什么问题吗?我的意思是,哪一个耽搁事实上困扰着你?