中间件面经整理

消息队列专题

1.JMS和AMQP的区别?
(1)JMS只有两种实现,分别是点对点和话题订阅的模式;AMQP常用的有五种,点对点,发布订阅,广播,headers是根据发送消息的属性来看究竟传递到哪一个队列里面去。
(2)JMS只能在Java上面使用,AMQP是跨平台的。
(3)JMS可以传递多种类型的数据(Java原始的数据流,StreamMessage;MapMessage键值对,TextMessage字符串对象,ObjectMessage序列化的字符串对象以及BytesMessage二进制),AMQP只能传递byte[]类型的二进制数据。
2.几种消息队列的区别?
中间件面经整理_第1张图片
3.RabbitMQ的架构?
(1)Broker,rabbitmq的服务节点称之为broker;
(2)Queue,队列,用户可以订阅队列,消息就是在队列里面传输的。
(3)Exchange,交换机,生产者将消息发布到交换机里面,之后交换机将消息路由到队列里面。
(4)Binding,绑定关系,交换机可以和队列进行绑定。
(5)routingKey,路由键,就是交换机的路由规则。
4.RabbitMQ如何保证消息能够收到?
(1)发送方的确认机制,确认消息是否投递到交换机里面。
(2)接收方的确认机制,没确认的消息是不会删除的,收不到ack是不会走下一个的。
5.为什么RabbitMQ会有重复消费,如何避免?
(1)rabbitMq有一个返回确认得机制,就是你收到消息之后需要确认一下自己已经收到了,如果发这个已经收到了得消息得时候网络中断就导致这个消息没有消费,mq会重新发送给我们。
(2)避免可以采用第一个,就是数据库中对于数据有一个版本,只有去取出得版本能对的上上一个版本,才更新,否则都算是重复消费。
(3)效率低,所以我们可以考虑用setnx就是redis来操作同一个事情。
6.RabbitMQ的四种模式?
(1)单播模式direct:如果队列和交换机绑定的路由键是dog,那么就只会转发路由键为dog的消息,不会转发别的。
(2)广播模式fanout:会将消息发送到所有绑定的队列上,不去处理路由键。
(3)订阅模式topic:会按照模糊匹配的方式去将消息发送到交换机绑定的特性规则的队列中去。”*”表示匹配一个,”#”表示匹配0个或者多个。
7.rabbitmq如何保证消息不丢失?
(1)mq消息丢失主要是三种情况,发送的时候丢了,mq自己搞丢了,接收端搞丢了
(2)发送的时候采取confirm方式(开启事务的话是同步的,会在阻塞);mq开启持久化;接收端关闭自动ack

Redis这一块

1.Redis的几种基本数据结构?
中间件面经整理_第2张图片

-String
(1)当我们只存放简单数字的时候,比如123,那么redisObject(redis基本对象,包括数据类型,编码方式以及指针等)的指针就直接指向这个数据。
(2)当我们存放一个大一点的字符串超过32长度的时候,那么就会使用SDS(包括len长度,buff存放字符串,free表示buff中未使用的长度)来存放,同时redisObject中的指针就会指向这个。
(3)int存放小于8位的long形数据,embstr存储小于44字节长度的,raw存储更大的
(4)首先如果我们的字符串需要用redisObject去存放指向真正数据的指针,一个redisObject就需要16字节去存放,同时也知道动态字符串SDS的大小是超过64字节就需要去换成raw类型了,这个时候减去,就剩下了48字节;这个SDS里面有标记长度,分配,以及类型的标记,各占一字节,就剩下45字节了,字符串都以\0结尾,再减去一字节,就剩下44字节了。
中间件面经整理_第3张图片
中间件面经整理_第4张图片
-Hash类
(1)一样可以使用两种编码形式,一种是ziplist,一种是字典
(2)Ziplist就是key-value挨着存放,字典就是用指针进行连接。
(3)少于512个元素,同时元素长度小于64个字节的时候采用ziplist,多的时候采用字典。
里面存在一个ht数组,这个数组有两个单位,0表示正在用的,1表示括容得时候用的,在括容得时候ht[1] >= 第一个大于 ht[0].used * 2 的 2n;
中间件面经整理_第5张图片
下面是渐进式rehash得流程
中间件面经整理_第6张图片
在每次进行增删改查得时候,会直接把这个ht[0]对应得键值对全部挪到新的上面,增加直接在新的上面,修改在旧的上面,查询旧的找不到就到新的上面。当我们全部完成得时候,就用新的替代旧的。
-list
(1)实际就是按照插入顺序进行排序的,可以添加到列表头也可以添加到列表尾部,实际上底层是个链表。
(2)其底层采用ziplist:一片连续的存储空间存储数据,里面会由若干个entry组成,entry里面存放了上一个entry的大小。
(3)当列表元素多的时候,就采用链表的形式存储;少的时候就采用zipList。
(4)压缩链表中可以直接记录链表尾部得位置,因为他能获取链表得长度偏移量。
(5)每个entry里面有一个属性,标志得是上一个entry得大小,这样就能快速找到上一个entry得入口了。
(6)他用1/5得长度来表示前面节点得大小是不是254字节以上,是的话就用特殊得标志来表示,不是得话就直接表示长度了。
(7)但是这样有一种隐患,就是有一堆大小在253-254之间得entry,首个entry前面添加了一个大于254得entry导致其指针从1个字节变成了5个字节,后面所有得都得跟着变。
(8)所以ziplist不适合存放太多的大数据,因为拷贝浪费时间。
-Zset
(1)使用ziplist或者是字典+跳表实现;
(2)Ziplist存储的时候,就是按照分值按顺序来存放所有的数据信息。
(3)字典+跳表就是字典中key存放数据,value存放分值;跳表object属性存放元素成员,score属性存放分值。
(4)元素数量小于128,元素长度小于64字节,就使用zipList,否则使用跳表+字典。
-set
(1)可以使用整数集合和字典来存放。
(2)当set里面的数据都是整数同时元素数量都不超过512的时候就采用intset,否则采用字典;
(3)字典实际上就是key能用,但是value为null;
2.Redis的过期策略?
(1)设置过期时间,expire,没有设置过期时间就是永不过期。
(2)定时删除,为每一个key设置一个定时器,到了过期时间的时候就用这个定时器去删除这个key。(优点:内存释放的块;缺点:需要花费大量的CPU时间)
(3)懒汉式删除:过期了不删除,之后每次调用的时候去看一下过没过期,过期了就删除并且返回null。(优点:对于CPU的时间占用少;缺点:如果一直没人调用,那么就会造成内存泄漏)
(4)定期删除:每隔一段时间,去执行依次删除过期key的操作。
Redis使用的过期策略:懒汉式+ 定期删除(对指定数个库的每一个库随机删除小于等于指定个数个过期的key)。
7.如何保证数据库和缓存的数据一致性?
(1)读取数据的时候:程序判断缓存中是否存在;存在的时候,相当于命中缓存,那么直接拿出来;没命中的时候,就从数据库中读取,之后存放在缓存中。
(2)写数据的第一种策略:更新数据库,之后更新缓存
问题:A写数据库,B后于A写数据库,B写缓存,A写缓存,缓存和数据库中不一致,是脏数据。解决线程安全问题是可以加锁的,但是效率低,我们不怎么考虑这种方式。
(3)写数据的第二种策略:更新数据库,删除缓存中的数据
问题:A读数据,未命中,从数据库中拿出;B修改,之后删除缓存;A网络延迟,将脏数据写入缓存。可能性小,需要同时满足很多条件。可以设置缓存过期时间短一些,这样就保证了脏数据存放的时间很短。
优点:避免了所有数据都写入缓存的缓存频繁更新问题
缺点:复杂的逻辑全靠代码实现,会有冗余代码;缓存未命中的查询时间很长;
8.Redis数据持久化策略?
在指定的时间间隔内,将数据写入磁盘中,恢复的时候就是将快照文件直接读到内存里面。Redis会fork一个子进程来进行持久化,先将数据写到临时文件里面,持久化结束了,将这个临时文件替换。
(1)save只管保存,其余的不管,保存完了才能去干别的事情。
(2)Bgsave在后台进行异步,同时接受客户端请求。
优点:
(1)适合大规模的数据恢复,其速度比AOF要快
(2)Rdb在保存文件的时候,父进程只是创建一个子进程就完事了,后面的事情都是子进程在做,我们还能正常接受请求。
缺点:
(1)数据安全性低,如果备份的时间点出现了故障,就会丢失最后一次持久化的数据。
(2)Fork的时候,备份中的数据被克隆了一份,有两倍的内存膨胀。
9.Redis数据持久化策略AOF?
以日志的形式来记录每个操作,只许追加文件但是不允许改写文件,redis重启之后会从里面读取文件
三种形式:出场就是每一秒记录一次,但是会有数据丢失;每一次都记录,性能较差。
文件越来越大的时候,就会有重写机制,超过指定大小的阈值的时候,就会进行内容压缩,只保留可以恢复数据的最小指令集。
优点:
(1)数据安全,可以选择合适的。
(2)中途宕机也不会影响前面的数据。
缺点:
(1)更新频率高,恢复速度慢。
(2)运行速度低。
10.Redis为什么速度这么快?
(1)其基于响应式开发的网络事件处理器称之为文件事件处理器,这个东西是单线程的。采用I/O多路复用的机制监听多个socket。
(2)文件时间处理器:多个Socket,IO多路复用,文件事件派发器,事件处理器。
(3)多个socket有多个操作,每个操作对应不同的文件事件,将socket放到一个队列里面排队,每次取一个给分派器,分派器将socket给事件处理器。
(4)纯内存操作,核心基于IO多路复用,避免频繁切换线程带来的问题。
11.什么叫缓存雪崩?
原因:缓存大面积失效,大量的请求都同时落在数据库上造成IO压力过大;
解决:随机过时间,防止同一时间大面积失效。
12.什么叫缓存穿透?
原因:大量的访问一些不存在的key导致redis命中失败,查询数据库。
解决:缓存一下值为null的key设置短暂的过期时间。
13.什么叫缓存击穿?
原因:缓存中没有,数据库有,大量的用户同时访问
解决:加锁,其余自旋,一个查询;热点数据永不过期。
14.Redis集群策略,哨兵模式?
(1)集群监控:哨兵对redis的主节点和从节点进行监控,看其是否正常工作。
(2)消息通知:一个节点存在问题的时候,会发送给用户。
(3)故障转移:主节点挂了,自动转移到从节点上。
(4)配置中心:主节点挂了,允许客户端搞一个新的主节点。
-具体的流程
(1)哨兵是一个独立的进程,作为进程,其会独立运行,同时其是发送命令,等待redis的响应。
(2)一个哨兵对redis服务器监控可能有问题,所以可以使用多个哨兵。
(3)假设一个服务器宕机,哨兵1监控到了,不会马上将其下线,仅仅是哨兵1认为其不可用(主观下线),当其余的哨兵也检测其不可用并且达到了一定的数量得时候会发起一次投票,之后进行切换操作。
15.Redis集群,主从复制?
(1)从数据库连接主数据库,发送SYNC命令;
(2)主数据库接收到SYNC命令后,开始执行BGSAVE(在生成RDB文件的过程中还继续保持可用)命令生成RDB文件并使用缓冲区记录此后执行的所有写命令;
(3)主数据库BGSAVE执行完后,向所有从数据库发送快照文件,并在发送期间继续记录被执行的写命令;
(4)从数据库收到快照文件后丢弃所有旧数据,载入收到的快照;
(5)主数据库快照发送完毕后开始向从数据库发送缓冲区中的写命令;
(6)从数据库完成对快照的载入,开始接收命令请求,并执行来自主数据库缓冲区的写命令;(从数据库初始化完成)
(7)主数据库每执行一个写命令就会向从数据库发送相同的写命令,从数据库接收并执行收到的写命令(从数据库初始化完成后的操作)
(8)出现断开重连后,2.8之后的版本会将断线期间的命令传给重数据库,增量复制。
(9)主从刚刚连接的时候,进行全量同步;全同步结束后,进行增量同步。当然,如果有需要,slave 在任何时候都可以发起全量同步。Redis 的策略是,无论如何,首先会尝试进行增量同步,如不成功,要求从机进行全量同步。
16.Redis集群,Cluster集群?
其实哨兵模式基本已经实现了高可用,但是由于所有的数据在每一个redis节点上面都存了一份,比较浪费内存,所以这个cluster模式保证了节约内存。
(1)默认拥有16384个插槽,并将这些插槽分配给集群中得各个节点。
(2)每个节点都有自己得从节点,插入删除得时候都会进行同步。
(3)每次来请求得时候,都会首先进行一个算法,得到得结果进行mod16383,根据插槽得所属关系看看落在哪一个节点上面。
17.主从复制的核心原理?
(1)主节点可读可写,从节点只读不写。
(2)主从都维护一个偏移量。
(3)主节点维护一个复制积压缓冲区,主从的offset差的太多且超过缓冲区长度,那么就进行全量复制。
(4)每个redis都有一个id,从节点存放主节点的id,断开之后重新连接,看看id是不是存过,是的话增量复制,否则全量复制。
18.缓存有什么弊端?
(1)数据一致性差
(2)缓存雪崩
(3)缓存穿透
(4)缓存击穿
19.Redis的新型数据结构?
(1)bitmap:就是只有1,0,一般是统计可能网站有没有人访问这种。
(2)Hyperloglog:用于计算基数的,相同元素去重,还能合并。
(3)Geospatial:记录地理位置。
20.Redis的数据结构的应用场景?
(1)string:图片,视频,秒杀,分布式锁等;
(2)Hash:可以存放单点登录用户信息;
(3)List:做redis的分页功能
(4)Set:全局去重,可以快速判断用户是否注册
(5)Zset:排行榜,topN;
21.Redis和数据库保持一致性?
(1)首先需要将缓存删除,之后MySQL更新数据库
-但是这种情况下,要是删除了之后,用户就来了,看到没有数据,就从数据库里面拖拽数据,那么得到得就是脏数据。
(2)首先更新缓存,之后删除数据
-这种得话,如果更新完了,但是还没有删除,就宕机了,这样里面得就是脏数据了。
使用双删策略,就是首先,我们删除缓存,写数据库,之后延时500ms之后,再删除缓存。
(3)另一种就是采用binlog + 消息队列去进行更新操作得。
22.redis的性能瓶颈在哪里?
(1)操作bigKey的时候,分配内存消耗的多(单个大于10kb,或者数据量太大)。
(2)AOF的always机制开启,每一次都会刷入磁盘,写磁盘的速度比写内存慢;
(3)无法利用CPU多核。
23.Redis得reHash的过程?
(1)首先会重新根据大小等要素创建一个新的空的Hash表。
(2)之后将index设置成0.
(3)每次有增删改查等操作的时候,除了执行正常的操作,还需要执行rehash操作,就是从index开始找到第一个不是空的位置,将其内容全部放在新的表中,之后index++。
(4)但是要是长时间压根没有操作的话,还是会有定时机制去帮助将所有的key给迁移过去。
(5)全部完事了之后,将原表空间释放,之后指向新的表。
(6)这种方式的好处就是可以避免集中的reHash操作带来的庞大的计算量。
(7)但是坏处就是需要二倍的存储空间。
24.Redis的Rehash的过程中数据量大会有什么问题吗?
(1)扩容开始的时候,会创建两个hash表,这样会导致占用空间大。
(2)查找更新和删除的操作会在两个表上面进行,所以耗时增加。
(3)当数据量大的时候,会使得内存超过maxmemory,导致驱逐淘汰策略,使得主从不一致的问题。
25.Zset为什么使用跳表和字典?
(1)单独使用字典的话,会导致范围查询很困难,因为需要排序。
(2)单独使用跳表的话,会导致根据key查询值得困难。
26.Redis3.0中得LRU如何实现得?
(1)首先搞出来一个池子,这个池子就是存放我们需要淘汰得key得池子。
(2)之后每次将N个key放到池子里面,要是池子满了,就将空闲时间最小的那个key从池子里面拿出去。
(3)之后想要淘汰的时候,就淘汰掉池子里面空闲时间最大的key。
27.RDB的优点?
(1)其是压缩后的数据,占用空间小。
(2)可以最大化redis的性能,父进程继续应对服务,子进程进行复制。
(3)恢复大的数据集的时候很棒。
28.RDB的缺点?
(1)服务器故障,丢失一次数据。
(2)数据量大的时候,相当于整个占用内存扩充两倍。
29.AOF的优缺点?
优点就是数据不会丢失,一条一条加。
缺点就是性能低。
30.pipeline有什么好处?
由于redis是单线程的,所以他的命令实际上是堆积到一起去执行的,一次命令花费的时间是一次网络的时间+一次命令的时间;使用pipeline可以使执行的时间变成一次网络的时间+多次命令的时间,大大减少时间。
31.数据库丢失场景(脑裂)?
(1)数据库有三个节点,每个节点一主两从。
(2)当第一个节点的主库和其他两个从库发生了网络故障,那么其只能接受写指令却不能将其同步到从库。
(3)一段时间内无法恢复,将会选举新的库称为master,这样在这段时间接受的写入信息就都丢失了。

你可能感兴趣的:(中间件,java-rabbitmq,rabbitmq)