在我的场景中,我使用PubSub安排任务。这比在Google Compute Engine中的Docker容器内运行的Python脚本消耗的消息多达2.000个PubSub消息。该脚本使用PubSub消息。
每条消息的处理时间约为30秒到5分钟。因此,确认截止日期为600秒(10分钟)。
from google.cloud import pubsub_v1
from google.cloud.pubsub_v1.subscriber.message import Message
def handle_message(message: Message):
# do your stuff here (max. 600sec)
message.ack()
return
def receive_messages(project, subscription_name):
subscriber = pubsub_v1.SubscriberClient()
subscription_path = subscriber.subscription_path(project, subscription_name)
flow_control = pubsub_v1.types.FlowControl(max_messages=5)
subscription = subscriber.subscribe(subscription_path, flow_control=flow_control)
future = subscription.open(handle_message)
# Blocks the thread while messages are coming in through the stream. Any
# exceptions that crop up on the thread will be set on the future.
# The subscriber is non-blocking, so we must keep the main thread from
# exiting to allow it to process messages in the background.
try:
future.result()
except Exception as e:
# do some logging
raise
因为我正在处理这么多PubSub消息,所以{m} creating a template用于以下两种方式之一使用auto-scaling的计算引擎:
gcloud compute instance-groups managed create my-worker-group \
--zone=europe-west3-a \
--template=my-worker-template \
--size=0
gcloud beta compute instance-groups managed set-autoscaling my-worker-group \
--zone=europe-west3-a \
--max-num-replicas=50 \
--min-num-replicas=0 \
--target-cpu-utilization=0.4
gcloud beta compute instance-groups managed set-autoscaling my-worker-group \
--zone=europe-west3-a \
--max-num-replicas=50 \
--min-num-replicas=0 \
--update-stackdriver-metric=pubsub.googleapis.com/subscription/num_undelivered_messages \
--stackdriver-metric-filter="resource.type = pubsub_subscription AND resource.label.subscription_id = my-pubsub-subscription" \
--stackdriver-metric-single-instance-assignment=10
到目前为止,这么好。选项一扩展到大约8个实例,而第二个选项将启动最大实例数。现在我发现有些奇怪的事情发生了,这就是我在这里发帖的原因。也许你可以帮助我?!
消息重复:似乎每个实例中的PubSub服务(计算引擎内的docker容器内的Python脚本)读取一批消息(~10),有点像缓冲区并给出它们到我的代码。看起来所有同时旋转的实例将读取所有相同的消息(2.000的前10个),并将开始处理相同的内容。在我的日志中,我看到大多数消息由不同的机器处理3次。我期待PubSub知道某些用户是否缓冲了10条消息,以便另一个用户将缓冲10条不同的消息,而不是相同的消息。
确认截止日期:由于缓冲缓冲区末端的消息(让我们说消息8或9)必须在缓冲区中等待,直到前面的消息为止(消息1到7)已被处理。等待时间加上自己的处理时间的总和可能会超过600秒的超时。
负载平衡:由于每台计算机都会缓冲这么多消息,因此只有少数几个实例会占用负载,而其他实例则完全空闲。对于使用PubSub stackdriver指标的scaling-option 2,会发生这种情况。
人们告诉我,我需要使用Cloud SQL或其他方法实现手动同步服务,其中每个实例都指示它正在工作的消息,以便其他实例不会启动相同的操作。但我觉得这不可能是真的 - 因为那时我不知道PubSub是什么意思。
更新我找到了nice explanation by Gregor Hohpe,是2015年企业集成模式一书的合着者。实际上我的观察是错误的,但观察到的副作用是真实的。
Google Cloud Pub / Sub API实际上实现了两者 发布 - 订阅频道和竞争消费者模式。在 Cloud Pub / Sub的核心是一个经典的Publish-Subscribe Channel, 它将发布给它的单个消息发送给多个 订户。这种模式的一个优点是添加订阅者 是无副作用的,这是发布 - 订阅频道的一个原因 有时被认为比点对点更松散耦合 频道,仅向一个订户发送消息。添加 点对点渠道的消费者会导致竞争消费者 因此具有很强的副作用。
我观察到的副作用是关于每个订阅者(订阅相同订阅,点对点==竞争消费者)的消息缓冲和消息流控制。当前版本的Python Client Lib包装了PubSub REST API(和RPC)。如果使用该包装器,则无法控制:
我们观察到的副作用是:
尚未考虑的可能解决方案:
答案 0 :(得分:1)
我认为有两种主要方法可以解决这个问题。
1)不要直接推送到您的工作进程,而是推送到负载均衡器。
或
2)让你的工作流程提取请求,而不是将它们推送给工人。
请参阅
中“推送和拉送”下的“负载平衡”部分答案 1 :(得分:0)
Python客户端库有许多配置选项:https://googleapis.github.io/google-cloud-python/latest/pubsub/subscriber/api/client.html#google.cloud.pubsub_v1.subscriber.client.Client.subscribe
尤其要查看flow_control
和scheduler
。重要报价:
flow_control参数可用于控制 消息被拉出。设置相对保守 默认情况下,以防止“消息ho积”-客户出现这种情况 提取大量消息,但处理速度不够快 使其“饿死”其他邮件客户。增加这些 设置可能会导致不使用 处理时间长。
此外,您可以控制以下订阅的ack_deadline_seconds
:https://cloud.google.com/pubsub/docs/reference/rpc/google.pubsub.v1#google.pubsub.v1.Subscription