Redis 缓存

HTTP服务器中Redis缓存详解

1. 历史演化与背景

1.1 缓存技术的发展历程

在早期的Web应用中,每次用户请求都需要直接访问数据库,这导致了严重的性能瓶颈。随着互联网的发展,缓存技术逐步演化:

  1. 内存缓存阶段(2000年代初):应用程序在内存中存储常用数据
  2. 分布式缓存阶段(2005年左右):Memcached的出现,支持多服务器缓存
  3. Redis时代(2009年至今):Redis(Remote Dictionary Server)提供了更丰富的数据结构和功能

1.2 Redis在HTTP服务器中的作用

Redis作为一个高性能的键值存储系统,在HTTP服务器中主要承担以下角色:

  • 数据缓存:缓存频繁访问的数据库查询结果
  • 会话存储:存储用户会话信息
  • 计数器:实现访问统计、限流等功能
  • 消息队列:处理异步任务

2. 核心概念与术语解释

2.1 重要术语及全称

  • Redis: Remote Dictionary Server(远程字典服务器)
  • TTL: Time To Live(生存时间)
  • LRU: Least Recently Used(最近最少使用)
  • LFU: Least Frequently Used(最不经常使用)
  • AOF: Append Only File(仅追加文件)
  • RDB: Redis Database(Redis数据库快照)
  • RESP: Redis Serialization Protocol(Redis序列化协议)
  • Pipeline: 管道技术,批量执行命令
  • Connection Pool: 连接池,管理数据库连接

2.2 基础数据结构

Redis支持多种数据结构:

  • String: 字符串,最基本的数据类型
  • Hash: 哈希表,类似于编程语言中的字典
  • List: 列表,有序的字符串集合
  • Set: 集合,无序且唯一的字符串集合
  • Sorted Set: 有序集合,每个元素都有一个分数

3. Redis缓存架构设计

3.1 整体架构

复制代码
HTTP请求 -> Web服务器 -> 缓存层(Redis) -> 数据库
                    |
                    v
                 缓存命中 -> 直接返回

3.2 连接池设计原理

连接池是管理数据库连接的重要组件,它的核心思想是:

  1. 预创建连接:启动时创建一定数量的连接
  2. 连接复用:多个请求共享连接,避免频繁创建/销毁
  3. 连接管理:监控连接状态,自动回收无效连接

4. 核心结构体详解

4.1 Redis连接结构体

cpp 复制代码
struct RedisConnection {
    redisContext* context;      // Redis连接上下文
    time_t last_used;          // 最后使用时间
    bool is_connected;         // 连接状态
    std::string host;          // Redis服务器地址
    int port;                  // Redis服务器端口
    int database;              // 数据库编号(0-15)
};

字段说明

  • context: hiredis库提供的连接上下文,包含socket信息和缓冲区
  • last_used: 用于连接池的空闲连接回收机制
  • is_connected: 标识连接是否有效,用于连接健康检查
  • host/port: 服务器地址信息,用于重连
  • database: Redis支持16个数据库(0-15),默认使用0号数据库

4.2 缓存项结构体

cpp 复制代码
struct CacheItem {
    std::string key;           // 缓存键
    std::string value;         // 缓存值
    time_t expire_time;        // 过期时间戳
    time_t access_time;        // 最后访问时间
    int access_count;          // 访问次数
    size_t size;              // 数据大小(字节)
};

字段说明

  • key/value: 基本的键值对数据
  • expire_time: Unix时间戳,用于TTL过期检查
  • access_time: 用于LRU淘汰策略
  • access_count: 用于LFU淘汰策略
  • size: 用于内存使用量统计和限制

4.3 连接池配置结构体

cpp 复制代码
struct PoolConfig {
    int min_connections;       // 最小连接数
    int max_connections;       // 最大连接数
    int connection_timeout;    // 连接超时时间(秒)
    int idle_timeout;         // 空闲超时时间(秒)
    int retry_times;          // 重试次数
    std::string host;         // Redis服务器地址
    int port;                 // Redis服务器端口
    std::string password;     // 认证密码
    int database;             // 默认数据库
};

5. 核心函数详解

5.1 连接管理函数

createConnection()

功能 : 创建新的Redis连接
入参:

  • host: 服务器地址(string类型)
  • port: 端口号(int类型)
  • timeout: 超时时间(int类型,单位秒)
    返回值 : RedisConnection* 指针,成功返回连接对象,失败返回nullptr
    内部流程:
  1. 调用hiredis的redisConnectWithTimeout()建立连接
  2. 检查连接状态,设置超时参数
  3. 如果有密码,执行AUTH命令认证
  4. 选择指定的数据库(SELECT命令)
getConnection()

功能 : 从连接池获取可用连接
入参 : 无
返回值 : RedisConnection* 指针
内部流程:

  1. 检查空闲连接队列
  2. 如果有空闲连接,检查连接有效性
  3. 如果无空闲连接且未达到最大连接数,创建新连接
  4. 如果达到最大连接数,等待或返回错误
releaseConnection()

功能 : 释放连接回连接池
入参 : conn - 要释放的连接指针
返回值 : bool - 成功返回true,失败返回false
内部流程:

  1. 检查连接有效性
  2. 更新最后使用时间
  3. 将连接放回空闲队列
  4. 通知等待的线程

5.2 缓存操作函数

set()

