Redis клиент для Rust: обзор библиотеки redis-rs

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Redis клиент для Rust: библиотека redis-rs

Библиотека redis-rs — это основной и наиболее популярный клиент для работы с Redis в экосистеме Rust. Она предоставляет полный набор функций для взаимодействия с Redis: от простых команд GET/SET до сложных транзакций, пайплайнов и Pub/Sub. Благодаря поддержке как синхронного, так и асинхронного (async/await) режимов, redis-rs подходит для любых проектов — от скриптов до высоконагруженных веб-серверов.

Библиотека написана на чистом Rust, использует безопасную работу с памятью и типобезопасность, что минимизирует ошибки времени выполнения. Поддерживаются все популярные типы данных Redis: строки, списки, множества, хеши, отсортированные множества, битовые карты, HyperLogLog и потоки.

Установка и подключение

Добавьте зависимость в файл Cargo.toml:

[dependencies]
redis = { version = "0.27", features = ["tokio-comp"] }

Для синхронного использования достаточно просто redis = "0.27". Для асинхронного — выберите один из исполнителей: tokio-comp (по умолчанию) или async-std-comp.

Базовое использование (синхронный режим)

Пример подключения к локальному Redis и выполнения простых команд:

use redis::Commands;

fn main() -> redis::RedisResult<()> {
    let client = redis::Client::open("redis://127.0.0.1:6379/")?;
    let mut con = client.get_connection()?;

    con.set("my_key", "hello world")?;
    let value: String = con.get("my_key")?;
    println!("Получено значение: {}", value);

    // Работа с хешами
    con.hset("user:1", "name", "Alice")?;
    con.hset("user:1", "age", "30")?;
    let name: String = con.hget("user:1", "name")?;
    println!("Имя пользователя: {}", name);

    Ok(())
}

Обратите внимание на автоматическую десериализацию: вы указываете тип, в который нужно преобразовать результат (String, i32, Vec<String> и т.д.), и библиотека делает всё сама.

Асинхронный режим с Tokio

Для высокопроизводительных приложений используйте асинхронный API:

use redis::AsyncCommands;
use tokio;

#[tokio::main]
async fn main() -> redis::RedisResult<()> {
    let client = redis::Client::open("redis://127.0.0.1:6379/")?;
    let mut con = client.get_multiplexed_async_connection().await?;

    // Установка с TTL (время жизни ключа)
    con.set_ex("temp_key", "временное значение", 60).await?;
    let val: Option<String> = con.get("temp_key").await?;
    println!("Значение: {:?}", val);

    // Работа со списками
    con.lpush("queue", "task1").await?;
    con.lpush("queue", "task2").await?;
    let tasks: Vec<String> = con.lrange("queue", 0, -1).await?;
    println!("Задачи в очереди: {:?}", tasks);

    Ok(())
}

Асинхронный клиент использует мультиплексированные соединения (один TCP-сокет для множества запросов), что значительно повышает производительность.

Расширенные возможности

Пайплайны (конвейерная обработка)

Позволяют отправить несколько команд за один сетевой вызов, что ускоряет пакетные операции:

use redis::pipe;

fn main() -> redis::RedisResult<()> {
    let client = redis::Client::open("redis://127.0.0.1:6379/")?;
    let mut con = client.get_connection()?;

    let (val1, val2): (i32, i32) = redis::pipe()
        .cmd("INCR").arg("counter_a").ignore()
        .cmd("INCR").arg("counter_b").ignore()
        .cmd("GET").arg("counter_a").query(&mut con)?
        .cmd("GET").arg("counter_b").query(&mut con)?;

    println!("Счётчики: {}, {}", val1, val2);
    Ok(())
}

Pub/Sub (издатель-подписчик)

Пример подписки на каналы:

use redis::pubsub::PubSubCommands;

fn main() -> redis::RedisResult<()> {
    let client = redis::Client::open("redis://127.0.0.1:6379/")?;
    let mut con = client.get_connection()?;

    con.subscribe(&["news", "updates"], |msg| {
        let channel = msg.get_channel_name();
        let payload: String = msg.get_payload()?;
        println!("Канал: {}, сообщение: {}", channel, payload);
        Ok(())
    }                    

Рекомендаций