Книга: Программирование на языке Ruby
19.2. FastCGI
19.2. FastCGI
Чаще всего CGI критикуют за то, что при каждом запросе создается новый процесс, и это заметно снижает производительность. Невозможность сохранять в памяти объекты между последовательными запросами также не украшает дизайн системы. Для разрешения этих проблем была создана технология FastCGI.
По сути дела, FastCGI — это определение и программная реализация протокола. Обычно она реализуется в надстройки над Web-сервером, например модуля в случае сервера Apache. FastCGI позволяет работающему внутри процесса компоненту перехватывать HTTP-запросы и направлять их через сокет другому процессу, работающему в течение длительного времени. По сравнению с традиционным порождением новых процессов это существенно ускоряет работу. Кроме того, программист получает возможность оставить данные в памяти и найти их там при обработке следующего запроса.
Серверы, адаптированные для работы с FastCGI, реализованы на многих языках, в том числе на Ruby. Эли Грин (Eli Green) написал целиком на Ruby модуль (он есть в архиве RAA), который реализует протокол FastCGI и упрощает разработку FastCGI-программ.
Не вдаваясь в детали реализации, мы представили в листинге 19.1 пример приложения. Как видите, он повторяет функциональность предыдущего примера.
Листинг 19.1. Пример FastCGI
require "fastcgi"
require "cgi"
last_time = ""
def get_ramblings(instream)
# He слишком красивый способ извлечь значение из первой пары
# имя-значение. CGI сделал бы это за нас.
data = ""
if instream != nil
data = instream.split("&")[0].split(" = ")[1] || ""
end
return CGI.unescape(data)
end
def reverse_ramblings(ramblings)
if ramblings == nil then return "" end
chunks = ramblings.split(/s+/)
chunks.reverse.join(" ")
end
server = FastCGI::TCP.new('localhost', 9000)
begin
server.each_request do |request|
stuff = request.in.read
out = request.out
out << "Content-type: text/htmlrnrn"
out << <<-EOF
<html>
<head><titlе>Отражатель текста</title></head>
<h1>sdrawkcaB txeT</h1>
<i>Вы перед этим сказали: #{last_time}</i><BR>
<b>#{reverse_ramblings(get_ramblings(stuff))}</b>
<form method="POST" action="/fast/serv.rb">
<textarea name="ramblings">
</textarea>
<input type="submit" name="submit">
</form>
</body></html>
EOF
last_time = get_ramblings(stuff)
request.finish
end
ensure
server.close
end
Сразу же бросается в глаза (если вы читали предыдущий раздел) то, что в FastCGI приходится вручную делать кое-какие вещи, которые были не нужны при работе с библиотекой CGI
. Во-первых, «зашивание» в код экранированного HTML-кода. Во-вторых, метод get_ramblings
, который сам разбирает входные данные и возвращает нужное значение. Кстати, этот код будет работать только для POST-запросов — еще одно удобство, утраченное с отказом от библиотеки CGI.
Но вместе с тем у FastCGI есть и достоинства. Мы не проводили замеров, но — как следует из самого названия — FastCGI быстрее CGI. Вместо накладных расходов на создание нового процесса мы просто открываем соединение с портом 9000 на локальной машине (FastCGI::TCP.new('localhost', 9000)
). Кроме того, в переменной last_tim
e хранится часть состояния сеанса — вещь, невозможная в традиционной технологии CGI.
Отметим также, что эти библиотеки можно до определенного предела «смешивать». Вспомогательные функции из cgi.rb
, например метод CGI.escapeHTML
, можно использовать автономно (не делая библиотеку основой приложения). Тогда предыдущий пример оказался бы несколько проще для восприятия.