请考虑以下架构:
write -> DynamoDB table -> stream -> Lambda -> write metadata item to same table
它可以用于许多非常糟糕的情况,例如表和项目级别的聚合。我已经看到官方AWS工程师在几次技术讲座中推广了这种架构。
但是编写元数据项不是将新项添加到流中并再次运行Lambda吗?
如何避免无限循环?有没有一种方法可以避免元数据写入流中?
在这种架构下,花费2个流和Lambda请求是不可避免的吗? (我们会根据请求收取费用),即如果它是元数据项,则提前退出Lambda函数。
答案 0 :(得分:2)
由于从DynamoDB流触发AWS Lambda函数是一个二进制选项(开/关),因此不可能仅对表的某些写入触发AWS Lambda函数。因此,将针对刚刚写入DynamoDB表的项目再次调用您的AWS Lambda函数。重要的一点是在您的AWS Lambda函数中具有适当的逻辑,以检测到它已写入该数据,并且在这种情况下不再写入数据。否则,您将得到提到的无限循环,这将是非常不幸的情况,尤其是如果它不被注意的话。
答案 1 :(得分:0)
当前dynamo DB不提供基于条件的流订阅,因此,是的,Dynamo DB将在无限循环中执行lambda函数,当前唯一的解决方案是限制lambda函数的执行时间,您可以使用多个lambda函数,一个lambda函数将仅用于检查是否写入了元数据,我正在共享一个云体系结构图,说明如何实现它,
答案 2 :(得分:0)
有点晚了,但希望人们寻求更具示范性的答案会发现这很有用。
假设您要处理要添加到某个项目的记录,且该记录不超过特定阈值,则可以使用if条件来检查并处理或跳过该记录,例如
此代码假定您为每个实体/对象类型都具有一个属性“ Type”-Rick Houlihan本人向我推荐了该属性,但是您也可以检查属性是否存在,例如"<your-attribute>" in record["dynamodb"]["NewImage"]
-并且您是用PK和SK作为通用主键和排序键名进行设计。
threshold = (os.environ.get("THRESHOLD"))
def get_value():
response = table.query(KeyConditionExpression=Key('PK').eq(<your-pk>))
value = response['Items']['<your-attribute>'] if 'Items' in response else 0
return value
def your_aggregation_function():
# Your aggregation logic here
# Write back to the table with a put_item call once done
def lambda_handler(event, context):
for record in event['Records']:
if record['eventName'] != "REMOVE" and record["dynamodb"]["NewImage"]["Type'] == <your-entity-type>:
# Query the table to extract the attribute value
attribute_value = get_value(record["dynamodb"]["Keys"]["PK"]["S"])
if attribute_value < threshold:
# Send to your aggregation function
在lambda处理程序中具有适当的条件(或者您可以更改满足自己需求的位置)可以防止出现无限循环。
您可能希望在更新表达式中进行其他检查,以确保两个(或多个)并发的lambda不会写入同一对象。建议您使用date = # timestamp defined in the lambda
并将其添加到SK中,或者,如果不能,则在项目中添加“ EventDate”属性,以便您可以添加ConditionExpression
或UpdateExpression SET if_not_exists(#attribute, :date)
以上内容将确保您的lambda为idempotent。