← Назад к вопросам

Как решишь проблему медленного выполнения запроса

2.3 Middle🔥 211 комментариев
#Базы данных и SQL

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

# Как будет происходить попадание данных в базу данных в Redis

Определение

Redis — это in-memory data store (хранилище данных в памяти), а не traditio базама на диске. Данные хранятся в RAM и теряются при перезагрузке, если не сохранены на диск.

Архитектура Redis

Апликация (Java)
     ↓
Redis Client (Jedis, Lettuce)
     ↓
Redis Server (в памяти)
     ↓
Persistence (опционально)
 ├── RDB (снимок памяти)
 └── AOF (журнал команд)

Как данные попадают в Redis

1. SET команда — основной способ

// Java код с Redis
import redis.clients.jedis.Jedis;

public class RedisExample {
    public static void main(String[] args) {
        // Подключаемся к Redis
        Jedis jedis = new Jedis("localhost", 6379);
        
        // 1. Отправляем SET команду
        jedis.set("user:123:name", "John");  // key, value
        
        // Что происходит:
        // ┌─────────────┐
        // │ Java Code   │
        // └──────┬──────┘
        //        │ SET user:123:name John
        //        ↓
        // ┌─────────────────────────────────┐
        // │ Redis Network Protocol (RESP)   │
        // │ *3\r\n$3\r\nSET\r\n$15\r\nuser:123:name\r\n$4\r\nJohn\r\n │
        // └──────┬──────────────────────────┘
        //        │
        //        ↓
        // ┌─────────────────────────────────┐
        // │ Redis Server (localhost:6379)   │
        // │ Парсит команду                  │
        // │ Сохраняет в hash table в памяти │
        // │ Возвращает OK                   │
        // └─────────────────────────────────┘
        
        // 2. Получаем значение
        String name = jedis.get("user:123:name");
        System.out.println(name);  // John
        
        // 3. Удаляем
        jedis.del("user:123:name");
        
        jedis.close();
    }
}

2. MSET команда — множественное добавление

jedis.mset(
    "user:1:name", "Alice",
    "user:2:name", "Bob",
    "user:3:name", "Charlie"
);
// Все три пары добавляются атомарно

3. PUSH команда — добавление в очередь

// Добавление в list
jedis.lpush("queue", "task1");  // Вспомогательный в начало
jedis.rpush("queue", "task2");  // В конец

// Добавление в set
jedis.sadd("users", "alice", "bob", "charlie");

// Добавление в sorted set
jedis.zadd("leaderboard", 100, "alice");  // score, member
jedis.zadd("leaderboard", 95, "bob");

Хранение в памяти

Hash Table структура

Redis хранит данные в hash table:

┌─────────────────────────────────────┐
│ Redis Memory (RAM)                  │
├─────────────────────────────────────┤
│ "user:123:name" → "John"          │
│ "user:123:age" → "30"             │
│ "user:456:name" → "Alice"         │
│ "config:timeout" → "5000"         │
│ ...                                │
└─────────────────────────────────────┘

Разные типы данных

// String
jedis.set("key", "value");

// List (очередь)
jedis.lpush("mylist", "a", "b", "c");
// Результат: [c, b, a]

// Set (множество, без дубликатов)
jedis.sadd("myset", "a", "b", "a");  // a добавляется один раз

// Sorted Set (с порядком)
jedis.zadd("scores", 100, "player1");
jedis.zadd("scores", 95, "player2");

// Hash (объект с полями)
jedis.hset("user:123", "name", "John");
jedis.hset("user:123", "email", "john@example.com");

Сохранение на диск (Persistence)

1. RDB — Redis Database (снимок памяти)

# Конфигурация (redis.conf)
save 900 1        # Сохранить если 1 ключ изменился за 900 сек
save 300 10       # Сохранить если 10 ключей изменилось за 300 сек
save 60 10000     # Сохранить если 10000 ключей изменилось за 60 сек

