<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" version="2.0"><channel><atom:link rel="hub" href="http://tumblr.superfeedr.com/" xmlns:atom="http://www.w3.org/2005/Atom"/><description>Когда в информационных технологиях есть что-то хорошее.</description><title>Саклесс</title><generator>Tumblr (3.0; @sucklessru)</generator><link>http://suckless.ru/</link><item><title>Поменялся адрес RSS</title><description>&lt;p&gt;У нас поменялся &lt;a href="http://suckless.ru/rss"&gt;адрес RSS-фида&lt;/a&gt;. Пожалуйста, проверьте его в своих читалках. Кстати, у нас есть ещё и твиттер: &lt;a href="http://twitter.com/suckless666"&gt;@suckless666&lt;/a&gt;.&lt;/p&gt;</description><link>http://suckless.ru/post/12372583557</link><guid>http://suckless.ru/post/12372583557</guid><pubDate>Sat, 05 Nov 2011 20:57:38 +0500</pubDate><category>suckless</category><category>rss</category><dc:creator>eveel</dc:creator></item><item><title>Собственная тучка на OpenNebula</title><description>&lt;p&gt;&lt;strong&gt;Облачные вычисления&lt;/strong&gt; — самый модный и порванный баззворд в сфере IT за последние  несколько лет. Даже агенство Gartner в &lt;a href="http://www.gartner.com/it/page.jsp?id=1826214"&gt;своём ежегодном отчёте&lt;/a&gt; второй год подряд упоминает этот термин, обозначая одну из стратегических технологий. При всём ажиотаже, нет ничего плохого в том, чтобы отделить зёрна от плевел, и создать свою маленькую и уютную «тучку».&lt;/p&gt;

&lt;p&gt;Итак, давайте понимать облачные вычисления как технологию предоставления ресурсов по требованию пользователя, контролирующую весь их жизненный цикл: создание, использование, модификацию, учёт и уничтожение.&lt;/p&gt;

&lt;p&gt;Часто к «облакам» навешивают ярлык какой-либо бизнес-модели: IaaS, PaaS, SaaS, etc. Я расскажу про развёртывание полноценного &lt;a href="http://ru.wikipedia.org/wiki/IaaS"&gt;IaaS-облака&lt;/a&gt; в совершенно реальном месте — &lt;a href="http://www.imm.uran.ru"&gt;Институте математики и механики УрО РАН&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Так сложилось, что нам понадобилась инфраструктура, позволяющая быстро запустить пачку виртуальных машин, а также быстро её удалить и развернуть пачку других виртуальных машин. Ещё в нашем ЦОД часто ломаются работающие сервера и нередко покупаются новые. Встал вопрос о выборе связующего ПО.&lt;/p&gt;

&lt;p&gt;Мы долго выбирали между модным нынче &lt;a href="http://www.openstack.org/"&gt;OpenStack&lt;/a&gt; и менее знаменитой &lt;a href="http://opennebula.org/"&gt;OpenNebula&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Главной причиной отказа от OpenStack было то, что мне он показался довольно неудачной попыткой слепить нечто рабочее из обломков существующих «облачных» решений. В итоге вместо унифицированного инструментария мы имеем дело с разрозненными останками разношёрстных «облачных» решений, что сильно затрудняет конфигурацию, поддержку и повседневную работу с системой.&lt;/p&gt;

&lt;p&gt;Было решено использовать OpenNebula, и сейчас видно, что решение оказалось правильным.&lt;/p&gt;

&lt;p&gt;Ядро OpenNebula написано на C++ и занимается исключительно управлением состоянием системы. Вокруг ядра имеется множество утилит, написанных на Ruby и Shell, которые решают различные задачи: управление пользователями, контроль виртуальных машин, хранилища образов, и т. д.&lt;/p&gt;

&lt;p&gt;OpenNebula разделяет понятие управляющей машины и узла «облачного» кластера. Очевидно, управляющая машина отдаёт узлам кластера команды на выполнение (например, запустить VM под гипервизором Xen), а сами узлы всего лишь выполняют полученные команды. Для обмена данными OpenNebula использует протокол SSH с перенаправлением потоков ввода-вывода и авторизацией при помощи секретных ключей. Программное обеспечение OpenNebula ставится только на управляющие машины.&lt;/p&gt;

&lt;p&gt;Сегодня OpenNebula поддерживает такие гипервизоры, как KVM, Xen и Hyper-V. В качестве системы хранения образов виртуальных машин поддерживается NFS, MooseFS, а также тупое пробрасывание образов через SCP. Увы, поддержка клёвого хранилища OpenStack Swift отсутствует, потому что все операции в OpenNebula выполняются при помощи библиотеки &lt;a href="http://libvirt.org/"&gt;libvirt&lt;/a&gt;, которая пока не способна работать со Swift.&lt;/p&gt;

&lt;p&gt;Мы развернули свою «тучку» из остатков старого вычислительного кластера, умеющих аппаратную виртуализацию. В качестве гипервизора выбрали модный KVM, а данные решено было хранить в файловой системе NFS на имеющемся &lt;a href="http://ru.wikipedia.org/wiki/NAS"&gt;NAS&lt;/a&gt; от EMC².&lt;/p&gt;

