Redis作为队列 - 批量检索

时间:2014-09-26 15:39:35

标签: python redis scaling

我们的Python应用程序每天提供大约200万个API请求。我们从业务中得到了一项新要求,即生成报告,该报告应包含每天唯一请求和响应的计数。

  • 我们想使用Redis排队所有请求&响应。
  • 另一个工作者实例将从Redis队列中检索上述数据并对其进行处理。
  • 处理后的结果将保留在数据库中。

最简单的选择是使用LPUSH和RPOP。但RPOP将一次返回一个值,这将影响性能。有没有办法从Redis那里做大量的流行音乐?

对该场景的其他建议将受到高度赞赏。

4 个答案:

答案 0 :(得分:2)

一个简单的解决方案是使用redis pipelining

在单个请求中,您将被允许执行多个RPOP指令。 大多数redis驱动程序都支持它。在使用Redis-py的python中,它看起来像这样:

pipe = r.pipeline()
# The following RPOP commands are buffered
pipe.rpop('requests')
pipe.rpop('requests')
pipe.rpop('requests')
pipe.rpop('requests')
# the EXECUTE call sends all buffered commands to the server, returning
# a list of responses, one for each command.
pipe.execute()

答案 1 :(得分:1)

可以从不同的角度来看待这个问题。您的要求是:

  
    

要求......生成每天应包含唯一请求和响应计数的报告。

  

为什么不使用Redis功能来解决实际需求并避免批量LPUSH / LPOP的问题,而不是将请求存储在列表中然后对结果进行后处理。

如果我们只想记录唯一计数,那么您可能需要考虑使用排序集

这可能是这样的:

收集请求统计信息

# Collect the request statistics in the sorted set.
# The key includes date so we can do the "by date" stats.
key = 'requests:date'
r.zincrby(key, request, 1)

报告请求统计信息

  • 可以使用ZSCAN批量迭代所有成员,但这是无序的。
  • 可以使用ZRANGE一次性获取所有成员(或其他任何成员)。

Python代码:

# ZSCAN: Iterate over all members in the set in batches of about 10.
# This will be unordered list.
# zscan_iter returns tuples (member, score)
batchSize = 10
for memberTuple in r.zscan_iter(key, match = None, count = batchSize):
    member = memberTuple[0]
    score = memberTuple[1]
    print str(member) + ' --> ' + str(score)


# ZRANGE: Get all members in the set, ordered by score.
# Here there maxRank=-1 means "no max".
minRank = 0
maxRank = -1
for memberTuple in r.zrange(key, minRank, maxRank, desc = False, withscores = True):
    member = memberTuple[0]
    score = memberTuple[1]
    print str(member) + ' --> ' + str(score)

这种方法的好处

  1. 解决实际需求 - 按天报告唯一请求的数量。

  2. 无需后处理任何内容。

  3. 可以执行其他查询,例如"热门请求"开箱即用:)

答案 2 :(得分:0)

另一种方法是使用Hyperloglog data structure。 那是especially designed for this kind of use case

它允许计算具有低误差范围(0.81%)且内存使用率非常低的唯一项目。

使用HLL非常简单:

PFADD myHll "<request1>"
PFADD myHll "<request2>"
PFADD myHll "<request3>"
PFADD myHll "<request4>"

然后得到计数:

PFCOUNT myHll

答案 3 :(得分:0)

实际问题是关于Redis List,您可以使用lrange在一次调用中获取所有值,下面是解决方案;

xproto