Store ip ranges in Redis

I have many IP ranges for different providers. for example

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: ... 

I convert this IP to int32:

 P1: 3232235786 - 3232235826, 3232236048 - 3232236081, etc 

My task: find the name of the provider by the user's IP address (for example, 192.168.2.20 (3232236052))

In MySQL, it's simple:

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

How to do the same with Redis?

+8
redis
source share
4 answers

It depends if you think that the IP ranges may overlap or not. If not, the solution is pretty simple:

  • use a hash collection to store provider data.
  • use zset to index the maximum value of your ranges.
  • get a (unique) range whose maximum value is greater than IP
  • check the min value of this range below IP

Example:

Here are my providers. Each of them is identified with an identifier. Please note that I can add additional properties for each provider:

 > 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 

Each time a provider is added to the system, it is necessary to maintain the index (manually: this is Redis, not a relational database). Score is the maximum value, member is the range identifier.

 > 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" 

Now, to request a unique range corresponding to the IP address, you will need 2 roundtrips:

 > 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" 

Then the client program simply needs to verify that your IP is greater than or equal to the minimum address of the returned range.

Now, if you think that ranges can overlap, the solution is much more complicated, and this has already been explained here .

+14
source share

In my opinion, the best solution would be a sorted set .

Paste the range of use of ZADD .
In member assign a range name.
For score assign the maximum value in the range.

 ZADD ip_table 3232235826 some_name 

Then, to search for a range, use ZRANGEBYSCORE with user_ip as min_value and limit = 1.

 ZRANGEBYSCORE ip_table user_ip +inf LIMIT 0 1 

It will find the range with the smallest ip at the endpoint, which is greater than or equal to user_ip.

+9
source share

If you get this data for a provider such as MaxMind, libraries may be available for this to do this quickly and efficiently. I do not think that you will get more performance using Redis in this case.

0
source share

This is similar to what Didier La Spezie suggested, but we use the start and end range of the range in the sorted set, because there may be “spaces”.

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

0
source share

All Articles