Redis中有超过40亿个关键值对?

时间:2012-05-07 08:16:36

标签: redis

我正在尝试在redis中存储ip号以及相关的ISP信息。我有Maxmind数据,csv文件包含每个ISP的开始和结束编号。

在SQL中查询时,我可以检查IP(在将其转换为数字后)以在一个范围内可用并获得相关的ISP。

我正在考虑将所有范围转换为单个数字,并在Redis中提交所有键值对以便更快地查找。 这大约将导致Redis商店中的40亿个键值对。 我已经完成了几亿个关键值对,但我正在寻找建议/建议,在Redis中转向40亿对。 我必须注意哪些性能问题,或者我有什么方法可以做得更好?

感谢您提出的所有建议。

更新:感谢下面的建议,我可以让这个工作。 以为我会在这里分享Python代码(快速和脏):

import redis
import pymysql

conn = pymysql.connect(host='localhost',user='user',passwd='password',db='foo')
cur = conn.cursor()
cur.execute('select startipnum,endipnum,isp from wiki.ipisp order by endipnum;')
result = cur.fetchall()

r = redis.StrictRedis(host='localhost', port=6379, db=0)
ispctr = 1
for row in result:
    tempDict = {'ispname':row[2],'fromval':row[0],'toval':row[1]}
    namefield = ispctr
    r.hmset(namefield,tempDict)
    r.zadd('ispmaxindex',row[1],namefield)
    ispctr = ispctr+1
conn.close()

ipstotest = ['23.23.23.23','24.96.185.10','203.59.91.235','188.66.105.50','99.98.163.93']
for ip in ipstotest:
    ipvalsList = [int(ipoct) for ipoct in ip.split('.')]
    ipnum = (16777216*ipvalsList[0]) + (65536*ipvalsList[1]) + (256*ipvalsList[2]) + ipvalsList[3]
    ipnum = long(ipnum)
    tempVal1 = r.zrangebyscore('ispmaxindex',ipnum,float('Inf'),0,1)
    tempval2 = r.hgetall(tempval1[0])
    print tempval2['ispname']

4 个答案:

答案 0 :(得分:4)

我认为这是错误的做法。

将IP映射保持为整数范围(从IP到IP,converted to decimal)并使用传统数据库或使用比较强的NoSQL快速查询主题IP。

答案 1 :(得分:3)

你可以在Redis中存储4B项而不会降低性能,但你需要内存(即一切都必须适合内存)。

此处描述了使用Redis实现此类查询的最佳方法:

store ip ranges in Redis

在这里:

Redis or Mongo for determining if a number falls within ranges?

因此,最优解决方案的复杂性取决于您认为IP范围是否重叠的事实。

答案 2 :(得分:2)

只需使用geodis即可。它已经为国家/位置查找提供IP,并为您有效地存储这些数据。您可以自由地仅将其用于数据加载,并直接从redis本身请求数据。

答案 3 :(得分:2)

我们用于快速地理IP分辨率的方法是采用所有IP范围并在/24(前三个四边形)中断开它们,并存储包含这些地址中所有匹配的记录。这为您提供了1600万个密钥和O(1)访问权限。如果你能够容忍客户端分解存储记录的复杂性,那么它的性能不会占用大量的RAM。

更详细:

  • 取所有范围,并按前24位分解。
    • 范围128.100.60.0-128.100.60.9成为一条记录,<128.100.60 | 0 9 | (...recA...)>
    • 范围128.100.60.10 - 128.100.62.80将变为<128.100.60 | 10 255 | (...recB...)><128.100.61 | 0 255 | (...recB...)><128.100.62 | 0 80 | (...recB...)>
  • 将具有相同前缀的所有记录合并到一个哈希,该哈希的键是其范围的 top 。所以
    • key 128.100.60{9: {...recA...}, 255: {...recB...}}
    • key 128.100.61{255: {...recB...}}
    • key 128.100.62{80: {...recB...}, ...}

要检索特定IP,请通过其24位密钥检索复合记录,并返回其子密钥大于最后一个部分的第一个结果。如果我查找128.100.60.20,我会发现9不是更大,但是255是,所以返回recB

这是在Hadoop之类的事情中进行范围连接(甚至空间连接!)的常用策略:在一些合理的块上进行分区,然后在范围的一端进行索引。