Как стать автором
Обновить

Изобретаем технологию: опыт соединения нескольких open-source проектов

Время на прочтение6 мин
Количество просмотров1.9K
Я хотел бы поделиться опытом создания приложения, или точнее технологии, основанной на нескольких open-source проектах. Это нечто вроде веб-сервера с поддержкой асинхронных сообщений и возможностью исполнения скриптов на JavaScript.


С необходимостью что-то изобретать я столкнулся после окончания нескольких проектов, связанных так или иначе с автоматизацией финансов. Мы использовали привычную трехзвенную модель клиент-сервер приложений-сервер БД с некоторыми доработками. Я осознал, что даже куча доработок не делает эту технологию удобной. Она все время «вылезает наружу» и требует внимания.

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

1) Клиентом должен быть браузер.

Только очень серьезная причина может заставить нас делать «толстое» приложение со своей графической библиотекой и то в качестве дополнения к браузеру. Посмотрев на текущее состояние дел, на скорость Chrome, на Google Gears, Google Docs, на работу с объектом canvas, на возможности графических фреймворков на JavaScript, я утвердился в этом решении окончательно.

2) Наиболее удобной формой хранения данных является реляционная БД с SQL.

Везде! То есть не только еще и на сервере приложений, но и на клиенте! Нет ни одной разумной причины отказаться от возможности иметь данные в реляционном виде даже на клиента кроме необходимости в дикой производительности. Разумеется, к этому времени я уже наткнулся на SQLITE ( sqlite.org ). Это встраиваемая кросс-платформенная реляционная БД в исходных кодах, в public domain, с поддержкой практически всего действительно необходимого в SQL. Я вообще советую любому ознакомиться с этим проектом в качестве учебного пособия. SQLITE имеет очень интересные (и полезные на мой взгляд) особенности. Например. Тип данных хранится вместе с самим значением, то есть в одном и том же столбце таблицы в разных записях можно хранить и строку, и число, и blob. Есть возможность создавать in-memory базу данных (то есть полностью в оперативной памяти). Есть триггеры. Нету встроенного языка! Исходный код проекта доступен в удобной форме, называемой amalgamation ( sqlite.org/amalgamation.html ), то есть буквально из двух файлов: cpp и h. Очень удобно включать в проект. Проект гибко настраивается компиляционными опциями.

3) Бизнес-логика должна создаваться на скриптовом языке высокого уровня.

Это не должен быть C++ или Java. Эти языки привнесут ненужную сложность и не дадут необходимой гибкости. Как ни странно, мой выбор пал на JavaScript. В свое время я занимался довольно плотно веб-программированием и от языка JavaScript у меня осталось очень приятное впечатление. Это очень гибкий и легко расширяемый язык, но отчего-то его не используют в качестве серверного решения. В качестве реализации я выбрал Google V8 ( code.google.com/p/v8 ). Это проект компилятора и среды исполнения JavaScript, реализующий стандарт ECMA-262 ( www.ecma-international.org/publications/standards/Ecma-262.htm ) и используемый в браузере Chrome.

Исходный код V8 доступен через систему subversion ( ru.wikipedia.org/wiki/Subversion ). Часто subversion называют svn по названию стандартного клиентского приложения. В wiki все хорошо описано, но в двух словах, это система репозитариев (централизованных хранилищ файлов вместе со всей историей их изменения) и рабочих копий («снимков» веток проекта в виде каталогов и файлов на локальных компьютерах пользователей). Эта система пришла на смену CVS. После проб я выбрал SmartSVN ( www.syntevo.com/smartsvn ) в качестве клиента subversion и более-менее доволен. Есть бесплатная версия.

4) Транспорт будущей системы должен быть основан на асинхронных сообщениях.

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

Надо приступать к работе, но с чего начать? Не очень хочется с нуля выводить работу с файлами, сетью, да еще желательно иметь кросс-платформенные возможности, зачем отказываться от Linux в качестве альтернативной, а может и основной платформы? После недолгих поисков я нашел STLPlus ( stlplus.sourceforge.net ). Это достаточно грамотно спроектированная Windows и Unix C++ библиотека, в которой есть все что нужно для первичного набора функционала. Пришлось ее попилить напильником.

Итак, первым делом создаем систему обмена асинхронными сообщениями. Не будем размениваться на мелочи, ведь мы строим идеал. Поэтому эта система должна быть a) zero-configuration и b) автоматически переходить с неисправной сети на исправную. Это означает, что каждый компьютер в рамках нашей сети должен все время рассылать широковещательные UDP-сообщения со списком своих IP-адресов и в результате каждый из компьютеров связывается с каждым через все доступные сети и исключает используемое соединение из обмена при неисправности сети. В простейшем случае мы можем соединить компьютеры с помощью Ethernet и WiFi и при отказе Ethernet система автоматически перейдет на WiFi. Вопросы контроля доступа пока отложим.