&lt;p&gt;Можно представить структуру «облака» графически:&lt;/p&gt;

&lt;p&gt;&lt;img src="http://media.tumblr.com/tumblr_lu5h8pOcat1qbiia7.png" alt="Структура облака ИММ УрО РАН на основе OpenNebula"/&gt;&lt;/p&gt;

&lt;p&gt;После решения оргвопросов:&lt;/p&gt;

&lt;ol&gt;&lt;li&gt;выделили отдельную управляющую машину с CentOS 6 на борту, где запустили демон &lt;em&gt;oned&lt;/em&gt;, Web-интерфейс &lt;a href="http://opennebula.org/documentation:rel3.0:sunstone"&gt;Sunstone&lt;/a&gt; и сервер MySQL для хранения состояния системы;&lt;/li&gt;
&lt;li&gt;забрали у старого вычислительного кластера три сервера с поддержкой аппаратной виртуализации, установили туда Scientific Linux 6.1 и отключили SELinux, который требует настройки и мешает работе KVM;&lt;/li&gt;
&lt;li&gt;создали пары SSH-ключей, при помощи которых машины могут «ходить» друг к другу от пользователя &lt;em&gt;oneadmin&lt;/em&gt; без пароля;&lt;/li&gt;
&lt;li&gt;на каждом узле кластера установили сетевой мост, позволяющий каждой виртуальной машине быть полноценным членом ЛВС ИММ УрО РАН;&lt;/li&gt;
&lt;li&gt;сконфигуровали в &lt;em&gt;oned&lt;/em&gt; политику «если VM упала, то пытаться перезапустить её на другом узле»;&lt;/li&gt;
&lt;li&gt;закрыли подсеть «облака» брандмауэром, дав доступ к конкретным машинам и портам только через сетевой шлюз;&lt;/li&gt;
&lt;li&gt;создали собственный образ Scientific Linux, заточенный на быстрый запуск внутри OpenNebula в качестве VM;&lt;/li&gt;
&lt;li&gt;запустили на его основе тестовую машину с полуработающим морфологическим анализатором &lt;a href="http://myaso.eveel.ru"&gt;myaso&lt;/a&gt;.&lt;/li&gt;
&lt;/ol&gt;&lt;p&gt;Таким образом, получилась полноценная, простая в использовании и масштабируемая «облачная» инфраструктура с поддержкой живых миграций виртуальных машин, мониторингом состояния кластера, наличием мер по обеспечению отказоустойчивости, а также многими другими радостями, о которых можно прочесть в &lt;a href="http://opennebula.org/documentation:rel3.0"&gt;документации&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Как я уже говорил, всё вышеперечисленное достигается благодаря тому, что система не переусложнена, все виртуальные машины хранятся на независимом NFS-томе, а взаимодействие управляющей машины с узлами кластера ведётся через надёжный SSH:&lt;/p&gt;

&lt;p&gt;&lt;img src="http://media.tumblr.com/tumblr_lu5hbwQ6iG1qbiia7.png" alt="Логическое представление облака ИММ УрО РАН на основе OpenNebula"/&gt;&lt;/p&gt;

&lt;p&gt;Напоследок, приложу скриншот Sunstone. Как видно, прямо сейчас у нас практически нет нагрузки, и балансировщик запихал две VM на третий сервер. В случае выхода его из строя, виртуальные машины мгновенно перенесутся на другие узлы и продолжат свою работу без каких-либо заметных проблем:&lt;/p&gt;

&lt;p&gt;&lt;img src="http://media.tumblr.com/tumblr_lu5gk63VII1qbiia7.png" alt="OpenNebula Sunstone"/&gt;&lt;/p&gt;</description><link>http://suckless.ru/post/12334617154</link><guid>http://suckless.ru/post/12334617154</guid><pubDate>Sat, 05 Nov 2011 00:35:00 +0500</pubDate><category>cloud</category><category>opennebula</category><dc:creator>eveel</dc:creator></item><item><title>В Контакте вместе с Ruby</title><description>&lt;p&gt;На сегодняшний день скорость развития рынка Web-приложений крайне велика. Относительно новым и пока не до конца сформировавшимся рынком является рынок приложений в социальных сетях. Аудитория социальных сетей растёт. Количество денег, которые тратят пользователи, увеличивается. Интерес к получению дохода путём создания приложений, очевиден. Самой популярной и динамично развивающейся социальной сетью в России является &lt;a href="http://vkontakte.ru"&gt;В Контакте&lt;/a&gt;. Само собой, она предоставляет богатый API, функциональность которого расширяется практически каждый месяц.&lt;/p&gt;

&lt;p&gt;Сегодня в Интернете полно библиотек, которые позволяют как-то работать со вконтактом. Часть из них парсит страницы, другая работает напрямую с API. Первые сразу отпадают, если вы хотите заработать на своём приложении, а вторые часто забрасываются авторами или не справляются с темпами развития социальной сети.&lt;/p&gt;

