面试笔记(04)

1、 SpringCloud组件底层原理?

(1)服务发现——Netflix Eureka
Eureka Client:负责将这个服务的信息注册到 Eureka Server 中。
Eureka Server:注册中心,里面有一个注册表,保存了各个服务所在的机器和端口号。

(2)客服端负载均衡——Netflix Ribbon
Ribbon 的负载均衡策略:
1)随机 (Random)
2)轮询 (RoundRobin)
3)一致性哈希 (ConsistentHash)
4)哈希 (Hash)
5)加权(Weighted)
Ribbon 的负载均衡默认使用的最经典的 Round Robin 轮询算法。
首先 Ribbon 会从 Eureka Client 里获取到对应的服务注册表,也就知道了所有的服务都部署在了哪些机器上,在监听哪些端口号。然后 Ribbon 就可以使用默认的 Round Robin 算法,从中选择一台机器。Feign 就会针对这台机器,构造并发起请求。

(3)断路器——Netflix Hystrix
发起请求是通过 Hystrix 的线程池来走的,不同的服务走不同的线程池,实现了不同服务调用的隔离,避免了服务雪崩的问题。
Hystrix 是隔离、熔断以及降级的一个框架。

服务隔离:
1)业务之间不可互相影响,不同业务需要有独立的运行空间。
2)最彻底的,可以采用物理隔离,不同的机器部署在不同地方。
3)采用进程隔离,一个机器多个 Tomcat。
4)请求隔离。
5)由于 Hystrix 框架所属的层级为代码层,所以实现的是请求隔离,线程池或信号量。

服务熔断:
服务熔断的作用类似于我们家用的保险丝,当某服务出现不可用或响应超时的情况时,为了防止整个系统出现雪崩,暂时停止对该服务的调用。

服务降级:
服务降级是从整个系统的负荷情况出发和考虑的,对某些负荷会比较高的情况,为了预防某些功能(业务场景)出现负荷过载或者响应慢的情况,在其内部暂时舍弃对一些非核心的接口和数据的请求,而直接返回一个提前准备好的fallback(退路)错误处理信息。这样,虽然提供的是一个有损的服务,但却保证了整个系统的稳定性和可用性。

(4)服务网关——Netflix Zuul
Zuul,微服务网关,负责网络路由。
所有请求都往网关走,网关会根据请求中的一些特征,将请求转发给后端的各个服务。
而且有一个网关之后,还有很多好处,比如可以做统一的降级、限流、认证授权、安全,等等。

(5)分布式配置——Spring Cloud Config
Spring Cloud Config为分布式系统中的外部配置提供服务器和客户端支持。
Spring Cloud Config具有中心化、版本控制、支持动态更新和语言独立等特性。其特点是:
1)提供服务端和客户端支持(Spring Cloud Config Server和Spring Cloud Config Client);
2)集中式管理分布式环境下的应用配置;
3)基于Spring环境,实现了与Spring应用无缝集成;
4)可用于任何语言开发的程序;
5)默认实现基于Git仓库(也支持SVN),从而可以进行配置的版本管理。

(6)服务调用——Netflix Feign
基于 Feign 的动态代理机制,根据注解和选择的机器,拼接请求 URL 地址,发起请求。
首先,如果你对某个接口定义了 @FeignClient 注解,Feign 就会针对这个接口创建一个动态代理。
接着你要是调用那个接口,本质就是会调用 Feign 创建的动态代理,这是核心中的核心。
Feign的动态代理会根据你在接口上的 @RequestMapping 等注解,来动态构造出你要请求的服务的地址。
最后针对这个地址,发起请求、解析响应。

2、Eureka 自我保护机制

