目录
##Nacos (Nacos服务注册中心+Nacos服务配置中心)
#什么是微服务/分布式(谈谈对微服务的理解--面试)
微服务是一种分布式架构模型。
将各个业务的共性进行抽取,做成独立运行的各项服务,可以针对各项服务进行部署、更新和扩展,可以解决因并发访问过大带来的系统复杂性,但会增加一定的维护成本。
SpringCloud是什么?(了解)
SpringCloud是一系列框架的集合,集成SpringBoot,提供很多优秀服务:服务发现和注册,统一配置中心, 负载均衡,网关, 熔断器等的一个微服务治理框架.
#分布式事务处理机制 面试问了
分布式事务呢是指事务的参与者支持事务的服务器,资源服务器以及事务服务器分别位于分布式系统的不同节点之上比如说大型的电商系统中的一些下单场景会涉及到扣库存,优惠促销计算,订单ID的生成,通常的情况下,库存,促销,主键生成策略都位于不同的服务器和数据库表中那么下单接口的成功与否不仅取决于本地节点的数据库操作而且还依赖第三方系统的一个结果,这个时候分布式事务,就是保证这些操作,要么全部成功,要么全部失败,因此本质上来说,分布式事务就是为了保证不同数据库的数据一致性基于CAP定理,对于上面情况产生的分布式事务问题,我们要么采用强一致性方案,要么采用弱一致性方案,强制性方案是指通过第三方事务管理器,来协调多个节点的事务性,保证每一个节点的事务达到同时成功或者同时失败,为了实现这一需求,我们会引入X/Open DTP模型提供的XA协议,基于2阶段提交或者3阶段提交的方式去实现,但是如果全局事务管理器中的多个节点,任意一个节点,在进行事务提交确认的时候,比如由于网络通信的延迟,导致了阻塞,就会影响到所有节点的事务提交,而这个阻塞过程呢,也会影响到用户的请求线程,一旦发送这种情况,这对于用户体验和整体的一个性能来讲,影响会非常的大,而弱一致性的方案就是针对强一致方案所衍生出来的性能和数据一致性平衡的一个方案,说白了,就是损失掉强一致性,数据在某一个时刻或者存在不一致的状态但是最终这些数据会达成一致,这样的好处就是提升了系统的性能,在弱一致性方案当中,常见的解决方案,比如:使用分布式消息队列来实现最终的一致性,或者基于TCC事务通过演进版本的二阶段提交,实现最终一致性,亦或者使用seata事务框架,他提供了多种事务模型,比如说AT,XA,Sage,TCC等不同的模型,提供的是强一致性或者弱一致性的一个支持,以上就是我对分布式事务的整体的理解。
#Spring Cloud Alibaba
##SpringCloud有哪些核心组件?(必会)
Eureka: 服务注册中心
Spring Cloud Config: 服务配置中心
Feign: 远程调用
Ribbon: 实现服务调用的负载均衡
Zuul: 网关
Hystrix: 熔断器
##市面上常用服务注册中心
市面上常用注册中心
Eureka——伊瑞卡(Netfix)
Nacos——内口四(Alibaba)
#Eureka注册中心工作原理--面试
1、注册
服务启动时会在注册中心进行注册
客户端每30秒拉取一次注册表,刷新本地缓存的注册表,
客户端每30秒向注册中心发送心跳包,注册中心连续三次没有检测到心跳包,会认为这个服务已不可用,删除它的注册信息
2、保护
由于网络中断,注册中心会出现心跳异常;
15分钟内,85%的服务出现心跳异常,会进入自我保护模式,所有的注册信息不删除,等待网络恢复
##Nacos (Nacos服务注册中心+Nacos服务配置中心)
##Nacos服务注册及健康状态如何检测/工作原理?
注册:服务启动时会在注册中心进行注册
客户端会每5秒注册中心发送心跳包,注册中心15秒内没有检测到心跳包会认为服务处于一种不健康状态,30秒内没有检测到心跳包会认为这个服务已不可用,删除它的注册信息
##项目中如何实现服务的调用?
1、基于RestTemplate对象进行调用
2、基于Feign进行服务调用
这两种方式在进行服务调用时,都可以借助Ribbon实现负载均衡。
#Sentinel 熔断限流
Sentinel是阿里推出的一个流量控制平台
什么是限流
(并发访问比较大的情况下,想对某个资源进行更好的保护,让这个资源能够持续的对外提供服务,不至于出现系统宕机的现象。--但限流不是限制所有的请求对这个资源的访问,有一部分请求是可以通过的)
为什么要限流,Sentinel 限流常用算法?
限流的目的是为了保证服务更加可靠的运行,不至于系统在遇到突发流量时,出现系统宕机的现象。
常用的限流算法 计划漏漏
有计数器法,滑动窗口算法,漏斗算法,漏桶算法等。
Sentinel的限流规则中默认有哪些限流模式?
(直连,关联,链路)---问过
何为降级/熔断?
(让外部应用停止对服务的访问,生活中跳闸,路障设置-此路不通————可以理解为暂时关闭不稳定的服务)
为什么要进行熔断呢?
(平均响应速度越来越慢或经常出现异常,这样可能会导致调用链堆积,最终系统崩溃————把某些服务暂时停掉,保证重要的业务能够持续对外提供服务) 面试
Sentinel熔断降级策略有哪些?
(慢调用比例、异常比例、异常数)
#Redis 缓存数据库 面试
##Redis是什么? 缓列布 事持集
Redis 是一个 Key-Value 结构的分布式缓存数据库,非关系型数据库;读写速度很快,
使用场景:一般会用来做缓存、消息队列,分布式锁,同时还支持事务 、持久化、集群等。
##Redis中的数据类型/数据结构/存储结构
string:以字符串形式存储数据,一个字符串类型的值能存储最大容量是512M
list:以列表形式存储数据,
set:以集合形式存储数据,
zset(sorted sets):有序集合,可对数据基于某个权重进行排序。
hash:以对象形式存储数据
##说说Redis对应的Java客户端有哪些?
Redis 支持的 Java 客户端都有jedis、lettuce、Redisson等。
##说说Redis内部存储结构?
dict 本质上是为了解决算法中的查找问题(Searching),是一个用于维护key和value映射关系的数据结构,与很多语言中的Map或dictionary类似。本质上是为了解决算法中的查找问题(Searching)
sds:就等同于char * ,它可以存储任意二进制数据,不能像C语言字符串那样以字符’\0’来标识字符串的结 束,因此它必然有个长度字段。
skiplist (跳跃表): 跳表是一种实现起来很简单,单层多指针的链表,它查找效率很高,堪比优化过的二叉平衡树,且比平衡树的实现,quicklist.
ziplist 压缩表:ziplist是一个编码后的列表,是由一系列特殊编码的连续内存块组成的顺序型数据结构。
##redis的持久化——高可靠性
1、什么是redis的持久化?
把内存中的数据同步到硬盘文件中,当Redis重启后再将硬盘文件重新加载到内存以达到数据恢复的目的
2、redis持久化方式?
RDB方式的持久化(redis的默认数据持久化方式):按照一定的时间周期策略把内存中的数据以快照的形式保存到硬盘的二进制文件。即快照存储,对应产生的数据文件为dump.rdb,通过配置文件中的save参数来定义快照的周期。
AOF方式的持久化:是通过记录操作日志的方式,记录redis数据,这个机制默认是关闭的。
AOF方式中的rewrite操作?
redis中的可以存储的数据是有限的,很多数据可能会自动过期,也可能会被用户删除或被redis用缓存清除的算法清理掉。也就是说redis中的数据会不断淘汰掉旧的,只有一部分常用的数据会被自动保留在redis内存中,所以可能很多之前的已经被清理掉的数据,对应的写日志还停留在AOF中,AOF日志文件就一个,会不断的膨胀,最后导致文件很大。
为了处理这种情况, Redis 引入了 AOF 重写:可以在不打断服务端处理请求的情况下, 对 AOF 文件进行重建(rebuild)
3、save(同步保存)或者bgsave(异步保存)有什么不同?
Redis Save 命令执行一个同步保存操作,将当前 Redis 实例的所有数据快照(snapshot)以 RDB 文件的形式保存到硬盘。
BGSAVE 命令执行之后立即返回 OK ,然后 Redis fork 出一个新子进程,原来的 Redis 进程(父进程)继续处理客户端请求,而子进程则负责将数据保存到磁盘,然后退出。
##redis的哨兵机制——高可用性
哨兵(Sentinel) 是 Redis 的高可用性解决方案。
由一个或多个 Sentinel 实例组成的 Sentinel 系统 可以监视任意多个主服务器,以及主服务器属下面的所有从服务器。
Sentinel 可以在被监视的主服务器进入下线状态时,自动将它的某个从服务器升级为新的主服务器,继续处理命令请求。
Redis的高可用如何保证/实现?
Redis的高可用主要从如下几个方面进行实现:
第一:数据的持久化(AOF,RDB)
第二:与哨兵机制结合实现负载均衡
第三:Redis集群高可用
#什么是高可用?
答:就算是在极端环境下,也可以正常提供服务,哪怕是网线坏了
如何实现高可用?
答:集群(集群中的一些服务器挂了,也可以继续提供服务)
##redis的主从复制
单个Redis支持的读写能力还是有限的,我们可以使用多个redis来提高redis的并发处理能力,这些redis根据一定的架构设计整合就叫主从复制
##Redis缓存穿透/缓存击穿
缓存穿透又称之为缓存击穿,一般的缓存系统,都是按照 key 去缓存查询对应的 value,找不到时,就会执行后端数据库查询。一些恶意的请求会故意多次查询不存在的 key,对后端系统造成很大的压力。这就叫 做缓存穿透。
如何避免?
1:对查询结果为空的情况也进行缓存,缓存时间设置短一点,或者该 key 对应的数据 insert 了之后清理 缓存。
2:对一定不存在的 key 进行过滤
##Redis缓存雪崩
当缓存服务器重启或者大量缓存集中在某一个时间段失效,造成瞬时 数据库请求量增大,压力骤增,导致系统崩溃
如何避免?
1:不同的 key,设置不同的过期时间,让缓存失效的时间点尽量均匀
2:在缓存失效后,通过加锁或者队列来控制读数据库写缓存的线程数量。比如对某个 key 只允许一个线 程查询数据和写缓存,其他线程等待。
3:做二级缓存,A1为原始缓存,A2为拷贝缓存,A1失效时,可以访问A2,A1缓存失效时间设置为短期,A2设置为长期
##Redis和MySQL如何保持数据一致性--面试
1、在高并发的业务场景下,数据库大多数情况都是用户并发访问最薄弱的环节。
2、所以,就需要使用redis做一个缓冲操作,让请求先访问到redis,而不是直接访问MySQL等数据库。
3、读取缓存步骤一般没有什么问题,但是一旦涉及到数据更新:数据库和缓存更新,就容易出现缓存(Redis)和数据库(MySQL)间的数据一致性问题。
实际项目中,无论是先操作数据库,还是先操作缓存,都会存在脏数据的情况;所以通常不会去保证缓存和数据库的强一致性,而是做出一定的牺牲,保证两者数据的最终一致性。如果是实在无法接受脏数据的场景,则比较合理的方式是放弃使用缓存,直接走数据库。
保证数据库和缓存数据最终一致性的常用方案如下:
1)更新数据库,数据库产生 binlog日志。
2)监听和消费 binlog,执行失效缓存操作。
3)如果步骤2失效缓存失败,则引入重试机制,将失败的数据通过MQ方式进行重试,同时考虑是否需要引入幂等机制。
##redis单线程模型
###单线程的redis为什么这么快/redis为什么是单线程的?
主要有以下几点:
1、基于内存的操作
2、使用了 I/O 多路复用模型,select、epoll 等,基于 reactor 模式开发了自己的网络事件处理器。
3、单线程可以避免不必要的上下文切换和竞争条件,减少了这方面的性能消耗。
4、以上这三点是 redis 性能高的主要原因,其他的还有一些小优化,例如:对数据结构进行了优化,简单动态字符串、压缩列表等。
1)纯内存操作
2)核心是基于非阻塞的IO多路复用机制
3)单线程反而避免了多线程的频繁上下文切换问题
当前任务在执行完 CPU 时间片切换到另一个任务之前会先保存自己的状态,以便下次再切换回这个任务时,可以再加载这个任务的状态。任务从保存到再加载的过程就是一次上下文切换。
##Redis的数据淘汰策略有哪些?
Redis 中默认提供 6 种数据淘汰策略,分别为:
volatile-lru:从已设置过期时间的数据集(server.db[i].expires)中挑选最近最少使用的数据淘汰
volatile-ttl:从已设置过期时间的数据集(server.db[i].expires)中挑选将要过期的数据淘汰
volatile-random:从已设置过期时间的数据集(server.db[i].expires)中任意选择数据淘汰
allkeys-lru:当内存不足以容纳新写入数据时,移除最近最少使用的 key(这个是最常用的)
allkeys-random:从数据集(server.db[i].dict)中任意选择数据淘汰。
no-eviction:禁止驱逐数据,也就是说当内存不足以容纳新写入数据时,新写入操作会报错。这个应该没人使用吧!
#什么是消息中间件/消息队列?
支持与保障分布式应用程序之间同步/异步收发消息的中间件
###使用过Redis做消息队列吗?
Redis 本身提供了一些组件来实现消息队列的功能,但是多多少少都存在一些缺点,相比于市面上成熟的消息队列,例如 Kafka、Rocket MQ 来说并没有优势,因此目前我们并没有使用 Redis 来做消息队列。
#消息中间件/消息队列 有哪些
RabbitMQ 每秒钟可以处理几万到十几万条消息。对消息堆积的处理并不好,当大量消息堆积 时,性能会急剧下降
RocketMQ 每秒钟可以处理记几十万条消息,大多数情况下可以做到毫秒级的响应。对在线 业务的响应时延做了很多优化
Kafka 性能最高,但当业务场景中每秒钟消息数量没有那么多时,时延反而会比较高,所以不 适合在线业务场景
1.为什么选择消息中间件 不选择多线程
不用担心消息丢失
#rpc负载均衡实现原理
首先需要有处理网络连接通讯的模块,负责连接建立、管理和消息的传输。其次需要有编
解码的模块,因为网络通讯都是传输的字节码,需要将我们使用的对象序列化和反序列
化。剩下的就是客户端和服务器端的部分,服务器端暴露要开放的服务接口,客户调用服
务接口的一个代理实现,这个代理实现负责收集数据、编码并传输给服务器然后等待结果
返回。