&lt;p&gt;Примеры:&lt;/p&gt;

&lt;ol&gt;&lt;li&gt;&lt;a href="https://github.com/kavu/userapi-ruby"&gt;userapi-ruby&lt;/a&gt; — заброшено;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/vovka/VK-Ruby-API"&gt;vk-ruby-api&lt;/a&gt; — является надстройкой над данными пользователя, код странный;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/PavelTyk/vkontakte_api"&gt;vkontakte_api&lt;/a&gt; — плагин для Rails (не реализован в виде engine), заброшен;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/bublik/vkontakte"&gt;bublik/vkontakte&lt;/a&gt; — заброшен;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/mamantoha/vkontakte"&gt;mamantoha/vkontakte&lt;/a&gt; — живой проект, является библиотекой исключительно для клиентских приложений. Увы, для авторизации парсит страницы, что запрещено правилами использования в Контакте.&lt;/li&gt;
&lt;/ol&gt;&lt;p&gt;Поскольку так сложилось, что на данный момент не существует функциональной и корректной API-обёртки В Контакте для Ruby, я представляю собственное решение — &lt;a href="https://github.com/zinenko/vk-ruby"&gt;vk-ruby&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Я постарался предусмотреть и избежать многих узких мест, поэтому vk-ruby:&lt;/p&gt;

&lt;ol&gt;&lt;li&gt;прост в расширении: список всех возможных методов API находятся в YAML-файлах, которые легко модифицировать, форкнув проект на GitHub;&lt;/li&gt;
&lt;li&gt;включает в себя все три типа приложений В Контакте:

&lt;ul&gt;&lt;li&gt;&lt;em&gt;serverside&lt;/em&gt; — «подключенный» сайт;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;standalone&lt;/em&gt; — мобильное или desktop-приложение;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;secure&lt;/em&gt; — защищенный сервер вашего приложения.&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ol&gt;&lt;p&gt;Что нужно, чтобы начать работать с API В Контакте?&lt;/p&gt;

&lt;ol&gt;&lt;li&gt;первым делом, &lt;a href="http://vkontakte.ru/developers.php"&gt;зарегистрировать&lt;/a&gt; собственное приложение и получить необходимые ключи;&lt;/li&gt;
&lt;li&gt;ознакомиться со &lt;a href="http://vkontakte.ru/developers.php?o=-1&amp;amp;p=%D0%90%D0%B2%D1%82%D0%BE%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D1%8F&amp;amp;s=0"&gt;способами авторизации&lt;/a&gt; приложения В Контакте;&lt;/li&gt;
&lt;li&gt;установить gem &lt;a href="https://rubygems.org/gems/vk-ruby"&gt;vk-ruby&lt;/a&gt;.&lt;/li&gt;
&lt;/ol&gt;&lt;h3&gt;Начало работы&lt;/h3&gt;

&lt;p&gt;Cоздадим приложение необходимого типа:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;serverside = VK::Serverside.new :app_id =&amp;gt; APP_ID, :app_secret =&amp;gt; APP_SECRET
# или
standalone = VK::Standalone.new :app_id =&amp;gt; APP_ID
# или
secure = VK::Secure.new :app_id =&amp;gt; APP_ID, :app_secret =&amp;gt; APP_SECRET
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Здесь и далее, константы &lt;code&gt;APP_ID&lt;/code&gt; и &lt;code&gt;APP_SECRET&lt;/code&gt; — ключи, которые вы получите при регистрации приложения. Далее необходимо авторизоваться.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;serverside.authorize(CODE) 
# или
standalone.authorize(CODE) 
# или
secure.authorize
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Информация о параметре &lt;code&gt;CODE&lt;/code&gt; приведена в документации о способах авторизации. Кстати, теперь мы можем «дёргать» необходимые методы.&lt;/p&gt;

&lt;p&gt;Например, посмотрим, установил ли пользователь наше приложение:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;serverside.isAppUser # =&amp;gt; 1
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Установил. Попробуем выполнить поиск по аудиозаписям:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;tracks = serverside.audio.search(:q =&amp;gt; 'Rammstein')
unread.shift # =&amp;gt; количество треков
tracks.map do |track|
  track['title']
end # =&amp;gt; [ 'Mutter', 'Bang Bang', 'Du Hast', ... ]
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Standalone-приложениям предлагается поддержка &lt;a href="http://vkontakte.ru/developers.php?o=-1&amp;amp;p=%D0%A0%D0%B0%D1%81%D1%88%D0%B8%D1%80%D0%B5%D0%BD%D0%BD%D1%8B%D0%B5_%D0%BC%D0%B5%D1%82%D0%BE%D0%B4%D1%8B_API&amp;amp;s=0"&gt;расширенных методов&lt;/a&gt;. Например, доступ к личным сообщениям пользователя:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;unread = standalone.messages.get :filters =&amp;gt; '1'
puts unread.shift # =&amp;gt; количество сообщений
unread.map { |msg| msg['title'] } # =&amp;gt; [ 'заголовок1', 'заголовок2', ... ]
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Secure-приложения получают доступ как к обычным и расширенным методам API, так и к административным методам. Например, возможность отправлять пользователям уведомления.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;secure.secure.sendNotification(
  :message =&amp;gt; 'Привет!', 
  :timestamp =&amp;gt; Time.now.to_i, 
  :random =&amp;gt; rand(1000)
)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Легко заметить, код получается довольно простым и аккуратным. Всё что нужно для работы — это ознакомится со &lt;a href="http://vkontakte.ru/developers.php?oid=-1&amp;amp;p=%D0%9E%D0%BF%D0%B8%D1%81%D0%B0%D0%BD%D0%B8%D0%B5_%D0%BC%D0%B5%D1%82%D0%BE%D0%B4%D0%BE%D0%B2_API"&gt;списком&lt;/a&gt; методов API.&lt;/p&gt;

