2016-04-07 2 views
0

У нас есть таблица в нашей базе данных, которая имеет статический диапазон IP-адресов городов и их IP-адрес. Это выглядит примерно так:Как memcache или хранить пару значений ключа, когда ключ находится в диапазоне, а не одно значение?


IP-TO, IP-FROM, CITY

100, 110, A

111, 168, B

...

965, 1000, Z

Я упомянул образец данных. Реальные данные огромны с почти 64 тыс. Строк в таблице.

Для каждого пользователя на нашем веб-сайте мы определяем их город со своего IP-адреса, выполняя SQL-запрос на SQL-сервере.

Поскольку данные являются статическими, например, каждый пользователь с IP-адресом в диапазоне от 100 до 110 относится к городу A, мы без необходимости каждый раз ударяем базу данных.

Мы думали о кешировании каждого уникального посещения ip. Например: IP-100, отображенные на IP-101, отображенный на ... IP-110, отображенный на

Но это создало бы 64k ключи в кэше, и я чувствую, что нет смысла хранить кратному ключи, которые имеют такое же значение, когда мы знаем диапазон.

Можем ли мы как-то сделать это лучше, то есть с помощью минимального ключа кеша mem или с использованием другого подхода вообще?

+0

В примере я вижу, есть разница в 10 в каждый диапазон IP. Всегда ли диапазон всегда имеет постоянное значение? –

+0

Нет. Это всего лишь образец данных. Это не так. Я бы изменил это для большей ясности. – maverick

ответ

0

Список IP-адресов можно сортировать (поскольку они, по сути, являются числами). Если у вас большой неперекрывающийся список диапазонов IP, вы можете сортировать их в один большой список. Если у вас есть большой, отсортированный список значений, вы можете сделать на нем binary search. С 64 тыс. Позиций вы можете выполнять поиск всего списка примерно за 16 сравнений (практически мгновенно).

С правильными индексами и запросами ваша БД могла бы сделать это за вас. Если вы считаете, что это может быть быстрее по-другому (подсказка: используйте профилирование, чтобы определить, действительно ли это!) Или обеспокоены дополнительными поездками в базу данных, вы можете кэшировать данные всей таблицы в памяти и выполнять поиск в списке. В терминах высокого уровня:

public class IPRangeCache 
{ 
    private List<IPRangeRecord> sortedRangeRecords = null; // get from database 

    public string GetCity(IPAddress ip) { 
     // binary search to find from sortedRangeRecords 
    } 
} 

Бинарный поиск должен учитывать как начальное, так и конечное числа. Пользовательский компаратор или пользовательский двоичный поиск должны сделать это выполнимым. Это должно быть очень быстро.

Вы также можете попробовать кэшировать IP-адреса за последние несколько минут в словаре, но я думаю, что это вряд ли будет быстрее.

0

Мы можем использовать общий словарь C#.

Мы создаем класс, который содержит диапазон IP. Этот класс будет действовать как ключ к словарю.

class IP_Range 
{ 
    public int MinIP { get; set; } 
    public int MaxIP { get; set; } 
} 

Мы должны будем создать класс сравнения, который поможет в сравнении ключей словаря.

class IP_RangeComparer : IEqualityComparer<IP_Range> 
{ 
    public bool Equals(IP_Range r1, IP_Range r2) 
    { 
     return (r1.MinIP == r2.MinIP && r1.MaxIP == r2.MaxIP); 
    } 

    public int GetHashCode(IP_Range r) 
    { 
     return r.MinIP.GetHashCode(); 
    } 
} 

Затем мы можем создать общий словарь и использовать его, как показано ниже:

IDictionary<IP_Range, string> myCache = new Dictionary<IP_Range, string>(new IP_RangeComparer()); 

// Adding entries 
myCache.Add(new IP_Range() { MinIP = 100, MaxIP = 110 }, "A"); 
myCache.Add(new IP_Range() { MinIP = 111, MaxIP = 168 }, "B"); 
myCache.Add(new IP_Range() { MinIP = 169, MaxIP = 200 }, "C"); 

// Reading the dictionary 
string city = myCache[new IP_Range() { MinIP = 169, MaxIP = 200 }]; 

См this article для дальнейшего объяснения.

Примечание. Чтобы узнать ключ для конкретного IP-адреса, который вы ищете, вам придется перебирать коллекцию myCache.Keys.

0

Вы можете создать экземпляр класса IpAddressfrom the value, а затем использовать в качестве ключа кеша только one of the bytes. Таким образом, вы будете только один раз в базу данных для 001.xxx.xxx.xxx, один раз для 002.xxx.xxx.xxx и т.д.

var address = new IPAddress(value); 
var bytes = address.GetAddressBytes(); //an array of four bytes