<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Insight IT</title><link>https://www.insight-it.ru/</link><description></description><atom:link href="https://www.insight-it.ru/feed/index.xml" rel="self"></atom:link><lastBuildDate>Sun, 07 Jun 2015 22:45:00 +0300</lastBuildDate><item><title>Что стоит знать о памяти в Linux?</title><link>https://www.insight-it.ru//linux/2015/chto-stoit-znat-o-pamiati-v-linux/</link><description>&lt;p&gt;Подсистема работы с оперативной памятью в &lt;a href="/tag/linux/"&gt;Linux&lt;/a&gt; - достаточно многогранная конструкция. Чтобы разобраться в её деталях нужно целенаправленно погрузиться в тему, с обязательным чтением исходников ядра, но это нужно не каждому. Для разработки и эксплуатации серверного программного обеспечения важно иметь хотябы базовое предстваление о том, как она работает, но меня не перестает удивлять насколько небольшая доля людей им обладает. В этом посте я постараюсь кратко пробежаться по основным вещам, без понимания которых на мой взгляд очень легко натворить глупостей.
&lt;!--more--&gt;&lt;/p&gt;
&lt;h2 id="kakaia-byvaet-pamiat"&gt;Какая бывает память?&lt;/h2&gt;
&lt;h3 id="fizicheskaia-i-virtualnaia"&gt;Физическая и виртуальная&lt;/h3&gt;
&lt;p&gt;Начнем издалека. В спецификации любого компьютера и в частности сервера непременно числится надпись "N гигабайт оперативной памяти" - именно столько в его распоряжении находится &lt;em&gt;физической&lt;/em&gt; памяти.&lt;/p&gt;
&lt;p&gt;Задача распределения доступных ресурсов между исполняемым программным обеспечением, в том числе и &lt;em&gt;физической&lt;/em&gt; памяти, лежит на плечах операционной системы, в нашем случае Linux. Для обеспечения иллюзии полной независимости, она предоставляет каждой из программ свое &lt;strong&gt;независимое&lt;/strong&gt; &lt;em&gt;виртуальное&lt;/em&gt; адресное пространство и низкоуровневый интерфейс работы с ним. Это избавляет их от необходимости знать друг о друге, размере доступной &lt;em&gt;физической&lt;/em&gt; памяти и текущей её занятости. Адреса в виртуальном пространстве процессов называют &lt;strong&gt;логическими&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Для отслеживания соответствия между физической и виртуальной памятью ядро Linux использует иерархический набор структур данных в своей служебной области &lt;em&gt;физической&lt;/em&gt; памяти (только оно работает с ней напрямую), а также специализированные аппаратные контуры, которые в совокупности называют &lt;abbr title="Memory Management Unit"&gt;MMU&lt;/abbr&gt;.&lt;/p&gt;
&lt;p&gt;Следить за каждым байтом памяти в отдельности было бы накладно, по-этому ядро оперирует достаточно большими блоками памяти - &lt;strong&gt;страницами&lt;/strong&gt;, типовой размер которых составляет 4 килобайта.&lt;/p&gt;
&lt;p&gt;Также стоит упомянуть, что на аппаратном уровне как правило есть поддержка дополнительного уровня абстракции в виде "сегментов" оперативной памяти, с помощью которых можно разделять программы на части. В отличии от других операционных систем, в Linux она практически не используется - логический адрес всегда совпадает с линейным (адресом внутри сегмента, которые сконфигурированы фиксированным образом).&lt;/p&gt;
&lt;h3 id="failovaia-i-anonimnaia"&gt;Файловая и анонимная&lt;/h3&gt;
&lt;p&gt;У приложений существует много способов выделить себе память для тех или иных нужд. Высокоуровневые языки программирования и библиотеки часто прячут от разработчиков какой из них в реальности использовался и другие детали (хотя их всегда можно "раскусить" с помощью &lt;code&gt;strace&lt;/code&gt;). Если углубляться в особенности каждого доступного варианта, эта статья быстро бы превратилась в книгу. Вместо этого предлагаю разделить их на две, на мой взгляд, крайне важные группы по тому, какую память они выделяют:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Файловой&lt;/strong&gt; памяти однозначно соответствует какой-либо файл или его часть в файловой системе. Первым делом в ней как правило находится исполняемый код самой программы. Для прикладных задач можно запросить отображение файла в виртуальное адресное пространство процесса с помощью системного вызова &lt;code&gt;mmap&lt;/code&gt; - после чего с ним можно работать как с любой другой областью памяти без явного чтения/записи, что будет при этом происходить с данными в файловой системе и что будут видеть другие процессы "отобразившие" этот же файл зависит от настроек.&lt;/li&gt;
&lt;li&gt;Любую другую выделенную память называют &lt;strong&gt;анонимной&lt;/strong&gt;, так как ей не соответствует никакой файл, которые как известно именованы. Сюда попадают как переменные на стеке, так и области, выделенные с помощью функций вроде &lt;code&gt;malloc&lt;/code&gt; (к слову, за сценой для выделения больших блоков памяти они обычно тоже используют &lt;code&gt;mmap&lt;/code&gt; с особым набором настроек, а для всего остального - &lt;code&gt;brk/sbrk&lt;/code&gt; или выдают ранее освобожденную память).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;На первый взгляд отличия не выглядят чем-то особенным, но тот факт, что области файловой памяти именованы, позволяет операционной системе экономить физическую память, порой очень значительно, сопоставляя виртуальные адреса нескольких процессов, работающих с одним и тем же файлом, одной физической странице в памяти. Это работает прозрачно, начиная от кода запущенных нескольких копий приложений, заканчивая специально сконструированными под эту оптимизацию систем.&lt;/p&gt;
&lt;h3 id="vytesniaemaia-i-net"&gt;Вытесняемая и нет&lt;/h3&gt;
&lt;p&gt;Суммарный объем используемой виртуальной памяти всех программ запросто может превышать объем доступной физической памяти. При этом в каждый конкретный момент времени приложениями может использоваться лишь небольшое подмножество хранимых по виртуальным адресам данных. Это означает, что операционная система может откладывать не используемые в данный момент данные из оперативной памяти на жесткий диск ("вытесняя"" их из памяти), а затем при попытке к этим данным обратиться - скопировать обратно в физическую оперативную память.
Этот механизм официально называется &lt;strong&gt;major page fault&lt;/strong&gt;, но под просто page fault как правило подразумевают тоже её, так как minor page fault мало кого заботит (отличие в том, что в случае minor ядру удается найти запрашиваемые данные уже загруженными в память с какой-то другой целью и обращения к диску в итоге не происходит).&lt;/p&gt;
&lt;p&gt;На время восстановления запрашиваемых приложением данных его выполнение &lt;em&gt;прерывается&lt;/em&gt; и управление передается ядру для выполнения соответствующей процедуры. Время, которое потребуется, чтобы приложение смогло продолжить свою работу, напрямую зависит от типа используемого жесткого диска:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Прочитать 4Кб данных с обычного серверного жесткого диска 7200rpm занимает порядка &lt;strong&gt;10 мс&lt;/strong&gt;, при хорошем стечении обстоятельств чуть меньше.&lt;ul&gt;
&lt;li&gt;Если вытесненных страниц оказывается много, запросто могут набегать заметные доли секунды (как условным пользователям, так и на внутренних приборах, в зависимости от задачи).&lt;/li&gt;
&lt;li&gt;Особенно опасны циклические pagefaults, когда есть две или более регулярно используемые области памяти, которые вместе не помещаются в физическую память, по-этому бесконечно вытесняют друг друга туда-обратно.&lt;/li&gt;
&lt;li&gt;При этом диск вынужден делать честный seek, что само по себе тоже может быть не кстати. Например, если с этим же диском работает какая-либо база данных.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Если используется &lt;abbr title="Solid State Drive"&gt;SSD&lt;/abbr&gt;, то ситуация несколько более радужная - из-за отсутствия механического движения аналогичная операция занимает примерно на порядок меньше, около &lt;strong&gt;1 мс&lt;/strong&gt; или её доли, в зависимости от типа и конкретной модели диска. Но годы идут, а &lt;abbr title="Solid State Drive"&gt;SSD&lt;/abbr&gt; так и остаются нишевым компромиссным продуктом по цене-объему.&lt;/li&gt;
&lt;li&gt;А теперь для сравнения: если бы страница уже была в памяти, то при обращении к ней счет шел бы на &lt;strong&gt;сотни наносекунд&lt;/strong&gt;. Это почти &lt;em&gt;на 4 порядка быстрее&lt;/em&gt;, чем pagefault, даже на &lt;abbr title="Solid State Drive"&gt;SSD&lt;/abbr&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Стоит отметить, что с точки зрения приложения всё это прозрачно и является внешним воздействием, то есть может происходить в самый не подходящий, с точки зрения решаемой им задачи, момент.&lt;/p&gt;
&lt;p&gt;Думаю понятно, что приложения, которым важна высокая производительность и стабильное время отклика, должны избегать pagefault'ов всеми доступными методами, к ним и перейдем.&lt;/p&gt;
&lt;h2 id="metody-upravleniia-podsistemoi-pamiati_1"&gt;Методы управления подсистемой памяти&lt;/h2&gt;
&lt;h3 id="swap"&gt;&lt;del&gt;swap&lt;/del&gt;&lt;/h3&gt;
&lt;p&gt;С файловой памятью всё просто: если данные в ней не менялись, то для её вытеснения делать особо ничего не нужно - просто перетираешь, а затем всегда можно восстановить из файловой системы.&lt;/p&gt;
&lt;p&gt;С анонимной памятью такой трюк не работает: ей не соответствует никакой файл, по-этому чтобы данные не пропали безвозвратно, их нужно положить куда-то ещё. Для этого можно использовать так называемый "swap" раздел или файл. Можно, но на практике не нужно. Если swap выключен, то анонимная память становится невытесняемой, что делает время обращения к ней предсказуемым.&lt;/p&gt;
&lt;p&gt;Может показаться минусом выключенного swap, что, например, если у приложения утекает память, то оно будет гарантированно зря держать физическую память (утекшая не сможет быть вытеснена). Но на подобные вещи скорее стоит смотреть с той точки зрения, что это наоборот поможет раньше обнаружить и устранить ошибку.&lt;/p&gt;
&lt;h3 id="mlock"&gt;mlock&lt;/h3&gt;
&lt;p&gt;По-умолчанию вся файловая память является вытесняемой, но ядро Linux предоставляет возможность запрещать её вытеснение с точностью не только до файлов, но и до страниц внутри файла.&lt;/p&gt;
&lt;p&gt;Для этого используется системный вызов &lt;code&gt;mlock&lt;/code&gt; на области виртуальной памяти, полученной с помощью &lt;code&gt;mmap&lt;/code&gt;. Если спускаться до уровня системных вызовов не хочется, рекомендую посмотреть в сторону консольной утилиты &lt;code&gt;vmtouch&lt;/code&gt;, которая делает ровно то же самое, но снаружи относительно приложения.&lt;/p&gt;
&lt;p&gt;Несколько примеров, когда это может быть целесообразно:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;У приложения большой исполняемый файл с большим количеством ветвлений, некоторые из которых срабатывают редко, но регулярно. Такого стоит избегать и по другим причинам, но если иначе никак, то чтобы не ждать лишнего на этих редких ветках кода - можно запретить им вытесняться.&lt;/li&gt;
&lt;li&gt;Индексы в базах данных часто физически представляют собой именно файл, с которым работают через &lt;code&gt;mmap&lt;/code&gt;, а &lt;code&gt;mlock&lt;/code&gt; нужен чтобы минимизировать задержки и число операций ввода-вывода на и без того нагруженном диске(-ах).&lt;/li&gt;
&lt;li&gt;Приложение использует какой-то статический словарь, например с соответствием подсетей IP-адресов и стран, к которым они относятся. Вдвойне актуально, если на одном сервере запущено несколько процессов, работающих с этим словарем.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="oom-killer"&gt;&lt;abbr title="Out Of Memory"&gt;OOM&lt;/abbr&gt; killer&lt;/h3&gt;
&lt;p&gt;Перестаравшись с невытесняемой памятью не трудно загнать операционную систему в ситуацию, когда физическая память кончилась, а вытеснять ничего нельзя. Безысходной она выглядит лишь на первый взгляд: вместо вытеснения память можно освободить.&lt;/p&gt;
&lt;p&gt;Происходит это достаточно радикальными методами: послуживший названием данного раздела механизм выбирает по определенному алгоритму процесс, которым наиболее целесообразно в текущий момент пожертвовать - с остановкой процесса освобождается использовавшаяся им память, которую можно перераспределить между выжившими. Основной критерий для выбора: текущее потребление физической памяти и других ресурсов, плюс есть возможность вмешаться и вручную пометить процессы как более или менее ценные, а также вовсе исключить из рассмотрения. Если отключить &lt;abbr title="Out Of Memory"&gt;OOM&lt;/abbr&gt; killer полностью, то системе в случае полного дефицита ничего не останется, как перезагрузиться.&lt;/p&gt;
&lt;h3 id="cgroups"&gt;&lt;abbr title="control groups"&gt;cgroups&lt;/abbr&gt;&lt;/h3&gt;
&lt;p&gt;По-умолчанию все пользовательские процессы наравне претендуют на почти всю физически доступную память в рамках одного сервера. Это поведение редко является приемлемым. Даже если сервер условно-однозадачный, например только отдает статические файлы по HTTP с помощью &lt;a href="/tag/nginx/"&gt;nginx&lt;/a&gt;, всегда есть какие-то служебные процессы вроде &lt;a href="/tag/syslog/"&gt;syslog&lt;/a&gt; или какой-то временной команды, запущенной человеком. Если же на сервере одновременно работает несколько production процессов, например, популярный вариант - подсадить к веб-серверу &lt;a href="/tag/memcached/"&gt;memcached&lt;/a&gt;, крайне желательно, чтобы они не могли начать "воевать" друг с другом за память в случае её дефицита.&lt;/p&gt;
&lt;p&gt;Для изоляции важных процессов в современных ядрах существует механизм &lt;abbr title="control groups"&gt;cgroups&lt;/abbr&gt;, c его помощью можно разделить процессы на логические группы и статически сконфигурировать для каждой из групп сколько физической памяти может быть ей выделено. После чего для каждой группы создается своя почти независимая подсистема памяти, со своим отслеживанием вытеснения, &lt;abbr title="Out Of Memory"&gt;OOM&lt;/abbr&gt; killer и прочими радостями.&lt;/p&gt;
&lt;p&gt;Механизм &lt;abbr title="control groups"&gt;cgroups&lt;/abbr&gt; намного обширнее, чем просто контроль за потреблением памяти, с его помощью можно распределять вычислительные ресурсы, "прибивать" группы к ядрам процессора, ограничивать ввод-вывод и многое другое. Сами группы могут быть организованы в иерархию и вообще на основе &lt;abbr title="control groups"&gt;cgroups&lt;/abbr&gt; работают многие системы "легкой" виртуализации и нынче модные Docker-контейнеры.&lt;/p&gt;
&lt;p&gt;Но на мой взгляд именно контроль за потреблением памяти - самый необходимый минимум, который определенно стоит настроить, остальное уже по желанию/необходимости.&lt;/p&gt;
&lt;h2 id="numa_1"&gt;&lt;abbr title="Non-Uniform Memory Access"&gt;NUMA&lt;/abbr&gt;&lt;/h2&gt;
&lt;p&gt;В многопроцессорных системах не вся память одинакова. Если на материнской плате предусмотрено &lt;code&gt;N&lt;/code&gt; процессоров (например, 2 или 4), то как правило все слоты для оперативной памяти физически разделены на &lt;code&gt;N&lt;/code&gt; групп так, что каждая из них располагается ближе к соответствующему ей процессору - такую схему называют &lt;abbr title="Non-Uniform Memory Access"&gt;NUMA&lt;/abbr&gt;.&lt;/p&gt;
&lt;p&gt;Таким образом, каждый процессор может обращаться к определенной &lt;code&gt;1/N&lt;/code&gt; части физической памяти быстрее (примерно раза в полтора), чем к оставшимся &lt;code&gt;(N-1)/N&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Ядро Linux самостоятельно умеет это всё определять и по-умолчанию достаточно разумным образом учитывать при планировании выполнения процессоров и выделении им памяти. Посмотреть как это все выглядит и подкорректировать можно с помощью утилиты &lt;code&gt;numactl&lt;/code&gt; и ряда доступных системных вызовов, в частности &lt;code&gt;get_mempolicy&lt;/code&gt;/&lt;code&gt;set_mempolicy&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id="operatsii-s-pamiatiu"&gt;Операции с памятью&lt;/h2&gt;
&lt;p&gt;Есть несколько тем, с которыми в реальности сталкиваются лишь &lt;a href="/tag/c/"&gt;C/C++&lt;/a&gt; разработчики низкоуровневых систем, и не мне им про это рассказывать. Но даже если напрямую с этим не сталкиваться на мой взгляд полезно в общих чертах знать, какие бывают нюансы:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Операции, работающие с памятью:&lt;ul&gt;
&lt;li&gt;В большинстве своем не атомарны (то есть другой поток может их "увидеть" на полпути), без явной синхронизации атомарность возможна только для блоков памяти не больше указателя (т.е. как правило 64 бита) и то при определенных условиях.&lt;/li&gt;
&lt;li&gt;В реальности происходят далеко не всегда в том порядке, в котором они написаны в исходном коде программы: процессоры и компиляторы на правах оптимизации могут менять их порядок, как считают нужным. В случае многопоточных программ эти оптимизации часто могут приводить к нарушению логики их работы. Для предотвращения подобных ошибок разработчики могут использовать специальные инструменты, в частности &lt;strong&gt;барьеры памяти&lt;/strong&gt; - инструкции, которые запрещают переносить операции с памятью между частями программы до неё и после.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Новые процессы создаются с помощью системного вызова &lt;code&gt;fork&lt;/code&gt;, который порождает копию текущего процесса (чтобы запустить другую программу в новом процессе существует отдельное семейство системных вызовов - &lt;code&gt;exec&lt;/code&gt;), у которого виртуальное пространство практически полностью идентично родительскому, что не потребляет дополнительной физической памяти до тех пор, пока тот или другой не начнут его изменять. Этот механизм называется &lt;code&gt;copy on write&lt;/code&gt; и на нем можно играть для создания большого числа однотипных независимых процессов (например, обрабатывающих какие-то запросы), с минимумом дополнительных расходов физической памяти - в некоторых случаях так жить удобнее, чем с многопоточным приложением.&lt;/li&gt;
&lt;li&gt;Между процессором и оперативной памятью находится несколько уровней кешей, обращение к которым ещё на порядки быстрее, чем к оперативной памяти. К самому быстрому - доли наносекунд, к самому медленному единицы наносекунд. На особенностях их работы можно делать микро оптимизации, но из высокоуровневых языков программирования до них толком не добраться.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="itogo"&gt;Итого&lt;/h2&gt;
&lt;p&gt;Подсистему памяти в Linux нельзя бросать на произвол судьбы. Как минимум, стоит следить за следующими показателями и вывести на приборы (как суммарно, так и по процессам или их группам):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Скорость возникновения major page faults;&lt;/li&gt;
&lt;li&gt;Срабатывания &lt;abbr title="Out Of Memory"&gt;OOM&lt;/abbr&gt; killer;&lt;/li&gt;
&lt;li&gt;Текущий объем использования физической памяти (это число обычно называют &lt;abbr title="Resident Set Size"&gt;RSS&lt;/abbr&gt;, не путать с одноименным форматом для публикации текстового контента).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;В штатном режиме все три показателя должны быть стабильны (а первые два - близки к нулю). Всплески или плавный рост стоит рассматривать как аномалию, в причинах которой стоит разобраться. Какими методами - надеюсь я показал достаточно направлений, куда можно по-копать.&lt;/p&gt;
&lt;div class="card teal"&gt;
&lt;div class="card-content white-text"&gt;
&lt;ul&gt;
&lt;li class="white-text"&gt;Статья написана с ориентиром на современные Debian-like дистрибутивы Linux и физическое оборудование с двумя процеcсорами Intel Xeon. Общие принципы ортогональны этому и справедливы даже для других операционных систем, но вот детали могут сильно разниться даже в зависимости от сборки ядра или конфигурации.&lt;/li&gt;
&lt;li class="white-text"&gt;У большинства упомянутых выше системных вызовов, функций и команд есть &lt;code&gt;man&lt;/code&gt;, к которому рекомендую обращаться за подробностями об их использовании и работе. Если под рукой нет linux-машины, где можно набрать &lt;code&gt;man foo&lt;/code&gt; - они обычно легко ищутся с таким же запросом.&lt;/li&gt;
&lt;li class="white-text"&gt;Если есть желание углубиться в какую-либо из затронутых вскользь тем - пишите об этом в комментариях, любая из них может стать заголовком отдельной статьи.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 id="ps"&gt;P.S.&lt;/h2&gt;
&lt;p&gt;На последок ещё раз повторю цифры, которые настоятельно рекомендую запомнить:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;0.0001 мс&lt;/strong&gt; (100 нс) - обращение к оперативной памяти&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;0.1-1 мс&lt;/strong&gt; (0.1-1 млн. нс) - обращение к &lt;abbr title="Solid State Drive"&gt;SSD&lt;/abbr&gt; при major pagefault, &lt;em&gt;на 3-4 порядка дороже&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;5-10 мс&lt;/strong&gt; (5-10 млн. нс) - обращение к традиционному жесткому диску при pagefault, &lt;em&gt;ещё на порядок дороже&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;// мс - миллисекунды, нс - наносекунды.&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Иван Блинков</dc:creator><pubDate>Sun, 07 Jun 2015 22:45:00 +0300</pubDate><guid>tag:www.insight-it.ru,2015-06-07:linux/2015/chto-stoit-znat-o-pamiati-v-linux/</guid><category>оперативная память</category><category>память</category><category>pagefault</category><category>page fault</category><category>cgroups</category><category>NUMA</category><category>oom</category><category>oom killer</category><category>mlock</category></item><item><title>Реинкарнация сайта</title><link>https://www.insight-it.ru//misc/2015/reinkarnatsiia-saita/</link><description>&lt;p&gt;После, пожалуй, самого длительного периода без обновлений в истории &lt;strong class="trebuchet"&gt;Insight&amp;nbsp;IT&lt;/strong&gt;, сайт прошел через "реинкарнацию" - был переделан с нуля, сохранен лишь контент. Этого сложно не заметить, если Вы здесь не впервые. Желающих получить ответы на вопросы в духе "как так?", "зачем?", "что поменялось?" и "что дальше?" - прошу читать далее.&lt;/p&gt;
&lt;!--more--&gt;
&lt;h2 id="kak-tak"&gt;Как так?&lt;/h2&gt;
&lt;p&gt;Многие годы, занимаясь &lt;strong class="trebuchet"&gt;Insight IT&lt;/strong&gt;, я совмещал приятное с полезным: по большому счёту оставаясь просто хобби, сайт помогал мне знакомиться с будущими партнерами, клиентами, коллегами, что долгое время позволяло мне обходиться без стабильного источника дохода. Когда я в итоге "сдался" и пошел работать в крупную компанию за зарплату - эта дополнительная ценность стала менее значимой. Во многом из-за этого здесь нельзя найти ни одной записи датированной прошлым годом (хотя есть и другие причины, конечно, но об этом в заключении).&lt;/p&gt;
&lt;h2 id="zachem"&gt;Зачем?&lt;/h2&gt;
&lt;p&gt;Резонный вопрос - зачем вкладывать столько сил, чтобы всё переделать на в заброшенном сайте? Началось всё со спортивного интереса: я начал замечать, что постепенно теряю хватку в мирах opensource и веб-разработки. В Яндексе вокруг меня по большей части разный backend внутренней разработки. Кандидат для экспериментов в лице &lt;strong class="trebuchet"&gt;Insight IT&lt;/strong&gt; нашелся быстро, что из этого получилось - в следующем разделе.&lt;/p&gt;
&lt;h2 id="chto-pomenialos"&gt;Что поменялось?&lt;/h2&gt;
&lt;h3 id="rip-wordpress"&gt;R.I.P. WordPress&lt;/h3&gt;
&lt;p&gt;Первые 6 c половиной лет своего существования &lt;strong class="trebuchet"&gt;Insight IT&lt;/strong&gt; проработал на &lt;a href="/tag/wordpress/"&gt;WordPress&lt;/a&gt; в качестве &lt;abbr title="Content Management System"&gt;CMS&lt;/abbr&gt;. С пьедестала самой популярной &lt;abbr title="Content Management System"&gt;CMS&lt;/abbr&gt; в мире, насколько я знаю, за всё это время WordPress так никто и не сместил. Думаю, в первую очередь благодаря крайне простому в использовании интерфейсу для управления сайтом, а во вторую - выдающемуся ассортименту плагинов и тем. Плюс имевший место в 2008-м акцент на блоги отходит в сторону, сейчас на нем какие только сайты не делают.&lt;/p&gt;
&lt;p&gt;Но за &lt;del&gt;красоту&lt;/del&gt; простоту приходится платить:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;abbr title="What You See Is What You Get"&gt;WYSIWYG&lt;/abbr&gt; редактор создает верстку сомнительного качества,&lt;/li&gt;
&lt;li&gt;При установке большого числа плагинов и без того далёкая от идеала производительность становится невыносимой,&lt;/li&gt;
&lt;li&gt;У всех компонентов разные разработчики и релизные циклы, постоянно нужно следить за совместимостью, регулярно накатывать обновления как минимум по части безопасности, после обновлений часто всё ломается.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Вопрос с производительностью решается агрессивным кешированием и клиентской оптимизацией. Не раз занимался этим для других сайтов, в том числе и на WordPress, но для некоммерческого проекта не понятно как оправдать трудозатраты на изначальную настройку и поддержание этого всего в рабочем состоянии. Зачастую плагины разрабатываются без оглядки на то, что, например, &lt;a href="/tag/javascript/"&gt;JavaScript&lt;/a&gt;-библиотека, от которой они зависят, может быть ещё не быть загружена и пытаются ей пользоваться в распечатанном прямо вперемешку с HTML JavaScript, что даже само по себе плохо, а с перенесенными вниз зависимостями и вовсе не работает.&lt;/p&gt;
&lt;p&gt;Верстку тоже можно "чинить" через текстовый режим редактора, но такие правки имеют обыкновение пропадать после любого изменения в визуальном режиме, что крайне надоедает.&lt;/p&gt;
&lt;p&gt;Уже в 2009-м минусы WordPress для меня начали перевешивать плюсы. Тогда достойной альтернативы, увы, не нашлось и всё осталось как есть. Но не в этот раз.&lt;/p&gt;
&lt;h3 id="staticheskie-saity"&gt;Статические сайты&lt;/h3&gt;
&lt;p&gt;Несколько лет назад начал набирать популярность подход с &lt;strong&gt;генерацией статических сайтов&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Вместо хранения в базе данных статьи и другой контент приравнивается к исходному коду, то есть:&lt;ul&gt;
&lt;li&gt;Хранятся в системе контроля версий в виде файлов в специализированном формате (как правило, &lt;a href="https://www.insight-it.ru/goto/4eefcf89/" rel="nofollow" target="_blank" title="https://ru.wikipedia.org/wiki/Markdown"&gt;Markdown&lt;/a&gt; или ReStructured Text), который удобен для написания человеко-читаемых текстов и однозначно преобразовывается в чистый, валидный, HTML.&lt;/li&gt;
&lt;li&gt;Пишутся в текстовых редакторах, ориентированных на разработчиков, с подсветкой синтаксиса, автодополнением и т.п.&lt;/li&gt;
&lt;li&gt;При необходимости легко начать использовать общепринятые инструменты для работы с кодом, в том числе совместной (ревью кода, ветвление, непрерывная интеграция, отслеживание проблем).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;С помощью &lt;code&gt;make&lt;/code&gt; или аналога сайт собирается примерно так же, как это делала бы программа на &lt;a href="/tag/c/"&gt;C++&lt;/a&gt;:&lt;ul&gt;
&lt;li&gt;Создается output директория с будущим результатом.&lt;/li&gt;
&lt;li&gt;В ней генерируются все страницы сайта - для статей с помощью шаблонизатора добавляется вся необходимая HTML-обвязка, а навигационные страницы (по категориям и тегам, с по-страничным выводом) создаются с нуля, тоже по шаблону.&lt;/li&gt;
&lt;li&gt;Весь клиентский код на JavaScript и CSS, а также статические файлы вроде изображений, группируются и прогоняются через разные фильтры для уменьшения количества файлов и их размеров.&lt;/li&gt;
&lt;li&gt;Внутренние ссылки в исходном коде как правило реализованы по путям в локальной файловой системе, а как они будут выглядеть в итоговом сайте конфигурируется и тоже применяется при сборке.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;В итоге, чтобы посмотреть на результат в браузере подойдет любой веб-сервер, умеющий отдавать статические файлы из папки, то есть совсем любой за вычетом специализированных.&lt;/li&gt;
&lt;li&gt;Как легко такую папочку кешировать на всех уровнях, а также как быстро и дешево можно такой сайт показывать пользователям, рассказывать, думаю, не нужно.&lt;/li&gt;
&lt;li&gt;Но у отсутствия динамической серверной логики есть и минусы:&lt;ul&gt;
&lt;li&gt;&lt;del&gt;Тоска по гламурной админке WordPress.&lt;/del&gt;&lt;/li&gt;
&lt;li&gt;Для реализации некоторого функционала &lt;em&gt;(в нашем случае - комментариев и поиска по сайту)&lt;/em&gt; требуется как-то изворачиваться, возможные варианты:&lt;ul&gt;
&lt;li&gt;Воспользоваться сторонним сервисом - &lt;a href="/tag/disqus/"&gt;Disqus&lt;/a&gt; уже использовался и раньше, а обе лидирующие поисковые системы предоставляют сервис поиска по конкретному сайту, так что я пошел по этому пути).&lt;/li&gt;
&lt;li&gt;Поселить рядом с кучей статики какой-о набор скриптов, но не очень понятно как их интегрировать с системой сборки сайта, которая по сути выполняет роль &lt;abbr title="Content Management System"&gt;CMS&lt;/abbr&gt;.&lt;/li&gt;
&lt;li&gt;Реализовать его на JavaScript - скажем для поиска по сайту можно при сборке сложить весь контент в один большой JSON, и искать по нему уже на клиенте. Но я решил пожалеть пользователей с долгоиграющими ноутбуками, особенно новых без вентиляторов. Раньше ещё можно было пожалеть владельцев смартфонов, но когда их стали делать восьми-ядерными...&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Время, которое технически необходимо для публикации нового контента или изменений в шаблонах, начинает зависеть от размера самого сайта - не смотря на попытки реализовать кеширование при сборке, многие изменения требуют перегенерации примерно всего сайта.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;И, напоследок, ввиду низкой серверной ресурсоемкости таких сайтов, для него легко найти качественный хостинг бесплатно.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Взвесив "за" и "против", я решил, что для &lt;strong class="trebuchet"&gt;Insight IT&lt;/strong&gt; такой вариант очень даже подходит. Осталось выбрать конкретную реализацию такой системы сборки сайта.&lt;/p&gt;
&lt;p&gt;Первопроходцем и лидером рынка здесь является &lt;a href="https://www.insight-it.ru/goto/d9898f57/" rel="nofollow" target="_blank" title="http://jekyllrb.com/"&gt;Jekyll&lt;/a&gt;. Всем хорош, очень много кем используется, масса тем и плагинов. Но один субъективный минус поставил на нём лично для меня крест - &lt;a href="/tag/ruby/"&gt;Ruby&lt;/a&gt;. Вот тошнит меня от его синтаксиса и всё.&lt;/p&gt;
&lt;p&gt;Был вариант, конечно, закрыть на это глаза и не лезть вглубь, а просто собрать сайт из готовых компонентов, но опыт подсказывает, что без напильника нынче ничего не взлетает.&lt;/p&gt;
&lt;p&gt;Подходящую альтернативу искать долго не пришлось: выбор пал на &lt;a href="https://www.insight-it.ru/goto/f5099f2a/" rel="nofollow" target="_blank" title="http://getpelican.com"&gt;Pelican&lt;/a&gt;, практически единственный вариант на &lt;a href="/tag/python/"&gt;Python&lt;/a&gt;. Готовых плагинов у него не так много, но самое основное есть, а недостающее мне определенно было не сложно допилить, благо с экосистемой Python я тесно знаком. В качестве шаблонизатора используется &lt;a href="/tag/jinja2/"&gt;Jinja2&lt;/a&gt;, лучше которого я по-прежнему ничего не видел. Про сам перенос сайта можно написать отдельный пост, и не один, что я надеюсь и сделаю в скором будущем, так что здесь эту тему дальше развивать не буду.&lt;/p&gt;
&lt;h3 id="https"&gt;https://&lt;/h3&gt;
&lt;p&gt;Как при желании можно было заметить, &lt;strong class="trebuchet"&gt;Insight IT&lt;/strong&gt; уже много лет живет за &lt;a href="https://www.insight-it.ru/goto/26a5858d/" rel="nofollow" target="_blank" title="https://www.cloudflare.com/"&gt;CloudFlare&lt;/a&gt; - многофункциональной распределенной прокси, выполняющей роль &lt;abbr title="Content Delivery Network"&gt;CDN&lt;/abbr&gt;, &lt;abbr title="Domain Name System"&gt;DNS&lt;/abbr&gt;,защиты от разного рода атак и многого другого. Изначально поддержка &lt;abbr title="Secure Sockets Layer"&gt;SSL&lt;/abbr&gt; была доступна только на платном тарифе, который некоммерческому проекту был ни к чему, но с недавних пор это стало не так и я за компанию решил перейти на &lt;code&gt;https://&lt;/code&gt;, раз уж всё равно все внутренние ссылки переехали. Плюсы не критичны, но всё же есть:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Само отображение защищенного соединения в адресной строке браузеров внушает уверенность если не всем, то какой-то части посетителей&lt;/li&gt;
&lt;li&gt;Поддержка современных протоколов в лице SPDY и, вероятно, со временем HTTP/2.0&lt;/li&gt;
&lt;li&gt;Говорят, использование защищенного соединения положительно сказывается на репутации сайта в глазах как минимум поиска Google&lt;/li&gt;
&lt;li&gt;Владельцы публичных WiFi точек не могут показывать свою рекламу на сайте&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Основной минус - дополнительные накладные расходы на инициализацию соединения и, собственно, шифрование, но как правило это не особо критично.&lt;/p&gt;
&lt;p&gt;К слову, стоявший за CloudFlare простенький &lt;abbr title="Virtual Private Server"&gt;VPS&lt;/abbr&gt; тоже заменен, на наиболее популярный среди хостингов статичных сайтов &lt;a href="https://www.insight-it.ru/goto/e7e0e370/" rel="nofollow" target="_blank" title="https://pages.github.com/"&gt;GitHub Pages&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id="kontent"&gt;Контент&lt;/h3&gt;
&lt;p&gt;В состав Pelican входит инструмент для конвертации статей из XML-формата WordPress в Markdown, которым я и воспользоваться. Большую часть работы он сделал, но всё равно потребовался ручной просмотр и адаптация всех страниц сайта. Это заняло уйму времени, но в целом того стоило:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Везде причёсан HTML, во многом благодаря &lt;a href="/tag/markdown/"&gt;Markdown&lt;/a&gt;; лучше оформлены изображения и врезки, ещё раз проверены опечатки.&lt;/li&gt;
&lt;li&gt;Исторически статьи раскладывались по рубрикам по мере написания, по-этому общая структура сайта была хаотичной. Теперь разбил их на категории по-другому, на этот раз, надеюсь, более логичным образом.&lt;/li&gt;
&lt;li&gt;Пока перечитывал осознал, что значительная часть контента морально устарела и годится только для совсем начинающих или как историческая перспектива. Решил сделать некоторый акцент на годе публикации - теперь он присутствует в URL статей, а также в &lt;a href="https://www.insight-it.ru/highload/"&gt;оглавлении публикаций об архитектуре высоконагруженных интернет-проектов&lt;/a&gt;. Совсем-совсем неактуальным пришлось пожертвовать или явно подписать соответствующим образом.&lt;/li&gt;
&lt;li&gt;Как следствие из предыдущих двух пунктов, в очередной раз полностью поменялась структура ссылок сайта. По-возможности со старых адресов сохранены редиректы, но, к сожалению, в концепции статических сайтов возможны только клиентские, через meta-тег или JavaScript. Поисковые системы же предпочитают серверные, через 301/307 HTTP-код и заголовок Location.&lt;/li&gt;
&lt;li&gt;В общем, позиции &lt;strong class="trebuchet"&gt;Insight IT&lt;/strong&gt; в поисковых системах определенно пострадают, остается лишь надеяться что не катастрофическим образом - ведь сейчас это основной источник посетителей. Если вам не безразлична судьба сайта - твиты, лайки и прочие входящие ссылки по новым адресам крайне приветствуются.&lt;/li&gt;
&lt;li&gt;Теперь весь контент публикуется под лицензией &lt;a href="https://www.insight-it.ru/goto/c3aba0/" rel="nofollow" target="_blank" title="http://creativecommons.org/licenses/by-nc-nd/4.0/"&gt;Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International License&lt;/a&gt;, о чем свидетельствует значок в правом-нижнем углу каждой страницы.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="dizain"&gt;Дизайн&lt;/h3&gt;
&lt;p&gt;В плане дизайна я не особо гурман, но предыдущий определенно требовал замены. Изыски здесь ни к чему, так что всё свелось к выбору готовой визуальной концепции.&lt;/p&gt;
&lt;p&gt;За всё те же последние несколько лет &lt;a href="https://www.insight-it.ru/goto/80e3ad2/" rel="nofollow" target="_blank" title="http://getbootstrap.com/"&gt;Twitter Bootstrap&lt;/a&gt; стал решением по-умолчанию для подобных ситуаций благодаря низкому порогу входа и хорошей комбинации встроенного функционала, кроссбраузерности и приличного внешнего вида. По иронии ровно это и стало причиной моего от него отказа в данном случае: уж больно он всем приелся и на каждом углу почти без изменений используется.&lt;/p&gt;
&lt;p&gt;В своё время мне приглянулось своей стройностью и логичностью концепция &lt;a href="https://www.insight-it.ru/goto/7d571a9f/" rel="nofollow" target="_blank" title="http://www.google.com/design/spec/"&gt;Material Design&lt;/a&gt; от &lt;a href="/tag/google/"&gt;Google&lt;/a&gt;, которую они активно внедряют сами и всем советуют. Не долго думая, я пошел поискать opensource решения с готовой реализацией для веб-сайтов и остановился на &lt;a href="https://www.insight-it.ru/goto/823b55/" rel="nofollow" target="_blank" title="http://materializecss.com"&gt;варианте&lt;/a&gt;, который одновременно имел достаточный функционал, сколько-либо большое сообщество и минимум зависимостей, особенно от громоздких &lt;a href="/tag/javascript/"&gt;JavaScript&lt;/a&gt;-библиотек, чем грешили альтернативные варианты.&lt;/p&gt;
&lt;p&gt;Основной цвет сменился с желтовато-зеленого на ярко синий, появился набор акцентных цветов, а типографичный логотип остался почти неизменным. Иконочный шрифт сделан специальный, только с использующимися иконками, получается очень маленький по байтам.&lt;/p&gt;
&lt;p&gt;Итого, с моей субъективной колокольни получилось заметно лучше прежнего, но хочется всё же услышать и ваше мнение в комментариях.&lt;/p&gt;
&lt;h2 id="chto-dalshe_1"&gt;Что дальше?&lt;/h2&gt;
&lt;p&gt;Как обычно, многое зависит от вас, читателей. Вложенные в реконструкцию сайта силы дают некоторый толчок к мотивации писать новые материалы, но без обратной связи её определенно на долго не хватит.&lt;/p&gt;
&lt;p&gt;С закрытием Google Reader два года назад число подписчиков на счетчике от FeedBurner упало почти на два порядка, так что можно считать, что сейчас и правда для &lt;strong class="trebuchet"&gt;Insight IT&lt;/strong&gt; всё начинается почти с начала.&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Иван Блинков</dc:creator><pubDate>Sat, 30 May 2015 20:10:00 +0300</pubDate><guid>tag:www.insight-it.ru,2015-05-30:misc/2015/reinkarnatsiia-saita/</guid><category>Pelican</category><category>Python</category><category>Creative Commons</category><category>https</category><category>Material Design</category><category>Cloudflare</category><category>GitHub</category><category>GitHub Pages</category><category>Markdown</category><category>git</category><category>SSL</category><category>https</category></item><item><title>Вакансии: разработчики облачной IaaS платформы в Крок</title><link>https://www.insight-it.ru//vacancy/2013/vakansii-razrabotchiki-oblachnojj-iaas-platformy-v-krok/</link><description>&lt;div class="card orange darken-3"&gt;
&lt;p&gt;&lt;div class="card-content white-text center"&gt;
&lt;strong&gt;Вакансии более не актуальны&lt;/strong&gt;
&lt;/div&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;Ведущая российская ИТ-компания ищет талантливых, креативных и энергичных
инженеров и разработчиков для развития коммерческой облачной платформы
КРОК, предоставляющей услугу типа &amp;laquo;Инфраструктура как сервис&amp;raquo; (IaaS). В современном высокотехнологичном офисе Вас ждет дружная сплоченная команда профессионалов, занимающаяся разработкой передовой &amp;laquo;облачной&amp;raquo; платформы, у которой всегда найдется для Вас множество интересных, сложных и разнообразных задач, способных удовлетворить даже самые заоблачные амбиции!&lt;/p&gt;
&lt;!--more--&gt;
&lt;h2 id="razrabotchik-na-platforme-linux"&gt;Разработчик на платформе Linux&lt;/h2&gt;
&lt;h3 id="obiazannosti"&gt;Обязанности&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Проектирование архитектуры компонентов &amp;laquo;облачного&amp;raquo; решения;&lt;/li&gt;
&lt;li&gt;Разработка и интеграция модулей облачной платформы;&lt;/li&gt;
&lt;li&gt;Исследования в области распределенных высоконагруженных систем.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="trebovaniia"&gt;Требования&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Опыт в области shell-программирования;&lt;/li&gt;
&lt;li&gt;Уверенное знание Python, приветствуется знание С++ или Java;&lt;/li&gt;
&lt;li&gt;Владение средствами разработки (autotools, git, svn и др.);&lt;/li&gt;
&lt;li&gt;Опыт администрирования ОС Linux от 1 года (преимущественно RHEL,
    CentOS, Debian или SLES);&lt;/li&gt;
&lt;li&gt;Опыт работы с технологиями виртуализации (Qemu/KVM, XEN, Hyper-V или
    VMware);&lt;/li&gt;
&lt;li&gt;Знание &amp;laquo;облачных&amp;raquo; технологий особенно приветствуется.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="inzhener-po-oblachnym-resheniiam_1"&gt;Инженер по облачным решениям&lt;/h2&gt;
&lt;h3 id="obiazannosti_1"&gt;Обязанности&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Общение с техническими специалистами заказчика для определения задач
    и специфических требований, предъявляемых к информационной системе;&lt;/li&gt;
&lt;li&gt;Исследовательская работа по поиску, тестированию и внедрению
    различных технологий;&lt;/li&gt;
&lt;li&gt;Участие во внедрении решений для автоматизации ИТ-инфраструктуры;&lt;/li&gt;
&lt;li&gt;Тестирование различных вариантов исполнения инфраструктурных
    решений;&lt;/li&gt;
&lt;li&gt;Техническая поддержка внедряемых решений решения.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="trebovaniia_1"&gt;Требования&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Навыки администрирования современных ОС GNU/Linux и Windows;&lt;/li&gt;
&lt;li&gt;Понимание принципов виртуализации вычислительных ресурсов;&lt;/li&gt;
&lt;li&gt;Приветствуется опыт написания сценариев на языках shell и Python;&lt;/li&gt;
&lt;li&gt;Личные качества: коммуникабельность, общительность, активная
    жизненная позиция.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="usloviia_1"&gt;Условия&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Конкурентная заработная плата по результатам собеседования;&lt;/li&gt;
&lt;li&gt;Возможность профессионального и карьерного роста;&lt;/li&gt;
&lt;li&gt;Компания оплачивает обучение и сертификацию;&lt;/li&gt;
&lt;li&gt;Социальный пакет (медицинская страховка, бесплатное питание в офисе,
    спортивные программы и компенсация фитнеса, английский язык);&lt;/li&gt;
&lt;li&gt;Компания оказывает помощь при переезде в Москву (оплата стоимости
    проезда для прохождения собеседований, &amp;laquo;подъемные&amp;raquo; при выходе на
    работу).&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="kuda-otpravliat-reziume"&gt;Куда отправлять резюме?&lt;/h2&gt;
&lt;div class="card orange darken-3"&gt;
&lt;p&gt;&lt;div class="card-content white-text center"&gt;
&lt;strong&gt;Вакансии более не актуальны&lt;/strong&gt;
&lt;/div&gt;&lt;/p&gt;
&lt;/div&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Иван Блинков</dc:creator><pubDate>Thu, 19 Sep 2013 19:40:00 +0400</pubDate><guid>tag:www.insight-it.ru,2013-09-19:vacancy/2013/vakansii-razrabotchiki-oblachnojj-iaas-platformy-v-krok/</guid><category>autotools</category><category>C++</category><category>CentOS</category><category>Debian</category><category>Git</category><category>IaaS</category><category>Java</category><category>KVM</category><category>Linux</category><category>Python</category><category>Qemu</category><category>RHEL</category><category>SLES</category><category>SVN</category><category>Xen</category><category>вакансии</category><category>виртуализация</category><category>Крок</category><category>облачные вычисления</category></item><item><title>Горячая замена кода</title><link>https://www.insight-it.ru//theory/2013/goryachaya-zamena-koda/</link><description>&lt;p&gt;Относительно недавно почитывая RSS через доживающий свои дни Google
Reader, о предстоящем закрытии которого не написал только самый ленивый
IT-блоггер &lt;em&gt;(к слову, любопытно насколько
сильно просядет счетчик &lt;a href="/feed/"&gt;RSS-подписчиков Insight IT&lt;/a&gt; с текущих
16870, боюсь, что очень сильно...)&lt;/em&gt;, я наткнулся на статью под
заголовком &lt;strong&gt;"Горячее обновление кода не нужно?"&lt;/strong&gt; и с выводом, что мол и
правда особо не нужно, которая и подтолкнула меня поделиться своими
мыслями на эту тему.&lt;/p&gt;
&lt;!--more--&gt;
&lt;p&gt;Для начала давайте разберемся в том, что же вообще такое &lt;strong&gt;"горячая
замена кода"&lt;/strong&gt; &amp;nbsp;(&lt;em&gt;hot code replacement&lt;/em&gt;&amp;nbsp;или&amp;nbsp;&lt;em&gt;hot code swapping&lt;/em&gt;)? По
сути это возможность обновить (или откатить) код работающей программы
без её&amp;nbsp;перезапуска и, как следствие, периода недоступности, потери
состояния и повторной инициализации.&lt;/p&gt;
&lt;p&gt;В каких ситуациях это может быть полезно? Ответ следует из моего
импровизированного определения выше:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Когда простой &lt;em&gt;(downtime)&lt;/em&gt; неприемлем&lt;/li&gt;
&lt;li&gt;Когда есть какое-то состояние в памяти, которое не хочется терять&lt;/li&gt;
&lt;li&gt;Когда инициализация процесса трудоемка и занимает много времени, что
    чаще всего связано с восстановлением &amp;nbsp;состояния с диска или других
    внешних источников&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Ко многим клиент-серверным приложениям, в том числе и веб-сайтам,
предъявляют очень высокие требования по отказоустойчивости, то есть
простои как таковые не допустимы даже в экстренных случаях, не говоря
уже о регулярном обновлении компонентов системы. Но чтобы обеспечить
высокой уровень доступности, измеряемый количеством девяток после
запятой в 99.(9)%, одной горячей замены кода не достаточно, нужно в
любом случае обеспечить доступность всех данных и ключевых серверных
компонентов системы даже в случае выхода из строя сервера, стойки,
маршрутизатора и даже целого датацентра. Обычно это делается "на уровень
выше" относительно самого кода приложения, путем добавления в систему
как минимум резервных (активных или пассивных) копий всех компонентов и
балансировщика нагрузки, способного обнаруживать неполадки и
соответствующим образом перенаправлять поток запросов. Балансировщик
нагрузки также нуждается в выделении под него как минимум двух серверов
с переключением на уровне DNS. Возвращаясь к изначальной теме: если уж
приложение способно пережить экстренный сбой любого компонента, то и без
всякой горячей замены спокойно переживет его плановый перезапуск в связи
с обновлением. Хотя на практике даже при резервировании всех компонентов
небольшая доля запросов может быть потеряна или обработана за
неприемлемо длинный срок в процессе перемаршрутизации их потока.&lt;/p&gt;
&lt;p&gt;Казалось бы клиент-серверные приложения чаще всего не имеют состояния, в
том плане, что все состояние находится в какой-то внешней сущности вроде
СУБД, так что инициализировать особо нечего и состояние потерять не
жалко. И на самом деле часто так и бывает, в том же мире
&lt;a href="/tag/php/"&gt;PHP&lt;/a&gt;&amp;nbsp;довольно популярна практика: положить новую версию кода
в соседнюю папочку, поменять document root в конфиге nginx, попросить
nginx перечитать свой конфиг - максимум сбросится кэш &lt;a href="/tag/apc/"&gt;APC&lt;/a&gt;
или &lt;a href="/tag/xcache/"&gt;xcache&lt;/a&gt;, что мало кого волнует, так как побочным
эффектом будет просто несколько ответов на запросы медленнее обычного.&lt;/p&gt;
&lt;p&gt;А как быть с самой СУБД? Например, &lt;a href="/tag/redis/"&gt;Redis&lt;/a&gt; при запуске
зачитывает в память все данные прежде чем начать принимать запросы, что
может занимать сколько-то минут. Другие СУБД, которые могут отвечать на
запросы и по данным на диске, стартуют относительно быстро, но провал в
их производительности до того, как разогреется встроенный в них кэш,
заметен невооруженным глазом. Очень похожа ситуация и с брокерами
сообщений вроде &lt;a href="/tag/rabbitmq/"&gt;RabbitMQ&lt;/a&gt;: если они и хранят данные на
диске, то скорее как резервную копию. А&amp;nbsp;&lt;a href="/tag/memcached/"&gt;memcached&lt;/a&gt;,
Redis без персистентности&amp;nbsp;и другие хранилища данных в памяти вовсе могут
разогреваться после перезапуска неопределенно долго, так как наполняются
по мере поступления запросов на запись.&lt;/p&gt;
&lt;p&gt;В языках программирования, основанных на байт-коде и виртуальных
машинах, зачастую есть возможность осуществлять &lt;em&gt;горячее обновление
кода&lt;/em&gt;&amp;nbsp;без перезапуска самой виртуальной машины. Когда говорят про
&lt;a href="/tag/erlang/"&gt;Erlang&lt;/a&gt;,&amp;nbsp;очень часто упоминают эту возможность как одно
из ключевых преимуществ платформы, так как она хорошо сочетается с её
системой легковесных не зависящих от ОС процессов и встроенного в
виртуальную машину эффективного хранилища данных в памяти (ETS). В мире
&lt;a href="/tag/java/"&gt;Java&lt;/a&gt; это тоже возможно, но используется намного реже и
позиционируется скорее как инструмент для отладки. В момент подмены кода
в работающей виртуальной машине языка программирования с точки зрения ОС
ничего не меняется: все открытые соединения, файловые дескрипторы и
выделенная оперативная память остаются за ней, то есть она выступает
своего рода посредником между одновременно загруженными двумя версиями
кода, одна из которых будет выгружена из памяти, как только закончит
свою работу и передаст все "дела" новой. Хотя это очень поверхностное
описание, на практике всплывает масса нюансов вроде миграции состояний
процессов в обе стороны, совместимости протоколов взаимодействия и пр.
Плановый перезапуск в данной схеме нужен лишь для обновления самой
виртуальной машины, что обычно требуется намного реже, чем обновление
кода приложения.&lt;/p&gt;
&lt;p&gt;Возможность горячей замены кода на уровне виртуальной машины, казалось
бы, выглядит очень привлекательно для разработки обсуждавшихся выше
инфраструктурных компонентов, от балансировщика нагрузки до различных
хранилищ данных, что позволило бы не терять регулярно в
производительности при обновлениях из-за сброса кэша и переустановки
сетевых соединений. Но в реальности таких продуктов можно пересчитать по
пальцам, почему? Все просто: удобство требует жертв - избегая
периодических провалов в производительности из-за минимизации
перезапусков процессов при обновлении, приходится проигрывать в
производительности постоянно по сравнению с нативным кодом. Для
инфраструктуры обычно оказывается приоритетнее постоянная
производительность, что практически по-умолчанию означает разработку на
одном из диалектов &lt;a href="/tag/c/"&gt;C/C++&lt;/a&gt;, где подобная схема с подменой кода
на лету хоть и возможна, но сложна в реализации ввиду отсутствия
популярных стабильных решений.&lt;/p&gt;
&lt;p&gt;Подводя итог: &lt;strong&gt;горячая замена кода - скорее удобство, чем жизненная
необходимость&lt;/strong&gt;. Удобство при разработке, позволяющее не
инициализировать программу заново при каждом изменении в коде. Удобство
при эксплуатации, позволяющее не терять текущее состояние в памяти и
минимизировать время простоя каждого отдельного компонента системы.
Удобство при поиске сложно воспроизводимых багов, так как есть
возможность на ходу загрузить отладочную &lt;em&gt;(debug)&lt;/em&gt; сборку на проблемной
боевой машине. Но многие проекты прекрасно себе живут и без всего этого,
стоит оно того или нет - сугубо индивидуальное решение.&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Иван Блинков</dc:creator><pubDate>Mon, 29 Apr 2013 10:47:00 +0400</pubDate><guid>tag:www.insight-it.ru,2013-04-29:theory/2013/goryachaya-zamena-koda/</guid><category>hot code replacement</category><category>hot code swapping</category><category>горячая замена кода</category><category>горячее обновление кода</category><category>инициализация</category><category>отладка</category><category>перезапуск</category><category>разработка</category><category>эксплуатация</category></item><item><title>Вакансии: команда Python разработчиков в EVAplacer</title><link>https://www.insight-it.ru//vacancy/2013/vakansii-komanda-python-razrabotchikov-v-evaplacer/</link><description>&lt;div class="card orange darken-3"&gt;
&lt;p&gt;&lt;div class="card-content white-text center"&gt;
&lt;strong&gt;Вакансии более не актуальны&lt;/strong&gt;
&lt;/div&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;Новая &lt;em&gt;международная геоинформационная социальная сеть&lt;/em&gt; EVAplacer
набирает команду разработчиков.&lt;/p&gt;
&lt;!--more--&gt;
&lt;h2 id="vedushchii-razrabotchik-servernoi-chasti-na-python"&gt;Ведущий разработчик серверной части на Python&lt;/h2&gt;
&lt;h3 id="zadachi"&gt;Задачи&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Разработка серверной части проекта на Python&lt;/li&gt;
&lt;li&gt;Проектирование архитектуры системы и схемы базы данных&lt;/li&gt;
&lt;li&gt;Организация взаимодействия серверной части проекта с клиентской&lt;/li&gt;
&lt;li&gt;Принятие технических решений&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="trebovaniia"&gt;Требования&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Свежий опыт веб-разработки на Python &lt;em&gt;без использования Django&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;Суммарный опыт веб-разработки от 5 лет&lt;/li&gt;
&lt;li&gt;Самостоятельность и заинтересованность в качестве результата своей
    работы&lt;/li&gt;
&lt;li&gt;Умение делегировать часть работы коллегам&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="tekhnologii"&gt;Технологии&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Предстоит работать со следующими технологиями:&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.insight-it.ru/goto/2e568974/" rel="nofollow" target="_blank" title="http://flask.pocoo.org/"&gt;Flask&lt;/a&gt; +
    &lt;a href="https://www.insight-it.ru/goto/35c21496/" rel="nofollow" target="_blank" title="http://jinja.pocoo.org/"&gt;Jinja2&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.insight-it.ru/goto/bf2b1e00/" rel="nofollow" target="_blank" title="http://www.mongodb.org/"&gt;MongoDB&lt;/a&gt; +
    &lt;a href="https://www.insight-it.ru/goto/a6920afe/" rel="nofollow" target="_blank" title="http://lucene.apache.org/solr/"&gt;Solr&lt;/a&gt; +
    &lt;a href="https://www.insight-it.ru/goto/9ecaff4c/" rel="nofollow" target="_blank" title="http://memcached.org/"&gt;memcached&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.insight-it.ru/goto/39ecae7b/" rel="nofollow" target="_blank" title="http://www.zeromq.org/"&gt;ZeroMQ&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Опыт работы именно с ними очень желателен, но не обязателен&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="zarplata"&gt;Зарплата&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;В диапазоне 100-150 тысяч рублей в месяц в зависимости от опыта&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="klientskii-razrabotchik_1"&gt;Клиентский разработчик&lt;/h2&gt;
&lt;h3 id="zadachi_1"&gt;Задачи&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Разработка клиентской части проекта&lt;/li&gt;
&lt;li&gt;Работа на стыке с серверной частью (Python), создание HTML и других
    шаблонов на Jinja2&lt;/li&gt;
&lt;li&gt;Оптимизация скорости загрузки страниц&lt;/li&gt;
&lt;li&gt;Принятие технических решений по клиентской части&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="trebovaniia_1"&gt;Требования&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Опыт разработки на JavaScript/CoffeeScript и валидной верстки на
    HTML5&lt;/li&gt;
&lt;li&gt;Понимание основных принципов клиентской оптимизации&lt;/li&gt;
&lt;li&gt;Суммарный опыт веб-разработки от 3 лет&lt;/li&gt;
&lt;li&gt;Усидчивость, самостоятельность и заинтересованность в качестве
    результата своей работы&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="tekhnologii_1"&gt;Технологии&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Предстоит работать со следующими технологиями:&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.insight-it.ru/goto/35c21496/" rel="nofollow" target="_blank" title="http://jinja.pocoo.org/"&gt;Jinja2&lt;/a&gt; +
    &lt;a href="https://www.insight-it.ru/goto/312f4825/" rel="nofollow" target="_blank" title="http://elsdoerfer.name/docs/webassets/"&gt;webassets&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.insight-it.ru/goto/834fa52/" rel="nofollow" target="_blank" title="http://coffeescript.org/"&gt;CoffeeScript&lt;/a&gt; +
    &lt;a href="https://www.insight-it.ru/goto/dca1748a/" rel="nofollow" target="_blank" title="http://sass-lang.com/"&gt;SASS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.insight-it.ru/goto/f573c764/" rel="nofollow" target="_blank" title="http://twitter.github.com/bootstrap/"&gt;Twitter Bootstrap&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.insight-it.ru/goto/3b02d98c/" rel="nofollow" target="_blank" title="http://jquery.com/"&gt;jQuery&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.insight-it.ru/goto/96340c7c/" rel="nofollow" target="_blank" title="http://leafletjs.com/"&gt;Leaflet&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Опыт работы именно с ними очень желателен, но не обязателен&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="zarplata_1"&gt;Зарплата&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;В диапазоне 60-100 тысяч рублей в месяц в зависимости от опыта&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="spetsialist-po-testirovaniiu_1"&gt;Специалист по тестированию&lt;/h2&gt;
&lt;h3 id="zadachi_2"&gt;Задачи&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Основные:&lt;ul&gt;
&lt;li&gt;Разработка автоматических тестов для серверной части проекта на
    Python&lt;/li&gt;
&lt;li&gt;Регрессионное тестирование сайта с помощью
    &lt;a href="https://www.insight-it.ru/goto/561c2b8c/" rel="nofollow" target="_blank" title="http://seleniumhq.org/"&gt;Selenium&lt;/a&gt; или альтернатив&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Дополнительные:&lt;ul&gt;
&lt;li&gt;Нагрузочное тестирование с использованием
    &lt;a href="https://www.insight-it.ru/goto/52bdc53f/" rel="nofollow" target="_blank" title="http://jmeter.apache.org/"&gt;JMeter&lt;/a&gt; или альтернатив&lt;/li&gt;
&lt;li&gt;Ручное визуальное тестирование, в т.ч. на кроссбраузерность&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="trebovaniia_2"&gt;Требования&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Свежий опыт тестирования интернет-проектов, желательно на Python&lt;/li&gt;
&lt;li&gt;Суммарный опыт в тестировании от 3 лет&lt;/li&gt;
&lt;li&gt;Внимательность, самостоятельность и заинтересованность в качестве
    результата работы команды&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="zarplata_2"&gt;Зарплата&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;В диапазоне 50-100 тысяч рублей в месяц в зависимости от опыта&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="usloviia_1"&gt;Условия&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Премии по достижении ключевых вех проекта&lt;/li&gt;
&lt;li&gt;Офис в центре Москвы (м. Охотный ряд, меньше 5 минут пешком)&lt;/li&gt;
&lt;li&gt;Работа на MacBook Pro&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="card orange darken-3"&gt;
&lt;p&gt;&lt;div class="card-content white-text center"&gt;
&lt;strong&gt;Вакансии более не актуальны&lt;/strong&gt;
&lt;/div&gt;&lt;/p&gt;
&lt;/div&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Иван Блинков</dc:creator><pubDate>Fri, 08 Feb 2013 10:20:00 +0400</pubDate><guid>tag:www.insight-it.ru,2013-02-08:vacancy/2013/vakansii-komanda-python-razrabotchikov-v-evaplacer/</guid><category>CoffeeScript</category><category>EVAplacer</category><category>Flask</category><category>html5</category><category>JavaScript</category><category>Jinja2</category><category>JMeter</category><category>JQuery</category><category>Leaflet</category><category>MacBook Pro</category><category>Memcached</category><category>MongoDB</category><category>Python</category><category>sass</category><category>Selenium</category><category>Solr</category><category>Twitter Bootstrap</category><category>webassets</category><category>ZeroMQ</category><category>вакансии</category><category>разработчик</category><category>тестировщик</category></item><item><title>Вакансия: Java-разработчик</title><link>https://www.insight-it.ru//vacancy/2013/vakansiya-java-razrabotchik/</link><description>&lt;div class="card orange darken-3"&gt;
&lt;p&gt;&lt;div class="card-content white-text center"&gt;
&lt;strong&gt;Вакансия более не актуальна&lt;/strong&gt;
&lt;/div&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;В крупный тур-оператор &lt;strong&gt;Библио-Глобус&lt;/strong&gt; нужен
ответственный порядочный человек, умеющий работать в команде. Крупная
компания, динамичный бизнес, постоянно меняющиеся задачи.
&lt;!--more--&gt;&lt;/p&gt;
&lt;h2 id="chto-nuzhno-budet-delat"&gt;Что нужно будет делать?&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Надо будет писать на &lt;strong&gt;Java&lt;/strong&gt; сервлеты и просто программы.&lt;/li&gt;
&lt;li&gt;Есть собственное API доступа к данным, через которые надо работать.&lt;/li&gt;
&lt;li&gt;В компании используются: &lt;strong&gt;Linux&lt;/strong&gt; (RHEL6/CentOS5),&amp;nbsp;&lt;strong&gt;nginx&lt;/strong&gt;,
    &lt;strong&gt;Java&lt;/strong&gt;, &lt;strong&gt;Oracle&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="trebovaniia-k-kandidatu"&gt;Требования к кандидату&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Опыт программирования от 3-х лет.&amp;nbsp;На чем - не так важно.&lt;/li&gt;
&lt;li&gt;Ответственность&lt;/li&gt;
&lt;li&gt;Порядочность&lt;/li&gt;
&lt;li&gt;Заинтересованность в результате&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="usloviia-raboty"&gt;Условия работы&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Зарплата - 150000 рублей в месяц&lt;/li&gt;
&lt;li&gt;Полный рабочий день&lt;/li&gt;
&lt;li&gt;Офис в Москве&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="kuda-otpravliat-reziume"&gt;Куда отправлять резюме?&lt;/h2&gt;
&lt;div class="card orange darken-3"&gt;
&lt;p&gt;&lt;div class="card-content white-text center"&gt;
&lt;strong&gt;Вакансия более не актуальна&lt;/strong&gt;
&lt;/div&gt;&lt;/p&gt;
&lt;/div&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Иван Блинков</dc:creator><pubDate>Mon, 14 Jan 2013 12:53:00 +0400</pubDate><guid>tag:www.insight-it.ru,2013-01-14:vacancy/2013/vakansiya-java-razrabotchik/</guid><category>CentOS</category><category>Java</category><category>Linux</category><category>nginx</category><category>Oracle</category><category>RHEL</category><category>Библио-Глобус</category><category>вакансия</category><category>Москва</category></item><item><title>5 лет</title><link>https://www.insight-it.ru//misc/2013/5-let/</link><description>&lt;p&gt;Сегодня у &lt;strong&gt;Insight IT&lt;/strong&gt; первый полу-юбилей, 5 лет, в связи с чем я
решил подвести небольшое резюме прошедшего года, да и всего этого
довольно значимого как для проекта, так и для меня лично, периода
времени. А также чуть-чуть пофилософствовать у будущем. &amp;nbsp;Ничего
технического не будет, читающим мой блог чисто из прагматических
соображений рекомендую не тратить свое время на нижеизложенное.&lt;/p&gt;
&lt;!--more--&gt;
&lt;p&gt;Когда я сегодня сообразил, что сегодня как раз 3-е число и
надо бы что-то по этому поводу написать, то первое, что попытался
вспомнить: когда и про что я последний раз писал? Не вспомнил... Полез
смотреть - оказалось всего чуть больше месяца назад, про &lt;a href="https://www.insight-it.ru/event/2012/web-standards-days/"&gt;очередную конференцию&lt;/a&gt;, а &lt;a href="https://www.insight-it.ru/storage/2012/obzor-riak/"&gt;по делу&lt;/a&gt; - полтора месяца, тоже не особо много. При этом оказалось, что за 2012 год я умудрился написать аж 32 поста, когда посчитал - сильно удивился. Хоть среди них и много "левых" постов, у меня никогда не было ощущения, что я публиковал по 2-3 статьи в месяц...&lt;/p&gt;
&lt;p&gt;Если попытаться найти объяснение обоим вышеизложенным фактам, оно
окажется на поверхности: &lt;em&gt;моя активность на Insight IT имеет ярко
выраженную обратную зависимость от моей профессиональной деятельности.&lt;/em&gt;
С конца весны IT-индустрия "в спячке": написал много статей, наиболее
стоящей, на мой взгляд, получилась &lt;a href="https://www.insight-it.ru/interactive/"&gt;серия статей про интерактивные сайты&lt;/a&gt;.&amp;nbsp;Осень - пора конференций и, как следствие, &lt;a href="/tag/konferencii/"&gt;отчетов по ним&lt;/a&gt;. В декабре я после очень долгого перерыва устроился на работу "за зарплату", от необходимости каждый будний день кататься в офис организм до сих пор немного в шоке :)&lt;/p&gt;
&lt;p&gt;По последнему пункту сразу попробую ответить на основные вопросы:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;В &lt;a href="https://www.insight-it.ru/goto/f1105828/" rel="nofollow" target="_blank" title="http://company.yandex.ru/"&gt;Яндекс&lt;/a&gt;;&lt;/li&gt;
&lt;li&gt;Официально - менеджером проектов;&lt;/li&gt;
&lt;li&gt;По факту - cкорее просто менеджером с сильно техническим уклоном;&lt;/li&gt;
&lt;li&gt;Про зарплату рассказывать не положено;&lt;/li&gt;
&lt;li&gt;Про технические детали - тоже, так что лежащий у меня в черновиках
    пост с заголовком &lt;strong&gt;"Архитектура Яндекса",&lt;/strong&gt; видимо, надолго там и
    останется из-за NDA, а жаль, мог бы выйти неплохим...&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Вернемся от лирического отступления обратно к Insight IT. Об итогах года
обычно говорят в цифрах. Решив в свое время публиковать полные посты в
&lt;a href="/feed/"&gt;RSS&lt;/a&gt; я обрек Insight IT на минимальную посещаемость, но циферка
в 16000+ подписчиков на счетчике FeedBurner мне по-прежнему греет душу,
&lt;em&gt;очень рад, что вы со мной&lt;/em&gt; :)&lt;/p&gt;
&lt;p&gt;Хотя на самом деле с посещаемостью тоже не все так плохо, как кажется, в
основном благодаря поисковым системам и разным другим блогам и форумам.
Раньше я всегда умалчивал цифры о посещаемости, но что-то не припомню
из-за чего именно, так что раз такое дело - опубликую данные из Google
Analytics за весь 2012 год, а если вдруг вспомню почему раньше этого не
делал - удалю:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;116k уникальных посетителей&lt;/li&gt;
&lt;li&gt;231k заходов &lt;em&gt;(visits)&lt;/em&gt;:&lt;ul&gt;
&lt;li&gt;36% с поисковых систем&lt;/li&gt;
&lt;li&gt;33% с других сайтов&lt;/li&gt;
&lt;li&gt;23% напрямую&lt;/li&gt;
&lt;li&gt;8% с других источников&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;490k просмотров страниц&lt;/li&gt;
&lt;li&gt;58% - Россия, 25% - Украина, 5% - Беларусь, 12% - остальные страны&lt;/li&gt;
&lt;li&gt;Всего 2% посетителей используют Internet Explorer, лидирует Chrome с
    49%&lt;/li&gt;
&lt;li&gt;65% - Windows, 21% - Linux, 9% - Mac OS X, 2% - Android, 2% - iOS,
    0,2% - FreeBSD, 0.8% - остальные операционные системы&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Если говорить об итогах пяти лет, я, к сожалению, не могу похвастаться
стабильным ростом... Insight IT стал &lt;em&gt;"популярным в узких кругах"&lt;/em&gt;
довольно быстро, буквально в первый же месяц я написал &lt;a href="https://www.insight-it.ru/highload/2008/arkhitektura-google/"&gt;первую успешную статью про Google&lt;/a&gt;,
которая "выстрелила" 4 февраля 2008г., потом еще несколько и
пошло-поехало. &lt;a href="https://www.insight-it.ru/highload/"&gt;Серия статей про архитектуру высоконагруженных проектов&lt;/a&gt; до сих пор вне конкуренции по спросу среди всего доступного у меня контента; она, как говорится, к прочтению обязательна.
Но быстро выйдя на уровень 1-10 тысяч читателей в день выше я
подняться, увы, до сих пор не смог. Практически единственным
исключением был, пожалуй, сезон 2010-2011, когда была написана &lt;a href="https://www.insight-it.ru/highload/2010/arkhitektura-vkontakte/"&gt;самая популярная моя статья, про Вконтакте&lt;/a&gt;.
Были и "ямы" - без притока новых постов у Insight IT остаются только
"пассивные" источники новых читателей, поисковые системы да старые
входящие ссылки. Динамику спада активности уже обсуждали чуть выше,
повторяться не буду.&lt;/p&gt;
&lt;p&gt;Если Вы &lt;a href="https://www.insight-it.ru/goto/a1390f6d/" rel="nofollow" target="_blank" title="https://twitter.com/blinkov"&gt;следите за моим Twitter&lt;/a&gt;, то Вы
уже, вероятно, в курсе, что осенью у меня возникло желание отказаться от
WordPress, в основном так как мне очень стыдно от того месива в
HTML/JavaScript/CSS коде, которое он генерирует. Еще ко всему прочему
это все очень медленно грузится, а плагины, призванные исправить данную
ситуацию, в 99% случаев ломают или функциональность, или внешний вид,
или и то и другое. К слову, стабильность и совместимость плагинов
WordPress - отдельная история, думаю многие из вас наблюдали в
октябре-ноябре сообщения о недоступности Insight IT, которые как
оказалось в ходе разбора полетов были вызваны эпизодической
несовместимостью пары плагинов с (возможно излишне) свежей версией PHP.
Статус этой истории с переездом пока на паузе, так как устраивающего
меня из коробки решения я не нашел, пока ограничился временными
полу-мерами. Но желание по-прежнему осталось - как будет возможность
постараюсь снова заняться этим вопросом.&lt;/p&gt;
&lt;p&gt;Кстати, во вступлении я обещал затронуть тему будущего Insight IT - у
меня уже далеко не раз было желание сделать из него что-то большее, чем
просто технический блог. И, возможно, переход с WordPress на какую-то
другую платформу сможет этому поспособствовать, но пока за проектом стою
только я - врядли что-то кардинально изменится. Но так или иначе будущее
Insight IT с самых первых дней всегда определял не я, а вы,
&lt;strong&gt;читатели&lt;/strong&gt;, без вас я бы давно забросил это дело.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Так что хочу посоветоваться, каким бы вы хотели видеть Insight IT в
следующем году или даже через еще 5 лет, в 2018м? Было бы интересно
обсудить в комментариях как просто темы для новых статей, так и
возможные направления кардинальных перемен.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="/feed/"&gt;До новых встреч!&lt;/a&gt;&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Иван Блинков</dc:creator><pubDate>Thu, 03 Jan 2013 23:06:00 +0400</pubDate><guid>tag:www.insight-it.ru,2013-01-03:misc/2013/5-let/</guid><category>5 лет</category><category>Insight IT</category><category>обзор</category><category>работа</category><category>статистика</category></item><item><title>Web Standards Days</title><link>https://www.insight-it.ru//event/2012/web-standards-days/</link><description>&lt;p&gt;Моё сегодняшнее путешествие на еще одну конференцию "для общего
развития" закончилось с на удивление хорошими впечатлениями. Не смотря
на скучные на&amp;nbsp;первый взгляд &amp;nbsp;названия докладов и &amp;nbsp;общую неоднозначную
тематику, мероприятие оказалось очень даже не плохим.&lt;/p&gt;
&lt;!--more--&gt;
&lt;p&gt;&lt;a href="https://www.insight-it.ru/goto/355926f4/" rel="nofollow" target="_blank" title="http://webstandardsdays.ru/"&gt;Мероприятие&lt;/a&gt; вообще независимое и
проводится во многих крупных городах СНГ, в Москве проходило на
территории Яндекса, который засветился на единственной имеющейся у меня
фотографии (к чему пробел перед запятой не знаю):&lt;/p&gt;
&lt;p&gt;&lt;img alt="WSD @ Yandex" class="responsive-img" src="https://www.insight-it.ru/images/wstdays-yandex.jpg" title="WSD @ Yandex"/&gt;&lt;/p&gt;
&lt;p&gt;Вкратце пробежимся по докладам:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Current work on CSS at W3C&lt;/strong&gt;&amp;ensp;&lt;em&gt;(Bert Bos)&lt;/em&gt;: на первое выступление я
    опоздал, видел лишь его кусочек из дома через трансляцию. На первый
    взгляд показалось довольно унылым, чуть не передумал вообще ехать
    из-за этого. Если первый взгляд оказался обманчивым - поправьте меня
    в комментариях.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;New developments in Semantic Web and Internationalization at the W3C&lt;/strong&gt;&amp;ensp;&lt;em&gt;(Felix Sasaki)&lt;/em&gt;: хоть семантический Интернет - по-прежнему
    все так же "круто", но никто, даже видимо в самом W3C, так толком и
    не знает зачем он сдался на практике. В докладе, например, был
    момент где заявлялось, что &lt;code&gt;&amp;lt;a property="http://creativecommons.org..."&lt;/code&gt;
&lt;code&gt;href="http://creativecommons.org..."&amp;gt;&lt;/code&gt;&amp;nbsp;намного более машино-читабельно &lt;em&gt;(machine readable)&lt;/em&gt;, чем &lt;code&gt;&amp;lt;a href="http://creativecommons.org..."&amp;gt;&lt;/code&gt;. А&amp;nbsp;&lt;a href="/tag/google/"&gt;Google&lt;/a&gt;,
    &lt;a href="/tag/yandex/"&gt;Яндекс&lt;/a&gt; и прочие поисковые системы значит, видимо,
    вручную &amp;nbsp;непосильным трудом миллионов китайцев каждый день строят
    поисковый индекс, так как компьютерам с атрибутом href
    самостоятельно разобраться нереально. Если хотите мое мнение: из
    всех этих "семантических" прибабахов на сегодняшний день самым
    полезным является стандарт &lt;strong&gt;hReview&lt;/strong&gt;, так как с его помощью можно
    в выдаче Google&amp;nbsp;напротив&amp;nbsp;страниц своего сайта звездочки рисовать,
    которые здорово привлекают внимание. Остальные - пока лишь теория и
    практическую пользу&amp;nbsp;среднестатистическому&amp;nbsp;интернет-проекту принести
    не могут, буду рад, если расскажете мне в комментариях, почему я не
    прав по этому вопросу..&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Yandex and W3C&lt;/strong&gt;&amp;ensp;&lt;em&gt;(Charles McCathieNevile aka Chaals)&lt;/em&gt;: я уже
    слышал этот доклад на
    &lt;a href="https://www.insight-it.ru/event/2012/yet-another-conference-2012/"&gt;YaC&lt;/a&gt;,
    из нового Чаальз чуть подробнее показал как выглядит продвигаемый&amp;nbsp;в
    W3C им и Яндексом&amp;nbsp;&lt;strong&gt;prefetch&lt;/strong&gt;. Если раньше я не придавал ему
    особого значения, то в этот раз мне это предложение показалось очень
    адекватным. По сути prefetch.txt - подобный robots.txt файлик в
    корне домена, &amp;nbsp;в котором в простом формате сайт сообщает браузеру,
    что такие-то статические ресурсы желательно заранее скачать и на
    особых условиях локально кэшировать для быстрой работы сайта.
    &lt;a href="https://www.insight-it.ru/goto/f91336cb/" rel="nofollow" target="_blank" title="http://mail.yandex.ru/prefetch.txt"&gt;Пример&lt;/a&gt;. Особо находчивые
    сейчас воскликнут, что для этого же есть AppCache
    из&amp;nbsp;&lt;a href="/tag/html5/"&gt;HTML5&lt;/a&gt;! Да, есть, но из-за обилия лишних заморочек
    эту технологию очень мало кто умеет нормально "готовить", так что у
    prefetch есть все шансы со временем вытеснить AppCache. Жаль, что на
    сегодня поддерживается почти никем, лишь Яндекс.Браузером.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;SVGO: оптимизатор SVG&lt;/strong&gt;&amp;ensp;&lt;em&gt;(Кир Белевич)&lt;/em&gt;: если вдруг Вы работаете с
    этим векторным форматом графики, имейте ввиду, что можно значительно
    &amp;nbsp;уменьшить его объем и ускорить&amp;nbsp;производительность отрисовки выкинув
    формальности, не влияющие на отображение, в ущерб, правда,
    соответствию стандартам. Для этого как раз есть некоторое количество
    утилит, в т.ч. и обсуждавшаяся SVGO.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Чётко и резко. Новая графика для экранов с высоким разрешением&lt;/strong&gt;&amp;ensp;&lt;em&gt;(Вадим Макеев)&lt;/em&gt;: очень доступно об особенностях верстки под
    современные мобильные и не очень дисплеи. Основной заключительный
    трюк доклада я слышал уже в третий раз из разных источников, так как
    все трое о нем восторженно отзываются, наверное и правда работает.
    Суть в следующем: если для сайта нужно JPEG-изображение размером
    &lt;strong&gt;X&lt;/strong&gt;x&lt;strong&gt;Y&lt;/strong&gt;, подготавливаем вместо него изображение
    &lt;strong&gt;2*X&lt;/strong&gt;x&lt;strong&gt;2*Y&lt;/strong&gt; и сохраняем его с низким качеством, порядка 20-30%
    вместо обычных 70-90%. По объему во многих случаях оно может
    оказаться даже меньше, чем традиционный аналог, но при использовании
    такого изображения оно отлично смотрится (без видимого размытия и
    JPEG-артефактов) как на обычных экранах, так и на экранах с высоким
    соотношением физического пикселя к виртуальному (которые как раз и
    называют "retina"). Про это соотношение &amp;nbsp;краткая справка: физический
    пиксель - лампочка на матрице, виртуальный - единица измерения,
    которая и используется в CSS; у обычных экранов это соотношение
    равно 1 или даже меньше; у Android бывает 1.5; у "ретиновой"
    продукции Apple и флагманских смартфонов/планшетов - 2; больше двух
    тоже бывает, но в природе встречается редко, почти никогда.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Паттерны Javascript&lt;/strong&gt;&amp;ensp;&lt;em&gt;(Антон Немцев)&lt;/em&gt;: доклад и правда об очень
    базовых вещах в JavaScript, но с шутками и картинками, &amp;nbsp;который все
    равно позволил мне обнаружить некоторые неудачные моменты в своем
    клиентском коде. По делу и не скучно.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Grunt. Система сборки для фронтенд-разработчиков&lt;/strong&gt;&amp;ensp;&lt;em&gt;(Артём
    Сапегин)&lt;/em&gt;: в общем-то заголовок передает всю суть доклада, добавлю
    лишь, что он полностью на &lt;a href="/tag/javascript/"&gt;JavaScript&lt;/a&gt;&amp;nbsp;и имеет
    200+ плагинов на все случаи жизни. &amp;nbsp;Я как-то по старинке пользуюсь
    для этого &lt;a href="https://www.insight-it.ru/goto/5908cea6/" rel="nofollow" target="_blank" title="https://github.com/miracle2k/webassets"&gt;webassets&lt;/a&gt;, хотя
    возможно и зря, надо будет по-детальнее взвесить за и против этих
    двух и подобных продуктов.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Адаптивный веб-дизайн &amp;mdash; Что? Где? Когда?&lt;/strong&gt;&amp;ensp;&lt;em&gt;(Анна Селезнёва)&lt;/em&gt;:
    отзывчивый дизайн &lt;em&gt;(responsive web design)&lt;/em&gt; - лишь небольшая часть
    адаптивного &lt;em&gt;(adaptive)&lt;/em&gt;. Последний включает в себя не только
    перераспределение содержимого веб-страниц при разном разрешении
    экрана, но и приспособление под разные типы управляющих устройств
    (не только сенсорные экраны, но и стилус, клавиатуры, читающий вслух
    софт для слепых и пр.), а также по-хорошему к нему же относятся &amp;nbsp;и
    вещи вроде стилей для печати веб-страниц.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Getting touchy&lt;/strong&gt;&amp;ensp;&lt;em&gt;(Patrick H. Lauke)&lt;/em&gt;: докладчик, видимо на
    досуге, детально ковыряется в том, каким образом в JavaScript
    создаются события на основе различных жестов, как эмулируется мышь и
    прочих подобных штуках. &amp;nbsp;Мораль доклада: для большинства простых
    сайтов стандартная эмуляция мыши мобильными браузерами вполне
    достаточна, различные трюки с сенсорными &lt;em&gt;(touch)&lt;/em&gt; событиями нужны
    лишь в определенных элементах (вроде слайдшоу или динамики внутри
    тега &lt;code&gt;&amp;lt;canvas&amp;gt;&lt;/code&gt;), требующих повышенной интерактивности, за которую
    нужно быть готовыми платить. Платить как местами низкой
    производительностью, так и &amp;nbsp;ограничением стандартных механизмов
    браузера - как минимум масштабированием&amp;nbsp;&lt;em&gt;(pinch to zoom)&lt;/em&gt; и/или
    пролистыванием&amp;nbsp;&lt;em&gt;(scrolling)&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Технолог &amp;mdash; тоже дизайнер&lt;/strong&gt;&amp;ensp;&lt;em&gt;(Артём Поликарпов)&lt;/em&gt;: вся соль доклада лежала в одном его слайде:
    &amp;gt; "Если дизайнер не показал, как делать что-то, нельзя делать вид, что этого нет".
    Все остальное было лишь примерами того, как это может выглядеть на
    практике, в духе как будет выглядеть кнопочка, если её отключить,
    что делать с чрезмерно длинными заголовками и пр. В обсуждении
    докладчику&amp;nbsp;досталось&amp;nbsp;за то, что он не обратил внимание на то, что не
    смотря на всяческие плюсы данного подхода, обязательно нужно быть
    готовым нести полную ответственность за собственное творчество. Если
    "технолог" не видит всей картины проекта (а это практически всегда
    так), подобным "творчеством" можно сильно навредить, особенно если
    никого не&amp;nbsp;предупредить&amp;nbsp;о его существовании, хотя бы дизайнера, а
    лучше и всех других заинтересованных лиц.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Круглый стол с экспертами W3C, Яндекса и Opera Software&lt;/strong&gt; &amp;ensp;&lt;em&gt;(все иностранные гости)&lt;/em&gt;: обсуждались всякие формальности взаимодействия
    внутри и снаружи W3C и проектов вроде
    &lt;a href="https://www.insight-it.ru/goto/a8f3b207/" rel="nofollow" target="_blank" title="http://www.webstandards.org/"&gt;webstandards.org&lt;/a&gt;.&amp;nbsp;Ничего практически
    полезного, к сожалению, "со стола" не унес, думаю, и аудитория и
    выступающие к тому моменту уже порядком подустали. Разве что был
    интересный момент о том, что независимому эксперту для попадания в
    подобные организации необходимо активно тусоваться в тематических
    группах почтовых рассылок &lt;em&gt;(mailing list)&lt;/em&gt;, мозолить всем глаза, а
    также реально заниматься чем-то общественно полезным, что может хотя
    бы чуть-чуть изменит мир в лучшую сторону.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Вместо заключения повторюсь, что мероприятие вопреки моим ожиданиям
оказалось довольно качественным. Подробности по докладам, презентации,
может быть даже со временем видео и т.п. см. на страничке
&lt;a href="https://www.insight-it.ru/goto/46069b1f/" rel="nofollow" target="_blank" title="http://events.yandex.ru/events/yagosti/wsd-msk-nov-2012/"&gt;Яндекса&lt;/a&gt;&amp;nbsp;о
&lt;strong&gt;Web Standards Days&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;По традиции рекомендую &lt;a href="/feed/"&gt;подписаться на Insight IT через RSS&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Иван Блинков</dc:creator><pubDate>Sun, 25 Nov 2012 01:22:00 +0400</pubDate><guid>tag:www.insight-it.ru,2012-11-25:event/2012/web-standards-days/</guid><category>html5</category><category>web standards</category><category>Web Standards Days</category><category>веб стандарты</category><category>конференции</category><category>мероприятия</category><category>Яндекс</category></item><item><title>Обзор Riak</title><link>https://www.insight-it.ru//storage/2012/obzor-riak/</link><description>&lt;p&gt;&lt;a href="https://www.insight-it.ru/goto/243e6801/" rel="nofollow" target="_blank" title="http://basho.com/products/riak-kv/"&gt;Riak&lt;/a&gt; - распределенная
&lt;em&gt;opensource&lt;/em&gt;&amp;nbsp;база данных, разработанная на &lt;a href="/tag/erlang/"&gt;Erlang&lt;/a&gt; и
спроектированная в расчете на:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Высокую доступность и устойчивость к сбоям;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Масштабируемость и простоту обслуживания;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Универсальность.&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;У проекта отличная&amp;nbsp;&lt;a href="https://www.insight-it.ru/goto/e20af489/" rel="nofollow" target="_blank" title="https://docs.basho.com/riak/latest/"&gt;официальная документация&lt;/a&gt;&amp;nbsp;на английском, далее же в этой статье я расскажу об основных её особенностях чуть подробнее, а также хитростях и подводных камнях, выявленных в процессе применения на практике (с перспективы веб-разработки).&lt;/p&gt;
&lt;!--more--&gt;
&lt;h2 id="vysokaia-dostupnost-i-ustoichivost-k-sboiam"&gt;Высокая доступность и устойчивость к сбоям&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Все данные в кластере&amp;nbsp;&lt;em&gt;реплицируются&lt;/em&gt; по принципу соседей на хэш
    кольце (см. логотип для иллюстрации) и даже в случае сбоев
    &lt;em&gt;доступны&lt;/em&gt; посредством интеллектуального перенаправления запросов
    внутри кластера.&lt;/li&gt;
&lt;li&gt;В случае возникновения коллизий из-за разрыва сетевого соединения
    или просто одновременной записи, на запрос получения данных &lt;em&gt;может
    вернуться несколько версий&lt;/em&gt; и приложение само может решить как их
    объединить или какую версию использовать.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="masshtabiruemost-i-prostota-obsluzhivaniia"&gt;Масштабируемость и простота обслуживания&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Добавление нового сервера тривиально путем копирования конфига и
    одной команды.&lt;/li&gt;
&lt;li&gt;Перераспределение данных и все остальное прозрачно происходит за
    сценой.&lt;/li&gt;
&lt;li&gt;Минимальный рекомендуемый размер Riak кластера - 5 серверов, меньшее
    количество не дает раскрыть весь потенциал.&lt;/li&gt;
&lt;li&gt;Одинаково легко обслуживать как маленький, так и большой кластер.&lt;/li&gt;
&lt;li&gt;Есть коммерческая &lt;em&gt;Enterprise&lt;/em&gt; версия с поддержкой от &lt;strong&gt;Basho&lt;/strong&gt;,
    компании-разработчика Riak (изначально выходцы из Akamai),
    равноправной зашифрованной репликацией между датацентрами и
    поддержкой &lt;em&gt;SNMP&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;Есть встроенный веб-интерфейс для мониторинга и управления
    кластером, у меня правда так и не дошли руки его освоить:&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="video-container"&gt;
&lt;iframe allowfullscreen="" frameborder="0" height="480" src="//www.youtube.com/embed/R0_PLMCrtZw?rel=0" width="853"&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;h2 id="universalnost"&gt;Универсальность&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Схема отсутствует, ключи и данные - произвольные бинарные строки.
    Ключи располагаются в пространствах имен &lt;em&gt;(bucket)&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;Сериализация - на усмотрение разработчика, популярные варианты -
    Erlang'овский &lt;em&gt;BERT&lt;/em&gt;, &lt;em&gt;JSON&lt;/em&gt; для других платформ, можно использовать
    просто как &lt;em&gt;файловую систему&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;Модульная система хранилищ данных, альтернатив много, основная -
    &lt;a href="/tag/google/"&gt;Google&lt;/a&gt; &lt;a href="/tag/leveldb/"&gt;LevelDB&lt;/a&gt;;&amp;nbsp;еще интересный
    вариант с хранением полностью в оперативной памяти - получается
    продвинутый распределенный кэш с репликацией, поиском и пр.&lt;/li&gt;
&lt;li&gt;Гибко настраиваемое количество узлов кластера, которые должны
    подтвердить успешность операции, чтобы она считалась успешной: можно
    указывать для всего кластера, пространства имен и даже конкретного
    запроса. Riak в любом случае остается eventually consistent базой
    данных (AP из CAP теоремы), но с возможностью управлять балансом
    производительности операций и надежностью выполнения запросов.&lt;/li&gt;
&lt;li&gt;Три интерфейса доступа &lt;em&gt;(API)&lt;/em&gt;:&lt;ul&gt;
&lt;li&gt;&lt;a href="/tag/protocol-buffers/"&gt;Google ProtocolBuffers&lt;/a&gt; - для основного
    использования в боевых условиях.&lt;/li&gt;
&lt;li&gt;&lt;a href="/tag/http/"&gt;HTTP&lt;/a&gt; &lt;a href="/tag/rest/"&gt;REST&lt;/a&gt; - для использования в
    языках, где нет готового клиента на ProtocolBuffers и для того,
    чтобы по-быстрому что-то посмотреть из консоли через curl. Хотя
    по факту клиенты для большинства языков программирования есть и
    проще делать запросы через интерпретатор.&lt;/li&gt;
&lt;li&gt;Еще есть прямой интерфейс Erlang-сообщений, но даже из самого
    Erlang им пользоваться не рекомендуют, не говоря уже о
    реализациях Erlang node (BERT) на других платформах.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Вместе с данными хранятся метаданные для разных целей, которые
    используются в соответствующих типах запросов:&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.insight-it.ru/goto/3d61cc81/" rel="nofollow" target="_blank" title="http://ru.wikipedia.org/wiki/%D0%92%D0%B5%D0%BA%D1%82%D0%BE%D1%80%D0%BD%D1%8B%D0%B5_%D1%87%D0%B0%D1%81%D1%8B"&gt;Векторные часы&lt;/a&gt;
    для разрешения конфликтов версий данных&amp;nbsp;&lt;em&gt;(обязательно, есть
    автоматическое разрешение);&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;Индекс для полнотекстного поиска &lt;em&gt;(концептуально позаимствован у
    &lt;a href="/tag/lucene/"&gt;Lucene&lt;/a&gt;/&lt;a href="/tag/solr/"&gt;Solr&lt;/a&gt;, опционально);&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;Индекс для простых выборок &lt;em&gt;(по бинарным и числовым полям,
    опционально);&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;Связанные ключи &lt;em&gt;(отдаленный аналог внешних ключей,
    опционально).&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Встроенная поддержка &lt;a href="/tag/mapreduce/"&gt;MapReduce&lt;/a&gt;, фазы можно
    реализовывать на &lt;a href="/tag/erlang/"&gt;Erlang&lt;/a&gt; или
    &lt;a href="/tag/javascript/"&gt;JavaScript&lt;/a&gt;;&amp;nbsp;для обоих языков есть библиотека с
    наиболее популярными случаями, которые можно использовать для
    образца.&lt;/li&gt;
&lt;li&gt;Есть поддержка выполнения операций до/после операций записи/чтения
    &lt;em&gt;(hooks)&lt;/em&gt;, чаще всего используются для построения полнотекстного
    индекса, но можно реализовать и свои, специфичные для приложения.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="nedokumentirovannye-vozmozhnosti"&gt;Недокументированные возможности&lt;/h2&gt;
&lt;p&gt;Пока я их нашел всего две:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Счетчики:&lt;/strong&gt;&amp;nbsp;как такового API в для&amp;nbsp;увеличения/уменьшения числовых
    значений &lt;em&gt;(increment/decrement)&lt;/em&gt; в Riak нет, так как он не лезет
    внутрь хранящихся данных. Зато есть векторные часы, которые растут с
    каждой операцией записи по ключу. Чтобы реализовать увеличение
    &lt;em&gt;(increment)&lt;/em&gt; необходимо записать в Riak пустую бинарную строку с
    опцией &lt;em&gt;return_body,&amp;nbsp;&lt;/em&gt;и у вернувшегося значения сложить все поля в
    векторных часах. &lt;a href="https://www.insight-it.ru/goto/6a894d09/" rel="nofollow" target="_blank" title="https://gist.github.com/4061705"&gt;Пример на
    Erlang&lt;/a&gt;. Если нужно еще и
    уменьшение (decrement) этого можно добиться с помощью пары счетчиков
    "плюс и минус" и вычитать второе значение из первого. Для&amp;nbsp;авто
    инкремента&amp;nbsp;основных ключей не самый лучший вариант, но для не особо
    критичных случаев вполне себе работает.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Выборка по списку ключей &lt;em&gt;(multiget)&lt;/em&gt;:&amp;nbsp;&lt;/strong&gt;такого API тоже нет, но
    здесь на выручку приходит &lt;em&gt;MapReduce&lt;/em&gt;. Это, пожалуй, наиболее
    популярное его применение. На вход подаем имеющийся список ключей и
    используем фазы из готовой библиотеки: &lt;em&gt;reduce_set_union&lt;/em&gt; и
    &lt;em&gt;map_identity&lt;/em&gt;. Данные возвращаются&amp;nbsp;неотсортированные &amp;nbsp;и требуют
    небольшой обертки на выходе, но все равно это намного быстрее, чем
    последовательно проходить по списку ключей и делать для каждого
    обычный &lt;em&gt;get&lt;/em&gt;. &lt;a href="https://www.insight-it.ru/goto/d557f797/" rel="nofollow" target="_blank" title="https://gist.github.com/4061784"&gt;Пример на Erlang&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="card blue lighten-4"&gt;
&lt;p&gt;&lt;div class="card-content"&gt;
Буду рад, если Вы поможете мне дополнить этот список, оставив известные
Вам подобные трюки в комментариях.
&lt;/div&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;h2 id="podvodnye-kamni"&gt;Подводные камни&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Если в Вашем приложении необходима функциональность &lt;strong&gt;постраничного
    просмотра отсортированных данных&lt;/strong&gt; &lt;em&gt;(pagination)&lt;/em&gt;, то будьте готовы
    реализовать её на клиенте. То есть Riak быстро сделал нужную выборку
    всех "страниц" и уже на клиенте её придется отсортировать и выкинуть
    лишнее. Вообще в большинстве случаев результаты запросов к Riak
    приходят в произвольном порядке из-за его распределенной природы.&lt;/li&gt;
&lt;li&gt;В продолжение к предыдущему: в &lt;a href="https://www.insight-it.ru/goto/1093e454/" rel="nofollow" target="_blank" title="https://docs.basho.com/riak/latest/dev/using/search/"&gt;REST Solr интерфейсе&lt;/a&gt;&amp;nbsp;есть
    аргументы (в ProtoBuf это тоже добавили в одной из последних
    версий), которые, казалось бы, достаточны для реализации
    постраничного просмотра: &lt;strong&gt;sort&lt;/strong&gt;, &lt;strong&gt;start&lt;/strong&gt;, &lt;strong&gt;rows&lt;/strong&gt; - что еще
    нужно? На практике оно работает не так, как было бы логично.
    Сортировка по значению (заданная в sort) применяется ПОСЛЕ того, как
    была отсчитана страница по start и rows. Они отмеряются по ключам
    или рейтингу значения в полнотекстном поиске и никак иначе. С тем же
    успехом эти 5-10 значений можно очень быстро отсортировать и на
    клиенте. Зачем-то это может быть и нужно, но в моем случае оказалось
    совершенно бесполезно.&lt;/li&gt;
&lt;li&gt;У Riak есть 4 основных типа запросов: простой
    get/set,&amp;nbsp;полнотекстовый&amp;nbsp;поиск, вторичные ключи &lt;em&gt;(secondary
    indices)&lt;/em&gt;, МapReduce и проход по связанным ключам &lt;em&gt;(link walking)&lt;/em&gt;.&lt;ul&gt;
&lt;li&gt;Если Ваши данные являются сериализованным JSON, BERT или XML, то
    в большинстве случаев Вам нужны лишь первые два из них,
    исключение - упомянутая выше выборка по списку ключей через
    MapReduce.&lt;/li&gt;
&lt;li&gt;Основной сценарий использования вторичных индексов - метаданные
    к произвольным неструктурированным бинарным данным, например в
    случае с аналогом файловой системы. Либо совсем примитивные
    случаи, когда правда нужно сделать простую выборку по одному
    целочисленному полю, что бывает редко.&lt;/li&gt;
&lt;li&gt;Если данные сериализованы, то связанные ключи проще хранить
    внутри данных, а не средствами СУБД. Разницы в
    производительности нет, в итоге делается тот же MapReduce с теми
    же фазами.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Хоть Riak "из коробки" и правда надежнее многих других СУБД и 1-2
    упавших/отключенных сервера в кластере внешне практически не
    заметны, есть одно но. Если один узел упал - соединения всех
    подключенных к нему клиентов теряются. Два основных
    пути&amp;nbsp;преодоления&amp;nbsp;этого момента:&lt;ul&gt;
&lt;li&gt;Если кластер клиентов и кластер Riak расположены на разных
    серверах, то между ними можно поставить отказоустойчивый TCP
    балансировщик нагрузки, в частности &lt;a href="/tag/haproxy/"&gt;HAProxy&lt;/a&gt; или
    &lt;a href="/tag/ipvs/"&gt;IPVS&lt;/a&gt; здесь наиболее органично вписываются.&lt;/li&gt;
&lt;li&gt;Если на одних и тех же, то есть вариант поставить балансировщик
    нагрузки перед клиентами (для веба возможно и в HTTP/HTTPS
    режиме), а каждый клиент подключается к своему локальному
    серверу Riak и если один, другой или оба сразу упали, то
    отрубать весь физический сервер целиком.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="vyvody"&gt;Выводы&lt;/h2&gt;
&lt;p&gt;Riak отлично подходит для многих вариантов использования, как в Интернет
среде, так и в смежных вроде телекома. Обладает отличным набором
положительных "черт характера", о которых шла речь в начале статьи.
Прекрасно справляется с большим потоком как операций записи, так и
операций чтения.&lt;/p&gt;
&lt;p&gt;Как уже упоминалось, практически единственный сценарий, где Riak совсем
не справляется, это выборки по большим объемам данных с сортировкой и
постраничным выводом. Но даже в этом случае никто не мешает использовать
отдельный сервис, который будет индексировать нужным образом данные и
подготавливать список идентификаторов для последующей multiget выборки
из Riak. К слову, проекты по этой части уже появляются, например
&lt;a href="https://www.insight-it.ru/goto/1232aa05/" rel="nofollow" target="_blank" title="https://github.com/rzezeski/yokozuna"&gt;Yokozuna&lt;/a&gt; - интеграция
полноценного Solr с Riak &lt;em&gt;(Riak Search - лишь частичный порт Solr+Lucene
на Erlang)&lt;/em&gt;.&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Иван Блинков</dc:creator><pubDate>Tue, 13 Nov 2012 02:09:00 +0400</pubDate><guid>tag:www.insight-it.ru,2012-11-13:storage/2012/obzor-riak/</guid><category>Basho</category><category>Erlang</category><category>LevelDB</category><category>Protocol Buffers</category><category>REST</category><category>Riak</category><category>БД</category><category>обзор</category><category>СУБД</category></item><item><title>Оптимизация интерактивных сайтов</title><link>https://www.insight-it.ru//interactive/2012/optimizaciya-interaktivnykh-sajjtov/</link><description>&lt;p&gt;Возвращаясь к теме&amp;nbsp;&lt;a href="https://www.insight-it.ru/interactive/"&gt;"Интерактивных сайтов"&lt;/a&gt;,&amp;nbsp;сегодня я хотел бы обсудить заключительную часть повествования, их
&lt;strong&gt;оптимизацию&lt;/strong&gt;. Возможно вы уже успели реализовать все или часть
обсуждавшихся в предыдущих статьях приемов, в этой статье я "подкину"
Вам еще несколько.&amp;nbsp;Настоятельно рекомендую прежде чем читать дальше
ознакомиться хотя бы с первой статьей про общую архитектуру, а лучше,
конечно, со всеми предыдущими статьями серии. В этот раз мы пройдемся по
всем обсуждавшимся в отдельных статьях компонентам, правда в другом
порядке, и будем обсуждать возможные пути их улучшения.&lt;/p&gt;
&lt;!--more--&gt;
&lt;h2 id="oglavlenie-serii-interaktivnye-saity"&gt;Оглавление серии "Интерактивные сайты"&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://www.insight-it.ru/interactive/2012/arkhitektura-interaktivnykh-sajjtov/"&gt;Общая архитектура&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.insight-it.ru/interactive/2012/klientskaya-chast-interaktivnogo-sajjta/"&gt;Организация клиентской части&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.insight-it.ru/interactive/2012/postoyannoe-soedinenie-mezhdu-brauzerom-i-serverom/"&gt;Постоянное соединение между браузером и сервером&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.insight-it.ru/interactive/2012/povtornoe-ispolzovanie-shablonov/"&gt;Повторное использование шаблонов&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.insight-it.ru/interactive/2012/servernaya-chast-interaktivnogo-sajjta-i-potoki-soobshhenijj/"&gt;Серверная часть интерактивного сайта и потоки сообщений&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href="https://www.insight-it.ru/interactive/2012/optimizaciya-interaktivnykh-sajjtov/"&gt;Оптимизация&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="servernaia-chast"&gt;Серверная часть&lt;/h2&gt;
&lt;p&gt;На серверной стороне есть масса простора для оптимизации, но, чтобы не
распыляться, постараюсь сосредоточиться лишь на том, что напрямую
связано с темой &lt;em&gt;интерактивных сайтов&lt;/em&gt;. В частности на процессе
маршрутизации сообщений и уведомлений между пользователями.&lt;/p&gt;
&lt;p&gt;Когда разрабатывается первая версия сайта, то многие части функционала
проще всего реализовать в виде массовых рассылок, как-то так: произошло
какое-то публично-доступное событие, допустим кто-то куда-то поставил
"мне нравится", отправляем его в брокер сообщений с пометкой "доставить
всем" &lt;em&gt;(fanout)&lt;/em&gt;. В итоге все подключенные на данный момент клиенты
получают это уведомление и каждый сам решает что с ним делать - что-то
менять на текущей странице или просто проигнорировать.&lt;/p&gt;
&lt;p&gt;Но при большом количестве соединений и потоке событий такой подход
становится роскошью. Большинство подобных ситуаций можно реализовать
подпиской на тематические &lt;em&gt;(topic)&lt;/em&gt; рассылки для каждого пользователя
индивидуально, то есть когда пользователь открывает ту или иную
страницу - серверная сторона должна подписать его на уведомления,
связанные именно с тем контентом, который находится у него на экране.
Это позволит свести к минимуму количество&amp;nbsp;доставленных&amp;nbsp;зря сообщений.&lt;/p&gt;
&lt;p&gt;Ситуации, когда правда нужны массовые рассылки по всем пользователям,
хоть и редки, но все же бывают. Если есть возможность их избежать, то
лучшей ей воспользоваться.&lt;/p&gt;
&lt;p&gt;Чтобы реализовать индивидуальные подписки как изложено выше, вероятно
понадобится еще и изменить принцип установления соединений между
брокером сообщений и сервером, поддерживающим постоянное соединение. Для
схемы массовых рассылок достаточно одного такого соединения на сервер.
Каждый сервер хранит список активных соединений с браузерами и, получив
новое сообщение от брокера, просто итеративно проходится по нему,
ретранслируя сообщение в каждое соединение. В таком случае для
последнего соединения в списке задержка может достигать нескольких
секунд, что не всегда приемлемо. Для схемы индивидуальных подписок есть
два основных варианта:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Реализовать мини-брокер внутри каждого такого сервера, т.е. сам
    сервер по-прежнему держит лишь одно соединение с настоящим брокером
    и получает все подряд сообщения, но прежде чем ретранслировать
    анализирует его и отправляет лишь части соединений.&lt;/li&gt;
&lt;li&gt;Либо держать создавать много примитивных процессов, которые с одной
    стороны держат соединение с браузером, с другой - с брокером. Каждый
    из них подписан именно на те сообщения, которые нужны данному
    пользователю, и ретранслируют их все без анализа.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="card blue lighten-4"&gt;
&lt;p&gt;&lt;div class="card-content"&gt;
Оба варианта имеют право на существование, какой окажется лучше -
зависит от многих факторов, нужно тестировать. Лично мне больше по душе
второй, но далеко не на каждой платформе его удастся эффективно
реализовать - настоящих системных процессов для такого использования
не&amp;nbsp;напасешься.
&lt;/div&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;h2 id="postoiannoe-soedinenie-mezhdu-brauzerom-i-serverom"&gt;Постоянное соединение между браузером и сервером&lt;/h2&gt;
&lt;p&gt;Помимо выбора удачной библиотеки абстракции протоколов для различных
браузеров, о чем я уже довольно подробно писал в соответствующей статье
серии, здесь я могу предложить еще два момента для значительного
улучшения производительности.&lt;/p&gt;
&lt;h3 id="mezhvkladochnoe-vzaimodeistvie-cross-tab-communication"&gt;Межвкладочное взаимодействие &lt;em&gt;(cross-tab communication)&lt;/em&gt;&lt;/h3&gt;
&lt;p&gt;На эту тему в Интернете ходит масса слухов и разговоров, но адекватной
инструкции о том как это можно кроссбраузерно организовать в разумные
сроки я не встречал, если кто знает - дайте в ссылку в комментариях,
пожалуйста. А я пока попробую поделиться своим опытом.&lt;/p&gt;
&lt;p&gt;Вкратце для тех, кто не в курсе: в самой простой реализации постоянное
соединение между браузером и сервером устанавливается для каждой вновь
открытой вкладки заново. Так как каждое такое соединение ресурсоемко, то
этого хотелось бы избежать. Помочь в этом может организация
&lt;strong&gt;межвкладочного взаимодействия&lt;/strong&gt; или, другими словами, общения между
вкладками/окнами браузера: одна вкладка избирается &lt;em&gt;главной&lt;/em&gt; и
устанавливает соединение с сервером, когда она получает новое
сообщение - она переправляет его конкретной открытой вкладке или же всем
сразу; те же, в свою очередь, когда хотят отправить сообщение на сервер,
отправляют его сначала &lt;em&gt;главной&lt;/em&gt; вкладке, а та уже пересылает на сервер.
В итоге все работает как и раньше, но соединений не больше одного на
браузер.&lt;/p&gt;
&lt;p&gt;Вообще в явном виде общение между вкладками браузера, как Вы, вероятно,
знаете, не предусмотрено. Именно из-за этого реализовать это все
кроссбраузерно не просто. Для начала приведу список технологий, которые
так или иначе можно для этого приспособить, большинство из них принято
относить к нынче модному &lt;a href="/tag/html5/"&gt;HTML5&lt;/a&gt;, в порядке возрастания
моих симпатий:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.insight-it.ru/goto/704e1f8a/" rel="nofollow" target="_blank" title="http://en.wikipedia.org/wiki/Local_shared_object"&gt;Flash Local Shared Cookies&lt;/a&gt; - даже не рассматривал как вариант, так как требуется Adobe Flash, плюс, кажется, постоянно всплывает окно вроде
    &lt;a href="https://www.insight-it.ru/goto/e9a669cc/" rel="nofollow" target="_blank" title="http://www.macromedia.com/support/documentation/en/flashplayer/help/help06.html"&gt;этого&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.insight-it.ru/goto/732af670/" rel="nofollow" target="_blank" title="http://caniuse.com/#feat=x-doc-messaging"&gt;postMessage&lt;/a&gt;&amp;nbsp;-&amp;nbsp;отправка
    сообщения указанному окну по его идентификатору. Поддержка
    браузерами хорошая, но большинство примеров показывают общение с
    iframe, а сопутствующего API для получения списка всех открытых
    окон/вкладок я не нашел, может быть плохо искал.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.insight-it.ru/goto/86256a54/" rel="nofollow" target="_blank" title="http://caniuse.com/#feat=webworkers"&gt;Web Workers&lt;/a&gt; - в браузере
    создается не зависящий от вкладок поток, с которым можно общаться из
    вкладок. Поддержка браузерами хромает, а там где её нет -
    polyfill'ов пока не придумали.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.insight-it.ru/goto/fc6c98e9/" rel="nofollow" target="_blank" title="http://caniuse.com/#feat=namevalue-storage"&gt;Web Storage&lt;/a&gt; -
    локальное хранилище пар ключ-значение с ограничением в 5-10Мб на
    домен. Хорошая поддержка браузерами, а там где её нет - есть
    polyfill'ы. Еще бывает &lt;a href="https://www.insight-it.ru/goto/71a12fd0/" rel="nofollow" target="_blank" title="http://caniuse.com/#feat=sql-storage"&gt;Web SQL&lt;/a&gt;, но для данной задачи это уже перебор.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;В общем рекомендую последний вариант, из дополнительных плюсов хранилище
можно использовать и для других целей, но об этом в следующих разделах.&lt;/p&gt;
&lt;p&gt;Если есть желание и время можно работать напрямую с API хранилища, но
все же самостоятельно разбираться с особенностями браузеров - занятие не
благодарное, так что могу посоветовать взглянуть на имеющиеся opensource
библиотеки-обертки. Из тех, что я пробовал, мне больше всего нравится
&lt;strong&gt;&lt;a href="https://www.insight-it.ru/goto/288f4119/" rel="nofollow" target="_blank" title="http://www.jstorage.info/"&gt;jStorage&lt;/a&gt;&lt;/strong&gt;&amp;nbsp;из-за своей "зеленой" таблицы
поддержки браузерами и готовому publish/subscribe API.&lt;/p&gt;
&lt;p&gt;Итак, вкратце пройдемся по ориентировочному алгоритму реализации
межвкладочного взаимодействия:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Каждая вкладка при своем открытии придумывает себе уникальный
    идентификатор (проще всего на основе &lt;em&gt;Math.random&lt;/em&gt;), будем называть
    его &lt;strong&gt;tab_id&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;В хранилище будут храниться список всех активных tab_id, допустим,
    &lt;strong&gt;tabs&lt;/strong&gt; и tab_id &lt;em&gt;главной&lt;/em&gt; &lt;em&gt;вкладки&lt;/em&gt;, допустим,&amp;nbsp;&lt;strong&gt;master&lt;/strong&gt;. Каждая
    новая вкладка смотрит есть ли другие открытые вкладки. Если есть -
    просто дописывает себя в tabs, если нет - то еще и объявляет себя
    главной и открывает соединение с браузером.&lt;/li&gt;
&lt;li&gt;Далее она подписывается на сообщения отправленные лично ей (по её
    tab_id) и на различные типы сообщений, которые могут быть интересны
    всем вкладкам.&lt;/li&gt;
&lt;li&gt;В обработчике события &lt;em&gt;window.onbeforeunload&lt;/em&gt;&amp;nbsp;(происходит сразу же
    перед закрытием вкладки) каждая вкладка убирает себя из &lt;strong&gt;tabs&lt;/strong&gt;&amp;nbsp;и
    если она была главной, то и из &lt;strong&gt;master&lt;/strong&gt; тоже. Альтернативный
    вариант: &lt;strong&gt;master&lt;/strong&gt; сразу может выбирать себе "преемника". Так как
    это событие срабатывает не всегда (когда компьютер жестко вырубился
    питанием, фатальный сбой в браузере, плюс оно не поддерживается
    неоправданно популярной в рунете Оперой и мобильным Safari), то
    придется создать альтернативный механизм проверки активности
    &lt;strong&gt;master&lt;/strong&gt; и очистки &lt;strong&gt;tabs&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Так как какого-либо API для проверки открыта ли вкладка по её
    &lt;strong&gt;tab_id&amp;nbsp;&lt;/strong&gt;по очевидным причинам нет, нужно придумать свою схему.
    Самый простой рабочий вариант, пришедший мне в голову:&lt;ul&gt;
&lt;li&gt;Главная вкладка пишет каждые несколько сотен&amp;nbsp;миллисекунд&amp;nbsp;в
    хранилище текущую дату/время, теоретически так как все
    происходит на одном компьютере, то текущее время во всех
    вкладках должно быть одно и то же;&lt;/li&gt;
&lt;li&gt;Не-главные вкладки каждые 1-3 секунд читают значение из того же
    места в хранилище и если оно отстает от текущего на, допустим,
    больше чем секунду, то главную вкладку, вероятно, закрыли и надо
    её "свергнуть" - удалить из &lt;strong&gt;tabs&lt;/strong&gt; и &lt;strong&gt;master&lt;/strong&gt;&amp;nbsp;и назначить,
    например, первую или последнюю запись из списка&amp;nbsp;&lt;strong&gt;tabs&lt;/strong&gt; новой
    главной вкладкой;&lt;/li&gt;
&lt;li&gt;Если выбранная новая вкладка тоже оказалась уже закрыта, не
    беда - во всех случаях, кроме совсем неадекватных, этот не
    хитрый механизм переберет все&amp;nbsp;&lt;strong&gt;tabs&lt;/strong&gt; и найдет-таки нормальную
    открытую;&lt;/li&gt;
&lt;li&gt;Каждая вкладка подписывается на изменения значения &lt;strong&gt;master&lt;/strong&gt;,
    чтобы если новое значение совпадет с её tab_id открыть
    соединение с сервером.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Отправка сообщений происходит по простому publish/subscribe, где
    master подписывается и ретранслирует в соединение с сервером, а
    отправляют все остальные вкладки. Если вкладка отправляет запрос,
    ответ на который хочет получить только она сама (чаще всего переход
    на другую страницу сайта или отправка формы), то она указывает в
    отправляемом запросе свой "обратный адрес" в виде tab_id. Master,
    получив ответ на такое сообщение с указанным обратным адресом,
    перенаправляет его отправителю.&lt;/li&gt;
&lt;li&gt;Также в хранилище полезно иметь переменную-флаг (также с подпиской
    на изменения), обозначающую открыто ли сейчас где-то постоянное
    соединение, чтобы вместо того, чтобы отправлять сообщения&amp;nbsp;в
    никуда&amp;nbsp;вкладки использовали какой-то альтернативный способ (AJAX или
    переход по ссылке / отправка формы средствами браузера). В качестве
    альтернативы можно реализовать очередь неотправленных сообщений, но
    по факту когда с соединением проблемы, то неизвестно когда они
    устранятся и устранятся ли вообще, так что смысла в ней чаще всего
    мало.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Надеюсь вышеизложенное окажется кому-то полезным, если нужны какие-то
уточнения - не стесняйтесь спрашивать в комментариях.&lt;/p&gt;
&lt;h3 id="minimizatsiia-razmera-soobshchenii"&gt;Минимизация размера сообщений&lt;/h3&gt;
&lt;p&gt;&lt;a href="/tag/json/"&gt;JSON&lt;/a&gt; хоть и сильно выигрывает у &lt;a href="/tag/xml/"&gt;XML&lt;/a&gt;&amp;nbsp;по объему
сериализованных сообщений, но все же является текстовым форматом с
указанием схемы (название для каждого значения) внутри самого сообщения.
Почему минимизация объема передаваемых по постоянному соединению
данных - дело полезное, объяснять, думаю, не стоит.&lt;/p&gt;
&lt;p&gt;Первое, что приходит в голову, чтобы уменьшить объем сообщений -
избавиться от включенной в них схемы, оставив только чистые данные.
Изобретать свой формат ни к чему, есть неплохой&amp;nbsp;широко
распространенный&amp;nbsp;кандидат в виде &lt;a href="/tag/google/"&gt;Google&lt;/a&gt;&amp;nbsp;&lt;a href="/tag/protocol-buffers/"&gt;Protocol
Buffers&lt;/a&gt;. Кстати, недавно нашел библиотеку с
&lt;a href="/tag/javascript/"&gt;JavaScript&lt;/a&gt; реализацией Protocol Buffers с хорошими
отзывами, в ближайшее время думаю сам опробую:
&lt;a href="https://www.insight-it.ru/goto/a420ea/" rel="nofollow" target="_blank" title="https://github.com/sirikata/protojs"&gt;protojs&lt;/a&gt;. Если кто уже работал с
ней - буду рад, если поделитесь впечатлениями.&lt;/p&gt;
&lt;p&gt;Но на практике оказалось, что эта самая схема обычно занимает максимум
10-20% от сообщения, так как большинство данных все же текстовые.
Использование Protocol Buffers было бы намного более выгодным, если бы
было необходимо "упаковать" много чисел или флагов, для текстовых данных
выигрыш намного меньше.&lt;/p&gt;
&lt;p&gt;Экономии в разы можно добиться используя обычные алгоритмы компрессии
(или, если так привычнее, архивации) данных.
&lt;a href="/tag/javascript/"&gt;JavaScrtipt&lt;/a&gt; "из коробки" этого делать не умеет, но
есть полно библиотек на любой вкус и цвет, правда все хромают и чаще
всего не кроссбраузерные. Приведу несколько, которые запомнились после
вечера, проведенного за изучением данного вопроса:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.insight-it.ru/goto/be52f434/" rel="nofollow" target="_blank" title="http://rosettacode.org/wiki/LZW_compression"&gt;LZW&lt;/a&gt; - есть реализации
    на большинстве языков программирования, но компрессия не очень
    сильная (раза в полтора-два в лучшем случае), плюс реализация под
    интересующий меня &lt;a href="/tag/erlang/"&gt;Erlang&lt;/a&gt; оказалась дико неэффективна
    по памяти, а на бинарных строках сходу не нашлась.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.insight-it.ru/goto/49c64f8e/" rel="nofollow" target="_blank" title="https://github.com/imaya/zlib.js"&gt;zlib.js&lt;/a&gt; - умеет &lt;em&gt;zlib (deflate)&lt;/em&gt;
    и &lt;em&gt;gzip&lt;/em&gt;, но, к сожалению, в моем браузере не могла разжать обратно
    то, что сжала, плюс объем кода библиотеки очень большой.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.insight-it.ru/goto/730dabaf/" rel="nofollow" target="_blank" title="https://github.com/dankogai/js-deflate"&gt;js-deflate&lt;/a&gt; - не
    обновлялась уже 4 года, отсутствует документация, но зато в целом
    работает. Подбирать метод компрессии для серверной стороны пришлось
    почти экспериментально, оказался &lt;em&gt;zlib (deflate)&lt;/em&gt; без заголовков и
    контрольной суммы (в &lt;a href="/tag/erlang/"&gt;Erlang&lt;/a&gt; встроенная функция zlib:zip). Компрессия примерно в 3-4 раза.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Если все же решите использовать компрессию, то рекомендую реализовать
флаг для ситуаций когда в клиенте все же декомпрессия по каким-то
причинам сломана. Достаточно просто сжать-разжать короткую строку и
сравнить с оригиналом, если не совпало или выскочило исключение -
просить сервер отвечать без компрессии.&lt;/p&gt;
&lt;p&gt;По поводу дополнительных вычислительных ресурсов, которые будут
потребляться на компрессию/декомпрессию, вопрос, конечно, спорный, в
целом надо все мерять и делать выводы. Но если учесть, что почти во всех
современных устройствах, даже телефонах, как минимум 1Ггц процессор, а
на сервере можно кэшировать уже сжатые данные, то это не особо большая
проблема. К слову объем сообщений уменьшается тоже не гарантированно,
бывает что "сжатая" версия оказывается такой же или даже чуть больше,
чем оригинал. В общем, использовать компрессию нужно осторожно :)&lt;/p&gt;
&lt;h2 id="povtornoe-ispolzovanie-shablonov_1"&gt;Повторное использование шаблонов&lt;/h2&gt;
&lt;p&gt;Сообщение со списком шаблонов для использование на клиентской части,
вероятно, будет самым большим по объему и больше других выиграет от
компрессии. Но есть возможность легко минимизировать и количество таких
сообщений. Помните, я писал, что локальное хранилище в браузере можно и
для других целей использовать?&lt;/p&gt;
&lt;p&gt;Кэширование шаблонов - идеальный пример. Получив от сервера шаблоны он
кладет их не только в объект-обертку, но и в локальное хранилище. На
сервере помимо самого JSON'а с шаблонами генерируем хэш (md5, sha или
crc - не важно) текущей версии. Клиент, когда открывает соединение,
сообщает серверу есть ли у него какая-то версия и если есть, то какая,
сервер отправляет новую версию в ответ только если хэши не совпали.&lt;/p&gt;
&lt;p&gt;Аналогичным образом можно кэшировать и другую редко меняющуюся объемную
информацию, например данные для автодополнения в текстовых полях
&lt;em&gt;(autocomplete)&lt;/em&gt;.&lt;/p&gt;
&lt;h2 id="zakliuchenie"&gt;Заключение&lt;/h2&gt;
&lt;p&gt;Надеюсь предложенные в этой статье приемы окажутся Вам полезны. Буду
рад, если Вы поделитесь своим опытом и приемами по данной теме в
комментариях, а также с удовольствием обсужу подробности.&lt;/p&gt;
&lt;div class="card green"&gt;
&lt;p&gt;&lt;div class="card-content white-text"&gt;
Эта статья - шестая и заключительная в &lt;a class="green-text text-lighten-4" href="https://www.insight-it.ru/interactive/"&gt;серии про Интерактивные сайты&lt;/a&gt;, автор - &lt;a class="green-text text-lighten-4" href="https://www.insight-it.ru/goto/b03d9116/" rel="nofollow" target="_blank" title="http://blinkov.ru"&gt;Иван&amp;nbsp;Блинков&lt;/a&gt;, основано на личном опыте.
До встречи &lt;a class="green-text text-lighten-4" href="/feed/"&gt;на страницах Insight IT&lt;/a&gt;!
&lt;/div&gt;&lt;/p&gt;
&lt;/div&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Иван Блинков</dc:creator><pubDate>Sat, 20 Oct 2012 12:32:00 +0400</pubDate><guid>tag:www.insight-it.ru,2012-10-20:interactive/2012/optimizaciya-interaktivnykh-sajjtov/</guid><category>deflate</category><category>html5</category><category>JavaScript</category><category>JSON</category><category>jStorage</category><category>Protocol Buffers</category><category>Web Storage</category><category>zlib</category><category>клиентская оптимизация</category><category>компрессия</category><category>кэширование</category><category>оптимизация</category></item><item><title>High Performance Conference aka BitByte 2012</title><link>https://www.insight-it.ru//event/2012/high-performance-conference-aka-bitbyte-2012/</link><description>&lt;p&gt;Когда я наткнулся в RSS на объявление о данном мероприятии я сразу
отнесся к нему скептически: если бы "высокая производительность" &lt;em&gt;(high
performance)&lt;/em&gt; при разработке высоконагруженных интернет-проектов была
первым приоритетом, то самым распространенным языком программирования в
вебдеве был бы &lt;a href="/tag/c/"&gt;C&lt;/a&gt; или даже Ассемблер, а не &lt;a href="/tag/php/"&gt;PHP&lt;/a&gt;.
Но судя по заголовкам докладов речь все же была о &lt;a href="https://www.insight-it.ru/highload/"&gt;highload&lt;/a&gt;, так что в качестве эксперимента я решил съездить.&lt;/p&gt;
&lt;!--more--&gt;
&lt;p&gt;Дело было 6 октября в Москве. Сама HPC являлась частью некого фестиваля
BitByte. В двух других потоках, как я понял, говорили об HR и стартапах,
то есть в коридоре между залами была довольно забавная смесь из толпы
студентов и небольшого количества технарей и HRов. Хотя самый большой
зал почему-то был у HPC-секции. Организация у всего этого была очень
минималистичная, без бейджиков и обеда, хотя с интернет-трансляцией. А
вот слайды с докладов до сих пор не опубликовали...&lt;/p&gt;
&lt;p&gt;Формат мероприятия был довольно необычный: всего 5 докладов на секцию
примерно по часу. Два от &lt;strong&gt;Badoo&lt;/strong&gt; и по одному от&amp;nbsp;организаторов
(&lt;strong&gt;ITmozg&lt;/strong&gt;), &lt;strong&gt;Моего_Мира@mail.ru&lt;/strong&gt; и &lt;strong&gt;Фотостраны&lt;/strong&gt;. С одной стороны
"длинный" формат хорош тем, что докладчики могли не торопиться и было
масса времени на Q&amp;amp;A, но по факту тот же объем информации, что излагался
за час можно было бы запросто выдать и за стандартные 15-30 минут -
какими-то особыми деталями никто не радовал, а жаль.&amp;nbsp;Но обо всем
по-порядку.&lt;/p&gt;
&lt;h3 id="optimizatsiia-mongodb-dos-and-donts"&gt;Оптимизация MongoDB - DO's and DON'Ts&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Даниил Павлючков&lt;/strong&gt;&amp;ensp;&lt;em&gt;(ITmozg)&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Вообще компания-организатор ITmozg - &lt;del&gt;просто HR-агенство в сфере
IT&lt;/del&gt;&amp;nbsp;специализированный рекрутинговый онлайн ресурс для IT и Телеком
сфер, которое ко всему прочему проводит мероприятия вроде этого. Их сайт
не отличается особой популярностью (и, как следствие, нагрузками) и
содержит помимо новостей и информации о мероприятиях, что-то типа
каталога вакансий и резюме. Он частично разработан докладчиком&amp;nbsp;с
использованием MongoDB. Так и родился этот доклад.&lt;/p&gt;
&lt;p&gt;Состоял он из обсуждения различных ходящих по Интернету слухов и статей
о &lt;a href="/tag/mongodb/"&gt;MongoDB&lt;/a&gt; и нескольких примеров о том, как базовый
функционал можно реализовать с использованием документ-ориентированного
подхода по сравнению с реляционным.&lt;/p&gt;
&lt;p&gt;Основной минус такого рода докладов в том, что слушатели обычно делятся
на две категории: если им актуальна данная тема, то довольно вероятно,
что они уже читали все то, о чем говорит докладчик, а если не
актуальна - то они тем более не слушают.&lt;/p&gt;
&lt;p&gt;Примерно по-этим же причинам я сам пока не выступаю на конференциях: о
клиентах по &lt;a href="https://www.insight-it.ru/consulting/"&gt;консультациям&lt;/a&gt; не культурно рассказывать, а из своих проектов в ситуацию сколько-либо серьезных нагрузок еще ни один не попал. А про все остальное и так можно почитать в Интернете...&lt;/p&gt;
&lt;h3 id="badoo-desktop-optimizatsiia-prilozheniia-na-million-iuzerov-onlain"&gt;Badoo Desktop: оптимизация приложения на миллион юзеров онлайн&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Сергей Аверин aka Xek&lt;/strong&gt;&amp;ensp;&lt;em&gt;(Badoo)&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Про Badoo думаю у меня уже достаточно информации, чтобы написать
отдельную статью (если Вам интересно - дайте знать в комментариях), так
что в технические подробности вдаваться особо не буду. Скажу лишь, что у
них используется вполне стандартный стек технологий (&lt;a href="/tag/php/"&gt;PHP&lt;/a&gt; и
&lt;a href="/tag/handlersocket/"&gt;MySQL&lt;/a&gt;), но реализованный в своем особом стиле,
который мне даже сложно как-то конкретно охарактеризовать.&lt;/p&gt;
&lt;p&gt;Если кто не слышал, Badoo - довольно крупный международный сайт
знакомств (в Top200 сайтов мира по версии Alexa).&amp;nbsp;Сергей рассказывал об
их десктопном приложении, которое постоянно висит в трее, поддерживает
статус онлайн и доставляет уведомления. И, конечно, серверной части,
которая его обслуживает.&lt;/p&gt;
&lt;p&gt;Общий посыл доклада, с моей точки зрения, был следующий: при разработке
больших и сложных систем никому нельзя доверять, нужно самостоятельно
проверять все варианты и цифры и думать исключительно собственной
головой. Сложно не согласиться.&lt;/p&gt;
&lt;p&gt;Доклад пестрил разными историями, советами и примерами, что само по себе
очень здорово, но по мне так не хватало какой-то общей "сюжетной линии".
Из тех, что запомнились:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Они завели специальный режим для экстренных случаев, когда что-то
    сломалось или пик нагрузки - они могут сказать всем или части
    десктоп-приложений отправлять им данные реже, чем обычно. Жаль, для
    веб-сайтов это чуть менее применимо, но всегда полезно заранее
    подумать в этом направлении и составить план действий и список
    возможных мер по снижению нагрузки.&lt;/li&gt;
&lt;li&gt;Гоняясь за производительностью кода (внутри PHP), можно выиграть
    максимум десятки процентов. Чтобы добиться выигрыша
    производительности в десятки раз, нужно менять принцип того, как
    работает приложение.&lt;/li&gt;
&lt;li&gt;Не раз упоминались разного рода проблемы с таймаутами, но у меня не
    сложилось четкого впечатления, в чем были их причины и что было
    сделано для их устранения.&lt;/li&gt;
&lt;li&gt;В Badoo довольно либерально относятся к единственным точкам отказа
    &lt;em&gt;(single point of failure)&lt;/em&gt;, так что некоторые внутренние сервисы у
    них все же являются таковыми.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="push-uvedomlenie-i-obshchaia-arkhitektura-proekta-moi_mirmailru"&gt;Пуш-уведомление и общая архитектура проекта Мой_Мир@Mail.Ru&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Дмитрий Казаков&lt;/strong&gt;&amp;ensp;&lt;em&gt;(Mail.ru Group)&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Если честно, я все же надеялся услышать хоть что-то стоящее на этом
докладе... Наверное в свете того, что я недавно довольно тесно
интересовался данной темой, что в итоге вылилось в серию статей
&lt;a href="https://www.insight-it.ru/interactive/"&gt;"Интерактивные сайты"&lt;/a&gt;. Но Mail.ru оказались в своем репертуаре: "у нас есть свои крутые технологии, они круче всех на свете,
но почему именно мы решили их создать и в чем их преимущества/отличия от
общеиспользуемых решений, мы не расскажем". В opensource тоже не
дождетесь. Исключение из этого правила пока лишь одно -&amp;nbsp;&lt;strong&gt;Tarantool&lt;/strong&gt;
(СУБД, работающая в основном в памяти, чем-то напоминает
&lt;a href="/tag/redis/"&gt;Redis&lt;/a&gt;), но из-за такого их поведения на конференциях я и
к этому их opensource проекту подозрительно отношусь.&lt;/p&gt;
&lt;p&gt;Сам Мой Мир отдельной статьи явно не заслуживает, так что вкратце:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="/tag/perl/"&gt;Perl&lt;/a&gt; с модулями на &lt;a href="/tag/c/"&gt;C&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Хранение данных с использованием собственной технологии "Silver" и
    вышеупомянутого Tarantool&lt;/li&gt;
&lt;li&gt;Плюс немного &lt;a href="/tag/memcached/"&gt;memcached&lt;/a&gt;, а про самое главное -
    шину обмена сообщениями докладчик забыл&lt;/li&gt;
&lt;li&gt;Для взаимодействия между браузером и сервером используют CometD,
    видимо тот самый на странноватом Bayeux протоколе&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;И немного статистики:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;7.5 миллионов пользователей&lt;/li&gt;
&lt;li&gt;40 миллионов просмотров страниц в день&lt;/li&gt;
&lt;li&gt;283.5 миллиона показов в день (видимо, просто хитов включая статику)&lt;/li&gt;
&lt;li&gt;1 миллион новых друзей в день (февраль 2011)&lt;/li&gt;
&lt;li&gt;25 разработчиков&lt;/li&gt;
&lt;li&gt;300 фронтендов&lt;/li&gt;
&lt;li&gt;Под уведомления: 12 серверов с 16Гб памяти и 4+1 дисками&lt;/li&gt;
&lt;li&gt;10 миллионов уведомлений на сервер, при средней длине уведомления в
    116 байт&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="kak-slat-150m-pisem-kazhdyi-den"&gt;Как слать 150М писем каждый день&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Андрей Сас&lt;/strong&gt;&amp;ensp;&lt;em&gt;(Badoo)&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Андрей по совместительству вел развлекательную программу от Badoo в
перерыве, так что доклад также по инерции прошел в
развлекательно-увесилительном формате. Про, собственно, основные вопросы
минимизации попадания в спам и прочих проблем в доставке почты
целеноправленно умолчали под предлогом, что это их конкурентное
преимущество.&lt;/p&gt;
&lt;p&gt;Из того, что было сказано:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Для отправки почты используется &lt;strong&gt;две очереди&lt;/strong&gt;: одна для генерации
    писем, другая для их отправки.&lt;/li&gt;
&lt;li&gt;Несколько удивил тот факт, что обе они реализованы &lt;strong&gt;просто на
    файлах&lt;/strong&gt;, как я понял с единственной мотивацией "так надежнее".&lt;/li&gt;
&lt;li&gt;Сама отправка через команду mail, вызывающую&amp;nbsp;&lt;strong&gt;ssmtp&lt;/strong&gt; (облегченный
    аналог sendmail), через собственные MTA.&lt;/li&gt;
&lt;li&gt;В качестве MTA используется проприетарный &lt;strong&gt;Communigate Pro&lt;/strong&gt;,
    который, по их мнению, быстрее и надежнее opensource альтернатив.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="arkhitektura-proekta-na-30m-polzovatelei"&gt;Архитектура проекта на 30М пользователей&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;&amp;nbsp;Дмитрий Смирнов&lt;/strong&gt;&amp;ensp;&lt;em&gt;(Фотострана)&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Фотострана - не имеющая никакого отношения к фото социальная сеть, в
Топ20 рунета по данным LiveInternet, но о которой никто не слышал.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Почти традиционный &lt;a href="/tag/lamp/"&gt;LAMP&lt;/a&gt; стек, за исключением того, что
    по историческим причинам &lt;a href="/tag/freebsd/"&gt;FreeBSD&lt;/a&gt; вместо
    &lt;a href="/tag/linux/"&gt;Linux&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Мега-короткий цикл разработки - деплой новой версии каждый час (!),
    недельные спринты в Agile отдыхают&lt;/li&gt;
&lt;li&gt;Тоже написали свою альтернативу Redis, которая, судя по графикам,
    примерно на порядок его быстрее, но не собираются её опубликовывать&lt;/li&gt;
&lt;li&gt;Узкоспециализированные сервера - нет не только смешанных серверов
    вроде СУБД + сервер приложений, но и разные части проекта (анкеты,
    поиск, "питомцы" и т.п.) разнесены по разным машинам&lt;/li&gt;
&lt;li&gt;Собственная система отдачи статики с двухслойным кэшем и, как я
    понял, без использования CDN&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="zakliuchenie"&gt;Заключение&lt;/h3&gt;
&lt;p&gt;Для малобюджетного бесплатного мероприятия содержательность оказалась
очень даже неплоха. Думаю особенно полезно данное мероприятие оказалось
для присутствовавших там в большом количестве начинающих студентов,
которые пытались понять, интересна ли им тема веб-разработки в целом и
высоких нагрузок в частности или нет.&lt;/p&gt;
&lt;p&gt;По традиции напомню, что если Вы хотите оперативно узнавать о новых
статьях об&amp;nbsp;&lt;a href="https://www.insight-it.ru/highload/"&gt;архитектуре высоконагруженных интернет проектов&lt;/a&gt;, а также других материалах - рекомендую
&lt;a href="/feed/"&gt;подписаться на &lt;strong&gt;Insight IT&lt;/strong&gt; через RSS&lt;/a&gt;.&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Иван Блинков</dc:creator><pubDate>Tue, 09 Oct 2012 13:12:00 +0400</pubDate><guid>tag:www.insight-it.ru,2012-10-09:event/2012/high-performance-conference-aka-bitbyte-2012/</guid><category>Badoo</category><category>BitByte</category><category>High Performance Conference</category><category>HPC</category><category>ITmozg</category><category>Mail.ru</category><category>конференция</category><category>мероприятия</category><category>Мой Мир</category><category>Фотострана</category></item><item><title>Yet Another Conference 2012</title><link>https://www.insight-it.ru//event/2012/yet-another-conference-2012/</link><description>&lt;p&gt;Осень, сезон конференций в самом разгаре. На этой неделе был на двух,
еще несколько предстоит в этом месяце. В этом посте вкратце хочу
рассказать о прошедшей в понедельник YAC2012 от &lt;a href="/tag/yandex/"&gt;Яндекса&lt;/a&gt;,
чуть позже будет пост и о прошедшем сегодня HPC aka BitByte. На "яке"
про &lt;a href="https://www.insight-it.ru/highload/"&gt;highload&lt;/a&gt; не было совсем практически ничего, так что если Вас это не смущает - приступим.&lt;/p&gt;
&lt;!--more--&gt;
&lt;h2 id="nachalo"&gt;Начало&lt;/h2&gt;
&lt;p&gt;Началось все с презентации &lt;a href="https://www.insight-it.ru/goto/ddf4244/" rel="nofollow" target="_blank" title="http://browser.yandex.ru"&gt;Яндекс.Браузера&lt;/a&gt; -
если в двух словах, то это форк Chromium (как следствие - в основе
WebKit) с встроенным Opera Turbo и сервисами Яндекса. Я явно не являюсь
их целевой аудиторией, но для не-айтишников совсем не знающих
английский - может быть и окажется актуальным. К слову, когда проверял
"рабочесть" ссылки узнал, что версии под &lt;a href="/tag/linux/"&gt;Linux&lt;/a&gt; у него
нет, что странно, так как сам Chromium прекрасно работает, им и
пользуюсь ежедневно.&lt;/p&gt;
&lt;p&gt;Всего на конференции было 4 потока, выбрать на какой идти было не сложно
методом исключения:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Я не большой фанат виртуализации, так что &lt;strong&gt;"Облачные технологии"&lt;/strong&gt;
    вычеркнул первыми;&lt;/li&gt;
&lt;li&gt;С математикой знаком лишь по наслышке благодаря гуманитарному
    образованию, так что на "&lt;strong&gt;Интернет-математике"&lt;/strong&gt; ловить тоже особо
    было нечего;&lt;/li&gt;
&lt;li&gt;Разработка приложений под Android - дело неблагодарное, так что
    &lt;strong&gt;"Yandex Mobile Camp"&lt;/strong&gt;&amp;nbsp;также не стал моим выбором (кстати, у них
    якобы запустился "конкурент" Google Play);&lt;/li&gt;
&lt;li&gt;В итоге я весь день провел во втором зале с названием
    &lt;strong&gt;"Фронтенд"&lt;/strong&gt;, который ближе к вечеру перетек в &lt;strong&gt;"Системное
    администрирование"&lt;/strong&gt; - темы хоть и не совсем по моей части, но
    хочешь-не-хочень, а приходится иметь с ними дело&amp;nbsp;чуть ли не каждый
    день.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="frontend"&gt;Фронтенд&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;del&gt;Charles McCathieNevile&lt;/del&gt; &lt;strong&gt;Chaals (Яндекс)&lt;/strong&gt; -&amp;nbsp;&lt;em&gt;Yandex and W3C&lt;/em&gt;&lt;ul&gt;
&lt;li&gt;В прошлом году Chaals выступал на YAC, представляя Opera и W3C,
    теперь он работает консультантом в Яндекс по этой же части.&lt;/li&gt;
&lt;li&gt;Соответственно Яндекс недавно стал первым полным участником W3C
    из РФ, думаю в основном благодаря ему.&lt;/li&gt;
&lt;li&gt;Вкратце про W3C - это международное сообщество компаний, которые
    сообща предлагают и развивают разного рода стандарты в сфере
    Интернета. Работа организована в ввиде нескольких десятков
    узкотематических рабочих групп; каждая из компаний-участников
    может присоединиться к любой из них выделив под это какую-то
    часть рабочего времени своих сотрудников. Работа и обсуждения в
    основном ведутся удаленно по e-mail, но регулярно проводятся и
    оффлайн встречи рабочих групп.&lt;/li&gt;
&lt;li&gt;Участие платное, ориентировочно: полное участие стоит 70 тыс.
    евро в год, ограниченное участие для исследовательских центров,
    государств и т.п. - 7 тыс. евро в год, для стартапов - порядка 1
    тыс. евро в год.&lt;/li&gt;
&lt;li&gt;Почти неофициально было сказано, что первым стандартом, который
    предложит Яндекс будет prefetch карт в браузер.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Александр Чупахин (Яндекс)&lt;/strong&gt; - &lt;em&gt;Профилирование и ускорение сложных
    JavaScript-систем на примере API Яндекс.Карт&lt;/em&gt;&lt;ul&gt;
&lt;li&gt;Мораль данного доклада: если у Вас в проекте много сложного
    JavaScript, то его стоит профилировать.&lt;/li&gt;
&lt;li&gt;Собственно карты и прочая разного рода графика - один из
    немногих use case'ов, где есть большой простор для оптимизации
    производительности JS. Еще из потенциальных вариантов -
    клиентская часть при &lt;a href="https://www.insight-it.ru/interactive/2012/postoyannoe-soedinenie-mezhdu-brauzerom-i-serverom/"&gt;постоянном соединении между браузером и сервером&lt;/a&gt;.&amp;nbsp;Для типичных же сайтов это актуально довольно редко.&lt;/li&gt;
&lt;li&gt;Помимо собственной системы тестирования и оценки
    производительности они пользуются &lt;a href="https://www.insight-it.ru/goto/8494c721/" rel="nofollow" target="_blank" title="https://developers.google.com/web-toolkit/speedtracer/"&gt;Google Speed
    Tracer&lt;/a&gt; -
    рекомендую взглянуть, если занимаетесь чем-то подобным.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Jan Jongboom (Cloud9)&lt;/strong&gt; - &lt;em&gt;The Architect Way&lt;/em&gt;&lt;ul&gt;
&lt;li&gt;Выступал на хорошем западном уровне, но не знаю, что он забыл на
    фронтенд секции. Речь шла об их фреймворке под названием
    Architect для &lt;a href="/tag/node-js/"&gt;node.js&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Дмитрий Барановский (Adobe)&lt;/strong&gt; - &lt;em&gt;Raphaёl - past, present and
    future&lt;/em&gt;&lt;ul&gt;
&lt;li&gt;Автор, судя по всему, популярной библиотеки для "рисования" в
    браузере без флеша и canvas, о ней и рассказывал.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Владимир Агафонкин (Cogniance)&lt;/strong&gt; - &lt;em&gt;Progressive Enhancement:
    практичный подход к современной кроссбраузерной разработке&lt;/em&gt;&lt;ul&gt;
&lt;li&gt;Докладчик - автор еще одной популярной JS-библиотеки, на этот
    раз для отрисовки карт -
    &lt;a href="https://www.insight-it.ru/goto/96340c7c/" rel="nofollow" target="_blank" title="http://leafletjs.com/"&gt;Leaflet&lt;/a&gt;, которая используется
    во многих крупных интернет-проектах, например в foursquare,
    Flickr и Wikimedia.&lt;/li&gt;
&lt;li&gt;Суть доклада: нужно разрабатывать не для современных браузеров и
    потом добавлять "костыли" для старых и мобильных браузеров, а
    наоборот - сначала базовый HTML и функционал, потом базовые CSS
    и JavaScript, которые будут работать практически везде и дадут
    80-90% желаемого внешнего вида и уже только потом реализовывать
    все более и более навороченные "фишки" из HTML5, CSS3 и прочих
    нынче модных аббревиатур.&lt;/li&gt;
&lt;li&gt;С данным принципом в целом очень даже согласен, сам стараюсь по
    возможности в этом "направлении" работать, когда приходится
    иметь дело с фронтендом. Хотя в базовой HTML версии все же
    иногда имеет смысл пожертвовать частью функционала, но это уже
    детали.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Алексей Емелин (Яндекс)&lt;/strong&gt; - &lt;em&gt;Тестирование "безDOMных" объектов
    современных веб-интерфейсов на примере API Яндекс.Карт&lt;/em&gt;&lt;ul&gt;
&lt;li&gt;Яндекс.Карты реализованы довольно хитрым "многослойным"
    образом - часть на canvas, часть на DOM-дереве, так что
    тестировать и правда сложновато.&lt;/li&gt;
&lt;li&gt;Поверхностно показывали закрытую систему для тестирования карт,
    работает примерно так: "создается новый функционал вручную
    тестируется -&amp;gt; эта версия берется за эталон -&amp;gt; когда
    появляется новая версия старого функционала - открываются два
    окна браузера, в одном запускается эталон, в другом новая
    версия -&amp;gt; если скриншоты совпали - все ок, если нет - вручную
    смотрим что не так -&amp;gt; повторяем для всех популярных браузеров".&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Константин Горский (Яндекс)&lt;/strong&gt; - &lt;em&gt;Что разработчикам интерфейсов
    нужно знать о дизайне&lt;/em&gt;&lt;ul&gt;
&lt;li&gt;Довольно доходчиво и с картинками излагалась простая мысль,
    автором которой, кажется, является Стив Джобс:&amp;nbsp;&lt;em&gt;"Дизайн - это не
    как что-то выглядит, а как оно работает"&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;То есть чтобы стать дизайнером, не нужно заканчивать
    художественный ВУЗ, достаточно начать думать о том что, как и
    зачем делают пользователи и как сделать так, чтобы им это все
    давалось легче и приятнее.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="sistemnoe-administrirovanie"&gt;Системное администрирование&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Demir Ozgur (Snapfish/HP)&lt;/strong&gt; - &lt;em&gt;System Administration
    Automation in High Scale&lt;/em&gt;&lt;ul&gt;
&lt;li&gt;Не смотря на многообещающее название, доклад оказался
    чрезвычайно примитивным. Базовая теория автоматизации админских
    задач, плюс какие-то общеизвестные байки о
    &lt;a href="/tag/facebook/"&gt;Facebook&lt;/a&gt; и ком-то еще.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Виталий Антоненко (ЦПИ КС)&lt;/strong&gt; - &lt;em&gt;SDN - технология удобного
    управления компьютерной сетью&lt;/em&gt;&lt;ul&gt;
&lt;li&gt;Доклад был об &lt;strong&gt;OpenFlow&lt;/strong&gt; - альтернативному открытому протоколу
    сетевой маршрутизации, основной сферой применения которого, по
    словам докладчика, являются научные и исследовательские проекты.&lt;/li&gt;
&lt;li&gt;Я думаю, в сфере интернет-проектов он тоже применим, но о
    прецедентах не слышал.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Владимир Неверов (Яндекс)&lt;/strong&gt; - &lt;em&gt;Отказоустойчивость и
    балансировка нагрузки без регистрации и смс&lt;/em&gt;&lt;ul&gt;
&lt;li&gt;Основная тема доклада - &lt;a href="/tag/ipvs/"&gt;IPVS&lt;/a&gt;, метод балансировки
    нагрузки по-умолчанию в Яндекс.&lt;/li&gt;
&lt;li&gt;Используется в совокупности с балансировкой на уровне DNS и
    проприетарными аппаратными решениями.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Владимир Иванов (Яндекс)&lt;/strong&gt; - &lt;em&gt;Как запускали IPv6 в Яндексе&lt;/em&gt;&lt;ul&gt;
&lt;li&gt;Не смотря на небольшие проблемы с дикцией, Владимир живо и
    интересно закрыл секцию, апплодисменты были более чем заслужены.&lt;/li&gt;
&lt;li&gt;IPv6 уже работает. В большинстве случаев. Но у некоторых
    интернет-провайдеров он капитально сломан, что может приводить к
    недоступности сайта у некоторого % пользователей.&lt;/li&gt;
&lt;li&gt;Для минимизации ущерба в Яндекс используют whitelist'ы на DNS
    серверах, которые выдают IPv6 только пользователям определенных
    интернет-провайдеров.&lt;/li&gt;
&lt;li&gt;К слову, &lt;a href="/tag/google/"&gt;Google&lt;/a&gt; вроде как уже перешел наоборот
    на blacklist'ы ISP, у которых IPv6 точно сломан. Подробнее
    &lt;a href="https://www.insight-it.ru/goto/ea0ec1a7/" rel="nofollow" target="_blank" title="http://en.wikipedia.org/wiki/IPv6_brokenness_and_DNS_whitelisting"&gt;тут&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="zakliuchenie"&gt;Заключение&lt;/h2&gt;
&lt;p&gt;Конференция от Яндекса оказалась хороша для общего развития. Но
практическая ценность подобных мероприятий все же от года к году
неуклонно падает. Организаторам определенно нужно более тщательно
фильтровать докладчиков на адекватность и темы на востребованность.&lt;/p&gt;
&lt;p&gt;По организации все было в целом более-менее стандартно, подробнее можно
почитать &lt;a href="https://www.insight-it.ru/goto/a1390f6d/" rel="nofollow" target="_blank" title="https://twitter.com/blinkov"&gt;у меня в Твиттере&lt;/a&gt;&amp;nbsp;(всегда рад
новым фолловерам) или &lt;a href="https://www.insight-it.ru/goto/ff4411e2/" rel="nofollow" target="_blank" title="https://twitter.com/search/?q=%23yac2012"&gt;по
хэштегу&lt;/a&gt;, пока не далеко еще
опустилось по ленте.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;P.S.: Я все еще в поисках бесплатного билета на HighLoad++ - если кто
может с этим помочь, буду благодарен :)&lt;/strong&gt;&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Иван Блинков</dc:creator><pubDate>Sun, 07 Oct 2012 01:08:00 +0400</pubDate><guid>tag:www.insight-it.ru,2012-10-07:event/2012/yet-another-conference-2012/</guid><category>Yet Another Conference</category><category>конференции</category><category>мероприятия</category><category>Яндекс</category></item><item><title>Вакансии: PHP и Python разработчики в Киеве</title><link>https://www.insight-it.ru//vacancy/2012/vakansii-php-i-python-razrabotchiki-v-kieve/</link><description>&lt;div class="card orange darken-3"&gt;
&lt;p&gt;&lt;div class="card-content white-text center"&gt;
&lt;strong&gt;Вакансии более не актуальны&lt;/strong&gt;
&lt;/div&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;Киевская команда разработчиков игр для социальных и мобильных платформ
Level UP ищет опытных специалистов по
веб-разработке на Python и PHP.&lt;/p&gt;
&lt;!--more--&gt;
&lt;h2 id="senior-python-developer"&gt;Senior Python Developer&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Задачи:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Разработка высоконагруженных веб-приложений;&lt;/li&gt;
&lt;li&gt;Разработка внутренних и публичных API;&lt;/li&gt;
&lt;li&gt;Разработка архитектуры комплексных сервисов;&lt;/li&gt;
&lt;li&gt;Конвертирование бизнес-задач в технические решения (R&amp;amp;D).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Требования:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Опыт разработки на &lt;strong&gt;Python&lt;/strong&gt; более 3х лет;&lt;/li&gt;
&lt;li&gt;Сильные навыки применения реляционных и нереляционных баз данных;&lt;/li&gt;
&lt;li&gt;Опыт в разработке высоконагруженных веб-приложений;&lt;/li&gt;
&lt;li&gt;Дружба с &lt;strong&gt;Linux&lt;/strong&gt; и &lt;strong&gt;Git&lt;/strong&gt;;&lt;/li&gt;
&lt;li&gt;Хорошее знание клиентских технологий (HTML, CSS, Javascript);&lt;/li&gt;
&lt;li&gt;Опыт работы в команде.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Плюсом будет:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Опыт разработки комплексных проектов на &lt;strong&gt;PHP&lt;/strong&gt; или серверном
    &lt;strong&gt;Javascript&lt;/strong&gt; &lt;em&gt;(node.js)&lt;/em&gt;;&lt;/li&gt;
&lt;li&gt;Опыт разработки инструментов для верстки, автоматизации верстки,
    шаблонизаторов и пр.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="senior-php-developer"&gt;Senior PHP Developer&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Задачи:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Разработка высоконагруженных социальных веб-приложений;&lt;/li&gt;
&lt;li&gt;Работа в небольшой дружной команде до 15 человек;&lt;/li&gt;
&lt;li&gt;Решение нетривиальных задач и создание инструментов для внутреннего
    использования;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Требования:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Опыт разработки на &lt;strong&gt;PHP&lt;/strong&gt; более 3х лет;&lt;/li&gt;
&lt;li&gt;Опыт работы с &lt;strong&gt;MySQL&lt;/strong&gt; и &lt;strong&gt;MongoDB&lt;/strong&gt;;&lt;/li&gt;
&lt;li&gt;Опыт в разработке высоконагруженных веб-приложений;&lt;/li&gt;
&lt;li&gt;Дружба с &lt;strong&gt;Linux&lt;/strong&gt; и &lt;strong&gt;Git&lt;/strong&gt;;&lt;/li&gt;
&lt;li&gt;Хорошее знание клиентских технологий (HTML, CSS, Javascript);&lt;/li&gt;
&lt;li&gt;Опыт примененения функционарного и юнит тестирования.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Плюсом будет:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Опыт разработки на &lt;strong&gt;Python&lt;/strong&gt; или серверном &lt;strong&gt;Javascript&lt;/strong&gt;
&lt;em&gt;(nodejs)&lt;/em&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="usloviia-dlia-oboikh-vakansii"&gt;Условия для обоих вакансий&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Зарплата в диапазоне &lt;strong&gt;\$2500-4000&lt;/strong&gt; в месяц по результатам
    собеседования;&lt;/li&gt;
&lt;li&gt;Полный рабочий день в &lt;strong&gt;Киевском офисе&lt;/strong&gt;, иногородним помощь с
    переездом;&lt;/li&gt;
&lt;li&gt;За успешную рекомендацию специалиста по данным вакансиям компания
    выплачивает&amp;nbsp;&lt;strong&gt;бонус в размере $1000&lt;/strong&gt; так что сообщите своим
    знакомым, кому-то это может быть интересно.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="zainteresovalo"&gt;Заинтересовало?&lt;/h2&gt;
&lt;div class="card orange darken-3"&gt;
&lt;p&gt;&lt;div class="card-content white-text center"&gt;
&lt;strong&gt;Вакансии более не актуальны&lt;/strong&gt;
&lt;/div&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;Не лишним будет, если кроме резюме Вы напишите - почему Вам нравится
серверная разработка на Python или PHP и почему Вам интересна данная
вакансия. Плюс упомяните, пожалуйста, что Вы узнали о данной вакансии
через &lt;strong&gt;Insight IT&lt;/strong&gt;.&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Иван Блинков</dc:creator><pubDate>Thu, 20 Sep 2012 20:16:00 +0400</pubDate><guid>tag:www.insight-it.ru,2012-09-20:vacancy/2012/vakansii-php-i-python-razrabotchiki-v-kieve/</guid><category>css</category><category>Git</category><category>html</category><category>JavaScript</category><category>Level UP</category><category>Linux</category><category>MongoDB</category><category>MySQL</category><category>node.js</category><category>PHP</category><category>Python</category><category>вакансии</category><category>Киев</category></item><item><title>Архитектура Pinterest</title><link>https://www.insight-it.ru//highload/2012/arkhitektura-pinterest/</link><description>&lt;p&gt;&lt;a href="https://www.insight-it.ru/goto/975fdd8/" rel="nofollow" target="_blank" title="https://www.pinterest.com/"&gt;Pinterest&lt;/a&gt; - по непонятным для меня причинам
популярная в определенных кругах социальная сеть, построенная вокруг
произвольных картинок чаще всего не собственного производства. Как и
&lt;a href="https://www.insight-it.ru/highload/2012/arkhitektura-instagram/"&gt;Instagram&lt;/a&gt;
проект довольно молодой, с очень похожей историей и стеком технологий.
Тем не менее, Pinterest определенно заслуживает внимания как один из
самых быстрорастущих по посещаемости вебсайтов за всю историю.&lt;/p&gt;
&lt;!--more--&gt;
&lt;h2 id="platforma"&gt;Платформа&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="/tag/amazon/"&gt;Amazon&lt;/a&gt; &lt;a href="/tag/aws/"&gt;AWS&lt;/a&gt;&amp;nbsp;- хостинг и вспомогательные
    сервисы&lt;/li&gt;
&lt;li&gt;&lt;a href="/tag/nginx/"&gt;nginx&lt;/a&gt;&amp;nbsp;- вторичная балансировка нагрузки, отдача
    статики&lt;/li&gt;
&lt;li&gt;&lt;a href="/tag/python/"&gt;Python&lt;/a&gt;&amp;nbsp;- язык программирования&lt;/li&gt;
&lt;li&gt;&lt;a href="/tag/django/"&gt;Django&lt;/a&gt;&amp;nbsp;- фреймворк&lt;/li&gt;
&lt;li&gt;&lt;a href="/tag/mysql/"&gt;MySQL&lt;/a&gt;&amp;nbsp;- основная СУБД&lt;/li&gt;
&lt;li&gt;&lt;a href="/tag/memcached/"&gt;memcached&lt;/a&gt;&amp;nbsp;- кэширование объектов&lt;/li&gt;
&lt;li&gt;&lt;a href="/tag/redis/"&gt;Redis&lt;/a&gt;&amp;nbsp;- кэширование коллекций объектов&lt;/li&gt;
&lt;li&gt;&lt;a href="/tag/solr/"&gt;Solr&lt;/a&gt;&amp;nbsp;- поиск&lt;/li&gt;
&lt;li&gt;&lt;a href="/tag/hadoop/"&gt;Hadoop&lt;/a&gt;&amp;nbsp;- анализ данных&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="statistika"&gt;Статистика&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;3 миллиона уникальных посетителей в день&lt;/li&gt;
&lt;li&gt;18 миллионов уникальных посетителей в месяц&lt;/li&gt;
&lt;li&gt;4-я по популярности социальная сеть в США после
    &lt;a href="/tag/facebook/"&gt;Facebook&lt;/a&gt;,&amp;nbsp;&lt;a href="/tag/twitter/"&gt;Twitter&lt;/a&gt;&amp;nbsp;и
    &lt;a href="/tag/linkedin/"&gt;LinkedIn&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Порядка 500 виртуальных машин в EC2&lt;/li&gt;
&lt;li&gt;80 миллионов объектов в S3&lt;/li&gt;
&lt;li&gt;410Тб пользовательских данных&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="razvitie"&gt;Развитие&lt;/h2&gt;
&lt;h4&gt;Март 2010&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;1 маленький виртуальный веб-сервер&lt;/li&gt;
&lt;li&gt;1 маленький виртуальный сервер MySQL&lt;/li&gt;
&lt;li&gt;Все это в Rackspace, 1 разработчик&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Январь 2011&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;1 сервер nginx для балансировки нагрузки, 4 веб-сервера&lt;/li&gt;
&lt;li&gt;2 сервера MySQL с master/slave репликацией&lt;/li&gt;
&lt;li&gt;3 сервера для отложенного выполнения задач&lt;/li&gt;
&lt;li&gt;1 сервер MongoDB&lt;/li&gt;
&lt;li&gt;Переехали на Amazon &lt;a href="/tag/ec2/"&gt;EC2&lt;/a&gt; + &lt;a href="/tag/s3/"&gt;S3&lt;/a&gt; +
    &lt;a href="/tag/cloudfront/"&gt;CloudFront&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Осень 2011&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;2 сервера nginx, 16 веб-серверов, 2 сервера для API&lt;/li&gt;
&lt;li&gt;5 функционально разделенных серверов MySQL с 9 read slave&lt;/li&gt;
&lt;li&gt;Кластер из 4 узлов Cassandra&lt;/li&gt;
&lt;li&gt;15 серверов Membase в 3 отдельных кластерах&lt;/li&gt;
&lt;li&gt;8 серверов memcached&lt;/li&gt;
&lt;li&gt;10 серверов Redis&lt;/li&gt;
&lt;li&gt;7 серверов для отложенной обработки задач&lt;/li&gt;
&lt;li&gt;4 сервера Elastic Search&lt;/li&gt;
&lt;li&gt;3 кластера MongoDB&lt;/li&gt;
&lt;li&gt;3 разработчика&lt;/li&gt;
&lt;li&gt;Если кто-то может объяснить зачем им сдался такой зоопарк, кроме как
    потестировать разные варианты, можете взять с полки пирожок.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Зима 2011-2012&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Заменили CloudFront на &lt;a href="/tag/akamai/"&gt;Akamai&lt;/a&gt; - вполне объяснимо,
    так как у Akamai намного лучше покрытие по миру, а
    качественный&amp;nbsp;&lt;a href="/tag/cdn/"&gt;CDN&lt;/a&gt; для сайта с большим количеством
    изображений - чуть ли не залог успеха.&lt;/li&gt;
&lt;li&gt;90 веб серверов и 50 серверов для API&lt;/li&gt;
&lt;li&gt;66 + 66 MySQL серверов на m1.xlarge инстансах EC2&lt;/li&gt;
&lt;li&gt;59 серверов Redis&lt;/li&gt;
&lt;li&gt;51 серверов memcached&lt;/li&gt;
&lt;li&gt;25+1 сервер для отложенной обработки задач на основе Redis&lt;/li&gt;
&lt;li&gt;Кластеризованный Solr&lt;/li&gt;
&lt;li&gt;6 разработчиков&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Весна-лето 2012&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Снова сменили CDN, на этот раз в пользу ранее неизвестного мне &lt;a href="/tag/edge-cast/"&gt;Edge
    Cast&lt;/a&gt;. Покрытие по всему миру довольно скромное,
    так что единственное логичное объяснение, которое мне приходит в
    голову - не потянули Akamai по деньгам.&lt;/li&gt;
&lt;li&gt;135 веб серверов и 75 серверов для API&lt;/li&gt;
&lt;li&gt;80 + 80 серверов MySQL&lt;/li&gt;
&lt;li&gt;110 серверов Redis&lt;/li&gt;
&lt;li&gt;60 серверов memcached&lt;/li&gt;
&lt;li&gt;60 + 2&amp;nbsp;сервера&amp;nbsp;для отложенной обработки задач на основе Redis&lt;/li&gt;
&lt;li&gt;25 разработчиков&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="vybor"&gt;Выбор&lt;/h2&gt;
&lt;h4&gt;Почему Amazon Ec2/S3?&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Очень хорошая надежность, отчетность и поддержка&lt;/li&gt;
&lt;li&gt;Хорошие дополнительные сервисы: кэш, базы данных, балансировка
    нагрузки, &lt;a href="/tag/mapreduce/"&gt;MapReduce&lt;/a&gt; и т.п.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Новые виртуальные машины готовы за считанные секунды&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Почему MySQL?&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Очень "зрелая", хорошо известная и любимая многими&lt;/li&gt;
&lt;li&gt;Редки катастрофичные потери данных&lt;/li&gt;
&lt;li&gt;Линейная зависимость времени отклика от частоты запросов&lt;/li&gt;
&lt;li&gt;Хорошая поддержка сторонним ПО (XtraBackup, Innotop, Maatkit)&lt;/li&gt;
&lt;li&gt;Надежное активное сообщество&lt;/li&gt;
&lt;li&gt;Отличная поддержка от Percona&lt;/li&gt;
&lt;li&gt;Бесплатна&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Почему memcached?&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Очень "зрелый", отличная производительность, хорошо известный и
    любимый многими&lt;/li&gt;
&lt;li&gt;Никогда не ломается&lt;/li&gt;
&lt;li&gt;Бесплатен&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Почему Redis?&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Много удобных &lt;strong&gt;структур данных&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Поддержка персистентности и репликации&lt;/li&gt;
&lt;li&gt;Также многим известен и нравится&lt;/li&gt;
&lt;li&gt;Стабильно хорошая производительность и надежность&lt;/li&gt;
&lt;li&gt;Также бесплатен&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="arkhitektura"&gt;Архитектура&lt;/h2&gt;
&lt;h4&gt;Сlustering vs Sharding&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Большую часть презентации, на основе которой написана данная статья
    (&lt;a href="https://www.insight-it.ru/goto/10005efe/" rel="nofollow" target="_blank" title="http://www.slideshare.net/eonarts/mysql-meetup-july2012scalingpinterest"&gt;ссылка&lt;/a&gt;,
    если не охота листать до секции источников информации), занимает
    раздел под названием "Clustering vs Sharding". В связи с путаницей в
    терминологии пришлось несколько раз перечитывать, чтобы понять к
    чему они клонят, сейчас попробую объяснить.&lt;/li&gt;
&lt;li&gt;Вообще есть два фундаментальных способа распределить данные между
    несколькими серверами:&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Вертикально:&lt;/strong&gt;&amp;nbsp;разные таблицы (или просто логически разные
    типы данных) разносятся на разные сервера.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Горизонтально:&lt;/strong&gt; каждая таблица разбивается на некоторое
    количество частей и эти части разносятся на разные сервера по
    определенному алгоритму.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;С первого взгляда казалось, что они пытаются вертикальное разбиение
    назвать &lt;em&gt;sharding&lt;/em&gt;, а горизонтальное - &lt;em&gt;clustering&lt;/em&gt;. Хотя вообще они
    почти синонимы и на русский я их обычно примерно одинаково перевожу.&lt;/li&gt;
&lt;li&gt;По факту же оказалось, что под словом clustering они понимают все
    программные продукты для хранения данных, которые имеют встроенную
    поддержку работы в кластере. В частности они имеют ввиду
    &lt;a href="/tag/cassandra/"&gt;Cassandra&lt;/a&gt;, &lt;a href="/tag/membase/"&gt;Membase&lt;/a&gt;,
    &lt;a href="/tag/hbase/"&gt;HBase&lt;/a&gt; и &lt;a href="/tag/riak/"&gt;Riak&lt;/a&gt;, которые прозрачно для
    пользователя горизонтально распределяют данные по кластеру.&lt;/li&gt;
&lt;li&gt;За словом &lt;em&gt;sharding&lt;/em&gt; в их терминологии стоит аналогичная схема
    собственной разработки, использующая огромное количество логических
    БД в MySQL, распределенных между меньшим количеством &lt;del&gt;физических серверов&lt;/del&gt; виртуальных машин. Именно по этому пути и пошли в
    Pinterest, плюс очень похожий подход используется в
    &lt;a href="https://www.insight-it.ru/highload/2010/arkhitektura-facebook/"&gt;Facebook&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;От себя добавлю, что хоть при наличии должных ресурсов разработка
    собственной системы распределения данных и может быть
    целесообразной, в большинстве случаев на начальном этапе проще
    основываться на готовых решениях вроде перечисленных выше. К слову в
    opensource доступны и основанные на MySQL подобные решения:&lt;ul&gt;
&lt;li&gt;&lt;a href="/tag/vitess/"&gt;Vitess&lt;/a&gt; от &lt;a href="/tag/google/"&gt;Google&lt;/a&gt; /
    &lt;a href="/tag/youtube/"&gt;YouTube&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="/tag/flockdb/"&gt;FlockDB&lt;/a&gt; от &lt;a href="/tag/twitter/"&gt;Twitter&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;В их проекте данная подсистема развивалась следующим образом:&lt;ul&gt;
&lt;li&gt;1 БД + внешние ключи + join'ы&amp;nbsp;&amp;rarr;&lt;/li&gt;
&lt;li&gt;1 БД + денормализация + кэш&amp;nbsp;&amp;rarr;&lt;/li&gt;
&lt;li&gt;1 БД + master/slave + кэш&amp;nbsp;&amp;rarr;&lt;/li&gt;
&lt;li&gt;несколько функциональных разделенных БД + master/slave + кэш&amp;nbsp;&amp;rarr;&lt;/li&gt;
&lt;li&gt;вертикально и горизонтально разделенные БД (по
    идентификаторам) + по резервные БД (пассивный slave) + кэш&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;При использовании аналогичного решения остерегайтесь:&lt;ul&gt;
&lt;li&gt;Невозможности выполнять большинство запросов с join&lt;/li&gt;
&lt;li&gt;Отсутствия транзакций&lt;/li&gt;
&lt;li&gt;Дополнительных манипуляций для поддержания ограничений
    уникальности&lt;/li&gt;
&lt;li&gt;Необходимости тщательного планирования для изменений схемы&lt;/li&gt;
&lt;li&gt;Необходимости выполнения одного и того же запроса с последующей
    агрегацией для построения отчетов&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Остальные моменты&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Кэширование многоуровневое:&lt;ul&gt;
&lt;li&gt;Коллекции объектов хранятся в списках Redis&lt;/li&gt;
&lt;li&gt;Сами объекты - в memcached&lt;/li&gt;
&lt;li&gt;На уровне SQL запросы в основном примитивны и написаны вручную,
    так что часты попадания в кэш MySQL&lt;/li&gt;
&lt;li&gt;Кэш файловой системы - само собой&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Еще пара фактов про кэширование в Pinterest:&lt;ul&gt;
&lt;li&gt;Кэш разбит также на несколько частей (шардов), для упрощения
    обслуживания и масштабирования&lt;/li&gt;
&lt;li&gt;В коде для кэширования используются Python'овские декораторы, на
    вид собственной разработки, хотя точно не уверен&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Балансировка нагрузки осуществляется в первую очередь за счет Amazon
    ELB, что позволяет легко подключать/отключать новые сервера
    посредством API.&lt;/li&gt;
&lt;li&gt;Так как большинство пользователей живут в США по ночам нагрузка
    сильно падает, что позволяет им по ночам отключать до 40%
    виртуальных машин. В пиковые часы EC2 обходится порядка 52$ в час,
    а по ночам - всего 15$.&lt;/li&gt;
&lt;li&gt;Elastic Map Reduce, основанный на Hadoop, используется для анализа
    данных и стоит всего несколько сотен долларов в месяц&lt;/li&gt;
&lt;li&gt;Текущие проблемы:&lt;ul&gt;
&lt;li&gt;Масштабирование команды&lt;/li&gt;
&lt;li&gt;Основанная на сервисах архитектура:&lt;ul&gt;
&lt;li&gt;Ограничения соединений&lt;/li&gt;
&lt;li&gt;Изоляция функционала&lt;/li&gt;
&lt;li&gt;Изоляция доступа (безопасность)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="uroki-ot-komandy-pinterest"&gt;Уроки от команды Pinterest&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;em&gt;"Оно сломается. Все должно быть просто."&lt;/em&gt; - столько раз уже слышу
    это наставление, но ни разу не видел разработчиков, которые реально
    к нему прислушивались.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;"Кластеризация - страшная штука."&lt;/em&gt; - конечно страшная, большая и
    сложная. Но кому сейчас легко?&lt;/li&gt;
&lt;li&gt;&lt;em&gt;"Продолжайте получать удовольствие."&lt;/em&gt; - с этим не могу не
    согласиться, без удовольствия работать совершенно невозможно в любой
    сфере.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="istochniki-informatsii"&gt;Источники информации&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.insight-it.ru/goto/10005efe/" rel="nofollow" target="_blank" title="http://www.slideshare.net/eonarts/mysql-meetup-july2012scalingpinterest"&gt;Scaling Pinterest @ MySQL Meetup&lt;/a&gt;&lt;ul&gt;
&lt;li&gt;В презентации можно посмотреть примеры кода и SQL-запросов&lt;/li&gt;
&lt;li&gt;Если кто-то знает где можно посмотреть/послушать запись этого
    мероприятия - поделитесь ссылкой, пожалуйста&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.insight-it.ru/goto/ac4a03d6/" rel="nofollow" target="_blank" title="http://highscalability.com/blog/2012/5/21/pinterest-architecture-update-18-million-visitors-10x-growth.html"&gt;Pinterest Architecture Update&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Вакансии в Pinterest&lt;/li&gt;
&lt;/ul&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Иван Блинков</dc:creator><pubDate>Wed, 15 Aug 2012 22:26:00 +0400</pubDate><guid>tag:www.insight-it.ru,2012-08-15:highload/2012/arkhitektura-pinterest/</guid><category>Akamai</category><category>Amazon</category><category>Apache Hadoop</category><category>AWS</category><category>CDN</category><category>CloudFront</category><category>django</category><category>EC2</category><category>Edge Cast</category><category>Hadoop</category><category>Memcached</category><category>MySQL</category><category>nginx</category><category>Pinterest</category><category>Python</category><category>Redis</category><category>S3</category><category>Solr</category><category>Архитектура Pinterest</category><category>архиткутера</category><category>Масштабируемость</category></item><item><title>Moscow Erlang Factory Lite 2012</title><link>https://www.insight-it.ru//event/2012/moscow-erlang-factory-lite-2012/</link><description>&lt;p&gt;Давненько я не выбирался на IT-мероприятия, так что продолжу традицию
делиться впечатлениями. Как следует из заголовка она была исключительно
про &lt;a href="/tag/erlang/"&gt;Erlang&lt;/a&gt;, причем в самых разных его проявлениях.
Недавно я написал пару статей про него, можно найти по соответствующему
&lt;a href="/tag/erlang/"&gt;тегу&lt;/a&gt;. Конференция была всего на пол дня, так что пост
получится явно небольшой - много времени не займет ;)&lt;/p&gt;
&lt;!--more--&gt;
&lt;h2 id="organizatsiia"&gt;Организация&lt;/h2&gt;
&lt;p&gt;Мероприятие проводили совместно &lt;strong&gt;Erlang Solutions&lt;/strong&gt;&amp;nbsp;(международная
организация, которая регулярно проводит подобные Erlang-мероприятия,
сертификации и т.п.) и &lt;strong&gt;Яндекс&lt;/strong&gt;. Проходило все в двух шагах от офиса
Яндекса, плюс они же занимались собственно всеми организационными
вопросами. Единственный представитель Erlang Solutions видимо не знал
что в Москве бывают пробки и сильно опоздал, к слову у меня на телефоне
его фотка нашлась, заодно можно оценить масштабы мероприятия (весь
единственный зал):&lt;/p&gt;
&lt;p&gt;&lt;img alt="Фотография с Erlang Factory Lite" class="responsive-img" src="https://www.insight-it.ru/images/erlang-factory-lite-photo.jpg" title="Фотография с Erlang Factory Lite"/&gt;&lt;/p&gt;
&lt;p&gt;Конференция по задумке должна была быть полностью на английском, без
перевода, так как якобы трансляцию могли смотреть и не русские. Но по
факту докладчики были к этому не готовы, у примерно трети докладчиков
был английский с кошмарным акцентом, не говоря уже о длинных паузах
"э-э-э" пока вспоминались подходящие слова.&lt;/p&gt;
&lt;p&gt;Еще из косяков к началу конференции никто не удосужился проверить звук и
удаленный&amp;nbsp;переключатель&amp;nbsp;слайдов.&lt;/p&gt;
&lt;p&gt;А в остальном все ок, простенько и со вкусом. Едем дальше.&lt;/p&gt;
&lt;h2 id="doklady"&gt;Доклады&lt;/h2&gt;
&lt;h3 id="iandeks"&gt;Яндекс&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;В Яндексе всего три Erlang-программиста, кажется все присутствовали&lt;/li&gt;
&lt;li&gt;Используют свой форк &lt;a href="/tag/ejabberd/"&gt;ejabberd&lt;/a&gt;&amp;nbsp;примерно пятилетней
    давности для их мессенджера и пуш-уведомлений:&lt;ul&gt;
&lt;li&gt;С момента своего создания изменения из основной ветки развития
    не мерджились и обратно выкладываться в opensource не собираются
    из-за "сильной интеграции с другими сервисами Яндекса"&lt;/li&gt;
&lt;li&gt;Для хранения постоянных данных используют
    &lt;a href="/tag/mongodb/"&gt;MongoDB&lt;/a&gt;, на вопрос почему именно докладчик так
    честно ответил "не знаю"&lt;/li&gt;
&lt;li&gt;Основная часть доклада ушла на рассказ об оптимизациях внутри
    самого ejabberd, реализованных в их форке, в частности:&lt;ul&gt;
&lt;li&gt;Добавили проверку на то, жив ли процесс перед тем как
    отправлять ему сообщение, изначально ejabberd в этом плане
    был более оптимистичен и их это по непонятным причинам не
    устроило.&lt;/li&gt;
&lt;li&gt;Уменьшили объем используемой оперативной памяти за счет
    "ленивой подгрузки" части данных, которые редко
    используются. Из зала, кстати, кто-то добавил что у
    аналогичного форка от Erlang Solutions повсеместное
    &amp;nbsp;использование бинарных строк вместо обычных дало очень
    ощутимую экономию оперативной памяти.&lt;/li&gt;
&lt;li&gt;И, кажется, объединили принимающий и отправляющий сообщения
    процессы в один.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;На вопрос о цифрах выдали только порядки: несколько десятков
    серверов обслуживают несколько сотен тысяч пользователей онлайн.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="fedora-project_1"&gt;Fedora Project&lt;/h2&gt;
&lt;p&gt;Обсуждался вопрос сильного "отставания" доступных по-умолчанию в
&lt;a href="/tag/linux/"&gt;Linux&lt;/a&gt;-дистрибутивах версий Erlang, да и не только Erlang,
от последней стабильной. Я думаю очень актуальный вопрос для тех, кто
занимается продажей коммерческого софта для Linux, или для тех, кто
занимается сборкой и поддержкой пакетов для opensource проектов.&lt;/p&gt;
&lt;p&gt;Erlang сделан так, что подход &lt;em&gt;"все свое ношу с собой"&lt;/em&gt;, &lt;strong&gt;существенно&lt;/strong&gt;
проще и удобнее, чем управление зависимостями. Хотя докладчик приводил
пример, что &lt;a href="/tag/couchdb/"&gt;CouchDB&lt;/a&gt; как раз использует альтернативный
подход требования точных версий зависимостей и у них в Fedora были
большие заморочки с тем, что они обновили
&lt;a href="/tag/javascript/"&gt;JavaScript&lt;/a&gt;-движок на одну версию выше, чем от
которого зависела последняя версия CouchDB. Я так и не уловил как в
итоге эту ситуацию решили, наверное пришлось оставить в репозитории две
версии зависимости или дождаться и&amp;nbsp;обновления&amp;nbsp;CouchDB.&lt;/p&gt;
&lt;h2 id="mochi-media"&gt;Mochi Media&lt;/h2&gt;
&lt;p&gt;Вместо рассказа о &lt;strong&gt;mochiweb&lt;/strong&gt; речь шла о различных вариантах как можно
реализовать случайный выбор элемента из списка и их слабых и сильных
сторонах. Причем для примера использовался не реальный проект, где они
подобным занимаются (баннерная сеть), а IRC-бот&amp;nbsp;написанный&amp;nbsp;для
развлечения. Да и к Erlang практически никакого отношения, единственной
что узнал полезного: стандартный модуль &lt;strong&gt;random&lt;/strong&gt; написан по не самому
удачному алгоритму, созданному в начале 80-х, и если это сколько-либо
критично для приложения - лучше вместо него использовать &lt;strong&gt;crypto&lt;/strong&gt; или
сторонние библиотеки.&lt;/p&gt;
&lt;h3 id="maks-lapshin"&gt;Макс Лапшин&lt;/h3&gt;
&lt;p&gt;Докладчик является, пожалуй, самым активным участником российского
Erlang-сообщества, известен в узких кругах как автор &lt;strong&gt;Erlyvideo&lt;/strong&gt;,
opensource решения для потокового вещания видео. Рассказывал про
какой-то другой проект, в частности о парсере протокола FIX,
использующегося на фондовых биржах и отличающегося огромной
спецификацией с более чем сотней типов сообщений. Основная идея доклада:
если нужно написать много однотипного кода, его лучше сгенерировать, чем
копипастить.&lt;/p&gt;
&lt;p&gt;К счастью, авторы этого протокола заботятся о разработчиках и публикуют
спецификацию в виде &lt;a href="/tag/xml/"&gt;XML&lt;/a&gt;-файла, который Макс предлагает
парсить и генерировать на его основе необходимые .erl файлы, не дерево
синтаксиса, а прямо текстовые .erl файлы. В конкретно этом случае ему
нужно было из proplist-ов создавать record'ы, а сам парсинг сообщений он
решил написать на &lt;a href="/tag/c/"&gt;C&lt;/a&gt;.&amp;nbsp;Хотя мне кажется эту конвертацию тоже
можно было бы убрать в C.&lt;/p&gt;
&lt;h3 id="aleks-gunin"&gt;Алекс Гунин&lt;/h3&gt;
&lt;p&gt;Это был единственный доклад на 80% на русском, так как попытка начать
его на английском закончилась полным провалом. Хотя заголовок у доклада
был самый, пожалуй, интересный - &lt;em&gt;"как сделать Erlang по-настоящему
распределенным и отказоустойчивым"&lt;/em&gt;. Основная идея была использовать
часть распределенной СУБД &lt;a href="/tag/riak/"&gt;Riak&lt;/a&gt;, отвечающую за
распределение и поиск данных в кластере &lt;em&gt;(Riak Core)&lt;/em&gt;, для маршрутизации
простых Erlang сообщений и &amp;nbsp;по аналогии с несколькими репликами данных
запускать несколько копий одинаковых процессов. Для реализации этой
затеи они написали совместимые со стандартными модули gen_server2,
gen_fsm2 и т.п. &lt;em&gt;(что, кстати, плохая практика - из-за таких названий
можно легко столкнуться с конфликтами в пространстве имен модулей,
например в &lt;a href="/tag/rabbitmq/"&gt;RabbitMQ&lt;/a&gt; и каком-то еще популярном проекте
тоже есть gen_server2, как-то сталкивался)&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Задумка явно толковая и думаю для многих систем актуальная, но
подробностей очень мало, плюс докладчик очень смутно излагал свои мысли
даже на русском. Он не сказал для какой компании он все это
разрабатывал, но пообещал выложить саму систему маршрутизации сообщений
в opensource. Когда и где - не ясно.&lt;/p&gt;
&lt;h3 id="lev-valkin"&gt;Лев Валкин&lt;/h3&gt;
&lt;p&gt;Это был последний доклад, где я присутствовал, в оставшейся секции из
трех докладов мне совсем ничего не приглянулось, но зато этот мне больше
всего понравился. Думаю в первую очередь так как Лев косвенно
пропагандировал&amp;nbsp;очень близкую мне тему использования &lt;strong&gt;Erlang&lt;/strong&gt; для
создания &lt;a href="https://www.insight-it.ru/interactive/"&gt;интерактивных веб-сайтов&lt;/a&gt;. Большинство докладов были все же про другие предметные области. Раньше про его компанию &lt;strong&gt;Echo&lt;/strong&gt; ничего не слышал, но список клиентов на главной у них солидный, надо будет почитать на досуге.&lt;/p&gt;
&lt;p&gt;Сам доклад был про выбор и оценку языков программирования и
связанных&amp;nbsp;платформ по относительно объективным критериям (сообщество,
ассортимент opensource библиотек, возможности в тестировании,
интроспекции и дебаге, плюшки вроде горячей замены кода и пр.). Правда в
итоге все свелось к тому, что главное, чтобы разработчикам &lt;em&gt;нравилось
что они делают&lt;/em&gt; - иначе как бы не была объективно&amp;nbsp;хороша та или иная
технология все равно получится черти что :)&lt;/p&gt;
&lt;p&gt;Изначально Лев планировал доклад на тему &lt;strong&gt;Erlang vs node.js&lt;/strong&gt;, но её
забраковали организаторы, видимо за холиварность. В итоге она все же
местами затрагивалась, да и вопросы после доклада в основном были по
ней.&lt;/p&gt;
&lt;p&gt;Основные моменты:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Повторное использование кода между серверным JavaScript и
    клиентским - в большинстве случаев &lt;strong&gt;миф&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Легко найти серверного node.js-разработчика, так как все и так уже
    знают JavaScript &amp;nbsp;- тоже &lt;strong&gt;миф&lt;/strong&gt;, клиентская разработка
    концептуально сильно отличается от серверной, намного больше
    node.js-разработчиков приходит с других серверных платформ, а не с
    клиентского JavaScript.&lt;/li&gt;
&lt;li&gt;node.js хоть и сильно проигрывает Erlang по ряду объективных
    показателей применительно к веб разработке, благодаря своей
    популярности именно среде молодых веб-разработчиков (во многом
    благодаря вышеизложенным мифам) сильно угрожает популяризации Erlang
    в этой же самой среде.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Свое мнение про JavaScript в целом и node.js в частности оставлю за
кадром, недавно в одном из постов высказывался уже на эту тему.&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Иван Блинков</dc:creator><pubDate>Sat, 23 Jun 2012 02:40:00 +0400</pubDate><guid>tag:www.insight-it.ru,2012-06-23:event/2012/moscow-erlang-factory-lite-2012/</guid><category>ejabberd</category><category>Erlang</category><category>Erlang Solutions</category><category>конференции</category><category>мероприятия</category><category>Яндекс</category></item><item><title>Основы Erlang: синтаксис и пунктуация</title><link>https://www.insight-it.ru//erlang/2012/osnovy-erlang-sintaksis-i-punktuaciya/</link><description>&lt;p&gt;Мои теоретичесие рассуждения о &lt;a href="https://www.insight-it.ru/erlang/2012/erlang-v-internet-proektakh/"&gt;месте Erlang в &lt;del&gt;современном мире&lt;/del&gt; Интернете&lt;/a&gt;&amp;nbsp;Вы
можете почитать в отдельной статье. Если сомневаетесь интересно Вам это
все или нет - то прочтите сначала её. Сегодня я постараюсь вернуться с
небес на землю и пройтись по азам этого пугающего многих языка
программирования. Коротко и по делу.&lt;/p&gt;
&lt;!--more--&gt;
&lt;p&gt;Установка ничем особым не выделяется, дистрибутив рекомендую брать
&lt;a href="https://www.insight-it.ru/goto/767abd85/" rel="nofollow" target="_blank" title="https://www.erlang-solutions.com/downloads/download-erlang-otp"&gt;отсюда&lt;/a&gt;,
если до сих пор пользуетесь отсутствующей в списке ОС - лучше сначала
исправить этот факт.&lt;/p&gt;
&lt;p&gt;После установки в &lt;code&gt;$PATH&lt;/code&gt; окажутся исполняемые файлы:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;erl&lt;/strong&gt; - одновременно интерактивная консоль и запуск приложений;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;erlc&lt;/strong&gt; - компилятор в байт-код для виртуальной машины BEAM или
    нативный код посредством HiPE, напрямую использовать не придется
    практически.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Со всем что будет обсуждаться в этой статье можно эксперементировать
просто в интерактивной консоли, которая запускается просто командой
&lt;strong&gt;erl&lt;/strong&gt; без аргументов.&lt;/p&gt;
&lt;h2 id="punktuatsiia"&gt;Пунктуация&lt;/h2&gt;
&lt;p&gt;Сразу скажу, что пунктуация в Erlang довольно своеобразна, больше похожа
на русский язык, чем на другие языки программирования. По крайней мере я
именно этой ассоциацией пользовался, когда запоминал.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Все функции заканчиваются &lt;strong&gt;точкой&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;После каждого выражения в функции - &lt;strong&gt;запятая;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Все ветви кода &lt;code&gt;(case, if, ...)&lt;/code&gt;, кроме последней, заканчиваются
    &lt;strong&gt;точкой с запятой&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;После заголовка функции и условий ветвления пишется &lt;strong&gt;стрелка&lt;/strong&gt; &lt;code&gt;-&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Маленькая демонстрация:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nf"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;X&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Y&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
  &lt;span class="nv"&gt;Z&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;X&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nv"&gt;X&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt;
    &lt;span class="nv"&gt;Y&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
      &lt;span class="nv"&gt;Z&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nv"&gt;Y&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;true&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
      &lt;span class="nv"&gt;Z&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nv"&gt;Y&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;К слову, функции возвращают результат выполнения последнего выражения, в
данном случае оно представляет собой весь блок &lt;code&gt;if&lt;/code&gt;, а &lt;code&gt;end&lt;/code&gt;
обозначает его окончание (не функции).&lt;/p&gt;
&lt;h2 id="sintaksis"&gt;Синтаксис&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Foo&lt;/code&gt; - все что начинается с английской заглавной буквы -
    переменная, специально объявлять ничего не нужно&lt;/li&gt;
&lt;li&gt;&lt;code&gt;_&lt;/code&gt;&amp;nbsp;- сам знак нижнего подчеркивания и все что с него
    начинается - особый случай переменной, значение которой не значимо
    для программы и при первой возможности "выкидывается"&lt;/li&gt;
&lt;li&gt;Цифры в основном как обычно, есть научная нотация в духе &lt;code&gt;1.23e4&lt;/code&gt;
    (1.23 умножить на 10 в степени 4) и системы исчисления с другим
    основанием, скажем двоичная - &lt;code&gt;2#101010&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;foo&lt;/code&gt; - с строчной буквы начинаются &lt;em&gt;атомы&lt;/em&gt;, по сути константы,
    используются повсеместно:&lt;ul&gt;
&lt;li&gt;названия функций и модулей&lt;/li&gt;
&lt;li&gt;&lt;code&gt;true&lt;/code&gt; и &lt;code&gt;false&lt;/code&gt; - булевые значения&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ok&lt;/code&gt; - типичный результат успешный результат выполнения&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;?FOO&lt;/code&gt;&amp;nbsp;- хоть официально и называются константами, но по сути -
    макросы, перед компиляцией заменяются на заранее определенный кусок
    кода&lt;strong&gt;&amp;nbsp;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;{foo, bar}&lt;/code&gt; - кортеж, набор данных фиксированной длины&lt;/li&gt;
&lt;li&gt;&lt;code&gt;[foo, bar]&lt;/code&gt; - простой однонаправленный список произвольной длины&lt;/li&gt;
&lt;li&gt;&lt;code&gt;"foo"&lt;/code&gt; - текстовая строка, представленная в виде
    однонаправленного списка (что не эффективно с точки зрения
    потребления памяти, до 4 байт на символ)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;&amp;lt;"foo"&amp;gt;&amp;gt;&lt;/code&gt; - бинарная строка, может содержать что угодно,
    в.т.ч. и текст; все что не цифры по возможности лучше хранить в этом
    типе данных.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="sopostavlenie-pattern-matching"&gt;Сопоставление &lt;em&gt;(pattern matching)&lt;/em&gt;&lt;/h2&gt;
&lt;p&gt;Очень мощная концепция &lt;em&gt;сопоставления&lt;/em&gt; используется в &lt;strong&gt;Erlang&lt;/strong&gt; на
каждом углу. В базовом варианте работает примерно так:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Result&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Если в функции foo все прошло нормально, то она возвращает, например
&lt;code&gt;{ok, 123}&lt;/code&gt;, и переменной &lt;code&gt;Result&lt;/code&gt; окажется лишь значение &lt;code&gt;123&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Если же возникла какая-то проблема, то она вернет что-то другое, скажем
&lt;code&gt;{error, timeout}&lt;/code&gt;, приложение столкнется с несоответствием левой и
правой части (атомы &lt;strong&gt;ok&lt;/strong&gt; и &lt;strong&gt;error&lt;/strong&gt; разные) и прекращает свое
выполнение (если бы было чего выполнять).&lt;/p&gt;
&lt;p&gt;Базовый принцип, надеюсь, понятен. Подобным образом выбирается какую из
реализаций функции использовать, в какую ветвь &lt;strong&gt;case&lt;/strong&gt; идти и т.п. В
общем есть много других более сложных применений, но о них в другой раз.&lt;/p&gt;
&lt;h2 id="spiski"&gt;Списки&lt;/h2&gt;
&lt;p&gt;Со списками есть три особые операции:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;[Head | Tail ] = [1, 2, 3, 4]&lt;/code&gt; - вытащить элемент с головы
    списка, работает по принципу сопоставления, в &lt;code&gt;Head&lt;/code&gt; окажется
    &lt;code&gt;1&lt;/code&gt;, а в &lt;code&gt;Tail&lt;/code&gt; - &lt;code&gt;[2, 3, 4]&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;[1, 2] ++ [3, 4]&lt;/code&gt; - конкатенация, результатом будет &lt;code&gt;[1, 2, 3, 4]&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;[N&amp;nbsp;*&amp;nbsp;N&amp;nbsp;|| N&amp;nbsp;&amp;lt;- [1,&amp;nbsp;2,&amp;nbsp;3], N &amp;gt; 1]&lt;/code&gt; - выглядит замороченно, по
    сути это обычный отображение &lt;em&gt;(map)&lt;/em&gt; с фильтрацией &lt;em&gt;(filter)&lt;/em&gt; - то
    есть выражение перед &lt;code&gt;||&lt;/code&gt; применяется к каждому элементу списка,
    значение которых попадает в переменную &lt;strong&gt;N&lt;/strong&gt;, а после запятой -
    условие, накладываемое на &lt;strong&gt;N&lt;/strong&gt;; таким образом результат будет &lt;strong&gt;[4,
    9]&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="binarnye-stroki"&gt;Бинарные строки&lt;/h2&gt;
&lt;p&gt;C ними намного больше всяких трюков и преобразований, приведу наиболее
значимые:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Binary = &amp;lt;&amp;lt;Integer:64&amp;gt;&amp;gt;&lt;/code&gt; - преобразовать целое число Integer
    в бинарную строку Binary длиной 64 бита (для примера, может быть
    любой&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;&amp;lt;Integer1:32, Integer2:32&amp;gt;&amp;gt; =&amp;nbsp;Binary&lt;/code&gt; - распокавать обратно
    бинарную строку в целые числа, но уже два по 32 бита; чем-то похоже
    на операцию &lt;code&gt;[H | T]&lt;/code&gt; у списков, но намного более гибко&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Binary3 = &amp;lt;&amp;lt;Binary1/binary, Binary2/binary&amp;gt;&amp;gt;&lt;/code&gt; - конкатенация
    бинарных строк, результат окажется в &lt;code&gt;Binary3&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;&amp;lt; &amp;lt;&amp;lt;(N * N)/integer&amp;gt;&amp;gt; || &amp;lt;&amp;lt;N&amp;gt;&amp;gt; &amp;lt;= &amp;lt;&amp;lt;1, 2, 3&amp;gt;&amp;gt;, N &amp;gt; 1 &amp;gt;&amp;gt;&lt;/code&gt;&amp;nbsp;- аналог последнего примера для списков, только для
    бинарных данных; результат аналогичен - &lt;code&gt;&amp;lt;&amp;lt;4, 9&amp;gt;&amp;gt;&lt;/code&gt;; к слову
    официально это называется &lt;em&gt;binary comprehensions&lt;/em&gt;, а для списков -
    &lt;em&gt;list comprehensions&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="zakliuchenie"&gt;Заключение&lt;/h2&gt;
&lt;p&gt;Очень многое пришлось опустить, иначе самое главное затерялось бы, да и
объем статьи сильно вырос. Подробности всегда можно найти на
&lt;a href="https://www.insight-it.ru/goto/547f742d/" rel="nofollow" target="_blank" title="http://www.erlang.org/"&gt;официальном сайте&lt;/a&gt;, в man'ах, да и просто
погуглив.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Удачного освоения Erlang!&lt;/em&gt;&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Иван Блинков</dc:creator><pubDate>Fri, 22 Jun 2012 01:27:00 +0400</pubDate><guid>tag:www.insight-it.ru,2012-06-22:erlang/2012/osnovy-erlang-sintaksis-i-punktuaciya/</guid><category>Erlang</category><category>Программирование</category><category>разработка</category></item><item><title>Вакансии: развитие поведенческих технологий в рунете (СПб)</title><link>https://www.insight-it.ru//vacancy/2012/vakansii-razvitie-povedencheskikh-tekhnologijj-v-runete-spb/</link><description>&lt;div class="card orange darken-3"&gt;
&lt;p&gt;&lt;div class="card-content white-text center"&gt;
&lt;strong&gt;Вакансии более не актуальны&lt;/strong&gt;
&lt;/div&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;Представьте себе рекламу, которая интересна. Рекламу, которая не
раздражает, а дает персональную рекомендацию. Подобный механизм создает
компания &lt;strong&gt;RuTarget&lt;/strong&gt; - стартап, занимающийся развитием поведенческих технологий на российском рекламном рынке.
&lt;!--more--&gt;&lt;/p&gt;
&lt;p&gt;Если Вы способный IT-специалист из &lt;strong&gt;Санкт-Петербурга&lt;/strong&gt;, всегда мечтали
написать систему уровня Facebook или Twitter, на одном дыхании читаете
статьи о Google Big Table и хотели бы участвовать в создании полезной
системы, возможно, одна из этих вакансий будет Вам интересна:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Системный архитектор&lt;/li&gt;
&lt;li&gt;Старший разработчик&lt;/li&gt;
&lt;li&gt;Младший разработчик&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Система RuTarget использует &lt;strong&gt;Real Time Bidding API&lt;/strong&gt; - аукцион показов
рекламы в режиме реального времени. За последние три года эта технология
совершила революцию в рекламе на Западе. RuTarget - одни из первых, кто
внедряет ее в России. Математический алгоритм принимает 170 миллионов
решений о показах в день, за доли секунды распознает посетителя и
подбирает полезные для него предложения, используя знания о предыдущих
его действиях в сети.&lt;/p&gt;
&lt;h3 id="rabota-v-kompanii-rutarget-eto"&gt;Работа в компании RuTarget - это:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Работа над высоконагруженным рекламным проектом, способным
    выдерживать в штатном режиме 500 миллионов запросов в день с уровнем
    доступности 99.9%.&lt;/li&gt;
&lt;li&gt;Новейшие технологии и компоненты: &lt;strong&gt;Apache Hadoop (+Pig, Hive и
    Mahout), Map-Reduce, Membase, Memcached, Redis.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Отсутствие legacy-кода и необходимости его поддержки.&lt;/li&gt;
&lt;li&gt;Работа в режиме &lt;strong&gt;Scrum, TDD.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;В коллективе только разработчики.&lt;/em&gt; У нас нет менеджеров, которые
    плохо понимают в программировании, но любят навязывать свое мнение.&lt;/li&gt;
&lt;li&gt;Интересные технические и алгоритмические задачи для любого уровня
    квалификации.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="ot-sistemnogo-arkhitektora-i-starshego-razrabotchika-my-ozhidaem"&gt;От системного архитектора и старшего разработчика мы ожидаем:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Вас не надо контролировать и говорить, что и как делать, вы способны
    самостоятельно ставить задачи, оценивать сроки их выполнения и
    находить адекватные решения.&lt;/li&gt;
&lt;li&gt;Вы умеете коротко и ясно излагать свои мысли в устной и письменной
    форме.&lt;/li&gt;
&lt;li&gt;Вы любите работать в команде, умеете выслушивать чужую точку зрения
    и принимать совместные решения.&lt;/li&gt;
&lt;li&gt;Вас не пугают фразы &amp;ldquo;коллизии в хеш-таблицах&amp;rdquo;, &amp;ldquo;минимизация
    contention&amp;rdquo;, &amp;ldquo;красно-черные деревья&amp;rdquo;, &amp;ldquo;фильтр Блума&amp;rdquo;.&lt;/li&gt;
&lt;li&gt;Вы разделяете мнение &amp;ldquo;язык и платформа для задачи, а не наоборот&amp;rdquo;.&lt;/li&gt;
&lt;li&gt;Вы считаете написание тестов частью задачи.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="senior-developer-system-architect-java_1"&gt;Senior Developer / System Architect (Java)&lt;/h2&gt;
&lt;h3 id="neobkhodimye-navyki"&gt;Необходимые навыки:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Опыт программирования на &lt;strong&gt;Java&lt;/strong&gt; в коммерческих проектах не менее
    3-х лет&lt;/li&gt;
&lt;li&gt;Глубокое понимание &lt;strong&gt;OOP&lt;/strong&gt;, опыт многопоточного программирования&lt;/li&gt;
&lt;li&gt;Опыт разработки высоконагруженных сервисов. Глубокое понимание
    принципов масштабирования и отказоустойчивости.&lt;/li&gt;
&lt;li&gt;Знание английского языка на уровне, достаточном для чтения и ведения
    документации.&lt;/li&gt;
&lt;li&gt;Опыт разработки на нескольких языках (желательно &lt;strong&gt;C/C+&lt;/strong&gt;+ или
    &lt;strong&gt;JavaScript&lt;/strong&gt;).&lt;/li&gt;
&lt;li&gt;Опыт администрирования &lt;strong&gt;Linux&lt;/strong&gt;-систем.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="dopolnitelnymi-preimushchestvami-budut"&gt;Дополнительными преимуществами будут:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Общая математическая эрудиция. Знакомство с алгоритмами
    классификации и кластерного анализа, машинного обучения, &lt;strong&gt;data
    mining&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Участие в разработке рекламных сервисов, систем управления медийной
    и контекстной рекламой. Знакомство с технологиями &lt;strong&gt;RTB&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="senior-software-developer-data-mining-java_1"&gt;Senior Software Developer / Data Mining (Java)&lt;/h2&gt;
&lt;h3 id="neobkhodimye-navyki_1"&gt;Необходимые навыки:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Опыт программирования на &lt;strong&gt;Java&lt;/strong&gt; в коммерческих проектах не менее
    3-х лет.&lt;/li&gt;
&lt;li&gt;Общая математическая эрудиция. Знакомство с алгоритмами
    классификации и кластерного анализа, статистики, машинного обучения,
    data mining.&lt;/li&gt;
&lt;li&gt;Опыт работы с частью из следующих алгоритмов: &lt;strong&gt;K-Means Clustering,
    Principal Components Analysis, Decision Trees, Random Forests,
    Expectation Maximization, Support Vector Machines, Nonlinear
    Regression And Correlation.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Знакомство с пакетами математического и статистического анализа.&lt;/li&gt;
&lt;li&gt;Знание английского языка на уровне, достаточном для чтения и ведения
    документации.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="dopolnitelnymi-preimushchestvami-budut_1"&gt;Дополнительными преимуществами будут:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Участие в разработке рекламных сервисов, систем управления медийной
    и контекстной рекламой. Знакомство с технологиями &lt;strong&gt;RTB&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Опыт создания клиент-серверных или распределенных приложений.&lt;/li&gt;
&lt;li&gt;Опыт администрирования &lt;strong&gt;Linux&lt;/strong&gt;-систем.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="junior-developer-intern-java_1"&gt;Junior Developer / Intern (Java)&lt;/h2&gt;
&lt;p&gt;Для Junior Developer это возможность обучаться в коллективе
высококлассных профессионалов, а также приобрести бесценный опыт работы
с облачными сервисами. Если Вы учитесь, возможен гибкий график с учетом
посещения лекций.&lt;/p&gt;
&lt;h3 id="ot-vas-ozhidaetsia"&gt;От Вас ожидается:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Вы умеете коротко и ясно излагать свои мысли в устной и письменной
    форме.&lt;/li&gt;
&lt;li&gt;Вы любите работать в команде, умеете выслушивать чужую точку зрения
    и принимать совместные решения.&lt;/li&gt;
&lt;li&gt;Вы понимаете, как выбрать оптимальную структуру данных для
    поставленной задачи, вы способны рассчитать асимптотическую
    сложность ваших алгоритмов.&lt;/li&gt;
&lt;li&gt;Вы разделяете мнение &amp;ldquo;язык и платформа для задачи, а не наоборот&amp;rdquo;.&lt;/li&gt;
&lt;li&gt;Фразы &lt;em&gt;&amp;ldquo;консоль Linux&amp;rdquo;&lt;/em&gt; и &lt;em&gt;&amp;ldquo;bash-скрипт&amp;rdquo;&lt;/em&gt; вас как минимум не пугают.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="neobkhodimye-navyki_2"&gt;Необходимые навыки:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Опыт программирования на &lt;strong&gt;Java&lt;/strong&gt; не менее 1 года.&lt;/li&gt;
&lt;li&gt;Понимание принципов &lt;strong&gt;OOP&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Знание английского языка на уровне, достаточном для чтения и ведения
    документации.&lt;/li&gt;
&lt;li&gt;Опыт администрирования &lt;strong&gt;Linux&lt;/strong&gt;-систем.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="dopolnitelnymi-preimushchestvami-budut_2"&gt;Дополнительными преимуществами будут:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Общая математическая эрудиция. Знакомство с алгоритмами
    классификации и кластерного анализа, машинного обучения, data
    mining.&lt;/li&gt;
&lt;li&gt;Участие в разработке рекламных сервисов, систем управления медийной
    и контекстной рекламой. Знакомство с технологиями &lt;strong&gt;RTB&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Опыт создания клиент-серверных или распределенных приложений.&lt;/li&gt;
&lt;li&gt;Опыт разработки на нескольких языках (&lt;strong&gt;C/C++&lt;/strong&gt; или &lt;strong&gt;JavaScript&lt;/strong&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="usloviia-raboty_1" style="text-align: center;"&gt;Условия работы&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Зарплата по результатам собеседования:&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;System Architect&lt;/strong&gt; от 90 тыс. рублей&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Senior Software&lt;/strong&gt; &lt;strong&gt;Developer&lt;/strong&gt; от 70 тыс. рублей&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Junior Developer&lt;/strong&gt; от 30 тыс. рублей&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Гибкий график работы.&lt;/li&gt;
&lt;li&gt;Комфортные рабочие места, быстрые компьютеры, большие мониторы.&lt;/li&gt;
&lt;li&gt;Бесплатные горячие обеды.&lt;/li&gt;
&lt;li&gt;Круглосуточный доступ в офис.&lt;/li&gt;
&lt;li&gt;Возможность удаленной работы из дома при необходимости.&lt;/li&gt;
&lt;li&gt;Полная рабочая неделя в офисе в &lt;strong&gt;Санкт-Петербурге&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;После собеседования Вас могут попросить выполнить тестовое задание.&lt;/p&gt;
&lt;p&gt;При подаче резюме опишите, пожалуйста, отдельно свой непосредственный
опыт и знания, которые будут наиболее полезны для проекта, и укажите,
что узнали о вакансии через &lt;span class="trebuchet"&gt;Insight IT&lt;/span&gt;.&lt;/p&gt;
&lt;div class="card orange darken-3"&gt;
&lt;p&gt;&lt;div class="card-content white-text center"&gt;
&lt;strong&gt;Вакансии более не актуальны&lt;/strong&gt;
&lt;/div&gt;&lt;/p&gt;
&lt;/div&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Иван Блинков</dc:creator><pubDate>Mon, 04 Jun 2012 13:35:00 +0400</pubDate><guid>tag:www.insight-it.ru,2012-06-04:vacancy/2012/vakansii-razvitie-povedencheskikh-tekhnologijj-v-runete-spb/</guid><category>Java</category><category>RuTarget</category><category>вакансии</category></item><item><title>Серверная часть интерактивного сайта и потоки сообщений</title><link>https://www.insight-it.ru//interactive/2012/servernaya-chast-interaktivnogo-sajjta-i-potoki-soobshhenijj/</link><description>&lt;p&gt;Вернемся к теме &lt;a href="https://www.insight-it.ru/interactive/"&gt;интерактивных сайтов&lt;/a&gt; с обратной стороны, серверной. В ней есть огромный простор для творчества, так как
в отличии от клиентской части отсутствуют ограничения, накладываемыми
браузерами. С "простором" же приходит и неоднозначность/неопределенность, вариантов как реализовать одно и то же множество, так что возможно приводимые мной примеры Вам окажутся не по душе &amp;nbsp;- и это нормально, правильный путь не единственный, их много :)&lt;/p&gt;
&lt;p&gt;Приступим!&lt;/p&gt;
&lt;!--more--&gt;
&lt;h2 id="vnutrennie-servisy"&gt;Внутренние сервисы&lt;/h2&gt;
&lt;p&gt;Напомню, что обычно на внутренние сервисы ложится реализация всей или
большей части бизнес-логики приложения. Они получают пользовательские
запросы в стандартизированном виде через прослойки в виде внешних
интерфейсов и, при необходимости взаимодействуя друг с другом и
остальными компонентами системы, определяют какой ответ необходимо
отправить и какие другие действия предпринять.&lt;/p&gt;
&lt;p&gt;Я не буду здесь особо вдаваться в возможные детали реализации самой
бизнес-логики - она практически всегда уникальна, скорее заслуживает
внимания её "обертка" - сам процесс, принимающий и создающий внутренние
запросы.&lt;/p&gt;
&lt;p&gt;Вообще создание внутренних сервисов очень хорошо ложится на так
называемую &lt;a href="https://www.insight-it.ru/goto/7e699ecd/" rel="nofollow" target="_blank" title="http://ru.wikipedia.org/wiki/%D0%9C%D0%BE%D0%B4%D0%B5%D0%BB%D1%8C_%D0%B0%D0%BA%D1%82%D0%BE%D1%80%D0%BE%D0%B2"&gt;модель "акторов"&lt;/a&gt;,
система разбивается на некие логические примитивы, общающиеся между
собой исключительно передачей сообщений. По сути процессы с
определенными разработчиками наборами входящих и исходящих сообщений и
алгоритмом преобразования одних в другие. При таком подходе группа
одинаково функционирующих акторов (вероятно распределенная по нескольким
серверам для отказоустойчивости и возможности масштабирования) и
образует внутренний сервис.&lt;/p&gt;
&lt;p&gt;На практике есть масса способов воплотить эту модель в жизнь,
перечислю&amp;nbsp;с пояснениями наиболее заслуживающие внимания&amp;nbsp;на мой взгляд:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Функциональные языки программирования,&lt;/strong&gt;&amp;nbsp;в &lt;a href="/tag/erlang/"&gt;Erlang&lt;/a&gt;
    и &lt;a href="/tag/scala/"&gt;Scala&lt;/a&gt; модель акторов является практически "сердцем"
    всего языка и связанной платформы; у обоих есть библиотеки для
    реализации надежных, высокопроизводительных и масштабируемых акторов
    (&lt;strong&gt;OTP&lt;/strong&gt; и &lt;strong&gt;Akka&lt;/strong&gt;, соответственно). Если не боитесь кардинально
    отличающейся от нынче модного ООП парадигмы разработки, этот вариант
    наиболее жизнеспособный, &lt;em&gt;рекомендую&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Асинхронный HTTP-сервер&lt;/strong&gt;, в частности &lt;a href="/tag/tornado/"&gt;Tornado&lt;/a&gt; и
    &lt;a href="/tag/node-js/"&gt;node.js&lt;/a&gt;&amp;nbsp;- они основаны на &lt;a href="https://www.insight-it.ru/linux/2012/kak-rabotaet-epoll/"&gt;epoll&lt;/a&gt; и помимо эффективной обработки HTTP-запросов умеют и эффективно их отправлять посредством идущего в комплекте асинхронного же клиента.
    При таком подходе по сути получается несколько "уровней"
    HTTP-серверов, первый из которых публично доступен для общения с
    внешним миром и в ответ на каждый входящий запрос обращается сразу к
    нескольким внутренним HTTP-сервисам (вероятно параллельно) и на их
    основе составляет ответ пользователю. Этот подход одно время активно
    пропагандировали на конференциях ребята из одного крупного
    отечественного сайта с вакансиями. Особенным бонусом этого варианта
    является возможность использовать в роли внутреннего сервиса
    какую-то старую, доставшуюся по наследству &lt;em&gt;(legacy)&lt;/em&gt;, систему,
    которая с одной стороны по-прежнему нужна, а с другой - человек,
    который в ней&amp;nbsp;разбирался уже давно уволился.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="/tag/c/"&gt;С++&lt;/a&gt; и &lt;a href="/tag/thrift/"&gt;Thrift&lt;/a&gt;&lt;/strong&gt; - хоть одного из
    участников этой пары можно легко заменить на альтернативу, вместе
    они смотрятся наиболее органично: потенциально
    высокопроизводительная реализация бизнес-логики на С++ плюс
    проверенная в деле многими крупными и очень крупными проектами
    обертка для создания серверов и клиентов, легко общающихся из разных
    языков программирования (речь о Thrift, если не очевидно). Если в
    команде проекта есть гуру C++ - этот вариант Ваш, в противном случае
    не рекомендую, т.к. &lt;em&gt;очень&lt;/em&gt; легко накосячить.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Иногда внутренние сервисы возможно сделать совсем изолированными, то
есть без взаимодействия с другими компонентами системы. Но в большинстве
случаев это не так, зачастую для принятия решения им необходимы внешние
данные.&lt;/p&gt;
&lt;h2 id="baza-dannykh-i-keshirovanie"&gt;База данных и кэширование&lt;/h2&gt;
&lt;p&gt;По большому счету интерактивные сайты не особо сильно отличаются от
статичных с точки зрения организации хранения данных.&lt;/p&gt;
&lt;p&gt;Из особенностей хочу отметить более-менее четкое разграничение
&lt;strong&gt;стабильной&lt;/strong&gt; информации и &lt;strong&gt;свежей&lt;/strong&gt;, актуальной лишь короткое время.
Для социальной сети это могут быть, например, профили пользователей
(стабильная) и сообщения (свежая).&lt;/p&gt;
&lt;p&gt;В соответствии с этим стоит выбирать хранилище данных и политику
кэширования:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Стабильная информация, которая редко обновляется и в тысячи раз чаще
    читается, прекрасно поддается кэшированию и возможно даже прекрасно
    будет себя чувствовать в реляционной СУБД.&lt;/li&gt;
&lt;li&gt;Свежую информацию вероятно вообще важнее доставить в кратчайшие
    сроки получателю, а сохранять в персистентном виде можно вообще
    постфактум для архива, на маловероятный случай когда она повторно
    понадобится. Про кэширование лучше вообще забыть. Для этого самого
    "архива" часто используют нереляционные распределенные базы данных
    вроде &lt;a href="/tag/hbase/"&gt;HBase&lt;/a&gt;, &lt;a href="/tag/cassandra/"&gt;Cassandra&lt;/a&gt; или
    &lt;a href="/tag/riak/"&gt;Riak&lt;/a&gt;. А про оперативную доставку получателю поговорим
    в следующем разделе.&lt;/li&gt;
&lt;li&gt;Хранилища данных в памяти вроде &lt;a href="/tag/memcached/"&gt;memcached&lt;/a&gt; или
    &lt;a href="/tag/redis/"&gt;Redis&lt;/a&gt; с отключенной персистентностью можно
    использовать независимо для временного хранения каких-то побочных
    данных (восстановимых производных данных или просто чего-то не особо
    важного, вроде счетчиков пользователей онлайн).&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="potoki-soobshchenii"&gt;Потоки сообщений&lt;/h2&gt;
&lt;p&gt;Одной из ключевых задач интерактивного сайта является доставка сообщений
пользователем в реальном времени, причем их источник может быть как
внешний, так и внутренний, зачастую это просто другие пользователи.&lt;/p&gt;
&lt;p&gt;Часть системы, отвечающую за маршрутизацию таких сообщений, обычно
назвают &lt;strong&gt;брокером сообщений&lt;/strong&gt;&amp;ensp;&lt;em&gt;(message broker)&lt;/em&gt;. Для доставки
сообщений в браузер чаще всего используют &lt;strong&gt;интерфейс сериализованных
данных&lt;/strong&gt;, подробно обсуждавшийся в &lt;a href="https://www.insight-it.ru/interactive/2012/postoyannoe-soedinenie-mezhdu-brauzerom-i-serverom/"&gt;одной из предыдущих статей серии&lt;/a&gt;. Когда пользователь устанавливает соединение с этим интерфейсом, он, в
свою очередь, напрямую или через внутренний сервис регистрируется в
брокере сообщений для оперативного получения сообщений, предназначенных
соответствующему пользователю.&lt;/p&gt;
&lt;p&gt;Предлагаю рассмотреть типичные сценарии маршрутизации сообщений, они
довольно просты:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Конкретный получатель&lt;/strong&gt;, к сообщению (которое обычно никак не
    анализируется брокером) прикрепляется метка-идентификатор,
    обозначающий кому именно оно предназначено. Такое сообщение получит
    только процесс, зарегистрировавшийся с аналогичным идентификатором.
    Типичный пример использования - личные сообщения от пользователя к
    пользователю.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Группа получателей&lt;/strong&gt;, актуально для проектов, где пользователи
    взаимодействуют не на глобальном пространстве, а разбиты на части по
    какому-то признаку. Скажем это может быть какой-то B2B сервис и
    сообщения ходят только между сотрудниками одной компании-клиента.
    Обычно используется такие же метки, как и при конкретном получателе,
    только с одной из сторон (обычно принимающей) вместо конкретного
    идентификатора указывается какой-то паттерн, вроде &lt;code&gt;CompanyA.*&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Публичные сообщения&lt;/strong&gt; - получают все пользователи, метки не
    используются. Обычно это уведомления о глобальных для сайта событиях
    или публикации каких-то материалов.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Реализаций брокеров сообщений есть много разных, общий принцип работы у
всех примерно одинаковый и соответствует трем изложенным выше пунктам.
Для интернет-проектов очень рекомендую &lt;a href="/tag/rabbitmq/"&gt;RabbitMQ&lt;/a&gt;, в нем
эти стратегии маршрутизации называются &lt;em&gt;direct&lt;/em&gt;, &lt;em&gt;topic&lt;/em&gt; и &lt;em&gt;fanout&lt;/em&gt;
exchange, соответственно.&lt;/p&gt;
&lt;p&gt;Отправлять сообщения через брокер в большинстве случаев будут различные
внутренние сервисы в случае возникновения определенных событий &lt;em&gt;(читай:
получения ими определенных входящих сообщений и попадания в определенную
ветвь алгоритма их обработки)&lt;/em&gt;. Какую стратегию маршрутизации
использовать - тоже на их совести.&lt;/p&gt;
&lt;p&gt;К слову, внутренние сервисы также могут подписываться на получение части
сообщений из брокера, например для асинхронного создания "архива"
событий, отправки почтовых уведомлений или выполнения ресурсоемких задач
вроде конвертации медиа-файлов.&lt;/p&gt;
&lt;p&gt;При получении сообщения клиентская часть меняет соответствующим образом
текущую версию открытой страницы. От открытия дополнительного
всплывающего окна до просто смены цифры в количестве чего-нибудь.&lt;/p&gt;
&lt;p&gt;Будьте аккуратны с публичными сообщениями - их количество в единицу
времени может рости очень быстро с увеличением размеров аудитории.
Горизонтально масштабируемый брокер сообщений очень важен, если в Вашем
проекте в основном используются именно публичные сообщения.&lt;/p&gt;
&lt;h2 id="zakliuchenie"&gt;Заключение&lt;/h2&gt;
&lt;p&gt;Таким образом наша цепь замыкается - между браузерами любых
пользователей можно в "мягком" реальном времени пересылать любые
сообщения, пропуская их через бизнес-логику для регулирования данного
процесса, и, при необходимости, использовать постоянные и временные
хранилища данных.&lt;/p&gt;
&lt;p&gt;Как я уже упоминал&amp;nbsp;&lt;a href="https://www.insight-it.ru/interactive/2012/arkhitektura-interaktivnykh-sajjtov/"&gt;в первой статье серии&lt;/a&gt;, серверная часть у интерактивного сайта не так уж и кардинально отличается от любого другого - примерно те же компоненты, примерно так же работают и взаимодействуют. Разница в деталях.&lt;/p&gt;
&lt;p&gt;В следующей, заключительной, статье серии мы по второму кругу пройдемся
по ключевым моментам и попробуем рассмотреть наиболее перспективные
моменты для улучшений и оптимизации, хотя, как говорится, заранее
оптимизировать - плохая примета :)&lt;/p&gt;
&lt;div class="card green"&gt;
&lt;p&gt;&lt;div class="card-content white-text"&gt;
Эта статья - пятая в &lt;a class="green-text text-lighten-4" href="https://www.insight-it.ru/interactive/"&gt;серии про Интерактивные сайты&lt;/a&gt;, автор - &lt;a class="green-text text-lighten-4" href="https://www.insight-it.ru/goto/b03d9116/" rel="nofollow" target="_blank" title="http://blinkov.ru"&gt;Иван&amp;nbsp;Блинков&lt;/a&gt;, основано на личном опыте.
До встречи &lt;a class="green-text text-lighten-4" href="/feed/"&gt;на страницах Insight IT&lt;/a&gt;!
&lt;/div&gt;&lt;/p&gt;
&lt;/div&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Иван Блинков</dc:creator><pubDate>Mon, 04 Jun 2012 05:38:00 +0400</pubDate><guid>tag:www.insight-it.ru,2012-06-04:interactive/2012/servernaya-chast-interaktivnogo-sajjta-i-potoki-soobshhenijj/</guid><category>Akka</category><category>C++</category><category>Cassandra</category><category>Erlang</category><category>HBase</category><category>Memcached</category><category>OTP</category><category>RabbitMQ</category><category>Redis</category><category>Riak</category><category>Scala</category><category>Thrift</category></item><item><title>Вакансии: команда IT-звезд</title><link>https://www.insight-it.ru//vacancy/2012/vakansii-komanda-it-zvezd/</link><description>&lt;div class="card orange darken-3"&gt;
&lt;p&gt;&lt;div class="card-content white-text center"&gt;
&lt;strong&gt;Вакансии более не актуальны&lt;/strong&gt;
&lt;/div&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;Благодаря сайту &lt;strong class="trebuchet"&gt;Insight IT&lt;/strong&gt;, компания
RDM-Soft нашла ОТЛИЧНОГО тимлида! Теперь, &lt;a href="https://www.insight-it.ru/vacancy/2012/vakansiya-php-polkovodec/"&gt;тимлидер&lt;/a&gt; ищет в свою команду&amp;nbsp;единомышленников и просто IT-звезд.&lt;/p&gt;
&lt;!--more--&gt;
&lt;h2 id="o-kompanii"&gt;О компании&lt;/h2&gt;
&lt;p&gt;История компании началась в 2003 году. С этого момента выпущено много
проектов. Некоторыми из них Вы, возможно, так или иначе пользовались.
Сейчас запускается еще один проект:&amp;nbsp;&lt;strong&gt;SEO-биржа&lt;/strong&gt;. У Вас
есть прекрасная возможность оказаться у истоков будущего хита!&lt;/p&gt;
&lt;h2 id="kto-nuzhen"&gt;Кто нужен?&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Mr. Backend.&lt;/strong&gt; Он же программист.&amp;nbsp;&lt;em&gt;(вакансия закрыта)&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Мастер-ломастер.&lt;/strong&gt; Он же инженер по контролю качества, проще
    говоря тестер.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Dr. Frontend.&lt;/strong&gt; Он же фронтендщик. &lt;em&gt;(вакансия закрыта)&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="mr-backend"&gt;Mr. Backend&lt;/h3&gt;
&lt;h4&gt;Требования&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Отличные знания: &lt;strong&gt;PHP&lt;/strong&gt;, &lt;strong&gt;ООП&lt;/strong&gt;, &lt;strong&gt;SQL&lt;/strong&gt;, &lt;strong&gt;MVC&lt;/strong&gt;,
    &lt;strong&gt;ZendFramework&lt;/strong&gt; (либо альтернатив), &lt;strong&gt;Linux&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Опыт работы по специальности: от 3 лет.&lt;/li&gt;
&lt;li&gt;Опыт работы в команде.&lt;/li&gt;
&lt;li&gt;Желание развиваться и изучать новое.&lt;/li&gt;
&lt;li&gt;Отсутствие желания искать работу в ближайшие 3 года.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Задачи&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Разработка серверной части проекта.&amp;nbsp;Включает в себя :&lt;ul&gt;
&lt;li&gt;бухгалтерия;&lt;/li&gt;
&lt;li&gt;бизнес-логика;&lt;/li&gt;
&lt;li&gt;статистика;&lt;/li&gt;
&lt;li&gt;различные парсеры.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="master-lomaster-sqa"&gt;Мастер-Ломастер (SQA)&lt;/h3&gt;
&lt;h4&gt;Требования&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Хорошие знания: &lt;strong&gt;PHP&lt;/strong&gt;, &lt;strong&gt;SQL&lt;/strong&gt;, &lt;strong&gt;Linux&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Отличные знания принципов whitebox и blackbox тестирования.&lt;/li&gt;
&lt;li&gt;Опыт работы по специальности: от 2 лет.&lt;/li&gt;
&lt;li&gt;Опыт работы в команде.&lt;/li&gt;
&lt;li&gt;Желание развиваться и изучать новое.&lt;/li&gt;
&lt;li&gt;Отсутствие желания искать работу в ближайшие 3 года.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Задачи&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Написание юнит-тестов, автотестов.&lt;/li&gt;
&lt;li&gt;Тестирование:&lt;ul&gt;
&lt;li&gt;бекенда;&lt;/li&gt;
&lt;li&gt;фронтенда;&lt;/li&gt;
&lt;li&gt;бизнес-логики;&lt;/li&gt;
&lt;li&gt;производительности;&lt;/li&gt;
&lt;li&gt;безопасности.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;В общем, тоже очень много интересной работы.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="dr-frontend"&gt;Dr. Frontend&lt;/h3&gt;
&lt;h4&gt;Требования&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Понимание, как сделать интерфейс удобным и приятным для пользователя&lt;/li&gt;
&lt;li&gt;Отличные знания: &lt;strong&gt;HTML&lt;/strong&gt;, &lt;strong&gt;CSS&lt;/strong&gt;, &lt;strong&gt;JavaScript&lt;/strong&gt;&amp;nbsp;(jQuery, ExtJS
    или других распространенных библиотек)&lt;/li&gt;
&lt;li&gt;Опыт проектирования и реализации пользовательского интерфейса&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Задачи&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Прототипирование UI сервиса&lt;/li&gt;
&lt;li&gt;Реализация спроектированного UI&lt;/li&gt;
&lt;li&gt;Разработка расширений&amp;nbsp;для Firefox и Chrome.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="usloviia_1"&gt;Условия&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Удаленная работа.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;Работа в профессиональной команде.&lt;/li&gt;
&lt;li&gt;Полный рабочий день (5 дней в неделю по 8 часов).&lt;/li&gt;
&lt;li&gt;Карьерный и профессиональный рост.&lt;/li&gt;
&lt;li&gt;Прислушивание к Вашему мнению.&lt;/li&gt;
&lt;li&gt;Зарплата по результатам собеседования:&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Mr. Backend:&lt;/strong&gt;&amp;nbsp;от $1500 до $2000&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Мастер-Ломастер:&lt;/strong&gt;&amp;nbsp;от $700 до $1500&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Dr. Frontend:&lt;/strong&gt; от $1000 до $2000&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="card orange darken-3"&gt;
&lt;p&gt;&lt;div class="card-content white-text center"&gt;
&lt;strong&gt;Вакансии более не актуальны&lt;/strong&gt;
&lt;/div&gt;&lt;/p&gt;
&lt;/div&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Иван Блинков</dc:creator><pubDate>Fri, 04 May 2012 18:20:00 +0400</pubDate><guid>tag:www.insight-it.ru,2012-05-04:vacancy/2012/vakansii-komanda-it-zvezd/</guid><category>css</category><category>html</category><category>JavaScript</category><category>JQuery</category><category>PHP</category><category>RDM-soft</category><category>SQA</category><category>ZendFramework</category><category>вакансии</category></item><item><title>Архитектура Instagram</title><link>https://www.insight-it.ru//highload/2012/arkhitektura-instagram/</link><description>&lt;p&gt;&lt;a href="https://www.insight-it.ru/goto/a8e562b3/" rel="nofollow" target="_blank" title="https://instagram.com/"&gt;Instagram&lt;/a&gt; - всего лишь &lt;a href="/tag/ios/"&gt;iOS&lt;/a&gt;, а теперь
и &lt;a href="/tag/android/"&gt;Android&lt;/a&gt;, приложение для обмена фотографиями с
друзьями. Последнее время находится на слуху благодаря новости о покупке
проекта &lt;a href="/tag/facebook/"&gt;Facebook&lt;/a&gt;'ом за кругленькую сумму. Недавно один
из основателей проекта, Mike Krieger, выступил на конференции с докладом
о техническом аспекте проекта, который я и хотел бы вкратце пересказать.&lt;/p&gt;
&lt;!--more--&gt;
&lt;h2 id="statistika"&gt;Статистика&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Начало:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;1 сервер слабее Macbook Pro&lt;/li&gt;
&lt;li&gt;25к регистраций в первый день&lt;/li&gt;
&lt;li&gt;2 разработчика&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Сегодня:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;40+ миллионов пользователей&lt;/li&gt;
&lt;li&gt;100+ виртуальных серверов в EC2, в том числе:&lt;/li&gt;
&lt;li&gt;Проект куплен Facebook за &lt;em&gt;1 млрд. долл&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;1 миллион регистраций за 12 часов после запуска Android-версии&lt;/li&gt;
&lt;li&gt;5 разработчиков&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="tekhnologii"&gt;Технологии&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="/tag/ubuntu/"&gt;Ubuntu&lt;/a&gt; &lt;a href="/tag/linux/"&gt;Linux&lt;/a&gt; 11.04&lt;/strong&gt; - основная
операционная система&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="/tag/python/"&gt;Python&lt;/a&gt;&lt;/strong&gt; - основной язык программирования серверной части&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="/tag/django/"&gt;Django&lt;/a&gt;&lt;/strong&gt; - фреймворк&lt;/li&gt;
&lt;li&gt;&lt;a href="/tag/amazon/"&gt;&lt;strong&gt;Amazon&lt;/strong&gt;&lt;/a&gt;:&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="/tag/ec2/"&gt;EC2&lt;/a&gt;&lt;/strong&gt;&amp;nbsp;- хостинг&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="/tag/elb/"&gt;ELB&lt;/a&gt;&lt;/strong&gt;&amp;nbsp;- балансировка входящих HTTP-запросов&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="/tag/route53/"&gt;Route53&lt;/a&gt;&lt;/strong&gt; - DNS&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="/tag/s3/"&gt;S3&lt;/a&gt;&lt;/strong&gt; - хранение фотографий&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="/tag/cloudfront/"&gt;CloudFront&lt;/a&gt;&lt;/strong&gt; - &lt;a href="/tag/cdn/"&gt;CDN&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="/tag/nginx/"&gt;nginx&lt;/a&gt;&lt;/strong&gt; - второй уровень балансировки входящихHTTP-запросов&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="/tag/gunicorn/"&gt;gunicorn&lt;/a&gt;&lt;/strong&gt; - WSGI-сервер&lt;/li&gt;
&lt;li&gt;&lt;a href="/tag/haproxy/"&gt;&lt;strong&gt;HAProxy&lt;/strong&gt;&lt;/a&gt;&amp;nbsp;- балансировка нагрузки внутри системы&lt;/li&gt;
&lt;li&gt;&lt;a href="/tag/postgresql/"&gt;&lt;strong&gt;PostgreSQL&lt;/strong&gt;&lt;/a&gt; - основное хранилище данных&lt;/li&gt;
&lt;li&gt;&lt;a href="/tag/postgis/"&gt;&lt;strong&gt;postgis&lt;/strong&gt;&lt;/a&gt; - поддержка гео-запросов&lt;/li&gt;
&lt;li&gt;&lt;a href="/tag/pgfouine/"&gt;&lt;strong&gt;pgfouine&lt;/strong&gt;&lt;/a&gt; - отчеты на основе логов&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="/tag/pgbouncer/"&gt;pgbouncer&lt;/a&gt;&lt;/strong&gt; - создание пула соединений&lt;/li&gt;
&lt;li&gt;&lt;a href="/tag/redis/"&gt;&lt;strong&gt;Redis&lt;/strong&gt;&lt;/a&gt; - дополнительное хранилище данных&lt;/li&gt;
&lt;li&gt;&lt;a href="/tag/memcached/"&gt;&lt;strong&gt;Memcached&lt;/strong&gt;&lt;/a&gt; - кэширование&lt;/li&gt;
&lt;li&gt;&lt;a href="/tag/gearman/"&gt;&lt;strong&gt;Gearman&lt;/strong&gt;&lt;/a&gt; - очередь задач&lt;/li&gt;
&lt;li&gt;&lt;a href="/tag/solr/"&gt;&lt;strong&gt;Solr&lt;/strong&gt;&lt;/a&gt; - гео-поиск&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="/tag/munin/"&gt;munin&lt;/a&gt;&lt;/strong&gt;, &lt;a href="/tag/statsd/"&gt;&lt;strong&gt;statsd&lt;/strong&gt;&lt;/a&gt;, &lt;a href="/tag/pingdom/"&gt;&lt;strong&gt;pingdom&lt;/strong&gt;&lt;/a&gt; - мониторинг&lt;/li&gt;
&lt;li&gt;&lt;a href="/tag/fabric/"&gt;&lt;strong&gt;Fabric&lt;/strong&gt;&lt;/a&gt; - управление кластером&lt;/li&gt;
&lt;li&gt;&lt;a href="/tag/xfs/"&gt;&lt;strong&gt;xfs&lt;/strong&gt;&lt;/a&gt; - файловая система&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="filosofiia"&gt;Философия&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Простота&lt;/li&gt;
&lt;li&gt;Минимизация операционных издержек&lt;/li&gt;
&lt;li&gt;Использование подходящих инструментов&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="istoriia"&gt;История&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Забыли сделать &lt;strong&gt;favicon.ico&lt;/strong&gt; до запуска - в первый же день логи
пестрили ошибками 404&lt;/li&gt;
&lt;li&gt;Для хранения данных использовали просто &lt;strong&gt;Django &lt;a href="/tag/orm/"&gt;ORM&lt;/a&gt;&lt;/strong&gt; и
&lt;strong&gt;PostgreSQL&lt;/strong&gt; (из-за postgis)&lt;/li&gt;
&lt;li&gt;Начали с одного слабого сервера, после успешного запуска решили
переехать на &lt;strong&gt;EC2&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Довольно быстро пришлось вынести &lt;a href="/tag/subd/"&gt;СУБД&lt;/a&gt; на отдельный сервер
(виртуальный, естественно)&lt;/li&gt;
&lt;li&gt;Количество фотографий продолжало расти и расти, даже самый большой
инстанс &lt;strong&gt;EC2&lt;/strong&gt; не справлялся&lt;/li&gt;
&lt;li&gt;Решили вертикально разделить данные на несколько баз, с использованием
механизма &lt;strong&gt;routers&lt;/strong&gt; из ORM, параллельно избавившись от внешних ключей&lt;/li&gt;
&lt;li&gt;Через несколько месяцев суммарный размер базы данных перевалил за 60Гб и
перестало справляться и это решение&lt;/li&gt;
&lt;li&gt;Следующим шагом стало горизонтальное разбиение данных &lt;em&gt;(sharding)&lt;/em&gt;:&lt;/li&gt;
&lt;li&gt;Создали несколько тысяч логических баз данных.&lt;/li&gt;
&lt;li&gt;Распределили их по существенно меньшему количеству физических серверов (читай: виртуальных машин).&lt;/li&gt;
&lt;li&gt;Написали свой механизм определения где искать какую базу данных, с поддержкой миграции (вероятно тоже на основе routers).&lt;/li&gt;
&lt;li&gt;По последним данным под &lt;strong&gt;PostgreSQL&lt;/strong&gt; используется 12+12 виртуальных
машин с максимальной оперативной памятью (68.4Гб), а также сетевые диски
EBS, объединенные в программный RAID посредством mdadm. Это необходимо,
чтобы весь массив данных помещался в памяти, EBS не в состоянии
обеспечить достаточную производительность.&lt;/li&gt;
&lt;li&gt;С некоторыми задачами лучше справляется &lt;strong&gt;Redis&lt;/strong&gt;:&lt;/li&gt;
&lt;li&gt;Для каждого пользователя в Redis есть список идентификаторов новых
фотографий от других пользователей, на которых он подписан.&lt;/li&gt;
&lt;li&gt;При отображении потока новых для пользователя фотографий делается
выборка части такого списка, после чего посредством multiget достается
подробная о них информация из memcached.&lt;/li&gt;
&lt;li&gt;Пробовали возложить на него задачу хранения списков подписчиков, но в
итоге вернулись к решению на &lt;strong&gt;PostgreSQL&lt;/strong&gt; с небольшим кэшированием.&lt;/li&gt;
&lt;li&gt;В Redis также хранится информация о сессиях.&lt;/li&gt;
&lt;li&gt;Несколько фактов о Redis:&lt;ul&gt;
&lt;li&gt;Так как все находится в памяти - очень быстрые операции записи и работы с множествами.&lt;/li&gt;
&lt;li&gt;Является не заменой, а дополнением к основному хранилищу данных.&lt;/li&gt;
&lt;li&gt;Redis хорош для структур данных, которые относительно ограничены.&lt;/li&gt;
&lt;li&gt;Отлично подходит для кэширования комплексных структур данных, где нужно большее, чем просто получить значение по ключу (например - счетчики, подмножества, проверка вхождения в множества).&lt;/li&gt;
&lt;li&gt;Механизм репликации (посредством slaveof) позволяет легко
масштабировать операции чтения.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Пользователи синхронно загружают фотографии на медиа-сервер с
(опциональными) заголовком и месте на карте, все остальное происходит
асинхронно посредством очередей, например:&lt;ul&gt;
&lt;li&gt;Сохраняются гео-метки, обновляется &lt;strong&gt;Solr&lt;/strong&gt; (который впоследствии заменил postgis).&lt;/li&gt;
&lt;li&gt;Идентификатор нового фото добавляется в обсуждавшиеся выше списки для всех подписчиков автора.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Поначалу использовали &lt;a href="/tag/apache/"&gt;Apache&lt;/a&gt; + &lt;code&gt;mod_wsgi&lt;/code&gt; для запуска
&lt;strong&gt;Django&lt;/strong&gt;, впоследствии перешли к gunicorn из-за меньшего потребления
ресурсов и простоты настройки.&lt;/li&gt;
&lt;li&gt;С недавних пор начали использовать&amp;nbsp;&lt;strong&gt;Amazon ELB&lt;/strong&gt;&amp;nbsp;вместо &lt;strong&gt;DNS
round-robin&lt;/strong&gt; для первичной балансировки входяших HTTP-запросов, что
позволило:&lt;/li&gt;
&lt;li&gt;избежать необходимости дешифровки &lt;a href="/tag/ssl/"&gt;&lt;strong&gt;SSL&lt;/strong&gt;&lt;/a&gt; посредством nginx;&lt;/li&gt;
&lt;li&gt;ускорить исключение из балансировки проблемных серверов.&lt;/li&gt;
&lt;li&gt;Благодаря использованию &lt;strong&gt;xfs&lt;/strong&gt; есть возможность "замораживать" и
"размораживать" дисковые массивы при резервном копировании.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="podvodim-itogi"&gt;Подводим итоги&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Многие проблемы с масштабируемостью - результат банальных
    человеческих ошибок.&lt;/li&gt;
&lt;li&gt;Масштабирование = замена всех деталей в машине на скорости 150 км/ч.&lt;/li&gt;
&lt;li&gt;Заранее сложно узнать как в основном будут обращаться к данным, без
    реального использования.&lt;/li&gt;
&lt;li&gt;В первую очередь попытайтесь адаптировать известные Вам технологии и
    инструменты для создания простого и понятного решения, прежде чем
    бросаться на поиски чего-то нетривиального.&lt;/li&gt;
&lt;li&gt;Дополните свое основное хранилище более гибким компонентом, вроде
    Redis.&lt;/li&gt;
&lt;li&gt;Постарайтесь не использовать два инструмента для решения одной и той
    же задачи.&lt;/li&gt;
&lt;li&gt;Оставайтесь гибкими и ловкими = напоминайте себе о том, что на самом
    деле имеет значение.&lt;/li&gt;
&lt;li&gt;Разрабатывайте решения, к которым не придется постоянно возвращаться
    из-за их сбоев.&lt;/li&gt;
&lt;li&gt;Активное юнит- и функциональное тестирование стоят потраченного на
    них времени.&lt;/li&gt;
&lt;li&gt;DRY: не делайте одну и ту же работу несколько раз.&lt;/li&gt;
&lt;li&gt;Слабая связанность посредством уведомлений или сигналов позволяет
    легко менять структуру проекта.&lt;/li&gt;
&lt;li&gt;Дисковый ввод-вывод часто оказывается узким местом, особенно на EC2.&lt;/li&gt;
&lt;li&gt;Спускаться до C нужно только при необходимости, большую часть работы
    лучше делать в Python.&lt;/li&gt;
&lt;li&gt;Короткий цикл разработки - залог быстрого развития.&lt;/li&gt;
&lt;li&gt;Частые совместные рассмотрения кода нужны, чтобы все были в курсе
    происходящего.&lt;/li&gt;
&lt;li&gt;Не изобретайте велосипед.&lt;/li&gt;
&lt;li&gt;Окружите себя с толковыми &lt;a href="https://www.insight-it.ru/consulting/"&gt;консультантами&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Культура открытости вокруг разработки.&lt;/li&gt;
&lt;li&gt;Делитесь с &lt;a href="/tag/opensource/"&gt;opensource&lt;/a&gt; сообществом.&lt;/li&gt;
&lt;li&gt;Фокусируйтесь на том, что вы делаете лучше всего.&lt;/li&gt;
&lt;li&gt;Вашим пользователям абсолютно без разницы, написали ли Вы
    собственную СУБД или нет.&lt;/li&gt;
&lt;li&gt;Не переоптимизируйте и не предполагайте заранее как сайт будет
    расти.&lt;/li&gt;
&lt;li&gt;Не рассчитывайте, что "кто-то еще присоединится к команде и
    разберется с этим".&lt;/li&gt;
&lt;li&gt;Для социальных стартапов очень мало, или даже совсем нет, нерешимых
    вопросов, связанных с масштабируемостью.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="istochnik-informatsii"&gt;Источник информации&lt;/h2&gt;
&lt;p&gt;Упоминавшаяся во вступлении неприлично длинная презентация из 185
слайдов:&lt;/p&gt;
&lt;iframe data-aspect-ratio="" data-auto-height="true" frameborder="0" height="600" id="doc_73113" scrolling="no" src="//www.scribd.com/embeds/89025069/content?start_page=1&amp;amp;view_mode=scroll" width="100%"&gt;&lt;/iframe&gt;
&lt;p&gt;На видео, к сожалению, это выступление не записывалось.&lt;/p&gt;
&lt;p&gt;Часть информации взята из &lt;a href="https://www.insight-it.ru/goto/ce2d4e38/" rel="nofollow" target="_blank" title="http://instagram-engineering.tumblr.com/"&gt;технического блога Instagram&lt;/a&gt;.&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Иван Блинков</dc:creator><pubDate>Fri, 13 Apr 2012 20:11:00 +0400</pubDate><guid>tag:www.insight-it.ru,2012-04-13:highload/2012/arkhitektura-instagram/</guid><category>Amazon</category><category>Android</category><category>CloudFront</category><category>django</category><category>EC2</category><category>ELB</category><category>Fabric</category><category>Facebook</category><category>gearman</category><category>gunicorn</category><category>HAProxy</category><category>Intagram</category><category>iOS</category><category>Linux</category><category>Memcached</category><category>Munin</category><category>nginx</category><category>ORM</category><category>pgbouncer</category><category>pgFouine</category><category>Pingdom</category><category>postgis</category><category>PostgreSQL</category><category>Python</category><category>Redis</category><category>Route53</category><category>S3</category><category>Solr</category><category>statsd</category><category>Ubuntu</category><category>WSGI</category><category>xfs</category><category>Архитектура Instagram</category></item><item><title>Повторное использование шаблонов</title><link>https://www.insight-it.ru//interactive/2012/povtornoe-ispolzovanie-shablonov/</link><description>&lt;blockquote&gt;
&lt;p&gt;Лень - двигатель прогресса&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Сегодня мы рассмотрим способ, позволяющий немного упростить себе жизнь
при создании &lt;a href="https://www.insight-it.ru/interactive/"&gt;интерактивного сайта&lt;/a&gt;&amp;nbsp;путем повторного использования шаблонов. Визуально результат будет примерно таким же, как при дублировании бизнес-логики в браузере, но ценой существенно меньших
трудозатрат на разработку JavaScript-клиента, да и на серверной части
тоже. Хотите узнать как это провернуть?&lt;/p&gt;
&lt;!--more--&gt;
&lt;p&gt;Небольшая ремарка, чтобы не было недопонимания из-за терминологии:&lt;/p&gt;
&lt;div class="card blue lighten-4"&gt;
&lt;div class="card-content"&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Шаблон&lt;/strong&gt;&amp;ensp;&lt;em&gt;(template)&lt;/em&gt; : HTML-документ с расширенным набором тегов,
    которые впоследствии используются для подстановки динамических
    данных.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Шаблонизатор&lt;/strong&gt;&amp;ensp;&lt;em&gt;(templating engine)&lt;/em&gt; : библиотека, позволяющая на
    основе &lt;em&gt;шаблона&lt;/em&gt; (использующего определенный синтаксис
    дополнительных тегов) и &lt;em&gt;динамических данных&lt;/em&gt; получить итоговый
    HTML-документ, пригодный для отображения в браузере.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Рендеринг&lt;/strong&gt;&amp;ensp;&lt;em&gt;(rendering)&lt;/em&gt; : в данном контексте &amp;mdash; процесс, которым занимается шаблонизатор.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 id="obshchii-printsip"&gt;Общий принцип&lt;/h2&gt;
&lt;p&gt;Чтобы сразу в голове сложилась нужная картина, начнем с дополненной
схемы из статьи про &lt;a href="https://www.insight-it.ru/interactive/2012/arkhitektura-interaktivnykh-sajjtov/"&gt;архитектуру интерактивных сайтов&lt;/a&gt;:&lt;/p&gt;
&lt;p&gt;&lt;img alt="Повторное использование шаблонов" class="responsive-img" src="https://www.insight-it.ru/images/templates.jpeg" title="Повторное использование шаблонов"/&gt;&lt;/p&gt;
&lt;p&gt;Если вкратце, то стандартный интерфейс внутренних сервисов, скрывающихся
за блоком &lt;strong&gt;"Бизнес-логика"&lt;/strong&gt;, можно реализовать таким образом, чтобы он
возвращал все необходимые данные для рендеринга шаблона плюс его имя.
База &lt;strong&gt;шаблонов&lt;/strong&gt; у всех общая, у каждого уникальное имя, каждый сервер
интерфейсов (обоих) держит по копии всех шаблонов в памяти.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;HTML интерфейс&lt;/strong&gt; просто разбирает HTTP-запросы, отправляет на его
основе сообщение(ия) внутренним сервисам, получает в ответ имя шаблона и
данные для его заполнения, с помощью &lt;strong&gt;шаблонизатора&lt;/strong&gt; рендерит итоговый
&lt;a href="/tag/html/"&gt;HTML&lt;/a&gt; и отдает браузеру или роботу.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Интерфейс сериализованных данных&lt;/strong&gt;&amp;ensp;&lt;em&gt;(если он, как и обсуждалось ранее,
работает через &lt;a href="https://www.insight-it.ru/interactive/2012/postoyannoe-soedinenie-mezhdu-brauzerom-i-serverom/"&gt;постоянное соединение с браузером&lt;/a&gt;)&lt;/em&gt;&amp;nbsp;каждому
подключившемуся клиенту первым делом отправляет
&lt;a href="/tag/json/"&gt;JSON&lt;/a&gt;-объект с шаблонами, по крайней мере если их не особо
много, иначе лучше "по запросу". При действии пользователя
JavaScript-клиент отправляет сообщение с информацией, на его основе
интерфейс сериализованных данных передает то же самое (а может и как-то
модифицированное) сообщение внутреннему сервису, также получает в ответ
имя шаблона и данные и перенаправляет их клиенту (возможно
сконвертировав в другой формат). Клиенту остается передать их своему
шаблонизатору и заменить результатом его работы какую-то часть уже
имеющегося в окне браузера HTML-документа.&lt;/p&gt;
&lt;h2 id="rendering"&gt;Рендеринг&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Шаблонизаторов&lt;/strong&gt; сейчас доступно огромное количество под любую
платформу, с разной производительностью и возможностями, но чтобы
воплотить эту стратегию в жизнь подойдут далеко не все. Два основных
требования:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Отсутствие внешних вызовов при рендеринге&lt;/em&gt;, то есть на входе только
    данные, если используются какие-то фильтры или что-то такое - они
    должны быть частью шаблонизатора.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Шаблонизатор должен иметь реализацию на JavaScript&lt;/em&gt;, так как будет
    исполняться в том числе и в браузере.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Да, многофункциональные шаблонизаторы вроде &lt;a href="/tag/jinja2/"&gt;Jinja2&lt;/a&gt; - это
очень удобно, но конкретно в данном случае богатый ассортимент
возможностей не уместен. Наиболее известный &lt;em&gt;кроссплатформенный&lt;/em&gt;
шаблонизатор, не обремененный ничем лишним, называется
&lt;strong&gt;&lt;a href="https://www.insight-it.ru/goto/89b84f30/" rel="nofollow" target="_blank" title="http://mustache.github.io/"&gt;mustache&lt;/a&gt;&lt;/strong&gt;. С его использованием иногда
получаются довольно замысловатые конструкции, но зато он отлично
подходит под этот сценарий использования и прост как три копейки,
изучить можно за 5 минут, &lt;em&gt;рекомендую&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;В этой схеме напрашивается использование &lt;a href="/tag/node-js/"&gt;node.js&lt;/a&gt; для
реализации &lt;strong&gt;HTML-интерфейса&lt;/strong&gt;, что откроет доступ к многочисленным
шаблонизаторам, &lt;a href="https://www.insight-it.ru/goto/261edaf6/" rel="nofollow" target="_blank" title="https://github.com/joyent/node/wiki/modules#wiki-templating"&gt;реализованным исключительно на JavaScript&lt;/a&gt;.
Тем более кроме рендеринга шаблонов эта часть проекта практически ничего
и не делает. В качестве бонуса требование про отсутствие внешних вызовов
станет не таким строгим, да и в целом, если минималистичное решение
вроде &lt;a href="/tag/mustache/"&gt;mustache&lt;/a&gt;&amp;nbsp;по каким-то идеологическим соображениям
не устраивает - любой написанный для node.js шаблонизатор наверняка
станет отличным выходом.&lt;/p&gt;
&lt;h2 id="struktura-shablonov"&gt;Структура шаблонов&lt;/h2&gt;
&lt;p&gt;При рендеринге на клиентской стороне &lt;strong&gt;обычно&lt;/strong&gt; нужно заменять лишь
содержимое определенного блока, где располагается основной контент
сайта. Изменения в в других частях сайта нужны существенно реже,
соответственно стоит вынести их в отдельные шаблоны.&lt;/p&gt;
&lt;p&gt;Таким образом большинство шаблонов, соответствующих страницам сайта,
представляют собой содержимое одного блока. Отдельные шаблоны,
актуальные для всего сайта, создаются для:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Блока &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt; документа&lt;/li&gt;
&lt;li&gt;Видимой "шапки" сайта&lt;/li&gt;
&lt;li&gt;Сайдбара(ов), если они не сильно зависят от основного контентом
    страниц&lt;/li&gt;
&lt;li&gt;Видимого "подвала" сайта плюс тегов для подключения
    &lt;a href="/tag/javascript/"&gt;JavaScript&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;HTML-интерфейс&lt;/strong&gt; при чтении их из файловой системы "склеивает" их в
полные шаблоны для каждой страницы, просто конкатенацией или с
использованием механизмов шаблонизатора. &lt;strong&gt;Интерфейс сериализованных
данных&lt;/strong&gt; "заворачивает" шаблоны страниц в JSON (или другой используемый
формат) прямо в исходном виде для вставки в блок с основным контентом.
Из "общесайтовых"&amp;nbsp;шаблонов браузерному клиенту вероятно могут
понадобиться только сайдбар(ы), и то не всегда.&lt;/p&gt;
&lt;p&gt;Изменения в остальных частях сайта лучше все же отдать на совесть
&lt;em&gt;представлений&lt;/em&gt; на основе клиентского фреймворка. В первую очередь это
касается изменения &lt;code&gt;&amp;lt;title&amp;gt;&lt;/code&gt; и других мета-тегов.&lt;/p&gt;
&lt;h2 id="primechaniia"&gt;Примечания&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;При использовании минималистичного шаблонизатора без внешних вызовов
    будьте морально готовы передавать ему "многоуровневые" объекты для
    вставки в шаблон. Например, если говорить о постраничной навигации,
    там, где в продвинутом шаблонизаторе было бы что-то вроде &lt;code&gt;{% pagination(current_page, total_pages) %}&lt;/code&gt;,&amp;nbsp;может понадобится не
    только написать саму верстку (что, в целом, хорошая практика), а еще
    и передать информацию о точном списке страниц, какая именно из них
    активная, где пропуски и пр.&lt;/li&gt;
&lt;li&gt;Стоит обращать внимание на производительность используемого
    шаблонизатора. Например, под одну из платформ "официальная"
    реализация &lt;strong&gt;mustache&lt;/strong&gt;, как оказалось,&amp;nbsp;проигрывает сторонней с
    отрывом в 2 порядка.&lt;/li&gt;
&lt;li&gt;Хоть при таком подходе добиться одинакового внешнего вида страниц
    при рендеринге серверной и клиентской частью достаточно легко,
    следить за их соответствием все же стоит - какие-то детали можно и
    упустить.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="zakliuchenie"&gt;Заключение&lt;/h2&gt;
&lt;p&gt;Как я уже намекал в конце &lt;a href="https://www.insight-it.ru/interactive/2012/postoyannoe-soedinenie-mezhdu-brauzerom-i-serverom/"&gt;предыдущего материала&lt;/a&gt;,
обсуждавшийся в этой статье подход не совсем &lt;em&gt;"идеологически
правильный"&lt;/em&gt;, по крайней мере с точки зрения используемого &lt;em&gt;клиентского
фреймворка&lt;/em&gt;. &lt;strong&gt;Модели&lt;/strong&gt;,&amp;nbsp;вероятно,&amp;nbsp;будут использоваться для хранения
библиотеки шаблонов и данных для их рендеринга, а не для объектов
предметной области проекта. &lt;strong&gt;Представления&lt;/strong&gt; будут отвечать лишь за
рендеринг шаблонов и синхронизацию второстепенных элементов интерфейса.
Если Вы все же пойдете по этому пути, хочется, чтобы Вы сделали это
осознанно. Альтернативный сценарий создания полноценного
JavaScript-приложения для работы в браузере для некоторых проектов
по-прежнему может оказаться более предпочтительным.&lt;/p&gt;
&lt;p&gt;В&amp;nbsp;следующей&amp;nbsp;статье мы наконец-то перейдем к более привычной для меня
&lt;em&gt;серверной части&lt;/em&gt; интерактивных сайтов, там тоже есть много интересных
моментов, которые стоит обсудить.&lt;/p&gt;
&lt;div class="card green"&gt;
&lt;p&gt;&lt;div class="card-content white-text"&gt;
Эта статья - четвертая в &lt;a class="green-text text-lighten-4" href="https://www.insight-it.ru/interactive/"&gt;серии про Интерактивные сайты&lt;/a&gt;, автор - &lt;a class="green-text text-lighten-4" href="https://www.insight-it.ru/goto/b03d9116/" rel="nofollow" target="_blank" title="http://blinkov.ru"&gt;Иван&amp;nbsp;Блинков&lt;/a&gt;, основано на личном опыте.
До встречи &lt;a class="green-text text-lighten-4" href="/feed/"&gt;на страницах Insight IT&lt;/a&gt;!
&lt;/div&gt;&lt;/p&gt;
&lt;/div&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Иван Блинков</dc:creator><pubDate>Fri, 13 Apr 2012 08:00:00 +0400</pubDate><guid>tag:www.insight-it.ru,2012-04-13:interactive/2012/povtornoe-ispolzovanie-shablonov/</guid><category>html</category><category>JSON</category><category>mustache</category><category>node.js</category><category>rendering</category><category>template</category><category>template engine</category><category>интерфейс</category><category>шаблон</category><category>шаблонизация</category></item><item><title>Вакансия закрыта: PHP-полководец</title><link>https://www.insight-it.ru//vacancy/2012/vakansiya-php-polkovodec/</link><description>&lt;div class="card orange darken-3"&gt;
&lt;p&gt;&lt;div class="card-content white-text center"&gt;
&lt;strong&gt;Вакансия более не актуальна&lt;/strong&gt;
&lt;/div&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;Компания &lt;strong&gt;RDM-Soft&lt;/strong&gt; приглашает на работу
полководца команды &lt;a href="/tag/php/"&gt;PHP&lt;/a&gt;-разработчиков &lt;em&gt;(тимлидера)&lt;/em&gt;.&lt;/p&gt;
&lt;div&gt;
&lt;!--more--&gt;
&lt;/div&gt;
&lt;h2 id="o-kompanii"&gt;О компании&lt;/h2&gt;
&lt;p&gt;История компании началась в 2003 году. С этого момента выпущено много
проектов. Некоторыми из них Вы, возможно, так или иначе пользовались.
Сейчас запускается еще один проект: &lt;strong&gt;SEO-биржа&lt;/strong&gt;. У Вас есть прекрасная возможность оказаться у истоков будущего хита в роли лидера команды разработчиков!&lt;/p&gt;
&lt;h2 id="obiazannosti"&gt;Обязанности&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Руководство группой разработчиков.&lt;/li&gt;
&lt;li&gt;Ставить задачи команде и проверять их выполнение.&lt;/li&gt;
&lt;li&gt;Бить по рукам за некачественный код, показывать как правильно
    писать.&lt;/li&gt;
&lt;li&gt;Хвалить, раздавать пряники.&lt;/li&gt;
&lt;li&gt;Иногда писать самому.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="trebovaniia"&gt;Требования&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Опыт руководства командой разработчиков.&lt;/li&gt;
&lt;li&gt;Понимание аспектов мотивации и демотивации программистов.&lt;/li&gt;
&lt;li&gt;Опыт программирования от 3-х лет.&lt;/li&gt;
&lt;li&gt;Отличное знание &lt;strong&gt;PHP5&lt;/strong&gt; &amp;amp;&amp;amp; &lt;strong&gt;MVC&lt;/strong&gt; &amp;amp;&amp;amp; &lt;strong&gt;SQL&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Базовые знания &lt;strong&gt;JavaScript&lt;/strong&gt; &amp;amp;&amp;amp; &lt;strong&gt;HTML&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Базовые знания &lt;strong&gt;unix shell&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Опыт работы с &lt;strong&gt;svn&lt;/strong&gt; || &lt;strong&gt;git&lt;/strong&gt; || &lt;strong&gt;mercurial.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Опыт работы с &lt;strong&gt;redmine&lt;/strong&gt; || &lt;strong&gt;mantis&lt;/strong&gt; || &lt;strong&gt;jira&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="pliusom-budet"&gt;Плюсом будет&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Навыки работы с NoSQL: &lt;strong&gt;MongoDB&lt;/strong&gt; || &lt;strong&gt;Redis&lt;/strong&gt; || &lt;strong&gt;Memcached&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Опыт разработки в области HA и HL.&lt;/li&gt;
&lt;li&gt;Опыт применения lean- и agile- методологий в разработке.&lt;/li&gt;
&lt;li&gt;Знания таких слов как: ДеМарко, КанБан, Таичи Оно, SCRUM.&lt;/li&gt;
&lt;li&gt;Понимание цикла Деминга и SDLС в принципе.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="usloviia"&gt;Условия&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Удаленная работа.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Гибкий график работы.&lt;/li&gt;
&lt;li&gt;Работа в слаженной профессиональной команде.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Зарплата от \$2500 до \$3000 в месяц.&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="vakansiia-zakryta"&gt;Вакансия закрыта&lt;/h2&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Иван Блинков</dc:creator><pubDate>Thu, 12 Apr 2012 20:52:00 +0400</pubDate><guid>tag:www.insight-it.ru,2012-04-12:vacancy/2012/vakansiya-php-polkovodec/</guid><category>PHP</category><category>teamlead</category><category>вакансии</category><category>менеджер</category><category>разработчик</category></item><item><title>Постоянное соединение между браузером и сервером</title><link>https://www.insight-it.ru//interactive/2012/postoyannoe-soedinenie-mezhdu-brauzerom-i-serverom/</link><description>&lt;p&gt;В статье про &lt;a href="https://www.insight-it.ru/interactive/2012/klientskaya-chast-interaktivnogo-sajjta/"&gt;клиентскую часть интерактивного интернет-проекта&lt;/a&gt; мы подошли к вопросу возможности использования двухстороннего
постоянного соединения между сайтом и JavaScript-клиентом для
синхронизации их состояний. Такое соединение представляет собой канал
для обмена сообщениями &lt;em&gt;в реальном времени&lt;/em&gt; между браузером и серверным
процессом, причем каждая сторона может быть инициатором отправки
сообщения и имеет некую логику реакции на получаемые сообщения.&lt;/p&gt;
&lt;p&gt;Сегодня мы рассмотрим основные варианты реализации этого принципа и как
он сочетается с обсуждавшимися в предыдущих статьях
&lt;a href="https://www.insight-it.ru/interactive/"&gt;серии&lt;/a&gt; темами.&lt;/p&gt;
&lt;!--more--&gt;
&lt;h2 id="transport"&gt;Транспорт&lt;/h2&gt;
&lt;p&gt;Так как одной из сторон постоянного соединения является браузер, вопрос
кроссбраузерности при его реализации стоит не менее остро, чем,
например, при верстке. В 2001 году, когда появился на свет самый часто
вспоминаемый недобрым словом браузер в мире, о подобных технологиях
постоянного соединения между браузером и сервером практически никто не
задумывался даже отдаленно.&lt;/p&gt;
&lt;p&gt;Существуют несколько протоколов и связанных с ними технологий, которые
позволяют реализовать постоянное с точки зрения приложения соединение
между браузером и сервером, обычно их называют &lt;strong&gt;транспортами&lt;/strong&gt;. Каждый
из них обладает разной производительностью, особенностями реализации и
нагрузкой на серверную часть. Возможно не полный их список c краткими
пояснениями:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://www.insight-it.ru/goto/5ddd244b/" rel="nofollow" target="_blank" title="http://ru.wikipedia.org/wiki/WebSocket"&gt;WebSocket&lt;/a&gt;:&lt;/strong&gt;&amp;nbsp;пожалуй,
    самый эффективный с точки зрения производительности и нагрузки на
    сервер транспорт. Протокол относительно новый, появился в рамках
    работы над &lt;a href="/tag/html5/"&gt;HTML5&lt;/a&gt;. Доступен только в очень свежих
    браузерах, имеет несколько более-менее стандартных версий.
    Используется одно соединение для обоих направлений обмена
    сообщениями.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://www.insight-it.ru/goto/4587ee12/" rel="nofollow" target="_blank" title="http://dev.w3.org/html5/eventsource/"&gt;EventSource&lt;/a&gt;:&lt;/strong&gt;&amp;nbsp;появился
    примерно в то же время, что и WebSocket, но по задумке должен
    использоваться для получения односторонних уведомлений от сервера. В
    совокупности с простыми AJAX запросами для отправки событий из
    браузера может использоваться для двустороннего общения. Но так как
    он доступен примерно в тех же версиях браузеров, что и WebSocket, со
    сценариями, когда он оказывался бы более предпочтительным, я не
    сталкивался. Технически очень похож на следующий транспорт.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.insight-it.ru/goto/1a0e9c02/" rel="nofollow" target="_blank" title="http://en.wikipedia.org/wiki/Push_technology#HTTP_server_push"&gt;&lt;strong&gt;AJAX Multipart&lt;/strong&gt;&lt;/a&gt; aka &lt;strong&gt;&lt;a href="https://www.insight-it.ru/goto/1a0e9c02/" rel="nofollow" target="_blank" title="http://en.wikipedia.org/wiki/Push_technology#HTTP_server_push"&gt;HTTP Streaming&lt;/a&gt;:&lt;/strong&gt;&amp;nbsp;после
    получения HTTP-запроса от клиента сервер не "отпускает" его и по
    мере поступления отправляет в него свои сообщения. Для отправки
    сообщений из браузера при необходимости создается&amp;nbsp;второе соединение.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://www.insight-it.ru/goto/dcd446e1/" rel="nofollow" target="_blank" title="http://en.wikipedia.org/wiki/Push_technology#Long_polling"&gt;AJAX/HTTP Polling&lt;/a&gt;:&lt;/strong&gt;&amp;nbsp;в
    отличии от предыдущего транспорта, сервер закрывает HTTP-соединение
    после каждого отправленного в него сообщения или по прошествии
    определенного таймаута (обычно порядка 20-40 секунд). А браузер
    сразу же после получения сообщения открывает новое соединение, таким
    образом у сервера по-прежнему практически всегда есть соединение,
    куда можно отправить сообщения. Хоть по нагрузке на сервер этот
    вариант самый тяжелый, поддерживают его практически все браузеры.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://www.insight-it.ru/goto/9344995a/" rel="nofollow" target="_blank" title="https://github.com/gimite/web-socket-js"&gt;Adobe Flash&lt;/a&gt;:&lt;/strong&gt;&amp;nbsp;эта
    платформа может эмулировать поддержку WebSocket при определенном
    стечении обстоятельств (удачная комбинация Flash-плеера и браузера).
    Немного нетривиальна в настройке из-за своих особенностей.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;По поводу поддержки каждого из них различными браузерами было бы неплохо
составить табличку, но на самом деле нюансов там много и многое зависит
не только от версии браузера, но и от других обстоятельств, вроде
наличия и типа прокси, использования трюков с iframe, наличия
Flash-плеера и т.п.&lt;/p&gt;
&lt;p&gt;Все вышеизложенные транспорты в конечном итоге основываются на протоколе
&lt;a href="/tag/http/"&gt;HTTP&lt;/a&gt;. Большинство из современных браузеров ограничивают
количество одновременных HTTP-соединений с доменом &lt;strong&gt;до двух&lt;/strong&gt;, что как
раз достаточно даже для менее эффективных вариантов.&lt;/p&gt;
&lt;p&gt;В любом случае работать напрямую с транспортами не обязательно, благо
существует большое количество библиотек и сервисов, позволяющих от них
абстрагироваться, к ним и переходим.&lt;/p&gt;
&lt;h2 id="abstraktsiia"&gt;Абстракция&lt;/h2&gt;
&lt;p&gt;По сути такие библиотеки состоят из двух частей: клиентской на
&lt;a href="/tag/javascript/"&gt;JavaScript&lt;/a&gt; и серверной для одной или нескольких
платформ. Клиент определяет какой из доступных в текущем браузере
транспортов является наиболее эффективным и с его помощью устанавливает
соединение с сервером, который поддерживает несколько протоколов. С
точки зрения разработчика интерфейс, ими предоставляемый, не зависит от
транспорта и примерно одинаков:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Метод для &lt;strong&gt;отправки&lt;/strong&gt; сообщения противоположной стороне.&lt;/li&gt;
&lt;li&gt;Регистрация обработчика события, который будет вызван &lt;strong&gt;при
    получении&lt;/strong&gt; сообщения от противоположной стороны, с содержанием
    сообщения в аргументе.&lt;/li&gt;
&lt;li&gt;Метод, который будет вызван при установке и разрывании соединения.&lt;/li&gt;
&lt;li&gt;Инициатором соединения по очевидным причинам всегда является клиент,
    так что у него есть дополнительный механизм для этого, с
    возможностью указать какие-то настройки.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;При выборе такой библиотеки для конкретного проекта очень большую роль
играет его основная серверная платформа: обычно хочется использовать тот
же язык программирования для обработки сообщений, что и для реализаций
основной серверной части. Чаще всего используется основанный на
&lt;a href="/tag/epoll/"&gt;epoll&lt;/a&gt; или аналогах HTTP-сервер, что позволяет
поддерживать большое количество пользователей онлайн:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="/tag/node-js/"&gt;Node.js&lt;/a&gt; на &lt;a href="/tag/javascript/"&gt;JavaScript&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;На &lt;a href="/tag/erlang/"&gt;Erlang&lt;/a&gt; есть несколько очень эффективных
    HTTP-серверов:&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.insight-it.ru/goto/82a43b29/" rel="nofollow" target="_blank" title="https://github.com/extend/cowboy"&gt;cowboy&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.insight-it.ru/goto/4567a795/" rel="nofollow" target="_blank" title="https://github.com/ostinelli/misultin"&gt;misultin&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.insight-it.ru/goto/2902d504/" rel="nofollow" target="_blank" title="https://github.com/mochi/mochiweb"&gt;mochiweb&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.insight-it.ru/goto/798908e5/" rel="nofollow" target="_blank" title="http://yaws.hyber.org/"&gt;yaws&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="/tag/tornado/"&gt;Tornado&lt;/a&gt;&amp;nbsp;на &lt;a href="/tag/python/"&gt;Python&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="/tag/netty/"&gt;netty&lt;/a&gt; на &lt;a href="/tag/java/"&gt;Java&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Так как самих библиотек этой категории существует примерно пару
десятков, расскажу вкратце о наиболее заслуживающих внимания на мой
взгляд:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.insight-it.ru/goto/4034b77d/" rel="nofollow" target="_blank" title="http://socket.io"&gt;socket.io&lt;/a&gt;: поддерживает практически все
    возможные транспорты, включая &lt;a href="/tag/flash/"&gt;Flash&lt;/a&gt;. Основная
    серверная платформа - &lt;strong&gt;node.js&lt;/strong&gt;, силами сторонних разработчиков
    есть реализации протокола на других платформах. Имеет спорную
    репутацию, проект довольно громоздкий, в некоторых ситуациях ведет
    себя непредсказуемо.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.insight-it.ru/goto/4dc9c4cc/" rel="nofollow" target="_blank" title="https://github.com/sockjs/sockjs-client"&gt;SockJS&lt;/a&gt;: очень молодой
    проект, поддерживает необходимый минимум транспортов, прост в
    эксплуатации. Относительно стабилен и предсказуем. Серверная часть
    доступна на &lt;strong&gt;node.js&lt;/strong&gt;, &lt;strong&gt;Tornado&lt;/strong&gt; и &lt;strong&gt;cowboy/misultin,&lt;/strong&gt; активно
    работают над другими платформами.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Существуют коммерческие решения, абсолютно идентичные по принципу работы
и функционалу. Аналогичная обсуждавшимся opensource решениям библиотека
дополняется брокером сообщений для организации паттерна
"публикация-подписка" и в совокупности с хостингом "в облаках" продается
с оплатой за количество переданных сообщений (или по подписке с каким-то
лимитом), естественно с нехилой наценкой. Плюсы и минусы очевидны:
отсутствие необходимости обо всем этом заботиться против относительно
высокой стоимости, потере контроля при сбоях или необходимости
изменений, привязке к стороннему поставщику услуг и т.п. Рекламировать
их не буду, при желании легко гуглятся, ровно как и оставшиеся
альтернативные opensource проекты.&lt;/p&gt;
&lt;h2 id="vernemsia-k-interaktivnym-saitam"&gt;Вернемся к интерактивным сайтам&lt;/h2&gt;
&lt;p&gt;Надеюсь, только что закончившегося лирического отступления на 3/4 статьи
Вам будет достаточно, чтобы составить общее представление о построении
постоянного соединения между браузером и сервером, а желательно и
определиться с каким-то решением для автоматического выбора наиболее
эффективного транспорта в контексте именно Вашего проекта.&lt;/p&gt;
&lt;p&gt;Получив примитивный интерфейс в виде "отправить сообщение /
отреагировать на сообщение" необходимо определиться с тем, что же мы
будем передавать в этих сообщениях и как будем на них реагировать.&lt;/p&gt;
&lt;p&gt;С форматом сериализации сообщений все довольно просто: выбор между XML и
JSON очевиден в пользу последнего, а заморачиваться с чем-то более
экзотическим смысла мало (хотя давно хочу попробовать в этой роли
&lt;a href="/tag/protocol-buffers/"&gt;Protocol Buffers&lt;/a&gt; или &lt;a href="/tag/bson/"&gt;BSON&lt;/a&gt;, но
никак руки не доходят).&lt;/p&gt;
&lt;p&gt;Намного интереснее вопрос о том, что, собственно, будет в этих
сообщениях содержаться. В &lt;a href="https://www.insight-it.ru/interactive/2012/klientskaya-chast-interaktivnogo-sajjta/"&gt;предыдущей статье&lt;/a&gt;
мы остановились на использовании фреймворка для организации кода
JavaScript-клиента. Предлагаемая ими концепция &lt;strong&gt;модели&lt;/strong&gt;&amp;nbsp;обычно
по-умолчанию предоставляет возможность синхронизации с сервером
посредством &lt;a href="/tag/ajax/"&gt;AJAX&lt;/a&gt; запросов и механизм изменения этого
поведения. Для использовавшегося в качестве примера
&lt;a href="/tag/backbone-js/"&gt;Backbone.js&lt;/a&gt;&amp;nbsp;для этого необходимо переопределить
функцию &lt;strong&gt;Backbone.sync&lt;/strong&gt;.&amp;nbsp;При сохранении модели клиент будет отправлять
объект с идентификатором модели и списком её изменений. Запрос изменений
с сервера будет происходить асинхронно, то есть после отправки сообщения
о том, что нужны данные для такой-то модели, посредством метода fetch он
сам не получит ответа. Собственно изменения в модели произведет
обработчик получения сообщений, в котором должна быть реализована
соответствующая логика. Далее подписанные на события изменений в моделях
объекты-представления будут соответствующим образом обновлять DOM-дерево
страницы, отображая пользователю нужную информацию. &lt;em&gt;Это, пожалуй,
наиболее &lt;strong&gt;правильный&lt;/strong&gt; способ интегрировать постоянное соединение и
клиентский фреймфорк.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Основными минусами его является очень серьезный объем работы по
разработке клиентской части, а также дублирование достаточно большой
части логики и HTML-шаблонов между серверной и клиентской сторонами. Я
бы рекомендовал использовать этот подход, только если позволяют трудовые
ресурсы (читай: есть хотя бы отдельный специализирующийся на JavaScript
разработчик), либо когда проект по каким-то причинам решил отказаться от
реализации статичного HTML-интерфейса.&lt;/p&gt;
&lt;p&gt;В следующей статье я расскажу о менее трудозатратном способе добиться
того же результата, который основан на жертве идеологической
правильностью в пользу минимизации повторного написания кода.&lt;/p&gt;
&lt;div class="card green"&gt;
&lt;p&gt;&lt;div class="card-content white-text"&gt;
Эта статья - третья в &lt;a class="green-text text-lighten-4" href="https://www.insight-it.ru/interactive/"&gt;серии про Интерактивные сайты&lt;/a&gt;, автор - &lt;a class="green-text text-lighten-4" href="https://www.insight-it.ru/goto/b03d9116/" rel="nofollow" target="_blank" title="http://blinkov.ru"&gt;Иван&amp;nbsp;Блинков&lt;/a&gt;, основано на личном опыте.
До встречи &lt;a class="green-text text-lighten-4" href="/feed/"&gt;на страницах Insight IT&lt;/a&gt;!
&lt;/div&gt;&lt;/p&gt;
&lt;/div&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Иван Блинков</dc:creator><pubDate>Tue, 10 Apr 2012 00:47:00 +0400</pubDate><guid>tag:www.insight-it.ru,2012-04-10:interactive/2012/postoyannoe-soedinenie-mezhdu-brauzerom-i-serverom/</guid><category>AJAX</category><category>Comet</category><category>epoll</category><category>EventSource</category><category>Flash</category><category>HTTP</category><category>JavaScript</category><category>polling</category><category>streaming</category><category>WebSocket</category><category>клиентская часть</category><category>серверная часть</category><category>HTML5</category></item><item><title>Клиентская часть интерактивного сайта</title><link>https://www.insight-it.ru//interactive/2012/klientskaya-chast-interaktivnogo-sajjta/</link><description>&lt;p&gt;Клиентская часть сайта играет ключевую роль в обеспечении
его&amp;nbsp;&lt;em&gt;интерактивности&lt;/em&gt;. Именно на нее возлагается переопределение
стандартного поведения для создания впечатления живого организма вместо
кучки бездушных страниц. В статье про
&lt;a href="https://www.insight-it.ru/interactive/2012/arkhitektura-interaktivnykh-sajjtov/"&gt;архитектуру&lt;/a&gt;
интерактивных сайтов я подробно изложил основные функции и требования,
которые перед ним стоят. Сегодня же я представлю свое видение того, как
его грамотно реализовать. На статус единственно-правильного-решения не
претендую, статью можно воспринимать просто как набор практических
советов и рекомендаций.
&lt;!--more--&gt;&lt;/p&gt;
&lt;p&gt;Итак, сегодня мы будем обсуждать создание JavaScript-клиента для
интерактивного сайта. Начнем, пожалуй, с организации кода проекта с
целью облегчения его сопровождения при росте кодовой базы, перейдем к
переопределению ключевых обработчиков событий, затем к сохранению
стандартного поведения браузера и закончим синхронизацией состояния
между клиентом и сервером.&lt;/p&gt;
&lt;h2 id="organizatsiia-koda"&gt;Организация кода&lt;/h2&gt;
&lt;h3 id="sborka"&gt;Сборка&lt;/h3&gt;
&lt;p&gt;Первое, чем стоит обзавестись перед разработкой сложного
JavaScript-приложения, это системой его сборки. С точки зрения
клиентской оптимизации весь &lt;a href="/tag/javascript/"&gt;JavaScript&lt;/a&gt;-код по
возможности должен быть минифицирован и собран в один файл, подключенный
в конце &lt;a href="/tag/html/"&gt;HTML&lt;/a&gt;, желательно асинхронно. Работать с ним в
таком виде невозможно, соответственно надо иметь возможность легко
собирать его из набора красиво отформатированных файлов, используемых
при&amp;nbsp;разработке.&lt;/p&gt;
&lt;p&gt;На вопрос &lt;em&gt;"Какую систему сборки использовать?"&lt;/em&gt;&amp;nbsp;в большинстве случаев
правильный ответ: ту же, что и для сборки серверной части. Make, rake,
maven, ant, rebar... - любому из них без труда можно поручить эту
задачу. Для конкатенации можно использовать хоть консольную команду
&lt;code&gt;&amp;gt;&amp;gt;&lt;/code&gt;, для минимизации есть много альтернативных библиотек, в порядке
моих симпатий:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.insight-it.ru/goto/ec53b5fa/" rel="nofollow" target="_blank" title="https://developers.google.com/closure/compiler/"&gt;&lt;strong&gt;Google Closure&lt;/strong&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.insight-it.ru/goto/6ccc0709/" rel="nofollow" target="_blank" title="http://developer.yahoo.com/yui/compressor/"&gt;&lt;strong&gt;YUI Compressor&lt;/strong&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.insight-it.ru/goto/28795a57/" rel="nofollow" target="_blank" title="https://github.com/mishoo/UglifyJS"&gt;&lt;strong&gt;UglifyJS&lt;/strong&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Если хочется чего-то более гибкого, могу порекомендовать воспользоваться
&lt;a href="https://www.insight-it.ru/goto/5908cea6/" rel="nofollow" target="_blank" title="https://github.com/miracle2k/webassets"&gt;&lt;strong&gt;Webassets&lt;/strong&gt;&lt;/a&gt;, который я уже
упоминал в статье про
&lt;a href="https://www.insight-it.ru/python/2012/jinja2/"&gt;Jinja2&lt;/a&gt;. В
консольном режиме прекрасно подключается к любой системе сборки и языку
программирования. Описать процесс сборки &lt;a href="/tag/javascript/"&gt;JavaScript&lt;/a&gt;
и &lt;a href="/tag/css/"&gt;CSS&lt;/a&gt; можно очень подробно и именно так, как считаете
нужным, естественно на &lt;a href="/tag/python/"&gt;Python&lt;/a&gt;. Сопоставимый по
возможностям проект из мира &lt;a href="/tag/ruby/"&gt;Ruby&lt;/a&gt; - &lt;a href="https://www.insight-it.ru/goto/5b3a9a97/" rel="nofollow" target="_blank" title="http://synthesis.sbecker.net/pages/asset_packager"&gt;Asset Packager&lt;/a&gt;, наверняка
есть много других.&lt;/p&gt;
&lt;h3 id="chitabelnyi-kod"&gt;Читабельный код&lt;/h3&gt;
&lt;p&gt;Не знаю как Вы, а я тихо ненавижу &lt;strong&gt;JavaScript&lt;/strong&gt; все ~10 лет, которые я
с ним знаком. Так как он по сути является монополией на рынке браузерных
приложений (Flash, Java апплеты и ActiveX за альтернативы можно даже не
считать), использовать его так или иначе приходится в любом сколько-либо
серьезном интернет-проекте. Даже Google Dart&amp;nbsp;вряд ли&amp;nbsp;всерьез приживется.&lt;/p&gt;
&lt;p&gt;При полном отсутствии конкуренции совершенно не удивительно, что у него
никуда не годящийся синтаксис и набор не знаю откуда взявшихся
абстракций в виде прототипов и замыканий. С этим всем определенно можно
мириться и работать, особенно если только им и заниматься, но привыкший
к серверным языкам программирования мозг определенно чувствует себя&amp;nbsp;не
комфортно.&lt;/p&gt;
&lt;p&gt;Если Вас тоже не раз посещали подобные мысли, то Вы вероятно как и я при
первой же возможности пересядете (или уже пересели) на
&lt;a href="/tag/coffeescript/"&gt;&lt;strong&gt;CoffeeScript&lt;/strong&gt;&lt;/a&gt;, компилируемый в JavaScript язык
программирования.&amp;nbsp;Немного рекламы этого проекта:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Золотое правило CoffeeScript: &lt;strong&gt;"It's just Javascript"&lt;/strong&gt; &lt;em&gt;(это
    просто JavaScript)&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;Прямое преобразование кода в JavaScript&lt;/li&gt;
&lt;li&gt;Доступны абсолютно все JavaScript-библиотеки&lt;/li&gt;
&lt;li&gt;Никаких точек с запятой в конце каждой строки&lt;/li&gt;
&lt;li&gt;Структурирование кода на основе отступов, как в Python&lt;/li&gt;
&lt;li&gt;Объявление функций просто стрелочкой &lt;code&gt;-&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;При вызове методов даже скобки писать не обязательно&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Человеческое наследование: простое &lt;strong&gt;class MyClass extends
    MyParent&lt;/strong&gt;&amp;nbsp;превращается в довольно хитрую конструкцию с
    использованием прототипов и замыканий:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nx"&gt;MMyClass&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;__extends&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;MyClass&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;MyParent&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;MyClass&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;MyClass&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;__super__&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="nx"&gt;arguments&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nx"&gt;MyClass&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;prototype&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;initialize&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;MyClass&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;})();&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Много укороченных команд ветвления кода (&lt;strong&gt;if&lt;/strong&gt;, &lt;strong&gt;switch,&lt;/strong&gt; циклы&amp;nbsp;и
    т.п.)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;В целом код выходит раза в полтора-два короче и намного приятнее для
    глаз&lt;/li&gt;
&lt;li&gt;Консольный компилятор с функцией наблюдения за директориями&lt;/li&gt;
&lt;li&gt;Легко подключается как фильтр в Webassets&lt;/li&gt;
&lt;li&gt;Подробнее с примерами на &lt;a href="https://www.insight-it.ru/goto/834fa52/" rel="nofollow" target="_blank" title="http://coffeescript.org/"&gt;официальном сайте&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;В общем рекомендую :)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="logicheskoe-razdelenie-koda"&gt;Логическое разделение кода&lt;/h3&gt;
&lt;p&gt;Если Вы сталкивались со сколько-либо сложным пользовательским
интерфейсом "на jQuery", то скорее всего не по наслышке понимаете откуда
взялось выражение &lt;strong&gt;"спагетти-код"&lt;/strong&gt;. В связи с событийной парадигмой
разработки браузерных приложений, очень часто JavaScript-код с
использованием jQuery или альтернатив превращается в так называемый
&lt;em&gt;"коллбек на коллбеке, коллбеком погоняет"&lt;/em&gt; (коллбек - транслит от
английского callback - обработчик события).&amp;nbsp;При отсутствии четкой
структуры такой код становится очень сложно поддерживать при его
увеличении в объемах. Но это не повод отказываться от jQuery - от
событий никуда не деться, и эта библиотека отлично справляется с
абстракций от особенностей их реализации в различных браузерах.&lt;/p&gt;
&lt;p&gt;На мой взгляд, одним из наиболее резонных способов решения (или
заблаговременного предотвращения) этой проблемы является использование в
разумных пределах &lt;a href="/tag/oop/"&gt;объектно-ориентированные&lt;/a&gt;&amp;nbsp;возможности
&lt;strong&gt;JavaScript&lt;/strong&gt; &lt;em&gt;(благо CoffeeScript это дело сильно упрощает)&lt;/em&gt;.
Соответственно, используемые классы можно разумно располагать в какой-то
иерархии с точки зрения наследования (для обеспечения DRY, don't repeat
yourself - "не повторяйся") и с точки зрения расположения в файловой
системе (с разложенными по папкам файлами работать намного проще, чем с
здоровенной вереницей обработчиков событий в одном файле).&lt;/p&gt;
&lt;p&gt;Собственно никто не мешает начать заворачивать код в классы на пустом
месте, но я позволю себе предложить немного более элегантное решение,
которое помимо организации кода пригодится нам и в дальнейшем. Подобно
серверным фреймворкам, для клиентских приложений есть библиотеки,
предоставляющие базовые классы для решения типичных задач:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Модель&lt;/strong&gt;&amp;nbsp;&lt;em&gt;(Model)&lt;/em&gt; - как и в традиционном MVC представляет собой
    класс, объект которого содержит локальную копию каких-то данных и
    предоставляет механизмы для её синхронизации с внешним хранилищем.
    Основное отличие от серверных моделей - хранилищем выступает не
    СУБД, а либо локальное хранилище браузера через HTML5, либо
    удаленный сервис через REST или другой интерфейс. Плюс так как они
    находятся вне "зоны доверия", то полученные от них данные нужно
    обязательно валидировать, фильтровать и проверять на серверной
    стороне, прежде чем что-либо с ними делать.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Представление&lt;/strong&gt; &lt;em&gt;(View)&lt;/em&gt; или &lt;strong&gt;контроллер&lt;/strong&gt; &lt;em&gt;(Controller)&lt;/em&gt; - тут,
    по моим впечатлениям, образовалась путаница и за обоими названиями в
    нашем контексте имеют ввиду примерно одно и то же. Объект такого
    класса следит за изменениями и событиями в связанных с ним моделях и
    элементах DOM, каким-либо образом на них реагируя. Таким образом
    большая часть кода, которая раньше была "вереницей обработчиков
    событий", оказывается методами этого класса. При этом базовый класс
    из библиотеки берет на себя нормальное поведение &lt;strong&gt;this&lt;/strong&gt;&amp;nbsp;и следит
    за тем, чтобы обработчики автоматически добавлялись на динамические
    созданные элементы DOM.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Маршрутизатор&lt;/strong&gt; &lt;em&gt;(Router)&lt;/em&gt;&amp;nbsp;- следит за состоянием адресной строки
    и позволяет обрабатывать изменения, понадобится для восстановления
    поведения браузера.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Коллекция&lt;/strong&gt; &lt;em&gt;(Collection)&lt;/em&gt; - отсортированный набор однотипных
    моделей, с которым можно работать как с единым целым.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="card blue lighten-4"&gt;
&lt;p&gt;&lt;div class="card-content"&gt;
Не стоит рассматривать эти абстракций как единственный верный способ
делать клиентские приложения, но при их использовании появляется хоть
какая-то логика и становится более-менее понятно где какой кусок кода
должен находиться и где его потом искать. Для абстракции особенностей
реализаций браузеров они по-прежнему полагаются на &lt;code&gt;$&lt;/code&gt; в виде
&lt;a href="https://www.insight-it.ru/goto/3b02d98c/" rel="nofollow" target="_blank" title="http://jquery.com/"&gt;jQuery&lt;/a&gt; или &lt;a href="https://www.insight-it.ru/goto/e6412e50/" rel="nofollow" target="_blank" title="http://zeptojs.com/"&gt;Zepto&lt;/a&gt;.
&lt;/div&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;Мне известны три библиотеки, предоставляющие большую часть изложенных
выше абстракций. Вкратце о каждой:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.insight-it.ru/goto/e1e90fac/" rel="nofollow" target="_blank" title="http://documentcloud.github.com/backbone/"&gt;&lt;strong&gt;Backbone.js&lt;/strong&gt;&lt;/a&gt;&amp;nbsp;-
    самая&amp;nbsp;широко распространенная из трех, используется во многих
    серьезных проектах.&amp;nbsp;Основана на библиотеке
    &lt;a href="https://www.insight-it.ru/goto/48609b39/" rel="nofollow" target="_blank" title="http://documentcloud.github.com/underscore/"&gt;Underscore.js&lt;/a&gt;,
    которая с одной стороны предоставляет массу удобных функций и
    шаблонизатор, но с другой стороны - не особо-то и часто они
    оказываются нужны.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.insight-it.ru/goto/d7dc0253/" rel="nofollow" target="_blank" title="http://spinejs.com/"&gt;&lt;strong&gt;Spine.js&lt;/strong&gt;&lt;/a&gt;&amp;nbsp;- библиотека по-моложе, которая
    очень похожа на Backbone.js, но написана на CoffeeScript и из-за
    отсутствия внешних зависимостей вышла компактнее. Отличия в основном
    в терминологии и деталях реализации.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.insight-it.ru/goto/a115abb7/" rel="nofollow" target="_blank" title="http://knockoutjs.com/"&gt;&lt;strong&gt;Knockout.js&lt;/strong&gt;&lt;/a&gt; - эта
    библиотека&amp;nbsp;пропагандирует использование &lt;code&gt;data-*&lt;/code&gt; атрибутов из HTML5
    для хранения метаданных, которые как-то управляют изменениями
    тегов-владельцев при определенных событиях, практически забирая на
    себя роль представления. Концепция кажется мне мутноватой, так что
    лично для себя я её использование всерьез и не рассматривал никогда.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Когда в этой статье дело будет доходить до примеров кода, я буду
приводить их на основе &lt;strong&gt;Backbone.js&lt;/strong&gt;, так как в свое время я
остановился именно на ней. Почему? В основном из-за того, что она
используется в очень многих проектах и стоит за ней целая компания, а не
просто один разработчик, которому однажды может надоесть поддерживать
проект (как в случае с Spine.js). Но в глубине души я, конечно, надеюсь,
что однажды они уберут эту жесткую зависимость от Underscore.js, а то и
может быть тоже перепишут все на CoffeeScript.&lt;/p&gt;
&lt;p&gt;В целом я стараюсь изложить общую концепцию: те же принципы можно
реализовать и с использованием альтернатив, и с использованием
разрозненных библиотек, решающих более узкие задачи, и вообще с нуля,
самостоятельно занимаясь вопросами кроссбраузерности и прочих
особенностей современного Интернета. Последний путь, кстати, не
настолько уж и безумен, как кажется, крупные компании и интернет-проекты
обычно по нему и идут, если человеческие и финансовые ресурсы позволяют.&lt;/p&gt;
&lt;h2 id="obrabotchiki-sobytii_1"&gt;Обработчики событий&lt;/h2&gt;
&lt;p&gt;В предыдущем разделе мы прилично так отвлеклись от основной темы -
&lt;em&gt;интерактивных сайтов&lt;/em&gt;. Это было необходимо для того, чтобы достаточно
комплексное JavaScript-приложение в итоге оказалось поддерживаемым и
имело хоть какую-то структуру и логику.&lt;/p&gt;
&lt;p&gt;Напомню, то, что раньше было просто независимым обработчиком событий
становится методом представления (по терминологии Backbone.js). У
каждого представления создается "оглавление" методов-обработчиков в
атрибуте &lt;strong&gt;events&lt;/strong&gt;.&amp;nbsp;Наверное многим хотелось бы увидеть какой-то пример
кода, но так как статьями с примерами примитивных приложений на
Backbone.js пестрит весь Интернет, тратить на это время желания
совершенно никакого, сошлюсь на самый популярный: &lt;a href="https://www.insight-it.ru/goto/fbd5c000/" rel="nofollow" target="_blank" title="http://documentcloud.github.com/backbone/docs/todos.html"&gt;список задач
TODO&lt;/a&gt;, для
сравнения &lt;a href="https://www.insight-it.ru/goto/28094239/" rel="nofollow" target="_blank" title="https://github.com/maccman/spine.todos"&gt;то же самое на Spine.js&lt;/a&gt;.&amp;nbsp;К слову, при использовании &lt;em&gt;CoffeeScript&lt;/em&gt; использовать стандартный механизм
&lt;code&gt;Backbone.****.extend({ ... })&lt;/code&gt; не обязательно, &lt;code&gt;class MyClass extends Backbone.****&lt;/code&gt; прекрасно делает то же самое.&lt;/p&gt;
&lt;p&gt;По мне, так намного интереснее не какие именно события обрабатываются
(все равно 90% уникальны для проекта), а как их распределить по разным
представлениям. Обычно получается что-то в этом духе:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Пользовательское&lt;/strong&gt; представление будет модифицировать страницу в
    тех местах, где оно как-то связано с текущим пользователем: форма
    авторизации, надпись "Привет, ****!", кнопка выхода и пр.
    Вероятно, оно будет использовать &lt;em&gt;модель&lt;/em&gt; текущего пользователя или
    в тривиальных случаях просто самостоятельно работать с cookie
    сессии.&lt;/li&gt;
&lt;li&gt;Классы &lt;em&gt;модели&lt;/em&gt; и &lt;em&gt;представления&lt;/em&gt;, а вероятно и &lt;em&gt;коллекции&lt;/em&gt;,
    понадобятся каждой &lt;strong&gt;логической сущности&lt;/strong&gt;, которая каким-либо
    образом отражается в пользовательском интерфейсе. Это может быть что
    угодно, например задача в TODO-списке, статья, комментарий - все
    зависит от тематики проекта.&lt;/li&gt;
&lt;li&gt;Если &lt;strong&gt;навигация&lt;/strong&gt; по сайту каким-то образом динамически
    видоизменяется, то представление понадобится и для нее. Например,
    часто подсвечивают пункты в глобальной навигации на основе изменений
    в текущем адресе страницы.&lt;/li&gt;
&lt;li&gt;И, последний пункт, который собственно и относится к сегодняшней
    теме - одно представление будет общим для всего сайта и будет
    отвечать за его &lt;strong&gt;интерактивность&lt;/strong&gt;. Давайте его рассмотрим
    подробнее.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Для отсутствия перезагрузок браузера внутри сайта, нам нужно
переопределить:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;События клика на ссылки: по содержимому атрибута &lt;code&gt;href&lt;/code&gt; нужно определить,
что ссылка внутренняя и вызвать "цепную реакцию" в других
представлениях, чтобы в итоге пользователь увидел то, что должен.&lt;/li&gt;
&lt;li&gt;При отправке формы есть два сценария:&lt;ul&gt;
&lt;li&gt;Обновляется связанная &lt;em&gt;модель&lt;/em&gt; и синхронизируется с сервером. В
таком сценарии при необходимости можно вообще скрыть кнопку отправки
и "автосохранять" изменения в модели.&lt;/li&gt;
&lt;li&gt;Связанной модели по каким-то причинам нет и нужно просто на основе
данных формы что-то сделать, например выполнить поиск по указанной в
форме фразе или отправить запрос на авторизацию.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Для отмены стандартной реакции браузера на события у jQuery есть два
основных механизма: &lt;code&gt;event.preventDefault()&lt;/code&gt; и &lt;code&gt;return false&lt;/code&gt;. В
данной ситуации (да и большинстве других), целесообразнее пользоваться
последним, так как если вдруг в коде обработчика окажется какая-то
ошибка, то пользователь просто увидит стандартную реакцию браузера, а не
окажется в ситуации "некликающихся ссылок" и "неотправляющихся форм".&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="vosstanovlenie-povedeniia-brauzera"&gt;Восстановление поведения браузера&lt;/h2&gt;
&lt;p&gt;В предыдущем разделе я даже не стал подробно останавливаться на том, как
сделать так "чтобы пользователь увидел то, что должен". Наверняка можно
придумать массу способов решения этой задачи, но единственный реально
применимый на практике - воспроизвести визуально то же самое, что
происходит при обычной&amp;nbsp;перезагрузке страницы.&lt;/p&gt;
&lt;p&gt;И первое, с чего стоит начать - с адресной строки, именно там должен
появиться тот адрес, который был в &lt;code&gt;href&lt;/code&gt; ссылки и action формы. Но на
самом деле проще сказать, чем сделать:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Возможность просто полностью поменять текущий адрес в адресной
    строке из JavaScript без инициализации открытия страницы есть только
    в совсем свежих браузерах посредством &lt;strong&gt;HTML5 History API&lt;/strong&gt;
    (&lt;a href="https://www.insight-it.ru/goto/61b4e54f/" rel="nofollow" target="_blank" title="https://developer.mozilla.org/en/DOM/Manipulating_the_browser_history#The_pushState().C2.A0method"&gt;pushState&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;В старых браузерах переходы между внутренними страницами сайта можно
    эмулировать через изменения якоря ссылки, который в URL идет после
    &lt;code&gt;#&lt;/code&gt; и обычно используется для "перелистывания" на середину
    HTML-документа. Для отслеживания таких изменений используется
    событие
    &lt;a href="https://www.insight-it.ru/goto/a35bb215/" rel="nofollow" target="_blank" title="https://developer.mozilla.org/en/DOM/window.onhashchange"&gt;onhashchange&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;В еще более старых браузерах это событие эмулируют разными трюками с
    iframe и setInterval.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;Backbone.history.start()&lt;/code&gt;&amp;nbsp;берет на себя абстракцию изменений в
адресной строке, правда поддержку &lt;em&gt;pushState&lt;/em&gt; нужно явно включить в
аргументах. Заодно восстанавливается нормальное поведение кнопок "Назад"
и "Вперед" в браузере.&lt;/p&gt;
&lt;p&gt;Для обработки и создания событий, отражающихся в адресной строке, нужно
сделать подкласс &lt;strong&gt;Backbone.Router&lt;/strong&gt;. C ситуациями когда их имеет смысл
создать несколько, я не сталкивался. По аналогии с серверными
фреймворками в атрибуте &lt;strong&gt;routes&lt;/strong&gt;&amp;nbsp;задается соответствие паттернов
адресов к методам-обработчикам, которые будут выполниться при переходе.
В них вызываются необходимые изменения в коллекциях, моделях и
представлениях, чтобы привести в нужное состояние текущий документ.&lt;/p&gt;
&lt;p&gt;Для инициации "виртуального" перехода на новую внутреннюю страницу нужно
вызвать метод &lt;strong&gt;navigate&lt;/strong&gt; у нашего объекта-маршрутизатора, первым
аргументом передав её адрес без первого /, а вторым - настройки:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;trigger&lt;/strong&gt; - вызывать ли обработчик из маршрутизатора?&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;replace&lt;/strong&gt; - добавлять ли страницу, с которой мы уходим в историю
    браузера, чтобы можно было на нее вернуться при нажатии кнопки
    "назад"?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Таким образом, во внутренних ссылках мы используем нормальные
относительные URL, начинающиеся с /. По ним будут нормально ходить
роботы и браузеры без JavaScript. В обработчике кликов на них мы:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;проверяем правда ли она внутренняя (начинается ли она с /);&lt;/li&gt;
&lt;li&gt;"отменяем" стандартный переход, вернув &lt;code&gt;false&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;вызываем &lt;code&gt;router.navigate(href.substring(1), {trigger: true})&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Осталась еще несколько атрибутов поведения браузера, которые необходимо
починить, чтобы визуально все выглядело "как обычно":&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Клик по ссылке с зажатым Shift должен открывать её &lt;em&gt;в новом окне&lt;/em&gt;, а
    с зажатым Ctrl или при клике средней кнопкой мыши - &lt;em&gt;в новой
    вкладке&lt;/em&gt;. Довольно не хитро делается на основе атрибутов
    объекта-события, который передает обработчику jQuery (button,
    shiftkey, metakey), для открытия окна или вкладки - window.open.&lt;/li&gt;
&lt;li&gt;Если пользователь сделал какое-то действие, а прореагировать на него
    мгновенно не получается (так как что-то грузится, вероятно) - нужно
    включить курсор ожидания, установив в CSS &lt;strong&gt;cursor: wait&lt;/strong&gt;, и,
    желательно, анимированный &lt;strong&gt;favicon.ico&lt;/strong&gt;. И, соответственно,
    вернуть все как было, когда страница примет нужный вид. Для смены
    favicon до сих пор пользуюсь каким-то довольно старым плагином к
    jQuery, который не особо шикарно, но все же работает. Его сайт,
    видимо, накрылся, так что продублировал:&amp;nbsp;&lt;a href="https://www.insight-it.ru/goto/d6f7fab3/" rel="nofollow" target="_blank" title="https://gist.github.com/2320740"&gt;https://gist.github.com/2320740&lt;/a&gt;, если кто знает более адекватные альтернативы - дайте знать в комментариях, пожалуйста, руки поискать все никак не доходят.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="sinkhronizatsiia-sostoianiia"&gt;Синхронизация состояния&lt;/h2&gt;
&lt;p&gt;По-умолчанию Backbone.js предлагает хранить все состояние клиента в
моделях и синхронизировать его с серверным посредством реализации
простенького REST API на сервере
(&lt;a href="https://www.insight-it.ru/goto/e85f288a/" rel="nofollow" target="_blank" title="http://documentcloud.github.com/backbone/#Sync"&gt;подробнее&lt;/a&gt;), к
которому запросы отправляются посредством обычного &lt;code&gt;$.ajax&lt;/code&gt;. Чтобы
инициировать процесс нужно вручную вызвать у экземпляра модели метод
&lt;strong&gt;fetch&lt;/strong&gt;, чтобы обновить клиентское состояние данными с сервера, или
метод &lt;strong&gt;save&lt;/strong&gt;, для обратного процесса.&lt;/p&gt;
&lt;p&gt;Для многих приложений этого, в целом, достаточно. Но ограничение
очевидно - нет возможности мгновенно узнать, что на сервере что-то
изменилось. Чего-то близкого можно достичь вызовом &lt;strong&gt;fetch&lt;/strong&gt; раз в N
секунд для каждой модели, но если пользователей предполагается хоть
сколько-либо много, нагрузка на серверную часть будет неоправданно
велика.&lt;/p&gt;
&lt;p&gt;Резонным дополнением этой схемы является использование постоянного
соединения между клиентом и сервером для синхронизации их состояний.
Именно это мы и обсудим в следующей статье серии.&lt;/p&gt;
&lt;div class="card green"&gt;
&lt;p&gt;&lt;div class="card-content white-text"&gt;
Эта статья - вторая в &lt;a class="green-text text-lighten-4" href="https://www.insight-it.ru/interactive/"&gt;серии про Интерактивные сайты&lt;/a&gt;, автор - &lt;a class="green-text text-lighten-4" href="https://www.insight-it.ru/goto/b03d9116/" rel="nofollow" target="_blank" title="http://blinkov.ru"&gt;Иван&amp;nbsp;Блинков&lt;/a&gt;, основано на личном опыте.
До встречи &lt;a class="green-text text-lighten-4" href="/feed/"&gt;на страницах Insight IT&lt;/a&gt;!
&lt;/div&gt;&lt;/p&gt;
&lt;/div&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Иван Блинков</dc:creator><pubDate>Fri, 06 Apr 2012 21:17:00 +0400</pubDate><guid>tag:www.insight-it.ru,2012-04-06:interactive/2012/klientskaya-chast-interaktivnogo-sajjta/</guid><category>AJAX</category><category>Backbone.js</category><category>CoffeeScript</category><category>JavaScript</category><category>JQuery</category><category>клиентская часть</category></item><item><title>Архитектура интерактивных сайтов</title><link>https://www.insight-it.ru//interactive/2012/arkhitektura-interaktivnykh-sajjtov/</link><description>&lt;p&gt;В &lt;a href="https://www.insight-it.ru/interactive/2012/anons-serii-statejj-interaktivnye-sajjty/"&gt;анонсе&lt;/a&gt;&amp;nbsp;серии статей &lt;a href="https://www.insight-it.ru/interactive/"&gt;"Интерактивные сайты"&lt;/a&gt; я постарался максимально доходчиво изложить свою мотивацию к ей созданию, да и актуальность самой темы, так что сразу к делу!
&lt;!--more--&gt;&lt;/p&gt;
&lt;p&gt;Итак, мы хотим сделать так, чтобы с точки зрения &lt;em&gt;пользователя&lt;/em&gt; наш сайт
выглядел &lt;strong&gt;интерактивным&lt;/strong&gt;. То есть воспринимался не как набор отдельно
загружающихся страниц, а скорее как обычное приложение для компьютера.
Ему, в целом, не важно как именно мы этого добьемся, главное чтобы при
этом браузер вел себя как обычно и визуально все реагировало почти
мгновенно.&lt;/p&gt;
&lt;p&gt;Сразу хочу предупредить, что далеко не всем сайтам такая
глобальная&amp;nbsp;&lt;em&gt;интерактивность&lt;/em&gt; пойдет на пользу. Если пользователи сайта
редко что-либо делают и большую часть времени читают длинные тексты, то,
вероятно, этот проект как раз из этой категории: быстрота реакции на
клик не так радует, когда большую часть времени приходится работать
скроллом. Если Ваш интернет-проект является сайтом с длинным контентом в
формате блога, новостей или вики - подумайте лишний раз, прежде чем
переделывать весь сайт, вероятно будет достаточно интерактивных
комментариев и голосований на &lt;a href="/tag/ajax/"&gt;AJAX&lt;/a&gt;. Для социальных сетей,
сайтов знакомств, интернет-магазинов, поисковых систем, корпоративных
сайтов и многих других визуально заметная&amp;nbsp;&lt;em&gt;интерактивность&lt;/em&gt;&amp;nbsp;определенно
станет одним из ключевых &lt;strong&gt;конкурентных преимуществ&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;В этом посте я постараюсь нарисовать крупными мазками картину того, как
этого можно достичь. Визуально её я представил следующим образом:&lt;/p&gt;
&lt;p&gt;&lt;img alt="Архитектура интерактивного сайта" class="responsive-img" src="https://www.insight-it.ru/images/interactive-site-architecture.jpeg" title="Архитектура интерактивного сайта"/&gt;&lt;/p&gt;
&lt;h2 id="obshchie-zamechaniia"&gt;Общие замечания&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Здесь и далее я буду описывать "среднестатистический" интернет-проект, в
зависимости от специфики могут появляться дополнительные компоненты или
убираться за ненадобностью упомянутые. Например, если известно, что
пользоваться сайтом будут только сотрудники какой-то компании, то помимо
замены Интернета на Интранет, можно запросто избавиться и от
&lt;strong&gt;HTML-интерфейса&lt;/strong&gt; и всего, что с ним связано - никаким роботам доступ
к нему не нужен.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Наверное стоит прямым текстом сказать, что:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Голубые элементы - компоненты проекта, а серые - внешние.&lt;/li&gt;
&lt;li&gt;Связи в виде прямых линий означают&amp;nbsp;двусторонний&amp;nbsp;обмен данными,
транспорт и формат пока особо не важны.&lt;/li&gt;
&lt;li&gt;Схема логическая, так что вопросы балансировки нагрузки,
отказоустойчивости, репликации и т.п. остались в стороне; за каждым
блоком может стоять произвольное количество серверов.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Я решил не загромождать схему мониторингом, резервным копированием,
почтой, сервисом доменов и прочими хоть и важными, но не связанными
напрямую с темой компонентами системы.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;В этом посте не будет никаких конкретных примеров реализации и
технологий, оставим это на &lt;a href="https://www.insight-it.ru/interactive/"&gt;следующие статьи&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="klientskaia-chast"&gt;Клиентская часть&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Начнем наше путешествие. Пользователь вводит в адресной строке браузера
адрес нашего сайта и жмет Enter, инициируя тем самым сначала определение
IP-адреса через DNS, а затем и HTTP-запрос к нашему &lt;strong&gt;HTML-интерфейсу&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Получив в ответ &lt;strong&gt;страницу&lt;/strong&gt; в формате &lt;a href="/tag/html/"&gt;HTML&lt;/a&gt; браузер
начинает загружать указанные в нем внешние ресурсы, в том числе и
&lt;strong&gt;Javascript-клиент&lt;/strong&gt;, которому и передается слово. Сама страница
параллельно отрисовывается как и в статичном сайте.&lt;/li&gt;
&lt;li&gt;Как уже упоминалось выше, некоторые проекты решают не тратить силы на
поддержку двух интерфейсов к сайту, жертвуя тем самым доступом
большинства роботов и браузеров без поддержки
&lt;a href="/tag/javascript/"&gt;JavaScript&lt;/a&gt;. Стартовый HTML-документ в этом случае
превращается просто в практически пустой статичный файл, который служит
лишь для загрузки клиента.&lt;/li&gt;
&lt;li&gt;Так как наша цель стоит в интерактивном взаимодействии пользователем,
повторять эти действия при каждом переходе на другую страницу -
&lt;em&gt;непозволительная роскошь&lt;/em&gt;. Кстати, можно начинать думать и общаться не
в терминах страниц, а в терминах &lt;strong&gt;экранов&lt;/strong&gt;, которые видит
пользователь.&lt;/li&gt;
&lt;li&gt;Для обеспечения этого&amp;nbsp;&lt;strong&gt;JavaScript-клиент&lt;/strong&gt; должен переопределить
стандартные обработчики событий перехода по внутренним ссылкам сайта и
отправки форм. Ему нужно отменить стандартный механизм перехода на
другую страницу и вместо него отправить запрос через &lt;strong&gt;интерфейс
сериализованных данных&lt;/strong&gt;. На основе полученного в ответ сообщения он
меняет какую-то часть загруженного ранее HTML-документа, чтобы он
соответствовал тому &lt;em&gt;экрану&lt;/em&gt;, который ожидал увидеть пользователь. В
итоге пользователь видит в браузере ровно ту же картинку, как если бы он
ввел тот адрес, на который вела нажатая ссылка, или просто нажал на нее
с отключенным JavaScript.&lt;/li&gt;
&lt;li&gt;Важно не сломать при этом поведение браузера: кнопка "назад" должна
работать как обычно, а в адресной строке должны меняться ссылки (это
актуально, например, когда пользователь отправляет содержимое адресной
строки кому-то по почте или через мессенджер).&lt;/li&gt;
&lt;li&gt;При ожидании ответа от сервера стоит эмулировать курсор и иконку
загрузки страницы, чтобы пользователь &lt;em&gt;не паниковал&lt;/em&gt; в случае (пускай и
редком) визуально заметных задержек.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;На резонный вопрос &lt;em&gt;"Почему, собственно, этот трюк обеспечит
интерактивность?"&lt;/em&gt;, ответ хоть и не всегда однозначен, но он все же
есть:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Сериализованные &lt;strong&gt;изменения&lt;/strong&gt; страницы занимают меньший объем, чем
&lt;strong&gt;полный&lt;/strong&gt; HTML со всеми связанными ресурсами, заголовками, версткой
и прочим - &lt;em&gt;значительно меньше данных нужно передавать по сети&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;Как правило, есть возможность держать &lt;strong&gt;постоянное&lt;/strong&gt; соединение
между браузером и интерфейсом сериализованных данных, что позволяет
&lt;em&gt;не делать лишние HTTP-запросы&lt;/em&gt;. Обратная сторона медали - это самое
соединение постоянно же использует часть серверных ресурсов, но есть
способы минимизировать эти издержки.&lt;/li&gt;
&lt;li&gt;Для некоторых действий изменения HTML не требуют ответа сервера и
могут быть сделаны параллельно с отправкой запроса (например
&amp;nbsp;различные вариации на тему +1 или написание комментария, текст
которого можно взять из формы).&lt;/li&gt;
&lt;li&gt;Как правило, можно предсказать наиболее вероятные переходы по
экранам и &lt;em&gt;загрузить необходимые изменения заранее&lt;/em&gt;. Хотя этот
вопрос скорее из области оптимизации.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Таким образом, в большинстве случаев есть техническая возможность
снизить время отклика &amp;nbsp;на действие пользователя с 500-2000 мс в
случае неплохо сделанного статического сайта до 20-200 мс., что
вполне сопоставимо с откликом десктопного приложения.&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Как все это сделать на практике - тема следующей статьи из серии.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="servernaia-chast"&gt;Серверная часть&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;С серверной точки зрения основным отличием является четкое разделение
двух входных точек:&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;HTML-интерфейс&lt;/strong&gt;&amp;nbsp;отдает готовые документы в ответ на HTTP-запросы.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Интерфейс сериализованных данных&lt;/strong&gt;&amp;nbsp;использует какое-то постоянное
соединение, хотя в некоторых случаях целесообразно ограничиться
просто асинхронными HTTP-запросами.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Если для статичных сайтов полное &lt;em&gt;выделение бизнес-логики в отдельные
сервисы&lt;/em&gt; - просто хорошее архитектурное решение, то для интерактивных
сайтов - это практически &lt;strong&gt;необхохимо&lt;/strong&gt;. Иначе придется реализовывать и
поддерживать две копии кода для каждого интерфейса и надеяться, что они
постоянно будут оставаться совместимыми и выдавать одинаковый результат.&lt;/li&gt;
&lt;li&gt;Хорошей практикой является использование какого-то одного протокола
общения между компонентами системы, в частности пользовательских
интерфейсов с сервисами бизнес-логики и последних друг с другом.
Желательно использовать что-то бинарное и с поддержкой разных языков
программирования, хотя если весь проект на одной платформе и не
планирует это менять - можно использовать и стандартный для этой
платформы протокол.&lt;/li&gt;
&lt;li&gt;Чтобы не включать элементы верстки при передаче через интерфейс
сериализованных данных, рекомендую использовать кроссплатформенный
формат HTML-шаблонов. Об этом будет отдельная статья.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Интерфейс сериализованных данных&lt;/strong&gt; при необходимости легко может быть
адаптирован для использования в роли &lt;em&gt;API для сторонних сервисов или
собственных приложений&lt;/em&gt; для мобильных платформ или настольных
компьютеров.&lt;/li&gt;
&lt;li&gt;В целом внутренние сервисы общаются с остальными располагающимися на
серверной части компонентами системы вполне обычным образом.&lt;/li&gt;
&lt;li&gt;В статье про серверную часть подробно будет рассматриваться
использование брокера сообщений для уведомлений пользователей в реальном
времени.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="podvodim-itogi"&gt;Подводим итоги&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Глобальная интерактивность&lt;/em&gt; сайта требует использования достаточно
    сложного и комплексного JavaScript-клиента и создания
    дополнительного более легковесного внешнего инетрфейса на серверной
    части.&lt;/li&gt;
&lt;li&gt;По-настоящему &lt;em&gt;мгновенной&lt;/em&gt; реакцией сайта смогут насладиться лишь
    пользователи с &lt;strong&gt;современным браузером&lt;/strong&gt; и относительно &lt;strong&gt;широким
    интернет-каналом&lt;/strong&gt;. Из-за возможных сетевых задержек или
    особенностей устаревших браузеров эффект мгновенного перехода все же
    может теряться, но при должном тестировании реально добиться
    нормального поведения сайта и в таких ситуациях. Хотя зачастую
    "проваливание" до обычного режима статичных страниц в подобных
    ситуациях - вполне резонное решение.&lt;/li&gt;
&lt;li&gt;Архитектура серверной части проекта в большинстве случаев не требует
    существенных изменений. Хотя если в ней все было хаотично и не
    продумано, то создание интерактивного клиента может послужить
    неплохим поводом пересмотреть и привести в порядок и её.&lt;/li&gt;
&lt;li&gt;Кроме очевидной потребности в использовании JavaScript для клиента,
    особых ограничений на используемые технологии и языки
    программирования, обсуждаемая схема не накладывает.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="card green"&gt;
&lt;p&gt;&lt;div class="card-content white-text"&gt;
Эта статья - первая в &lt;a class="green-text text-lighten-4" href="https://www.insight-it.ru/interactive/"&gt;серии про Интерактивные сайты&lt;/a&gt;, автор - &lt;a class="green-text text-lighten-4" href="https://www.insight-it.ru/goto/b03d9116/" rel="nofollow" target="_blank" title="http://blinkov.ru"&gt;Иван&amp;nbsp;Блинков&lt;/a&gt;, основано на личном опыте.
До встречи &lt;a class="green-text text-lighten-4" href="/feed/"&gt;на страницах Insight IT&lt;/a&gt;!
&lt;/div&gt;&lt;/p&gt;
&lt;/div&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Иван Блинков</dc:creator><pubDate>Wed, 04 Apr 2012 01:05:00 +0400</pubDate><guid>tag:www.insight-it.ru,2012-04-04:interactive/2012/arkhitektura-interaktivnykh-sajjtov/</guid><category>архитектура</category><category>Интерактивные сайты</category><category>клиентская часть</category><category>Масштабируемость</category><category>серверная часть</category><category>схема</category></item></channel></rss>