&lt;p&gt;Конечно, &lt;a href="https://rubygems.org/gems/vk-ruby"&gt;vk-ruby&lt;/a&gt; легко интегрировать в любое приложение. Ruby on Rails, Sinatra, Padrino — не имеет значения, хоть в другой gem. В качестве &lt;a href="https://github.com/zinenko/social_app"&gt;небольшого примера&lt;/a&gt; я написал простое Web-приложение на микрофреймворке Sinatra.&lt;/p&gt;

&lt;p&gt;Огромным камнем в огороде вконтакта является способ авторизации клиентских приложений, который предполагает встраивание браузера и «ручное» заполнение формы авторизации. Это действительно большая проблема, которая не решилась даже с переходом В Контакте на OAuth 2.0. В качестве частичного решения, я написал утилиту &lt;a href="https://github.com/zinenko/vk-console"&gt;vk-console&lt;/a&gt;, которая авторизуется в системе, выполняя парсинг страниц.&lt;/p&gt;

&lt;p&gt;Я старался сделать данный инструмент простым и удобным, но как и любому проекту поддержка будет не лишней! Если знаете как его улучшить, нашли баг или ещё что то, то пишите, &lt;a href="https://github.com/zinenko/vk-ruby"&gt;форкайте&lt;/a&gt; — буду очень рад.&lt;/p&gt;</description><link>http://suckless.ru/post/10080778911</link><guid>http://suckless.ru/post/10080778911</guid><pubDate>Sun, 11 Sep 2011 20:07:00 +0600</pubDate><category>ruby</category><category>vkontakte</category><dc:creator>izinenko</dc:creator></item><item><title>Ruby ♥ ØMQ (Fuck You, Erlang!)</title><description>&lt;p&gt;Сложные системы состоят из множества компонент, между которыми возникает необходимость организовывать взаимодействие, часто сводящееся к передаче сообщений. Разные команды разработчиков решали эту задачу по-разному. Итак, как же в рамках экосистемы Ruby можно решить эту задачу?&lt;/p&gt;

&lt;ul&gt;&lt;li&gt;Если посмотреть на наш постер с &lt;a href="http://balcone.eveel.ru/post/6144232810/opencirrus2011"&gt;Open Cirrus 2011&lt;/a&gt;, то можно заметить, что мы в первой черновой реализации нашего сервиса использовали фреймворк Gearman и официальный гем &lt;a href="http://rubygems.org/gems/gearman-ruby"&gt;gearman-ruby&lt;/a&gt;. Gearman создан ребятами из LiveJournal для связывания всех сервисов своей платформы в единое целое. К сожалению, архитектура «клиент → сервер задач → обработчик» не всегда адекватна задаче: например, просто так связать точку &lt;em&gt;А&lt;/em&gt; с точкой &lt;em&gt;Б&lt;/em&gt; не получится.&lt;/li&gt;
&lt;li&gt;Ребята из GitHub сочинили протокол BERT на основе терминов &lt;em&gt;(terms)&lt;/em&gt; языка Erlang и связали свои сервисы при помощи фреймворка &lt;a href="https://github.com/mojombo/ernie"&gt;Ernie&lt;/a&gt;, написанного на Ruby и Erlang, и реализующего протокол BERT-RPC. Достаточно посмотреть, как работает этот инструмент, чтобы назвать статью “Fuck You, Erlang!”, как это было сделано ранее и повлекло за собой кучу справедливого непонимания со стороны читателей. Erlang — отличный язык, OTP — крутая платформа. Ernie, построенный на их основе, кажется ужасно неадекватным решением.&lt;/li&gt;
&lt;li&gt;На фоне существующих решений выделяется библиотека &lt;a href="http://www.zeromq.org"&gt;ØMQ&lt;/a&gt;: The Intelligent Transport Layer. Несмотря на наличие суффика “mq” в названии, ØMQ не является очередью сообщений в привичном для нас виде. Кстати, авторы ØMQ (iMatix Corporation) в своё время разработали протокол AMQP и сейчас на основе предыдущего опыта постарались максимально приблизиться к удобству работы с сообщениями в Erlang/OTP.&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;&lt;abbr title="ZeroMQ"&gt;ØMQ&lt;/abbr&gt; — очень эффективная и навороченная &lt;em&gt;библиотека&lt;/em&gt; для организации обмена сообщениями, не привязанная к конкретному транспортному уровню. Внутри одного процесса можно устроить обмен сообщениями между потоками поверх UNIX-сокетов или внутрипроцессового IPC, а удалённые приложения могут «разговаривать» друг с другом поверх протоколов TCP или UDP. Более того, ØMQ ориентирована на верхний уровень модели OSI, поэтому даже сообщение в полмегабайта переданное из пункта &lt;em&gt;А&lt;/em&gt; в пункт &lt;em&gt;Б&lt;/em&gt; придёт в целости и сохранности.&lt;/p&gt;

