Your SlideShare is downloading. ×
Баннерокрутилка на Erlang
Баннерокрутилка на Erlang
Баннерокрутилка на Erlang
Баннерокрутилка на Erlang
Баннерокрутилка на Erlang
Баннерокрутилка на Erlang
Баннерокрутилка на Erlang
Баннерокрутилка на Erlang
Баннерокрутилка на Erlang
Баннерокрутилка на Erlang
Баннерокрутилка на Erlang
Баннерокрутилка на Erlang
Баннерокрутилка на Erlang
Баннерокрутилка на Erlang
Баннерокрутилка на Erlang
Баннерокрутилка на Erlang
Баннерокрутилка на Erlang
Баннерокрутилка на Erlang
Баннерокрутилка на Erlang
Баннерокрутилка на Erlang
Баннерокрутилка на Erlang
Баннерокрутилка на Erlang
Баннерокрутилка на Erlang
Баннерокрутилка на Erlang
Баннерокрутилка на Erlang
Баннерокрутилка на Erlang
Баннерокрутилка на Erlang
Баннерокрутилка на Erlang
Баннерокрутилка на Erlang
Баннерокрутилка на Erlang
Баннерокрутилка на Erlang
Баннерокрутилка на Erlang
Баннерокрутилка на Erlang
Баннерокрутилка на Erlang
Баннерокрутилка на Erlang
Upcoming SlideShare
Loading in...5
×

Thanks for flagging this SlideShare!

Oops! An error has occurred.

×
Saving this for later? Get the SlideShare app to save on your phone or tablet. Read anywhere, anytime – even offline.
Text the download link to your phone
Standard text messaging rates apply

Баннерокрутилка на Erlang

1,760

Published on

Published in: Technology
1 Comment
4 Likes
Statistics
Notes
No Downloads
Views
Total Views
1,760
On Slideshare
0
From Embeds
0
Number of Embeds
1
Actions
Shares
0
Downloads
16
Comments
1
Likes
4
Embeds 0
No embeds

Report content
Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
No notes for slide

