Подозреваю, что большая часть из вас не придала большого значения выходу нового яндексового сервиса "Куда все идут", про который мы пока официально нигде даже не написали. Кроме того, сервис расчитан на молодежь с экстравертивным складом характера, которая любит собираться куда-то веселой гурьбой, а многие программисты наоборот — чаще интроверты и затворники.

Но для меня это сейчас — Сервис с большой буквы, потому что именно это тот самый "большой сервис на Джанго", который я до сего времени периодически упоминал, и который мы писали аж с мая прошлого года. И вот мы его выпустили в прошлый вторник, за остаток недели отловили несколько веселых багов, и теперь я хочу представить вам свое пострелизное мыслеизлияние :-).

Исторические факты

Просто так для завтравки хочется привести несколько фактов, которые никуда особенно больше не приткнешь.

Изменчивая судьба

Немножко подробней хочу рассказать про последний пункт.

Автор общей идеи о разработке сервисов в Яндексе на Джанго — Григорий Бакунов (Bobuk). И хоть человек он харизматичный, и слушают его обычно внимательно, такая большая идея, как использование нового фреймворка, нуждается в серьезных основаниях. Особенно учитывая, что в Яндексе есть свой работающий и отлаженный способ делать веб-приложения. Поэтому концепция разработки сервисов на Джанго изначально называлась "прототипированием". Если я правильно понимаю, предполагалось быстро делать "на каком-то там Питоне" прототип, а после этого, если сервис всем нравится, его надо было переписать заново (!) по-нормальному :-).

У нас же отношение было немного другое. Надо было сделать сервис так, чтобы он показал, что эта модель разработки вполне серьезная, и что переписывать ничего не надо. Поэтому проектировалось все сразу не как прототип, а как продукт. Ну и в итоге где-то в конце лета мы осознали, что из рамок прототипирования давно выросли, обросли некоторым количеством фичастых идей, и пришлось де-факто признать, что мы делаем уже таки полноценный продукт.

Это было про смену концепции разработки. Смена концепции сервиса звучит прозаичней. Изначально Офлайн задумывался так, что будет жестко завязан на сервис Я.ру. А потом идея поменялась на то, что сервисом могут пользоваться и люди, у которых нет странички на Я.ру. Скажете, "всего-то"? Для нас это значило в середине разработке, когда основной объем кода уже был и работал, что у нас появляется целый новый класс пользователей — те, у кого нет дневника на Я.ру. А значит у них нет аватаров, имен и "друзей" (в Я.рушном понимании). И значит по всему коду мы должны были обработать все места, где преполагалось, что все это уже есть. И самое главное: нужно было приделать в наш интерфейс совершенно новую форму заведения страницы в Я.ру, которая серьезно поменяла интерфейс присоединения к событию, а также чувствительно усложнила этот процесс внутри. А, и еще мы получили под конец большой ворох дурацких проблем с подсчетом количества людей, потому что цифры перестали совпадать с количеством аватарок, которые мы отображаем. Я думаю, там до сих пор еще могут вылезать всякие несоответствия :-)

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

Смена же верстальщика означает, что пока view-source сайту делать рано: верстка сейчас представляет смесь двух разных подходов. Наш нынешний верстальщик — Женя Якушевский, с которым у меня есть уверенность, что мы в итоге доведем сайт до очень хорошего и, что немаловажно, модного технологического уровня.

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

Программирование

За время работы над проектом моя уверенность в надежности выбранного иструмента укрепилась. Мы не встретили никаких фатальных проблем, и всегда имели возможность быстро реагировать на меняющиеся требования. Звучит, возможно, слегка рекламно, но это действительно так. Вот только связного изложения истории у меня, уж простите, на этот раз не получится. Ограничусь дайджестом вещей, которые помню, и которые кажутся интересными.

Это мой первый проект, где бо́льшую часть кода я пишу не сам. Пока что я все еще учусь ускользающему навыку под названием "передача отвественности". Это когда, получая описание какой-то фичи, мне нужно думать не о том, как я буду писать код, а о том, что надо перевести описание задачи в термины нашей архитектуры и передать ее другому программисту. И еще очень сложно привыкнуть к тому, что другой человек пишет код совсем не так, как ты сам, и разделять при ревью кода то, что нужно сделать объективно по-другому, и то, что просто выглядит странно лично для ревьюера. Я вообще думаю, что наш программист Ваня Бибилов скоро будет меня тихо ненавидеть за мелочные докапывания к названиям переменных :-).