默认情况下,如果 Eureka Server 在一定的 90s 内没有接收到某个微服务实例的心跳,会注销该实例。但是在微服务架构下服务之间通常都是跨进程调用,网络通信往往会面临着各种问题,比如微服务状态正常,网络分区故障,导致此实例被注销。
固定时间内大量实例被注销,可能会严重威胁整个微服务架构的可用性。为了解决这个问题,Eureka 开发了自我保护机制,那么什么是自我保护机制呢?
Eureka Server 在运行期间会去统计心跳失败比例在 15 分钟之内是否低于 85%,如果低于 85%,Eureka Server 即会进入自我保护机制。

3、Consul、Eureka与Nacos的区别

Eureka
1)应用内/外:直接集成到应用中,依赖于应用自身完成服务的注册与发现。
2)ACP原则:遵循AP(可用性+分离容忍)原则,有较强的可用性,服务注册快,但牺牲了一定的一致性。
3)版本迭代:目前已经不进行升级。
4)集成支持:只支持SpringCloud集成。
5)访问协议:HTTP。
6)雪崩保护:支持雪崩保护。

Consul
1)应用内/外:属于外部应用,侵入性小。
2)ACP原则:遵循CP原则(一致性+分离容忍) 服务注册稍慢,由于其一致性导致了在Leader挂掉时重新选举期间真个consul不可用。
3)版本迭代:目前仍然进行版本迭代。
4)集成支持:支持SpringCloud、K8S集成。
5)访问协议:HTTP/DNS。
6)雪崩保护:不支持雪崩保护。

Nacos
1)应用内/外:属于外部应用,侵入性小。
2)ACP原则:通知遵循CP原则(一致性+分离容忍) 和AP原则(可用性+分离容忍)。
3)版本迭代:目前仍然进行版本迭代。
4)集成支持:支持Dubbo 、SpringCloud、K8S集成。
5)访问协议:HTTP/动态DNS/UDP。
6)雪崩保护:支持雪崩保护。

4、Feign远程调用的协议

Feign是一个http请求调用的轻量级框架,可以以Java接口注解的方式调用Http请求。Spring Cloud引入 Feign并且集成了Ribbon实现客户端负载均衡调用。Feign封装了Http调用流程,更适合面向接口化的变成习惯。
Feign远程调用流程图:
面试笔记(04)_第1张图片

5、SQL优化步骤

(1)通过show status命令了解各种SQL的执行频率。
(2)定位执行效率较低的SQL语句。
(3)通过EXPLAIN分析较低SQL的执行计划。
(4)通过show profile分析SQL。
(5)通过trace分析优化器如何选择执行计划。
(6)确定问题并采取相应的优化措施。

6、MySQL索引类型

物理存储角度
(1)聚集索引(clustered index)
(2)非聚集索引(non-clustered index)

逻辑角度
(1)主键索引:主键索引是一种特殊的唯一索引,不允许有空值
(2)普通索引或者单列索引
(3)多列索引(复合索引):复合索引指多个字段上创建的索引,只有在查询条件中使用了创建索引时的第一个字段,索引才会被使用。使用复合索引时遵循最左前缀集合
(4)唯一索引或者非唯一索引
(5)空间索引:空间索引是对空间数据类型的字段建立的索引,MYSQL中的空间数据类型有4种,分别是GEOMETRY、POINT、LINESTRING、POLYGON。MYSQL使用SPATIAL关键字进行扩展,使得能够用于创建正规索引类型的语法创建空间索引。创建空间索引的列,必须将其声明为NOT NULL,空间索引只能在存储引擎为MYISAM的表中创建。

全值匹配我最爱,最左前缀要遵守;
带头大哥不能死,中间兄弟不能断;
索引列上少计算,范围之后全失效;
LIKE百分写最右,覆盖索引不写星;
不等空值还有or,索引失效要少用。
解释说明:
全值匹配:全值匹配指的是和索引中的所有列进行匹配。
匹配最左前缀:在有多列索引的情况下,只使用索引的第一列。
匹配列前缀:可以只匹配某一列的值的开头部分。例如某个字符串以某个字母开头。
匹配范围值:在有多列索引的情况下,只使用索引的第一列匹配一定范围内的值。
精确匹配某一列并范围匹配另外一列:例如在某个多列索引表中,第一列全匹配,第二列范围匹配。
只访问索引的查询:即查询只需要访问索引,而无须访问数据行