&lt;p&gt;Внутри ØMQ реализованы традиционные паттерны построения сетевых приложений: парадигма «запрос-ответ», «издатель-подписчик», механизмы маршрутизации сообщений, построения отказоустойчивых систем и многое другое, описанное в &lt;a href="http://zguide.zeromq.org/"&gt;гайде&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Итак, главное для нас — сообщения. Сообщениями обмениваются изолированные приложения при помощи специальных сокетов в контексте ØMQ.&lt;/p&gt;

&lt;p&gt;Рассмотрим более-менее прикладную задачу. Пусть имеется Web-приложение, при помощи которого пользователи обрабатывают что-то большое. Это самое «что-то большое» должно обрабатываться и отдаваться клиентам, не вынуждая систему отказывать им в обслуживании из-за высокой нагруженности. Логично разделить приложение на две части (как показано на рисунке):&lt;/p&gt;

&lt;ul&gt;&lt;li&gt;frontend: Web-интерфейс и трекер заявок;&lt;/li&gt;
&lt;li&gt;backend: обработчик заявок.&lt;/li&gt;
&lt;/ul&gt;&lt;p style="text-align:center"&gt;&lt;img src="http://media.tumblr.com/tumblr_lm87es0rFT1qbiia7.png" alt="Архитектура системы"/&gt;&lt;/p&gt;

&lt;ul&gt;&lt;li&gt;Frontend работает с конечным пользователем по протоколу HTTP. С точки зрения механизма взаимодействия это очевидный «запрос-ответ», причём не имеющий отношения к ØMQ.&lt;/li&gt;
&lt;li&gt;Общение Frontend и Backend ведётся посредством двух UNIX-сокетов: &lt;code&gt;pub.sock&lt;/code&gt; и &lt;code&gt;pull.sock&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Когда Frontend получает заявку, он передаёт её в Backend с использованием механизма push-pull, то есть Backend постоянно слушает данные, поступающие от Frontend и немедленно реагирует на их появление.&lt;/li&gt;
&lt;li&gt;Как только Backend заканчивает обрабатывать заявку, он сигнализирует об этом Frontend при помощи механизма publish-subscribe, то есть заранее подключенный Frontend (подписчик) «висит» на Pub-сокете и через некоторое время получает данные от Backend.&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;Возьмём Sinatra и биндинги к ØMQ. Кстати, из-за особенностей реализации потоков в MRI, следует использовать версию Ruby 1.9 и неофициальный гем &lt;a href="http://rubygems.org/gems/ffi-rzmq"&gt;ffi-rzmq&lt;/a&gt;. Официальный гем &lt;a href="http://rubygems.org/gems/zmq"&gt;zmq&lt;/a&gt; «подвешивает» интерпретатор при завершении работы.&lt;/p&gt;

&lt;p&gt;В качестве нагрузки будем вычислять CRC32-хэш переданной строки и вызывать &lt;code&gt;sleep()&lt;/code&gt; на несколько секунд внутри бэкэнда, чтобы дать видимость сложной вычислительной задачи. Обмениваться данными будем в формате JSON при помощи библиотеки Yajl.&lt;/p&gt;

&lt;p&gt;Итак, &lt;a href="https://gist.github.com/1007093#file_backend.rb"&gt;код бэкэнда&lt;/a&gt;. Вообще, я старался комментировать код, хотя проблем при чтении быть не должно: всё очень просто.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;loop do
  begin
    logger.info(recv = pull.recv_string)
    data = Yajl.load(recv).first

    # imagine that we're processing this piece of crap
    crc32 = Zlib.crc32(data)
    sleep 2

    rep = [ data, crc32 ].to_json
    pub.send_string rep

    logger.info(rep)
  rescue Interrupt
    break
  end
end
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Теперь &lt;a href="https://gist.github.com/1007093#file_frontend.rb"&gt;код фронтэнда&lt;/a&gt;. Это вполне себе обычное приложение на микрофреймворке Sinatra.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;get '/' do
  # index template should be saved at views/index.erb
  erb :index
end

post '/' do
  data = params['data'] || ''
  if data.strip.empty?
    return redirect '/'
  end

  $queries[data] = nil

  # send query to backend
  push.send_string [data].to_json

  redirect '/'
end
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Кстати, не забываем положить &lt;a href="https://gist.github.com/1007093#file_index.erb"&gt;файл с ERb-шаблоном&lt;/a&gt; страницы по адресу &lt;code&gt;views/index.erb&lt;/code&gt; относительно остальных файлов.&lt;/p&gt;

