Подключение к шардированному кластеру Redis
Для подключения к шардированному кластеру Redis в строках подключения укажите FQDN хостов-мастеров в каждом шарде.
Поддерживаются шифрованное соединение через порт 6380
и нешифрованное через порт 6379
.
Важно
Используя SSL-соединение, можно подключаться только к кластерам с включенной настройкой Поддержка TLS.
Подключение из графических IDE
Подключение проверялось в следующем окружении:
- MacOS Big Sur 11.3.
- DBeaver Enterprise:
21.0
.
Подключаться из графических IDE к хостам кластера можно только через SSH-туннель с помощью созданной ВМ. Перед подключением подготовьте сертификат.
Чтобы избежать ошибок при подключении, сохраните сертификат
Поддержка подключения к кластеру Redis доступна только в коммерческих редакциях DBeaver
Чтобы подключиться к кластеру:
- Создайте новое соединение с БД:
- Выберите в меню База данных пункт Новое соединение.
- Выберите из списка БД Redis.
- Нажмите кнопку Далее.
- Укажите параметры подключения на вкладке Главное:
-
Хост — укажите через запятую FQDN хостов-мастеров каждого шарда.
О том, как получить FQDN хоста, см. инструкцию.
-
Порт —
6379
для обычного кластера или6380
для кластера с включенным SSL-шифрованием. -
В блоке Аутентификация укажите пароль от кластера.
-
- На вкладке SSH:
- Включите настройку Использовать туннель SSH.
- Укажите параметры SSH-туннеля:
- Хост/IP — публичный IP-адрес ВМ для подключения;
- Имя пользователя — логин для подключения к ВМ;
- Метод аутентификации —
Публичный ключ
; - Секретный ключ — путь к файлу закрытого ключа для подключения к ВМ;
- Passphrase — пароль от закрытого ключа.
- На вкладке SSL:
- Включите настройки Использовать SSL и Пропустить валидацию имени хоста.
- В блоке Параметры:
- Выберите Способ — Набор сертификатов.
- В поле Корневой сертификат укажите путь к сохраненному файлу SSL-сертификата.
- Нажмите кнопку Тест соединения ... для проверки соединения с БД. При успешном подключении будет выведен статус подключения, информация о СУБД и драйвере.
- Нажмите кнопку Готово, чтобы сохранить настройки соединения с БД.
Подготовка к подключению из Docker-контейнера
Чтобы подключаться к кластеру Managed Service for Redis из Docker-контейнера, добавьте в Dockerfile строки:
# Собрать вручную утилиту redis-tools с поддержкой TLS.
RUN apt-get update && \
apt-get install make gcc libssl-dev --yes && \
wget https://download.redis.io/redis-stable.tar.gz && \
tar -xzvf redis-stable.tar.gz && \
cd redis-stable && \
make BUILD_TLS=yes MALLOC=libc && \
make install && \
cp ./src/redis-cli /usr/bin/
# Собрать вручную утилиту redis-tools с поддержкой TLS.
RUN apt-get update && \
apt-get install wget make gcc libssl-dev --yes && \
wget https://download.redis.io/redis-stable.tar.gz && \
tar -xzvf redis-stable.tar.gz && \
cd redis-stable && \
make BUILD_TLS=yes MALLOC=libc && \
make install && \
cp ./src/redis-cli /usr/bin/ && \
# Получить SSL-сертификат.
mkdir --parents ~/.redis && \
wget "https://storage.yandexcloud.net/cloud-certs/CA.pem" \
--output-document ~/.redis/YandexInternalRootCA.crt && \
chmod 0655 ~/.redis/YandexInternalRootCA.crt
Примеры строк подключения
Примеры для Linux проверялись в следующем окружении:
- Виртуальная машина в Yandex Cloud с Ubuntu 20.04 LTS.
- Bash:
5.0.16
. - Python:
3.8.2
; pip3:20.0.2
. - PHP:
7.4.3
. - OpenJDK:
11.0.8
; Maven:3.6.3
. - Node.JS:
10.19.0
, npm:6.14.4
. - Go:
1.13.8
. - Ruby:
2.7.0p0
. - unixODBC:
2.3.6
.
Примеры для Windows проверялись в следующем окружении:
- Локальная машина с Windows 10 Pro build
19042.1052
. - PowerShell:
5.1.19041
. - cURL:
7.55.1 WinSSL
.
Примеры кода с заполненным FQDN хоста доступны в консоли управления
Bash
Перед подключением установите зависимости:
sudo apt update && sudo apt install -y redis-tools
Подключение напрямую к мастеру:
Укажите FQDN хоста-мастера в нужном шарде:
redis-cli \
-c \
-h <FQDN_хоста-мастера_в_нужном_шарде> \
-a <пароль>
Перед подключением установите зависимости:
Соберите утилиту redis-tools
с поддержкой TLS одним из двух способов::
-
Из репозитория
-
Подключите репозиторий:
sudo apt-add-repository ppa:redislabs/redis
Пакеты в этом репозитории уже собраны с флагом
BUILD_TLS=yes
. -
Установите утилиту:
sudo apt update && sudo apt install -y redis-tools
-
-
Вручную
Перейдите в директорию, куда хотите скачать дистрибутив. Скачайте стабильную версию утилиты и выполните сборку и установку:
wget https://download.redis.io/redis-stable.tar.gz && \ tar -xzvf redis-stable.tar.gz && \ cd redis-stable && \ make BUILD_TLS=yes && \ sudo make install && \ sudo cp ./src/redis-cli /usr/bin/
Подключение напрямую к мастеру:
Укажите FQDN хоста-мастера в нужном шарде:
redis-cli \
-c \
-h <FQDN_хоста-мастера_в_нужном_шарде> \
-a <пароль> \
-p 6380 \
--tls \
--cacert ~/.redis/YandexInternalRootCA.crt \
О том, как получить FQDN хоста, см. инструкцию.
После подключения к кластеру выполните команды:
SET foo bar
GET foo
Если запрос GET
возвращает значение nil
, значит, запись для ключа foo
была перемещена на другой шард. Подключитесь к нему и повторите запрос — он вернет значение bar
.
Go
Перед подключением установите зависимости:
sudo apt update && sudo apt install --yes golang git && \
go mod init github.com/go-redis/redis && \
go get github.com/redis/go-redis/v9
connect.go
package main
import (
"fmt"
"github.com/go-redis/redis/v7"
"time"
)
func main() {
hostports := []string{
"<FQDN_хоста-мастера_в_шарде_1>:6379",
...
"<FQDN_хоста-мастера_в_шарде_N>:6379",
}
options := redis.UniversalOptions{
Addrs: hostports,
DB: 0,
ReadOnly: false,
DialTimeout: 5 * time.Second,
Password: "<пароль>",
}
client := redis.NewUniversalClient(&options)
err := client.Set("foo", "bar", 0).Err()
if err != nil {
panic(err)
}
result, err := client.Get("foo").Result()
if err != nil {
panic(err)
}
fmt.Println(result)
client.Close()
}
connect.go
package main
import (
"context"
"crypto/tls"
"crypto/x509"
"fmt"
"net"
"os"
"strings"
"time"
"github.com/redis/go-redis/v9"
)
func main() {
caCert, err := os.ReadFile("/home/<домашняя_директория>/.redis/YandexInternalRootCA.crt")
if err != nil {
panic(err)
}
caCertPool := x509.NewCertPool()
caCertPool.AppendCertsFromPEM(caCert)
hostports := []string{
"<FQDN_хоста-мастера_в_шарде_1>:6380",
...
"<FQDN_хоста-мастера_в_шарде_N>:6380",
}
options := redis.UniversalOptions{
Addrs: hostports,
MaxRedirects: 1,
Password: "password",
DB: 0,
ReadOnly: false,
DialTimeout: 5 * time.Second,
TLSConfig: &tls.Config{
RootCAs: caCertPool,
ServerName: "c-<идентификатор_кластера>.rw.mdb.yandexcloud.net",
VerifyPeerCertificate: func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error {
certs := make([]*x509.Certificate, len(rawCerts))
for i := 0; i < len(rawCerts); i++ {
cert, err := x509.ParseCertificate(rawCerts[i])
if err != nil {
return fmt.Errorf("error parsing certificate: %+v", err)
}
certs[i] = cert
}
opts := x509.VerifyOptions{
Roots: caCertPool,
CurrentTime: time.Now(),
DNSName: "",
Intermediates: x509.NewCertPool(),
}
for i := range certs {
if i == 0 {
continue
}
opts.Intermediates.AddCert(certs[i])
}
_, err := certs[0].Verify(opts)
return err
},
},
}
options.Dialer = func(ctx context.Context, network, addr string) (net.Conn, error) {
parts := strings.Split(addr, ":")
newAddr := addr
if len(parts) > 1 && !strings.HasPrefix(parts[0], "[") {
newAddr = "[" + strings.Join(parts[:len(parts)-1], ":") + "]:" + parts[len(parts)-1]
}
netDialer := &net.Dialer{
Timeout: options.DialTimeout,
KeepAlive: 5 * time.Minute,
}
return tls.DialWithDialer(netDialer, network, newAddr, options.TLSConfig)
}
ctx := context.Background()
client := redis.NewUniversalClient(&options)
err = client.Set(ctx, "foo", "bar", 0).Err()
if err != nil {
panic(err)
}
get := client.Get(ctx, "foo")
err = get.Err()
if err != nil {
panic(err)
}
fmt.Println(get.String())
}
О том, как получить FQDN хоста, см. инструкцию.
Подключение:
go run connect.go
При успешном подключении к кластеру и выполнении тестового запроса будет выведена строка bar
.
Java
Перед подключением:
-
Установите зависимости:
sudo apt update && sudo apt install --yes default-jdk maven
-
Создайте директорию для проекта Maven:
cd ~/ && mkdir --parents project/src/java/com/example && cd project/
-
Создайте конфигурационный файл для Maven:
pom.xml
<?xml version="1.0" encoding="utf-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.example</groupId> <artifactId>app</artifactId> <packaging>jar</packaging> <version>0.1.0</version> <properties> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> </properties> <dependencies> <dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>3.7.0</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-simple</artifactId> <version>1.7.30</version> </dependency> </dependencies> <build> <finalName>${project.artifactId}-${project.version}</finalName> <sourceDirectory>src</sourceDirectory> <resources> <resource> <directory>src</directory> </resource> </resources> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-assembly-plugin</artifactId> <executions> <execution> <goals> <goal>attached</goal> </goals> <phase>package</phase> <configuration> <descriptorRefs> <descriptorRef> jar-with-dependencies</descriptorRef> </descriptorRefs> <archive> <manifest> <mainClass>com.example.App</mainClass> </manifest> </archive> </configuration> </execution> </executions> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-jar-plugin</artifactId> <version>3.1.0</version> <configuration> <archive> <manifest> <mainClass>com.example.App</mainClass> </manifest> </archive> </configuration> </plugin> </plugins> </build> </project>
Актуальные версии зависимостей для Maven:
-
Для подключения с SSL:
-
Создайте защищенное хранилище сертификатов:
keytool -importcert \ -alias YARootCrt \ -file ~/.redis/YandexInternalRootCA.crt \ -keystore ~/.redis/YATrustStore \ -storepass <пароль_защищенного_хранилища> \ --noprompt && chmod 0655 ~/.redis/YATrustStore
src/java/com/example/App.java
package com.example;
import java.util.HashSet;
import redis.clients.jedis.HostAndPort;
import redis.clients.jedis.JedisCluster;
import redis.clients.jedis.JedisPoolConfig;
public class App {
public static void main(String[] args) {
JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
HashSet<HostAndPort> jedisClusterNodes = new HashSet<HostAndPort>();
jedisClusterNodes.add(new HostAndPort("<FQDN_хоста-мастера_в_шарде_1>", 6379));
...
jedisClusterNodes.add(new HostAndPort("<FQDN_хоста-мастера_в_шарде_N>", 6379));
DefaultJedisClientConfig jedisClientConfig = DefaultJedisClientConfig.builder().
password("<пароль>").
build();
try {
JedisCluster jc = new JedisCluster(jedisClusterNodes, jedisClientConfig, 5, jedisPoolConfig);
jc.set("foo", "bar");
System.out.println(jc.get("foo"));
jc.close();
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
src/java/com/example/App.java
package com.example;
import redis.clients.jedis.DefaultJedisClientConfig;
import redis.clients.jedis.HostAndPort;
import redis.clients.jedis.JedisCluster;
import redis.clients.jedis.JedisPoolConfig;
import javax.net.ssl.SSLParameters;
import java.util.HashSet;
import java.util.Set;
public class App {
public static void main(String[] args) {
System.setProperty("javax.net.ssl.trustStore", "/home/<домашняя_директория>/.redis/YATrustStore");
System.setProperty("javax.net.ssl.trustStorePassword", "<пароль_защищенного_хранилища_сертификатов>");
JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
Set<HostAndPort> jedisClusterNodes = new HashSet<HostAndPort>();
SSLParameters sslParameters = new SSLParameters();
jedisClusterNodes.add(new HostAndPort("<FQDN_хоста-мастера_в_шарде_1>", 6380));
...
jedisClusterNodes.add(new HostAndPort("<FQDN_хоста-мастера_в_шарде_N>", 6380));
DefaultJedisClientConfig jedisClientConfig = DefaultJedisClientConfig.builder().
password("<пароль_кластера>").
ssl(true).
sslParameters(sslParameters).
build();
try {
JedisCluster jc = new JedisCluster(jedisClusterNodes, jedisClientConfig, 5, jedisPoolConfig);
jc.set("foo", "bar");
System.out.println(jc.get("foo"));
jc.close();
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
О том, как получить FQDN хоста, см. инструкцию.
Подключение:
mvn clean package && \
java -jar target/app-0.1.0-jar-with-dependencies.jar
При успешном подключении к кластеру и выполнении тестового запроса будет выведена строка bar
.
Node.js
Перед подключением установите зависимости:
sudo apt update && sudo apt install --yes nodejs npm && \
npm install ioredis
app.js
"use strict";
const Redis = require("ioredis");
const cluster = new Redis.Cluster(
[
{
host: "<FQDN_хоста-мастера_в_шарде_1>",
port: 6379
},
...
{
host: "<FQDN_хоста-мастера_в_шарде_N>",
port: 6379
}
],
{
redisOptions: {
password: "<пароль>"
}
}
);
cluster.on("ready", () => {
Promise.all([
cluster.set("foo", "bar"),
cluster.get("foo")
]).then(
(result) => {
console.log(result[1]); // result == ["OK", "bar"]
cluster.disconnect();
},
(reject) => {
console.log(reject);
cluster.disconnect();
}
);
});
app.js
"use strict";
const Redis = require("ioredis");
const fs = require("fs");
const cluster = new Redis.Cluster(
[
{
host: "<FQDN_хоста-мастера_в_шарде_1>",
port: 6380
},
...
{
host: "<FQDN_хоста-мастера_в_шарде_N>",
port: 6380
},
],
{
redisOptions: {
password: "<пароль>",
tls: {
ca: [fs.readFileSync("/home/<домашняя_директория>/.redis/YandexInternalRootCA.crt")],
checkServerIdentity: () => {
return null;
}
}
}
}
);
cluster.on("ready", () => {
Promise.all([
cluster.set("foo", "bar"),
cluster.get("foo")
]).then(
(result) => {
console.log(result[1]); // result == [ "OK", "bar"]
cluster.disconnect();
},
(reject) => {
console.log(reject);
cluster.disconnect();
}
);
});
О том, как получить FQDN хоста, см. инструкцию.
Подключение:
node app.js
При успешном подключении к кластеру и выполнении тестового запроса будет выведена строка bar
.
PHP
Перед подключением установите зависимости:
sudo apt update && sudo apt install --yes php php-dev php-pear && \
sudo pear channel-discover pear.nrk.io && \
sudo pear install nrk/Predis
connect.php
<?php
require "Predis/Autoloader.php";
Predis\Autoloader::register();
$hosts = [
"tcp://<FQDN_хоста-мастера_в_шарде_1>:6379",
...
"tcp://<FQDN_хоста-мастера_в_шарде_N>:6379",
];
$options = [
"cluster" => "redis",
"parameters" => [
"password" => "<пароль>",
],
];
$conn = new Predis\Client($hosts, $options);
$conn->set("foo", "bar");
var_dump($conn->get("foo"));
$conn->disconnect();
?>
connect.php
<?php
require "Predis/Autoloader.php";
Predis\Autoloader::register();
$hosts = [
'tls://<FQDN_хоста-мастера_в_шарде_1>:6380?ssl[cafile]=/home/<домашняя_директория>/.redis/YandexInternalRootCA.crt',
...
'tls://<FQDN_хоста-мастера_в_шарде_N>:6380?ssl[cafile]=/home/<домашняя_директория>/.redis/YandexInternalRootCA.crt',
];
$options = [
'cluster' => 'predis',
'parameters' => [
'password' => '<пароль>',
],
];
$conn = new Predis\Client($hosts, $options);
$conn->set('foo', 'bar');
var_dump($conn->get("foo"));
$conn->disconnect();
?>
О том, как получить FQDN хоста, см. инструкцию.
Подключение:
php connect.php
При успешном подключении к кластеру и выполнении тестового запроса будет выведена строка bar
.
Python
Перед подключением установите зависимости:
sudo apt update && sudo apt install -y python3 python3-pip python3-venv && \
python3 -m venv env && \
source env/bin/activate && \
pip install pip -U && \
pip install pyopenssl redis-py-cluster setuptools_rust
connect.py
from rediscluster import RedisCluster
startup_nodes = [
{"host": "<FQDN_хоста-мастера_в_шарде_1>", "port": 6379},
...
{"host": "<FQDN_хоста-мастера_в_шарде_N>", "port": 6379},
]
rc = RedisCluster(
startup_nodes=startup_nodes,
decode_responses=True,
skip_full_coverage_check=True,
password="<пароль>",
)
rc.set("foo", "bar")
print(rc.get("foo"))
connect.py
import OpenSSL
from rediscluster import RedisCluster
startup_nodes = [
{"host": "<FQDN_хоста-мастера_в_шарде_1>", "port": 6380},
...
{"host": "<FQDN_хоста-мастера_в_шарде_N>", "port": 6380},
]
rc = RedisCluster(
startup_nodes=startup_nodes,
decode_responses=True,
skip_full_coverage_check=True,
password="<пароль>",
ssl=True,
ssl_ca_certs="/home/<домашняя_директория>/.redis/YandexInternalRootCA.crt",
)
rc.set("foo", "bar")
print(rc.get("foo"))
О том, как получить FQDN хоста, см. инструкцию.
Подключение:
python3 connect.py
При успешном подключении к кластеру и выполнении тестового запроса будет выведена строка bar
.
Ruby
Перед подключением установите зависимости:
sudo apt update && sudo apt install --yes ruby && \
sudo gem install redis
connect.rb
# coding: utf-8
require 'redis'
nodes = [
{ host: '<FQDN_хоста-мастера_в_шарде_1>', port: 6379 },
...
{ host: '<FQDN_хоста-мастера_в_шарде_N>', port: 6379 }
]
conn = Redis.new(
cluster: nodes,
password: '<пароль>'
)
conn.set('foo', 'bar')
puts conn.get('foo')
conn.close
connect.rb
# coding: utf-8
require 'redis'
nodes = [
{ host: '<FQDN_хоста-мастера_в_шарде_1>', port: 6380 },
...
{ host: '<FQDN_хоста-мастера_в_шарде_N>', port: 6380 }
]
conn = Redis.new(
cluster: nodes,
password: '<пароль>',
ssl: true,
ssl_params: {
ca_file: '/home/<домашняя_директория>/.redis/YandexInternalRootCA.crt',
verify_hostname: false
}
)
conn.set('foo', 'bar')
puts conn.get('foo')
conn.close
О том, как получить FQDN хоста, см. инструкцию.
Подключение:
ruby connect.rb
При успешном подключении к кластеру и выполнении тестового запроса будет выведена строка bar
.