Amazon web services 在Kinesis中使用分区键以确保具有相同键的记录由相同的记录处理器(lambda)处理

Amazon web services 在Kinesis中使用分区键以确保具有相同键的记录由相同的记录处理器(lambda)处理,amazon-web-services,aws-lambda,amazon-kinesis,Amazon Web Services,Aws Lambda,Amazon Kinesis,我正在使用AWS kinesis和lambda开发一个实时数据管道,我正在尝试找出如何保证来自相同数据生产者的记录由相同的碎片处理,最终由相同的lambda函数实例处理 我的方法是使用分区键来确保来自相同生产者的记录由相同的碎片处理。但是,我无法让来自同一个碎片的记录由同一个lambda函数实例处理 基本设置如下所示: 有多个数据源将数据发送到动觉流 流有多个碎片来处理负载 有一个lambda函数通过事件源映射(批大小为500)连接到CREAR lambda函数正在处理记录,进行一些数据转换和

我正在使用AWS kinesis和lambda开发一个实时数据管道,我正在尝试找出如何保证来自相同数据生产者的记录由相同的碎片处理,最终由相同的lambda函数实例处理

我的方法是使用分区键来确保来自相同生产者的记录由相同的碎片处理。但是,我无法让来自同一个碎片的记录由同一个lambda函数实例处理

基本设置如下所示:

  • 有多个数据源将数据发送到动觉流
  • 流有多个碎片来处理负载
  • 有一个lambda函数通过事件源映射(批大小为500)连接到CREAR
  • lambda函数正在处理记录,进行一些数据转换和其他一些操作,然后将所有内容放入firehose
  • 以后还会发生更多的事情,但这与问题无关
看起来是这样的:

如图所示,有三个lambda函数实例被调用进行处理;每个碎片一个。 在此管道中,来自同一数据源的记录由同一lambda函数实例处理非常重要。根据我所读到的,这可以通过确保来自同一源的所有记录使用相同的分区键来保证,因此它们由相同的碎片处理

分区键

分区键用于按分区内的碎片对数据进行分组 流动Kinesis数据流服务隔离数据记录 使用分区键将属于一个流的数据分为多个碎片 与每个数据记录关联,以确定给定数据的碎片 记录属于。分区键是具有最大值的Unicode字符串 长度限制为256字节。MD5哈希函数用于映射 分区键到128位整数值并映射相关数据 将记录转换为碎片。当应用程序将数据放入流中时,它 必须指定分区密钥

资料来源:

这很有效。因此,具有相同分区键的记录由相同的碎片处理。但是,它们由不同的lambda函数实例处理。因此,每个分片调用一个lambda函数实例,但它不仅处理来自一个分片的记录,而且处理来自多个分片的记录。这里似乎没有记录如何移交给lambda的模式

以下是我的测试设置: 我将一组测试数据发送到流中,并在lambda函数中打印记录。这是三个函数实例的输出(检查每行末尾的分区键。每个键只应出现在三个日志中的一个日志中,而不应出现在多个日志中):

Lambda实例1:

{'type': 'c', 'source': 100, 'id': 200, 'data': 'ce', 'partitionKey': '100'}
{'type': 'c', 'source': 100, 'id': 200, 'data': 'ce', 'partitionKey': '100'}
{'type': 'c', 'source': 103, 'id': 207, 'data': 'ce2', 'partitionKey': '103'}
{'type': 'c', 'source': 100, 'id': 200, 'data': 'ce', 'partitionKey': '100'}
{'type': 'c', 'source': 103, 'id': 207, 'data': 'ce2', 'partitionKey': '103'}
{'type': 'c', 'source': 101, 'id': 204, 'data': 'ce4', 'partitionKey': '101'}
{'type': 'c', 'source': 101, 'id': 205, 'data': 'ce5', 'partitionKey': '101'}
{'type': 'c', 'source': 101, 'id': 205, 'data': 'ce5', 'partitionKey': '101'}
Lambda实例2:

{'type': 'c', 'source': 101, 'id': 201, 'data': 'ce1', 'partitionKey': '101'}
{'type': 'c', 'source': 102, 'id': 206, 'data': 'ce1', 'partitionKey': '102'}
{'type': 'c', 'source': 101, 'id': 202, 'data': 'ce2', 'partitionKey': '101'}
{'type': 'c', 'source': 102, 'id': 206, 'data': 'ce1', 'partitionKey': '102'}
{'type': 'c', 'source': 101, 'id': 203, 'data': 'ce3', 'partitionKey': '101'}
Lambda实例3:

{'type': 'c', 'source': 100, 'id': 200, 'data': 'ce', 'partitionKey': '100'}
{'type': 'c', 'source': 100, 'id': 200, 'data': 'ce', 'partitionKey': '100'}
{'type': 'c', 'source': 101, 'id': 201, 'data': 'ce1', 'partitionKey': '101'}
{'type': 'c', 'source': 101, 'id': 202, 'data': 'ce2', 'partitionKey': '101'}
{'type': 'c', 'source': 101, 'id': 203, 'data': 'ce3', 'partitionKey': '101'}
{'type': 'c', 'source': 101, 'id': 204, 'data': 'ce4', 'partitionKey': '101'}
{'type': 'c', 'source': 101, 'id': 204, 'data': 'ce4', 'partitionKey': '101'}
{'type': 'c', 'source': 101, 'id': 204, 'data': 'ce4', 'partitionKey': '101'}
{'type': 'c', 'source': 101, 'id': 204, 'data': 'ce4', 'partitionKey': '101'}
{'type': 'c', 'source': 101, 'id': 204, 'data': 'ce4', 'partitionKey': '101'}
这就是我将数据插入流的方式(如您所见,分区键设置为源id):

所以我的问题是:

  • 为什么每个lambda函数不能只处理一个碎片的记录
  • 如何做到这一点

谢谢

为什么您会关心哪个Lambda实例处理碎片?Lambda实例无论如何都没有状态,所以哪个实例读取哪个碎片并不重要。更重要的是,在任何时候,Lambda实例都只能从一个碎片读取数据。在完成调用后,它可以从另一个碎片读取

您是否使用KCL使用流中的记录?我通过事件源映射()直接使用流。因此,记录通过传递给函数的事件传递给lambda函数。@oneschilling您解决过这个问题吗?我也吃同样的issue@gfree显然这是不可能的。我还与AWS的支持人员进行了交谈,他们证实了这一点。我通过他们提出了一个功能请求。我认为他们最初计划将其作为与lambda结合使用的动觉特征,因为文件一开始就说明了这一点,但在某个时候有所改变。因此,对于我们来说,此时最好的选择是改变插入数据的方式,因为我们依赖于管道中的顺序。我们将这种逻辑转移到数据生产者,使piepline顺序不可知,这意味着我们可以毫无问题地增加碎片的数量。
processed_records = []
for r in records:
    processed_records.append({
        'PartitionKey': str(r['source']),
        'Data': json.dumps(r),
    })

kinesis.put_records(
    StreamName=stream,
    Records=processed_records,
)