Сегодня я расскажу как можно работать с базой данных PostgreSQL с помощью nginx’a без application’a (например, PHP или любого другого). Т.е. эта технология абсолютно не зависит от языка, на котором сделан сайт/проект/система.
Мы будем использовать мощь PostgreSQL в хранимых процедурах (stored procedures/functions), а кэшировать с помощью быстрого Redis.
Для начала возьмём нашу БД PostgreSQL и создадим хранимую процедуру на языке PL/pgSQL. В принципе, вы можете обойтись и без неё, но в данном случаи SQL Injection вам обеспечен
Выберем последние 25 записей из какой-нибудь таблицы (public.sometable
) и вернём это всё в формате JSON.
CREATE OR REPLACE FUNCTION __sometable_getlist() RETURNS text AS
$BODY$
DECLARE
data record;
return_data text := '';
BEGIN
FOR data IN
SELECT
id,
title,
content
FROM
public.sometable
ORDER BY
id DESC
LIMIT
25
LOOP
return_data := return_data || row_to_json(data)::text || ',';
END LOOP;
RETURN '[' || rtrim( return_data, ',' ) || ']';
END;
$BODY$
LANGUAGE plpgsql VOLATILE
COST 1;
Запустить её можно так:
SELECT * FROM __sometable_getlist()
Теперь возьмём сервер с FreeBSD и добавим 5 модулей для nginx’a:
- Postgres — модуль доступа к БД PostgreSQL
- SRCache — модуль кэширования результатов
- Echo — модуль, необходимый для SRCache
- HTTP Redis — модуль Redis (необходим для SRCache)
- Redis 2 — модуль Redis версии 2.x (необходим для SRCache)
Через командную строку это выглядит так:
cd /usr/ports/www/nginx
make config && make && make install clean
После того как nginx пересоберётся, мы готовы к настройке его конфигов.
Для начала добавим 2 upstream’a (PostgreSQL и Redis) в секции http
:
upstream database {
postgres_server
127.0.0.1:5432
dbname=databasename
user=databaseuser
password=megacoolpassword;
}
upstream redis2 {
server
127.0.0.1:6379;
}
Также добавим location’ы в секцию описания нашего server
, что будут читать (/redis/get
) и писать (/redis/set
) в Redis по ключу.
location /redis/get {
internal;
set $redis_key $arg_key;
redis_pass redis2;
}
location /redis/set {
internal;
set $redis_key $arg_key;
redis2_query select 0;
redis2_query set $redis_key $echo_request_body;
redis2_query expire $redis_key 60;
redis2_pass redis2;
}
Обратите внимание, что эти location’ы имеют аттрибут internal
, что означает что извне по этому адресу доступиться невозможно.
Теперь, когда у нас описаны сервера и есть location’ы для чтения и записи кэша, мы можем добавить адрес, по-которому нам и нужно получать наш результат в формате JSON.
Пускай, для примера, адрес будет следующим /json/sometable/list
.
Тогда в конфиг nginx’a в секцию описания нашего server
мы напишем:
location /json/sometable/list {
default_type application/json;
set $key "sometable_getlist";
srcache_fetch GET /redis/get key=$key;
srcache_store PUT /redis/set key=$key;
srcache_store_statuses 200;
postgres_pass database;
postgres_query "select * from __sometable_getlist()";
postgres_output text;
}
В итоге на запрошенный URL мы получим JSON-ответ, что можем далее использовать как нам будет удобно.
Теперь о скорости.
Время выполнения БД сравнивать нет смысла. Следовательно, необходимо сравнивать как быстро до клиента дойдёт ответ через связку nginx->redis
и nginx->php-fpm->php-redis
.
У меня связка nginx->redis
«выстреливает» за 3 ms,
а nginx->php-fpm->php-redis
аж за 12 ms.
Что, впрочем, ожидаемо.