2012-04-03 52 views
8

我有很多不同提供者的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相同?

+0

您是否已將IP存儲在Redis中?如果是的話,你如何存儲它們? – 2012-04-03 07:49:55

+0

我在MySQL數據庫中存儲了一個範圍,但是很多向MySQL獲取提供者名稱的查詢 - 這很糟糕:( – trong 2012-04-03 10:00:47

回答

14

這取決於你是否認爲你的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的,而不是一個關係數據庫)。分數是最大值,成員是範圍的ID。

> 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是比最小地址大於或等於返回的範圍。

現在,如果您考慮範圍可以重疊,解決方案要複雜得多,它已經被解釋爲here

9

我認爲最好的解決方案是sorted set

要插入範圍使用ZADD
member指定range_name。
score指定範圍內的最高值。

ZADD ip_table 3232235826 some_name 

然後查找範圍使用ZRANGEBYSCORE與user_ip如MIN_VALUE和極限= 1

ZRANGEBYSCORE ip_table user_ip +inf LIMIT 0 1 

它會找到範圍與端點最小的ip大於或等於user_ip。

+0

如何在您的實現中獲取提供者的名稱? – trong 2012-04-03 09:58:56

+0

成員應該包含提供者的名稱,我已經更正了它。 – 2012-04-03 10:02:01

0

如果您正在爲像MaxMind這樣的供應商獲取這些數據,可能已有庫可用來快速高效地完成此操作。在這種情況下,我認爲你不會使用Redis獲得很多性能。

+0

是的,我做了一些基準測試,發現使用redis查找速度慢了10倍 – stupidbodo 2013-04-13 10:39:49