хранить диапазоны ip в 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 ответов


Это зависит от того, считаете ли вы, что ваши диапазоны 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, а не реляционная база данных). Score-максимальное значение, member-идентификатор диапазона.

> 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-адрес больше или равно минимальному адресу возвращаемого диапазона.

Теперь, если вы считаете, что диапазоны могут перекрываться, решение намного сложнее, и это уже было объяснено здесь.


на мой взгляд лучшим решением будет сортированный набор.

для вставки диапазона используйте ZADD.
К member назначить range_name.
К score присвоить максимальное значение в диапазоне.

ZADD ip_table 3232235826 some_name

тогда для поиска диапазона используйте ZRANGEBYSCORE С user_ip как min_value и limit = 1.

ZRANGEBYSCORE ip_table user_ip +inf LIMIT 0 1

он найдет диапазон с наименьшим ip в конечной точке, который больше или равен user_ip.


Если вы получаете эти данные для поставщика, такого как MaxMind, могут быть уже доступны библиотеки, чтобы сделать это быстро и эффективно. Я не думаю, что вы получите большую производительность, используя Redis в этом случае.


Это похоже на то, что предложил Дидье специя, но мы используем диапазон начала и диапазон конца в отсортированном наборе, потому что могут быть "пробелы".

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