&lt;p&gt;Итак, для начала запускаем &lt;code&gt;backend.rb&lt;/code&gt;, который забивает на себя UNIX-сокеты и готовится обрабатывать данные. После этого запускаем &lt;code&gt;frontend.rb&lt;/code&gt; и заходим браузером по адресу &lt;a href="http://localhost:4567"&gt;http://localhost:4567&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Как видно, если добавить в очередь несколько заявок подряд, то они выполнятся последовательно. Таким образом, всю работу по доставке данных от фронтэнда к бэкэнду и обратно выполнила ØMQ, за что ей большое спасибо. У меня это выглядит примерно вот так:&lt;/p&gt;

&lt;p style="text-align:center"&gt;&lt;img src="http://media.tumblr.com/tumblr_lpmnnqvcsE1qbiia7.png" alt="Ruby ♥ Sinatra + ØMQ"/&gt;&lt;/p&gt;

&lt;p&gt;В качестве домашнего задания можно прочесть &lt;a href="http://zguide.zeromq.org/"&gt;гайд&lt;/a&gt; и попробовать добавить к фронтэнду возможность работы с несколькими бэкэндами, балансировки нагрузки между ними, в результате получив функциональный аналог Gearman.&lt;/p&gt;

&lt;p&gt;Приведённый в статье пример может показаться слишком простым. Это действительно так, и он не показывает даже верхушку айсберга возможностей ØMQ, но исключительно базовые вещи. В качестве материала для дальнейшего чтения могу категорически порекомендовать две шикарные статьи Ilya Grigorik [&lt;a href="http://www.igvita.com/2010/09/03/zeromq-modern-fast-networking-stack/"&gt;1&lt;/a&gt;,&lt;a href="http://www.igvita.com/2010/11/17/routing-with-ruby-zeromq-devices/"&gt;2&lt;/a&gt;].&lt;/p&gt;</description><link>http://suckless.ru/post/6151680466</link><guid>http://suckless.ru/post/6151680466</guid><pubDate>Sat, 04 Jun 2011 02:43:00 +0600</pubDate><category>ruby</category><category>erlang</category><category>zeromq</category><category>networking</category><dc:creator>eveel</dc:creator></item><item><title>Ruby Parallelism Benchmarking</title><description>&lt;p&gt;Посмотрим, насколько всё плохо в Ruby с параллелизмом: юзабельны ли треды? Возможно ли вообще в Ruby параллельное программирование? Опыты проведём на огромном компьютере &lt;a href="http://balcone.eveel.ru/post/1462671772/pw850"&gt;Fujitsu-Siemens PRIMEPOWER 850&lt;/a&gt; с установленным Sun Solaris 9.&lt;/p&gt;

&lt;p&gt;Будем одновременно считать суммы первых &lt;em&gt;N&lt;/em&gt; членов разложения нескольких &lt;em&gt;S&lt;/em&gt; сходящихся числовых рядов, затем эти суммы сложим.&lt;/p&gt;

&lt;p&gt;Естественно, такая задача запросто решается при помощи парадигмы &lt;a href="http://ru.wikipedia.org/wiki/MapReduce"&gt;MapReduce&lt;/a&gt;. Для работы у нас есть восемь процессоров SPARC64 по тысяче мегагерц каждый и тридцать два гигабайта оперативной памяти на всю систему.&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;li&gt;последовательное выполнение программы.&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;Для этого дела я написал достаточно простой бенчмарк: &lt;a href="https://gist.github.com/664853"&gt;parallel-bench.rb&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Вместо того, чтобы обсуждать код, лучше поговорить сразу о &lt;a href="https://gist.github.com/664899"&gt;результатах измерений&lt;/a&gt;. Для пущей наглядности я представил их в виде гистограммы. Чем короче столбик, тем лучше результат.&lt;/p&gt;

&lt;p style="text-align:center"&gt;&lt;img src="http://media.tumblr.com/tumblr_lpmdkhA5qU1qbiia7.png" alt="Визуализация результата"/&gt;&lt;/p&gt;

&lt;p&gt;Легко сделать выводы.&lt;/p&gt;

&lt;ul&gt;&lt;li&gt;Реализация Thread в MRI 1.8.7 и 1.9.2 сделана через &lt;a href="http://en.wikipedia.org/wiki/Global_Interpreter_Lock"&gt;GIL&lt;/a&gt; и на самом деле все Ruby-треды выполняются последовательно на одном процессоре, с огромным оверхедом. Треды в Ruby не просто неэффективны, они ужасно вредны.&lt;/li&gt;
&lt;li&gt;При использовании процессов, параметр &lt;em&gt;CPU&lt;/em&gt; влияет на число воркеров, выделяемых на задачу, отчего производительность повышается примерно в &lt;em&gt;CPU&lt;/em&gt; раз. В целом, вариант на процессах гораздо шустрее.&lt;/li&gt;
&lt;li&gt;Почему при &lt;code&gt;CPU=1&lt;/code&gt; вариант с процессами оказался самым медленным? Дело в том, что после каждого этапа вычислений, создаётся новый процесс вычисления следующего члена числового ряда и убивается отработавший. Куча дополнительного времени тратися впустую.&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;Итак, старый суперкомпьютер подтвердил очевидную вещь: преимущества параллельного программирования заметны лишь в том случае, когда время решения каждого этапа исходной задачи несопоставимо больше, чем временные затраты на обеспечение параллелизма. Когда такое условие выполняется, игра чертовски стоит свеч!&lt;/p&gt;

