簡體   English   中英

切換到“exactly-once”投放策略后如何避免“failed to send operations”錯誤?

[英]How to avoid "failed to send operations" errors after switching to the "exactly-once" delivery strategy?

我最近嘗試將我在 GCP Pub/Sub 中的訂閱切換為“exactly-once”交付策略。 但是,我開始在我的應用程序日志中每 30 分鍾看到約 10 次以下警告:

com.google.api.gax.rpc.InvalidArgumentException: io.grpc.StatusRuntimeException: INVALID_ARGUMENT: Some acknowledgement ids in the request were invalid. This could be because the acknowledgement ids have expired or the acknowledgement ids were malformed.
    at com.google.api.gax.rpc.ApiExceptionFactory.createException(ApiExceptionFactory.java:92)
    at com.google.api.gax.grpc.GrpcApiExceptionFactory.create(GrpcApiExceptionFactory.java:98)
    at com.google.api.gax.grpc.GrpcApiExceptionFactory.create(GrpcApiExceptionFactory.java:66)
    at com.google.api.gax.grpc.GrpcExceptionCallable$ExceptionTransformingFuture.onFailure(GrpcExceptionCallable.java:97)
    at com.google.api.core.ApiFutures$1.onFailure(ApiFutures.java:67)
    at com.google.common.util.concurrent.Futures$CallbackListener.run(Futures.java:1041)
    at com.google.common.util.concurrent.DirectExecutor.execute(DirectExecutor.java:30)
    at com.google.common.util.concurrent.AbstractFuture.executeListener(AbstractFuture.java:1215)
    at com.google.common.util.concurrent.AbstractFuture.complete(AbstractFuture.java:983)
    at com.google.common.util.concurrent.AbstractFuture.setException(AbstractFuture.java:771)
    at io.grpc.stub.ClientCalls$GrpcFuture.setException(ClientCalls.java:574)
    at io.grpc.stub.ClientCalls$UnaryStreamToFuture.onClose(ClientCalls.java:544)
    at io.grpc.PartialForwardingClientCallListener.onClose(PartialForwardingClientCallListener.java:39)
    at io.grpc.ForwardingClientCallListener.onClose(ForwardingClientCallListener.java:23)
    at io.grpc.ForwardingClientCallListener$SimpleForwardingClientCallListener.onClose(ForwardingClientCallListener.java:40)
    at com.google.api.gax.grpc.ChannelPool$ReleasingClientCall$1.onClose(ChannelPool.java:535)
    at io.grpc.internal.ClientCallImpl.closeObserver(ClientCallImpl.java:563)
    at io.grpc.internal.ClientCallImpl.access$300(ClientCallImpl.java:70)
    at io.grpc.internal.ClientCallImpl$ClientStreamListenerImpl$1StreamClosed.runInternal(ClientCallImpl.java:744)
    at io.grpc.internal.ClientCallImpl$ClientStreamListenerImpl$1StreamClosed.runInContext(ClientCallImpl.java:723)
    at io.grpc.internal.ContextRunnable.run(ContextRunnable.java:37)
    at io.grpc.internal.SerializingExecutor.run(SerializingExecutor.java:133)
    at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Unknown Source)
    at java.base/java.util.concurrent.FutureTask.run(Unknown Source)
    at java.base/java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(Unknown Source)
    at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
    at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
    at java.base/java.lang.Thread.run(Unknown Source)
Caused by: io.grpc.StatusRuntimeException: INVALID_ARGUMENT: Some acknowledgement ids in the request were invalid. This could be because the acknowledgement ids have expired or the acknowledgement ids were malformed.
    at io.grpc.Status.asRuntimeException(Status.java:535)
    ... 17 more

在同一線程中,緊跟在它們之后的是以下INFO日志消息:

Permanent error invalid ack id message, will not resend

我沒有看到這些警告引起的任何問題,但有點難以判斷,因為我的應用程序正在處理相當數量的消息(~1000 條/小時)。 我最初認為這些警告只是切換到“exactly-once”策略后的短期“余震”。 然而,我等了大約2個小時,它們一直以相同的頻率出現,沒有消失的跡象。 然后我禁用了“exactly-once”策略,之后它們立即消失了。 任何人都可以告訴我這些警告是否危險、我可以預期的副作用以及最重要的是我如何擺脫它們?

我正在使用spring-cloud-gcp-dependenciesspring-cloud-gcp-starter-pubsub 3.4.0版。 我還使用 Spring Cloud Stream 來處理傳入的消息,我依靠它來自動確認消息。

我的application.yaml文件中設置了以下配置:

spring:
  cloud:
    gcp:
      pubsub:
        subscriber:
          executor-threads: 15
          max-ack-extension-period: 23400 # 6 hours and 30 minutes
          acknowledgement-deadline: 600 # Maximum value

對於上下文:我的應用程序中的消息代表要執行的作業,它們可能需要很長時間才能完成——因此最長確認延長期為 6 小時 30 分鍾。

我還看到了以下 StackOverflow 問題: How to handle errors during message acknowledgement using google pubsub java library?

據我了解,這些警告的結果是消息將重新傳送到我的應用程序,但這正是我想要避免的。

謝謝你的問題,亞歷山大。

當對服務的 modifyAckDeadline 或 Acknowledgment 請求失敗時,您看到的錯誤會發生,因為確認 ID 已過期。 在這種情況下,服務會將過期的確認 ID 視為無效,因為更新的交付可能已經在進行中。 這是根據一次交付的保證 可能有以下幾個原因:

  • 由於網絡延遲,請求被延遲,當它到達服務器時,確認 ID 租約已經過期。
  • 發出 modifyAckDeadline 或 Acknowledgment 請求的任務不堪重負(高 CPU/memory.network 使用率),導致延遲發出這些請求。

我建議將min-duration-per-ack-extension設置為較大的數字以減少上述問題。 這將有助於減少確認 ID 租約過期的情況。 您可以為此字段設置的最大值為 600 秒。

此外,如其他堆棧溢出問題中所述,您應該考慮檢查確認操作的響應。 這可以用來指導您的應用程序,如果它可以期待重新交付。 樣品

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM