Connecting to a sharded Valkey™ cluster
To connect to a sharded Valkey™ cluster, in connection strings, specify the FQDNs of master hosts in each shard.
Encrypted connection is supported via port 6380
and unencrypted via port 6379
.
Warning
When using SSL, you can only connect to clusters with TLS support enabled.
Connecting from graphical IDEs
The connection was tested in the following environment:
- MacOS Big Sur 11.3.
- DBeaver Enterprise:
21.0
.
You can only use graphical IDEs to connect to cluster hosts through an SSL tunnel using a created VM. Before connecting, prepare a certificate.
To avoid connection errors, save the certificate
Connections to Valkey™ clusters are only available in DBeaver business editions
To connect to a cluster:
- Create a new DB connection:
- In the Database menu, select New connection.
- Select Valkey™ from the DB list.
- Click Next.
- Specify the connection parameters on the Main tab:
-
Host: Specify comma-separated FQDNs of master hosts in each shard.
To learn how to get a host FQDN, see this guide.
-
Port:
6379
for a regular cluster or6380
for a cluster with SSL encryption enabled. -
Under Authentication, specify the cluster password.
-
- On the SSH tab:
- Enable the Use SSL tunnel setting.
- Specify the SSH tunnel parameters:
- Host/IP: Public IP address of the VM to connect to.
- Username: Username for connecting to the VM.
- Authentication method:
Public key
. - Secret key: Path to the file with the private key used for connecting to the VM.
- Passphrase: Private key password.
- On the SSL tab:
- Enable the Use SSL and Skip hostname validation settings.
- Under Parameters:
- Select Method: Set of certificates.
- In the Root certificate field, specify the path to the saved SSL certificate file.
- Click Test connection ... to test a DB connection. If the connection is successful, you will see the connection status and information about the DBMS and driver.
- Click Ready to save the database connection settings.
Before you connect from a Docker container
To connect to a Yandex Managed Service for Valkey™ cluster from a Docker container, add the following lines to the Dockerfile:
# Build the redis-tools utility with TLS support manually.
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/
# Build the redis-tools utility with TLS support manually.
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/ && \
# Get an SSL certificate.
mkdir --parents ~/.redis && \
wget "https://storage.yandexcloud.net/cloud-certs/CA.pem" \
--output-document ~/.redis/YandexInternalRootCA.crt && \
chmod 0655 ~/.redis/YandexInternalRootCA.crt
Examples of connection strings
The Linux examples were tested in the following environment:
- Yandex Cloud virtual machine running 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
.
The Windows examples were tested in the following environment:
- A local machine with Windows 10 Pro build
19042.1052
. - PowerShell:
5.1.19041
. - cURL:
7.55.1 WinSSL
.
To see code examples with the host FQDN filled in, open the cluster page in the management console
Bash
Before connecting, install the dependencies:
sudo apt update && sudo apt install -y redis-tools
Connecting directly to the master host:
Specify the FQDN of the master host in the desired shard:
redis-cli \
-c \
-h <FQDN_of_master_host_in_required_shard> \
-a <password>
Before connecting, install the dependencies:
Build the redis-tools
utility with TLS support in one of two ways:
-
From a repository
-
Connect a repository:
sudo apt-add-repository ppa:redislabs/redis
Packages in this repository have already been built with the
BUILD_TLS=yes
flag. -
Install the utility:
sudo apt update && sudo apt install -y redis-tools
-
-
Manually
Go to the directory you want to download the distribution to. Download the stable version of the utility, then build and install it:
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/
Connecting directly to the master host:
Specify the FQDN of the master host in the desired shard:
redis-cli \
-c \
-h <FQDN_of_master_host_in_required_shard> \
-a <password> \
-p 6380 \
--tls \
--cacert ~/.redis/YandexInternalRootCA.crt \
To learn how to get a host FQDN, see this guide.
When you are connected to the cluster, run the commands:
SET foo bar
GET foo
If the GET
request returns nil
, it means that the entry for the foo
key has been moved to a different shard. Connect to it and repeat the request: it will return bar
.
Go
Before connecting, install the following dependencies:
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_of_master_host_in_shard_1>:6379",
...
"<FQDN_of_master_host_in_shard_N>:6379",
}
options := redis.UniversalOptions{
Addrs: hostports,
DB: 0,
ReadOnly: false,
DialTimeout: 5 * time.Second,
Password: "<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/<home_directory>/.redis/YandexInternalRootCA.crt")
if err != nil {
panic(err)
}
caCertPool := x509.NewCertPool()
caCertPool.AppendCertsFromPEM(caCert)
hostports := []string{
"<FQDN_of_master_host_in_shard_1>:6380",
...
"<FQDN_of_master_host_in_shard_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-<cluster_ID>.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())
}
To learn how to get a host FQDN, see this guide.
Connecting:
go run connect.go
If the connection to the cluster and the test query are successful, the bar
string is output.
Java
Before connecting:
-
Install the dependencies:
sudo apt update && sudo apt install --yes default-jdk maven
-
Create a folder for the Maven project:
cd ~/ && mkdir --parents project/src/java/com/example && cd project/
-
Create a configuration file for 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>
Up-to-date versions of dependencies for Maven:
-
To connect using SSL:
-
Create secure storage for certificates:
keytool -importcert \ -alias YARootCrt \ -file ~/.redis/YandexInternalRootCA.crt \ -keystore ~/.redis/YATrustStore \ -storepass <password_of_secure_certificate_storage> \ --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_of_master_host_in_shard_1>", 6379));
...
jedisClusterNodes.add(new HostAndPort("<FQDN_of_master_host_in_shard_N>", 6379));
DefaultJedisClientConfig jedisClientConfig = DefaultJedisClientConfig.builder().
password("<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/<home_directory>/.redis/YATrustStore");
System.setProperty("javax.net.ssl.trustStorePassword", "<secure_certificate_storage_password>");
JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
Set<HostAndPort> jedisClusterNodes = new HashSet<HostAndPort>();
SSLParameters sslParameters = new SSLParameters();
jedisClusterNodes.add(new HostAndPort("<FQDN_of_master_host_in_shard_1>", 6380));
...
jedisClusterNodes.add(new HostAndPort("<FQDN_of_master_host_in_shard_N>", 6380));
DefaultJedisClientConfig jedisClientConfig = DefaultJedisClientConfig.builder().
password("<cluster_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();
}
}
}
To learn how to get a host FQDN, see this guide.
Connecting:
mvn clean package && \
java -jar target/app-0.1.0-jar-with-dependencies.jar
If the connection to the cluster and the test query are successful, the bar
string is output.
Node.js
Before connecting, install the dependencies:
sudo apt update && sudo apt install -y nodejs npm && \
npm install ioredis
app.js
"use strict";
const Redis = require("ioredis");
const cluster = new Redis.Cluster(
[
{
host: "<FQDN_of_master_host_in_shard_1>",
port: 6379
},
...
{
host: "<FQDN_of_master_host_in_shard_N>",
port: 6379
}
],
{
redisOptions: {
password: "<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_of_master_host_in_shard_1>",
port: 6380
},
...
{
host: "<FQDN_of_master_host_in_shard_N>",
port: 6380
},
],
{
redisOptions: {
password: "<password>",
tls: {
ca: [fs.readFileSync("/home/<home_directory>/.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();
}
);
});
To learn how to get a host FQDN, see this guide.
Connecting:
node app.js
If the connection to the cluster and the test query are successful, the bar
string is output.
PHP
Before connecting, install the dependencies:
sudo apt update && sudo apt install -y 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_of_master_host_in_shard_1>:6379",
...
"tcp://<FQDN_of_master_host_in_shard_N>:6379",
];
$options = [
"cluster" => "redis",
"parameters" => [
"password" => "<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_of_master_host_in_shard_1>:6380?ssl[cafile]=/home/<home_directory>/.redis/YandexInternalRootCA.crt',
...
'tls://<FQDN_of_master_host_in_shard_N>:6380?ssl[cafile]=/home/<home_directory>/.redis/YandexInternalRootCA.crt',
];
$options = [
'cluster' => 'predis',
'parameters' => [
'password' => '<password>',
],
];
$conn = new Predis\Client($hosts, $options);
$conn->set('foo', 'bar');
var_dump($conn->get("foo"));
$conn->disconnect();
?>
To learn how to get a host FQDN, see this guide.
Connecting:
php connect.php
If the connection to the cluster and the test query are successful, the bar
string is output.
Python
Before connecting, install the following dependencies:
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_of_master_host_in_shard_1>", "port": 6379},
...
{"host": "<FQDN_of_master_host_in_shard_N>", "port": 6379},
]
rc = RedisCluster(
startup_nodes=startup_nodes,
decode_responses=True,
skip_full_coverage_check=True,
password="<password>",
)
rc.set("foo", "bar")
print(rc.get("foo"))
connect.py
import OpenSSL
from rediscluster import RedisCluster
startup_nodes = [
{"host": "<FQDN_of_master_host_in_shard_1>", "port": 6380},
...
{"host": "<FQDN_of_master_host_in_shard_N>", "port": 6380},
]
rc = RedisCluster(
startup_nodes=startup_nodes,
decode_responses=True,
skip_full_coverage_check=True,
password="<password>",
ssl=True,
ssl_ca_certs="/home/<home_directory>/.redis/YandexInternalRootCA.crt",
)
rc.set("foo", "bar")
print(rc.get("foo"))
To learn how to get a host FQDN, see this guide.
Connecting:
python3 connect.py
If the connection to the cluster and the test query are successful, the bar
string is output.
Ruby
Before connecting, install the dependencies:
sudo apt update && sudo apt install -y ruby && \
sudo gem install redis
connect.rb
# coding: utf-8
require 'redis'
nodes = [
{ host: '<FQDN_of_master_host_in_shard_1>', port: 6379 },
...
{ host: '<FQDN_of_master_host_in_shard_N>', port: 6379 }
]
conn = Redis.new(
cluster: nodes,
password: '<password>'
)
conn.set('foo', 'bar')
puts conn.get('foo')
conn.close
connect.rb
# coding: utf-8
require 'redis'
nodes = [
{ host: '<FQDN_of_master_host_in_shard_1>', port: 6380 },
...
{ host: '<FQDN_of_master_host_in_shard_N>', port: 6380 }
]
conn = Redis.new(
cluster: nodes,
password: '<password>',
ssl: true,
ssl_params: {
ca_file: '/home/<home_directory>/.redis/YandexInternalRootCA.crt',
verify_hostname: false
}
)
conn.set('foo', 'bar')
puts conn.get('foo')
conn.close
To learn how to get a host FQDN, see this guide.
Connecting:
ruby connect.rb
If the connection to the cluster and the test query are successful, the bar
string is output.