Riak二级索引(2i)——写入性能

Riak secondary indexes (2i) - write performance

在写入 Riak 的对象中包含二级索引 (2i) 对性能有何影响?

让我们考虑两种情况,都在一个桶中包含大量对象。每个对象都有一个二级索引,我们称它为example_bin(但它也可以是一个整数索引):

  1. example_bin几乎每个值都是不同的值。一个针对某个索引的特定值的查询 returns 只有一个,或者只有几个对象。此类索引可以是电子邮件地址或注册时间(作为 unix 时间戳)。
  2. example_int 索引只有几个可能的值。因此,针对特定索引值returns 的查询对象数量巨大。这样的索引可以代表一类用户,例如 'administrators' 或 'customers'.

更新这些对象对性能有何影响?我知道每次更新对象时都需要检查索引。上面的任何一个示例都可以构成 Riak 的耗时或耗资源的任务吗?

当使用 LevelDB 作为后端时,在 Riak 中更新对象的性能影响不应受到每个索引中有多少条目的影响。但是,它可能会受到每个分区中存储的总数据量、自上次更新密钥以来写入的数据量以及为该单个对象指定了多少不同索引条目的影响。

LevelDB 如何存储数据

当一个值被写入 LevelDB 时,它被添加到顶层的 .log 文件中。当 .log 文件达到一定大小时(我想是 1Mb,不记得那个大小是否可配置),文件被切断并开始一个新文件。这些文件未排序。 当顶层(0 级)有多个文件时,会触发压缩。压缩将组合一个或多个顶级文件,对它们包含的键进行排序,并将这些排序列表与级别 1 中适当的 .sst 文件合并。为每个排序级别创建一个清单文件,表明每个 .sst 文件中存储的密钥范围。 这个过程也会根据需要对较低级别重复,每个级别能够存储大约前一级数据量的 10 倍。

当为一个已经存在的键写入一个新值时,它只是被写入到顶层,掩盖了之前在较低层写入的任何值。以前的值将被替换,因为正常压缩会将新值向下移动到较低级别。

这对阅读有何影响

当请求密钥时,LevelDB 从级别 0 开始并检查那里的每个文件以查看它是否包含密钥。如果不是,它会向下移动到级别 1 并检查清单指示将包含密钥的文件。对连续较低的级别重复此操作,直到找到密钥或已达到最低级别。因此,返回最近写入的键值。 随着存储在每个 LevelDB 后端的数据总量的增加,使用的级别数、必须搜索的文件数以及读取最旧数据的时间也会增加。

LevelDB 后端如何实现索引

在 LevelDB 后端存储值时,后端使用的原始密钥是 {o,Bucket,Key} 的 sext 编码。 如果在对象中指定了任何索引条目,则对于每个索引,都会存储一个附加键,该键是 {i,Bucket,IndexName,IndexValue,Key}.

的 sext 编码

为了在更新值时删除任何过时的索引条目,必须在每次 PUT 或 DELETE 之前执行 GET,将前一个对象的索引规范与正在存储的对象的索引规范进行比较,以及任何删除了过时的 {i,...} 密钥并添加了任何新密钥。

索引查询

由于LevelDB以排序的方式存储数据,索引查询实现为从键{i,Bucket,IndexName,FirstValue,<<>>}{i,Bucket,IndexName,LastValue,<<255,255,255,255>>}的折叠(二进制<<255,...是一个理论值,表示排序顺序中最后一个可能的键)。 查询每个排序级别中的清单,因此只需要打开包含被折叠范围的一部分的数据文件。

总结

Almost each value of example_bin is a different value. A query for one specific value of the index returns only one, or just a few objects. Such index could be an e-mail address or the registration time (as a unix timestamp).

查询所需的索引条目和单个值很可能完全落在每个排序级别的单个文件中,因此此查询将需要打开并搜索级别 0 中的所有文件,以及级别 1 中的 1 个文件每个较低的级别。存在的级别数取决于存储的数据量,将是最大的决定因素。

There is only several possible values of example_int index. Therefore, the query for a specific index value returns huge number of objects. Such index could represent a category of users, such as 'administrators' or 'customers'.

用于查询单个值的索引条目范围更大,因此更有可能需要为每个排序级别查询多个文件。此查询将比前一个查询花费更长的时间,因为折叠中包含的索引条目数量更多,并且可能需要打开的文件数量更多。

What is the performance impact when updating these objects? I understand the index needs to be checked every time the object is updated. Can either of the examples above comprise a time- or resource-consuming task for Riak?

此处所需的时间取决于检索任何旧对象所需的时间,以及索引条目的更改次数。在这个过程中,整个索引从不被视为一个整体,只有前一个对象上的条目和新对象上的条目。因此,性能不会受到任何索引中条目数的影响,但会受到此对象具有或具有条目的索引数的影响。