簡體   English   中英

AWS Lambda 到 SQS 的連接超時

[英]AWS Lambda connection to SQS timed out

我正在處理一項涉及在 VPC 內運行Lambda function的任務。

這個 function 應該將消息推送到SQS和 lambda 執行角色具有策略: AWSLambdaSQSQueueExecutionRoleAWSLambdaVPCAccessExecutionRole添加。

Lambda 功能:

# Create SQS client
sqs = boto3.client('sqs')

queue_url = 'https://sqs.ap-east-1a.amazonaws.com/073x08xx43xx37/xyz-queue'

# Send message to SQS queue
response = sqs.send_message(
    QueueUrl=queue_url,
    DelaySeconds=10,
    MessageAttributes={
        'Title': {
            'DataType': 'String',
            'StringValue': 'Tes1'
        },
        'Author': {
            'DataType': 'String',
            'StringValue': 'Test2'
        },
        'WeeksOn': {
            'DataType': 'Number',
            'StringValue': '1'
        }
    },
    MessageBody=(
        'Testing'
     )
)

print(response['MessageId'])

測試執行結果如下:

{
  "errorMessage": "2020-07-24T12:12:15.924Z f8e794fc-59ba-43bd-8fee-57f417fa50c9 Task timed out after 3.00 seconds"
}

我也將超時從基本設置增加到 5 秒和 10 秒。 但是錯誤不斷出現。

如果有人過去遇到過類似的問題,或者想知道如何解決這個問題,請幫助我。

提前謝謝你。

當 AWS Lambda function 配置為使用 Amazon VPC 時,它會連接到 VPC 的指定子網。 這允許 Lambda function 與 VPC 內的其他資源進行通信。 但是,它無法與 Internet 通信 這是一個問題,因為 Amazon SQS 公共終端節點位於 Internet 上,而 function 因為無法訪問 Internet 而超時。

因此,您有 3 個選項:

選項 1:不連接到 VPC

如果您的 Lambda function 不需要與 VPC 中的資源通信(例如您上面提供的簡單的 function),只需將其連接到 VPC 當 Lambda function連接到 VPC 時,它可以與 Internet 和 Amazon SQS 公共終端節點進行通信。

選項 2:使用 VPC 終端節點

VPC 終端節點提供了一種無需通過 Internet 即可訪問 AWS 服務的方法。 您將為 Amazon SQS 配置VPC 終端節點 然后,當 Lambda function 希望與 SQS 隊列連接時,它可以通過端點而不是通過 Internet 訪問 SQS。 如果 Lambda function 需要與 VPC 中的其他資源通信,這通常是一個不錯的選擇。

選項 3:使用 NAT 網關

如果 Lambda function 配置為使用私有子網,則如果已在公共子網中配置了 NAT 網關,並且私有子網的路由表指向 NAT 網關,它將能夠訪問 Internet。 這涉及額外費用,只有在需要額外的 NAT 網關時才值得。

您需要將 lambda 放置在您的 VPC 中,然后為 SQS 或 NAT 網關設置 VPC 端點,當您添加 lambda function 時,請確保將其添加到私有子網中,否則不會將其添加到私有子網中。

參考

https://docs.aws.amazon.com/lambda/latest/dg/vpc.html

https://aws.amazon.com/premiumsupport/knowledge-center/internet-access-lambda-function/

我非常確信您不能使用 SQS 端點使用 Lambda 從 VPC 中調用 SQS 隊列。 我認為這是一個錯誤,但也許 Lambda 團隊這樣做是有原因的。 在任何情況下,您都會收到消息超時。 我做了一個簡單的測試 Lambda

import json
import boto3
import socket

