分布式缓存长 key 影响性能怎么办?一文讲透如何优化!

2023-05-01 09:56:48 浏览数 (1)

一、背景

有个需求需要将 SQL 语句作为分布式缓存的 key。 但是这样做会导致 key 太长。key 太长会有一些缺点。 但是 key 太长的问题也是可以解决的。 本文将详细讲述 key 太长的缺点和解决方案,希望对大家有帮助。

二、Key 太长的缺点

通常来说 SQL 作为 Key 太长,会有诸多缺点:

  • Key太长会占用更多的内存空间,降低缓存的效率和命中率。
  • Key太长会增加网络传输的开销,影响缓存的响应速度和吞吐量。
  • Key太长会导致数据分片不均匀,增加缓存服务器之间的负载差异和数据迁移的成本。
  • Key太长会增加缓存的管理和维护的难度,比如删除、更新、监控等操作。

因此,建议使用合理的Key设计规范,避免使用过长或者不必要的前缀、后缀、分隔符等。

三、解决方案

3.1 Hash (解决冲突问题)

可以使用哈希算法(如 MD5、SHA-1 等)将 SQL 语句转换成固定长度的字符串作为缓存 key。这种方式可以缩短 key 的长度,减小缓存空间占用,同时也可以提高查找效率。 但是,哈希算法可能存在冲突,需要注意缓存 key 的唯一性。

如何解决还冲突带来的唯一性问题?

  • 加前缀,比如不同的租户、店铺的ID 或者 Code 作为 Key 的前缀,可以极大降低冲突的概率。
  • 可以自定义值的结构 (1)将 SQL 存储在 Value 对象中,用于二次确认。 (2)如果原始的值是单个对象,可以定义为集合为。 通过 hash 值作为 key 读取出来值的时候对比当前 Sql 和 Value 中存储的 SQL 是否一致。 如果一致说明没有 Hash 冲突;如果不一致说明存在 hash 冲突,可以将新值放到集合中,读取时遍历集合取出对应的值即可。

伪代码如下:

代码语言:javascript复制
public class Value{
  String sql;
  Object value;
}

public class CacheValueWrapper{
    // 不冲突时存这里
    Value value;
    
    // 冲突时存这里
    List<Value> values;

    Value getValue(String sql){
       // 先匹配 value 

       // 再匹配 values
    }
}

3.2 语句映射(转化成唯一的值)

可以借助表的唯一键的特性。 新建一个映射表,包括 SQL 字符串、业务 Code (业务 ID)。

sql

id

select * from user where id=21

10086

select name,age from student where id=22

10087

业务Code 或者 业务 ID 可以使用数据库自增的特性也可以使用分布式 ID 生成器。 SQL 字符串设置为唯一键。 先通过 SQL 来查询,如果直接使用,如果表中没有这个 SQL 值则插入。

就可以将对应的业务 Code 或 业务ID 作为缓存 Key 的重要组成部分。

缓存Key: some_biz_prefix_10086

四、总结

本文提供一些解决 Key 过长的思路,希望对遇到相似问题的同学有启发。

0 人点赞