1. Обзор
Redisson — это клиент Redis для Java . В этой статье мы рассмотрим некоторые его функции и продемонстрируем, как он может облегчить создание распределенных бизнес-приложений.
Redisson представляет собой сетку данных в памяти , которая предлагает распределенные объекты и службы Java, поддерживаемые Redis . Его распределенная модель данных в памяти позволяет совместно использовать объекты и службы предметной области между приложениями и серверами.
В этой статье мы увидим, как настроить Redisson, понять, как он работает, и изучить некоторые объекты и сервисы Redisson.
2. Зависимости Maven
Давайте начнем с импорта Redisson
в наш проект, добавив раздел ниже в наш pom.xml:
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
<version>3.13.1</version>
</dependency>
Последнюю версию этой зависимости можно найти здесь .
3. Конфигурация
Прежде чем мы начнем, мы должны убедиться, что у нас установлена и запущена последняя версия Redis. Если у вас нет Redis и вы используете Linux или Macintosh, вы можете следовать приведенной здесь информации, чтобы настроить его. Если вы пользователь Windows, вы можете настроить Redis, используя этот неофициальный порт .
Нам нужно настроить Redisson для подключения к Redis. Redisson поддерживает подключения к следующим конфигурациям Redis:
- Один узел
- Мастер с подчиненными узлами
- Сторожевые узлы
- Кластерные узлы
- Реплицированные узлы
Redisson поддерживает кластер Amazon Web Services (AWS) ElastiCache и кэш Azure Redis для кластеризованных и реплицированных узлов.
Давайте подключимся к экземпляру Redis с одним узлом. Этот экземпляр работает локально на порту по умолчанию 6379:
RedissonClient client = Redisson.create();
Вы можете передавать различные конфигурации в метод создания
объекта Redisson
. Это могут быть конфигурации для подключения к другому порту или, может быть, для подключения к кластеру Redis. Эта конфигурация может быть в коде Java или загружена из внешнего файла конфигурации . `` ****
3.1. Конфигурация Java
Давайте настроим Redisson в коде Java:
Config config = new Config();
config.useSingleServer()
.setAddress("redis://127.0.0.1:6379");
RedissonClient client = Redisson.create(config);
Мы указываем конфигурации Redisson в экземпляре объекта Config
, а затем передаем его в метод create
. Выше мы указали Redisson, что хотим подключиться к экземпляру Redis с одним узлом. Для этого мы использовали метод useSingleServer
объекта Config
. Это возвращает ссылку на объект SingleServerConfig
.
Объект SingleServerConfig
имеет настройки, которые Redisson использует для подключения к экземпляру Redis с одним узлом. Здесь мы используем его метод setAddress
для настройки параметра адреса
. Это устанавливает адрес узла, к которому мы подключаемся. Некоторые другие параметры включают retryAttempts
, connectionTimeout
и clientName
. Эти параметры настраиваются с использованием соответствующих методов установки.
Мы можем настроить Redisson для различных конфигураций Redis аналогичным образом, используя следующие методы объекта Config :
useSingleServer
— для экземпляра с одним узлом. Получить настройки одного узла здесьuseMasterSlaveServers
— для мастера с подчиненными узлами. Получите настройки узла master-slave здесьuseSentinelServers
— для дозорных узлов. Получите настройки дозорного узла здесьuseClusterServers
— для кластерных узлов. Получите настройки кластерного узла здесьuseReplicatedServers
— для реплицированных узлов. Получите реплицированные настройки узла здесь
3.2. Конфигурация файла
Redisson может загружать конфигурации из внешних файлов JSON или YAML:
Config config = Config.fromJSON(new File("singleNodeConfig.json"));
RedissonClient client = Redisson.create(config);
Метод fromJSON
объекта Config
может загружать конфигурации из строки, файла, входного потока или URL-адреса. ``
Вот пример конфигурации в файле singleNodeConfig.json
:
{
"singleServerConfig": {
"idleConnectionTimeout": 10000,
"connectTimeout": 10000,
"timeout": 3000,
"retryAttempts": 3,
"retryInterval": 1500,
"password": null,
"subscriptionsPerConnection": 5,
"clientName": null,
"address": "redis://127.0.0.1:6379",
"subscriptionConnectionMinimumIdleSize": 1,
"subscriptionConnectionPoolSize": 50,
"connectionMinimumIdleSize": 10,
"connectionPoolSize": 64,
"database": 0,
"dnsMonitoringInterval": 5000
},
"threads": 0,
"nettyThreads": 0,
"codec": null
}
Вот соответствующий файл конфигурации YAML:
singleServerConfig:
idleConnectionTimeout: 10000
connectTimeout: 10000
timeout: 3000
retryAttempts: 3
retryInterval: 1500
password: null
subscriptionsPerConnection: 5
clientName: null
address: "redis://127.0.0.1:6379"
subscriptionConnectionMinimumIdleSize: 1
subscriptionConnectionPoolSize: 50
connectionMinimumIdleSize: 10
connectionPoolSize: 64
database: 0
dnsMonitoringInterval: 5000
threads: 0
nettyThreads: 0
codec: !<org.redisson.codec.JsonJacksonCodec> {}
Мы можем настроить другие конфигурации Redis из файла аналогичным образом, используя настройки, характерные для этой конфигурации. Для справки, вот их форматы файлов JSON и YAML:
- Одиночный узел – формат
- Мастер с подчиненными узлами – формат
- Узлы Sentinel — формат
- Кластерные узлы — формат
- Реплицированные узлы — формат
Чтобы сохранить конфигурацию Java в формате JSON или YAML, мы можем использовать методы toJSON
или toYAML объекта
Config
:
Config config = new Config();
// ... we configure multiple settings here in Java
String jsonFormat = config.toJSON();
String yamlFormat = config.toYAML();
Теперь, когда мы знаем, как настроить Redisson, давайте посмотрим, как Redisson выполняет операции.
4. Операция
Redisson поддерживает синхронные, асинхронные и реактивные интерфейсы . Операции над этими интерфейсами потокобезопасны .
Все сущности (объекты, коллекции, блокировки и службы), созданные RedissonClient
, имеют синхронные и асинхронные методы. Синхронные методы имеют асинхронные варианты . Эти методы обычно имеют то же имя метода, что и их синхронные варианты, с добавлением «Async». Давайте посмотрим на синхронный метод объекта RAtomicLong
:
RedissonClient client = Redisson.create();
RAtomicLong myLong = client.getAtomicLong('myLong');
Асинхронный вариант синхронного метода compareAndSet
будет таким:
RFuture<Boolean> isSet = myLong.compareAndSetAsync(6, 27);
Асинхронный вариант метода возвращает объект RFuture
. Мы можем установить прослушиватели для этого объекта, чтобы получить результат, когда он станет доступным:
isSet.handle((result, exception) -> {
// handle the result or exception here.
});
Для создания реактивных объектов нам потребуется использовать RedissonReactiveClient
:
RedissonReactiveClient client = Redisson.createReactive();
RAtomicLongReactive myLong = client.getAtomicLong("myLong");
Publisher<Boolean> isSetPublisher = myLong.compareAndSet(5, 28);
Этот метод возвращает реактивные объекты на основе стандарта Reactive Streams для Java 9.
Давайте рассмотрим некоторые распределенные объекты, предоставляемые Redisson.
5. Объекты
Отдельный экземпляр объекта Redisson сериализуется и сохраняется на любом из доступных узлов Redis, поддерживающих Redisson . Эти объекты могут быть распределены в кластере по нескольким узлам, и доступ к ним может осуществляться одним приложением или несколькими приложениями/серверами.
Эти распределенные объекты соответствуют спецификациям пакета java.util.concurrent.atomic.
Они поддерживают безблокировочные, потокобезопасные и атомарные операции над объектами, хранящимися в Redis . Согласованность данных между приложениями/серверами обеспечивается, поскольку значения не обновляются, пока другое приложение считывает объект.
Объекты Redisson привязаны к ключам Redis. Мы можем управлять этими ключами через интерфейс RKeys
. И затем мы получаем доступ к нашим объектам Redisson, используя эти ключи.
Есть несколько вариантов, которые мы можем использовать для получения ключей Redis.
Мы можем просто получить все ключи:
RKeys keys = client.getKeys();
В качестве альтернативы мы можем извлечь только имена:
Iterable<String> allKeys = keys.getKeys();
И, наконец, мы можем получить ключи, соответствующие шаблону:
Iterable<String> keysByPattern = keys.getKeysByPattern('key*')
Интерфейс RKeys также позволяет удалять ключи, удалять ключи по шаблону и выполнять другие полезные операции на основе ключей, которые мы могли бы использовать для управления нашими ключами и объектами.
Распределенные объекты, предоставляемые Redisson, включают:
ObjectHolder
BinaryStreamHolder
GeospatialHolder
Битсет
AtomicLong
АтомныйДабл
Тема
БлумФильтр
Гиперлоглог
Давайте рассмотрим три из этих объектов: ObjectHolder, AtomicLong
и Topic.
5.1. Держатель объекта
Представленный классом RBucket
, этот объект может содержать любой тип объекта. Этот объект имеет максимальный размер 512 МБ:
RBucket<Ledger> bucket = client.getBucket("ledger");
bucket.set(new Ledger());
Ledger ledger = bucket.get();
Объект RBucket
может выполнять атомарные операции, такие как compareAndSet и
getAndSet
, с объектами, которые он содержит.
5.2. AtomicLong
Представленный классом RAtomicLong
, этот объект очень похож на класс java.util.concurrent.atomic.AtomicLong
и представляет длинное
значение, которое может быть обновлено атомарно:
RAtomicLong atomicLong = client.getAtomicLong("myAtomicLong");
atomicLong.set(5);
atomicLong.incrementAndGet();
5.3. Тема
Объект Topic
поддерживает механизм «публикации и подписки» Redis. Чтобы прослушать опубликованные сообщения:
RTopic subscribeTopic = client.getTopic("foreach");
subscribeTopic.addListener(CustomMessage.class,
(channel, customMessage) -> future.complete(customMessage.getMessage()));
Выше Тема
зарегистрирована для прослушивания сообщений с канала «foreach». Затем мы добавляем прослушиватель в тему для обработки входящих сообщений из этого канала. Мы можем добавить несколько слушателей на канал.
Публикуем сообщения на канал «foreach»:
RTopic publishTopic = client.getTopic("foreach");
long clientsReceivedMessage
= publishTopic.publish(new CustomMessage("This is a message"));
Это может быть опубликовано из другого приложения или сервера. Объект CustomMessage
будет получен прослушивателем и обработан, как определено в методе onMessage
.
Подробнее о других объектах Redisson мы можем узнать здесь .
6. Коллекции
Мы работаем с коллекциями Redisson так же, как с объектами.
Распределенные коллекции, предоставляемые Redisson, включают:
карта
Мультикарта
Установлен
Сортированный набор
Сортированный набор
- Лекс
СортедСет
Список
Очередь
Дек
Блокировка очереди
ограниченная блокировка очереди
BlockingDeque
БлокировкаFairQueue
Отложенная очередь
PriorityQueue
PriorityDeque
Давайте рассмотрим три из этих коллекций: Map, Set
и List.
6.1. карта
Карты на основе Redisson реализуют интерфейсы java.util.concurrent.ConcurrentMap
и java.util.Map .
У Redisson есть четыре реализации карт. Это RMap
, RMapCache
, RLocalCachedMap
и RClusteredMap
.
Давайте создадим карту с Redisson:
RMap<String, Ledger> map = client.getMap("ledger");
Ledger newLedger = map.put("123", new Ledger());map
RMapCache
поддерживает вытеснение записи карты. RLocalCachedMap
позволяет локально кэшировать записи карты . RClusteredMap
позволяет разделить данные из одной карты между главными узлами кластера Redis.
Подробнее о картах Redisson мы можем узнать здесь .
6.2. Установлен
Set на основе Redisson реализует
интерфейс java.util.Set .
У Redisson есть три реализации Set :
RSet
, RSetCache
и RClusteredSet
с функциональностью, аналогичной их аналогам карты.
Давайте создадим сет
с Redisson:
RSet<Ledger> ledgerSet = client.getSet("ledgerSet");
ledgerSet.add(new Ledger());
Подробнее о наборах Redisson мы можем узнать здесь .
6.3. Список
Списки на основе Redisson
реализуют интерфейс java.util.List .
Давайте создадим список
с Redisson:
RList<Ledger> ledgerList = client.getList("ledgerList");
ledgerList.add(new Ledger());
Узнать больше о других коллекциях Redisson можно здесь .
7. Блокировки и синхронизаторы
Распределенные блокировки Redisson позволяют синхронизировать потоки между приложениями/серверами. Список замков и синхронизаторов Redisson включает:
Замок
Фэйрлок
Мультилок
ReadWriteLock
семафор
PermitExpirableSemaphore
Защелка
Давайте взглянем на Lock
и MultiLock.
7.1. Замок
Блокировка
Redisson реализует интерфейс java.util.concurrent.locks.Lock .
Давайте реализуем блокировку, представленную классом RLock
:
RLock lock = client.getLock("lock");
lock.lock();
// perform some long operations...
lock.unlock();
7.2. Мультилок
RedissonMultiLock группирует
несколько объектов RLock
и обрабатывает их как одну блокировку: ``
RLock lock1 = clientInstance1.getLock("lock1");
RLock lock2 = clientInstance2.getLock("lock2");
RLock lock3 = clientInstance3.getLock("lock3");
RedissonMultiLock lock = new RedissonMultiLock(lock1, lock2, lock3);
lock.lock();
// perform long running operation...
lock.unlock();
Мы можем узнать больше о других замках здесь .
8. Услуги
Redisson предоставляет 4 типа распределенных сервисов. Это: удаленная служба , служба живых объектов , служба исполнителя и служба исполнителя по расписанию . Давайте посмотрим на удаленную службу и службу живых объектов.
8.1. Удаленное обслуживание
Эта служба обеспечивает удаленный вызов методов Java с помощью Redis . Удаленная служба Redisson состоит из реализации на стороне сервера (рабочий экземпляр) и реализации на стороне клиента. Реализация на стороне сервера выполняет удаленный метод, вызванный клиентом. Вызовы из удаленной службы могут быть синхронными или асинхронными.
На стороне сервера регистрируется интерфейс для удаленного вызова:
RRemoteService remoteService = client.getRemoteService();
LedgerServiceImpl ledgerServiceImpl = new LedgerServiceImpl();
remoteService.register(LedgerServiceInterface.class, ledgerServiceImpl);
Клиентская сторона вызывает метод зарегистрированного удаленного интерфейса:
RRemoteService remoteService = client.getRemoteService();
LedgerServiceInterface ledgerService
= remoteService.get(LedgerServiceInterface.class);
List<String> entries = ledgerService.getEntries(10);
Мы можем узнать больше об удаленных услугах здесь .
8.2. Служба живых объектов
Redisson Live Objects расширяет концепцию стандартных объектов Java, доступ к которым возможен только из одной виртуальной машины JVM, до расширенных объектов Java, которые могут совместно использоваться различными виртуальными машинами JVM на разных машинах . Это достигается путем сопоставления полей объекта с хешем Redis. Это сопоставление выполняется через прокси-класс, созданный во время выполнения. Методы получения и установки полей сопоставляются с командами Redis hget/hset.
Redisson Live Objects поддерживает доступ к атомарным полям благодаря однопоточной природе Redis.
Создать живой объект просто:
@REntity
public class LedgerLiveObject {
@RId
private String name;
// getters and setters...
}
Мы аннотируем наш класс с помощью @REntity
и уникальное или идентифицирующее поле с помощью @RId
. Как только мы это сделали, мы можем использовать наш Live Object в нашем приложении:
RLiveObjectService service = client.getLiveObjectService();
LedgerLiveObject ledger = new LedgerLiveObject();
ledger.setName("ledger1");
ledger = service.persist(ledger);
Мы создаем наш Live Object как стандартные объекты Java, используя ключевое слово new
. Затем мы используем экземпляр RLiveObjectService
для сохранения объекта в Redis с помощью его метода persist .
Если объект ранее был сохранен в Redis, мы можем получить объект:
LedgerLiveObject returnLedger
= service.get(LedgerLiveObject.class, "ledger1");
Мы используем RLiveObjectService
, чтобы получить наш Live Object, используя поле с аннотацией @RId
.
Здесь мы можем найти больше о Redisson Live Objects, а другие услуги Redisson описаны здесь.
9. Конвейерная обработка
Redisson поддерживает конвейерную обработку. Несколько операций могут быть объединены в одну атомарную операцию . Этому способствует класс RBatch
. Несколько команд объединяются с экземпляром объекта RBatch
перед их выполнением:
RBatch batch = client.createBatch();
batch.getMap("ledgerMap").fastPutAsync("1", "2");
batch.getMap("ledgerMap").putAsync("2", "5");
BatchResult<?> batchResult = batch.execute();
10. Сценарии
Redisson поддерживает сценарии LUA. Мы можем выполнять сценарии LUA против Redis :
client.getBucket("foo").set("bar");
String result = client.getScript().eval(Mode.READ_ONLY,
"return redis.call('get', 'foo')", RScript.ReturnType.VALUE);
11. Низкоуровневый клиент
Возможно, нам захочется выполнять операции Redis, еще не поддерживаемые Redisson. Redisson предоставляет низкоуровневый клиент, который позволяет выполнять собственные команды Redis :
RedisClientConfig redisClientConfig = new RedisClientConfig();
redisClientConfig.setAddress("localhost", 6379);
RedisClient client = RedisClient.create(redisClientConfig);
RedisConnection conn = client.connect();
conn.sync(StringCodec.INSTANCE, RedisCommands.SET, "test", 0);
conn.closeAsync();
client.shutdown();
Клиент низкого уровня также поддерживает асинхронные операции.
12. Заключение
В этой статье был продемонстрирован Redisson и некоторые функции, которые делают его идеальным для разработки распределенных приложений. Мы исследовали его распределенные объекты, коллекции, блокировки и сервисы. Мы также изучили некоторые другие его функции, такие как конвейерная обработка, сценарии и низкоуровневый клиент.
Redisson также обеспечивает интеграцию с другими платформами , такими как JCache API, Spring Cache, Hibernate Cache и Spring Sessions. Подробнее о его интеграции с другими фреймворками мы можем узнать здесь .
Примеры кода вы можете найти в проекте GitHub .