7、聚簇索引与非聚簇索引的B+树有什么区别?

聚簇索引的叶子节点中保存着数据,InnoDB就是用聚簇索引的。
在聚簇索引的二级索引中,叶子节点保存着主键,所以在二级索引中查找时,先找到二级索引中的主键,在根据这个主键,从聚簇索引中找到该主键的数据,所以需要两次查找。

非聚簇索引就是说,叶子节点只是存着数据的地址,而不是数据本身。索引文件和数据文件两个文件是分开的。MyISAM就是采用非聚簇索引。
查找时,从上到下找到叶子节点,叶子节点保存着数据的地址,拿到这个地址后,就可以直接到磁盘中找了。

8、建立一个主键索引,一个复合索引有几颗B+树?

两颗B+树。

为什么B+树比B树更适合做索引?
 B树也是多叉树结构,一种自平衡的树,而且B+树是从B树演化而来的,那么为什么不使用B+树的前身B树呢?从结构比较来看,B树相比B+树的一个主要区别就在于B树的分支节点上存储着数据,而B+树的分支节点只是叶子节点的索引而已。根据这个差别可以得出以下结论:
(1)磁盘IO读写次数相比B树降低了
  在B+树中,其非叶子的内部节点都变成了key值,因此其内部节点相对B 树更小。如果把所有同一内部节点的key存放在同一盘块中,那么盘块所能容纳的key数量也越多。一次性读内存中的需要查找的key值也就越多。相对来说IO读写次数也就降低了。
(2)每次查询的时间复杂度是固定的
  在B+树中,由于分支节点只是叶子节点的索引,所以对于任意关键字的查找都必须从根节点走到分支节点,所有关键字查询路径长度相同,每次查询的时间复杂度是固定的。但是在B树中,其分支节点上也保存有数据,对于每一个数据的查询所走的路径长度是不一样的,所以查询效率也不一样。
(3)遍历效率更高
  由于B+树的数据都存储在叶子节点上,分支节点均为索引,方便扫库,只需扫一遍叶子即可。但是B树在分支节点上都保存着数据,要找到具体的顺序数据,需要执行一次中序遍历来查找。所以B+树更加适合范围查询的情况,在解决磁盘IO性能的同时解决了B树元素遍历效率低下的问题。

9、MySQL数据如何存储到磁盘?

https://my.oschina.net/u/1859679/blog/1581379

10、缓存击穿,缓存穿透,缓存雪崩

(1)缓存处理流程
前台请求,后台先从缓存中取数据,取到直接返回结果,取不到时从数据库中取,数据库取到更新缓存,并返回结果,数据库也没取到,那直接返回空结果。

(2)缓存穿透
描述:缓存穿透是指缓存和数据库中都没有的数据,而用户不断发起请求,如发起为id为“-1”的数据或id为特别大不存在的数据。这时的用户很可能是攻击者,攻击会导致数据库压力过大。
解决方案:
接口层增加校验,如用户鉴权校验,id做基础校验,id<=0的直接拦截;
从缓存取不到的数据,在数据库中也没有取到,这时也可以将key-value对写为key-null,缓存有效时间可以设置短点,如30秒(设置太长会导致正常情况也没法使用)。这样可以防止攻击用户反复用同一个id暴力攻击。

(3)缓存击穿
描述:缓存击穿是指缓存中没有但数据库中有的数据(一般是缓存时间到期),这时由于并发用户特别多,同时读缓存没读到数据,又同时去数据库去取数据,引起数据库压力瞬间增大,造成过大压力
解决方案:
设置热点数据永远不过期。
加互斥锁。

