Поменялся адрес RSS eveel сб 05 нояб 2011 20:57:38 №12372583557

У нас поменялся адрес RSS-фида. Пожалуйста, проверьте его в своих читалках. Кстати, у нас есть ещё и твиттер: @suckless666.

...



Собственная тучка на OpenNebula eveel сб 05 нояб 2011 00:35:00 №12334617154

Облачные вычисления — самый модный и порванный баззворд в сфере IT за последние несколько лет. Даже агенство Gartner в своём ежегодном отчёте второй год подряд упоминает этот термин, обозначая одну из стратегических технологий. При всём ажиотаже, нет ничего плохого в том, чтобы отделить зёрна от плевел, и создать свою маленькую и уютную «тучку».

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

Часто к «облакам» навешивают ярлык какой-либо бизнес-модели: IaaS, PaaS, SaaS, etc. Я расскажу про развёртывание полноценного IaaS-облака в совершенно реальном месте — Институте математики и механики УрО РАН.

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

Мы долго выбирали между модным нынче OpenStack и менее знаменитой OpenNebula.

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

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

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

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

Сегодня OpenNebula поддерживает такие гипервизоры, как KVM, Xen и Hyper-V. В качестве системы хранения образов виртуальных машин поддерживается NFS, MooseFS, а также тупое пробрасывание образов через SCP. Увы, поддержка клёвого хранилища OpenStack Swift отсутствует, потому что все операции в OpenNebula выполняются при помощи библиотеки libvirt, которая пока не способна работать со Swift.

Мы развернули свою «тучку» из остатков старого вычислительного кластера, умеющих аппаратную виртуализацию. В качестве гипервизора выбрали модный KVM, а данные решено было хранить в файловой системе NFS на имеющемся NAS от EMC².

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

Структура облака ИММ УрО РАН на основе OpenNebula

После решения оргвопросов:

  1. выделили отдельную управляющую машину с CentOS 6 на борту, где запустили демон oned, Web-интерфейс Sunstone и сервер MySQL для хранения состояния системы;
  2. забрали у старого вычислительного кластера три сервера с поддержкой аппаратной виртуализации, установили туда Scientific Linux 6.1 и отключили SELinux, который требует настройки и мешает работе KVM;
  3. создали пары SSH-ключей, при помощи которых машины могут «ходить» друг к другу от пользователя oneadmin без пароля;
  4. на каждом узле кластера установили сетевой мост, позволяющий каждой виртуальной машине быть полноценным членом ЛВС ИММ УрО РАН;
  5. сконфигуровали в oned политику «если VM упала, то пытаться перезапустить её на другом узле»;
  6. закрыли подсеть «облака» брандмауэром, дав доступ к конкретным машинам и портам только через сетевой шлюз;
  7. создали собственный образ Scientific Linux, заточенный на быстрый запуск внутри OpenNebula в качестве VM;
  8. запустили на его основе тестовую машину с полуработающим морфологическим анализатором myaso.

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

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

Логическое представление облака ИММ УрО РАН на основе OpenNebula

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

OpenNebula Sunstone

...



В Контакте вместе с Ruby izinenko вс 11 сент 2011 20:07:00 №10080778911

На сегодняшний день скорость развития рынка Web-приложений крайне велика. Относительно новым и пока не до конца сформировавшимся рынком является рынок приложений в социальных сетях. Аудитория социальных сетей растёт. Количество денег, которые тратят пользователи, увеличивается. Интерес к получению дохода путём создания приложений, очевиден. Самой популярной и динамично развивающейся социальной сетью в России является В Контакте. Само собой, она предоставляет богатый API, функциональность которого расширяется практически каждый месяц.

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

Примеры:

  1. userapi-ruby — заброшено;
  2. vk-ruby-api — является надстройкой над данными пользователя, код странный;
  3. vkontakte_api — плагин для Rails (не реализован в виде engine), заброшен;
  4. bublik/vkontakte — заброшен;
  5. mamantoha/vkontakte — живой проект, является библиотекой исключительно для клиентских приложений. Увы, для авторизации парсит страницы, что запрещено правилами использования в Контакте.

