Вспомню, как я с этим разбирался...
После недолгого изучения разных источников нашёл вот эту wiki. Это перевод официальной документации. Пользовался почти исключительно этим сайтом. Но прежде чем начать изучение, установим себе эту систему.
На официальном сайте скачиваем версию (на данный момент последняя стабильная - 2.0). Это архив с исходниками, собираем сами: после распаковки в каталоге делаем make. После сборки запускаем сервер с помощью:
$ ./redis-server
По умолчанию он поднимается на порту 6379 и дальше с ним можно взаимодействовать хотя бы даже и обычным telnet-ом. Но мы не будем так суровы :)
Для начала сделаем минимальные правки в конфиге: redis.conf в каталоге приложения - поставим daemonize yes, это позволит нам запускать сервер не отдавая ему консоль. Более тонкую настройку оставим на потом.
Запускать сервер теперь будем с явным указанием конфига:
$ ./redis-server redis.conf
Для освоения минимального набора команд воспользуемся консольным клиентом, который есть в сборке:
$ ./redis-cli <команда> <параметры ...>
Например, чтобы сохранить пару ключ-значение в Redis:
$ ./redis-cli set mykey myval
$ OK
... а чтобы получить значение по ключу:
$ ./redis-cli get mykey
$ "myval"
Redis поддерживает несколько типов данных для значений, которые мы "вкладываем" в ключи. Это строки, списки, множества и хэши. Детальнее посмотрите в руководстве, на пока понадобятся лишь имена команд, для каждого типа данных "геттеры" и "сеттеры" свои. Например для хэшей это:
hget, hset, hmset, hgetall... пока достаточно... (установить значение поля хэша, получить его, установить все поля-значения и получить все). Детально разбираться не будем, всё равно работать нам не в консоли. Достаточно просто понимать, какие есть инструменты.
Теперь переходим к Java.
Для работы с Redis есть несколько библиотек. Самая "живая" из них - Jedis, поддерживает версию 2.0, что нам и требуется.
Скачиваем её отсюда. Подключаем jedis-1.5.2.jar к проекту. Пишем класс для взаимодействия с redis:
Как видно из кода все методы библиотеки есть простые java-обёртки над командами Redis. А все наши методы - вызовы методов библиотеки. В конструктор нужно передать ip-адрес машины на которой запущен Redis-сервер, порт и пароль доступа к серверу. Третьим параметром передаём время ожидания ответа сервера в миллисекундах. Вообще, если есть такая возможность Redis лучше всего поднимать на той же машине, где работает наше приложение. Скорость обработки запросов у Redis на базе из миллиона записей составляет 1-2 миллисекунды. В сравнении с этим потери 20-50 ms на соединение (в лучшем случае) выглядят неприятно. Требования к памяти у Redis весьма скромные.
- /*
- * Redis get|set implementation
- */
- package net.multipi.connector.redis;
- import java.io.IOException;
- import java.util.Map;
- import java.util.Set;
- import redis.clients.jedis.Jedis;
- public class RedisConnector {
- private Jedis cli;
- /**
- * constructor: connect to Redis server and authorization
- * @param host
- * @param port
- * @param password
- */
- public RedisConnector(String host, int port, String password) {
- cli = new Jedis(host, port, 5000);
- cli.auth(password);
- try {
- cli.connect();
- } catch (Exception ex) {
- ex.printStackTrace(System.err);
- }
- }
- /**
- * calculate keys count (eg count of active sessions)
- * @return
- */
- public long getKeysCount() {
- return cli.dbSize();
- }
- /**
- * get all keys that begin with "begin" string
- * @param begin
- * @return
- */
- public Set<String> getAllKeys(String begin) {
- return cli.keys(begin+"*");
- }
- /**
- * set session values as map
- * @param sess
- * @param m
- * @return
- */
- public boolean setAll(String sess, Map<String, String> m) {
- String r = cli.hmset(sess, m);
- return (r.equals("OK"));
- }
- /**
- * set session values as map and set expire the session
- * @param sess
- * @param m
- * @param expire
- * @return
- */
- public boolean setAll(String sess, Map<String, String> m, int expire) {
- boolean rez = false;
- String r = cli.hmset(sess, m);
- long er = cli.expire(sess, expire);
- rez = (r.equals("OK") && er>0);
- return rez;
- }
- /**
- * set one of session values
- * @param sess
- * @param key
- * @param value
- * @return
- */
- public boolean set(String sess, String key, String value) {
- boolean rez = false;
- Map m = getAll(sess);
- if (m!=null) {
- m.put(key, value);
- rez = setAll(sess, m);
- }
- return rez;
- }
- /**
- * set or update session values and set expire
- * @param sess
- * @param key
- * @param value
- * @param expire
- * @return
- */
- public boolean set(String sess, String key, String value, int expire) {
- boolean rez = false;
- Map m = getAll(sess);
- if (m!=null) {
- m.put(key, value==null ? "" : value);
- rez = setAll(sess, m, expire);
- }
- return rez;
- }
- /**
- * check if session exists
- * @param sess
- * @return
- */
- public boolean isExists(String sess) {
- return cli.exists(sess);
- }
- /**
- * get session values
- * @param sess
- * @return
- */
- public Map<String, String> getAll(String sess) {
- return cli.hgetAll(sess);
- }
- /**
- * det session values and prolongs session
- * @param sess
- * @param expire
- * @return
- */
- public Map<String, String> getAll(String sess, int expire) {
- Map m = cli.hgetAll(sess);
- cli.hmset(sess, m);
- cli.expire(sess, expire);
- return m;
- }
- /**
- * get one of session values
- * @param sess
- * @param key
- * @return
- */
- public String get(String sess, String key) {
- return cli.hget(sess, key);
- }
- /**
- * delete session with all session data
- * @param sess
- * @return
- */
- public boolean del(String sess) {
- Long del = cli.del(sess);
- return del>0;
- }
- /**
- * close connection
- */
- public void close() {
- if (cli.isConnected()) {
- try {
- cli.disconnect();
- } catch (IOException ie) {}
- }
- }
- }
Использование Redis в качестве сессионного хранилища приятно ещё и тем, что в нём реализован механизм "устаревания" ключей. Достаточно установить срок жизни ключу и сервер сам "приберёт" его через указанное время. В текущей версии была неприятная особенность: после обновления значения ключ становился "вечным". Поэтому мы "напоминаем" ключам время жизни после апдейта, там где это нужно.
Ещё одна особенность едва не испортила впечатление от Jedis: при использовании внутреннего механизма пула соединений в этой библиотеке спустя 5-10 минут работы под нагрузкой система "засыпала", без видимой причины и без каких-либо ошибок прекращая реагировать на запросы. От пула пришлось отказаться, благо высокая скорость обработки запросов делала контроль за числом открытых коннектов задачей чисто "академической" важности.
В целом: инструмент весьма порадовал. После изнурительной борьбы за производительность запросов на "основной" БД скорость ответов от Redis создаёт прямо-таки фантастическое впечатление. А возможность работать с сервером "чем угодно", просто посылая команды на порт так и провоцирует написать свою реализацию клиента.
Комментариев нет:
Отправить комментарий