&lt;p&gt;К сожалению, выбросить GIL из MRI не представляется возможным. Сегодня все мечты о «настоящем параллелизме» возлагаются на &lt;a href="http://jruby.org"&gt;JRuby&lt;/a&gt;, а завтра — на &lt;a href="http://rubini.us"&gt;Rubinius&lt;/a&gt;.&lt;/p&gt;</description><link>http://suckless.ru/post/1490524178</link><guid>http://suckless.ru/post/1490524178</guid><pubDate>Sat, 06 Nov 2010 02:44:00 +0500</pubDate><category>ruby</category><category>concurrency</category><category>parallelism</category><category>map-reduce</category><category>benchmark</category><dc:creator>eveel</dc:creator></item><item><title>QR коды на Ruby и GD2</title><description>&lt;p&gt;Библиотека &lt;a href="http://www.imagemagick.org/script/index.php"&gt;ImageMagick&lt;/a&gt; применяется практически в любом Web-приложении (на языке Ruby) для обработки и композитинга изображений, рисования различных графических примитивов, и так далее.&lt;/p&gt;

&lt;p&gt;Если говорить о применении этой библиотеки в экосистеме Ruby, то сразу на ум приходит гем &lt;a href="http://rubygems.org/gems/rmagick"&gt;RMagick&lt;/a&gt;, который мало того, что имеет просто невероятно неудобное API, так его использование обходится дороже, чем тупой фоновый запуск отдельных программ, входящих в пакет ImageMagick. Плюс, иногда его требовательность к версиям установленных в системе библиотек способна поразить даже самых лояльных разработчиков.&lt;/p&gt;

&lt;p&gt;Ясен перец, что порой возникают задачи, где вся такая мощь и тяжесть ImageMagick не требуется и можно обойтись более гуманными средствами.&lt;/p&gt;

&lt;p&gt;Думаю, большинству PHP-разработчиков хорошо знакома достаточно милая библиотека &lt;a href="http://www.boutell.com/gd/"&gt;GD2&lt;/a&gt;. Среди Ruby-разработчиков она не пользуется большой популярностью, и это весьма грустно, ведь она способна достойно решать основные задачи работы с растровой графикой.&lt;/p&gt;

&lt;p&gt;Существует гем &lt;a href="http://rubygems.org/gems/gd2-ffij"&gt;gd2-ffij&lt;/a&gt;. Последняя его версия вышла в 2010 году, но осмотр кода показал, что развитие библиотеки остановилось отнюдь не потому, что всё очень плачевно. Дело в том, что требуемые от библиотеки задачи решены в необходимом и достаточном виде.&lt;/p&gt;

&lt;p&gt;Легко показать, что вывести какое-нибудь изображение с помощью GD2 не так уж тяжело. Я тут накидал простенькое приложение на Sinatra, которое рисует очень красивые и приятные глазу QR-коды с заданным текстом: &lt;a href="https://github.com/eveel/quoreux"&gt;https://github.com/eveel/quoreux&lt;/a&gt; :)&lt;/p&gt;

&lt;p&gt;Код, который рендерит и сохраняет результирующее изображение выглядит достаточно неплохо:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;image.draw do |canvas|
  qr.modules.each_index do |y|
    qr.modules.each_index do |x|
      canvas.color = qr.is_dark(y, x) ? dark : bright
      canvas.rectangle(x * settings.cell_width,
                       y * settings.cell_width,
                 (x + 1) * settings.cell_width,
                 (y + 1) * settings.cell_width, true)
      end
    end
  image.export image_path
end
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Результат работы всего приложения выглядит примерно так:&lt;/p&gt;

&lt;p&gt;&lt;img src="http://media.tumblr.com/tumblr_lpm9s3wqxP1qbiia7.png" alt="Quoreux"/&gt;&lt;/p&gt;

&lt;p&gt;Как видно, задача решена легко, с минимальными затратами ресурсов системы и человеческого времени, а значит, что иногда лучше думать, чем хвататься за ImageMagick.&lt;/p&gt;

&lt;p&gt;Меня огорчает лишь слабая поддержка GD2 со стороны Ruby-сообщества. Интересно, с чем это связано?&lt;/p&gt;</description><link>http://suckless.ru/post/1407624725</link><guid>http://suckless.ru/post/1407624725</guid><pubDate>Tue, 05 Oct 2010 00:00:00 +0600</pubDate><category>ruby</category><category>graphics</category><category>imagemagick</category><category>gd2</category><category>qr-code</category><dc:creator>eveel</dc:creator></item><item><title>Y-комбинатор поможет</title><description>&lt;p&gt;Мы знаем, что λ-исчисление лишено поддержки рекурсии. Также мы знаем, что использование λ-функций часто помогает сделать запись программы красивее и лаконичнее. В любом случае, возникают ситуации, когда достижению этой благородной цели мешает невозможность сделать рекурсивный вызов λ-функции.&lt;/p&gt;