Поскольку так сложилось, что на данный момент не существует функциональной и корректной API-обёртки В Контакте для Ruby, я представляю собственное решение — vk-ruby.

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

  1. прост в расширении: список всех возможных методов API находятся в YAML-файлах, которые легко модифицировать, форкнув проект на GitHub;
  2. включает в себя все три типа приложений В Контакте:
    • serverside — «подключенный» сайт;
    • standalone — мобильное или desktop-приложение;
    • secure — защищенный сервер вашего приложения.

Что нужно, чтобы начать работать с API В Контакте?

  1. первым делом, зарегистрировать собственное приложение и получить необходимые ключи;
  2. ознакомиться со способами авторизации приложения В Контакте;
  3. установить gem vk-ruby.

Начало работы

Cоздадим приложение необходимого типа:

serverside = VK::Serverside.new :app_id => APP_ID, :app_secret => APP_SECRET
# или
standalone = VK::Standalone.new :app_id => APP_ID
# или
secure = VK::Secure.new :app_id => APP_ID, :app_secret => APP_SECRET

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

serverside.authorize(CODE) 
# или
standalone.authorize(CODE) 
# или
secure.authorize

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

Например, посмотрим, установил ли пользователь наше приложение:

serverside.isAppUser # => 1

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

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

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

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

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

secure.secure.sendNotification(
  :message => 'Привет!', 
  :timestamp => Time.now.to_i, 
  :random => rand(1000)
)

Легко заметить, код получается довольно простым и аккуратным. Всё что нужно для работы — это ознакомится со списком методов API.

Конечно, vk-ruby легко интегрировать в любое приложение. Ruby on Rails, Sinatra, Padrino — не имеет значения, хоть в другой gem. В качестве небольшого примера я написал простое Web-приложение на микрофреймворке Sinatra.

Огромным камнем в огороде вконтакта является способ авторизации клиентских приложений, который предполагает встраивание браузера и «ручное» заполнение формы авторизации. Это действительно большая проблема, которая не решилась даже с переходом В Контакте на OAuth 2.0. В качестве частичного решения, я написал утилиту vk-console, которая авторизуется в системе, выполняя парсинг страниц.

Я старался сделать данный инструмент простым и удобным, но как и любому проекту поддержка будет не лишней! Если знаете как его улучшить, нашли баг или ещё что то, то пишите, форкайте — буду очень рад.

...



Ruby ♥ ØMQ (Fuck You, Erlang!) eveel сб 04 июнь 2011 02:43:00 №6151680466

Сложные системы состоят из множества компонент, между которыми возникает необходимость организовывать взаимодействие, часто сводящееся к передаче сообщений. Разные команды разработчиков решали эту задачу по-разному. Итак, как же в рамках экосистемы Ruby можно решить эту задачу?

ØMQ — очень эффективная и навороченная библиотека для организации обмена сообщениями, не привязанная к конкретному транспортному уровню. Внутри одного процесса можно устроить обмен сообщениями между потоками поверх UNIX-сокетов или внутрипроцессового IPC, а удалённые приложения могут «разговаривать» друг с другом поверх протоколов TCP или UDP. Более того, ØMQ ориентирована на верхний уровень модели OSI, поэтому даже сообщение в полмегабайта переданное из пункта А в пункт Б придёт в целости и сохранности.

Внутри ØMQ реализованы традиционные паттерны построения сетевых приложений: парадигма «запрос-ответ», «издатель-подписчик», механизмы маршрутизации сообщений, построения отказоустойчивых систем и многое другое, описанное в гайде.

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

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

Архитектура системы

Возьмём Sinatra и биндинги к ØMQ. Кстати, из-за особенностей реализации потоков в MRI, следует использовать версию Ruby 1.9 и неофициальный гем ffi-rzmq. Официальный гем zmq «подвешивает» интерпретатор при завершении работы.

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

Итак, код бэкэнда. Вообще, я старался комментировать код, хотя проблем при чтении быть не должно: всё очень просто.

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

Теперь код фронтэнда. Это вполне себе обычное приложение на микрофреймворке Sinatra.

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

Кстати, не забываем положить файл с ERb-шаблоном страницы по адресу views/index.erb относительно остальных файлов.

Итак, для начала запускаем backend.rb, который забивает на себя UNIX-сокеты и готовится обрабатывать данные. После этого запускаем frontend.rb и заходим браузером по адресу http://localhost:4567.

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

