JAVA面试——分布式缓存

    • 为什么用缓存?
      • 高性能:减少查询同一个数据时的响应速度
      • 高并发:减少数据库的承载压力(2000/s),缓存走内存,天然支撑高并发
    • 缓存的不良后果:
      • 缓存与数据库的双写不一致
      • 缓存雪崩
      • 缓存穿透
      • 缓存并发竞争
    • Redis和memcached区别(单线程、NIO、异步)
      • Redis支持服务器端数据操作:数据类型更多,功能更全
      • 内存使用效率对比:简单key-value时memcached效率高,hash结构存储Redis高
      • 性能对比:Redis单线程,小数据时Redis高;大数据时多线程的memcached高
      • 集群模式:memcached不支持集群,Redis支持
    • Redis单线程模型:
      • 文件事件处理器,单线程,通过IO多路复用程序同时监听多个socket,通过socket上的事件选择对应的事件处理器处理事件
      • AE_READABLE:socket可读(连接操作、客户端对Redis执行write操作,close操作)
      • AE_WRITABLE:socket可写(客户端对Redis执行read操作)
    • Redis单线程模型为什么效率高?
      • 纯内存操作(事件处理器在内存操作,性能高1ms)
      • 核心基于非阻塞IO多路复用机制(不处理、直接压队列)
      • 单线程避免了多线程的频繁上下文切换问题
    • Redis有哪些数据类型?
      • string
      • hash
        • 结构化数据,存放对象
          • key=150
          • value={
          •   “id”: 150,
          •   “name”: “zhangsan”,
          •   “age”: 20
          • }
      • list
        • 列表性数据结构(微博粉丝)
          • key=某大v
          • value=[zhangsan, lisi, wangwu]
      • set
        • 无需集合,自动去重
      • sorted set
        • 去重&排序
    • Redis的过期策略、内存淘汰机制
      • 定期删除+惰性删除
        • 每隔100ms抽取设置过期时间的key,检查是否过期后删除(定期)
        • 获取某个key时,redis检查是否过期(惰性)
      • 内存淘汰
