Pull to refresh

Comments 32

Вы, ребята, молодцы. И блог у вас классный, и распространяемые приложения очень даже.

По поводу этого геолокатора: я правильно понял, что оно не кеширует результаты и при каждом явном обращении к request.location пытается определить, откуда пользователь?
По умолчанию в куке хранит, чтобы лишний раз в базу не лезть. Добавлю в доукментацию это уточнение. Спасибо
Имхо это велосипед, и nginx и апач имеют mod_geoip, которую можно развернуть в памяти. Зачем лазить в БД на каждый запрос? По-моему это бред и ересь.
GEOIP_COUNTRY_CODE and GEOIP_COUNTRY_NAME и все?
Не все, у GeoIP много баз.
$ ls *dat
GeoIPCity-532.dat GeoIP.dat GeoIPISP.dat GeoIPNetSpeed.dat GeoIPOrg.dat
Ясно. Спасибо за информацию.
На каждый запрос никто в базу не лезет, один раз для пользователя, результат геолокации для пользователя кэшируется в куке (уже писал выше). Почему в базе, а не mod_geoip, написано в статье: «потребность в создании своей модели географии, отвечающей задачам бизнес-логики». Мы сделали выбор в пользу удобства создания своих кастомных регионов на основе географии ipgeobase в ущерб скорости и пока не жалеем.
Это все также можно сделать стандартным модулем для nginx mod_geo и не лазить в базу, это будет гораздо быстрее.
А минусующие — пусть приводят аргументы.

Мое мнение — даже на каждый первый запрос лазить в базу — очень плохо, когда этого можно избежать.
А как сделать, чтобы mod_geoip работал с базой ipgeobase.ru?
да и какой толк в этой базе? Хотя бы по размеру сравните с maxmind.
У Maxmind совсем плохо с городами в России, Украине и других постСССР. В то же время в ipgeobase вообще нет городов забугорья. Так что нужно совмещать :)
Совмещать не проблема, кстати.
Так я и не говорю, что это проблема, сам делаю для своего SypexGeo. Скорее можно сказать, что качественно совмещать проблема, даже не столько проблема, сколько затратно по времени.
да можно и без mod_geo, сами используем бинарную базу от maxmind — шустро, просто
Вы правы в том, что когда можно избежать лезть в базу — лучше не лезть. А ведь может случиться так, что информация понадобится не для редиректа на поддомен, а в логике самого проекта. Простейший пример:

<p>
Выберите город, {{ request.user }}. Текущее значение – <b>{{ request.location }}</b>
</p>


Можно получить эту информацию из nginx? Думаю, что можно. Но костыли, применяемые при этом, едва ли будут менее позорны, чем лишний запрос и красивый код :-)
никаких костелей там нет

proxy_set_header GEOIP_COUNTRY_CODE $geoip_country_code;


fastcgi_param GEOIP_COUNTRY_CODE $geoip_country_code;


То есть Вы считаете, что размазать логику на два слоя — Джанги и фронтенда — это вовсе не костыль, а сделать один дополнительный запрос к БД — восьмой смертный грех? =)
Это вовсе не костыль, берем любой типичный виртуальный хостинг, GEOIP_COUNTRY_CODE вы видите в переменных окружения апача, никто на пэхопэ не залезает в базу данных GeoIP.dat. Кроме того, это эффективно работает с несколькими сайтами на сервере (хорошо если сервер ваш и пара сайтов, а если их на сервере 500), каждому отдельному скрипту на каждом отдельном виртуалхосте ненужно лазить ни в каких базы данных, будь они sql, текст или бинарник — все есть в переменных окружения сервера. И так все работает везде уже лет десять как, а то и больше.
Не поймите меня неправильно, я не спорю о том, что nginx — великолепная штука, встроенная нересурсоёмкая геолокация из коробки — это тоже замечательно и правильно.

Но случай с джангой скорее исключение. Во-первых, она сама по себе достаточно прожорлива, поэтому её запускают обычно на ВДС или в облаках. Но не на виртуальных хостингах.

ВО-вторых, как ни крути, работа с нативными питоновскими объектами удобнее, чем две строки, получаемые из внешней среды.

Чёрт возьми, а давайте помиримся? :-)

Надо всего лишь предложить ребятам написать бэкенд для получения гео-локации из окружения и тогда мы оба будем правы!
Я не ссорился ;)