Следующий слой реализует адресацию. Здесь простейшее решение. На каждом компьютере можно зарегистрировать произвольный сетевой адрес (point@host) и отправлять/получать сообщения. Плюс есть система наподобие досок сообщений в fido, позволяющая одним сетевым адресам заявлять об обработке определеных имен, а другим искать этих обработчиков. Это позволяет свободно перемещать задачи по комьпютерам без какой-либо необходимости в изменении конфигурации.

Следующий шаг — встраивание веб-сервера. Ничего подходящего в open-source я, к сожалению, не нашел. Либо решения были слишком монструозными, либо узко специализированными, либо слишком упрощенные, либо тащили за собой свои библиотеки. Пришлось эту часть, то есть поддержку HTTP 1.1 в качестве сервера, написать самостоятельно. Ничего особенного сложного здесь нет, все достаточно хорошо документировано, проверяется тут же браузером.

Все задачи наше приложение выполняет в рамках сессий. Это нечто, что создается на сервере для обработки клиентских запросов или для запуска постоянных фоновых задач. В качестве сессии в нашей системе используется… контекст javascript. Образно это можно представить так: когда клиент открывает документ в браузере и делает запрос, то на сервер тоже открывается некий «документ» внутри которого выполняется javaScript код для обработки запросов. Проницательный читатель наверное уже догадался, что в этом «документе» нет полной реализации DOM или, скажем, объекта window. Конечно, но есть гораздо более полезные обертки: доступ к системе обмена сообщениями и базе SQLITE. Причем in-memory база SQLITE создается автоматически для каждой новой сессии. В систему обмена сообщениями встроена возможность отправить результат любого SELECT запроса в рамках сообщения и этот датасет будет автоматически восстановлен в базе получателя. То есть скрипт фактически все время работает с помощью SQL с локальной реляционной БД, в которую можно получить любые данные из удаленной базы.

Однако, контекст javascript, разумеется, позволяет делать не только это. Ведь по сути мы имеем дело с глобальным объектом javaScript, мы имеем возможность свободно создавать ему новые свойства, определять функции, то есть делать все то же, что и на клиентском контексте в окне браузера. Любые требуемые данные мы кэшируем в свойствах и т.д. И фактически весь выполняемый javaScript-код будет перед выполнением откомпилирован, производительность весьма высока.

Вернемся к нашему клиенту: браузеру. В последнее время наметилась тенденция превращения веб-страниц в веб-приложения (читай первую фразу в комиксе про Хром www.google.com/googlebooks/chrome/small_00.html ). А что это означает? Это означает, что обработка представления данных все сильней и сильней переносится на сторону клиента, то есть на браузер. Фактически в настоящее время ничто не мешает формировать видимый HTML полностью на браузере. Современная веб-страница сначала загрузит необходимые стили, билиотеки (фактически единственный раз), а затем перейдет в оффлайн и позволит пользователю настроить вид и разложить визуальные элементы как нужно. Обращение к веб-серверу будет происходить только за фактическими данными, скажем, в виде XML. Разумеется, я рисую некий идеал, но к нему все сейчас стремится. И самое главное, технологии делают это возможным.

Скажем, Google Gears ( gears.google.com, wiki здесь: ru.wikipedia.org/wiki/Google_Gears ). Это возможность из браузера работать с локальной базой SQLITE, кешировать ресурсы и запускать асинхронные фоновые потоки выполнения javascript.

Для перемещения данных из базы SQLITE сервера в базу SQLITE браузера я написал простейшую репликацию, основанную на триггерах. Требуется лишь перечислить реплицируемые таблицы и периодически забирать SQL изменений удаленной базы (баз). Данные забираются с помощью AJAX-запросов.

Здесь сделаю небольшое отступление про AJAX. Собственно, думаю он известен всем. Но, столкнувшись с необходимостью встроить его в клиентские библиотеки, я с удивлением обнаружил, что почти все примеры AJAX в интернет — ужасны с точки зрения проектирования. То же недоумение постигло меня, когда я возжелал быстро отыскать простейший скриптик для отправки формы через AJAX POST-запрос. Потом я уже конечно догадался, что большинство программистов сегодня используют на клиенте те или иные фреймворки (типа jQuery), в которые встроен подобный функционал.

Собственно, подводя черту. Спустя три месяца система живет и прекрасно себя чувствует. Все задумки реализованы в полном объеме. Вообще, приятно удивило, что все это заработало и почти как задумывалось. Были и огорчения, самым значительным из которых наверное следует считать ограничение V8, которые фактически не является мульти-тредовым. Код может выполняться одновременно только одним тредом, хотя контекстов можно подготовить сколько угодно. Chrome на каждую закладку запускает отдельный процесс.

Производительности системы для нас достаточно. Собственно, теперь мы приступаем к ее эксплуатации. О результатах, если интересно, сообщу позже отдельной статьей.
Теги:
Хабы:
Всего голосов 42: ↑39 и ↓3+36
Комментарии44

Публикации