虽然在写入时将大量小记录写入存储桶很容易且高效,但您付出的代价是当您尝试读取值时会变得昂贵,因为您很可能不知道键。如果您需要通过二级索引、键过滤器或者更糟糕的是,通过遍历存储桶中的所有键(这是一个非常繁重的操作,从不推荐用于生产环境)来查找这些键,那么效率将大大降低而不是通过键检索数据,而不是扩展。
Riak 中也没有附加功能,这意味着您需要先读取然后写入记录才能更新它并附加新的日志条目。根据您组织和协调写作的方式,正如您指出的那样,这可能会导致同一记录的并发更新,在设计解决方案时需要考虑这一点。
假设您正在收集的记录(例如日志条目)可以被视为一组,我推荐的一种技术是时间盒。时间装箱时,您根据时间段聚合数据。如果我们假设我们正在为一组服务器(在本例中命名为服务器)收集日志,我们可以创建具有基于服务器 ID 和日期时间标识符的键的记录,例如测量周期的开始。我们不需要完整的时间戳,只要足以让我们识别记录即可。包含 2013 年 3 月 7 日 14:15 到 14:20 期间的 server3 日志条目的记录可以命名为“server3_20130307_1415”。接下来的 5 分钟时间将相应地命名为“server3_20130307_1420”。如果一段时间内没有数据,则不会创建记录。
这使您可以自动知道涵盖特定时期的记录的密钥,并允许您严格根据密钥访问来检索记录,这可以很好地扩展和执行。您自然需要根据生成的数据量调整单个记录所涵盖的时间段,因为您通常希望将 Riak 中的对象大小保持在 1-2MB 以下。如果每个周期都有大量数据,那么考虑在应用程序级别压缩数据也是值得的,以便低于这个推荐的大小。
如果您希望能够访问更大的数据块而不必检索可能大量的记录,您可以定期聚合记录。例如,您可以读取一个小时内的所有记录,并将聚合数据写入一个名为“server3_20130307_14”的新记录,该记录涵盖整个 14:00-15:00 期间。如您所知,这很简单,并且很容易作为批处理作业实施。
采用这种方法时,如前所述,您需要考虑并发写入的可能性。我认为最好的方法是允许兄弟姐妹(使用存储桶属性 [1] 将存储桶的“allow_mult”设置为 true,将“last_write_wins”设置为 false)。这将导致 Riak 在并发更新的情况下保留记录的所有版本,并且您需要在读取具有兄弟姐妹的记录时解析在应用程序层中创建的任何兄弟姐妹。尽管这确实增加了一些复杂性,但它确保您不会丢失任何数据。
由于我们假设这种情况下的日志条目可以被视为一个集合,您可以通过集合并集合并所有兄弟的集合,然后更新对象(使用正确的向量时钟)以解析兄弟。
[1] http://docs.basho.com/riak/latest/references/apis/http/HTTP-Set-Bucket-Properties/