Showing posts with label erlang. Show all posts
Showing posts with label erlang. Show all posts

Sunday, February 21, 2010

Erlang

Не бывает достоинств без недостатков.
Достоинства:
  • функциональный язык с простым синтаксисом;
  • удобный синтаксис для записи математических функций;
  • ленивое исполнение;
  • событие ориентированный;
  • замыкания;
  • обширная библиотека OTP;
  • легковесные потоки;
  • удобная система фильтрации в условных операторах и разбора данных  по шаблону.
Недостатки, если смотреть излишне критично, вытекают из достоинств:
  • необычный синтаксис; 
  • никогда во время исполнения не чистит память, очистка вызываться только после завершения N-количества потоков;
  • во время очистки блокируется полностью вся виртуальная машина;
  • только недавно появилась поддержка многоядерных процессоров;
  • изначально написан для телефонных станций (ориентация на необычную специфичную сферу деятельности);
  • легковесные потоки - миф - при появлении ожидания  сообщения переключается на другой поток и при появлении новых сообщений ставим в очередь (возможно ее переполнение);
  • полностью функциональный язык со всеми неудобствами - нужно реализовывать большинство алгоритмов полностью рекурсивно (и кто его знает сколько оно будет думать?) и не использовать переопределение значений переменных(непривычно и иногда неудобно);
  • сложные вещи реализуется просто, простые очень сложно;
  • строки представлены списками, где используется не экономный формат данных для хранения 1 байта используется 8;
  • базы данные мнезье - все хорошо пока у вас памяти больше, чем данных, а потом или все читаем с диска или ядро убьет вас(не умеет оптимально кешировать запросы используя достоинства обоих типов хранения данных);
  • сложение строк дает разные значения в зависимости перемены мест слагаемых.

Риторические вопросы:
  • хотим чтобы не не использовали небезопасное выделение памяти и глобальные переменные - может стоит объяснить людям почему это плохо или дать удобный интерфейс для использования, а не полностью запрещать в синтаксисе?
  • ленивое выполнение - а вы всегда уверены когда это все выполниться и не зависнет ли? Как посчитать время исполнения? И все современные компиляторы стараются в месте с суперскалярной архитектурой (внеочередное выполнение, параллельное исполнение нескольких участков с применением уже рассчитанных результатов при благоприятном стечении условий) пытаются оптимизировать поток выполнения. И не стоить заменять логику надеждой - среда исполнения сама разберется  что уже не нужно исполнять дотянув реальное выполнения до последнего момента;
  • замыкания - если вы боитесь за стек включите оптимизации в компиляторе он давно умеет это избегать(в gcc - уже есть оптимизация при которой для рекурсивного выполнения стек если это возможно не растет).
  • если так уж хотим выделяться - берем гугловсий Go и получаем все тоже, но компилируемое... Не хотим? Есть куча библиотек по контролю за памятью и обменам сообщениями, все равно он преобразует в байткод исполняемый в виртуальной машине написанной на с, и если немного подумать можно сделать возможно и лучше и быстрее.

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

Wednesday, June 24, 2009

Параметры мобильного телефона используя wurfl

Для того чтобы определить параметры мобильного телефона можно использовать 2 пути:
  • определение свойств на основе мобильного профайла возвращенного в заголовках запроса (CC/PP);
  • определение на основе данных переданных в качестве UserAgent.
Первый случай дает возможность сделав несколько запросов на профайл и изменения в нем по протоколу CC/PP получить полные официальные данные об устройстве, но этот случай имеет несколько недостатков, указанный в профайле ресурс может быть недоступен и мы терем время на эти запросы.

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

Принцип работы с базой wurfl:
  1. найти максимально похоже имя user agent по xpath пути:"/wurfl/devices/device/@user_agent. (В первой версии искалось полное соответствие.)
  2. определить идентификатор этого описания: "/wurfl/devices/device[@user_agent='UserAgent']/@id"
  3. попытаться получить описание нужного нам свойства используя: "/wurfl/devices/device[@id='идентификатор']/group[@id='markup']/capability[@name='html_wi_oma_xhtmlmp_1_0']/@value" . markup - имя группы свойств, html_wi_oma_xhtmlmp_1_0 - свойство.
  4. Если получить не удалось получаем идентификатор подобного устройства: "/wurfl/devices/device[@id='идентификатор']/@fall_back".
  5. Если получить описание устройства не удается через fall_back мы всегда попадем на описание generic устройства, у которого значение всех свойств равно false.
Ссылки:

