什么是AWS Kinesis中的分区键?

59

我正在了解关于AWS Kinesis的内容。在下面的程序中,我将数据写入名为TestStream的流中。我运行了这段代码10次,向流中插入了10条记录。

var params = {
    Data: 'More Sample data into the test stream ...',
    PartitionKey: 'TestKey_1',
    StreamName: 'TestStream'
};

kinesis.putRecord(params, function(err, data) {
   if (err) console.log(err, err.stack); // an error occurred
   else     console.log(data);           // successful response
});

所有记录已成功插入。在这里,“分区键”真正意味着什么?它在后台做了什么?我阅读了它的文档,但没有理解它的含义。
3个回答

100

只有在流中有多个分片时,分区键才很重要(但始终需要它们)。Kinesis计算分区键的MD5哈希值以决定将记录存储在哪个分片上(如果您描述流,则会在分片描述中看到哈希范围)。

那么这为什么很重要呢?

每个分片每秒只能接受1,000条记录和/或1 MB数据(请参阅PutRecord文档)。如果您向单个分片写入速度超过此速率,则会收到ProvisionedThroughputExceededException

使用多个分片可以扩展此限制:4个分片可提供4,000条记录和/或4 MB每秒。当然,还有一些注意事项。

最大的问题是必须使用不同的分区键。如果所有记录都使用相同的分区键,则仍然写入单个分片,因为它们都具有相同的哈希值。如何解决取决于您的应用程序:如果您从多个进程编写,则使用进程ID、服务器IP地址或主机名可能已足够。如果您从单个进程编写,则可以使用记录中的信息(例如唯一的记录ID)或生成随机字符串。

第二个注意点是分区键占用总写入大小,并存储在流中。因此,虽然您可能可以通过在记录中使用某些文本组件来获得良好的随机性,但您会浪费空间。另一方面,如果您有一些随机文本组件,则可以从中计算自己的哈希值,然后将其字符串化为分区键。

最后,如果您正在使用PutRecords(如果您要写入大量数据,则应该这样做),则请求中的单个记录可能会被拒绝,而其他记录则被接受。这是因为这些记录发送到了已经达到其写入限制的分片,您需要在延迟后重新发送它们。
另一个回答指出记录在分区内是有序的,并声称这是使用分区键的真正原因。然而,这种排序反映了Kinesis接受记录的顺序,而不一定是客户端想要的顺序。
  • 如果客户端是单线程的,并使用PutRecord API,则是的,客户端和分区之间的排序应该是一致的。
  • 如果客户端是多线程的,则所有标准分布式系统引起的混乱(内部线程调度,网络路由,服务调度)都可能导致不一致的排序。
  • 如果客户端使用PutRecords API,批处理中的单个记录可能会被拒绝并必须重新发送。文档非常清楚,此API调用不保留排序。在高容量环境中,这是您将使用的API。

除了写入时的无序之外,reshard操作还会在读取时引入不一致性的潜在可能性。您必须从父级到子级遵循链路,认识到可能会有更多或更少的子级,并且分割可能不均匀。天真的“每个分片一个线程”的方法(例如Lambda使用的方法)将无法正常工作。

所以,最重要的是:是的,分片提供排序。但是,依赖该顺序可能会在您的应用程序中引入难以诊断的错误。

在大多数情况下,这并不重要。但是如果您需要保证顺序(例如在处理事务日志时),那么在写入记录时必须添加自己的排序信息,并确保在读取记录时正确排序。


2
分片是否有数据容量限制?如果我的应用程序只有一个分区键,但有100个分片怎么办? - Suhail Gupta
3
使用不同的分区键插入每个记录是什么意思?为什么我想要为每个记录使用相同的分区键? - Suhail Gupta
1
@SuhailGupta - 这个回答解决了你的问题吗? - kdgregory
1
如果我也可以问的话,如果我有两个分片但超过两个可能的分区键会发生什么?Kinesis是否只是确保特定分区键的所有数据使用相同的分片?例如,如果我有4个可能的分区键,它会将2个键分割到一个分片上,另外2个键分割到另一个分片上吗? - Gareth McCumskey
5
根据 AWS 文档,分区键的数量通常应远远大于可用的分片数量。因此,假设有场景,我有2个可用的分片,并且每秒钟500个传感器每个传输100字节数据到数据流中,如果我将传感器 ID 用作分区键,那么 MD5 哈希算法不会生成500个不同的值吗?那么这500个不同的值如何映射到创建的两个分片之一呢?我知道每个分片都有一个起始和结束哈希键,但是在分片创建时就已经分配了。 - Gaurav Parashar
显示剩余7条评论

48
接受的答案解释了Kinesis中的分区键是什么以及它们的用途(用于决定将数据发送到哪个分片)。不幸的是,它没有解释为什么首先需要分区键。
理论上,AWS可以为每个记录创建一个随机分区键,这将导致近乎完美的分散。
使用分区的真正原因是“排序/流式处理”。 Kinesis为每个分片维护排序(序列号)。
换句话说,通过将X和之后的Y流式传输到分片Z,可以确保在从所有分片拉取记录时,X将先于Y被拉取。另一方面,通过将X流式传输到分片Z1,然后将Y流式传输到分片Z2,无法保证顺序(从所有分片中拉取记录时)。 Y可能会在X之前被拉出来。
分片“流式传输”功能在许多情况下都很有用。
例如,视频服务使用用户名和电影名称作为分区键向用户流式传输电影。
例如,在处理常见事件流并应用聚合时。
在不需要排序(流式处理)或分组(例如聚合)的情况下,生成随机分区键就足够了。

这是否意味着500个分片的限制是单个流用于分区排序的限制?还是说如果它们里面没有任何内容,这些分片就会存在或消失? - RaviU

2
如果您不理解分片,可以将其视为由您创建的kinesis单个资源处理的不同队列。如前所述,您可以使用多个队列,因为一个队列只能处理每秒1MB的数据。因此,使用多个队列来处理更高的吞吐量。大多数情况下,您将使用AWS Lambda来处理队列。拥有多个队列还可以获得多个Lambda,这意味着现在您可以处理更多的数据输出。但是,这与您关于什么是分区键的问题无关。
如果您没有定义自己的分区键,则数据将随机分配到任何队列/分片中,并且您的Lambda仅始终处理相同类型的数据,因此您的数据顺序不会得到保留,因为如果Lambda拒绝了一批记录,Kinesis将在推送下一批之前再次释放相同的数据批次。
但是,如果您使用适当的分区键,比如customerID或movieID,您显然希望购买事件或电影内容按照相同的顺序进入。如果您使用相同的队列/分片使用唯一的customerID/movieID,则最终会将所有数据顺序地放入同一个队列/分片中,最终由Lambda检索,如果Lambda拒绝了一批数据,Kinesis会确保在成功处理该批次之前,它不会获取下一批数据。
这就是您的问题的答案。希望它有所帮助。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接