(4)缓存雪崩
描述: 缓存雪崩是指缓存中数据大批量到过期时间,而查询数据量巨大,引起数据库压力过大甚至down机。和缓存击穿不同的是,缓存击穿指并发查同一条数据,缓存雪崩是不同数据都过期了,很多数据都查不到从而查数据库。
解决方案:
缓存数据的过期时间设置随机,防止同一时间大量数据过期现象发生。
如果缓存数据库是分布式部署,将热点数据均匀分布在不同搞得缓存数据库中。
设置热点数据永远不过期。

11、redis版本3.0,ES版本 6.8.4

12、Dubbo与SprinCloud

面试笔记(04)_第2张图片

13、Dubbo协议类型

(1)dubbo 协议 (默认)
(2)rmi 协议
(3)hessian 协议
(4)http 协议
(5)webservice 协议
(6)thrift 协议
(7)memcached 协议
(8)redis 协议
(9)rest ( 就是 RestFull)

14、Dubbo服务端设置超时时间,客户端设置超时时间,最后会以哪个时间为准

dubbo在服务端和消费端都可以设置接口的超时时间,如果同一个接口,两端都进行了设置,消费端的优先级要高于消费端。
dubbo中的超时时间也是在调用端进行设置,当配置中心把某个接口的服务端列表推送给dubbo后,dubbo就会生成相应的调用代理,这是超时时间也会设置进来,但是这时,会用客户端去覆盖服务端的设置。

15、Dubbo中的SPI 机制

SPI,全称为 Service Provider Interface,是一种服务发现机制。它通过在ClassPath路径下的META-INF/services文件夹查找文件,自动加载文件里所定义的类。
SPI 的本质是将接口实现类的全限定名配置在文件中,并由服务加载器读取配置文件,加载实现类。这样可以在运行时,动态为接口替换实现类。正因此特性,我们可以很容易的通过 SPI 机制为我们的程序提供拓展功能。SPI 机制在第三方框架中也有所应用,比如 Dubbo 就是通过 SPI 机制加载所有的组件。不过,Dubbo 并未使用 Java 原生的 SPI 机制,而是对其进行了增强,使其能够更好的满足需求。在 Dubbo 中,SPI 是一个非常重要的模块。基于 SPI,我们可以很容易的对 Dubbo 进行拓展。如果大家想要学习 Dubbo 的源码,SPI 机制务必弄懂。

16、RabbitMQ持久化机制

队列和交换机有一个创建时候指定的标志durable。durable的唯一含义就是具有这个标志的队列和交换机会在重启之后重新建立,它不表示说在队列当中的消息会在重启后恢复。
消息队列持久化包括3个部分:
(1)exchange持久化,在声明时指定durable => true
(2)queue持久化,在声明时指定durable => true
(3)消息持久化,在投递时指定delivery_mode=> 2(1是非持久化)
如果exchange和queue都是持久化的,那么它们之间的binding也是持久化的。如果exchange和queue两者之间有一个持久化,一个非持久化,就不允许建立绑定。

17、CopyOnWriteArrayList和CopyOnWriteArraySet的底层实现原理

CopyOnWrite容器即写时复制的容器。通俗的理解是当往一个容器添加元素的时候,不直接往当前容器添加,而是先将当前容器进行Copy,复制出一个新的容器,然后新的容器里添加元素,添加完元素之后,再将原容器的引用指向新的容器。这样做的好处是可以对CopyOnWrite容器进行并发的读,而不需要加锁,因为当前容器不会添加任何元素。所以CopyOnWrite容器也是一种读写分离的思想,读和写不同的容器。
CopyOnWriteArrayList就是复制一个数组,对复制后产生的新数组进行操作,而旧的数组不会有影响,所以旧的数组可以依旧就行读取(可以看出来,读的时候如果有新的数据正在写是无法实时的读取到的,有延时,得等新数据写完以后,然后才可以读到新的数据)
CopyOnWriteArraySet其底层是基于CopyOnWriteArrayList实现。

