在Redis中存储ip范围

时间:2012-04-03 07:37:48

标签: redis

我有很多不同提供商的IP范围。例如

P1: 192.168.1.10 - 192.168.1.50, 192.168.2.16 - 192.168.2.49,
P2: 17.36.15.34 - 17.36.15.255,
P3: ...

我将此IP转换为int32:

P1: 3232235786 - 3232235826, 3232236048 - 3232236081, etc

我的任务:按用户IP地址查找提供商名称(例如192.168.2.20(3232236052))

在MySQL中很简单:

select name from ip_ranges where l_ip <= user_ip and user_ip <= r_ip

如何对Redis做同样的事情?

4 个答案:

答案 0 :(得分:17)

这取决于您是否认为您的IP范围可以重叠。 如果没有,解决方案很简单:

  • 使用哈希集合来存储提供者数据
  • 使用zset索引范围的最大值
  • 检索最大值大于IP的(唯一)范围
  • 检查此范围的最小值是否低于IP

示例:

这是我的提供者。每个都用id标识。请注意我可以添加附加到每个提供商的更多属性:

> hmset providers:1 name P1 min 3232235786 max 3232235826
OK
> hmset providers:2 name P3 min 1232235786 max 1232235826
OK
> hmset providers:3 name P3 min 2232235786 max 2232235826
OK
> hmset providers:4 name P4 min 4232235786 max 4232235826
OK

每次在系统中添加提供程序时,都必须维护索引(手动:这是Redis,而不是关系数据库)。分数是最大值,成员是范围的id。

> zadd providers:index 3232235826 1 1232235826 2 2232235826 3 4232235826 4
(integer) 4
> zrange providers:index 0 -1
1) "2"
2) "3"
3) "1"
4) "4"

现在要查询与IP地址对应的唯一范围,您需要2次往返:

> zrangebyscore providers:index 3232235787 +inf LIMIT 0 1
1) "1"
> hgetall providers:1
1) "name"
2) "P1"
3) "min"
4) "3232235786"
5) "max"
6) "3232235826"

然后客户端程序只需检查您的IP是否大于或等于返回范围的最小地址。

现在,如果你认为范围可以重叠,那么解决方案要复杂得多,而且已经解释过here

答案 1 :(得分:10)

在我看来,最佳解决方案是sorted set

要插入范围,请使用ZADDmember指定range_name 要score指定范围内的最高值。

ZADD ip_table 3232235826 some_name

然后使用user_ip作为min_value并且limit = 1来查找范围使用ZRANGEBYSCORE

ZRANGEBYSCORE ip_table user_ip +inf LIMIT 0 1

它将在端点找到大于或等于user_ip的最小ip范围。

答案 2 :(得分:0)

如果您为MaxMind等供应商提供此数据,可能已有库可用于快速有效地执行此操作。在这种情况下,我认为使用Redis不会获得太多性能。

答案 3 :(得分:0)

这与Didier Spezia提出的相似, 但是我们在排序集中使用开始范围和结束范围,因为可能存在“间隙”。

https://github.com/nmmmnu/GeoIP-Redis