功能 : 设置缓存键值对
入参:

  • key: 缓存键(const std::string&)
  • value: 缓存值(const std::string&)
  • expire_seconds: 过期时间(int,单位秒,默认-1表示永不过期)
    返回值 : bool - 成功返回true,失败返回false
    内部流程:
  1. 获取连接池中的连接
  2. 构造Redis SET命令
  3. 如果指定了过期时间,使用SETEX命令
  4. 执行命令并检查返回结果
  5. 释放连接回池中
get()

功能 : 获取缓存值
入参 : key - 缓存键(const std::string&)
返回值 : std::string - 缓存值,不存在返回空字符串
内部流程:

  1. 获取连接
  2. 执行GET命令
  3. 检查返回结果类型(REDIS_REPLY_STRING或REDIS_REPLY_NIL)
  4. 更新访问统计信息
  5. 释放连接
exists()

功能 : 检查键是否存在
入参 : key - 缓存键(const std::string&)
返回值 : bool - 存在返回true,不存在返回false
内部流程:

  1. 获取连接
  2. 执行EXISTS命令
  3. 检查返回的整数值(1表示存在,0表示不存在)
  4. 释放连接
del()

功能 : 删除缓存键
入参 : key - 缓存键(const std::string&)
返回值 : bool - 成功删除返回true,键不存在返回false
内部流程:

  1. 获取连接
  2. 执行DEL命令
  3. 检查返回的整数值(删除的键数量)
  4. 释放连接

5.3 过期时间管理函数

expire()

功能 : 设置键的过期时间
入参:

  • key: 缓存键(const std::string&)
  • seconds: 过期秒数(int)
    返回值 : bool - 成功返回true,键不存在返回false
    内部流程:
  1. 获取连接
  2. 执行EXPIRE命令
  3. 检查返回结果
  4. 释放连接
ttl()

功能 : 获取键的剩余生存时间
入参 : key - 缓存键(const std::string&)
返回值 : int - 剩余秒数,-1表示永不过期,-2表示键不存在
内部流程:

  1. 获取连接
  2. 执行TTL命令
  3. 返回整数结果
  4. 释放连接

6. 缓存策略设计

6.1 淘汰策略

Redis支持多种内存淘汰策略:

  1. noeviction: 不淘汰,内存满时返回错误
  2. allkeys-lru: 在所有键中使用LRU算法淘汰
  3. volatile-lru: 在设置了过期时间的键中使用LRU淘汰
  4. allkeys-lfu: 在所有键中使用LFU算法淘汰
  5. volatile-lfu: 在设置了过期时间的键中使用LFU淘汰
  6. allkeys-random: 在所有键中随机淘汰
  7. volatile-random: 在设置了过期时间的键中随机淘汰
  8. volatile-ttl: 淘汰即将过期的键

6.2 缓存更新策略

  1. Cache-Aside(旁路缓存)

    • 读取:先查缓存,缓存未命中再查数据库,然后更新缓存
    • 写入:先更新数据库,然后删除缓存
  2. Write-Through(写穿透)

    • 写入时同时更新缓存和数据库
  3. Write-Behind(写回)

    • 写入时只更新缓存,异步更新数据库

7. 循序渐进的实现流程

第一步:基础连接实现

  1. 引入hiredis库
  2. 实现基本的连接创建和销毁
  3. 实现简单的SET/GET操作

第二步:连接池实现

  1. 设计连接池结构
  2. 实现连接的获取和释放
  3. 添加连接健康检查

第三步:缓存策略实现

  1. 实现TTL过期机制
  2. 添加访问统计
  3. 实现基本的淘汰策略

第四步:高级功能

  1. 实现批量操作
  2. 添加事务支持
  3. 实现发布订阅功能

第五步:性能优化

  1. 实现管道技术
  2. 添加连接复用
  3. 实现异步操作

8. 错误处理与监控

8.1 常见错误类型

  • 连接错误: 网络问题、服务器宕机
  • 认证错误: 密码错误、权限不足
  • 内存错误: Redis内存不足
  • 命令错误: 语法错误、类型错误

8.2 监控指标

  • 连接池状态: 活跃连接数、空闲连接数
  • 缓存命中率: 命中次数/总请求次数
  • 响应时间: 平均响应时间、99分位响应时间
  • 内存使用: Redis内存使用量、键数量

HTTP 服务器 Redis 缓存组件

1. Redis 客户端连接池 (RedisClientPool)

功能:

管理一系列到 Redis 服务器的长连接(TCP连接)。其核心目标是避免为每个HTTP请求都重新建立和断开连接的开销,从而极大提升性能。

为什么需要:

  • 减少延迟: 建立 TCP 连接需要三次握手,开销很大。
  • 降低服务器负载: 频繁创建连接会消耗 Redis 服务器和应用的 CPU 和内存资源。
  • 控制连接数: 防止客户端在高并发时创建过多连接,耗尽 Redis 服务器的最大连接数资源。

主要成员变量:

cpp 复制代码
class RedisClientPool {
private:
    std::queue<redisContext*> idle_connections_; // 空闲连接队列
    std::vector<redisContext*> all_connections_; // 所有连接(可选,用于最终释放)
    int min_connections_;  // 最小保持的空闲连接数
    int max_connections_;  // 池中允许的最大连接数
    std::string host_;
    int port_;
    std::string password_;
    std::mutex pool_mutex_; // 互斥锁,保证多线程安全访问连接池
    std::condition_variable cv_; // 条件变量,用于连接等待和通知
    // ... 其他状态变量,如当前连接数、当前空闲数等 ...
};

2. 缓存管理器 (CacheManager)

功能:

这是缓存系统的大脑和控制器 。它对外提供简洁的 GetSetDelete 等接口,并内部实现缓存策略(如缓存穿透、缓存击穿、缓存雪崩的应对策略)。

为什么需要:

它封装了所有复杂的缓存逻辑,使业务代码(如 Controller)保持简洁,只需关心"取数据"和"存数据",而不必关心底层实现细节和异常处理。

主要成员变量:

cpp 复制代码
class CacheManager {
private:
    RedisClientPool& redis_pool_; // 持有连接池的引用
    // 策略相关的配置项
    int default_ttl_;            // 默认缓存过期时间(秒)
    bool enable_penetration_protection_; // 是否启用缓存穿透保护
    // 用于实现"缓存击穿"保护的互斥锁(或分布式锁客户端)
    // 例如: std::unordered_map<std::string, std::mutex> key_mutexes_;
    // 或者一个分布式锁组件的指针:DistributedLockClient* lock_client_;

    // 统计信息(可选)
    std::atomic<long long> cache_hits_;
    std::atomic<long long> cache_misses_;
};

3. 缓存读写器 (CacheReader / CacheWriter)

功能:

这是 CacheManager 的辅助组件,负责执行具体的 Redis 命令。CacheManager 处理策略,而 CacheReader/Writer 负责与 RedisClientPool 交互,执行具体的 GETSET 等命令,并处理基本的错误。

为什么需要:

遵循单一职责原则,将命令执行与策略逻辑分离,使代码更清晰、更易维护。

主要成员变量:

cpp 复制代码
class CacheReader {
private:
    RedisClientPool& pool_; // 从连接池获取连接来执行命令
};

class CacheWriter {
private:
    RedisClientPool& pool_;
};

4. 序列化/反序列化组件 (Serializer/Deserializer)

功能:

负责将内存中的数据结构 (如 C++ 对象、JSON、字符串)与存储在 Redis 中的字符串进行相互转换。

为什么需要:

Redis 只能存储字符串、二进制数据等基本类型。而我们的业务数据可能是复杂的对象(如 UserProduct)。这个组件负责桥接两者。

主要成员变量:

通常这是一个工具类,成员变量很少,主要包含配置项。

cpp 复制代码
class JsonSerializer { // 例如一个JSON序列化器
public:
    // 通常是静态方法或无需成员变量
    static std::string Serialize(const User& user);
    static User Deserialize(const std::string& json_str);
};
// 或者使用模板类
template<typename T>
class Serializer {
    static std::string serialize(const T& obj);
    static T deserialize(const std::string& data);
};

5. 后台管理模块 (BackgroundManager) - (可选但重要)

功能:

执行一些异步任务,不与具体的 HTTP 请求绑定。

  • 缓存预热: 在服务启动时,加载一些热点数据到缓存中。
  • 定时任务: 定期刷新某些缓存,避免其过期。
  • 状态统计: 定期收集和报告缓存命中率等指标。

主要成员变量:

cpp 复制代码
class CacheWarmUpService {
private:
    CacheManager& cache_manager_;
    DatabaseClient& db_client_; // 用于从源数据库加载数据
    std::vector<std::string> hot_keys_; // 需要预热的热点Key列表
};

总结与工作流程

当一个 HTTP 请求到来时:

  1. Controller 接收到请求,需要获取数据。
  2. Controller 调用 CacheManager::Get(key)
  3. CacheManagerRedisClientPool 中借出一个连接。
  4. CacheManager 使用 CacheReaderSerializer 尝试从 Redis 获取数据。
    • 如果命中: 反序列化数据后直接返回给 Controller。
    • 如果未命中:
      • CacheManager 执行策略(如使用互斥锁防止缓存击穿)。
      • 从原始数据源(如 MySQL)查询数据。
      • 调用 CacheManager::Set(key, value)
      • CacheManager 使用 CacheWriterSerializer 将数据写入 Redis。
  5. 数据返回给 Controller,最终生成 HTTP 响应。
  6. 连接被归还给 RedisClientPool

完整的代码实现

redis_pool.h示例:

cpp 复制代码
#pragma once

#include <string>
#include <vector>
#include <queue>
#include <mutex>
#include <condition_variable>
#include <memory>
#include <thread>
#include <atomic>
#include <chrono>
#include <hiredis/hiredis.h>

// Redis连接结构体
// 封装了单个Redis连接的所有信息
struct RedisConnection {
    redisContext* context;      // hiredis库提供的连接上下文,包含socket和缓冲区信息
    time_t last_used;          // 最后使用时间戳,用于空闲连接回收
    bool is_connected;         // 连接状态标识,true表示连接有效
    std::string host;          // Redis服务器IP地址或域名
    int port;                  // Redis服务器端口号,默认6379
    int database;              // 当前选择的数据库编号(0-15)
    
    // 构造函数
    RedisConnection() : context(nullptr), last_used(0), is_connected(false), 
                       host(""), port(0), database(0) {}
    
    // 析构函数,确保连接被正确释放
    ~RedisConnection() {
        if (context) {
            redisFree(context);
            context = nullptr;
        }
    }
};

// 缓存项结构体
// 用于本地缓存统计和管理(可选功能)
struct CacheItem {
    std::string key;           // 缓存键,唯一标识符
    std::string value;         // 缓存值,实际存储的数据
    time_t expire_time;        // 过期时间戳,Unix时间戳格式
    time_t access_time;        // 最后访问时间,用于LRU淘汰策略
    int access_count;          // 访问次数计数器,用于LFU淘汰策略
    size_t size;              // 数据大小(字节),用于内存使用统计
    