Это абсолютно не нужно писать, ибо все есть в request.META
Если в приложении вам достаточно получить строку с названием города или страны — то django-geoip вам, конечно же не нужен. Я уверен, что для массы проектов request.META — более чем достаточно. Но это не наш случай и в заметке я объяснил почему.
Ну ё-моё :-)

В request.META будет простое текстовое значение типа RU. Да, его легко вывести в шаблон, но на этом сфера его пользы и заканчивается.

Совсем другое дело django-geoip: {{ request.location }} это полноценная модель, понимаете? Причём кастомизируемая. Её можно и сохранять, и расширять, и даже внешние ключи на неё вешать.

Я пару комментариев назад слово «костыли» по отношению к употребил именно с этой позиции: он может передать лишь текстовую строку, в то время как django-geoip оперирует полноценным питоновским объектом.

Для того, чтобы с тем же комфортом работать с geoip'ом инжиникса, придётся писать много кода (как раз те самые обращения к request.META). Ну, или как меня осинило, предложить ребятам сделать поддержку mod_geoip, благо, насколько я понял их код, это делается элементарно с помощью storage.
Не совсем, Storage отвечает за то, где хранится результат geoip-поиска: в куках или нигде :)
Не трогать БД в текущей реализации не получится, разве что изменив middleware. Постараюсь в следующей версии подумать над поддержкой mod_geoip.
Да, чего-то я дал маху с просмотром исходников наискосок.

А Вы лучше не над поддержкой mod_geoip подумайте, а над интерфейсом способа локации. Чтоб и в базе можно было искать, и в бинарном файле и из окружения.

Интерфейсы вообще штука хорошая :-)
Получать геолокацию из окружения не проблема, а как быть с тем, что нам нужна своя, пользовательская география, которую необходимо редактировать администрации сайта? Она хранится в базе обычно, поэтому там же для удобства их связывания хранятся и данные ipgeobase в нашем решении. Да, это не оптимально по производительности, зато позволяет контролировать всю бизнес-логику прямо в django.

Можно заморочиться и выгружать заранее подготовленные данные со своей географией в формате, который поддерживает nginx, чтобы полностью избавиться от завязки на БД. Это решение мне нравится, но пока что игра не стоит свеч для текущих проектов с их нагрузкой.
Ну так и нужно хранить пользовательскую географию в модели. А если её внезапно не оказалось, или назначать администратором, или пусть юзер при следующем заходе сам инициализирует геолокацию.

А уж как она выполняться будет — от настроек проекта зависит. Хоть sql-поиском в базе IpGeoBase, хоть напрямую из окружения nginx :-)

Ну опустим тот факт, что SQL решение будет работать значительно медленнее, чем решения с бинарными базами.
Но зачем для хранения IP использовать BIGINT? Чтобы удвоить размер таблицы и индексов? Аналогично INT для городов и регионов, да даже в GeoIP с кучей дубликатов получается около 140 тысяч городов, регионов на порядок меньше.
Плюс к этому db_index на полях start_ip и end_ip создаст два отдельных индекса, а при поиске по таблице будет использоваться один. Опять же получаем таблицу большего размера, чем необходимо.
Вы правы, unsigned int тут хватило бы. Можно также уменьшить размер первичных ключей, бесспорно. Но зачем мелочиться, если вам действительно нужна производительность в первую очередь — не надо использовать SQL-решение :) У нас trade-off производительность меняем на удобство поддержки кастомной географии.
Ну пусть география у Вас кастомная, но IP то у Вас больше 4 байт не бывают (для IPv6 всё равно BIGINT не подходит)?

К примеру, у Вас сейчас один диапазон в таблице занимает 31 байт, если туда загнать базу GeoIP, то получим около 3,5 млн. диапазонов. Я протестил на базе GeoIP, получилось 106 МБ необходимых только для данных, и еще 158 МБ на индексы, т.е. только для одной таблицы с диапазонами вам понадобится 264 МБ. При том, что бинарная база с теми же данными GeoIP весит 25 МБ, и работает значительно быстрее. Приведя в порядок типы данных таблица похудеет на 85 МБ, замечу, что при этом вы абсолютно ничего не теряете. Если же сделать грамотно, то можно в MySQL добиться где-то 40-50 МБ.

P.S. я надеюсь Вы хоть не ищите диапазон с помощью запроса типа «ip» BETWEEN start_ip AND end_ip?
Sign up to leave a comment.

Articles