美文网首页
阿里P6之七NoSQL数据库Redis

阿里P6之七NoSQL数据库Redis

作者: Java及SpringBoot | 来源:发表于2019-11-28 10:15 被阅读0次

    个人专题目录


    7. NoSQL数据库Redis

    7.1 在你的项目中,哪些数据是数据库和Redis缓存双写一份的?如何保证双写一致性?

    高并发场景下的redis缓存和数据库双写不一致问题分析与解决方案设计

    7.2 系统上线,Redis缓存系统是如何部署的

    redis cluster,10台机器,5台机器部署了redis主实例,另外5台机器部署了redis的从实例,每个主实例挂了一个从实例,5个节点对外提供读写服务,每个节点的读写高峰qps可能可以达到每秒5万,5台机器最多是25万读写请求/s。

    机器是什么配置?32G内存+8核CPU+1T磁盘,但是分配给redis进程的是10g内存,一般线上生产环境,redis的内存尽量不要超过10g,超过10g可能会有问题。

    5台机器对外提供读写,一共有50g内存。

    因为每个主实例都挂了一个从实例,所以是高可用的,任何一个主实例宕机,都会自动故障迁移,redis从实例会自动变成主实例继续提供读写服务

    你往内存里写的是什么数据?每条数据的大小是多少?商品数据,每条数据是10kb。100条数据是1mb,10万条数据是1g。常驻内存的是200万条商品数据,占用内存是20g,仅仅不到总内存的50%。

    目前高峰期每秒就是3500左右的请求量

    7.3 系统上线,Redis缓存给了多大的总内存?命中率有多高?抗住了多少QPS?数据流回源会有多少QPS?

    http://fivezh.github.io/2019/02/11/cache-things/

    命中率计算:

    info命令:比如

    keyspace_hits:14414110
    keyspace_misses:3228654
    used_memory:433264648
    expired_keys:1333536
    evicted_keys:1547380
    
    • 查询命中数: 查询的命中个数,对应 keyspace_hits 字段。
    • 查询未命中数: 查询的未命中个数,对应 keyspace_misses 字段。
    • 查询命中率: 查询命中率,对应 keyspace_hits / ( keyspace_hits + keyspace_misses )。
    • 总Key个数: 缓存中总的 key 个数,所有 db 的 key 个数总和。
    • 已过期Key个数: 缓存中已过期 Key 个数,对应 expired_keys 字段。
      当缓存内存不足时,会根据用户配置的 maxmemory-policy 来选择性地删除一些 key 来保护内存不溢出
    • 通过计算hits和miss,我们可以得到缓存的命中率:14414110 / (14414110 + 3228654) = 81% ,一个缓存失效机制,和过期时间设计良好的系统,命中率可以做到95%以上

    7.4 热Key大Value问题,某个key出现了热点缓存导致缓存集群中的某个机器负载过高?如何发现并解决

    解决热点key问题,可以有以下几种方案:

    1. 互斥锁:查询数据库的过程,只让一个线程独占,这个线程构建缓存的过程,其他线程都要等待,直到第一个线程构建完成可以从中读取数据。
    2. 提前使用互斥锁:提前使用互斥锁,和互斥锁差不多,都是让一个线程独占构建缓存,不一样的是,在构建缓存的时候。在value内部设置一个超时值timeout1,这个过期时间比实际的缓存过期时间短。当从缓存中读到timeout1已经过期的时候,就认为数据也快过期了,直接执行查询数据库,进行构建缓存的过程。这样在所有快过期的数据前,就重新构建了缓存。
    3. 永远不过期
      1. 从redis上看,确实没有设置过期时间,这就保证了,不会出现热点key过期问题,也就是“物理”不过期。
      2. 从功能上看,如果不过期,那不就成静态的了吗?所以我们把过期时间存在key对应的value里,如果发现要过期了,通过一个后台的异步线程进行缓存的构建,也就是“逻辑”过期

    Redis使用过程中经常会有各种大key的情况, 比如:

    • 单个简单的key存储的value很大
    • hash, set,zset,list 中存储过多的元素(以万为单位)
      由于redis是单线程运行的,如果一次操作的value很大会对整个redis的响应时间造成负面影响,所以,业务上能拆则拆,下面举几个典型的分拆方案。
    1. 单个简单的key存储的value很大
      1. 改对象需要每次都整存整取
        1. 可以尝试将对象分拆成几个key-value, 使用multiGet获取值,这样分拆的意义在于分拆单次操作的压力,将操作压力平摊到多个redis实例中,降低对单个redis的IO影响;
      2. 该对象每次只需要存取部分数据
        1. 可以像第一种做法一样,分拆成几个key-value, 也可以将这个存储在一个hash中,每个field代表一个具体的属性,使用hget,hmget来获取部分的value,使用hset,hmset来更新部分属性
      3. hash、set、zset、list 中存储过多的元素
        1. 类似于场景一种的第一个做法,可以将这些元素分拆。以hash为例,原先的正常存取流程是 hget(hashKey, field) ; hset(hashKey, field, value)
          现在,固定一个桶的数量,比如 10000, 每次存取的时候,先在本地计算field的hash值,模除 10000, 确定了该field落在哪个key上。set, zset, list 也可以类似上述做法.

    7.5 超大Value打满网卡的问题如何规避

    • 业务设计上避免
    • 对于大文本【超过500字节】写入到Redis时,一定要压缩后存储!大文本数据存入Redis,除了带来极大的内存占用外,在访问量高时,很容易就会将网卡流量占满,进而造成整个服务器上的所有服务不可用,并引发雪崩效应,造成各个系统瘫痪!

    7.6 你过往的工作经历中,是否出现过缓存集群事故?说说怎么保证高可用的?

    redis cluster vs. replication + sentinal

    如果你的数据量很少,主要是承载高并发高性能的场景,比如你的缓存一般就几个G,单机足够了

    replication,一个mater,多个slave,要几个slave跟你的要求的读吞吐量有关系,然后自己搭建一个sentinal集群,去保证redis主从架构的高可用性,就可以了

    redis cluster,主要是针对海量数据+高并发+高可用的场景,海量数据,如果你的数据量很大,那么建议就用redis cluster

    7.7 平时如何监控缓存集群的QPS和容量

    Redis监控

    7.8 缓存集群如何扩容?

    Redis集群水平扩展

    7.9 说下redis的集群原理和选举机制

    Redis 集群模式的工作原理

    7.10 Key寻址算法都有哪些?

    分布式寻址算法

    • hash 算法(大量缓存重建)
      • 来了一个 key,首先计算 hash 值,然后对节点数取模。然后打在不同的 master 节点上。一旦某一个 master 节点宕机,所有请求过来,都会基于最新的剩余 master 节点数去取模,尝试去取数据。这会导致大部分的请求过来,全部无法拿到有效的缓存,导致大量的流量涌入数据库。
    • 一致性 hash 算法(自动缓存迁移)+ 虚拟节点(自动负载均衡)
      • 一致性 hash 算法将整个 hash 值空间组织成一个虚拟的圆环,整个空间按顺时针方向组织,下一步将各个 master 节点(使用服务器的 ip 或主机名)进行 hash。这样就能确定每个节点在其哈希环上的位置。
      • 来了一个 key,首先计算 hash 值,并确定此数据在环上的位置,从此位置沿环顺时针“行走”,遇到的第一个 master 节点就是 key 所在位置。
      • 在一致性哈希算法中,如果一个节点挂了,受影响的数据仅仅是此节点到环空间前一个节点(沿着逆时针方向行走遇到的第一个节点)之间的数据,其它不受影响。增加一个节点也同理。
      • 一致性哈希算法在节点太少时,容易因为节点分布不均匀而造成缓存热点的问题。为了解决这种热点问题,一致性 hash 算法引入了虚拟节点机制,即对每一个节点计算多个 hash,每个计算结果位置都放置一个虚拟节点。这样就实现了数据的均匀分布,负载均衡。
    • redis cluster 的 hash slot 算法
      • redis cluster 有固定的 16384 个 hash slot,对每个 key 计算 CRC16 值,然后对 16384 取模,可以获取 key 对应的 hash slot。
      • edis cluster 中每个 master 都会持有部分 slot,比如有 3 个 master,那么可能每个 master 持有 5000 多个 hash slot。hash slot 让 node 的增加和移除很简单,增加一个 master,就将其他 master 的 hash slot 移动部分过去,减少一个 master,就将它的 hash slot 移动到其他 master 上去。移动 hash slot 的成本是非常低的。客户端的 api,可以对指定的数据,让他们走同一个 hash slot,通过 hash tag 来实现。
      • 任何一台机器宕机,另外两个节点,不影响的。因为 key 找的是 hash slot,不是机器。

    7.11 Redis线程模型画个图说说

    Redis线程模型

    7.12 Redis内存模型画个图说说

    Redis内存模型

    7.13 Redis中的Lua有没有使用过? 可以用来做什么? 为什么可以这么用?

    Lua:
    https://www.cnblogs.com/huangxincheng/p/6230129.html

    1. 减少网络开销:可以将多个请求通过脚本的形式一次发送,减少网络时延和请求次数。
    2. 原子性的操作:Redis会将整个脚本作为一个整体执行,中间不会被其他命令插入。因此在编写脚本的过程中无需担心会出现竞态条件,无需使用事务。
    3. 代码复用:客户端发送的脚步会永久存在redis中,这样,其他客户端可以复用这一脚本来完成相同的逻辑。

    7.14 缓存穿透和缓存雪崩?

    缓存穿透含义:一般的缓存系统,都是按照key去缓存查询,如果不存在对应的value,就去DB查找。如果key对应的value是一定不存在的,并且对该key并发请求量很大,就会对DB造成很大的压力。这就叫做缓存穿透。

    缓存穿透解决方案:

    • 对查询结果为空的情况也进行缓存,缓存时间设置短一点,或者该key对应的数据insert了之后清理缓存;
    • 对一定不存在的key进行过滤。可以把所有的可能存在的key放到一个大的set中,查询时通过该set过滤(用的较少);

    缓存雪崩含义:当缓存服务器重启或者大量缓存集中在某一个时间段失效,这样在失效的时候,也会给DB带来很大压力;
    缓存雪崩解决方案:

    • 在缓存失效后,通过加锁或者队列来控制读数据库写缓存的线程数量。比如对某个key只允许一个线程查询数据和写缓存,其他线程等待;
    • 不同的key,设置不同的过期时间,让缓存失效的时间点尽量均匀;
    • 做二级缓存,A1为原始缓存,A2为拷贝缓存,A1失效时,可以访问A2,A1缓存失效时间设置为短期,A2设置为长期;

    相关文章

      网友评论

          本文标题:阿里P6之七NoSQL数据库Redis

          本文链接:https://www.haomeiwen.com/subject/vqbywctx.html