# Процесс:
# 1. Redis создаёт fork процесса
# 2. Child процесс пишет snapshot в dump.rdb
# 3. Parent процесс продолжает обслуживать клиентов
// Java код
public class RedisPersistence {
    public static void main(String[] args) {
        Jedis jedis = new Jedis();
        
        // Ручное сохранение
        jedis.save();      // Синхронное (блокирует)
        jedis.bgsave();    // Асинхронное (в фоне)
        
        jedis.close();
    }
}

2. AOF — Append Only File (журнал команд)

# Конфигурация (redis.conf)
appendonly yes
appendfsync everysec  # Синхронизировать диск каждую секунду

# Результат (appendonly.aof):
SET user:123:name John
SET user:456:name Alice
DEL user:123:name
LPUSH queue task1
LPUSH queue task2

При перезагрузке Redis:

  1. Читает appendonly.aof
  2. Переиграет все команды
  3. Восстанавливает состояние

Скорость vs Надёжность

Метод          Скорость    Надёжность  Когда использовать
──────────────────────────────────────────────────────────
No Persist.    Максимальная Ноль        Кеш (потеря OK)
RDB            Очень быст.  Хорошая     Backup'ы, снимки
AOF            Средняя      Отличная    Важные данные
RDB + AOF      Медленная     Отличная     Production

Практический пример: Redis как Cache

@Service
public class UserService {
    @Autowired
    private Jedis redis;
    @Autowired
    private UserRepository db;
    
    public User getUser(Long id) {
        String cacheKey = "user:" + id;
        
        // 1. Ищем в Redis
        String cached = redis.get(cacheKey);
        if (cached != null) {
            return parseUser(cached);  // Вернули из кеша
        }
        
        // 2. Не нашли — идём в БД
        User user = db.findById(id).orElse(null);
        if (user != null) {
            // 3. Сохраняем в Redis
            redis.setex(
                cacheKey, 
                3600,  // TTL = 1 час
                serializeUser(user)
            );
        }
        
        return user;
    }
    
    public void updateUser(Long id, User user) {
        // 1. Обновляем в БД
        db.save(user);
        
        // 2. Инвалидируем кеш
        redis.del("user:" + id);
    }
}

Пропускная способность и задержка

Операция           Задержка (latency)  Пропускная способность
──────────────────────────────────────────────────────────────
SET                ~0.1ms              100000+ операций/сек
GET                ~0.1ms              100000+ операций/сек
LPUSH              ~0.1ms              100000+ операций/сек
DEL                ~0.1ms              100000+ операций/сек

Disk Write (RDB)   ~10ms               зависит от диска
Disk Write (AOF)   ~1ms                зависит от диска

Потеря данных

// Сценарий 1: No persistence
jedis.set("important", "data");
// Redis crashed → данные потеряны

// Сценарий 2: RDB (снимок каждые 60 секунд)
jedis.set("important", "data");
// Redis crashed через 30 сек → потеря данных

// Сценарий 3: AOF (синхронизация каждую секунду)
jedis.set("important", "data");
// Redis crashed через 0.5 сек → максимум потеря 0.5 сек

// Сценарий 4: AOF fsync=always (синхр. каждую операцию)
jedis.set("important", "data");
// Redis crashed сразу же → данные сохранены!
// Но медленнее

На собеседовании

"Redis хранит данные в памяти (RAM). Процесс:

  1. Java приложение отправляет команду (SET, LPUSH и т.д.)
  2. Redis парсит команду
  3. Данные добавляются в hash table в памяти
  4. Redis возвращает ОК
  5. Получение: GET, LPOP и т.д. читают из памяти

Persistence (опционально):

  • RDB: периодически сохраняет снимок памяти на диск
  • AOF: логирует все команды в файл

Без persistence данные теряются при перезагрузке!

Производительность: ~100k операций в секунду с задержкой ~0.1ms."

Как решишь проблему медленного выполнения запроса | PrepBro