Expérience avec le stockage d'adresses IP dans PostgreSQL

description du problème

Plus d'une fois, notre équipe à Karuna a été confrontée au défi de stocker et d'utiliser des adresses IP dans une base de données. Supposons qu'il existe une tâche typique : vous devez analyser un grand nombre de plages d'adresses (~ 300k) à partir d'une  ressource connue , puis déterminer le pays par l'adresse IP du client. Cela ne semble rien de spécial. Cela peut être résolu tout simplement par l'une des méthodes décrites ci-dessous à faible charge. Mais si nous avons des milliers d'utilisateurs, ou notre service est-il un proxy devant tout le monde ? Dans ce cas, vous ne voulez pas être un goulot d'étranglement et vous devez vous battre pour chaque fraction de seconde.





Un peu d'adressage

Il existe 2 types d'adressage réseau





INET ( IP-) — , 1981 1993 . .





CIDR (Classless Inter-Domain Routing,  ) — IP-, .





 address/y,  y — . , /28 , 28 IP- , 4  — , .





,  192.168.5.0/24   192.168.5.1  192.168.5.254,  192.168.5.0 —  192.168.5.255 — .





inet cidr

PostgreSQL 2 IP- : inet  cidr.  inet/cidr.





 inet  , .  address/y.  y , 32 ( IPv4), .





 cidr  IPv4 ( IPv6).  address/y.  y  , (INET).





,  inet  ,  cidr . /8,  cidr , 24 , inet  . , 255.0.0.2/8  cidr .. 255.0.0.0  ( 2 ). 255.128.128.7/24, 255.255.255.255/31 — ,  inet  .





-?

(MacBook 16, 2019 2,6 GHz 6-Core Intel Core i7). IP-:





CREATE INDEX ON ip_ranges USING GIST (ip_range inet_ops);
      
      



(1.000.000) IP- :





DO
$$
DECLARE 
 i RECORD;
BEGIN
 FOR i IN 1..1000000 LOOP
  PERFORM country_id FROM ip_ranges WHERE ip_range >>= ‘{random_ip}’;
 end loop;
END;
$$
;
      
      



.





inet





cidr





749





891





ip4r

—  ip4r, .





, , PostgreSQL. . , .





 38 .





( ?)

 nginx,  geo , IP- .  docker-compose.yml:





version: '3.7'

services:
  web:
    image: nginx:latest
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf
      - ./GeoIP.dat:/var/geo/GeoIP.dat
      - ./geo.conf:/var/geo/geo.conf
    ports:
      - "8080:80"
    environment:
      - NGINX_PORT=80
      
      



 nginx:





http {
        ...
    geo $geo {
        default        NONE;
        include        /var/geo/geo.conf;
    }
    geoip_country /var/geo/GeoIP.dat;
        ...
    server {
        ...
        location / {
            ...
            add_header Geo-By-File $geo;
            add_header Geo-By-Binary $geoip_country_code;
        }
    }
}
      
      



,  $geo,  geo.conf :





128.0.0.0/1 US;
...
      
      



 GeoIP.dat  , ($geoip_country_code).





, . , ( , , ..).





, PostgreSQL — . , .





, ( ). , .. , - .





, , ,  inet  cidr, .  ip4r  ~20 .








All Articles