|
Декларативное рулит
|
|
|
| RWA Contest |
[Окт. 26, 2011|15:47 pm] |
Тут по моему старому проекту возникла задачка: сделать фильтрацию по диапазонам IP-адресов. Буду делать quick and dirty-реализацию на си с классами, если кто возжелает, может реализовать на своём любимом языке а потом сравним.
Задача такова: есть ASCIIZ-строка с IP-адресом, надо вернуть true, если этот адрес попадает в один из диапазонов, перечисленных в файле.
Файл текстовый такого формата,
192.168.1.3,192.168.1.5 192.168.2.4,193.0.0.3
Файл не отсортирован, дипапазоны произвольные и могут пересекаться. Первый адрес меньше второго или равен ему. Пересечение диапазонов можно обрабатывать двумя путями: лиюо отказываться грузить такой файл и выдавать что с чем пересеклось, либо не отказываться и корректно работать в таких условиях.
Файл грузится один раз и потом десятки миллионов раз лукапится. Записей в конфиге - сотни.
UPD: я не спрашивал, как мне это имплементить - задача школьная. Я просил добровольцев из числа читателей заимплементить это на ФЯ и померить. |
|
|
| Comments: |
Хорошая, студентам подкину.
From: (Anonymous) 2011-10-26 01:02 pm none (UTC)
| (Link)
|
Эх, реализовано такое уже в libgeoip, простой битовый trie.
А какие ограничения? Тупо сделать 512Мб массив битовых флагов, заполнить битом 1 диапазоны, и быстрее уже ничего не может быть. Разве что за счёт локальности памяти и кэша процессора -- на каком мерять собираются?
Не, 512 мбайт у нас нету. 1 ядро Xeon Core2, детальнее пока не скажу.
Binary search по списку границ, после устранения дублей и пересечений любым способом, думаю, будет быстрее всего, раз сотни.
ну или hashtables тоже можно.
Т. е. IP-адреса указываются не целыми префиксами, а такими вот диапазонами? Если не секрет, в чём смысл такой задачи?
смысла много разного.
1) для вычисления CIDR нужна отдельная тулза, а минимальный и максимальный IP можно определить по набору IP в логе визуально
2) пользователи не знают, что такое CIDR
3) фильтрация по CIDR не имеет физического смысла
У нас нечто подобное забыдлокоджено "в лоб". Масив пар лонгов "старт, енд". А потом приводим искомый адрес тоже в лонг, и тупым перебором и сравнением по этому масиву. Для пар сотен запесей работает заебца, как по мне.
Ну, у нас есть нехорошая тенденция разрастания всех конфигов до гигабайта, поэтому линейный поиск - это уж совсем ахтунг.
Один из текущих IP-фильтров разросся до 128к индивидуальных айпишников, с этим тоже такое может произойти, т.е. стараемся писать масштабируемо, если это не требует значительных работ. Случай с линейным vs бинарным поиском - как раз то.
From: (Anonymous) 2011-10-26 05:34 pm none (UTC)
| (Link)
|
Обычно для range lookup используются multiway range trees и segment trees. Для пересекающихся диапазонов можно сначала сделать "нормализацию".
у нас не "обычно":
1) нет обновлений 2) нет префиксов 3) нет задачи искать самый длинный префикс
В топку.
![[User Picture]](http://l-userpic.livejournal.com/55864689/10329734) | From: os80 2011-10-26 06:59 pm none (UTC)
| (Link)
|
Я не понял, как потом сравнивать будем.
Псевдокод:
sub find(ip_str)
{
ip_uint32 = ip2int(ip_str)
forall (entry in config)
{
if ip_uint32 >= entry.start && ip.uint32 <= entry.end
return true
}
return false
}
Идея должна быть понятна. Алгоритм, разумеется, должен быть быстрее линейного.
Навскидку, то что за полчаса написалось на эрланге.
http://ubuntuone.com/4jM6BSoxbUrRhipSCBGLni
А что мерить то?
Вариант номер 2 - дерево (первый вариант был через hashtable). http://ubuntuone.com/4pHqBhfOJvUnoraop5uJYx (http://ubuntuone.com/4pHqBhfOJvUnoraop5uJYx)
Работает так:
F = iptree:read("RU_ipranges.txt").
Естественно со своим именем файла. Результат - функция для проверки. Типа
3> F = iptree:read("RU_ipranges.txt").
4> F("192.168.1.1"). not_found 5> F("46.28.130.1"). found
Надо срочно писать ответ на node.js :)
Не указана важная деталь — реакция программы на ошибки.
Это специально сделано. Всё неспецифицированное можно делать как угодно.
![[User Picture]](http://l-userpic.livejournal.com/85095969/17388596) | From: pingback_bot 2011-10-27 10:20 pm none (UTC)
Попробовал задачку <lj user=nponeccop>. | (Link)
|
User inv2004 referenced to your post from RWA Contest saying: [...] насочинял для этой [...]
From: (Anonymous) 2011-10-29 05:31 pm none (UTC)
| (Link)
|
Выше thesz уже спрашивал - важно ли находить сам диапазон, в который попал IP? Иначе можно обойтись 3-мя изначально нулевыми матрицами a,b,c размера 256x256. Если есть адрес 100.101.102.103, то a[100,101]=1, b[101,102]=1, c[102,103]=1. И так для каждого IP из диапазонов в процессе прочтения файла (долго, что делать, но зато искать проще). Поиск как строить имхо очевидно и должно получиться достаточно быстро. Матрицы можно размотать в массивы стандартным образом, конечно.
//EO
Сам диапазон находить не нужно
![[User Picture]](http://l-userpic.livejournal.com/96083761/5827944) | From: gliv 2011-10-31 03:10 pm none (UTC)
| (Link)
|
А у количества данных какие порядки? Сколько диапазонов? Сколько IP- адресов?
IP-адресов - от тысяч до миллиарда. Причём из-за дурацкой архитектуры распараллеливания нельзя проверять адреса пачками (т.е. передавать в проверялку можно только по одному).
Диапазонов - единицы тысяч.
![[User Picture]](http://l-userpic.livejournal.com/85095969/17388596) | From: pingback_bot 2011-10-31 07:27 pm none (UTC)
решение задачи про фильтрацию IP-адресов на хаскеле | (Link)
|
| |
|
|