繁体   English   中英

Google Cloud PubSub无法确认消息

[英]Google Cloud PubSub not ack messages

我们拥有基于GCP PubSub的发布者和订阅者系统。 订户处理单个消息的时间很长,大约1分钟。 我们已经将订户确认截止时间设置为600秒(10分钟)(最大),以确保pubsub不会太早开始重新交付,因为基本上我们在这里运行时间很长。

我看到了PubSub的这种行为。 当代码发送确认和监视器确认PubSub确认请求已被接受并且确认本身以成功状态完成时,未确认消息的总数仍然相同。

在此处输入图片说明

图表上的指标显示的总和,均值和均值聚合对齐器均相同。 在上面的图片中,对齐器是平均的,没有启用减速器。

我正在使用@ google-cloud / pubsub Node.js库。 已经尝试了不同的版本(0.18.1、0.22.2、0.24.1),但是我想问题不在其中。

以下类可用于检查。

TypeScript 3.1.1,节点8.xx-10.xx

import { exponential, Backoff } from "backoff";

const pubsub = require("@google-cloud/pubsub");

export interface IMessageHandler {
    handle (message): Promise<void>;
}

export class PubSubSyncListener {
    private readonly client;

    private listener: Backoff;

    private runningOperations: Promise<unknown>[] = [];

    constructor (
        private readonly handler: IMessageHandler,
        private readonly options: {
            /**
             * Maximal messages number to be processed simultaniosly.
             * Listener will try to keep processing number as close to provided value
             * as possible.
             */
            maxMessages: number;
            /**
             * Formatted full subscrption name /projects/{projectName}/subscriptions/{subscriptionName}
             */
            subscriptionName: string;
            /**
             * In milliseconds
             */
            minimalListenTimeout?: number;
            /**
             * In milliseconds
             */
            maximalListenTimeout?: number;
        }
    ) {
        this.client = new pubsub.v1.SubscriberClient();

        this.options = Object.assign({
            minimalListenTimeout: 300,
            maximalListenTimeout: 30000
        }, this.options);
    }

    public async listen () {
        this.listener = exponential({
            maxDelay: this.options.maximalListenTimeout,
            initialDelay: this.options.minimalListenTimeout
        });

        this.listener.on("ready", async () => {
            if (this.runningOperations.length < this.options.maxMessages) {
                const [response] = await this.client.pull({
                    subscription: this.options.subscriptionName,
                    maxMessages: this.options.maxMessages - this.runningOperations.length
                });

                for (const m of response.receivedMessages) {
                    this.startMessageProcessing(m);
                }
                this.listener.reset();
                this.listener.backoff();
            } else {
                this.listener.backoff();
            }
        });

        this.listener.backoff();
    }

    private startMessageProcessing (message) {
        const index = this.runningOperations.length;

        const removeFromRunning = () => {
            this.runningOperations.splice(index, 1);
        };

        this.runningOperations.push(
            this.handler.handle(this.getHandlerMessage(message))
                .then(removeFromRunning, removeFromRunning)
        );
    }

    private getHandlerMessage (message) {
        message.message.ack = async () => {
            const ackRequest = {
                subscription: this.options.subscriptionName,
                ackIds: [message.ackId]
            };

            await this.client.acknowledge(ackRequest);
        };

        return message.message;
    }

    public async stop () {
        this.listener.reset();
        this.listener = null;
        await Promise.all(
            this.runningOperations
        );
    }
}

这基本上是消息的异步提取和立即确认的部分实现。 因为提出的解决方案之一是使用同步拉动。

如果我没有记错问题的症状,那么我在Java存储库中发现了类似的报告问题。

https://github.com/googleapis/google-cloud-java/issues/3567

这里的最后一个细节是,确认似乎对少量请求有效。 如果我在pubsub中触发单个消息然后立即对其进行处理,则未传递的消息数会减少(由于之前只有一条消息而下降为0)。

问题本身-发生了什么?为什么收到确认消息后未确认消息的数量没有减少?

要引用该文档 ,您正在使用的subscription / num_undelivered_messages指标是“订阅中未确认的消息(即积压消息)的数量。 每60秒采样一次采样后,最多120秒不可见数据。

您不应期望此指标在确认消息后立即下降。 此外,听起来好像您正试图将pubsub用于恰好一次的传递情况,试图确保不会再次传递该消息。 Cloud Pub / Sub不提供这些语义。 它至少提供一次语义。 换句话说,即使您已经收到一个值,确认了该值,收到了ack响应,并且看到指标从1下降到0,对于同一工人或另一个工人,仍然有可能并正确地接收到该消息的精确副本。 。 尽管在实践中这不太可能,但您应该专注于构建具有重复容忍能力的系统,而不是尝试确保确认成功,这样就不会重新传递您的消息。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM