Java八股文——Redis与一致性协议

摘要:
Redis是单线程的。在完成查询之前,keys命令将阻塞一段时间。您是否使用过Redis作为异步队列?Redis的列表可以用作消息队列,通过rpush插入并由lpop弹出。当Redis启动RDB时,它会周期性地分叉一个子进程。子进程将根据父进程的内存生成临时快照文件,并在完成后替换RDB文件。

Redis

  • Redis数据结构

  String字符串,list链表,hash键值对,set集合,sortedset有序集合,BloomFilter布隆过滤器

  布隆过滤器原理:当一个元素被加入到集合中时,通过K个散列函数将元素分布到一个位数组上的K个点,查询该元素的时候,如果hash出来的这个K个点都为1,则说明元素可能存在,如果有一个为0,则说明元素一定不存在。优点:可用于防止缓存穿透,数据库的元素先散列到布隆数组中,查询时先通过布隆过滤器判断是否存在再查询。缺点:牺牲了准确性和便利性,查询出来位数组上的点全为1也不一定存在。删除时也不能修改位数组,否则容易影响其他数据的查询

  • Redis数据结构的底层实现

    1. String:
      struct sdshdr{ 
        //记录buf数组中已使用字节的数量 
        //等于 SDS 保存字符串的长度 
        int len; 
        //记录 buf 数组中未使用字节的数量
        int free//字节数组,用于保存字符串 
        char buf[];
      }

      优点:不会有字符串变更造成的内存溢出问题;获取字符串长度的时间复杂度为1;空间预分配,惰性空间释放free字段,会默认留一定的空间放置多次重分配内存

    2. Hash:数组+链表的基础上,进行了一些rehash的优化,
      1. Redis的hash采用链地址法来处理冲突,没有使用红黑树
      2. hash表节点采用单链表结构
      3. rehash优化:分治思想,将庞大的迁移工作量分到每一次curd中,避免服务繁忙
    3. List:双向链表
    4. set:内部实现是value为null的Hashmap,通过计算hash的方式来排重。
    5. zset:使用hashmap和跳跃表(skiplist)来保证数据的存储和有序,Hashmap存放的是成员到score的映射,跳跃表中存放的是所有成员,排序依据是score,使用跳跃表机构可以获得比较高的查询效率,并且实现上简单。跳跃表:每个节点维持多个指向其他节点的指针,从而达到快速访问节点的目的
  • Redis有事务吗?

    1. multi开启事务
    2. exec执行事务内命令
    3. discard取消事务
    4. watch监视一个或多个key,key被改动时事务将会被打断
  • Redis单线程为什么执行这么快

    1. 纯内存操作,读写的时候不会受到磁盘IO的限制
    2. 单线程操作,避免了切换上下文和竞争条件,也避免了多进程或线程切换的CPU损耗,也不存在死锁的问题
    3. 采用了IO多路复用机制
  • 缓存问题:雪崩,穿透,击穿

  雪崩:同一时间内大量的缓存失效导致DB压力过大。
     这种情况可以对缓存的key在默认值上加上一些随机时间,让缓存失效的时间分散开来

  穿透:指缓存和数据库中都没有的数据,而用户不断发起请求
     这种情况可以对一些查询出来不存在的数据缓存一个null,失效时间设置短一些防止数据库新增了这个元素
     还可以使用布隆过滤器,在查询之前先通过布隆过滤器判断是否存在

  击穿:这个和穿透有点像,是指某个热点key在大量访问的时候突然失效了,导致请求直接来到数据库。
     热点key设置为永不过期,或者定时对这个key进行更新

  • Redis出现热点key造成集群访问量倾斜的解决办法?

    1. 使用本地缓存
    2. 利用分片算法的特性,对key进行打散处理,给hotkey加上前缀或后缀,把一个hotkey的数量变成redis实例个数的倍数
  • Redis里面有1亿个key,其中有10w个key是以某个固定的已知的前缀开头的,如何将它们全部找出来

  redis中有个指令是keys,可以指定模式查询对应的key列表

  ----如果这个redis正在给线上的业务提供服务,那使用keys指令会有什么问题?

  redis是单线程的,keys指令会阻塞一段时间,查询完成才能恢复。可以使用scan指令替代,scan是无阻塞的指令,不过scan可能会查出重复的数据,这个可以在客户端做一些去重。

  • 有使用过redis做异步队列吗?

  redis的list就可以做消息队列,通过rpush插入,lpop弹出。

  ----能否生产一次,消费多次?

  redis有pub/sub模型,可以实现一对多的消费,不过在消费者掉线的时候会有消息丢失的问题,这类情况还是使用专业的消息中间件比较好

  ----那有用过redis做延时队列吗?

  可以使用sortedset,拿时间戳作为score,消息内容作为key调用zadd来生产消息,消费者用zrangebyscore指令获取N秒之前的数据轮询进行处理。

  • redis怎么做持久化的?

  redis有两种持久化的方式,AOF和RDB,其中AOF是增量持久化,RDB是全量持久化,所有一般RDB会比较耗时,需要配合AOF使用,一般redis重启时,会通过RDB文件重新构建内存,然后再使用AOF重新对近期数据做处理进行完整恢复,不过一般redis在AOF开启时,是优先加载AOF,AOF文件找不到才使用RDB,AOF是日志型文件,每个指令都会存储,而RDB会优化指令,保证数据完整即可。

  • 机器突然断电,丢失的数据怎么办?

  开启了AOF之后,取决于AOF的sync设置,如果设置1s一次的话,会丢失1s内的数据,也可以设置成每条指令都sync一下,不过会导致磁盘io增多性能降低。

  • RDB的原理?

  redis在开启RDB时,会定时fork一个子进程,子进程会根据父进程内存生成临时快照文件,完成后对RDB文件进行替换。

  RDB相当于是redis某个时间段的内存快照,是十分紧凑的二进制文件,加载RDB文件比AOF文件快

  AOF相当于对redis的操作指令做复制,所有的写入命令会追加到aof_buf(缓冲区)中,根据对应的策略向硬盘做同步操作,然后定期对AOF文件进行重写,此外,AOF会对命令进行优化,简化一些操作命令

  • redis集群的同步原理?

  redis的主从同步分为全同步和修改同步,全同步一般是在启动的时候通过主机的bgsave生成RDB文件,从机通过RDB文件进行恢复,后续的同步都是修改同步,修改同步是通过propagate函数完成将一个操作记录到aof文件中或者扩散到其他slave中,在该函数中通过调用feedAppendOnlyFile()将操作记录到aof中,通过调用replicationFeedSlaves()将操作扩散到各slave中

  • redis集群模式的性能优化该怎么做?

    1. Master不做任何持久化操作
    2. 数据如果比较重要,某个slave开启aof备份,策略为每秒一次
    3. master和slave在同一个局域网内
    4. 避免在压力很大的主库上增加从库
  • redis怎么保证高可用

  redis中有哨兵模式,在主机宕机的时候,通过哨兵选举出新的master,哨兵必须存在三个以上,否则无法选举

    1. 领导者选举

    作用:选举出一个sentenel节点作为领导者去进行故障转移操作。

    过程:

      1). 每个做主观下线的sentinel节点向其他sentinel节点发送vote命令,要求将它设置为领导者。
      2). 收到命令的sentinel节点如果还没有同意过其他的sentinel发送的命令(还未投过票),那么就会同意,否则拒绝。
      3). 如果该sentinel节点发现自己的票数已经过半且达到了quorum的值,就会成为领导者。
      4). 如果这个过程出现多个sentinel成为领导者,则会等待一段时间重新选举。

    2. 选出新的master节点

      redis sentinel会选一个合适的slave来升级为master,那么,如何选择一个合适的slave呢?顺序如下:

      1). 选择slave-priority最高的slave节点(默认是相同)。
      2). 选择复制偏移量最大的节点。
      3). 如果以上两个条件都不满足,选runId最小的(启动最早的)。

    3. 更改slave节点的master节点

      当选举出新的master节点后,会将其余的节点变更为新的master节点的slave节点,如果原有的master节点重新上线,成为新的master节点的slave节点

  • redis的哨兵sentinel怎么保证自身的高可用呢?使用了什么协议?

  使用了Raft协议来保证高可用
  Raft协议中的相关概念:
  1、角色定义
    Leader:
    主节点,整个集群只有一个Leader,所有的写请求都通过Leader发送给Follower;
    Follower:
    从节点(服从角色);
    Candidate:
    在Leader消息发送失败或宕机,整集群没有Leader时,此时Follower接收Leader的心跳包失败,则Follwer开始竞选Leader时,它们的身份是Candidate。Candidate只是个中间状态,不会长期存在。
  2、Term(任期)定义
    在每一个Leader的任期期间,都有唯一表示该任期的一个Term;
  3、基本操作
    1、Raft将state machine replication划分为三个子问题
      1、Leader Election
      2、Log Replication
      3、Safety
    2、Leader Election步骤
      集群启动或Leader的心跳包消息无法发送给Follower时,触发 Leader Election——选主 操作。
    3、Log Replication步骤
      1、所有的写请求都要经过Leader;
      2、Leader将写请求携带在心跳包中发送给Follower;
      3、当Leader收到多数派回复的消息后,则先自己提交写操作,同时发送Commit请求给Follower;
    4、Safety保证
      1、Leader宕机感知:
        a、Raft通过TimeOut来保证Follower能正确感知Leader宕机或消息丢失的事件,并触发Follower竞选Leader;
        b、Leader需要给Follower发送心跳包(heartbeats),数据也是携带在心跳包中发送给Follower的;
      2、选主平票情况
        Leader Election时平票情况下,则两个Candidates会产生一个随机的Timewait,继续发送下一个竞选消息。
      3、脑裂(大小集群)情况:
        小集群由于没有得到多数派的回复,写操作失败;
        大集群会发生重新选主的过程,且新Leader拥有自己新的Term(任期),写操作成功;
        当小集群回到大集群时,由于小集群的Term小于新集群的Term,则同步新集群的信息。

  • 有没有考虑过,如果多个系统同时操作(并发)Redis带来的数据问题

    可以基于分布式锁操作。每个系统通过 Redis获取分布式锁,确保同一时间,只能有一个系统实例在操作某个 Key,别人都不允许读和写。
  你要写入缓存的数据,都是从 MySQL 里查出来的,都得写入 MySQL 中,写入 MySQL 中的时候必须保存一个时间戳,从 MySQL 查出来的时候,时间戳也查出来。
  每次要写之前,先判断一下当前这个 Value 的时间戳是否比缓存里的 Value 的时间戳要新。如果是的话,那么可以写,否则,就不能用旧的数据覆盖新的数据。

  • 如何保证缓存与数据库的双写一致性?

  先更新数据库,再删除缓存,将删除缓存的操作放在更新数据库的同一个事务中,如果删除缓存失败,抛出异常使当前事务回滚

  • redis线程模型了解吗?

    Redis 基于 Reactor 模式开发了自己的网络事件处理器: 这个处理器被称为文件事件处理器(file event handler)。文件事件处理器使用 I/O 多路复用(multiplexing)程序来同时监听多个套接字, 并根据套接字目前执行的任务来为套接字关联不同的事件处理器。文件处理器包括连接处理器,命令请求处理器,命令回复处理器,文件事件处理器以单线程方式运行, 但通过使用 I/O 多路复用程序来监听多个套接字, 文件事件处理器既实现了高性能的网络通信模型, 又可以很好地与 redis 服务器中其他同样以单线程方式运行的模块进行对接, 这保持了 Redis 内部单线程设计的简单性

  • 如何实现分布式锁?

  两种实现方式,redis和zookeeper,其中redis是通过lua表达式实现

  • 说到zookeeper,了解ZAB协议吗?

  zookeeper依赖ZAB协议来实现分布式数据一致性,ZAB协议全称为原子消息广播协议,ZAB协议可以说是在Paxos算法基础上进行了扩展和改造的。

  在ZooKeeper中所有的事务请求都由一个主服务器也就是Leader来处理,其他服务器为Follower,Leader将客户端的事务请求转换为事务Proposal,并且将Proposal分发给集群中其他所有的Follower,然  后Leader等待Follwer反馈,当有 过半数(>=N/2+1) 的Follower反馈信息后,Leader将再次向集群内Follower广播Commit信息,Commit为将之前的Proposal提交;

  ZAB协议中节点存在三种状态:

    Looking :系统刚启动时或者Leader崩溃后正处于选举状态
    Following :Follower节点所处的状态,Follower与Leader处于数据同步阶段;
    Leading :Leader所处状态,当前集群中有一个Leader为主进程;

  Zookeeper刚启动时,所有节点都处于Looking状态,这时集群会选举出一个Leader,Leader会处于Leading状态,其余节点发现存在主节点后,处于Following状态,并且与Leader保持同步,当从节点发现  Leader失去联系后,会开始新一轮选举。Zookeeper整个生命周期内都处于这样的循环

  ZAB协议定义了选举(election)、发现(discovery)、同步(sync)、广播(Broadcast)四个阶段。

  选举时,节点都会发送(myID,ZXID)到其余节点,通过判断ZXID(事务ID)的大小来决定哪个节点为leader,如果有多个节点都有LastZXID,则由myId决定,id小的为leader,id小表明该节点先加入集群。当投票数过半时,leader就产生了。然后Leader会以自身的lastZXID为基准,将follower同步。

  客户端提交事务请求时Leader节点为每一个请求生成一个事务Proposal,将其发送给集群中所有的Follower节点,收到过半Follower的反馈后开始对事务进行提交,ZAB协议使用了原子广播协议;在ZAB协议中只需要得到过半的Follower节点反馈Ack就可以对事务进行提交,这也导致了Leader几点崩溃后可能会出现数据不一致的情况,ZAB使用了崩溃恢复来处理数字不一致问题;消息广播使用了TCP协议进行通讯所有保证了接受和发送事务的顺序性。广播消息时Leader节点为每个事务Proposal分配一个全局递增的ZXID(事务ID),每个事务Proposal都按照ZXID顺序来处理;

  Leader节点为每一个Follower节点分配一个队列按事务ZXID顺序放入到队列中,且根据队列的规则FIFO来进行事务的发送。Follower节点收到事务Proposal后会将该事务以事务日志方式写入到本地磁盘中,成功后反馈Ack消息给Leader节点,Leader在接收到过半Follower节点的Ack反馈后就会进行事务的提交,以此同时向所有的Follower节点广播Commit消息,Follower节点收到Commit后开始对事务进行提交;

  • 一致性算法除了ZAB还有哪些?

  Base-Paxos

    paxos——Chubby(Google首次运用Multi Paxos算法到工程领域)

  Multi-Paxos

    zab协议——Zookeeper,raft协议——redis哨兵

  Paxos中的角色分类

  • Proposer 提案者:可以有多个,用于发起一个议案(由client向Proposer发出),议案包括议案编号、议案内容
  • Acceptor 接收者、批准者:用于接收Proposer提出的议案,并决定采纳哪一个议案
  • Learner 学习者、记录者:在最终决定采纳某个议案后,进行记录,不做其他事

  其中Proposer在Base-Paxos中可以存在多个,而Multi-Paxos中仅有一个,别名leader。因此,Base-paxos存在活锁问题:

  Java八股文——Redis与一致性协议第1张

  三种算法的区别:

  Raft:

    追加日志的操作必须是连续的(Multi-Paxos中是并发)
    只有拥有最新、最全日志的节点才能够当选Leader(Multi-Paxos中任意节点都可以写日志,无限制)

  zab:

    Raft每一次leader的任期叫做term,ZAB中叫做epoch
    Raft由leader向follower发送心跳,ZAB相反
    选主投票方式不同
    事务操作方式不同

  • 一致性就代表了正确性吗?

  一致性并不代表完全正确性,一致性需要客户端和共识算法(Consensus)来共同保证。
  Client Request操作的三个可能结果:成功、失败、unknown(Timeout)
  理解unknown(Timeout)
  场景:Client写请求,Leader向Follower同步日志,此时集群中有3个节点失败,2个节点存活,结果是? 假设节点为:S1、S2、S3、S4、S5(Leader)
  假设S5和S4存活,Client发起 第N次写请求 为 操作I 时,由于Leader没有得到多数派的回复,操作I只被发送到了S4中,此时Leader即会返回Client unknown,因为Leader不知道后面会不会成功将该条日志写入多数派中。
  结果1:假设Leader在返回客户端后,宕机的Follower:S1、S2、S3恢复正常,Leader再次发送 第N次写请求——操作I,且得到了多数派的回复,则提交日志,写操作最终结果为成功;
  结果2:假设Leader在返回客户端后,此时S5和S4宕机,且S1、S2、S3恢复正常,此时S1、S2、S3触发选主操作,且集群恢复可用,如果此时Client发起 第N+1次请求 为 操作I+1 ,且Client操作成功后 S5、S4恢复正常,则保存在S5、S4中的 操作I 会被删除,S5、S4同步最新的 操作I+1 到本地。则 第N次写请求—操作I 失败;

 

免责声明:文章转载自《Java八股文——Redis与一致性协议》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇Innodb日志与事务CNN实战2:CIFAR-10数据集上的图像识别下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

分布式算法(一致性Hash算法)

转载:https://www.cnblogs.com/moonandstar08/p/5405991.html 一、分布式算法     在做服务器负载均衡时候可供选择的负载均衡的算法有很多,包括: 轮循算法(Round Robin)、哈希算法(HASH)、最少连接算法(Least Connection)、响应速度算法(Response Time)、加权法(...

web.config中httpRunTime的属性

配置httpRuntime也可以让FileUpload上传更大的文件,不过设置太大了会因用户将大量文件传递到该服务器而导致的拒绝服务攻击(属性有说明) <httpRuntime> <httpRuntime useFullyQualifiedRedirectUrl="true|false"              maxRequestLe...

DialogFragment异常Fragment already added的原因与解决办法

DialogFragment异常的表现形式快速多次点击按钮展示DialogFragment弹框,100%复现崩溃 java.lang.IllegalStateException: Fragment already added: XXDialogFragment DialogFragment异常的发生原因 查看DialogFragment的show方法源码,...

关于HTTP协议头域详解

HTTP1.1  请求头:消息头   Accept:text/html,image/*  告诉服务器,客户机支持的数据类型 Accept-Charset:ISO-8859-1  告诉服务器,客户机采用的编码   Accept-EnCoding:gzip,compress 告诉服务器,客户机支持的数据压缩格式 Accept-Language:en   客户机...

IBM System p5 服务器 HACMP 安装指南

  一. 系统需求 1.1 硬件需求        IBM HACMP 支持所有 IBM System p5 服务器。   1.2 软件需求   1.2.1 AIX 与 RSCT 版本要求 AIX 5L Version RSCT Version RSCT Filesets AIX 5L Version 5.3 TL1 2.4.2 rsct.com...

[NewLife.XCode]百亿级性能

NewLife.XCode是一个有10多年历史的开源数据中间件,支持nfx/netcore,由新生命团队(2002~2019)开发完成并维护至今,以下简称XCode。 整个系列教程会大量结合示例代码和运行日志来进行深入分析,蕴含多年开发经验于其中,代表作有百亿级大数据实时计算项目。 开源地址:https://github.com/NewLifeX/X(求s...