    // 构造函数
    CacheItem() : key(""), value(""), expire_time(0), access_time(0), 
                 access_count(0), size(0) {}
};

// 连接池配置结构体
// 包含连接池的所有配置参数
struct PoolConfig {
    int min_connections;       // 最小连接数,连接池启动时创建的连接数量
    int max_connections;       // 最大连接数,连接池允许的最大连接数量
    int connection_timeout;    // 连接超时时间(秒),建立连接的最大等待时间
    int idle_timeout;         // 空闲超时时间(秒),连接空闲多久后被回收
    int retry_times;          // 重试次数,连接失败时的重试次数
    std::string host;         // Redis服务器地址
    int port;                 // Redis服务器端口
    std::string password;     // 认证密码,如果Redis设置了密码
    int database;             // 默认数据库编号
    
    // 默认构造函数,设置合理的默认值
    PoolConfig() : min_connections(5), max_connections(20), connection_timeout(5),
                  idle_timeout(300), retry_times(3), host("127.0.0.1"), 
                  port(6379), password(""), database(0) {}
};

// Redis连接池类
// 管理Redis连接的创建、分配、回收和销毁
class RedisPool {
private:
    PoolConfig config_;                              // 连接池配置
    std::queue<std::shared_ptr<RedisConnection>> idle_connections_;  // 空闲连接队列
    std::vector<std::shared_ptr<RedisConnection>> all_connections_;  // 所有连接的容器
    std::mutex pool_mutex_;                          // 连接池互斥锁,保护并发访问
    std::condition_variable pool_condition_;         // 条件变量,用于等待可用连接
    std::atomic<int> active_connections_;            // 当前活跃连接数的原子计数器
    std::atomic<bool> is_running_;                   // 连接池运行状态标识
    std::thread cleanup_thread_;                     // 清理线程,定期回收空闲连接
    
    // 统计信息(用于监控和调试)
    std::atomic<long long> total_requests_;          // 总请求数
    std::atomic<long long> successful_requests_;     // 成功请求数
    std::atomic<long long> failed_requests_;         // 失败请求数
    
public:
    // 构造函数,初始化连接池
    explicit RedisPool(const PoolConfig& config);
    
    // 析构函数,清理所有资源
    ~RedisPool();
    
    // 初始化连接池
    // 返回值:bool - 成功返回true,失败返回false
    bool initialize();
    
    // 关闭连接池
    void shutdown();
    
    // 从连接池获取一个可用连接
    // 返回值:shared_ptr<RedisConnection> - 连接对象智能指针,失败返回nullptr
    std::shared_ptr<RedisConnection> getConnection();
    
    // 将连接释放回连接池
    // 参数:conn - 要释放的连接
    void releaseConnection(std::shared_ptr<RedisConnection> conn);
    
    // 基础Redis操作函数
    
    // 设置键值对
    // 参数:key - 缓存键,value - 缓存值,expire_seconds - 过期时间(秒,-1表示永不过期)
    // 返回值:bool - 成功返回true,失败返回false
    bool set(const std::string& key, const std::string& value, int expire_seconds = -1);
    
    // 获取键对应的值
    // 参数:key - 缓存键
    // 返回值:string - 缓存值,键不存在返回空字符串
    std::string get(const std::string& key);
    
    // 检查键是否存在
    // 参数:key - 缓存键
    // 返回值:bool - 存在返回true,不存在返回false
    bool exists(const std::string& key);
    
    // 删除键
    // 参数:key - 缓存键
    // 返回值:bool - 成功删除返回true,键不存在返回false
    bool del(const std::string& key);
    
    // 设置键的过期时间
    // 参数:key - 缓存键,seconds - 过期秒数
    // 返回值:bool - 成功返回true,键不存在返回false
    bool expire(const std::string& key, int seconds);
    
    // 获取键的剩余生存时间
    // 参数:key - 缓存键
    // 返回值:int - 剩余秒数,-1表示永不过期,-2表示键不存在
    int ttl(const std::string& key);
    
    // 批量设置键值对
    // 参数:key_values - 键值对的vector,每个pair包含key和value
    // 返回值:bool - 全部成功返回true,有失败返回false
    bool mset(const std::vector<std::pair<std::string, std::string>>& key_values);
    
    // 批量获取键对应的值
    // 参数:keys - 键的vector
    // 返回值:vector<string> - 对应的值,不存在的键返回空字符串
    std::vector<std::string> mget(const std::vector<std::string>& keys);
    
    // 原子递增操作
    // 参数:key - 缓存键,increment - 递增值(默认为1)
    // 返回值:long long - 递增后的值,键不存在时从0开始递增
    long long incr(const std::string& key, long long increment = 1);
    
    // 原子递减操作
    // 参数:key - 缓存键,decrement - 递减值(默认为1)
    // 返回值:long long - 递减后的值,键不存在时从0开始递减
    long long decr(const std::string& key, long long decrement = 1);
    
    // 获取连接池统计信息
    struct PoolStats {
        int active_connections;     // 当前活跃连接数
        int idle_connections;       // 当前空闲连接数
        int total_connections;      // 总连接数
        long long total_requests;   // 总请求数
        long long successful_requests; // 成功请求数
        long long failed_requests;  // 失败请求数
        double success_rate;        // 成功率
    };
    
    // 获取连接池统计信息
    // 返回值:PoolStats - 包含各种统计信息的结构体
    PoolStats getStats() const;
    