1)noeviction:当内存不足以容纳新写入数据时,新写入操作会报错,这个一般没人用吧,实在是太恶心了
2)allkeys-lru:当内存不足以容纳新写入数据时,在键空间中,移除最近最少使用的key(这个是最常用的)
3)allkeys-random:当内存不足以容纳新写入数据时,在键空间中,随机移除某个key,这个一般没人用吧,为啥要随机,肯定是把最近最少使用的key给干掉啊
4)volatile-lru:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,移除最近最少使用的key(这个一般不太合适)
5)volatile-random:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,随机移除某个key
6)volatile-ttl:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,有更早过期时间的key优先移除
    • 手写LRU算法
  • Redis高并发、高可用、缓存一致性:
    • Redis高并发:主从架构,一主多从,单主用来写入数据,单机几万QPS,多从用来查询数据,多个从实例可以提供每秒10W的QPS。如果需要缓存容纳数据量大,用Redis集群。
    • Redis高可用:如果你做主从架构部署,其实就是加上哨兵就可以了,就可以实现,任何一个实例宕机,自动会进行主备切换。
    • 高并发
      • 主从架构,实现读写分离(master写,slave读),水平扩容
      • redis replication->主从架构->读写分离->水平扩容支撑读高并发
      • master开启持久化
      • 主从架构核心原理:
        • master启动线程,生成RDB快照,发送给slave
        • 断点续传,记录offset继续复制
        • 无磁盘复制:在内存创建rdb,发送给slave
    • Redis replication(复制)的完整流程
    • 数据同步的核心机制:
      • master和slave都会维护一个offset
      • backlog:用来全量复制中断后的增量复制
      • master run id:区分master(重启或者数据发生变化)
      • psync:psync runid offset,从节点使用此命令从master node进行复制
    • 全量复制
      • master生成快照
      • 发送给slave node
      • master在生成快照时,将所有新的写命令缓存在内存中,slave保存rdb后,将新的写命令复制
      • slave在接收到rdb后,清空旧数据,加载rdb
      • 如slave开启aof,立即重写aof
    • 增量复制
      • 全量复制中断
      • master用runid和offset从backlog中获取到丢失数据,发送给slave
    • heartbeat
      • master默认每隔10秒发送一次heartbeat,salve node每隔1秒发送一个heartbeat
    • 异步复制
      • master每次接收到写命令之后,现在内部写入数据,然后异步发送给slave node
    • 高可用性
      • 基于哨兵(sentinal)的高可用,故障转移(failover),主备切换
    • 哨兵:
      • 哨兵的作用:
      1. 集群监控,负责监控redis master和slave进程是否正常工作
      2. 消息通知,如果某个redis实例有故障,那么哨兵负责发送消息作为报警通知给管理员
      3. 故障转移,如果master node挂掉了,会自动转移到slave node上
      4. 配置中心,如果故障转移发生了,通知client客户端新的master地址
      • 分布式,哨兵集群运行
    • 主备切换数据丢失问题:
      • 异步复制导致:
        • master->slave复制是异步的,可能没复制完,master宕机
      • 集群脑裂导致:
        • master主节点,出现异常性的相同工作的两个节点
        • client可以和旧master写数据,恢复后旧master成为slave后数据丢失
      • 解决:
        • min-slaves-to-write 1
        • min-slaves-max-lag 10
        • 要求至少有1个slave,数据复制和同步的延迟不能超过10秒
        • 如果说一旦所有的slave,数据复制和同步的延迟都超过了10秒钟,那么这个时候,master就不会再接收任何请求了
    • 哨兵的核心原理:
      • sdown和odown转换:
        • sdown主观宕机
        • odown客观宕机
        • quorum指定数量
      • 哨兵的自动发现机制:
        • __sentinel__:hello这个channel里发送一个消息
      • slave配置的自动纠正
      • slave->master选举算法
        • 跟master断开连接的时长
        • slave优先级
        • 复制offset
        • run id
  • Redis重启数据恢复(数据持久化)
    • 持久化的意义:数据备份、故障恢复
    • 两种持久化:RDB、AOF
      • RDB:对Redis中数据执行周期性的持久化
      • AOF:对于每条写入命令作为日志,以append-only模式写入一个日志文件中(更加完整)
      • Redis重启后,通过回放AOF日志中的指令重新构建数据集
      • AOF大到一等程度后,rewrite操作,构建更小的AOF文件
    • RDB优劣势:
      • 优点:(冷备)
        • 生成多个数据文件,适合冷备。AOF需要写脚本处理。
        • RDB对Redis性能影响小,fork子进行进行RDB持久化
        • RDB重启恢复速度快
      • 缺点:
        • 恢复效果差,数据丢失
        • fork子进程时,数据文件特别大,会对客户端服务暂停数毫秒
    • AOF优劣势:
      • 优点:
        • 保护数据不丢失
        • append-only写入,没有磁盘寻址开销,写入性能高,文件不易损坏
        • AOF日志文件过大rewrite对客户端读写性能影响小
        • 日志文件可读
      • 缺点:
        • 日志文件大
        • 支持的写QPS低
        • 健壮性低
    • 结合RDB和AOF同时使用
  • Redis集群模式
    • 分布式数据的核心算法,数据分布的算法:
      • redis cluster——hash slot算法
        • 每个master持有部分slot
    • 节点间的内部通信机制
      • 集群的元数据维护:集中式(ZooKeeper)、gossip
        • gossip协议:元数据分散,降低压力,更新有延迟(meet ping pong fail)
      • 10000端口:用于节点间通信,为服务接口+10000,ping->pong
      • 交换信息的内容:故障信息、节点的增删、hash slot信息。。。
    • jedis: Redis的java client客户端
      • smart jedis:本地维护hashslot->node的映射表,缓存,不需要节点moved重定向
      • hash tag手动指定对应slot,set key1:{100}
    • 高可用与主备切换:
      • pfail(主观宕机) fail(客观宕机)
      • 与哨兵类似
  • Redis缓存雪崩与缓存穿透
    • 缓存雪崩:
      • 事前:Redis高可用(主从+哨兵、Redis Cluster)
      • 事中:本地ehcache缓存(系统内部小缓存)+hystrix限流(限流降级组件)
      • 事后:Redis持久化,快速恢复缓存数据
    • 缓存穿透:
      • 没查到,写空值到缓存中(set -999 UNKNOWN)
      • 使用布隆过滤器或者压缩filter提前拦截
  • 缓存与数据库双写数据一致性(读写串行化):
    • 缓存+数据库读写模式:cache aside pattern
      • 读。先缓存,再数据库,读完放入缓存
      • 更新,先删除缓存(缓存复杂计算得到、不会频繁访问),再更新数据库
    • 简单场景:先删缓存,在修改数据库
    • 复杂场景(删除缓存,修改数据库之前,读后缓存旧数据,数据库新修改)
      • 数据库与缓存更新读取操作进行异步(线程)串行化
        • 内存队列放请求,一个队列对应一个线程,串行进行操作
      • 读请求长时阻塞
        • 队列里写请求过多(部署多个服务,分摊数据更新)
        • 加多机器,每个机器上部署的服务实例处理更少的数据
      • 多服务实例部署的请求路由
        • 同一个商品的读写请求,路由到同一台机器上
        • nginx,hash路由功能
      • 热点商品的路由问题(读写请求高)
        • 商品更新清空缓存,导致读写并发,更新频率不高影响不大
  • Redis并发竞争问题:
    • 多客户端并发写一个key
    • CAS类的乐观锁方案
    • zookeeper提供分布式锁
    • 每个value的时间戳要比缓存中的时间戳更新,才可以写
  • 生产环境中的Redis怎么部署
posted @ 2019-02-12 15:37  李怕怕  阅读(2035)  评论(0编辑  收藏  举报