Redis中超过40亿个键值对?

Redis中超过40亿个键值对?,redis,Redis,我试图在redis中存储ip号码以及相关的ISP信息。我有Maxmind数据,csv文件包含每个ISP的开始和结束编号 在SQL中查询时,我可以检查IP(将其转换为数字后)是否在某个范围内可用,并获取相关的ISP 我正在考虑将所有范围转换为单个数字,并在Redis中提交所有键值对,以便更快地查找。 这将在Redis存储中产生大约40亿个键值对。 我已经为数亿个键值对做了这项工作,但当我在Redis中移动到40亿个键值对时,我正在寻找建议。 我必须注意的任何性能问题,或者有没有更好的方法 谢谢你的

我试图在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'] 导入redis 导入pymysql conn=pymysql.connect(host='localhost',user='user',passwd='password',db='foo') cur=连接光标() cur.execute('select startipnum,endipnum,isp from wiki.ipisp order by endipnum;') 结果=cur.fetchall() r=redis.StrictRedis(host='localhost',port=6379,db=0) ispctr=1 对于结果中的行: tempDict={'ispname':行[2],'fromval':行[0],'toval':行[1]} namefield=ispctr r、 hmset(名称字段,tempDict) r、 zadd('ispmaxindex',第[1]行,名称字段) ispctr=ispctr+1 康涅狄格州关闭 ipstotest=['23.23.23'、'24.96.185.10'、'203.59.91.235'、'188.66.105.50'、'99.98.163.93'] 对于ipstotest中的ip: ipvalsList=[int(ipoct)表示ip.split('.')中的ipoct ipnum=(16777216*ipvalsList[0])+(65536*ipvalsList[1])+(256*ipvalsList[2])+ipvalsList[3] ipnum=长(ipnum) tempVal1=r.zrangebyscore('ispmaxindex',ipnum,float('Inf'),0,1) tempval2=r.hgetall(tempval1[0]) 打印tempval2['ispname']
我认为这样做是错误的


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

您可以在Redis中存储4B个项目,而不会导致性能下降,但您需要内存(即,所有内容都必须放在内存中)

使用Redis实现此类查询的最佳方法如下所述:

在这里:


因此,最优解的复杂性取决于你认为IPS的范围是否可以重叠的事实。它已经进行了IP到国家/地区的查找,并为您高效地存储这些数据。您可以自由使用它,仅用于数据加载和直接从redis本身请求数据。

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

更详细地说:

  • 获取所有范围,并按其前24位将其打断。
    • 范围
      128.100.60.0-128.100.60.9
      成为一条记录,
    • 范围
      128.100.60.10-128.100.62.80
      将变为
  • 将具有相同前缀的所有记录合并到一个哈希中,该哈希的键位于其范围的顶部。所以
    • 128.100.60
      {9:{…recA…},255:{…recB…}
    • 128.100.61
      {255:{…recB…}
    • 128.100.62
      {80:{…recB…},}
要检索特定IP,请通过其24位键检索复合记录,并返回其子键大于最后一部分的第一个结果。如果我查一下
128.100.60.20
,我会发现
9
不是更大,而是
255
更大,因此返回
recB


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

这是我从maxmind得到的,IP的范围从和到转换为十进制。我尝试了MySQL,但范围查询的速度似乎很慢,这就是为什么我认为键值查找会更快/更有效。此外,我还想实时查找(过去5分钟内的所有IP~5000+IP)当我监视访问我网站的IP时,根据您网站的使用情况,您可以在Redis中缓存匹配项(除了我建议的内容)。也就是说,一旦您找到了一个与给定IP匹配的from,请将其保存在Redis中。如果您的使用配置文件包含频繁返回的访问者,或者来自同一地区的访问者,那么这个有限大小的缓存将为您提供出色的性能,而不会出现Redis内存大小问题。Ofer..这是一个非常好的目标。这就是我现在正在做的,并根据超过频率阈值的访问者,以增量方式添加到我的Redis商店中。谢谢你的建议。非常有用的链接。我们将进一步探讨这些问题。谢谢你,迪迪埃,geodis很整洁。谢谢你。