2

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

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

我正在考虑将所有范围转换为单独的数字,并在 Redis 中提交所有键值对以便更快地查找。这大约会在 Redis 存储中产生 40 亿个键值对。我已经为几亿个键值对做了这个,但是当我在 Redis 中移动到 40 亿对时,我正在寻找建议/建议。我必须注意的任何性能问题,或者有什么方法可以更好地做到这一点?

感谢您的所有建议。

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

导入redis
导入 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;')
结果 = cur.fetchall()

r = redis.StrictRedis(host='localhost', port=6379, db=0)
ispctr = 1
结果中的行:
    tempDict = {'ispname':row[2],'fromval':row[0],'toval':row[1]}
    名称字段 = ispctr
    r.hmset(名称字段,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']
对于 ipstotest 中的 ip:
    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])
    打印 tempval2['ispname']
4

4 回答 4

4

我相信这是错误的做法。

将 IP 映射保持为整数范围(从 IP - 到 IP,转换为十进制),并使用传统数据库或使用强比较的 NoSQL 快速查询您的主题 IP。

于 2012-05-07T09:46:44.470 回答
3

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

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

在 Redis 中存储 ip 范围

和这里:

Redis 或 Mongo 用于确定数字是否在范围内?

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

于 2012-05-07T10:21:36.127 回答
2

只需使用geodis。它已经进行了 IP 到国家/地区的查找,并为您有效地存储了这些数据。您可以自由地将它仅用于数据加载和直接从 redis 本身请求数据。

于 2012-05-07T15:41:05.027 回答
2

我们用于快速 Geo-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...)>
  • 将具有相同前缀的所有记录组合成一个哈希,其键是其范围的顶部。所以
    • 关键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 之类的事物中进行范围连接(甚至是空间连接!)的常用策略:在某个合理的块上分区,然后在范围的一端建立索引。

于 2012-12-18T02:52:25.487 回答