Transcript

  • 1. Баннерокрутилка:как это было на Erlang
  • 2. Задача● Выдача ссылок на новости ● База из тысяч новостей ● Ссылки выбираются произвольно ● Распределение – неравномерное● Форматирование ссылок перед выдачей ● Ссылки должны иметь формат блока ● Дополнительные поля: идентификатор блока, …
  • 3. Ta-da!● Требования: >= 5000 запросов в секунду ● Не справляемся – должны быстро выдавать пустую страницу, чтобы не «ломать» вёрстку ● Никакого кэширования● Срок выполнения: полтора месяца. ● При этом у разработчика баннерокрутилки есть и другие задачи
  • 4. Структура решения● Структуры в памяти, хранящие новости и статистику показов● Множество потоков, обрабатывающих HTTP-запросы● Контроллер ● добавляющий и удаляющий новости ● собирающий статистику ● на основе TCP-сокетов
  • 5. Структура решенияМножество потоков
  • 6. Erlang● DSL для многопоточных приложений● Встроенные в язык примитивы для посылки и приёма сообщений● Встроенные в язык шаблоны поведения● Встроенная в язык in-memory БД
  • 7. Структура решения● Структуры в памяти, хранящие новости и статистику показов: mnesia/ets/dict!● Множество потоков, обрабатывающих HTTP- запросы: gen_server!● Контроллер: gen_tcp!
  • 8. Структура решения● Структуры в памяти, хранящие новости и статистику показов: mnesia/ets/dict!● Множество потоков, обрабатывающих HTTP- запросы: gen_server! ● который уже написан за нас! mochiweb/misultin● Контроллер: gen_tcp! Batteries included
  • 9. Batteries included, though not all
  • 10. Основная часть решения● HTTP-сервер Mochiweb получает запрос, создаёт поток● Поток забирает из Mnesia данные● Поток производит выборку, сортирует данные, форматирует строки, выдаёт, умирает. Все счастливы. «In theory, theres no difference between theory and practice. In practice, there is». L. A. van der Snepscheut.
  • 11. Факап #1 У каждой новости есть коэффициент важности. В соответствии с этим коэффициентом необходимо выдавать новость чаще или реже остальных.● Перед выдачей нужно назначать взвешенные произвольные числа каждой новости и делать по ним выборку.● Новостей много.
  • 12. Факап #1● Mnesia построена на основе ETS● http://www.erlang.org/doc/man/ets.html: «In the current implementation, every object insert and look-up operation results in a copy of the object.»● Т. е. в копировании сотен новостей из потока в поток. Slow as hell.
  • 13. Эврика!● Вместо ETS напишем собственную структуру данных на основе gen_server, dict, queue, blackjack и hookers.● Повесим её в виде отдельного потока● Будем делать там грубую предвыборку новостей, которые потом быстро скопируются в рабочий поток
  • 14. ● Результат: рост производительности в 3 раза● Вывод: ● всегда думай, какие объёмы данных копируешь! ● профилируй!
  • 15. Основная часть решения v0.2● HTTP-сервер Mochiweb получает запрос, создаёт поток● Поток отправляет запрос в gen_server● gen_server производит предвыборку новостей и присылает результат● Поток производит выборку, сортирует данные, форматирует строки, выдаёт, умирает. Все счастливы.
  • 16. Факап #2 Новости – это текст. Текст – это строки.● Строки в Erlang – это связные списки символов● IO в Erlang – это очень медленно
  • 17. Эврика!● Если вы пишете на Erlang, то строка символов записывается так: "Hello world!~n"● Конкатенация записывается так: "Hello " ++ Username ++ "!~n"
  • 18. Эврика!● Если вы пишете на Erlang веб-приложения, то строка символов записывается так: <<"Hello world!~n">>● Конкатенация записывается так: [<<"Hello ">>, Username, <<"!~n">>]
  • 19. Почему:● <<>> – встроенный бинарный тип● <<"">> – бинарная строка● Списки символов нужно обрабатывать перед выдачей● Вывод бинарных данных – это просто вызов writev(2) ● Blazingly Fast
  • 20. Почему:● "Hello" ++ "!n" => "Hello!n" => строка ● Конкатенация списков – O(n) ● Вывод строки => цикл по списку из 7 символов● [<<"Hello">>, <<"!n">>] – тип iolist(). ● Добавление в начало списка – O(1) ● Вывод => цикл по списку из 2 элементов ● Встроенным функциям I/O всё равно, что выводить
  • 21. Кроме того● Строковые операции, наподобие обработки регулярных выражений, всё равно дорогие● Впрочем, они вообще не очень дешевы. Обработку данных нужно делать не на этапе выдачи, а на этапе помещения в базу – до тех пор, пока позволяют объёмы памяти и специфика решаемой задачи.● В данном случае кэширование конструируемых URL новостей и т. п. позволило отыграть 15%
  • 22. ● Результат: рост производительности в 10 (десять) раз● Вывод: ● всегда думай, как обрабатывать строки! ● профилируй!
  • 23. Основная часть решения v0.3● HTTP-сервер Mochiweb получает запрос, создаёт поток● Поток отправляет запрос в gen_server● gen_server производит предвыборку новостей и присылает результат● Поток производит выборку, сортирует данные, форматирует iolist()ы, выдаёт, умирает.
  • 24. профилируй!
  • 25. Основная часть решения v0.4● HTTP-сервер Misultin получает запрос, создаёт поток● Поток отправляет запрос в gen_server● gen_server производит предвыборку новостей и присылает результат● Поток производит выборку, сортирует данные, форматирует iolist()ы, выдаёт, умирает.
  • 26. Misultin● Реализация gen_server, как и Mochiweb● Интерфейс, абсолютно аналогичный Mochiweb● Стабильно на 10-15% быстрее
  • 27. Результат● Один человекомесяц● Быстрое веб-приложение # ab -qc 7200 -n 450000 http://localhost/block/35237 | grep Requests per sec Requests per second: 7693.35 [#/sec] (mean) #
  • 28. Killing feature! Начиная со второй недели разработки (как только был написан каркас), приложение было готово к работе. В любой момент не работал только тот функционал, который не был дописан.● Ни отладки● Ни непредусмотренного поведения● Только профилирование
  • 29. Killing feature!● Ни отладки● Ни непредусмотренного поведения В Erlang есть концепция «Let it crash». Близкий перевод – «Ну и хрен с ним».
  • 30. Let it crash● На обычном языке программирования: res = web_server.start_link(callback = Fun) if res == web_server.port_in_use: raise Exception("Port in use") elif res == web_server.socket_error: raise Exception("Socket error") elif res == errno.EACCES: raise Exception("Not enough privileges")
  • 31. Let it crash● На Erlang: {ok, Pid} = misultin:start_link([{loop, Fun}]).
  • 32. Let it crash● На Erlang: {ok, Pid} = misultin:start_link([{loop, Fun}]).● Если что-то шандарахнется, то предположение misultin:start_link/1 => {ok, _} окажется неверным, и поток вылетит сам с сообщением, например, таким: {badmatch, {error, eacces}}
  • 33. Результат● Один человекомесяц● Быстрое веб-приложение● Стабильное веб-приложение – за счёт eunit и «Let it crash»● Минимум кода – за счёт множества встроенных примитивов и «Let it crash»● Минимум требуемого опыта – Erlang изучается за 2 недели
  • 34. Уровень программиста● С одной стороны, Erlang учится за 2 недели● С другой стороны, нужно иметь навыки программирования. Not all batteries included Для написания баннерокрутилки в разное время требовался то JSON-декодер, то перекодировка из UTF8 в CP1251, то htmlspecialchars(). Ничего этого в stdlib нет, нужно брать сторонние библиотеки, оценивать их работоспособность и производительность.
  • 35. Напутствие● Предобрабатывай данные, пока это дёшево!● Не выполняй одни и те же операции дважды!● Используй «Let it crash» в интерфейсах собственного кода!● Профилируй!● Переписывай медленные операции на C, PHP, OCaml, whatever: существуют открытые биндинги

×