Ruby ♥ Sinatra + ØMQ

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

Приведённый в статье пример может показаться слишком простым. Это действительно так, и он не показывает даже верхушку айсберга возможностей ØMQ, но исключительно базовые вещи. В качестве материала для дальнейшего чтения могу категорически порекомендовать две шикарные статьи Ilya Grigorik [1,2].

...



Ruby Parallelism Benchmarking eveel сб 06 нояб 2010 02:44:00 №1490524178

Посмотрим, насколько всё плохо в Ruby с параллелизмом: юзабельны ли треды? Возможно ли вообще в Ruby параллельное программирование? Опыты проведём на огромном компьютере Fujitsu-Siemens PRIMEPOWER 850 с установленным Sun Solaris 9.

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

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

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

Сравним производительность работы в трёх случаях:

Для этого дела я написал достаточно простой бенчмарк: parallel-bench.rb.

Вместо того, чтобы обсуждать код, лучше поговорить сразу о результатах измерений. Для пущей наглядности я представил их в виде гистограммы. Чем короче столбик, тем лучше результат.

Визуализация результата

Легко сделать выводы.

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

К сожалению, выбросить GIL из MRI не представляется возможным. Сегодня все мечты о «настоящем параллелизме» возлагаются на JRuby, а завтра — на Rubinius.

...



QR коды на Ruby и GD2 eveel вт 05 окт 2010 00:00:00 №1407624725

Библиотека ImageMagick применяется практически в любом Web-приложении (на языке Ruby) для обработки и композитинга изображений, рисования различных графических примитивов, и так далее.

Если говорить о применении этой библиотеки в экосистеме Ruby, то сразу на ум приходит гем RMagick, который мало того, что имеет просто невероятно неудобное API, так его использование обходится дороже, чем тупой фоновый запуск отдельных программ, входящих в пакет ImageMagick. Плюс, иногда его требовательность к версиям установленных в системе библиотек способна поразить даже самых лояльных разработчиков.

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

Думаю, большинству PHP-разработчиков хорошо знакома достаточно милая библиотека GD2. Среди Ruby-разработчиков она не пользуется большой популярностью, и это весьма грустно, ведь она способна достойно решать основные задачи работы с растровой графикой.

Существует гем gd2-ffij. Последняя его версия вышла в 2010 году, но осмотр кода показал, что развитие библиотеки остановилось отнюдь не потому, что всё очень плачевно. Дело в том, что требуемые от библиотеки задачи решены в необходимом и достаточном виде.

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

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

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

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

Quoreux

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

Меня огорчает лишь слабая поддержка GD2 со стороны Ruby-сообщества. Интересно, с чем это связано?

...



Y-комбинатор поможет eveel вс 13 июнь 2010 00:00:00 №1407638872

Мы знаем, что λ-исчисление лишено поддержки рекурсии. Также мы знаем, что использование λ-функций часто помогает сделать запись программы красивее и лаконичнее. В любом случае, возникают ситуации, когда достижению этой благородной цели мешает невозможность сделать рекурсивный вызов λ-функции.

Здесь нам поможет Y-комбинатор.

Итак, я не в состоянии дать определение, выводы и основы комбинаторной логики, потому что Саклесс ни разу не об этом. Несмотря на это, следует вкратце рассказать об этом комбинаторе.

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

Итак, реализовать это можно как-то так:

def Y
  lambda { |f| f.call(f) }.call(
    lambda do |g|
      yield(lambda { |*n| g.call(g).call(*n) })
    end)
end

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

fact = Y { |this|
  lambda do |n|
    (n > 1) ? n * this.call(n - 1) : 1
  end
}

p fact.call(5) # => 120

Вуаля! Результат одинаков, но давайте посмотрим, как дела с производительностью? Для этого закатаем простой бенчмарк: объявим метод вычисления факториала, объявим метод создания Y-комбинатора, объявим λ-функцию вычисления факториала, а потом погоняем всё это дело на разных n.

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

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

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

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

В случае обработки деревьев, списков или чего-то в этом роде, этот приём позволяет сделать код красивым, чистым и шелковистым. К сожалению, придётся несколько пожертвовать производительностью, но в любом случае это лучше, чем превращать код в лапшу. И это хорошо.

...