使用简单的map-reduce列出桶中所有键与bucket.get_keys()的对比?
根据Riak的文档(使用Python绑定),get_keys()这个方法非常耗费资源,不适合在生产环境中使用。我的问题是,使用一个非常简单的map查询是否合适。例如,只用一个map阶段和这个函数:
function(v) { return [v.key]; }
这样做的性能会比get_keys()好吗?为什么Riak不直接提供这个实现,而是继续使用现在的get_keys()版本?有没有更好的方法来列出一个桶里的键?
2 个回答
如果你使用的是eleveldb这个后端(它是用LevelDB库实现的),那么你的键(也就是数据的标识符)会按照顺序存储。这样你就可以做一些类似于以下的操作:
def get_bucket_keys(riak_client, bucket_name, start='0', stop='Z'):
for record_key in riak_client.index(bucket_name, '$key', start, stop).run():
yield record_key
for key in get_bucket_keys(riak.RiakClient(), 'mybucket'):
print key
使用eleveldb时,riak会在所有节点中只扫描你指定的范围。所以,如果你能控制你的桶(数据存储的地方)中的键的范围,那么列出桶中的键会非常高效。
不过,有一个缺点就是你不能为每个节点处理的键的数量设置一个限制。这就是为什么你需要控制你想要列出键的桶中的键。
get_keys()
这个函数在后台调用了list_keys
,这个操作被认为是比较耗费资源的,因为它需要对所有的键进行全面扫描。根据你使用的Riak后端,这个操作可能还需要对存储在磁盘上的数据进行全面扫描(比如InnoStore)。不过,默认的存储后端(Bitcask)会把所有的键都存储在内存中,所以性能问题不会太大。
另外,list_keys
被认为耗费资源的原因是,它以前是一个阻塞操作,涉及到Basho开发者所说的对所有键进行“折叠”。现在,list_keys
使用的是桶的快照(而不是实时读取键空间),这使得这个操作变得更轻便。
升级到Riak 1.0后,这个操作变得更简单。如果你使用的是LevelDB后端,可以在一个桶上启用二级索引,并使用$key
索引(Riak自动提供的)来获取桶中所有键的列表。
至于为什么Riak没有提供更好的实现,关键在于这个功能的用途。在关系型数据库中,获取一个表的所有主键需要对整个表进行扫描。而在Riak中,从一个桶中获取所有键需要扫描每个节点中的所有数据,然后把键名传回原始节点,合并这些数据,再发送给调用的客户端。由于Riak是分布式的、无序的状态,这个操作无论怎么做都是比较耗费资源的。不过,正如我上面提到的,还是有一些方法可以改善这个问题。