def lambda_handler(event, context):
    print('lambda-test SQS...')
    sqsDomain='sqs.us-west-2.amazonaws.com'
    
    addr1 = socket.gethostbyname(sqsDomain)
    print('%s=%s' %(sqsDomain, addr1))
     
    print('Creating sqs client...')
    sqs = boto3.client('sqs')
    
    print('Sending Test Message...')
    response = sqs.send_message(
            QueueUrl='https://sqs.us-west-2.amazonaws.com/1234567890/testq.fifo',
            MessageBody='Test SQS Lambda!',
            MessageGroupId='test')
            
    print('SQS send response: %s' % response)

    return {
        'statusCode': 200,
        'body': json.dumps(response)
    }

我創建了一個 VPC、子網等 - 配置 Lambda function 以訪問 VPC 中的資源 根據本教程,此示例中的 EC2 實例通過 CLI 的私有端點調用 SQS 沒有問題。

If I drop my simple Lambda above into the same VPC and subnet, with SQS publishing permissions etc. and invoke the test function it will properly resolve the IP address of the SQS endpoint within the subnet, but the call will timeout (making sure your Lambda超時超過 60 秒讓 boto 失敗)。 啟用 boto 調試日志記錄進一步確認 IP 已正確解析,並且對 SQS 的 HTTP 請求超時。

我沒有嘗試使用非 FIFO 隊列,但由於 HTTP 調用在連接請求上失敗,這無關緊要。 這一定是 Lambda 的路由問題,因為同一子網中的 EC2 可以正常工作。

我修改了我的簡單 Lambda 並添加了一個 SNS 端點並進行了同樣有效的測試。 我能說的最好的問題似乎是 SQS 特有的。

import json
import boto3
import socket

def testSqs():
    print('lambda-test SQS...')
    sqsDomain='sqs.us-west-2.amazonaws.com'
    
    addr1 = socket.gethostbyname(sqsDomain)
    print('%s=%s' %(sqsDomain, addr1))
    
    print('Creating sqs client...')
    sqs = boto3.client('sqs')
    
    print('Sending Test Message...')
    response = sqs.send_message(
            QueueUrl='https://sqs.us-west-2.amazonaws.com/1234567890/testq.fifo',
            MessageBody='Test SQS Lambda!',
            MessageGroupId='test')
            
    print('SQS send response: %s' % response)

    return {
        'statusCode': 200,
        'body': json.dumps(response)
    }
    

def testSns():
    print('lambda-test SNS...')

    print('Creating sns client...')
    sns = boto3.client('sns')
    
    print('Sending Test Message...')
    response = sns.publish(
            TopicArn='arn:aws:sns:us-west-2:1234567890:lambda-test',
            Message='Test SQS Lambda!'
            )
            
    print('SNS send response: %s' % response)

    return {
        'statusCode': 200,
        'body': json.dumps(response)
    }
    

def lambda_handler(event, context):
    #return testSqs()
    return testSns()

我認為您唯一的選擇是 NAT(根據上面的 John),將您的呼叫從本地 EC2 退回(NAT 會更簡單、更便宜、更可靠),或者在 VPC 之外使用 Lambda 代理。 其他人在類似的帖子中建議。 您還可以將 SQS 隊列訂閱到 SNS 主題(我對此進行了原型制作並且它可以工作)並以這種方式將其路由出去,但這似乎很愚蠢,除非您出於某種模糊的原因絕對必須擁有 SQS。

我切換到SNS。 我只是希望獲得更多有關 SQS 的經驗。 希望有人可以證明我錯了,但我稱之為錯誤。

如果您在 VPC 的 lambda 中使用 boto3 python 庫,並且無法通過 vpc 端點連接到 sqs 隊列,則必須在創建 sqs 客戶端時設置 endpoint_url。 問題 1900描述了這背后的背景。

解決方案如下所示(對於 us-east-1 中的 sqs vpc 端點):

sqs_client = boto3.client('sqs',
    endpoint_url='https://sqs.us-east-1.amazonaws.com')

然后像往常一樣調用 send_message 或 send_message_batch。

暫無
暫無

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

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