&lt;p&gt;Здесь нам поможет &lt;a href="http://ru.wikibooks.org/wiki/%D0%9A%D0%BE%D0%BC%D0%B1%D0%B8%D0%BD%D0%B0%D1%82%D0%BE%D1%80%D1%8B_%E2%80%94_%D1%8D%D1%82%D0%BE_%D0%BF%D1%80%D0%BE%D1%81%D1%82%D0%BE!"&gt;Y-комбинатор&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Итак, я не в состоянии дать &lt;a href="http://traditio.ru/wiki/%D0%9A%D0%BE%D0%BC%D0%B1%D0%B8%D0%BD%D0%B0%D1%82%D0%BE%D1%80_Y"&gt;определение&lt;/a&gt;, выводы и &lt;a href="http://ru.wikipedia.org/wiki/%D0%9A%D0%BE%D0%BC%D0%B1%D0%B8%D0%BD%D0%B0%D1%82%D0%BE%D1%80%D0%BD%D0%B0%D1%8F_%D0%BB%D0%BE%D0%B3%D0%B8%D0%BA%D0%B0"&gt;основы&lt;/a&gt; комбинаторной логики, потому что Саклесс ни разу не об этом. Несмотря на это, следует вкратце рассказать об этом комбинаторе.&lt;/p&gt;

&lt;p&gt;Комбинатор Y помимо его названия с латинской (или какой там?) буквой “Y” называют «парадоксальным», благодаря его связи с самоотносимостью. Это свойство самоотносимости позволяет нам реализовать рекурсию над лямбда-исчислением. Мило, не правда ли?&lt;/p&gt;

&lt;p&gt;Итак, реализовать это можно как-то так:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;def Y
  lambda { |f| f.call(f) }.call(
    lambda do |g|
      yield(lambda { |*n| g.call(g).call(*n) })
    end)
end
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Раньше для реализации функции рекурсивного подсчёта факториала целого числа приходилось писать отдельный метод. Как правило, в таких случаях декларация отдельного метода выглядит не так изящно, как запись λ-функции:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;fact = Y { |this|
  lambda do |n|
    (n &amp;gt; 1) ? n * this.call(n - 1) : 1
  end
}

p fact.call(5) # =&amp;gt; 120
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Вуаля! Результат одинаков, но давайте посмотрим, как дела с производительностью? Для этого закатаем &lt;a href="https://gist.github.com/436062#file_benchmark_y_def.rb"&gt;простой бенчмарк&lt;/a&gt;: объявим метод вычисления факториала, объявим метод создания Y-комбинатора, объявим λ-функцию вычисления факториала, а потом погоняем всё это дело на разных &lt;em&gt;n&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Результат &lt;a href="https://gist.github.com/436062#file_benchmark_y_def.txt"&gt;несколько огорчает&lt;/a&gt;. При использовании λ-функций мы гораздо раньше напарываемся на ограничение уровня стека, чем при использовании методов. Это довольно печально, хотя на этом проблемы не заканчиваются.&lt;/p&gt;

&lt;p&gt;Уже на маленьких &lt;em&gt;n&lt;/em&gt; временные затраты (real) на вызовы λ-функции превышают тупой вызов метода. С увеличением &lt;em&gt;n&lt;/em&gt; разрыв идёт уже не на один, а на два порядка, то есть вариант с Y-комбинатором медленнее в &lt;strong&gt;сто раз&lt;/strong&gt;! Как решить эту проблему?&lt;/p&gt;

&lt;p&gt;На &lt;a href="http://habrahabr.ru/blogs/python/50354/" rel="nofollow"&gt;хабре&lt;/a&gt; в аналогичной статье человек предлагает решать эту проблему на Python при помощи промежуточного кэширования. Думаю, это поможет, но в таком случае становится несколько страшно смотреть на реализацию этого дела.&lt;/p&gt;

&lt;p&gt;Y-комбинатор позволяет избавить себя от лишнего объявления метода при использовании функции, требующей рекурсии.&lt;/p&gt;

&lt;p&gt;В случае обработки деревьев, списков или чего-то в этом роде, этот приём позволяет сделать код красивым, чистым и шелковистым. К сожалению, придётся несколько пожертвовать производительностью, но в любом случае это лучше, чем превращать код в лапшу. И это хорошо.&lt;/p&gt;</description><link>http://suckless.ru/post/1407638872</link><guid>http://suckless.ru/post/1407638872</guid><pubDate>Sun, 13 Jun 2010 00:00:00 +0600</pubDate><category>ruby</category><category>fprog</category><category>benchmark</category><dc:creator>eveel</dc:creator></item></channel></rss>