    // 检查连接池健康状态
    // 返回值:bool - 健康返回true,不健康返回false
    bool isHealthy() const;

private:
    // 创建新的Redis连接
    // 返回值:shared_ptr<RedisConnection> - 连接对象,失败返回nullptr
    std::shared_ptr<RedisConnection> createConnection();
    
    // 检查连接是否有效
    // 参数:conn - 要检查的连接
    // 返回值:bool - 有效返回true,无效返回false
    bool isConnectionValid(std::shared_ptr<RedisConnection> conn);
    
    // 清理空闲连接的后台线程函数
    void cleanupIdleConnections();
    
    // 执行Redis命令的通用函数
    // 参数:conn - Redis连接,command - 命令字符串
    // 返回值:redisReply* - Redis回复对象,需要调用者释放
    redisReply* executeCommand(std::shared_ptr<RedisConnection> conn, const std::string& command);
    
    // 执行Redis命令的通用函数(带参数)
    // 参数:conn - Redis连接,format - 命令格式字符串,... - 可变参数
    // 返回值:redisReply* - Redis回复对象,需要调用者释放
    redisReply* executeCommand(std::shared_ptr<RedisConnection> conn, const char* format, ...);
};

redis_pool.cpp示例

cpp 复制代码
#include "redis_pool.h"
#include <iostream>
#include <cstring>
#include <cstdarg>
#include <algorithm>

// RedisPool构造函数
// 初始化连接池的基本参数和状态
RedisPool::RedisPool(const PoolConfig& config) 
    : config_(config), active_connections_(0), is_running_(false),
      total_requests_(0), successful_requests_(0), failed_requests_(0) {
    
    // 验证配置参数的合理性
    if (config_.min_connections <= 0) {
        config_.min_connections = 1;
    }
    if (config_.max_connections < config_.min_connections) {
        config_.max_connections = config_.min_connections * 2;
    }
    if (config_.connection_timeout <= 0) {
        config_.connection_timeout = 5;
    }
    if (config_.idle_timeout <= 0) {
        config_.idle_timeout = 300;
    }
}

// RedisPool析构函数
// 确保所有资源被正确释放
RedisPool::~RedisPool() {
    shutdown();
}

// 初始化连接池
// 创建最小数量的连接并启动清理线程
bool RedisPool::initialize() {
    std::lock_guard<std::mutex> lock(pool_mutex_);
    
    if (is_running_) {
        return true;  // 已经初始化过了
    }
    
    // 创建最小数量的连接
    for (int i = 0; i < config_.min_connections; ++i) {
        auto conn = createConnection();
        if (!conn) {
            std::cerr << "Failed to create initial connection " << i << std::endl;
            // 清理已创建的连接
            while (!idle_connections_.empty()) {
                idle_connections_.pop();
            }
            all_connections_.clear();
            return false;
        }
        
        idle_connections_.push(conn);
        all_connections_.push_back(conn);
    }
    
    is_running_ = true;
    
    // 启动清理线程
    cleanup_thread_ = std::thread(&RedisPool::cleanupIdleConnections, this);
    
    std::cout << "Redis connection pool initialized with " 
              << config_.min_connections << " connections" << std::endl;
    
    return true;
}

// 关闭连接池
// 停止所有线程并释放所有连接
void RedisPool::shutdown() {
    {
        std::lock_guard<std::mutex> lock(pool_mutex_);
        if (!is_running_) {
            return;  // 已经关闭了
        }
        is_running_ = false;
    }
    
    // 通知所有等待的线程
    pool_condition_.notify_all();
    
    // 等待清理线程结束
    if (cleanup_thread_.joinable()) {
        cleanup_thread_.join();
    }
    
    // 清理所有连接
    std::lock_guard<std::mutex> lock(pool_mutex_);
    while (!idle_connections_.empty()) {
        idle_connections_.pop();
    }
    all_connections_.clear();
    
    std::cout << "Redis connection pool shutdown completed" << std::endl;
}

// 创建新的Redis连接
// 这是连接池的核心功能之一
std::shared_ptr<RedisConnection> RedisPool::createConnection() {
    auto conn = std::make_shared<RedisConnection>();
    
    // 设置连接超时
    struct timeval timeout = { config_.connection_timeout, 0 };
    
    // 尝试连接Redis服务器
    // 注意:这里使用模拟的连接,实际应该使用 redisConnectWithTimeout
    // conn->context = redisConnectWithTimeout(config_.host.c_str(), config_.port, timeout);
    
    // 模拟连接创建(实际项目中需要hiredis库)
    conn->context = nullptr;  // 在实际项目中这里应该是真实的Redis连接
    conn->host = config_.host;
    conn->port = config_.port;
    conn->database = config_.database;
    conn->last_used = time(nullptr);
    conn->is_connected = true;  // 模拟连接成功
    
    // 在实际项目中,这里需要检查连接状态
    /*
    if (!conn->context || conn->context->err) {
        if (conn->context) {
            std::cerr << "Redis connection error: " << conn->context->errstr << std::endl;
            redisFree(conn->context);
        }
        return nullptr;
    }
    */
    
    // 如果设置了密码,进行认证
    if (!config_.password.empty()) {
        // 实际项目中执行: AUTH password
        // redisReply* reply = (redisReply*)redisCommand(conn->context, "AUTH %s", config_.password.c_str());
        // 检查认证结果并释放reply
    }
    
    // 选择数据库
    if (config_.database != 0) {
        // 实际项目中执行: SELECT database
        // redisReply* reply = (redisReply*)redisCommand(conn->context, "SELECT %d", config_.database);
        // 检查选择结果并释放reply
    }
    
    std::cout << "Created new Redis connection to " << config_.host 
              << ":" << config_.port << std::endl;
    
    return conn;
}

