AWS Lambda 与 SQS 的连接超时
AWS Lambda connection to SQS timed out
我正在处理一项涉及 VPC.
内的 Lambda 函数 运行 的任务
此函数应该将消息推送到 SQS 并且 lambda 执行角色具有策略:AWSLambdaSQSQueueExecutionRole 和 AWSLambdaVPCAccessExecutionRole 已添加。
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"
}
I increased the Timeout from Basic Settings to 5 seconds & 10
seconds as well. But the error kept coming.
如果有人在过去遇到过类似的问题或者知道如何解决这个问题,请帮助我。
提前致谢。
当 AWS Lambda 函数配置为使用 Amazon VPC 时,它会连接到 VPC 的指定子网。这允许 Lambda 函数与 VPC 内的其他资源进行通信。但是,它无法与 Internet 通信。这是一个问题,因为 Amazon SQS public 端点存在于 Internet 上,并且函数超时,因为它无法连接到 Internet。
因此,您有 3 个选择:
选项 1:不连接到 VPC
如果您的 Lambda 函数不需要与 VPC 中的资源通信(例如您上面提供的简单函数),只需不要将其连接到 VPC .当 Lambda 函数未连接到 VPC 时,它可以与 Internet 和 Amazon SQS public 端点通信。
选项 2:使用 VPC 端点
VPC 端点提供了一种无需通过互联网即可访问 AWS 服务的方法。您将为 Amazon SQS 配置 VPC endpoint。然后,当 Lambda 函数希望连接 SQS 队列时,它可以通过端点而不是通过 Internet 访问 SQS。如果 Lambda 函数需要与 VPC 中的其他资源通信,这通常是一个不错的选择。
选项 3:使用 NAT 网关
如果 Lambda 函数配置为使用私有子网,并且在 public 子网 中配置了 NAT 网关,它将能够访问 Internet私有子网的路由 Table 指向 NAT 网关。这涉及额外的费用,只有在额外需要 NAT 网关时才值得。
您需要将您的 lambda 放在您的 VPC 中,然后为 SQS 或 NAT 网关设置一个 VPC 端点,当您将您的 lambda 函数添加到子网时,确保您只将它添加到私有子网,否则什么都不会工作。
参考
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)
}
我根据 Configuring a Lambda function to access resources in a VPC 创建了一个 VPC、子网等。本示例中的 EC2 实例根据本教程从 CLI 通过专用端点调用 SQS 没有问题。
如果我将上面的简单 Lambda 放到相同的 VPC 和子网中,使用 SQS 发布权限等并调用测试函数,它将正确解析子网内 SQS 端点的 IP 地址,但调用会超时(确保您的 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 代理。其他人在类似 post 中提出的建议。您还可以将 SQS 队列订阅到 SNS 主题(我对此进行了原型设计并且它有效)并以这种方式将其路由出去,但这看起来很愚蠢,除非您出于某些不明确的原因绝对必须拥有 SQS。
我切换到 SNS。我只是希望获得更多 SQS 经验。希望有人能证明我错了,但我称之为错误。
如果您在 VPC 的 lambda 中使用 boto3 python 库,并且无法通过 vpc 端点连接到 sqs 队列,则必须在创建时设置 endpoint_url sqs客户端。 Issue 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。
我正在处理一项涉及 VPC.
内的 Lambda 函数 运行 的任务此函数应该将消息推送到 SQS 并且 lambda 执行角色具有策略:AWSLambdaSQSQueueExecutionRole 和 AWSLambdaVPCAccessExecutionRole 已添加。
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"
}
I increased the Timeout from Basic Settings to 5 seconds & 10 seconds as well. But the error kept coming.
如果有人在过去遇到过类似的问题或者知道如何解决这个问题,请帮助我。
提前致谢。
当 AWS Lambda 函数配置为使用 Amazon VPC 时,它会连接到 VPC 的指定子网。这允许 Lambda 函数与 VPC 内的其他资源进行通信。但是,它无法与 Internet 通信。这是一个问题,因为 Amazon SQS public 端点存在于 Internet 上,并且函数超时,因为它无法连接到 Internet。
因此,您有 3 个选择:
选项 1:不连接到 VPC
如果您的 Lambda 函数不需要与 VPC 中的资源通信(例如您上面提供的简单函数),只需不要将其连接到 VPC .当 Lambda 函数未连接到 VPC 时,它可以与 Internet 和 Amazon SQS public 端点通信。
选项 2:使用 VPC 端点
VPC 端点提供了一种无需通过互联网即可访问 AWS 服务的方法。您将为 Amazon SQS 配置 VPC endpoint。然后,当 Lambda 函数希望连接 SQS 队列时,它可以通过端点而不是通过 Internet 访问 SQS。如果 Lambda 函数需要与 VPC 中的其他资源通信,这通常是一个不错的选择。
选项 3:使用 NAT 网关
如果 Lambda 函数配置为使用私有子网,并且在 public 子网 中配置了 NAT 网关,它将能够访问 Internet私有子网的路由 Table 指向 NAT 网关。这涉及额外的费用,只有在额外需要 NAT 网关时才值得。
您需要将您的 lambda 放在您的 VPC 中,然后为 SQS 或 NAT 网关设置一个 VPC 端点,当您将您的 lambda 函数添加到子网时,确保您只将它添加到私有子网,否则什么都不会工作。
参考
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)
}
我根据 Configuring a Lambda function to access resources in a VPC 创建了一个 VPC、子网等。本示例中的 EC2 实例根据本教程从 CLI 通过专用端点调用 SQS 没有问题。
如果我将上面的简单 Lambda 放到相同的 VPC 和子网中,使用 SQS 发布权限等并调用测试函数,它将正确解析子网内 SQS 端点的 IP 地址,但调用会超时(确保您的 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 代理。其他人在类似 post 中提出的建议。您还可以将 SQS 队列订阅到 SNS 主题(我对此进行了原型设计并且它有效)并以这种方式将其路由出去,但这看起来很愚蠢,除非您出于某些不明确的原因绝对必须拥有 SQS。
我切换到 SNS。我只是希望获得更多 SQS 经验。希望有人能证明我错了,但我称之为错误。
如果您在 VPC 的 lambda 中使用 boto3 python 库,并且无法通过 vpc 端点连接到 sqs 队列,则必须在创建时设置 endpoint_url sqs客户端。 Issue 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。