Friday, June 5, 2009

timeouts in merle

Добавил в мою ветвь кода merle возможность работы с timeout.
  1. В функцию connect новый параметр Options, передаваемый в функцию gen_server:start_link . Этот параметр позволяет установить timeout и включить режим отладки:
  • Options ::= [{timeout, Timeout} | {debug, [Flag]}]
  • Flag ::= trace | log | {logfile, File} | statistics | debug(debug == log && statistics)
  1. В getkeylist(Key, Timeout) добавлен параметр максимального ожидания ответа, предыдущий вариант тоже остался, его поведения также можно эмулировать - указав значение 0
  2. Функция setlist теперь ожидает установки только время указанное как значение времени кеширования (гарантия что. если время кэширования было превышено, сохранение не произойдет). При значении 0 поведение сохраняется, как было до изменения.
Эти изменения позволяют снизить количество одновреммено запущеных запросов к merle во время повышенной нагрузки на систему временем timeout.

Thursday, May 21, 2009

Код корректного перезапуска merle

При использование кода связи с memcached возможен случай когда соединение с memcached по каким-то причинам потеряно, например: рестарт memcached.
  • В данном случае возможен случай когда выполнить вызов не удается, но пересоединение не получается (закрытие (disconnect) сообщает - что закрывать нечего, а открытие (connect) сообщает - что уже есть соединение). В данном случае нужно убить это псевдо-рабочее соединение и запустить наново.
  • Другой случай когда соединяться не с кем - тогда метод connect просто выходит, не вызывая исключение, что очень плохо, так как не понятно, что произошло с системой - чтобы отловить эту ситуацию нужно разрешить посылку сигнала о завершении потока и ожидать получение этого сообщения.
Пример кода:

%%use with restart
try_with_restart(LU, F) ->
try
F()
catch
Sub : Reson ->
debug_log(LU, "Start procedure restart connect:~p~n",[{Sub,erlang:get_stacktrace(),Reson}]),
spawn(fun() ->
process_flag(trap_exit, true),
Connect = merle:connect(?MEMCACHED_HOST,?MEMCACHED_PORT),
case Connect of
{error, {already_started, Client}} ->
debug_log(LU, "try kill client status:~p~n",[Connect]),
exit(Client,kill);
Value ->
debug_log(LU, "Some other error:~p~n",[Value])
end,
receive
{'EXIT', Pid, Why} ->
debug_log(LU, "Me killed~p~n", [{Pid, Why}])
end
end),
undefined
end.

Примечание:
  1. F - функция обращающаяся к merle;
  2. debug_log() - вывод в логи отладочной информации.

Sunday, May 17, 2009

merle совместимый с nginx

Выложил коды проектов используемых мною с некоторыми изменениях в них.

Изменения в коде merle (memcached erlang interface) нацелено на совместимость с другими языками программирования, в частности возможность получения сохраненного контента из nginx.

Стандартный код использует binary_to_term для сохранения контента в результате при попытке получить контент из memcahed из других программ, ожидающих возврат обычной строки, в начале контента невозможно так как появляются служебные данные erlang.

В код добавлены функции сохранения как строка merle:setlist( url, time, content), и получения контента в виде строки merle:getkeylist (url). Также удалено использование нестандартного gen_server. Удален только для упрощения поддержки кода, так как усовершенствования по очередям сообщений в проекте были не нужны.

В результате этих изменений удалось организовать систему когда frontend server(использовался nginx) мог не запрашивая backend получить сразу данные из кэша, также получилось использовать как общих кэш и для php.

Остальные функции постарался оставить без изменений их поведения и формата сохраняемых ими данных(term_to_binary), измения заключаются в переносе функций преобразования term_to_binary(getkey) и binary_to_list (getkeylist) из вызовов gen_server.

В erlyweb изменены:
  • опции компиляции по умолчанию, теперь поведение подобно поведению make, когда компилируются только измененные файлы;
  • добавлена обработка исключение при рендеренге компонентов встроенных в основную страницу (вместо него при ошибке выдается указание, что компонент отработал с ошибкой), исключение при отработке основной страницы не отлавливается и передается при ошибке дальше, его нужно отлавливать внутри этой страницы самостоятельно;
  • также, добавлена поддержка использования прописных букв в пути к каталогам с компонентами(ранее использовалось преобразование всех букв к строчным).

Friday, March 27, 2009

Простейшая реализация OpenID