// 从连接池获取连接
// 这是连接池最重要的功能
std::shared_ptr<RedisConnection> RedisPool::getConnection() {
    std::unique_lock<std::mutex> lock(pool_mutex_);
    
    total_requests_++;
    
    // 等待可用连接,最多等待connection_timeout秒
    auto timeout = std::chrono::seconds(config_.connection_timeout);
    
    if (!pool_condition_.wait_for(lock, timeout, [this] {
        return !is_running_ || !idle_connections_.empty() || 
               static_cast<int>(all_connections_.size()) < config_.max_connections;
    })) {
        failed_requests_++;
        std::cerr << "Timeout waiting for available connection" << std::endl;
        return nullptr;
    }
    
    if (!is_running_) {
        failed_requests_++;
        return nullptr;
    }
    
    std::shared_ptr<RedisConnection> conn;
    
    // 首先尝试从空闲连接中获取
    if (!idle_connections_.empty()) {
        conn = idle_connections_.front();
        idle_connections_.pop();
        
        // 检查连接是否仍然有效
        if (!isConnectionValid(conn)) {
            // 连接无效,创建新连接
            conn = createConnection();
            if (!conn) {
                failed_requests_++;
                return nullptr;
            }
            
            // 更新连接列表
            auto it = std::find(all_connections_.begin(), all_connections_.end(), conn);
            if (it != all_connections_.end()) {
                *it = conn;
            } else {
                all_connections_.push_back(conn);
            }
        }
    } 
    // 如果没有空闲连接且未达到最大连接数,创建新连接
    else if (static_cast<int>(all_connections_.size()) < config_.max_connections) {
        conn = createConnection();
        if (!conn) {
            failed_requests_++;
            return nullptr;
        }
        all_connections_.push_back(conn);
    } else {
        // 这种情况不应该发生,因为wait_for应该会等待
        failed_requests_++;
        std::cerr << "No available connections and max limit reached" << std::endl;
        return nullptr;
    }
    
    // 更新连接使用时间
    conn->last_used = time(nullptr);
    active_connections_++;
    successful_requests_++;
    
    return conn;
}

// 释放连接回连接池
// 连接使用完毕后必须调用此函数
void RedisPool::releaseConnection(std::shared_ptr<RedisConnection> conn) {
    if (!conn) {
        return;
    }
    
    std::lock_guard<std::mutex> lock(pool_mutex_);
    
    if (!is_running_) {
        return;
    }
    
    // 检查连接是否仍然有效
    if (isConnectionValid(conn)) {
        conn->last_used = time(nullptr);
        idle_connections_.push(conn);
    } else {
        // 连接无效,从all_connections_中移除
        auto it = std::find(all_connections_.begin(), all_connections_.end(), conn);
        if (it != all_connections_.end()) {
            all_connections_.erase(it);
        }
    }
    
    active_connections_--;
    
    // 通知等待连接的线程
    pool_condition_.notify_one();
}

// 检查连接是否有效
// 用于连接健康检查
bool RedisPool::isConnectionValid(std::shared_ptr<RedisConnection> conn) {
    if (!conn || !conn->is_connected) {
        return false;
    }
    
    // 在实际项目中,这里应该发送PING命令来检查连接
    /*
    if (!conn->context || conn->context->err) {
        return false;
    }
    
    redisReply* reply = (redisReply*)redisCommand(conn->context, "PING");
    if (!reply) {
        return false;
    }
    
    bool valid = (reply->type == REDIS_REPLY_STATUS && 
                  strcmp(reply->str, "PONG") == 0);
    freeReplyObject(reply);
    return valid;
    */
    
    // 模拟连接检查
    return true;
}

// 清理空闲连接的后台线程
// 定期检查并回收长时间空闲的连接
void RedisPool::cleanupIdleConnections() {
    while (is_running_) {
        std::this_thread::sleep_for(std::chrono::seconds(60));  // 每60秒检查一次
        
        std::lock_guard<std::mutex> lock(pool_mutex_);
        
        if (!is_running_) {
            break;
        }
        
        time_t now = time(nullptr);
        std::queue<std::shared_ptr<RedisConnection>> new_idle_queue;
        
        // 检查空闲连接,移除过期的连接
        while (!idle_connections_.empty()) {
            auto conn = idle_connections_.front();
            idle_connections_.pop();
            
            if (now - conn->last_used < config_.idle_timeout && 
                isConnectionValid(conn) &&
                static_cast<int>(all_connections_.size()) > config_.min_connections) {
                new_idle_queue.push(conn);
            } else {
                // 移除过期或无效的连接
                auto it = std::find(all_connections_.begin(), all_connections_.end(), conn);
                if (it != all_connections_.end()) {
                    all_connections_.erase(it);
                }
                std::cout << "Removed idle connection" << std::endl;
            }
        }
        
        idle_connections_ = new_idle_queue;
    }
}

// 执行Redis命令的通用函数
// 这是所有Redis操作的基础
redisReply* RedisPool::executeCommand(std::shared_ptr<RedisConnection> conn, const char* format, ...) {
    if (!conn || !conn->context) {
        return nullptr;
    }
    
    // 在实际项目中,这里使用vsnprintf和redisCommand
    /*
    va_list args;
    va_start(args, format);
    redisReply* reply = (redisReply*)redisvCommand(conn->context, format, args);
    va_end(args);
    return reply;
    */
    
    // 模拟命令执行
    return nullptr;
}

