1. 当Redis遇到传统数据库:为什么需要协同?

就像快递小哥和仓库管理员的关系,Redis与传统数据库(如MySQL、PostgreSQL)的协同能大幅提升数据存取效率。Redis作为内存数据库,擅长处理高速读写;传统数据库则像可靠的档案库,保障数据持久化存储。

典型应用场景

  • 电商秒杀活动的库存缓存
  • 社交平台实时排行榜
  • 用户会话(Session)存储
  • 高频查询结果缓存
// 使用StackExchange.Redis实现缓存查询
public class ProductService
{
    private readonly IDatabase _redis;
    private readonly SqlConnection _db;

    public ProductService()
    {
        _redis = ConnectionMultiplexer.Connect("localhost").GetDatabase();
        _db = new SqlConnection("Server=.;Database=Shop;Integrated Security=True");
    }

    public async Task<Product> GetProductAsync(int id)
    {
        var cacheKey = $"product:{id}";
        var cachedProduct = await _redis.StringGetAsync(cacheKey);
        
        if (!cachedProduct.IsNullOrEmpty)
            return JsonConvert.DeserializeObject<Product>(cachedProduct!);

        var product = await _db.QueryFirstOrDefaultAsync<Product>(
            "SELECT * FROM Products WHERE Id = @Id", new { Id = id });

        if (product != null)
            await _redis.StringSetAsync(cacheKey, 
                JsonConvert.SerializeObject(product),
                TimeSpan.FromMinutes(30));

        return product;
    }
}

2. 常见协同模式详解

2.1 缓存层架构(Cache-Aside)

工作流程

  1. 先查Redis缓存
  2. 命中则直接返回
  3. 未命中则查询数据库
  4. 写入缓存后返回

优点

  • 降低数据库压力
  • 响应速度提升3-10倍
  • 架构简单易实现

缺点

  • 存在缓存击穿风险
  • 需要处理数据一致性
  • 缓存维护成本增加

2.2 双写策略(Write-Through)

// 同步写入Redis和MySQL的示例
public async Task CreateOrderAsync(Order order)
{
    using var transaction = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled);
    
    try
    {
        // 写入主数据库
        await _db.ExecuteAsync(
            "INSERT INTO Orders (...) VALUES (...)", order);
        
        // 写入Redis缓存
        await _redis.StringSetAsync($"order:{order.Id}", 
            JsonConvert.SerializeObject(order),
            TimeSpan.FromHours(1));
        
        transaction.Complete();
    }
    catch (Exception ex)
    {
        // 实现回滚逻辑
        await _redis.KeyDeleteAsync($"order:{order.Id}");
        throw;
    }
}

适用场景

  • 金融交易记录
  • 实时库存管理
  • 需要强一致性的系统

2.3 消息队列集成

Redis Streams实现数据库变更通知:

// 数据库变更时发布事件
public async Task UpdateProductPrice(int productId, decimal newPrice)
{
    // 更新数据库
    await _db.ExecuteAsync(
        "UPDATE Products SET Price = @Price WHERE Id = @Id",
        new { Price = newPrice, Id = productId });

    // 发布Redis消息
    await _redis.StreamAddAsync("product_updates", 
        new NameValueEntry[] 
        {
            new("productId", productId),
            new("newPrice", newPrice),
            new("timestamp", DateTime.UtcNow)
        });
}

// 其他服务消费消息
public async Task StartPriceUpdateConsumer()
{
    var stream = "product_updates";
    while (true)
    {
        var result = await _redis.StreamReadAsync(stream, "0-0", 10);
        foreach (var entry in result)
        {
            // 处理价格更新逻辑
            var productId = entry.Values.First(v => v.Name == "productId").Value;
            await UpdateSearchIndex(productId);
        }
        await Task.Delay(1000);
    }
}

3. 技术选型对比表

方案 响应速度 数据一致性 实现复杂度 适用场景
缓存层 ⚡⚡⚡⚡ ⚡⚡ ⚡⚡ 高频读操作
双写策略 ⚡⚡⚡ ⚡⚡⚡⚡ ⚡⚡⚡⚡ 强一致性要求
消息队列 ⚡⚡ ⚡⚡⚡ ⚡⚡⚡ 异步处理/系统解耦
数据同步 ⚡⚡ ⚡⚡⚡⚡ ⚡⚡⚡ 跨数据中心同步

4. 避坑指南:实践中必须注意的细节

4.1 缓存雪崩预防

// 随机过期时间避免集中失效
var random = new Random();
var expiry = TimeSpan.FromMinutes(30) + TimeSpan.FromSeconds(random.Next(0, 300));
await _redis.StringSetAsync(key, value, expiry);

4.2 缓存穿透处理

// 使用布隆过滤器
public class BloomFilter
{
    private readonly IDatabase _redis;
    
    public BloomFilter(IDatabase redis) => _redis = redis;

    public async Task<bool> MayExist(string key)
    {
        return await _redis.ExecuteAsync("BF.EXISTS", "myFilter", key)?.ToString() == "1";
    }
}

4.3 数据格式兼容性

// 使用版本化缓存键
public string GetCacheKey(string type, int id, int version = 1)
{
    return $"{type}:v{version}:{id}";
}

5. 性能优化实战技巧

内存优化示例

// 使用Hash类型存储对象
var product = new Product { Id = 1, Name = "Phone", Price = 599 };
await _redis.HashSetAsync($"product:{product.Id}", 
    new HashEntry[] 
    {
        new("name", product.Name),
        new("price", product.Price)
    });

批量操作优化

// 使用Pipeline批量处理
var batch = _redis.CreateBatch();
batch.StringSetAsync("key1", "value1");
batch.StringSetAsync("key2", "value2");
batch.Execute();

6. 未来趋势:多数据库协同的演进方向

  1. 混合持久化:Redis模块支持SQL查询
  2. 智能数据路由:AI驱动的自动缓存策略
  3. Serverless集成:云原生环境下的自动扩展
  4. 边缘计算:分布式缓存网络架构