Как написатьмасшабируемуюбаннерокрутилкуБирюков Денис,компания Каванга
Задачи перед сервисом• Производительность  – сейчас: 1000 баннеров/сек.  – хотим: 10 000 баннеров/сек.  – время отклика < ...
Задачи (прод.)• Таргетинги  –   Стандартные (UserAgent, geo …).  –   Стандартные ограничения, скорость, бюджет.  –   Станд...
Резюмируем свойства• Горизонтально масштабируемый (до 10000  хитов/сек). Перекрутов, в идеале, быть не  должно.• Многопото...
Схема сервиса в целомПлощадка    Клиент               Пользователь     Пользователь                        hadoop     PHP ...
UUServer•   Кука всего 4 KB – мало.•   Очень близко к хранилищу key/value.•   Выдача данных по TCP (свой протокол).•   При...
UUServer (прод.)• Внутри 64 независимых дерева - боремся с  локами и балансировками дерева при  вставке.• Раз в 5 мин запу...
Схема uuserverTCP запрос       UPD пакет (событие)                 UPD пакет (событие)      foreach(libs)                 ...
Схема front                                 nginxfastcgiexp            UUserver           fastcgievent       fastcgidummyf...
Cache• Хранит много объектов, если примитивно, то  std::map(u_int64_t, std::vector<...sort...> *).  Значение в каждой запи...
Cache (прод.)• Есть таблички, данные в которых меняются часто  (счетчики) — изменения приходят как из СУБД  так и от Count...
Cache: логика обновления                                            CacheInOut {TCP запрос     Данные из СУБД             ...
Cache: выбор баннеровTCP запрос     WaitToRead(),…                                Find place, geo                         ...
Cache: инкрементация (2экз)                                Есть 2 экземпляра     Increment(…)              Счетчиков (Read...
FastCgiExp• Сервер – и диспетчер и обработчик.• Есть пулы нитей (nginx (fastcgi), cache, uuserver).• В каждом процессе хра...
FastCgiExp: запросFastCgi запрос    Выбрать Нить               PoolThread FastCgi    Dummy         CheckReferer           ...
FastCgiEvent: запросFastCgi запрос        Выбрать Нить     PoolThread FastCgi     204             Выделить Нить     PoolTh...
FastCgiDummy: запросFastCgi запрос     Выделить Нить       PoolThread FastCgi                 UDP to SearchServerFastCgi о...
Что дальше?• Постоянные изменения логики движка  (поддержка).• Написать антинакрутчик (aio).• Переписать UUserver (aio) ?•...
Что дальше? (прод.)• Новые интерфейсы рекламодателям и  владельцам площадок (и поддержка и  юзабилити).• Соцдем.• Новые от...
Оптимизация трафикаТрафика много, денег     Возможно мало униковмало?                         Возможно сейчас у нас нет ре...
Тестирование. Машина.Процессор   Intel(R) Xeon(R) CPU E5630 @ 2.53GHz (2527.30-MHz K8-            class CPU), 2x4 coreПамя...
Тестирование. Бенчмарк.denis:/home/bdn# /usr/sbin/ab -r -c100 -n10000 -b2048 -C kui1v=777 "http://10.5.1.50/exp?sid=5&bt=5...
Тестирование. TOP.[root@mega ~]# toplast pid: 10965; load averages: 13.32, 6.52, 3.64               up1+23:47:28 16:18:526...
Тестирование. TOP.PID     UN THR PRI NICE SIZE     RES      STATE    C   TIME     WCPU COMMAND2583    kbe 54 47 0 220M    ...
Масшабируемаябаннерокрутилка:как это былона ErlangАртем Гавриченков,Highload Lab
Задача• Выдача ссылок на новости  – База из тысяч новостей  – Ссылки выбираются произвольно  – Распределение – неравномерн...
Ta-da!• Требования: >= 5000 запросов в секунду  – Не справляемся – должны быстро выдавать    пустую страницу, чтобы не «ло...
Схема решения• Структуры в памяти, хранящие новости  и статистику показов• Множество потоков, обрабатывающих HTTP-запросы•...
Схема решенияСтруктуры в памяти, хранящие новостии статистику показовМножество потоков, обрабатывающих запросыКонтроллер д...
Erlang• DSL для многопоточных приложений• Встроенные в язык примитивы для посылки и  приёма сообщений• Встроенные в язык ш...
Схема решения• Структуры в памяти, хранящие новости  и статистику показов: mnesia/ets/dict!• Множество потоков, обрабатыва...
Схема решения• Структуры в памяти, хранящие новости  и статистику показов: mnesia/ets/dict!• Множество потоков, обрабатыва...
Batteries included, though not all
Костяк решения• HTTP-сервер Mochiweb получает запрос, создаёт поток• Поток забирает из Mnesia данные• Поток производит выб...
Факап #1 У каждой новости есть коэффициент важности. В соответствии с этим коэффициентом необходимо выдавать новость чаще ...
Факап #1• Mnesia построена на основе ETS• http://www.erlang.org/doc/man/ets.html:    «In the current implementation, every...
Эврика:• Вместо ETS напишем собственную структуру  данных на основе gen_server, dict, queue,  blackjack и hookers.• Повеси...
Результат:  рост производительности в 3 разаВывод: – всегда думай, что копируешь! – профилируй!
Костяк решения v0.2• HTTP-сервер Mochiweb получает запрос, создаёт поток• Поток отправляет запрос в gen_server• gen_server...
Факап #2 Новости – это текст. Текст – это строки.• Строки в Erlang – это связные списки  символов• IO в Erlang – это очень...
Эврика:• Если вы пишете на Erlang,  то строка символов записывается так:               "Hello world!~n"• Конкатенация запи...
Эврика:• Если вы пишете на Erlang веб-приложения,  то строка символов записывается так:            <<"Hello world!~n">>• К...
Почему:• <<>> – встроенный бинарный тип• <<"">> – бинарная строка• Списки символов нужно обрабатывать  перед выдачей• Выво...
Почему:• "Hello" ++ "!n" => "Hello!n" => строка  – Конкатенация списков – O(n)  – Вывод строки => цикл по списку из 7 симв...
Кроме того:• Строковые операции, наподобие обработки  регулярных выражений, всё равно дорогие• Впрочем, они вообще не очен...
Результат:  рост производительности в 10 (десять) разВывод: – всегда думай, как обрабатывать строки! – профилируй!
Костяк решения v0.3• HTTP-сервер Mochiweb получает запрос, создаёт поток• Поток отправляет запрос в gen_server• gen_server...
Результат:  рост производительности в 10 (десять) разВывод:  всегда думай, как обрабатывать строки!  профилируй!
Костяк решения v0.4• HTTP-сервер Misultin получает запрос, создаёт поток• Поток отправляет запрос в gen_server• gen_server...
Misultin• Реализация gen_server, как и Mochiweb• Интерфейс, аналогичный Mochiweb• Стабильно на 10-15% быстрее
Результат• Один человекомесяц• Быстрое веб-приложение# ab -qc 7200 -n 450000 http://localhost/block/35237| grep Requests p...
Killing feature!  Начиная со второй недели разработки (как  только был написан каркас), приложение  было готово к работе.•...
Killing feature!• Ни отладки• Ни непредусмотренного поведения  В Erlang есть концепция «Let it crash».  Близкий перевод – ...
Let it crash• На обычном языке программирования: res = web_server.start_link(callback = F) if res == web_server.port_in_us...
Let it crash• На Erlang {ok, Pid} = misultin:start_link([{loop, F}]). if res == web_server.port_in_use:     raise Exceptio...
Let it crash• На Erlang {ok, Pid} = misultin:start_link([{loop, F}]). if res == web_server.port_in_use:     raise Exceptio...
Результат• Один человекомесяц• Быстрое веб-приложение• Стабильное веб-приложение  – eunit и «Let it crash»• Минимум кода  ...
Уровень кодера• С одной стороны, Erlang учится за 2 недели• С другой стороны, нужно иметь навыки  программирования. Not al...
Напутствие•   Предобрабатывай данные, пока это дёшево!•   Не выполняй одни и те же операции дважды!•   Используй «Let it c...
Блокировки. (опц.)pthread_rwlock_t rwlock; // 1       • Блокировки нужныpthread_rwlock_rdlock(&rwlock);       многопоточны...
Блокировки. (прод.) (опц.)volatile int lock = 0; // 3 (0-unlock, 1-lock)while (__sync_bool_compare_and_swap(&lock, 0, 1)){...
SearchServer (java) (опц.)• Поисковые РК: трафика и пользователей нужно  много (чем быстрее отдадим пользователю  поисковы...
SearchServer (java) (прод.) • Сервер хочется сделать независимым   (манипуляции с ним не должны влиять на   основной движо...
SearchServer: схема (опц.) РК8                                                                           РК3              ...
Тестирование. Конфиг (опц.)[root@mega /usr/local/kbe]# cat etc/kbe.conf###################################################...
Тестирование. Конфиг (опц.)# Delay to connect "dead" UUserver (in microseconds)repeat_time_to_uuserver=1000000# Thread cou...
Тестирование. Конфиг (опц.)# Maximum possible clients connected through Unix socketmax_internal_clients=110# Maximum possi...
Upcoming SlideShare
Loading in …5
×

как написать масштабируемую баннерокрутилку. денис бирюков, артем гавриченков. зал 3

3,583 views

Published on

1 Comment
1 Like
Statistics
Notes
  • По поводу блокировок: a) думаю стоило упомянуть RCU b) Возможно вместо usleep(10) в lock’е имело смысл использовать sched_yield/cpu_relax
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here
No Downloads
Views
Total views
3,583
On SlideShare
0
From Embeds
0
Number of Embeds
162
Actions
Shares
0
Downloads
15
Comments
1
Likes
1
Embeds 0
No embeds

No notes for slide

как написать масштабируемую баннерокрутилку. денис бирюков, артем гавриченков. зал 3

  1. 1. Как написатьмасшабируемуюбаннерокрутилкуБирюков Денис,компания Каванга
  2. 2. Задачи перед сервисом• Производительность – сейчас: 1000 баннеров/сек. – хотим: 10 000 баннеров/сек. – время отклика < 200 миллисекунд.• 365*24*7, обязательно отдать контент (хотя бы заглушку).• Много площадок (>1.000), много баннеров (>100.000).
  3. 3. Задачи (прод.)• Таргетинги – Стандартные (UserAgent, geo …). – Стандартные ограничения, скорость, бюджет. – Стандартные уникальные ограничения. – Аудиторные таргетинги (ретагетинг: бумеранг, поисковый, соцдем).• Точный подсчёт показов, кликов и событий, начислений и списаний денег.
  4. 4. Резюмируем свойства• Горизонтально масштабируемый (до 10000 хитов/сек). Перекрутов, в идеале, быть не должно.• Многопоточный (медленные запросы не должны держать быстрые). Минимизировать блокировки.• Синхронизация серверов в режиме “реального времени” (уменьшаем перекруты).
  5. 5. Схема сервиса в целомПлощадка Клиент Пользователь Пользователь hadoop PHP nginx hadoop front front SearchServer MySQL uuserver sphinx соцдем uuserver
  6. 6. UUServer• Кука всего 4 KB – мало.• Очень близко к хранилищу key/value.• Выдача данных по TCP (свой протокол).• Прием данных по UDP (свой протокол).• Масштабируемый.• Многопоточный (много блокировок).
  7. 7. UUServer (прод.)• Внутри 64 независимых дерева - боремся с локами и балансировками дерева при вставке.• Раз в 5 мин запускается цикл сохранения пользователей на диск.• Классический ретаргетинг организован плагинами на стороне uuserver.• Соединения ‘постоянные’.
  8. 8. Схема uuserverTCP запрос UPD пакет (событие) UPD пакет (событие) foreach(libs) {Retargeting;}Выбор mapПоиск user Выбираем очередь Выбор map Выбор map Поиск user Анализ Поиск user Map.insert(…) Выбираем очередьTCP ответ Increment, Update;
  9. 9. Схема front nginxfastcgiexp UUserver fastcgievent fastcgidummyfastcgiexp UUserver fastcgievent fastcgidummy CounterQueue MySQL cache Syslog Gearman sender receiverSearchServer hadoop receiver sender
  10. 10. Cache• Хранит много объектов, если примитивно, то std::map(u_int64_t, std::vector<...sort...> *). Значение в каждой записи — это табличка из СУБД.• Объекты — берутся из базы данных (она отвечает за сортировку и за целостность данных).• Данные в некоторых табличках меняются редко (площадки, рекламные кампании, цены), или очень редко (гео база) — изменения всегда приходят из СУБД.
  11. 11. Cache (прод.)• Есть таблички, данные в которых меняются часто (счетчики) — изменения приходят как из СУБД так и от CounterQueue.• Многопоточный (на каждое соединение — свой поток).• Соединения постоянные.• Блокировки (чтение/запись) накладываются на всю таблицу.
  12. 12. Cache: логика обновления CacheInOut {TCP запрос Данные из СУБД u_int32_t size; u_int32_t func; Анализ и char data[size]; построение } ‘таблички’ WaitToWrite()TCP ответ Данные из Cache Swap(std::vector<...>*) Delete old data Done()
  13. 13. Cache: выбор баннеровTCP запрос WaitToRead(),… Find place, geo Сортировка РК foreach(PK) {Targets;}TCP ответ Done(),… result
  14. 14. Cache: инкрементация (2экз) Есть 2 экземпляра Increment(…) Счетчиков (Readers-1) WaitToWrite() TCP запрос Call Increment(2) foreach(…){ Increment; syslog(...);} Swap(1,2) TCP ответ Done() Call Increment(2)
  15. 15. FastCgiExp• Сервер – и диспетчер и обработчик.• Есть пулы нитей (nginx (fastcgi), cache, uuserver).• В каждом процессе хранятся тела баннеров, заглушек и ссылок (доступ к ним производиться через read/write блокировку).• Настройка количества listen сокетов, размеры пулов, количество процессов производится редактированием файла конфигурации, с последующим перезапуском.
  16. 16. FastCgiExp: запросFastCgi запрос Выбрать Нить PoolThread FastCgi Dummy CheckReferer UDP to SearchServer FastCgi ответ Выделить Нить PoolThread UUServer Get User Info PoolThread Cache mq_send(…) mq_send(…) Выделить Нить Get BannerIdUDP to UUserver Banner
  17. 17. FastCgiEvent: запросFastCgi запрос Выбрать Нить PoolThread FastCgi 204 Выделить Нить PoolThread UUServerFastCgi ответ Get User Info mq_send(…) Get Location mq_send(…) UDP to UUserver
  18. 18. FastCgiDummy: запросFastCgi запрос Выделить Нить PoolThread FastCgi UDP to SearchServerFastCgi ответ Dummy
  19. 19. Что дальше?• Постоянные изменения логики движка (поддержка).• Написать антинакрутчик (aio).• Переписать UUserver (aio) ?• Мониторинг серверов (zabbix).
  20. 20. Что дальше? (прод.)• Новые интерфейсы рекламодателям и владельцам площадок (и поддержка и юзабилити).• Соцдем.• Новые отчеты (hadoop).• Мониторинг серверов (zabbix).
  21. 21. Оптимизация трафикаТрафика много, денег Возможно мало униковмало? Возможно сейчас у нас нет рекламы для вас (новые форматы) Возможно вы хотите много денег, или другие таргетинги.Опрашивайте рекламные движки каскадомДелитесь информацией о своих юзерах
  22. 22. Тестирование. Машина.Процессор Intel(R) Xeon(R) CPU E5630 @ 2.53GHz (2527.30-MHz K8- class CPU), 2x4 coreПамять 96 GBnload Incoming: Outgoing: Curr: 13.65 MBit/s Curr: 57.67 MBit/s Avg: 16.72 MBit/s Avg: 3.93 MBit/s Min: 5.52 kBit/s Min: 1.02 kBit/s Max: 66.14 MBit/s Max: 16.60 MBit/s Ttl: 783.21 MByte Ttl: 402.25 MBytenetstat 27 LISTEN 625 SYN_SENT 42 CLOSE_WAIT 971 LAST_ACK 42 FIN_WAIT_2 1928 ESTABLISHED 73 CLOSED 23593 TIME_WAIT
  23. 23. Тестирование. Бенчмарк.denis:/home/bdn# /usr/sbin/ab -r -c100 -n10000 -b2048 -C kui1v=777 "http://10.5.1.50/exp?sid=5&bt=5&bn=1&bc=3&ct=2" 100/10000 100/10000 100/50000 100/50000 1000/10000 10000/10000 1000/50000 10000/50000 4050 500 450 4000 400 микросек 3950 350 кол-во 3900 300 запросов 250 3850 в сек 200 3800 150 100 3750 50 3700 0 % % % % % % % % % одновременные 0 0 6 5 0 0 5 8 9 0 5 6 7 8 9 9 9 9 1 соединения / кол-во запросов всего доля запросов
  24. 24. Тестирование. TOP.[root@mega ~]# toplast pid: 10965; load averages: 13.32, 6.52, 3.64 up1+23:47:28 16:18:52646 processes: 8 running, 638 sleepingCPU: 55.2% user, 0.0% nice, 14.3% system, 7.2% interrupt, 23.3% idleMem: 18G Active, 1610M Inact, 11G Wired, 136K Cache, 9833M Buf, 63GFreeSwap: 4096M Total, 4096M Free
  25. 25. Тестирование. TOP.PID UN THR PRI NICE SIZE RES STATE C TIME WCPU COMMAND2583 kbe 54 47 0 220M 147M CPU7 7 21:25 353.47% cache706 root 1 73 0 6956K 1520K RUN 7 4:29 23.39% syslogd10890 www 1 65 0 50268K 36736K RUN 1 1:01 18.46% nginx10891 www 1 67 0 42076K 30064K RUN 1 0:56 18.16% nginx2615 kbe 49 44 0 76784K 22176K nanslp 0 1:42 11.52% fcgiexp2616 kbe 49 44 0 78832K 22268K nanslp 1 1:43 11.43% fcgiexp2617 кbe 49 44 0 82672K 20876K nanslp 0 1:40 11.33% fcgiexp2613 kbe 49 44 0 78704K 21924K nanslp 0 1:43 11.23% fcgiexp2614 kbe 49 44 0 80752K 22112K nanslp 1 1:42 11.04% fcgiexp1557 kbe 170 44 0 18291M 18159M sbwait 5 100:46 3.52% uuserver2609 kbe 3 44 0 28944K 4052K nanslp 0 0:06 1.07% sender2605 kbe 3 44 0 47372K 4232K nanslp 7 0:08 0.98% counterqueue2626 kbe 73 44 0 62856K 22464K nanslp 5 0:16 0.00% fcgievent2639 kbe 73 44 0 62856K 22472K nanslp 3 0:16 0.00% fcgievent1013 root 1 44 0 12064K 4152K select 3 0:02 0.00% sendmail10889 root 1 76 0 17500K 6024K pause 2 0:00 0.00% nginx
  26. 26. Масшабируемаябаннерокрутилка:как это былона ErlangАртем Гавриченков,Highload Lab
  27. 27. Задача• Выдача ссылок на новости – База из тысяч новостей – Ссылки выбираются произвольно – Распределение – неравномерное• Форматирование ссылок перед выдачей – Ссылки должны иметь формат блока – Дополнительные поля: идентификатор блока, …
  28. 28. Ta-da!• Требования: >= 5000 запросов в секунду – Не справляемся – должны быстро выдавать пустую страницу, чтобы не «ломать» вёрстку – Никакого кэширования• Срок выполнения: полтора месяца. – При этом у разработчика баннерокрутилки есть и другие задачи
  29. 29. Схема решения• Структуры в памяти, хранящие новости и статистику показов• Множество потоков, обрабатывающих HTTP-запросы• Контроллер – добавляющий и удаляющий новости – собирающий статистику – на основе TCP-сокетов
  30. 30. Схема решенияСтруктуры в памяти, хранящие новостии статистику показовМножество потоков, обрабатывающих запросыКонтроллер добавляющий и удаляющий новости собирающий статистику на основе TCP-сокетов
  31. 31. Erlang• DSL для многопоточных приложений• Встроенные в язык примитивы для посылки и приёма сообщений• Встроенные в язык шаблоны поведения• Встроенная в язык in-memory БД
  32. 32. Схема решения• Структуры в памяти, хранящие новости и статистику показов: mnesia/ets/dict!• Множество потоков, обрабатывающих HTTP-запросы: gen_server!• Контроллер: gen_tcp! добавляющий и удаляющий новости собирающий статистику на основе TCP-сокетов
  33. 33. Схема решения• Структуры в памяти, хранящие новости и статистику показов: mnesia/ets/dict!• Множество потоков, обрабатывающих HTTP-запросы: gen_server! – который уже написан за нас! mochiweb/misultin• Контроллер: gen_tcp! добавляющий и удаляющий новости собирающий статистику Batteries included на основе TCP-сокетов
  34. 34. Batteries included, though not all
  35. 35. Костяк решения• HTTP-сервер Mochiweb получает запрос, создаёт поток• Поток забирает из Mnesia данные• Поток производит выборку, сортирует данные, форматирует строки, выдаёт, умирает. Все счастливы. «In theory, theres no difference between theory and practice. In practice, there is». L. A. van der Snepscheut.
  36. 36. Факап #1 У каждой новости есть коэффициент важности. В соответствии с этим коэффициентом необходимо выдавать новость чаще или реже остальных.• Перед выдачей нужно назначать взвешенные произвольные числа каждой новости и делать по ним выборку.• Новостей много.
  37. 37. Факап #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.
  38. 38. Эврика:• Вместо ETS напишем собственную структуру данных на основе gen_server, dict, queue, blackjack и hookers.• Повесим её в виде отдельного потока• Будем делать там грубую предвыборку новостей, которые потом быстро скопируются в рабочий поток
  39. 39. Результат: рост производительности в 3 разаВывод: – всегда думай, что копируешь! – профилируй!
  40. 40. Костяк решения v0.2• HTTP-сервер Mochiweb получает запрос, создаёт поток• Поток отправляет запрос в gen_server• gen_server производит предвыборку новостей и присылает результат• Поток производит выборку, сортирует данные, форматирует строки, выдаёт, умирает. Все счастливы.
  41. 41. Факап #2 Новости – это текст. Текст – это строки.• Строки в Erlang – это связные списки символов• IO в Erlang – это очень медленно
  42. 42. Эврика:• Если вы пишете на Erlang, то строка символов записывается так: "Hello world!~n"• Конкатенация записывается так: "Hello " ++ Username ++ "!~n"
  43. 43. Эврика:• Если вы пишете на Erlang веб-приложения, то строка символов записывается так: <<"Hello world!~n">>• Конкатенация записывается так: [<<"Hello ">>, Username, <<"!~n">>]
  44. 44. Почему:• <<>> – встроенный бинарный тип• <<"">> – бинарная строка• Списки символов нужно обрабатывать перед выдачей• Вывод бинарных данных – это просто вызов writev(2) – Blazingly Fast
  45. 45. Почему:• "Hello" ++ "!n" => "Hello!n" => строка – Конкатенация списков – O(n) – Вывод строки => цикл по списку из 7 символов• [<<"Hello">>, <<"!n">>] – тип iolist() – Добавление в начало списка – O(1) – Вывод => цикл по списку из 2 элементов – Built-in функциям I/O всё равно, что выводить
  46. 46. Кроме того:• Строковые операции, наподобие обработки регулярных выражений, всё равно дорогие• Впрочем, они вообще не очень дешевы. Надо делать предобработку• Кэширование конструируемых URL новостей и т. п. позволило отыграть 15%
  47. 47. Результат: рост производительности в 10 (десять) разВывод: – всегда думай, как обрабатывать строки! – профилируй!
  48. 48. Костяк решения v0.3• HTTP-сервер Mochiweb получает запрос, создаёт поток• Поток отправляет запрос в gen_server• gen_server производит предвыборку новостей и присылает результат• Поток производит выборку, сортирует данные, форматирует iolist()ы, выдаёт, умирает.
  49. 49. Результат: рост производительности в 10 (десять) разВывод: всегда думай, как обрабатывать строки! профилируй!
  50. 50. Костяк решения v0.4• HTTP-сервер Misultin получает запрос, создаёт поток• Поток отправляет запрос в gen_server• gen_server производит предвыборку новостей и присылает результат• Поток производит выборку, сортирует данные, форматирует iolist()ы, выдаёт, умирает.
  51. 51. Misultin• Реализация gen_server, как и Mochiweb• Интерфейс, аналогичный Mochiweb• Стабильно на 10-15% быстрее
  52. 52. Результат• Один человекомесяц• Быстрое веб-приложение# ab -qc 7200 -n 450000 http://localhost/block/35237| grep Requests per secRequests per second: 7693.35 [#/sec] (mean)#
  53. 53. Killing feature! Начиная со второй недели разработки (как только был написан каркас), приложение было готово к работе.• Ни отладки• Ни непредусмотренного поведения• Только фичи и профилирование
  54. 54. Killing feature!• Ни отладки• Ни непредусмотренного поведения В Erlang есть концепция «Let it crash». Близкий перевод – «Ну и хрен с ним».
  55. 55. Let it crash• На обычном языке программирования: res = web_server.start_link(callback = F) 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")
  56. 56. Let it crash• На Erlang {ok, Pid} = misultin:start_link([{loop, F}]). 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")
  57. 57. Let it crash• На Erlang {ok, Pid} = misultin:start_link([{loop, F}]). if res == web_server.port_in_use: raise Exception("Port in use") Not ok? {badmatch, {error, eacces}} raise Exception("Socket error") elif res == errno.EACCES: raise Exception("Not enough privileges")
  58. 58. Результат• Один человекомесяц• Быстрое веб-приложение• Стабильное веб-приложение – eunit и «Let it crash»• Минимум кода – множество встроенных примитивов и «Let it crash»• Минимум требуемого опыта
  59. 59. Уровень кодера• С одной стороны, Erlang учится за 2 недели• С другой стороны, нужно иметь навыки программирования. Not all batteries included
  60. 60. Напутствие• Предобрабатывай данные, пока это дёшево!• Не выполняй одни и те же операции дважды!• Используй «Let it crash» в интерфейсах• Профилируй!• Переписывай медленные операции на C, PHP, OCaml, whatever
  61. 61. Блокировки. (опц.)pthread_rwlock_t rwlock; // 1 • Блокировки нужныpthread_rwlock_rdlock(&rwlock); многопоточным серверам (время отклика клиентам//pthread_rwlock_wrlock(&rwlock); очень отличается от...do something... запроса к запросу)pthread_rwlock_unlock(&rwlock); • Возможно вы кроме функции блокировкиpthread_mutex_t mtx; // 2 вызовете еще и планировщик (если потокpthread_mutex_lock(&mtx); будет заблокирован)...do something...pthread_mutex_unlock(&mtx);
  62. 62. Блокировки. (прод.) (опц.)volatile int lock = 0; // 3 (0-unlock, 1-lock)while (__sync_bool_compare_and_swap(&lock, 0, 1)){usleep(10);}...do something...lock = 0;• Если вы уверенны что блокировки потоков ПОЧТИ не будет — используйте 3-й тип• Если обработка запроса ВСЕГДА БЫСТРАЯ — а почему не aio?
  63. 63. SearchServer (java) (опц.)• Поисковые РК: трафика и пользователей нужно много (чем быстрее отдадим пользователю поисковый баннер тем лучше).• Интересных поисковых фраз много (сейчас пару тысяч).• Запросов пользователей много – мы примерно 100 пользователей в сек добавляем в различные поисковые аудитории.
  64. 64. SearchServer (java) (прод.) • Сервер хочется сделать независимым (манипуляции с ним не должны влиять на основной движок). • Перебор Regexp.match() перестал работать уже на паре сотен поисковых фраз. • Хочется учесть семантику русского языка и не заставлять менеджеров вводить все возможные сочетания слов в фразе (стемминг).
  65. 65. SearchServer: схема (опц.) РК8 РК3 Аудитория1 Аудитория2 РК2 РК5 Дом за КАД Дома … Домашний уют В доме … После стемминга и lowcast дом кад дом … домашн уют дом … После применения hash {230 5589} {230} … {389 501} {230} …Обратный индекс … 230 … Пользователь ввел:UDP: PK2,РК8,РК3,РК5 230 {230} дом “у дома”
  66. 66. Тестирование. Конфиг (опц.)[root@mega /usr/local/kbe]# cat etc/kbe.conf########################################################################### Counters from different processs come in this queue, and than sended to cache process ############################################################################ Maximum messages in system queue, numbercounter_queue_circ_buff_capacity=60000# Name for system queue. path (string) - only small sibols in root foldercounter_queue=/cache_counter_queue# Maximum messages in system queue, numbermax_msg_in_queue=200# Maximum messages in internal queue (if it more, theyll send to cache), numbermax_internal_queuq_len=5# Period time when thread send counters to cache, microsecondstime_for_periodic_counters_send=1000000# Time for limit wait data from system queue, (for reaction on TERM), nanosecondstime_for_max_queue_wait=110000000# Time for limit wait data from read process, (for reaction on TERM), nanosecondstime_for_max_condition_wait=220000000
  67. 67. Тестирование. Конфиг (опц.)# Delay to connect "dead" UUserver (in microseconds)repeat_time_to_uuserver=1000000# Thread count in cache pool, numberthread_count_in_pool_cache=10# Thread count in pool unique user, numberthread_count_in_pool_unique_user_exp=10# Time out for request for wait cache in cache queue, microsecondstime_out_in_pool_cache_queue=200000# Time out for request for wait unique user in unique user queue,in microsecondstime_out_in_pool_unique_user_queue=200000# Number of main fast cgi exposure processfast_cgi_exp_process_number=5# Ports for fastcgiexp, string - divided by , ## For main process (check nginx nginx.conf)fast_cgi_1_exp_ports=:9000,:9200,:9201fast_cgi_2_exp_ports=:9040,:9300,:9301fast_cgi_3_exp_ports=:9010,:9400,:9401fast_cgi_4_exp_ports=:9020,:9500,:9501fast_cgi_5_exp_ports=:9030,:9600,:9601# Number of threads processing the request on one socketfast_cgi_exp_concurency_for_port=5
  68. 68. Тестирование. Конфиг (опц.)# Maximum possible clients connected through Unix socketmax_internal_clients=110# Maximum possible clients connected through TCP socketmax_external_clients=10cache_external_port=1030cache_external_addr=127.0.0.1cache_internal_port=1031cache_internal_addr=/tmp/InternalSocketName#################################################### Parameters for pool initialised in fastcgidummy ##################################################### Number of main fast cgi exposure processfast_cgi_dummy_process_number=2# Ports for fastcgilight, string - divided by , ## For main process (check nginx nginx.conf)fast_cgi_1_dummy_ports=:9010,:9700fast_cgi_2_dummy_ports=:9020,:9800# Number of threads processing the request on one socketfast_cgi_dummy_concurency_for_port=10

×