// SET操作:设置键值对
// 这是最基本的缓存操作
bool RedisPool::set(const std::string& key, const std::string& value, int expire_seconds) {
    auto conn = getConnection();
    if (!conn) {
        return false;
    }
    
    bool result = false;
    
    // 在实际项目中执行Redis命令
    /*
    redisReply* reply;
    if (expire_seconds > 0) {
        // 使用SETEX命令设置带过期时间的键值对
        reply = (redisReply*)redisCommand(conn->context, "SETEX %s %d %s", 
                                         key.c_str(), expire_seconds, value.c_str());
    } else {
        // 使用SET命令设置永久键值对
        reply = (redisReply*)redisCommand(conn->context, "SET %s %s", 
                                         key.c_str(), value.c_str());
    }
    
    if (reply && reply->type == REDIS_REPLY_STATUS && 
        strcmp(reply->str, "OK") == 0) {
        result = true;
    }
    
    if (reply) {
        freeReplyObject(reply);
    }
    */
    
    // 模拟SET操作成功
    result = true;
    std::cout << "SET " << key << " = " << value;
    if (expire_seconds > 0) {
        std::cout << " (expires in " << expire_seconds << " seconds)";
    }
    std::cout << std::endl;
    
    releaseConnection(conn);
    return result;
}

// GET操作:获取键对应的值
// 这是最基本的缓存读取操作
std::string RedisPool::get(const std::string& key) {
    auto conn = getConnection();
    if (!conn) {
        return "";
    }
    
    std::string result;
    
    // 在实际项目中执行Redis命令
    /*
    redisReply* reply = (redisReply*)redisCommand(conn->context, "GET %s", key.c_str());
    
    if (reply) {
        if (reply->type == REDIS_REPLY_STRING) {
            result = std::string(reply->str, reply->len);
        }
        // reply->type == REDIS_REPLY_NIL 表示键不存在,返回空字符串
        freeReplyObject(reply);
    }
    */
    
    // 模拟GET操作
    result = "mock_value_for_" + key;
    std::cout << "GET " << key << " = " << result << std::endl;
    
    releaseConnection(conn);
    return result;
}

// EXISTS操作:检查键是否存在
bool RedisPool::exists(const std::string& key) {
    auto conn = getConnection();
    if (!conn) {
        return false;
    }
    
    bool result = false;
    
    // 在实际项目中执行Redis命令
    /*
    redisReply* reply = (redisReply*)redisCommand(conn->context, "EXISTS %s", key.c_str());
    
    if (reply && reply->type == REDIS_REPLY_INTEGER) {
        result = (reply->integer == 1);
    }
    
    if (reply) {
        freeReplyObject(reply);
    }
    */
    
    // 模拟EXISTS操作
    result = true;  // 假设键存在
    std::cout << "EXISTS " << key << " = " << (result ? "true" : "false") << std::endl;
    
    releaseConnection(conn);
    return result;
}

// DEL操作:删除键
bool RedisPool::del(const std::string& key) {
    auto conn = getConnection();
    if (!conn) {
        return false;
    }
    
    bool result = false;
    
    // 在实际项目中执行Redis命令
    /*
    redisReply* reply = (redisReply*)redisCommand(conn->context, "DEL %s", key.c_str());
    
    if (reply && reply->type == REDIS_REPLY_INTEGER) {
        result = (reply->integer > 0);  // 返回删除的键数量
    }
    
    if (reply) {
        freeReplyObject(reply);
    }
    */
    
    // 模拟DEL操作
    result = true;
    std::cout << "DEL " << key << " = " << (result ? "success" : "failed") << std::endl;
    
    releaseConnection(conn);
    return result;
}

// EXPIRE操作:设置键的过期时间
bool RedisPool::expire(const std::string& key, int seconds) {
    auto conn = getConnection();
    if (!conn) {
        return false;
    }
    
    bool result = false;
    
    // 在实际项目中执行Redis命令
    /*
    redisReply* reply = (redisReply*)redisCommand(conn->context, "EXPIRE %s %d", 
                                                 key.c_str(), seconds);
    
    if (reply && reply->type == REDIS_REPLY_INTEGER) {
        result = (reply->integer == 1);  // 1表示成功,0表示键不存在
    }
    
    if (reply) {
        freeReplyObject(reply);
    }
    */
    
    // 模拟EXPIRE操作
    result = true;
    std::cout << "EXPIRE " << key << " " << seconds << " = " 
              << (result ? "success" : "failed") << std::endl;
    
    releaseConnection(conn);
    return result;
}

// TTL操作:获取键的剩余生存时间
int RedisPool::ttl(const std::string& key) {
    auto conn = getConnection();
    if (!conn) {
        return -2;  // 连接失败
    }
    
    int result = -2;
    
    // 在实际项目中执行Redis命令
    /*
    redisReply* reply = (redisReply*)redisCommand(conn->context, "TTL %s", key.c_str());
    
    if (reply && reply->type == REDIS_REPLY_INTEGER) {
        result = static_cast<int>(reply->integer);
        // -1: 键存在但没有设置过期时间
        // -2: 键不存在
        // >0: 剩余秒数
    }
    
    if (reply) {
        freeReplyObject(reply);
    }
    */
    
    // 模拟TTL操作
    result = 300;  // 假设还有300秒过期
    std::cout << "TTL " << key << " = " << result << " seconds" << std::endl;
    
    releaseConnection(conn);
    return result;
}