Также, признаюсь, это мой первый проект, где я решил, что без тестов нам не обойтись, начал их сам писать, а затем втянул в это и Ваню тоже. Эффект мне понравился, мы ловим тестами довольно много регрессий. Не нравится пока только то, что тестов мало, потому что писать их, все же, труднее, чем я ожидал. Одна из интересных особенностей в том, что у нас в системе очень много тестов завязано на понятия типа "события в прошлом" и "события в будущем". Но поскольку текущее время всегда меняется, не получается сделать один фиксированный набор тестовых данных: он устаревает. Поэтому сейчас у нас есть код, который перед каждым тестом подгоняет времена событий под текущий момент.

В Яндексе принятая стратегия масштабирования доступа к БД — репликация. Наша же система эту стратегию не использует, потому что в Джанго это неудобно. Поэтому вместо того, чтобы распределять нагрузку на чтение из БД по репликам, мы активно используем кеширование в memcached. Впрочем, в ближайшее время я хочу таки заняться написанием БД-бэкенда для Джанги, который репликацию использовать будет. Иначе админы меня съедят :-)

Во время разработки я все время настаивал на том, чтобы мы не занимались тонкой оптимизацией по производительности. И чем дальше, тем больше я думаю, что это правильный подход. Система сильно менялась, во многих тяжелых запросах необходимость просто отпала, а некоторые наоборот появились. Если бы мы каждый раз тратили время на оптимизацию, много бы потеряли. Занявшись же оптимизацией в самом конце, мы потратили на нее примерно неделю. Больше всего тормозов добавляла старая как мир проблема — слишком много запросов в базу из-за доставания дополнительных данных отдельными запросами на каждый объект. Лечилось обычно: кешированием в памяти, хранением в таблицах предрасчитанных количеств, использованием SQL-запросов с "group by".

В процессе оптимизации родилось несколько полезных вещей, которые могут кому-нибудь пригодиться:

Про финальную производительность говорить особенного смысла нет, она не показательна. Меряли мы все на тестовой конфигурации, которая от боевой отличается тем, что там была одна машина вместо четырех, а на боевой сервис еще не так много народу ходит, чтобы посмотреть, что он выдерживает. Плюс ко всему, задачи заоптимизировать все вусмерть не было, надо было достигнуть некого проектного минимума. Но для того, чтобы было над чем позубоскалить в комментариях, все же скажу, что на одной машине система выдает 20 запросов в секунду. Это медленно, и во многом виной тому то, что система местами показывает данные в излишне (на мой взгляд) сложном виде. Например простая выборка событий в каталоге за период времени нагружена сортировкой по числу людей, присоединившихся к ним. Это добавляет в запрос немаленькую таблицу этих самых присоединений. Впрочем, и это все обходится, если надо. Пока справляемся :-)

Интересный момент, который я вначале никак не предвосхищал — расположение статических файлов, как CSS'а с Javascript'ом, так и файлов от пользователей. Как я уже сказал, у нас четыре машины, на которых крутится Джанго. Запросы к ним распределяются равномерно неким балансером. Запрос от пользователя, который загружает по HTTP некий файл (картинку), приходит на одну из машин, и сохраняется в локальную файловую систему. Другой запрос, которому нужна будет эта картинка, может прийти на совсем другую машину, и файла этого на ней не окажется. Решений у этой задачи, на самом деле, много, и я даже использовал ее на собеседованиях, когда мы искали программистов. Мы пока решили ее так, что запустили на всех этих машинах распределенную файловую систему — GPFS — которая объединяет несколько директорий с разных машин в одно пространство. И сейчас каждая машина считает, что складывает и забирает файлы к себе, хотя реально может таскать их с какой-то из соседних. К слову сказать, для Джанги сейчас есть практически готовая система подключаемых файловых бэкендов, которая отучит ее складывать файлы всегда только на локальный диск, и тогда проблемы такого рода можно будет решать более гибко.

Главное — trunk

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

Вскоре (пока еще не планировали когда именно) у нас будет очередной релиз версии уже 1.1, в основном построенный на комментариях после запуска. Хотя будет и кое-что новое интересное. А за ней будут еще и еще. И через какое-то время, я надеюсь, сервис действительно станет полезным :-).