Документация изначально написана для внутреннего пользования при создании модуля работы с OpenId. Модуль поддерживает только часть функционала openid (только регистрацию по первой версии OpenId). Результат можно посмотреть в здесь. Поддерживает только идентификаторы вида http://имя пользователя с именем провайдера - на этот идентификатор все openid провайдеры должны возвращать свое описание в заголовках страницы. Решил выложить, так как за пол года не появилось более полной реализации по сравнению с той, что есть у меня.

Общие шаги(OpenID *)

Полученному идентификатору запрашиваем страницу в ней ищем значения openid2.provider(OpenId 2.0), openid.delegate (OpenId 1.0 в общем случае должен совпадать с введенным именем пользователя), openid2.local_id(OpenId 2.0 в общем случае должен совпадать с введенным именем пользователя), openid.server (OpenId 1.0) и X-XRDS-Location (OpenId 2.0).

Например:
  • <link rel="openid2.provider" href="http://openid.yandex.ru/server/" />
  • <link rel="openid2.local_id" href="http://openid.yandex.ru/имя пользователя/" />
  • <link rel="openid.server" href="http://openid.yandex.ru/server/" />
  • <meta http-equiv="X-XRDS-Location" content="http://openid.yandex.ru/имя пользователя/yadis/" />
Для OpenId 1.0 Перенаправление пользователя для проверки его валидности

Сделать запрос к серверу (openid.server) на проверку пользователя (openid2.local_id) режим checkid_setup - так как это простейший режим и требующий минимальной реализации с нашей стороны:
  1. [openid.server]?
  2. openid.mode=checkid_setup&
  3. openid.identity=[openid2.local_id]&
  4. openid.return_to=[Путь на который нужно вернуться]&
  5. openid.trust_root=[Проверяем доверие серверу(доменное имя)]&
  6. openid.claimed_id=[openid2.local_id]
Для OpenId 2.0 Получение дополнительной информации

По полученному X-XRDS-Location получаем Yadis документ:
<?xml version="1.0" encoding="UTF-8" ?>
<xrds:XRDS xmlns:xrds="xri://$xrds" xmlns="xri://$xrd*($v*2.0)">
<XRD>
<Service priority="20">
<Type>http://specs.openid.net/auth/2.0/signon</Type>
<Type>http://openid.net/signon/1.0</Type>
<URI>http://openid.yandex.ru/server/</URI>
<LocalID>http://openid.yandex.ru/имя пользователя/</LocalID>
</Service>
</XRD>
</xrds:XRDS>

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

Возвращаемый сайтом ответ через обратное переполнение
В результате проверки на сайт мы должны вернуться в любом случае с такими параметрами:
  1. Удачный:
  • [Вернутся на такой url]?
  • openid.assoc_handle=[Тип подписи]&
  • openid.identity=[openid2.local_id]&
  • openid.mode=id_res& (нам доверяют)
  • openid.op_endpoint=[openid.server]&
  • openid.response_nonce=[временной штамп]&
  • openid.return_to=[Вернутся на такой url]&
  • openid.sig=&(подпись)
  • openid.signed=(от каких полей подпись)
  1. Не удачный
  • [Вернутся на такой url]?
  • openid.mode=cancel (вам не доверяют)
Проверка подписи
Для яндекса проверка не сработала, когда я тестировал модуль, возможно я что-то делаю не так. Стандартный код проверки OpenId тоже не делал эту проверку.

После получения мы должны проверить, а те ли нам ответили и запросить с сервера дополнительные сведения:
  • [openid.server]?
  • openid.mode=check_authentication&
  • openid.assoc_handle=[Значение openid.assoc_handle из предыдущего запроса]&
  • openid.sig=[Значение openid.sig из предыдущего запроса]&
  • openid.signed=[Значение openid.signed из предыдущего запроса]&
  • openid.identity=[Значение openid.identity из предыдущего запроса]&
  • openid.return_to=[Значение openid.return_to из предыдущего запроса]

Tuesday, September 30, 2008

Выложил реализацию recaptha на erlang

Сегодня обнаружил, что на googleсode выложили реализацию протокола openid. У нас в компании тоже есть реализация протокола openid - но она не полная, там не все особенности протокола реализованы - только наиболее важные для реализуемой нами системы.

Посоветовавшись мы решили выложить часть кода которую мы реализовали полностью для протокола recaptha чтобы не отставать:-) Результаты можно посмотреть здесь. Также выложена часть внутренней документации - как пояснение работы этого кода (на русском языке - так как было для внутреннего использования). Будет настроение переведу на более распостранненый в IT сфере английский.