redis学习笔记——缓存设计

缓存设计

11.1穿透优化

​ 缓存穿透是指查询一个根本不存在的数据,缓存层和存储层都不会命中,通常出于容错的考虑,如果从存储层查不到数据则不写入缓存层

  1. 缓存层不命中
  2. 存储层不命中,不将空结果写回缓存。
  3. 返回空结果。

缓存穿透将导致不存在的数据每次请求都要到存储层去查询,失去了缓存保护后端存储的意义。

缓存穿透问题可能会使后端存储负载加大,由于很多后端存储不具备高并发性,甚至可能造成后端存储宕掉。通常可以在程序中分别统计总调用数、缓存层命中数、存储层命中数,如果发现大量存储层空命中,可能就是
出现了缓存穿透问题。

如何解决缓存穿透问题:

  1. 缓存空对象
  2. 布隆过滤器拦截
  3. 两种方案对比
    在这里插入图片描述

11.2 无底洞优化

如何解决问题:

1.串行命令

由于n个key是比较均匀地分布在Redis Cluster的各个节点上,因此无法使用mget命令一次性获取,所以通常来讲要获取n个key的值,最简单的方法就是逐次执行n个get命令,这种操作时间复杂度较高,它的操作时间=n次网络时间+n次命令时间,网络次数是n。很显然这种方案不是最优的,但是实现起来比较简单

List<String> serialMGet(List<String> keys) {
// 结果集
List<String> values = new ArrayList<String>();
// n次串行get
for (String key : keys) {
    String value = jedisCluster.get(key);
    values.add(value);
}
return values;
}
2.串行IO
Map<String, String> serialIOMget(List<String> keys) {
// 结果集
Map<String, String> keyValueMap = new HashMap<String, String>();
// 属于各个节点的key列表,JedisPool要提供基于ip和port的hashcode方法
Map<JedisPool, List<String>> nodeKeyListMap = new HashMap<JedisPool, List<String>>();
// 遍历所有的keyfor (String key : keys) {
// 使用CRC16本地计算每个key的slot
int slot = JedisClusterCRC16.getSlot(key);
// 通过jedisCluster本地slot->node映射获取slot对应的node
JedisPool jedisPool = jedisCluster.getConnectionHandler().getJedisPoolFrom
Slot(slot);
// 归档
if (nodeKeyListMap.containsKey(jedisPool)) {
	nodeKeyListMap.get(jedisPool).add(key);
} else {
    List<String> list = new ArrayList<String>();
    list.add(key);
    nodeKeyListMap.put(jedisPool, list);
}
}
// 从每个节点上批量获取,这里使用mget也可以使用pipeline
for (Entry<JedisPool, List<String>> entry : nodeKeyListMap.entrySet()) {
JedisPool jedisPool = entry.getKey();
List<String> nodeKeyList = entry.getValue();
// 列表变为数组
String[] nodeKeyArray = nodeKeyList.toArray(new String[nodeKeyList.size()]);
// 批量获取,可以使用mget或者Pipeline
List<String> nodeValueList = jedisPool.getResource().mget(nodeKeyArray);
// 归档
for (int i = 0; i < nodeKeyList.size(); i++) {
keyValueMap.put(nodeKeyList.get(i), nodeValueList.get(i));
}
}
return keyValueMap;
}
3.并行IO

11.3 雪崩优化

预防和解决缓存雪崩问题,可以从以下三个方面进行着手。

  1. 保证缓存层服务高可用性
  2. 依赖隔离组件为后端限流并降级
  3. 提前演练。

11.4 热点key重建优化

  1. 互斥锁
    此方法只允许一个线程重建缓存,其他线程等待重建缓存的线程执行完,重新从缓存获取数据即可

  2. 永远不过期

在这里插入图片描述

本章重点回顾

  1. 缓存的使用带来的收益是能够加速读写,降低后端存储负载。
  2. 缓存的使用带来的成本是缓存和存储数据不一致性,代码维护成本增大,架构复杂度增大。
  3. 比较推荐的缓存更新策略是结合剔除、超时、主动更新三种方案共同完成。
  4. 穿透问题:使用缓存空对象和布隆过滤器来解决,注意它们各自的使用场景和局限性。
  5. 无底洞问题:分布式缓存中,有更多的机器不保证有更高的性能。有四种批量操作方式:串行命令、串行IO、并行IO、hash_tag。
  6. 雪崩问题:缓存层高可用、客户端降级、提前演练是解决雪崩问题的重要方法。
  7. 热点key问题:互斥锁、“永远不过期”能够在一定程度上解决热点,key问题,开发人员在使用时要了解它们各自的使用成本。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值