18、volatile关键字,可见性,禁止指令重排序

19、CAS底层如何实现

CAS的全称为Compare-And-Swap ,它是一条CPU并发原语。它的功能是判断内存某个位置的值是否为预期值,如果是则更新为新的值,这个过程是原子的。
CAS并发原语提现在Java语言中就是sun.miscUnSafe类中的各个方法。调用UnSafe类中的CAS方法,JVM会帮我实现CAS汇编指令.这是一种完全依赖于硬件 功能,通过它实现了原子操作。再次强调,由于CAS是一种系统原语,原语属于操作系统用于范畴,是由若干条指令组成,用于完成某个功能的一个过程,并且原语的执行必须是连续的,在执行过程中不允许中断,也即是说CAS是一条原子指令,不会造成所谓的数据不一致的问题。
在Java发展初期,java语言是不能够利用硬件提供的这些便利来提升系统的性能的。而随着java不断的发展,Java本地方法(JNI或JNA)的出现,使得java程序越过JVM直接调用本地方法提供了一种便捷的方式,因而java在并发的手段上也多了起来。而在Doug Lea提供的cucurenct包中,CAS理论是它实现整个java包的基石。
CAS 操作包含三个操作数 —— 内存位置(V)、预期原值(A)和新值(B)。 如果内存位置的值与预期原值相匹配,那么处理器会自动将该位置值更新为新值 。否则,处理器不做任何操作。无论哪种情况,它都会在 CAS 指令之前返回该 位置的值。(在 CAS 的一些特殊情况下将仅返回 CAS 是否成功,而不提取当前 值。)CAS 有效地说明了“我认为位置 V 应该包含值 A;如果包含该值,则将 B 放到这个位置;否则,不要更改该位置,只告诉我这个位置现在的值即可。”
通常将 CAS 用于同步的方式是从地址 V 读取值 A,执行多步计算来获得新 值 B,然后使用 CAS 将 V 的值从 A 改为 B。如果 V 处的值尚未同时更改,则 CAS 操作成功。
类似于 CAS 的指令允许算法执行读-修改-写操作,而无需害怕其他线程同时 修改变量,因为如果其他线程修改变量,那么 CAS 会检测它(并失败),算法 可以对该操作重新计算。

20、Hashmap是否线程安全

不安全

https://blog.csdn.net/u010416101/article/details/88727204

21、ConcurrentHashMap原理

面试笔记(04)_第3张图片

ConcurrentHashMap是由Segment数组结构和HashEntry数组结构组成。Segment是一种可重入锁ReentrantLock,在ConcurrentHashMap里扮演锁的角色,HashEntry则用于存储键值对数据。一个ConcurrentHashMap里包含一个Segment数组,Segment的结构和HashMap类似,是一种数组和链表结构, 一个Segment里包含一个HashEntry数组,每个HashEntry是一个链表结构的元素, 每个Segment守护者一个HashEntry数组里的元素,当对HashEntry数组的数据进行修改时,必须首先获得它对应的Segment锁。

22、Hashmap在那些情况下会发生线程不安全

HashMap的线程不安全主要体现如下:
(1)在JDK1.7中,当并发执行put操作时,会造成数据丢失,并发扩容操作时会造成死循环的情况。
(2)在JDK1.8中,当并发执行put操作时,也会造成数据丢失,但不会形成环形链表,所以不会出现死循环情况。

23、 SpringCloudGateway原理

面试笔记(04)_第4张图片

24、SpringCloud搭建步骤

面试笔记(04)_第5张图片

25、消息队列如何避免重复消费?

(1)利用数据库唯一约束实现幂等
(2)设置前置条件(加版本号)
(3)通过全局ID实现
(4)手动确认模式

你可能感兴趣的:(Java面试题,数据库,网络,队列,分布式,redis)