Комментарии: 46 (feed)

  1. bsn

    поздравляю с запуском! :)

  2. dms

    А я после того, как увидел этот сервис в первый раз, всё думал, на django он или нет) Поздравляю с новым проектом!

  3. FX Poster

    Ну что ж, с открытием! :)

  4. Voidus

    С открытием :) А список городов будет расширяться?

  5. MajestiC

    Отличная статья =) Как раз пришла по RSS в то время, когда я думал над распределением загруженных файлов по серверам.

    Иван, а какие еще варианты вы рассматривали, кроме GPFS. Интересны варианты с не Общей файловой системой. А конкретно для заливки файла с многих разных серверов на 1.

  6. Муркт

    Внутреннее изначальное название сервиса — “Яндекс.Офлайн”. Подразумевалось, что это сервис по организации встреч друзей в офлайне. Я продолжаю поминать его по этому имени, потому что во-первых привык, а во-вторых оно короче и проще склоняется (то есть склоняется в принципе).

    Надо просто «Куда все идут» делать как бы одним словом:

    — Ты чем занимаешься?

    — Куда-все-идутом!

    ;)

  7. MockSoul

    давайте уже сделаем бранч а-ля "django future" с экспериментальным лечением очевидных вещей. С большим количеством запросов для доставания счетчиков, связанной инфы и тп борятся по-моему все достаточно крупные проекты на джанго. Да, есть бранчи queryset-refactor и интеграция с sqlalchemy.. но первый слишком уж радикален, а второй совсем все меняет.

    Идея: бранч, который будет работоспобным для текущих проектов, но добавит горстку вещей для оптимизации по уменьшению кол-ва запросов.

    А то все чинят в одиночку кто во что горазд.

    В целом же использование джанго яндексом не может не радовать. Так или иначе к яндексу у девелоперов отношение хорошее, хотя я лично считаю многие сервисы бесполезными. Субъективно, конечно же. Я ведь программист - а значит, по Вашей схеме - затворник =).

    Хехе.. джанго (в данном контексте - питон) в умелых руках удивительно полезный инструмент. В неумелых - куча головной боли. Так или иначе будет способствовать отсеву "не-совсем-программистов" =).

  8. lusever js

    Т.е. на джанго проект делало два человека?

  9. Иван Сагалаев

    Т.е. на джанго проект делало два человека?

    Я в статье всех перечислил: менеджер, программист, верстальщик и я, как архитектор.

  10. Иван Сагалаев

    Да, есть бранчи queryset-refactor и интеграция с sqlalchemy.. но первый слишком уж радикален

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

    Но главное, я не считаю денормализацию (то есть хранение в базе предрасчитанных значений) хаком. Напротив, это быстрее, чем использование group by. А использование ORM позволяет реализовывать такой предрасчет надежно, потому что есть в коде точки, через которые проходят все изменения данных.

  11. MockSoul

    Но главное, я не считаю денормализацию (то есть хранение в базе предрасчитанных значений) хаком. Напротив, это быстрее, чем использование group by. А использование ORM позволяет реализовывать такой предрасчет надежно, потому что есть в коде точки, через которые проходят все изменения данны

    Да, но предрасчет счетчиков - это разве единственное? Распространённая проблема с select_related() и внешними ключами которые могут быть NULL.. Где-то я и у Вас тут по-моему фикс видел. Но не ручаюсь =). А например невозможность толком научить ORM кешировать какие-либо таблицы целиком автоматически. Ну вот например всякие списки городов те же. Да если честно много чего придумать можно =).

  12. Alex Lebedev
        <blockquote>
    

    <p>Одна из интересных особенностей в том, что у нас в системе очень много тестов завязано на понятия типа “события в прошлом” и “события в будущем”. Но поскольку текущее время всегда меняется, не получается сделать один фиксированный набор тестовых данных: он устаревает. Поэтому сейчас у нас есть код, который перед каждым тестом подгоняет времена событий под текущий момент.</p> </blockquote> <p>Помимо регенерации тестовых данных, видел два понравившихся мне подхода к решению этой проблемы:</p> <ol> <li> <p>Заворачиваем все обращения к текущим дате и времени в класс, который в тестовом режиме умеет возвращать не текущее время, а то, что ему сказали вернуть.</p> </li> <li> <p>Развитие первого подхода — используем любую mock-библиотеку и устанавливаем возвращаемые дату и время для стандартных системных функций.</p> </li> </ol> <p>По сравнению с динамически генерируемыми тестовыми данными гораздо легче тестировать логику типа "сделать X, затем в течение 10 дней отслеживать событие Y и если оно произойдет, сообщить пользователю" — можно играть в "машину времени" в рамках одного тестового сценария.</p>

  13. Юревич Юрий

    Полностью согласен с Алексеем. Я использую первый подход (с кастомным классом).

  14. Igorekk

    Поздравляю :) Я там отметился еще в пятницу. Правда, отмеченное событие продинамил, увы.

  15. Иван Сагалаев

    Алексей, Юрий, эта идея была. Благо, в Питоне достаточно просто подменить глобальную функцию времени для каждого теста. Но пока мы к этому не пришли, потому что хочется тестировать с реально меняющимся временем, так как система ведет себя по-разному. Например, после 19:00 у нас "протухают" сегодняшние события без четкого указания времени начала (выставки, например). Пару раз мы действительно ловили баги с этим, а также с витиеватыми понятиями "эта неделя", которое может включать от 4 до 10 дней :-). Впрочем, возможно действительно перейдем на одно или несколько предустановленных времен.

  16. kitich

    Ах вот оно как у вас в Яндексе все) Забавно было почитать )

    ЗЫ Кстати, почему-то не получилось под опенид залогиниться к вам...

  17. Alex Lebedev

    Ага, с OpenID какие-то проблемы. Пробовал залогиниться с помощью OpenID от MoiKrug.ru, получил сообщение об отсутствии эккаунта.

  18. zhur

    Для работы с репликами можно попробовать MySQL Proxy и RW Splitting. Сам не пробовал ;-)

  19. Иван Сагалаев

    Обещал выложить код кеширующего менеджера для справочных таблиц. Вот он: http://www.djangosnippets.org/snippets/560/

  20. Салихов Ильяс

    А можно поинтересоваться, какая сейчас посещаемость у сервиса, и на какую расчитываете, если не секрет ;)

    Просто я помню, как на РИТ-2007 Bobuk как раз высказывал свое мнение, что в Яндексе целесообразно использовать Django при посещаемости до 30 тыс. пользователей, выше — надо использовать уже отработанную схему.

  21. Иван Сагалаев

    Я разузнаю, не является ли это у нас NDA (очень вероятно, что является). Но в любом случае, мне и тогда казалось, что про 30 тысяч он поосторожничал :-).

  22. bobuk

    Речь шла о 30 тысячах на узел один узел.

  23. Михаил Евстафьев

    Забавный проект? Я думаю если бы Яндекс аннонсировал его на главной странице, то посещаемость увеличалась в разы. Кстати а почему до сих пор не аннонсировали?

  24. Иван Сагалаев

    Всему свое время :-). Я не уверен, что это будет главная страница, но наверняка где-нибудь его рекламировать будут. Постепенный запуск — это удобно. Меньше людей страдают от неожиданных багов, и у нас есть больше времени на исправления и изменения.

  25. Иван Сагалаев

    Компьюлента взяла у меня интервью про "Куда все идут": http://soft.compulenta.ru/346012/. Особо нового там ничего нет, но просто для истории пусть будет :-)

  26. Igorekk

    И сделали пару опечаток: "Янедксе" и "Сагалавева" :(

  27. Александр Пугачёв

    А вы не рассматривали использование SQLRelay (http://sqlrelay.sourceforge.net/sqlrelay/) для поддержки принятой в Яндексе схемы репликации? Вроде бы можно настроить для него правила так, что Джанго будет работать как работала, при этом запись будет идти в мастер-сервер, а чтение будет производиться из слейв-сервера (http://sqlrelay.sourceforge.net/sqlrelay/router.html)).

  28. Иван Сагалаев

    Рассматривали, причем не только SQLRelay. Но это не подходит, потому что раскидывает соединения на уровне отдельных операторов. А нужно — на уровне транзакций. Представьте такой сценарий:

    1. началась транзакция
    2. сделали UPDATE, который на мастер
    3. сделали SELECT, в расчете на то, что UPDATE изменил как-то данные, но он пошел на слейв

    Вот в 3 пункте SELECT не увидит данных от предыдущего UPDATE, потому что выполняется на другом сервере, в то время, как на первом транзакция еще не скоммичена.

  29. Sergey Panfilov

    Вопрос немного не по теме. Очень нравится прозрачное копирование сообщений из ЖЖ в журнал на я.ру. Как бы подкинуть идею команде разработчиков фотки.я.ру проделать то же самое с фликром?
    P.S. Спасибо за интересный расказ идет работа в Яндексе изнутри.

  30. Иван Сагалаев

    В Фотки написать лучше всего через стандартную обратную связь, ссылка есть внизу страницы на индексе Фоток: http://feedback.yandex.ru/?from=fotki

  31. Sergey Panfilov

    Спасибо

  32. Иван Матвеев

    Sergey Panfilov, известная идея, ага. Спасибо.

  33. http://onopko.livejournal.com/

    Хотелось бы услышать мнение разработчиков (например Вани Бибилова) о вкладе использования django, как новой технологии, в общее увеличение сроков проекта. А так же о вкладе менеджеров в увеличение этих сроков.

  34. Бибилов Иван

    Хотелось бы услышать мнение разработчиков (например Вани Бибилова) о вкладе использования django, как новой
    технологии, в общее увеличение сроков проекта. А так же о вкладе менеджеров в увеличение этих сроков.

    По моим ощущениям, основное время уходит именно на обдумывание того, "как это должно быть" менеджерами. Само программирование происходит довольно-таки быстро (субъективное ощущение). Т.е. реализовали фичу, дали посмотреть менеджерам, по результатам переделали / убрали вообще / видоизменили, повторили процесс по необходимости.

    Django позволяет поддерживать высокий темп в плане того, что от задумки до реализации проходит малый промежуток времени, после чего интерфейс (с точки зрения пользователя) можно "пощупать", внести коррективы и т.д.

    Т.к. это мой первый проект на Django, то сначала это сказывалось на скорости и качестве разработки (было медленно и некачественно, иногда быстро, но все равно некачественно). Чуткое руководство Ивана Сагалаева со временем это исправило.

    По ходу разработки вставали разнообразные технические вопросы:

    • Прикрутить стороннюю авторизацию (яндексовскую).
    • Производительность (слава memcached).
    • Кастомные SQL-запросы (в обход встроенного ORM).
    • Тестирование.
    • Многое, многое другое...

    Что-то решилось штатными средствами Django, что-то пришлось докручивать.

    Django - идеологически выстроенный web framework, на большинство вопросов веб-разработки он дает готовые ответы, а на что ответов нет, исправляется без насилия над мозгом и Django.

    Главное то, что полету мысли менеджеров Django не препятствовал, задумки реализовывались, и продукт со временем оформлялся в нечто идеологически целостное.

  35. Костя

    Спасибо, впервые узнаю из Вашего блога про Django и про новый сервис Яндекса - спасибо за информацию.
    И еще, откуда у Вас сведения о действиях Яндекса, интересно?!

  36. HEm
  37. Igorek

    Спасибо, впервые узнаю из Вашего блога про Django и про новый сервис Яндекса - спасибо за информацию.
    И еще, откуда у Вас сведения о действиях Яндекса, интересно?!

    Если бы Вы повнимательнее прочитали, то поняли, что Иван там работает :)

  38. vitalikwork

    Поздравляем

  39. Replica

    А давно сервис запущен? Как то промоушена небыло, народу там мало, хотя Яндекс мог бы создать куда большую посещаемость

  40. Иван Сагалаев

    Запустились 13 января (там в начале статьи про это написано :-) ). Промоушена действительно не было, потому что надо ж понять, как оно работает. Прошедший месяц мы как раз подчищали всякие нехорошести. А промоушен будет конечно со временем.

  41. spforth

    Прошедший месяц мы как раз подчищали всякие нехорошести.
    А промоушен будет конечно со временем.

    Если там приглашения потенциальным участникам "сходки" высылаются через сервис - то это и будет автоматическим промоушеном, никакой другой и не потребуется, Если, конечно, сервис понравится первым участникам.

  42. grey-evil

    Я в статье всех перечислил: менеджер, программист, верстальщик и я, как архитектор.

    Не всех :)

  43. Иван Сагалаев

    А, действительно... Извини! Исправляюсь.

    Сергей Горобцов (grey-evil) был верстальщиком где-то до середины проекта, работая еще как аутсорсер.

  44. Шон

    Почему Django, а не Ruby on Rails?

  45. Раньше все бекэнды раздавали медию с общего сетевого хранилища. Но это не правильно с точки зрения отказоустойчивости, т.к.если отвалится хранилище, то вся медиа исчезнет разом. Тут Ваня как и обещал придумал и реализовал крутую систему репликации медиа файлов на машинах кластера. Я уверен он её обязательно поделится с общественностью в скором времени. И там есть на что посмотреть - действительно получилась полезное и концептуально красивое приложение.

  46. Куда все идут. Иван Сагалаев. Рассказывает о другом яндекс сервисе.

Добавить комментарий

Format with markdown