【问题标题】:Python Google Cloud Function Connection reset by peerPython Google Cloud Function Connection 由对等方重置
【发布时间】:2019-02-07 07:45:11
【问题描述】:

详见此处:https://issuetracker.google.com/issues/113672049

在这里交叉发布:https://github.com/GoogleCloudPlatform/google-cloud-python/issues/5879)

在 Python 中使用 Google Cloud Function 中的 Firebase Storage API 时出现连接重置错误。

部署的函数正在调用一个 blob-get 即

from firebase_admin import storage

def fn(request):
  bucket = 'my-firebase-bucket'
  path = '/thing'
  blob = storage.bucket(bucket).get_blob(path)

故障是间歇性的;该功能的成功率约为 90%。

函数部署后第一次调用似乎更有可能失败。

【问题讨论】:

  • 我遇到了类似的问题。我正在使用谷歌存储。我设置了一个在文件上传到存储桶时触发的功能。我上传了 5719 个文件,处理了 5551 个文件。日志显示“连接“由对等方重置”错误。你能弄清楚如何去做吗?如果是,请分享。
  • 有些人建议设置一个计时器,或者在 ConnectionReset 上重试,但还没有人深入了解它。我感觉这是一个低级的 Python-C ConnectionPool 竞争条件,而且很难识别——但我只是猜测。 :)
  • 我还放了一个循环来完成未处理的文件。但是我注意到,如果我在不使用 gsutil 中的 -m 选项的情况下传输文件(到云存储),我不会再收到该错误。另外,他们提到 Python 是 beta 而 NodeJS 不是,所以我们可以期待随着时间的推移会变得更好。

标签: python google-cloud-storage google-cloud-functions firebase-storage


【解决方案1】:

您可能想检查您正在创建的客户端数量。

尝试跨函数调用重用网络连接,如 在优化网络中描述。但是,请注意,连接 2分钟未使用的可能会被系统关闭,并且 进一步尝试使用关闭的连接将导致 “连接重置”错误。您的代码应该使用一个库 很好地处理关闭的连接,或者在使用时显式处理它们 低级网络结构。

https://cloud.google.com/functions/docs/concepts/exec#network

查看这个示例,他们只创建一次客户端并在函数中重用它:

import os
from google.cloud import pubsub_v1

# Create a global Pub/Sub client to avoid unneeded network activity
pubsub = pubsub_v1.PublisherClient()


def gcp_api_call(request):
    """
    HTTP Cloud Function that uses a cached client library instance to
    reduce the number of connections required per function invocation.
    Args:
        request (flask.Request): The request object.
    Returns:
        The response text, or any set of values that can be turned into a
        Response object using `make_response`
        <http://flask.pocoo.org/docs/1.0/api/#flask.Flask.make_response>.
    """

    project = os.getenv('GCP_PROJECT')
    request_json = request.get_json()

    topic_name = request_json['topic']
    topic_path = pubsub.topic_path(project, topic_name)

    # Process the request
    data = 'Test message'.encode('utf-8')
    pubsub.publish(topic_path, data=data)

    return '1 message published'

https://cloud.google.com/functions/docs/bestpractices/networking#accessing_google_apis

【讨论】:

    【解决方案2】:

    云函数是无状态的,但可以重用之前调用的全局状态。这在tipsthese docs 中有解释。

    使用带重试的全局状态应该会给你一个更强大的功能:

    from tenacity import retry, stop_after_attempt, wait_random
    from firebase_admin import storage
    
    @retry(stop=stop_after_attempt(3), wait=wait_random(min=1, max=2))
    def get_bucket(storage):
        return storage.bucket('my-firebase-bucket')
    
    @retry(stop=stop_after_attempt(3), wait=wait_random(min=1, max=2))
    def get_blob(bucket, path):
        return bucket.get_blob(path)
    
    bucket = get_bucket(storage)
    
    def fn(request):
      path = '/thing'
      blob = get_blob(bucket, path)
      # etc..
    

    【讨论】:

    • 谢谢蒂姆。这是一个很好的建议,对于任何徘徊于此的人来说,都应该是最佳实践。我会将此作为问题的答案,因为真正的答案似乎是诸如此类的变通方法,因为问题的根源在 Google Cloud 的内部很深。
    • +1 - 只是想补充一点,“重试”似乎没有维护,但问题页面指向一个最近活跃的名为“tenacity”的分支:github.com/rholder/retrying/issues/65
    • 谢谢@favq 我更新了答案以使用tenacity
    • from google.api_core import retry实现这个会更一致吗?
    • 我已经尝试使用 google.api_core.retry 但我仍然遇到错误。 github.com/googleapis/google-cloud-python/issues/…
    猜你喜欢
    • 2019-02-14
    • 2019-12-07
    • 1970-01-01
    • 2019-11-10
    • 1970-01-01
    • 2020-03-18
    • 2019-08-20
    • 2014-01-01
    • 2019-01-08
    相关资源
    最近更新 更多