2012-04-03 7 views
8

Ich habe viele IP-Bereiche von verschiedenen Anbietern. Zum BeispielSpeicher IP-Bereiche in Redis

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

ich wandle diese IP int32:

P1: 3232235786 - 3232235826, 3232236048 - 3232236081, etc 

Meine Aufgabe: zu Provider-Namen von Benutzer-IP-Adresse finden (zum Beispiel 192.168.2.20 (3232236052))

In MySQL ist es einfach:

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

Wie man das macht Gleiches mit Redis?

+0

Haben Sie Ihre IPs bereits in Redis gespeichert? Wenn ja, wie speichern Sie sie? –

+0

Ich speichere Bereiche in MySQL DB, aber eine Menge von Abfragen an MySQL für Provider-Name - es ist schrecklich :( – trong

Antwort

14

Es hängt davon ab, ob Ihre IP-Bereiche sich überlappen oder nicht. Wenn nicht, ist die Lösung ganz einfach:

  • eine Sammlung von Hash zu speichern Anbieter Daten verwenden
  • einen Zsoll indizieren verwenden Sie den Maximalwert Ihrer Bereiche
  • rufen Sie die (einmalige) Bereich, dessen max Wert größer ist als ein IP-
  • Prüfung der der Minimalwert dieses Bereichs niedriger ist als die IP

Beispiel:

Hier sind meine Provider. Jeder von ihnen wird mit einer ID identifiziert. Bitte beachten Sie, ich zu jedem Provider gebunden mehr Eigenschaften hinzufügen könnte:

> 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 

Jedes Mal, wenn ein Anbieter in dem System hinzugefügt wird, muss ein Index beibehalten werden (manuell: Das ist Redis, nicht eine relationale Datenbank). Score ist der maximale Wert, member ist die ID des Bereichs.

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

nun die einzigartige Palette entsprechend einer IP-Adresse abfragen, müssen Sie 2 Rundreisen:

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

das Client-Programm Dann muss nur prüfen, ob Ihre IP größer oder gleich als die minimale Adresse ist des zurückgegebenen Bereichs.

Nun, wenn Sie die Bereiche überlappen können, ist die Lösung viel komplexer, und es wurde bereits here erläutert.

9

Meiner Meinung nach wäre die beste Lösung sorted set.

Um den Bereich zu verwenden, verwenden Sie ZADD.
Zu member range_name zuweisen.
Zu score höchsten Wert im Bereich zuweisen.

ZADD ip_table 3232235826 some_name 

Dann für die Suche nach Bereich Verwendung ZRANGEBYSCORE mit user_ip als min_value und limit = 1.

ZRANGEBYSCORE ip_table user_ip +inf LIMIT 0 1 

Es wird mit kleinster ip am Endpunkt findet Bereich, der größer oder gleich user_ip ist.

+0

Wie erhalten Sie den Namen des Anbieters in Ihrer Implementierung? – trong

+0

Mitglied sollte Name des Anbieters enthalten. Ich habe es korrigiert. –

0

Wenn Sie diese Daten für einen Anbieter wie MaxMind erhalten, sind möglicherweise bereits Bibliotheken verfügbar, um dies schnell und effizient durchzuführen. Ich denke nicht, dass Sie in diesem Fall viel Leistung mit Redis erzielen werden.

+0

Ja, ich habe einen Benchmark durchgeführt und festgestellt, dass die Verwendung von redis zum Nachschlagen 10 mal langsamer ist – stupidbodo