使用 Redis 检查 IP 是否在一个范围内

Checking if IP falls within a range with Redis

我有兴趣使用 Redis 检查 IP 地址(转换为整数)是否在 IP 范围内。范围很可能会重叠。

我找到了 this question/answer,虽然我无法完全理解其背后的逻辑。

感谢您的帮助!

this discussion中,Dvir Volk 和@antirez 建议使用排序集,其中每个条目代表一个范围,并具有以下形式:

Member = "min-max" range

Score = max value

例如:

ZADD z 10 "0-10"
ZADD z 20 "10-20"
ZADD z 100 "50-100"

并且为了检查一个值是否在一个范围内,您可以使用 ZRANGEBYSCORE 并解析成员 returned.

例如,要检查值 5:

ZRANGEBYSCORE z 5 +inf LIMIT 0 1

这将 return 为“0-10”成员,您只需解析字符串并验证您的值是否介于两者之间。

检查值 25:

ZRANGEBYSCORE z 25 +inf LIMIT 0 1

将 return“50-100”,但该值不在该范围内。

编辑 - 因为我得到了反对票(评论解释为什么会很好),我从我的回答中删除了一些混乱。

@DidierSpezia 在您的链接问题中的回答是一个很好的答案,但如果您处于 adding/removing 范围,则很难维护。

However it is not trivial (and expensive) to build and maintain it.

我有一个更易于维护的答案,但计算多个范围可能会变得缓慢且内存昂贵,因为它需要克隆一组所有范围。

您需要将所有范围保存两次,分为两组。每个范围的分数将是它的边界值。

使用@DidierSpezia 示例中的集合:

A 2-8
B 4-6
C 2-9
D 7-10 

你的两组将是:

ZADD ranges:low 2 "2-8" 4 "4-6" 2 "2-9" 7 "7-10"
ZADD ranges:high 8 "2-8" 6 "4-6" 9 "2-9" 10 "7-10"

查询一个值属于哪个范围,需要trim下边界高于查询值的范围,trim上边界低于查询值的范围。

我能想到的最有效的方法是克隆其中一组,trim根据上面给出的规则在其中一侧设置,改变范围的分数以反映另一个边界,然后 trim第二面.

查找 5 所属范围的方法如下:

    ZUNIONSTORE tmp 1 ranges:low
    ZREMRANGEBYSCORE tmp (5 +inf 
    ZINTERSTORE tmp 2 tmp ranges:high WEIGHTS 0 1
    ZREMRANGEBYSCORE tmp -inf (5 
    ZRANGE tmp 0 -1