// MSET操作:批量设置键值对
bool RedisPool::mset(const std::vector<std::pair<std::string, std::string>>& key_values) {
    if (key_values.empty()) {
        return true;
    }
    
    auto conn = getConnection();
    if (!conn) {
        return false;
    }
    
    bool result = false;
    
    // 在实际项目中,构造MSET命令
    /*
    std::string command = "MSET";
    for (const auto& kv : key_values) {
        command += " " + kv.first + " " + kv.second;
    }
    
    redisReply* reply = (redisReply*)redisCommand(conn->context, command.c_str());
    
    if (reply && reply->type == REDIS_REPLY_STATUS && 
        strcmp(reply->str, "OK") == 0) {
        result = true;
    }
    
    if (reply) {
        freeReplyObject(reply);
    }
    */
    
    // 模拟MSET操作
    result = true;
    std::cout << "MSET ";
    for (const auto& kv : key_values) {
        std::cout << kv.first << "=" << kv.second << " ";
    }
    std::cout << "= success" << std::endl;
    
    releaseConnection(conn);
    return result;
}

// MGET操作:批量获取键对应的值
std::vector<std::string> RedisPool::mget(const std::vector<std::string>& keys) {
    std::vector<std::string> results;
    
    if (keys.empty()) {
        return results;
    }
    
    auto conn = getConnection();
    if (!conn) {
        return results;
    }
    
    // 在实际项目中,构造MGET命令
    /*
    std::string command = "MGET";
    for (const auto& key : keys) {
        command += " " + key;
    }
    
    redisReply* reply = (redisReply*)redisCommand(conn->context, command.c_str());
    
    if (reply && reply->type == REDIS_REPLY_ARRAY) {
        for (size_t i = 0; i < reply->elements; ++i) {
            if (reply->element[i]->type == REDIS_REPLY_STRING) {
                results.push_back(std::string(reply->element[i]->str, 
                                            reply->element[i]->len));
            } else {
                results.push_back("");  // 键不存在
            }
        }
    }
    
    if (reply) {
        freeReplyObject(reply);
    }
    */
    
    // 模拟MGET操作
    for (const auto& key : keys) {
        results.push_back("mock_value_for_" + key);
    }
    
    std::cout << "MGET ";
    for (const auto& key : keys) {
        std::cout << key << " ";
    }
    std::cout << "= " << results.size() << " values" << std::endl;
    
    releaseConnection(conn);
    return results;
}

// INCR操作:原子递增
long long RedisPool::incr(const std::string& key, long long increment) {
    auto conn = getConnection();
    if (!conn) {
        return 0;
    }
    
    long long result = 0;
    
    // 在实际项目中执行Redis命令
    /*
    redisReply* reply;
    if (increment == 1) {
        reply = (redisReply*)redisCommand(conn->context, "INCR %s", key.c_str());
    } else {
        reply = (redisReply*)redisCommand(conn->context, "INCRBY %s %lld", 
                                         key.c_str(), increment);
    }
    
    if (reply && reply->type == REDIS_REPLY_INTEGER) {
        result = reply->integer;
    }
    
    if (reply) {
        freeReplyObject(reply);
    }
    */
    
    // 模拟INCR操作
    result = increment;  // 假设从0开始递增
    std::cout << "INCR " << key << " by " << increment << " = " << result << std::endl;
    
    releaseConnection(conn);
    return result;
}

// DECR操作:原子递减
long long RedisPool::decr(const std::string& key, long long decrement) {
    auto conn = getConnection();
    if (!conn) {
        return 0;
    }
    
    long long result = 0;
    
    // 在实际项目中执行Redis命令
    /*
    redisReply* reply;
    if (decrement == 1) {
        reply = (redisReply*)redisCommand(conn->context, "DECR %s", key.c_str());
    } else {
        reply = (redisReply*)redisCommand(conn->context, "DECRBY %s %lld", 
                                         key.c_str(), decrement);
    }
    
    if (reply && reply->type == REDIS_REPLY_INTEGER) {
        result = reply->integer;
    }
    
    if (reply) {
        freeReplyObject(reply);
    }
    */
    
    // 模拟DECR操作
    result = -decrement;  // 假设从0开始递减
    std::cout << "DECR " << key << " by " << decrement << " = " << result << std::endl;
    
    releaseConnection(conn);
    return result;
}

// 获取连接池统计信息
RedisPool::PoolStats RedisPool::getStats() const {
    std::lock_guard<std::mutex> lock(pool_mutex_);
    
    PoolStats stats;
    stats.active_connections = active_connections_.load();
    stats.idle_connections = static_cast<int>(idle_connections_.size());
    stats.total_connections = static_cast<int>(all_connections_.size());
    stats.total_requests = total_requests_.load();
    stats.successful_requests = successful_requests_.load();
    stats.failed_requests = failed_requests_.load();
    
    if (stats.total_requests > 0) {
        stats.success_rate = static_cast<double>(stats.successful_requests) / 
                           static_cast<double>(stats.total_requests) * 100.0;
    } else {
        stats.success_rate = 0.0;
    }
    
    return stats;
}

// 检查连接池健康状态
bool RedisPool::isHealthy() const {
    if (!is_running_) {
        return false;
    }
    
    auto stats = getStats();
    
    // 检查是否有足够的连接
    if (stats.total_connections < config_.min_connections) {
        return false;
    }
    
    // 检查成功率是否足够高
    if (stats.total_requests > 100 && stats.success_rate < 95.0) {
        return false;
    }
    
    return true;
}