![]() |
Здравствуйте, гость ( Вход | Регистрация )
![]() ![]() |
![]() |
![]()
Сообщение
#1
|
|
![]() Администратор ![]() ![]() ![]() ![]() ![]() Группа: Главные администраторы Сообщений: 14349 Регистрация: 12.10.2007 Из: Twilight Zone Пользователь №: 1 ![]() |
C++*, Веб-разработка* В настоящее время, благодаря таким инструментам как NodeJS, создание веб-приложения — сущий пустяк. Скачал бинарник, сваял js в 5 строчек кода и можно хвастаться. А если подключить express и добавить ещё 5 строчек, то получим полноценное веб-приложение с роутингом, шаблонами, сессиями и другими прелестями. Так просто, что даже скучно. И стало мне интересно: как обстоят дела у моего старого знакомого С++, с которым уже 5 лет не виделся. В своё время прельстил меня ActionScript и прочий JavaScript, а о добром друге, который не раз выручал, совсем позабыл. В свете недавних статей о Configurable Omnipotent Custom Applications Integrated Network Engine (сокращено Cocaine), попался мне на глаза проект под названием Fastcgi Daemon, на основе которого функционирует HTTP-интерфейс Cocaine. И так, знакомьтесь Fastcgi Daemon — Yandex's opensource framework for design highload FastCGI applications on C++. То есть Fastcgi Daemon — это фреймворк с открытым исходным кодом, разработанный в компании Yandex и предназначенный для создания высоконагруженных FastCGI-приложений на C++. К сожалению, это всё, что вы найдёте в README из официального репозитория. Больше документации доступно здесь github.com/lmovsesjan/Fastcgi-Daemon/wiki/_pages, но для полноценной работы и её недостаточно. Например, вся установка там занимает одну строку: sudo apt-get install fastcgi-daemon2-init libfastcgi-daemon2-dev libfastcgi2-syslog Но в официальных репозиториях Ubuntu, да и в каких-либо других (может плохо искал), эти пакеты обнаружить не удалось. В этой статье я решил собрать свои изыскания, связанные с установкой, настройкой и использованием этого инструмента. Все приведённые ниже исходники, а также готовые deb-файлы можно забрать здесь github.com/nickalie/HelloFastCGI Установка Проект поддерживается для Ubuntu, поэтому все операции ниже я производил на Ubuntu 12.04 64 bit со свежими обновлениями. Для начала установим все необходимые зависимости. Сделать это можно при помощи следующей команды: sudo apt-get install -y build-essential git debhelper automake1.9 autotools-dev libboost-dev libboost-thread-dev libfcgi-dev libxml2-dev libboost-regex-dev libtool libssl-dev autoconf-archive Теперь клонируем репозиторий с Fastcgi Daemon. Тут у нас на выбор 2 варианта:
Я выбрал первый вариант git clone https://github.com/golubtsov/Fastcgi-Daemon.git Переходим в папку со свежескачанным проектом cd Fastcgi-Daemon и запускаем сборку dpkg-buildpackage -rfakeroot На выходе получаем готовые к установке deb-файлы, которые находятся в родительской директории. Делаем cd .. и sudo dpkg -i ./libfastcgi-daemon2-dev_2.10-13_amd64.deb ./libfastcgi-daemon2_2.10-13_amd64.deb ./fastcgi-daemon2-init_2.10-13_amd64.deb ./fastcgi-daemon2_2.10-13_amd64.deb ./libfastcgi2-syslog_2.10-13_amd64.deb Также нам понадобится веб-сервер, который умеет работать с FastCGI. Я для своих нужд использую nginx, тоже самое советуют и в документации sudo apt-get install nginx Если хочется использовать свежайшую версию этого веб-сервера, то перед этим делаем sudo add-apt-repository ppa:nginx/stable && sudo apt-get update На этом с установкой покончено. Переходим к нашему первому приложению. Приложение Создаём файл HelloFastCGI.cpp и помещаем в него следующий код: #include <fastcgi2/component.h> #include <fastcgi2/component_factory.h> #include <fastcgi2/handler.h> #include <fastcgi2/request.h> #include <iostream> #include <sstream> class HelloFastCGI : virtual public fastcgi::Component, virtual public fastcgi::Handler { public: HelloFastCGI(fastcgi::ComponentContext *context) : fastcgi::Component(context) { } virtual void onLoad() { } virtual void onUnload() { } virtual void handleRequest(fastcgi::Request *request, fastcgi::HandlerContext *context) { request->setContentType("text/plain"); std::stringbuf buffer("Hello " + (request->hasArg("name") ? request->getArg("name") : "stranger")); request->write(&buffer); } }; FCGIDAEMON_REGISTER_FACTORIES_BEGIN() FCGIDAEMON_ADD_DEFAULT_FACTORY("HelloFastCGIFactory", HelloFastCGI) FCGIDAEMON_REGISTER_FACTORIES_END() Метод, который нас больше всего интересует — handleRequest. Именно он занимается обработкой запроса. Надеюсь из кода понятно, что происходит в этом методе, но на всякий случай поясню. Если в запросе (POST или GET) есть параметр “name”, то выводим текcт “Hello %name%”, иначе “Hello stranger”. Класс fastcgi::Request отвечает одновременно и за запрос, и за ответ, хотя обычно эта функциональность разделяется на 2 класса или объекта, как, например, в том же NodeJS. Уже “из коробки” мы можем работать c cookies, выставлять произвольные HTTP-статусы, заголовки и т. п. В общем, нам доступен джентельменский набор для разработки веб-сервисов и веб-приложений. Разве что по умолчанию не реализованы сессии, но они прикручиваются в 2 счёта. Об этом расскажу в следующей раз. Вернёмся же к нашим баранам. Теперь нам нужно скомпилировать этот класс в shared-библиотеку: g++ HelloFastCGI.cpp -O2 -fPIC -lfastcgi-daemon2 -shared -o libHelloFastCGI.so Затем следует подготовить конфигурационный файл HelloFastCGI.conf (важно, чтобы расширение было “conf”): <?xml version="1.0"?> <fastcgi xmlns:xi="http://www.w3.org/2001/XInclude"> <pools> <pool name="main" threads="1" queue="5000"/> </pools> <handlers> <handler pool="main" url="/hellofascgi"> <component name="HelloFastCGIComponent"/> </handler> </handlers> <components> <component name="HelloFastCGIComponent" type="MainModule:HelloFastCGIFactory"/> <component name="daemon-logger" type="logger:logger"> <level>INFO</level> <ident>hellofastcgi</ident> </component> </components> <modules> <module name="MainModule" path="./libHelloFastCGI.so"/> <module name="logger" path="/usr/lib/fastcgi2/fastcgi2-syslog.so"/> </modules> <daemon> <logger component="daemon-logger"/> <endpoint> <backlog>128</backlog> <socket>/tmp/fastcgi_daemon.sock</socket> <threads>1</threads> </endpoint> <pidfile>/var/run/fastcgi2/HelloFastCGI.pid</pidfile> <monitor_port>20012</monitor_port> </daemon> </fastcgi> У нас есть обработчик (handler) запросов, которые приходят на “/hellofastcgi” (например, www.somedomain.com/hellofastcgi). Этим обработчиком является компонент HelloFastCGIComponent, который лежит в модуле MainModule. Точнее в модуле лежит фабрика HelloFastCGIFactory, которая позволяет получить необходимый компонент. В свою очередь MainModule черпает свои ресурсы из недавно скомпилированной libHelloFastCGI.so. Также стоит обратить внимание на содержимое тэга “socket” — это ни что иное как unix-сокет, который нам вскоре понадобиться указывать в настройках nginx. “pidfile” — важен при демонизации FastCGI-Daemon. Его имя должно совпадать с именем conf-файла, различие только в расширениях. Чтобы демон был в состоянии делать start/stop/restart, pid должен лежать именно в “/var/run/fastcgi2/”. Самое время настроить веб-сервер. Так как всё это я проделываю на свежеустановленном nginx, то, не мудрствуя лукаво, правлю /etc/nginx/sites-available/default. Содержание должно быть примерно следующим: server { listen 80; location / { include fastcgi_params; fastcgi_param SCRIPT_FILENAME $fastcgi_script_name; fastcgi_pass unix:/tmp/fastcgi_daemon.sock; } } Перезапускаем nginx sudo service nginx restart Запускаем наше приложение при помощи fastcgi-daemon2 --config=HelloFastCGI.conf Если всё было сделано правильно, то открыв в браузере localhost/hellofastcgi, вы должны увидеть Hello stranger Добавим аргумент localhost/hellofastcgi?name=nick и получим Hello nick Ура, работает! Надеюсь, у вас тоже. Однако, сейчас Fastcgi Daemon запускается в консоли как обычное приложение. Где-же обещанная демонизация? Об этом поговорим ниже. Настройка daemon К счастью Fastcgi Daemon на то и Daemon, что его очень легко демонизировать (прошу прощения за тавтологию). Берём ранее созданный HelloFastCGI.conf, заменяем в нём относительный путь к libHelloFastCGI.so на абсолютный и кладём в /etc/fastcgi2/available. Теперь можно запускать/останавливать/перезапускать демона привычным способом: sudo service fascgi-daemon2 start/stop/restart <appname>/all В нашем случае это будет sudo service fastcgi-daemon2 start HelloFastCGI Чтобы запустить все доступные в /etc/fastcgi2/available приложения используем ключевое слово “all” sudo service fastcgi-daemon2 start all Немаловажным также является то, что в случае непредвиденного падения вашего приложения, оно будет автоматически перезапущено. Бенчмарки Любопытства ради решил сравнить производительность Fastcgi Daemon и NodeJS. Для этого набросал аналогичное приложение на JS: var http = require('http'); var url = require('url'); http.createServer(function (req, res) { res.writeHead(200, {'Content-Type': 'text/plain'}); var query = url.parse(req.url, true).query; res.end('Hello ' + (query.name ? query.name : 'stranger')); }).listen(1337, '127.0.0.1'); console.log('Server running at http://127.0.0.1:1337/'); Для чистоты эксперимента настроил proxy_pass в nginx для работы с node. Тестировал при помощи Apache Bench: ab -c 100 -n 20000 http://IPorURL/hellofastcgi?name=Nikolay и ab -c 100 -n 20000 http://IPorURL/?name=Nikolay Результаты: Fastcgi Daemon Concurrency Level: 100 Time taken for tests: 15.181 seconds Complete requests: 20000 Failed requests: 0 Write errors: 0 Non-2xx responses: 20000 Total transferred: 6460000 bytes HTML transferred: 3440000 bytes Requests per second: 1317.45 [#/sec] (mean) Time per request: 75.904 [ms] (mean) Time per request: 0.759 [ms] (mean, across all concurrent requests) Transfer rate: 415.56 [Kbytes/sec] received Connection Times (ms) min mean[+/-sd] median max Connect: 0 0 0.5 0 4 Processing: 12 75 31.2 68 474 Waiting: 9 73 31.4 66 471 Total: 12 76 31.3 68 475 Percentage of the requests served within a certain time (ms) 50% 68 66% 80 75% 85 80% 88 90% 96 95% 106 98% 114 99% 125 100% 475 (longest request) NodeJS Concurrency Level: 100 Time taken for tests: 23.038 seconds Complete requests: 20000 Failed requests: 0 Write errors: 0 Total transferred: 2700000 bytes HTML transferred: 260000 bytes Requests per second: 868.12 [#/sec] (mean) Time per request: 115.192 [ms] (mean) Time per request: 1.152 [ms] (mean, across all concurrent requests) Transfer rate: 114.45 [Kbytes/sec] received Connection Times (ms) min mean[+/-sd] median max Connect: 0 0 0.6 0 52 Processing: 39 114 21.7 109 306 Waiting: 28 112 21.5 107 305 Total: 40 115 21.7 109 306 Percentage of the requests served within a certain time (ms) 50% 109 66% 117 75% 125 80% 130 90% 145 95% 155 98% 168 99% 186 100% 306 (longest request) Стоит упомянуть, что всё это крутится на VirtualBox, которому выделено одно ядро от Core i7. В итоге получили разницу в полтора раза в пользу Fastcgi Daemon, что, как мне кажется, не так уж и плохо для NodeJS. Вот только потребление процессора у NodeJS доходило до 50%, а памяти — до 45 MБ (5.6 МБ в состоянии покоя). В то время как Fastcgi Daemon отъедал не более 20% процессора и 9.5 МБ RAM (4.5 МБ в состоянии покоя). То есть к ресурсам последний более дружелюбен, что неудивительно. Ясное дело, что сравнение получилось совсем сферическим в вакууме. По-хорошему, надо делать более насыщенный код, подключать БД, запускать оба приложения в многопоточном режиме. Но для начала и этого хватит. Вместо заключения На мой взгляд, очень интересный проект вышел из недр Яндекса. Помимо того, что Fastcgi Daemon значительно упрощает написание веб-приложений на C++, так ещё и содержит в себе необходимые init.d-скрипты для удобного управления уже готовыми приложениями. В следующий раз я опишу создание сервиса для авторизации на основе Fastcgi Daemon с сессиями, БД и шаблонами. Original source: habrahabr.ru (comments, light). Читать дальше -------------------- |
|
|
![]() ![]() |
Текстовая версия | Сейчас: 12.5.2025, 22:36 | |
|