redis性能优化

#### 缓存设计

1.缓存穿透 > 查询一个根本不存在的数据,缓存层没有,每次都要到存储层区查询,失去了缓存保护后端存储的意义
- 解决方案: 缓存空对象并设置超时时间
2. 缓存失效
>一大批缓存同一时间失效导致大量请求穿透缓存直达数据库,造成数据库压力过大甚至挂掉
- 解决方案: 将一次缓存过期时间设置为同一时间内不同时间,加个几秒的随机数
3. 缓存雪崩==> redis服务宕机或超大并发导致缓存层无法支撑,全部打到存储层导致存储层调用过高存储层也宕机了
- 使用高可用架构 如哨兵或集群
- 使用后端限流如Hysytix组件
- 提前做好预案
4. 热点key重建优化==>热点key失效的瞬间有大量的请求区访问后端重建缓存,导致后端负载过大
- 使用互斥锁 只允许一个线程重建缓存,其他线程等待从缓存中取值

开发规范与性能优化

  1. key名设计
    1. 可读性与可管理性,以业务名(或数据库名)为前缀(防止key冲突),用冒号分隔,比如业务名:表名:id
    2. 简洁性: 保证语义的前提下,控制key的长度
    3. 不要包含特殊字符 如 空格、换行、单双引号
  2. value设计
    • 拒绝bigkey
    • String一般超过10KB就是bigkey其他数据结构元素不要超过5000个
    • 非字符串的bigkey,不要使用del删除应使用hscan等渐进式删除
    • bigkey过期删除应配置异步删除(lazyfree-lazyexpire yes)
    • 网络拥塞 : 客户端每秒1000,一个bigkey为1m 对于一个千兆网肯定不行,对于单机多实例一个bigkey对其他实例也会影响
    • 优化bigkey
      1. 拆分
      2. 如果无法拆分取数据时应使用hmget 避免使用hgetall
      3. 选择适合的数据类型
      4. 控制key的生命周期
  3. 命令使用
    1. 关注要取出数据的量 有些情况下可以使用hscan,scan等避免使用hgetall
    2. 禁用命令,禁止使用keys flushall, flushdb
    3. redis多数据库较弱,多业务使用多数据库还是单线程的
    4. 使用批量命令提升效率如mget,mset ,pipeline管道
    5. redis事务建议使用lua脚本

客户端使用

  1. 避免多个应用使用同一redis
  2. 连接池的配置
    • maxTotal 连接池最大数量
        1. 要求高并发 1个命令1ms 要求5000QPS 理论上50 实际可以翻倍,无法保证连接释放就可以用
      • redis的应用数量*maxTotal应小于redis配置文件中maxClients
    1. maxIdle与minIdle 最大存活数与最小存活数 一般maxIdle会是QPS理论值
      1. 当连接池中的连接大于minIdle小于maxIdle,连接池会维持minIdle
      2. 当连接池连接数量大于maxIdle 连接池会维护maxIdle
      3. 连接预热 对于预知高并发,可以使用jedis.ping模拟连接然后释放让连接池保持在minIdle
      4. 高并发下建议客户端添加熔断功能(hystrix)
      5. 设置合理的密码
      6. redis对于过期键的清除策略
        1. 被动删除,当读写一个过期的key时,redis会删除这个过期的key
        2. 主动删除,redis会定期删除一批过期的key
        3. 当已用内存超过设置的内存值时会触发主动清理策略
          1. volatile-lru 根据最近使用情况删除过期的key,直到腾出空间
          2. allkeys-lru:根据最近使用情况删除所有的key,直到腾出空间
          3. allkeys-random:随机删除所有键,直到腾出空间
          4. volatile-random: 随机删除所有过期的键,直到腾出空间
          5. volatile-ttl 根据key过期时间删除,若没有使用noeviction策略
          6. noeviction 返回oom

布隆过滤器

简单理解 把key根据多个hash算法进行计算然后取模落到位数组上数组上元素值为1 取值时进行相同操作若计算后的几个落点至少有1个位1 就可能有此元素,若为0则肯定没有


	com.google.guava
	guava
	29.0-jre

//创建过滤器
BloomFilter bloomFilter = BloomFilter.create(Funnels.stringFunnel(Charset.forName("utf-8")), 1000000, 0.001);
//放值
bloomFilter.put(UUID.randomUUID().toString().replace("-", ""));
//取值
boolean contain = bloomFilter.mightContain("jamin" + i)
 

你可能感兴趣的:(Redis)