Python Google PubSub线程安全和忽略重复消息

Python Google PubSub线程安全和忽略重复消息,python,google-cloud-platform,google-cloud-pubsub,Python,Google Cloud Platform,Google Cloud Pubsub,我正在收听谷歌云平台周一至周五发布的财务数据。我想将所有邮件保存到磁盘。我正在用Python做这件事 如果我的应用程序宕机,我需要恢复任何丢失的数据包。我知道谷歌会自动重新发送未确认的信息 GCP文档列出了许多可用的订阅技术(异步/同步、推/拉、流式拉等)。有一个异步示例代码: def callback(message): print(f"Received {message}.") message.ack() streaming_pull_future =

我正在收听谷歌云平台周一至周五发布的财务数据。我想将所有邮件保存到磁盘。我正在用Python做这件事

如果我的应用程序宕机,我需要恢复任何丢失的数据包。我知道谷歌会自动重新发送未确认的信息

GCP文档列出了许多可用的订阅技术(异步/同步、推/拉、流式拉等)。有一个异步示例代码:

def callback(message):
    print(f"Received {message}.")
    message.ack()

streaming_pull_future = subscriber.subscribe(subscription_path, callback=callback)
print(f"Listening for messages on {subscription_path}..\n")

# Wrap subscriber in a 'with' block to automatically call close() when done.
with subscriber:
    try:
        # When `timeout` is not set, result() will block indefinitely,
        # unless an exception is encountered first.
        streaming_pull_future.result(timeout=5)
    except TimeoutError:
        streaming_pull_future.cancel()

  • 回调线程是否安全/是否只有一个线程在回调
  • 忽略已收到的邮件的最佳方式是什么?客户是否需要维护地图
  • Kamal Aboul Hosn的更新

    我想我可以坚持好,但我的问题是我需要手动检查所有消息是否确实已收到。为此,我启用了订单交付。我们的消息数据包含一个序列号,所以我想添加一个全局变量,如
    next\u expected\u seq\u num
    。收到每条消息后,我将处理并确认消息,并增加
    next\u expected\u seq\u num

    但是,如果我说有10个线程调用回调方法,我假设这10个线程中的任何一个都可能包含下一条消息?我必须使我的回调方法足够智能,以阻止其他9个线程的处理,同时第10个线程处理下一条消息。比如:

    (伪代码)

    既然我正在阻止多线程处理,我应该禁用多个回调线程吗

    是否有更好的方法检查/保证我们处理每一条信息

    我想知道我们是否应该像TCP一样信任GCP,启用多线程(并锁定数据库写入)


    如果在没有全局解释器锁的Python环境中运行,则回调不是线程安全的。在这种情况下,可以并行执行多个回调,并且必须使用锁保护任何共享数据结构

    因为云发布/订阅至少有一次传递语义,所以如果您需要忽略重复的消息,那么是的,您将需要对已经接收到的消息维护某种数据结构。请注意,可以在订阅服务器重新启动时传递副本。因此,您可能需要将其作为某种持久性存储。对于这种类型的重复数据消除,Redis往往是一种流行的选择

    对于有序传递,可以保证回调一次只针对一个排序键运行一条消息。因此,您不必编程期望多条消息同时为密钥运行。请注意,通常,只有吞吐量不超过1MB/s时,使用排序键对主题中的所有消息进行完全排序才有效,因为这是具有排序键的消息的发布限制。此外,如果必须按顺序处理消息,则仅使用排序键

    至于何时使用多线程,这实际上取决于处理的性质。如果大部分回调需要用锁来保护,那么多线程将不会有多大帮助。但是,如果只有一小部分需要锁保护,例如检查重复项,而大部分处理可以安全地并行完成,那么多线程可以带来更好的性能


    如果您只想防止重复,那么您可能不需要使用锁来保护对数据库的写入,除非数据库不能保证一致性。另外,请记住,锁定仅在您有一个订户客户端时才有用。

    如果您在没有全局解释器锁定的Python环境中运行,则回调不是线程安全的。在这种情况下,可以并行执行多个回调,并且必须使用锁保护任何共享数据结构

    因为云发布/订阅至少有一次传递语义,所以如果您需要忽略重复的消息,那么是的,您将需要对已经接收到的消息维护某种数据结构。请注意,可以在订阅服务器重新启动时传递副本。因此,您可能需要将其作为某种持久性存储。对于这种类型的重复数据消除,Redis往往是一种流行的选择

    对于有序传递,可以保证回调一次只针对一个排序键运行一条消息。因此,您不必编程期望多条消息同时为密钥运行。请注意,通常,只有吞吐量不超过1MB/s时,使用排序键对主题中的所有消息进行完全排序才有效,因为这是具有排序键的消息的发布限制。此外,如果必须按顺序处理消息,则仅使用排序键

    至于何时使用多线程,这实际上取决于处理的性质。如果大部分回调需要用锁来保护,那么多线程将不会有多大帮助。但是,如果只有一小部分需要锁保护,例如检查重复项,而大部分处理可以安全地并行完成,那么多线程可以带来更好的性能


    如果您只想防止重复,那么您可能不需要使用锁来保护对数据库的写入,除非数据库不能保证一致性。另外,请记住,锁定仅在您有一个订户客户端时才有帮助。

    是否有用于持久保存接收到的数据的内置功能?我没有做任何超乎寻常的事情,因此如果这种行为在某个地方不存在,我会感到惊讶。Pub/Sub客户端库中没有内置任何东西,云Pub/Sub也没有为此提供任何东西。这将非常困难,因为它本质上需要打开另一个数据库或服务来持久化这些ACK。我们知道有兴趣一次交货,而且
    def callback(msg)
    {
        seq_num = getSeqNum(msg.data);
    
        while(seq_num != next_expected_seq_num); // Make atomic
    
        // When we reach here, we have the next message
        assert(db.exists(seq_num) == false);
        
        // persist message
        
        ++next_expected_seq_num;       // make atomic/cannot be earlier
    
        msg.ack();
    }
    
    def callback(msg)
    {
        seq_num = getSeqNum(msg.data);
    
        lock();
    
        if(db.exists(seq_num) == false)
        {
            // persist message
        }
    
        unlock();
    
        msg.ack();
    }