白云阳光 發表於 2025-11-21 09:00:00

SpringCloud 常见面试题(二)

<h2 id="配置中心">配置中心</h2>
<h3 id="什么是配置中心有哪些常见的配置中心">什么是配置中心?有哪些常见的配置中心?</h3>
<p>配置中心是一个用于配置集中化管理目支持动态更新、分发配置文件的工具(服务)。</p>
<p>它实现了配置的统一管理和动态同新,当配置信息发生变化时,配置中心可以自动通知服务实例进行配置更新,这样就可以实例无需重启即可应用最新的配置,从一定程度上减少了系统访问的空窗期,非常灵活方便</p>
<p>常见的配置中心:</p>
<ul>
<li>Spring Cloud Config:Spring 提供的分布式配置管理工具,支持从 Git、SVN 等版本控制系统加载配置</li>
<li>Apollo:由携程开源的配置管理中心,支持配置的实时推送和权限管理。</li>
<li>Nacos:阿里巴巴的配置管理和服务发现工具,既支持配置中心功能,又能作为注册中心使用。</li>
<li>Consul:HashiCorp 提供的分布式系统管理工具,既可以用作服务发现,也可以用于存储和分发配置</li>
<li>Etcd:分布式键值存储工具,常用于 Kubernetes 集群中的配置管理。</li>
<li>Zookeeper:Zookeeper 是一个开源的分布式协调服务,和 Nacos 一样,其既可以作为注册中心,又可以作为配置中心。</li>
</ul>
<h3 id="为什么微服务需要配置中心">为什么微服务需要配置中心?</h3>
<p>微服务架构中的每个服务通常都需要一些配置信息,例如数据库连接地址、服务端口、日志级别等。这些配置可能因为不同环境、不同部署实例或者动态运行时需要进行调整和管理。</p>
<p>微服务的实例一般非常多,如果每个实例都需要一个个地去做这些配置,那么运维成本将会非常大,这时候就需要一个集中化的配置中心,去管理这些配置。</p>
<h3 id="springcloud可以选择哪些配置中心">SpringCloud可以选择哪些配置中心?</h3>
<p>和注册中心一样,SpringCloud也支持对多种配置中心的集成。常见的配置中心选型包括:</p>
<ul>
<li>Spring Cloud Config:官方推荐的配置中心,支持将配置文件存储在Git、SVN等版本控制系统中,并提供RESTful API进行访问和管理。</li>
<li>ZooKeeper:一个开源的分布式协调服务,可以用作配置中心。它具有高可用性、一致性和通知机制等特性。</li>
<li>Consul:另一个开源的分布式服务发现和配置管理工具,也可用作配置中心。支持多种配置文件格式,提供健康检查、故障转移和动态变更等功能。</li>
<li>Etcd:一个分布式键值存储系统,可用作配置中心。它使用基于Raft算法的一致性机制,提供分布式数据一致性保证。</li>
<li>Apollo:携程开源的配置中心,支持多种语言和框架。提供细粒度的配置权限管理、配置变更通知和灰度发布等高级特性,还有可视化的配置管理界面。</li>
<li>Nacos:阿里巴巴开源的服务发现、配置管理和服务管理平台,也可以作为配置中心使用。支持服务注册与发现、动态配置管理、服务健康监测和动态DNS服务等功能。</li>
</ul>
<h3 id="nacos配置中心的原理了解吗">Nacos配置中心的原理了解吗?</h3>
<p>配置中心,说白了就是一句话:配置信息的CRUD。</p>
<p><img src="https://seven97-blog.oss-cn-hangzhou.aliyuncs.com/imgs/202501051334257.png" alt="" loading="lazy"></p>
<p>具体的实现大概可以分成这么几个部分:</p>
<ol>
<li>配置信息存储:Nacos默认使用内嵌数据库Derby来存储配置信息,还可以采用MySQL等关系型数据库。</li>
<li>注册配置信息:服务启动时,Nacos Client会向Nacos Server注册自己的配置信息,这个注册过程就是把配置信息写入存储,并生成版本号。</li>
<li>获取配置信息:服务运行期间,Nacos Client通过API从Nacos Server获取配置信息。Server根据键查找对应的配置信息,并返回给Client。</li>
<li>监听配置变化:Nacos Client可以通过注册监听器的方式,实现对配置信息的监听。当配置信息发生变化时,Nacos Server会通知已注册的监听器,并触发相应的回调方法。</li>
</ol>
<h3 id="nacos配置中心长轮询机制">Nacos配置中心长轮询机制?</h3>
<p>一般来说客户端和服务端的交互分为两种:推(Push)和拉(Pull),Nacos在<strong>Pull的基础上,采用了长轮询来进行配置的动态刷新</strong>。详情可以看这篇文章Nacos交互模型</p>
<p>在长轮询模式下,客户端定时向服务端发起请求,检查配置信息是否发生变更。如果没有变更,服务端会"hold"住这个请求,即暂时不返回结果,直到配置发生变化或达到一定的超时时间。</p>
<p>具体的实现过程如下:</p>
<p><img src="https://seven97-blog.oss-cn-hangzhou.aliyuncs.com/imgs/202501051337892.png" alt="" loading="lazy"></p>
<p><img src="https://seven97-blog.oss-cn-hangzhou.aliyuncs.com/imgs/202501051340300.png" alt="" loading="lazy"></p>
<p>如果客户端发起 Pull 请求,服务端收到请求之后,先检查配置是否发生了变更:</p>
<ul>
<li>变更:返回变更配置;</li>
<li>无变更:设置一个定时任务,延期 29.5s 执行,把当前的客户端长轮询连接加入 allSubs 队列;</li>
</ul>
<p>在这 29.5s 内的配置变化:</p>
<ul>
<li>配置无变化:等待 29.5s 后触发自动检查机制,返回配置;</li>
<li>配置变化:在 29.5s 内任意一个时刻配置变化,会触发一个事件机制,监听到该事件的任务会遍历 allSubs 队列,找到发生变更的配置项对应的 ClientLongPolling 任务,将变更的数据通过该任务中的连接进行返回。相当于完成了一次 PUSH 操作;</li>
</ul>
<p>长轮询机制结合了 Pull 机制和 Push 机制的优点; 通过长轮询的方式,Nacos客户端能够实时感知配置的变化,并及时获取最新的配置信息。同时,这种方式也降低了服务端的压力,避免了大量的长连接占用内存资源。</p>
<h3 id="nacos的服务注册表结构是怎样的">Nacos的服务注册表结构是怎样的?</h3>
<p>Nacos采用了数据的分级存储模型,最外层是Namespace,用来隔离环境。然后是Group,用来对服务分组。接下来就是服务(Service)了,一个服务包含多个实例,但是可能处于不同机房,因此Service下有多个集群(Cluster),Cluster下是不同的实例(Instance)。</p>
<p>对应到Java代码中,Nacos采用了一个多层的Map来表示。结构为<code>Map&lt;String, Map&lt;String, Service&gt;&gt;</code>,其中最外层Map的key就是namespaceId,值是一个Map。内层Map的key是group拼接serviceName,值是Service对象。Service对象内部又是一个Map,key是集群名称,值是Cluster对象。而Cluster对象内部维护了Instance的集合。</p>
<h3 id="nacos中的namespace是什么如何使用它来组织和管理微服务">Nacos中的Namespace是什么?如何使用它来组织和管理微服务</h3>
<p>Nacos中的Namespace是用于隔离不同环境或应用之间的配置和服务信息的概念。通过使用Namespace,可以将不同的环境(例如开发、测试和生产)或不同的应用程序(例如Web应用和移动应用)的配置和服务信息分离开来,以避免冲突和错误。</p>
<p>在Nacos中,每个Namespace都有自己独立的配置和服务注册表。这意味着,如果有多个应用程序需要使用Nacos,可以将它们分别放置在不同的Namespace中。每个Namespace都有自己的命名空间ID,用于标识该Namespace。要使用Namespace,在Nacos客户端初始化时,需要指定要使用的Namespace ID。</p>
<p>通过使用Namespace,可以对不同Namespace下的服务进行分组和管理,例如可以使用Nacos提供的Group功能对同一Namespace下的服务进行分组,方便管理和查找。同时,使用Namespace还可以对不同环境下的配置进行隔离,避免不同环境之间的配置冲突。</p>
<h3 id="springcloud-config-是什么">SpringCloud Config 是什么?</h3>
<p>SpringCloud Config 为分布式系统外部化配置提供了服务端以及客户端的支持,简单来说就是一个配置中心,其主要包括以下两个部分的内容:Config Sever和 Config Cient 。</p>
<ul>
<li>ConfigServer是一个可横向扩展,并且集中式配置的服务器,主要用于集中管理服务各种环境下的配置,然后默认使用 Git进行存储配置的内容,因此可以很方便地实现配置的版本控制</li>
<li>Config Client 是 Config Server 的客户端,主要用于操作存储在 Config Server 中的配置信息。</li>
</ul>
<h2 id="远程调用">远程调用</h2>
<h3 id="说说微服务之间是如何独立通讯的">说说微服务之间是如何独立通讯的?</h3>
<p><strong>远程过程调用(Remote Procedure Invocation)</strong></p>
<p>也就是我们常说的服务的注册与发现,直接通过远程过程调用来访问别的service。</p>
<p><strong>优点</strong>:简单,常见,因为没有中间件代理,系统更简单</p>
<p><strong>缺点</strong>:只支持请求/响应的模式,不支持别的,比如通知、请求/异步响应、发布/订阅、发布/异步响应,降低了可用性,因为客户端和服务端在请求过程中必须都是可用的。</p>
<p><strong>消息</strong></p>
<p>使用异步消息来做服务间通信。服务间通过消息管道来交换消息,从而通信。</p>
<p><strong>优点</strong>:把客户端和服务端解耦,更松耦合,提高可用性,因为消息中间件缓存了消息,直到消费者可以消费,    支持很多通信机制比如通知、请求/异步响应、发布/订阅、发布/异步响应。</p>
<p><strong>缺点</strong>:消息中间件有额外的复杂。</p>
<h3 id="说说-rpc-的实现原理">说说 RPC 的实现原理</h3>
<p>首先需要有处理网络连接通讯的模块,负责连接建立、管理和消息的传输。其次需要有编 解码的模块,因为网络通讯都是传输的字节码,需要将我们使用的对象序列化和反序列化。剩下的就是客户端和服务器端的部分,服务器端暴露要开放的服务接口,客户调用服 务接口的一个代理实现,这个代理实现负责收集数据、编码并传输给服务器然后等待结果返回。</p>
<h3 id="能说下http和rpc的区别吗">能说下HTTP和RPC的区别吗?</h3>
<p>严格来讲,HTTP和RPC不是一个层面的东西:</p>
<ul>
<li>HTTP(Hypertext Transfer Protocol)是一种应用层协议,主要强调的是网络通信;</li>
<li>RPC(Remote Procedure Call,远程过程调用)是一种用于分布式系统之间通信的协议,强调的是服务之间的远程调用。</li>
</ul>
<p>一些RPC框架比如gRPC,底层传输协议其实也是用的HTTP2,包括Dubbo3,也兼容了gRPC,使用了HTTP2作为传输层的一层协议。</p>
<p>如果硬要说区别的话,如下:</p>
<table>
<thead>
<tr>
<th></th>
<th>HTTP</th>
<th>RPC</th>
</tr>
</thead>
<tbody>
<tr>
<td>定义</td>
<td>HTTP(超文本传输协议)是一种用于传输超文本的协议。</td>
<td>RPC(远程过程调用)是一种用于实现分布式系统中不同节点之间通信的协议。</td>
</tr>
<tr>
<td>通信方式</td>
<td>基于请求-响应模型,客户端发送请求,服务器返回响应。</td>
<td>基于方法调用模型,客户端调用远程方法并等待结果。</td>
</tr>
<tr>
<td>传输协议</td>
<td>基于TCP协议,可使用其他传输层协议如TLS/SSL进行安全加密。</td>
<td>可以使用多种传输协议,如TCP、UDP等。</td>
</tr>
<tr>
<td>数据格式</td>
<td>基于文本,常用的数据格式有JSON、XML等。</td>
<td>可以使用各种数据格式,如二进制、JSON、Protocol Buffers等。</td>
</tr>
<tr>
<td>接口定义</td>
<td>使用RESTful风格的接口进行定义,常用的方法有GET、POST、PUT、DELETE等。</td>
<td>使用IDL(接口定义语言)进行接口定义,如Protocol Buffers、Thrift等。</td>
</tr>
<tr>
<td>跨语言性</td>
<td>支持跨语言通信,可以使用HTTP作为通信协议实现不同语言之间的通信。</td>
<td>支持跨语言通信,可以使用IDL生成不同语言的客户端和服务端代码。</td>
</tr>
<tr>
<td>灵活性</td>
<td>更加灵活,适用于不同类型的应用场景,如Web开发、API调用等。</td>
<td>更加高效,适用于需要高性能和低延迟的分布式系统。</td>
</tr>
</tbody>
</table>
<p>在微服务体系里,基于HTTP风格的远程调用通常使用框架如Feign来实现,基于RPC的远程调用通常使用框架如Dubbo来实现。</p>
<h3 id="那feign和dubbo的区别呢">那Feign和Dubbo的区别呢?</h3>
<p>这两个才是适合拿来比较的东西:</p>
<table>
<thead>
<tr>
<th></th>
<th>Feign</th>
<th>Dubbo</th>
</tr>
</thead>
<tbody>
<tr>
<td>定义</td>
<td>Feign是一个声明式的Web服务客户端,用于简化HTTP API的调用。</td>
<td>Dubbo是一个分布式服务框架,用于构建面向服务的微服务架构。</td>
</tr>
<tr>
<td>通信方式</td>
<td>基于HTTP协议,使用RESTful风格的接口进行定义和调用。</td>
<td>基于RPC协议,支持多种序列化协议如gRPC、Hessian等。</td>
</tr>
<tr>
<td>服务发现</td>
<td>通常结合服务注册中心(如Eureka、Consul)进行服务发现和负载均衡。</td>
<td>通过ZooKeeper、Nacos等进行服务注册和发现,并提供负载均衡功能。</td>
</tr>
<tr>
<td>服务治理</td>
<td>不直接提供服务治理功能,需要结合其他组件或框架进行服务治理。</td>
<td>提供服务注册与发现、负载均衡、容错机制、服务降级等服务治理功能。</td>
</tr>
<tr>
<td>跨语言性</td>
<td>支持跨语言通信,可以使用HTTP作为通信协议实现不同语言之间的通信。</td>
<td>支持跨语言通信,通过Dubbo的IDL生成不同语言的客户端和服务端代码。</td>
</tr>
<tr>
<td>生态系统</td>
<td>集成了Spring Cloud生态系统,与Spring Boot无缝集成。</td>
<td>拥有完整的生态系统,包括注册中心、配置中心、监控中心等组件。</td>
</tr>
<tr>
<td>适用场景</td>
<td>适用于构建RESTful风格的微服务架构,特别适合基于HTTP的微服务调用。</td>
<td>适用于构建面向服务的微服务架构,提供更全面的服务治理和容错机制。</td>
</tr>
</tbody>
</table>
<p>需要注意的是,Feign和Dubbo并不是互斥的关系。实际上,Dubbo可以使用HTTP协议作为通信方式,而Feign也可以集成RPC协议进行远程调用。选择使用哪种远程调用方式取决于具体的业务需求和技术栈的选择。</p>
<h3 id="负载均衡的意义什么">负载均衡的意义什么?</h3>
<p>在计算中,负载均衡可以改善跨计算机,计算机集群,网络链接,中央处理单元或磁盘驱动器等多种计算资源的工作负载分布。</p>
<p>负载均衡旨在优化资源使用,最大化吞吐量,最小化响应时间并避免任何单一资源 的过载。使用多个组件进行负载均衡可而不是单个组件可能会通过冗余来提高可靠性和可用性。负载均衡可通常涉及专用软件或硬件,例如多层交换机或域名系统服务器进程。</p>
<h3 id="集中式与进程内负载均衡的区别">集中式与进程内负载均衡的区别</h3>
<p>目前业界主流的负载均衡方案可分成两类:</p>
<ol>
<li>集中式负载均衡, 即在 consumer 和 provider 之间使用独立的负载均衡设施(可以是硬件,如F5, 也可以是软件,如 Nginx), 由该设施负责把 访问请求 通过某种策略转发至 provider;</li>
<li>进程内负载均衡,将负载均衡逻辑集成到 consumer,consumer 从服务注册中心获知有哪些地址可用,然后自己再从这些地址中选择出一个合适的 provider。Ribbon 就属于后者,它只是一个类库,集成于 consumer 进程,consumer 通过它来获取到 provider 的地址。</li>
</ol>
<p><img src="https://seven97-blog.oss-cn-hangzhou.aliyuncs.com/imgs/202501011128525.png" alt="" loading="lazy"></p>
<h3 id="说说有哪些负载均衡算法">说说有哪些负载均衡算法?</h3>
<p>常见的负载均衡算法包含以下几种:</p>
<table>
<thead>
<tr>
<th><strong>内置负载均衡规则类</strong></th>
<th><strong>规则描述</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>RoundRobinRule</td>
<td>简单轮询服务列表来选择服务器。它是Ribbon默认的负载均衡规则。</td>
</tr>
<tr>
<td>AvailabilityFilteringRule</td>
<td>对以下两种服务器进行忽略:   <br>(1)在默认情况下,这台服务器如果3次连接失败,这台服务器就会被设置为“短路”状态。短路状态将持续30秒,如果再次连接失败,短路的持续时间就会几何级地增加。<br>(2)并发数过高的服务器。如果一个服务器的并发连接数过高,配置了AvailabilityFilteringRule规则的客户端也会将其忽略。并发连接数的上限,可以由客户端的<code>&lt;clientName&gt;.&lt;clientConfigNameSpace&gt;.ActiveConnectionsLimit</code>属性进行配置。</td>
</tr>
<tr>
<td>WeightedResponseTimeRule</td>
<td>为每一个服务器赋予一个权重值。服务器响应时间越长,这个服务器的权重就越小。这个规则会随机选择服务器,这个权重值会影响服务器的选择。</td>
</tr>
<tr>
<td><strong>ZoneAvoidanceRule</strong></td>
<td>以区域可用的服务器为基础进行服务器的选择。使用Zone对服务器进行分类,这个Zone可以理解为一个机房、一个机架等。而后再对Zone内的多个服务做轮询。</td>
</tr>
<tr>
<td>BestAvailableRule</td>
<td>忽略那些短路的服务器,并选择并发数较低的服务器。</td>
</tr>
<tr>
<td>RandomRule</td>
<td>随机选择一个可用的服务器。</td>
</tr>
<tr>
<td>RetryRule</td>
<td>重试机制的选择逻辑</td>
</tr>
</tbody>
</table>
<ul>
<li>轮询算法(Round Robin):轮询算法是最简单的负载均衡算法之一。它按照顺序将请求依次分配给每个后端服务器,循环往复。当请求到达时,负载均衡器按照事先定义的顺序选择下一个服务器。轮询算法适用于后端服务器具有相同的处理能力和性能的场景。</li>
<li>加权轮询算法(Weighted Round Robin):加权轮询算法在轮询算法的基础上增加了权重的概念。每个后端服务器都被赋予一个权重值,权重值越高,被选中的概率就越大。这样可以根据服务器的处理能力和性能调整请求的分配比例,使得性能较高的服务器能够处理更多的请求。</li>
<li>随机算法(Random):随机算法将请求随机分配给后端服务器。每个后端服务器有相等的被选中概率,没有考虑服务器的实际负载情况。这种算法简单快速,适用于后端服务器性能相近且无需考虑请求处理能力的场景。</li>
<li>加权随机算法(Weighted Random):加权随机算法在随机算法的基础上引入了权重的概念。每个后端服务器被赋予一个权重值,权重值越高,被选中的概率就越大。这样可以根据服务器的处理能力和性能调整请求的分配比例。</li>
<li>最少连接算法(Least Connection):最少连接算法会根据后端服务器当前的连接数来决定请求的分配。负载均衡器会选择当前连接数最少的服务器进行请求分配,以保证后端服务器的负载均衡。这种算法适用于后端服务器的处理能力不同或者请求的处理时间不同的场景。</li>
<li>哈希算法(Hash):哈希算法会根据请求的某个特定属性(如客户端IP地址、请求URL等)计算哈希值,然后根据哈希值选择相应的后端服务器。</li>
</ul>
<p>常见的负载均衡器,比如Ribbion、Gateway等等,基本都支持这些负载均衡算法。</p>
<h3 id="可以用几行代码实现一个负载均衡器吗">可以用几行代码实现一个负载均衡器吗?</h3>
<blockquote>
<p>不要题目吓到,这类题目不会让你实现一个完整的可以运行的系统,仅用几行代码突出其核心思想即可</p>
</blockquote>
<p>可以,例如可以用常见的轮询(Round Robin)的方式来分发请求。核心就是维护一个服务器列表和当前下标,每次请求返回一个不同的服务器</p>
<pre><code class="language-java">List&lt;String&gt; servers = List.of("A", "B", "C");
AtomicInteger index = new AtomicInteger(0);

public String getServer() {
    return servers.get(index.getAndIncrement() % servers.size());
}
</code></pre>
<p>Atomiclnteger 用来保证在多线程环境下也能安全地自增,不会出现重复或跳号的情况。</p>
<p>轮询的优点是实现简单、平均分配,缺点是不考虑服务器实际负载,所有机器一视同仁。</p>
<h3 id="什么是ribbon">什么是Ribbon?</h3>
<p>ribbon是一个负载均衡客户端,可以很好地控制htt和tcp的一些行为。<code>feign默认集成了ribbon</code>。</p>
<h3 id="什么是-feign它的优点是什么">什么是 Feign?它的优点是什么?</h3>
<p>Feign 是一个声明式的Web服务客户端。</p>
<p>所谓的声明式就是指不需要编写复杂的关于 Http 请求的东西。只需要声明一个一个接口,然后在这个接口上添加一些注解,这些注解包括了请求的方法(如GET和POST)、请求的URL等信息</p>
<p>Feign 在运行时通过注解和接口上定义的内容来动态构造和发送 Http 请求。所以使用 Feign,开发者只需要定义服务接口并通过注解指明服务名和参数等信息,Feign 就能自动完成 Http请求的构建、发送和结果处理</p>
<p>Feign 也是 Spring Cloud Netflix 组件之一,结合Spring Cloud 的服务注册和发现、负载均衡等功能,能够让服务间的调用变得更加方便</p>
<p>Feign 的主要特点有:</p>
<ul>
<li>声明式的服务客户端,通过 Java 接口和注解构建服务客户端,简化了 Http 调用的使用过程,无需手动构建 HTTP 请求</li>
<li>很好地融入了 SpringCloud 生态,可以使用 SpringCloud负载均衡、服务熔断等能力</li>
</ul>
<p>使用方式</p>
<ul>
<li>添加pom依赖。</li>
<li>启动类添加<code>@EnableFeignClients</code></li>
<li>定义一个接口<code>@FeignClient(name=“xxx”)</code>指定调用哪个服务</li>
</ul>
<h3 id="ribbon和feign的区别">Ribbon和Feign的区别?</h3>
<ol>
<li><strong>启动类注解不同</strong>,Ribbon是@RibbonClient feign的是@EnableFeignClients;</li>
<li><strong>服务指定的位置不同</strong>,Ribbon是在@RibbonClient注解上声明,Feign则是在定义抽象方法的接口中使用@FeignClient声明;</li>
<li><strong>调用方式不同</strong>,Ribbon需要自己构建http请求,模拟http请求。</li>
</ol>
<p>Ribbon是一个客户端负载均衡器,作用在于多个微服务实例间分发请求,提升可用性和性能。它可与各种HTTP客户端如RestTemplate配合使用来发送HTTP请求并进行负载均衡。</p>
<p>Feign则是一个声明式的HTTP客户端,通过编写接口来定义对远程微服务的需求。Feign使用注解和模板方法简化了远程调用的编写,使得调用远程服务的代码更加清晰和简洁。它更注重简洁的声明式编程模型,你只需编写接口并使用注解描述HTTP请求,Feign会在运行时生成实现类来执行实际的HTTP请求。</p>
<p>Ribbon更注重负载均衡,需要配合其他库如RestTemplate来发送http请求,而Feign则采用声明式编程模型,只需编写接口和注解即可。此外,Ribbon提供了自定义负载均衡策略的能力,而Feign通常与Ribbon一起使用以实现负载均衡。</p>
<h3 id="为什么feign第一次调用耗时很长">为什么Feign第一次调用耗时很长?</h3>
<p>主要原因是由于Ribbon的懒加载机制,当第一次调用发生时,Feign会触发Ribbon的加载过程,包括从服务注册中心获取服务列表、建立连接池等操作,这个加载过程会增加首次调用的耗时。</p>
<pre><code class="language-yml">ribbon:
        eager-load:
                enabled: true
                        clients: service-1
</code></pre>
<p>那怎么解决这个问题呢?</p>
<p>可以在应用启动时预热Feign客户端,自动触发一次无关紧要的调用,来提前加载Ribbon和其他相关组件。这样,就相当于提前进行了第一次调用。</p>
<h3 id="feign怎么实现认证传递">Feign怎么实现认证传递?</h3>
<p>比较常见的一个做法是,使用拦截器传递认证信息。可以通过实现RequestInterceptor接口来定义拦截器,在拦截器里,把认证信息添加到请求头中,然后将其注册到Feign的配置中。</p>
<pre><code class="language-java">@Configuration
public class FeignClientConfig {

        @Bean
        public RequestInterceptor requestInterceptor() {
                return new RequestInterceptor() {
                        @Override
                        public void apply(RequestTemplate template) {
                                // 添加认证信息到请求头中
                                template.header("Authorization", "Bearer " + getToken());
                        }
                };
        }
       
        private String getToken() {
                // 获取认证信息的逻辑,可以从SecurityContext或其他地方获取
                // 返回认证信息的字符串形式
                return "your_token";
        }
}
</code></pre>
<h3 id="fegin怎么做负载均衡ribbon">Fegin怎么做负载均衡?Ribbon?</h3>
<p>在Feign中,负载均衡是通过集成Ribbon来实现的。</p>
<p>Ribbon是Netflix开源的一个客户端负载均衡器,可以与Feign无缝集成,为Feign提供负载均衡的能力。</p>
<p>Ribbon在发起请求前,会从“服务中心”获取服务列表(清单),然后按照一定的负载均衡策略去发起请求,从而实现客户端的负载均衡。Ribbon本身也维护着“服务提供者”清单的有效性。如果它发现“服务提供者”不可用,则会重新从“服务中心”获取有效的“服务提供者”清单来及时更新。</p>
<p><img src="https://seven97-blog.oss-cn-hangzhou.aliyuncs.com/imgs/202501051350847.png" alt="" loading="lazy"></p>
<h3 id="feign-和-openfeign-的区别">Feign 和 OpenFeign 的区别?</h3>
<p>Feign 和 OpenFeign 都是用于简化服务之间的 HTTP 调用的工具,让我们可以更加方便地实现服务间的通信</p>
<p>Feign 最初是由 Netfix 开发的一个声明式, REST 客户端框架,它的目标是让微服务之间的调用像调用本地方法一样容易。如果我们想调用其它服务的接口,可以创建一个接口,然后通过注解声明所需要调用服务的方法和路径,Feign 可以自动发送 Http 请求和接收响应,转换为方法返回值</p>
<p>而 OpenFeign 是 Spring Cloud在 Feign 的基础上进一步封装的,它整合了 Spring Cloud 的特性,使得我们可以更加简单地使用 Feign,包括如下几个方面:</p>
<ul>
<li>自动配置:Openfeign利用Spring Boot的自动配置机制,通过@FeignClien和@EnableFeignClients 注解就可以创建一个 Feign 客户端,极大简化了Feign客户端的创建和配置过程。</li>
<li>负载均衡:与Spring Cloud等服务发现组件集成,可以轻松实现客户端负载均衡</li>
<li>Hystrix集成:只需要简单的配置就可以快速集成Hystrix,提高系统的容错性</li>
</ul>
<h2 id="服务容灾">服务容灾</h2>
<h3 id="什么是熔断器为什么需要熔断器">什么是熔断器?为什么需要熔断器?</h3>
<p>在微服务架构中,服务之间的调用关系会形成调用链路,链路中的任何一个服务都可能出现超时或者宕机的情况,而在微服务系统中,如果调用失败的话可能会引起大面积的服务瘫痪,即形成“服务雪崩”的情况,这样的话对于服务的影响是巨大的。</p>
<p>熔断器就是为了来解决这个问题,避免服务雪崩情况的发生。</p>
<p>熔断器的基本原理如下:</p>
<ul>
<li>正常情况下,熔断器处于关闭状态,服务消费者正常请求微服务中的服务提供者。</li>
<li>当发生了服务调用清求失败的时候,并且达到了一定比例,比如70% 的清求发生了失败,或者失败的清求次数达到了10等等,这个时候熔断器打开,此时将服务调用者不再发起服务调用请求,这种方法是一种快速失败的方法,也称为熔断方法。</li>
<li>熔断器启用一段时间时候,自动进入“半关闭状态”,这个时候熔断器允许服务调用者发起一个请求给服务提供者,如果请求调用成功了,关闭熔断器,反之继续打开熔断器,循环往复。</li>
</ul>
<p>这种方式在服务发生意外的时候,可以实现服务错误的隔离,避免了服务错误导致了系统的整体不可用,这样保证了系统即使出现了局部问题也不会发生服务雪崩的情况。</p>
<h3 id="什么是服务雪崩">什么是服务雪崩?</h3>
<p>在微服务中,假如一个或者多个服务出现故障,如果这时候,依赖的服务还在不断发起请求,或者重试,那么这些请求的压力会不断在下游堆积,导致下游服务的负载急剧增加。不断累计之下,可能会导致故障的进一步加剧,可能会导致级联式的失败,甚至导致整个系统崩溃,这就叫服务雪崩。</p>
<p>一般,为了防止服务雪崩,可以采用这些措施:</p>
<ul>
<li>服务高可用部署:确保各个服务都具备高可用性,通过冗余部署、故障转移等方式来减少单点故障的影响。</li>
<li>限流和熔断:对服务之间的请求进行限流和熔断,以防止过多的请求涌入导致后端服务不可用。</li>
<li>缓存和降级:合理使用缓存来减轻后端服务的负载压力,并在必要时进行服务降级,保证核心功能的可用性。</li>
</ul>
<h3 id="什么是服务熔断">什么是服务熔断?</h3>
<p>熔断机制是应对雪崩效应的一种微服务链路保护机制。当某个微服务不可用或者响应时间太长时,会进行服务降级,进而熔断该节点微服务的调用,快速返回“错误”的响应信息。当检测到该节点微服务调用响应正常后恢复调用链路。在Spring Cloud框架里熔断机制通过Hystrix实现,Hystrix会监控微服务间调用的状况,当失败的调用到一定阈值,缺省是5秒内调用20次,如果失败,就会启动熔断机制。</p>
<h3 id="什么是服务降级">什么是服务降级?</h3>
<p>服务降级,一般是从整体负荷考虑。当系统出现异常情况时,服务降级会主动屏蔽一些非核心或可选的功能,而只提供最基本的功能,以确保系统的稳定运行。通过减少对资源的依赖,服务降级可以保证系统的可用性和性能。它可以根据业务需求和系统状况来制定策略,例如替换耗时操作、返回默认响应、返回静态错误页面等。</p>
<p><code>Hystrix</code>相关注解<code>@EnableHystrix</code>:开启熔断 <code>@HystrixCommand(fallbackMethod=”XXX”)</code>,声明一个失败回滚处理函数<code>XXX</code>,当被注解的方法执行超时(默认是1000毫秒),就会执行<code>fallback</code>函数,返回错误提示。</p>
<h3 id="什么是服务限流">什么是服务限流?</h3>
<p>服务限流是一种流量控制策略,它通过限制每秒请求的数量(QPS)、请求频率、并发数等,来保护服务的处理能力,防止系统因为流量过大而出现性能问题或资源耗尽服务限流可以认为是服务降级的一种,限流就是通过限制系统清求的输入和输出,从而实现对于系统的保护,这个和降级的概念很像,都是为了保证核心功能的正常运行。限流是因为服务的吞吐量以及负载这些都是可以预估的,我们为了保证系统的正常运行,可以设置限制的國值,即涌过限制输入或者输出的方式来减少流量的流通,然后实现对于系统的保护限流有很多种实现方案,比如我们说的限流算法、延迟解决、拒绝解决等等,保证请求的范围在系统可以接受的阈值以内,实现对系统的保护。</p>
<h3 id="有哪些熔断降级方案实现">有哪些熔断降级方案实现?</h3>
<p>目前常见的服务熔断降级实现方案有这么几种:</p>
<table>
<thead>
<tr>
<th>框架</th>
<th>实现方案</th>
<th>特点</th>
</tr>
</thead>
<tbody>
<tr>
<td>Spring Cloud</td>
<td>Netflix Hystrix</td>
<td>提供线程隔离、服务降级、请求缓存、请求合并等功能;<br>可与Spring Cloud其他组件无缝集成 <br>官方已宣布停止维护,推荐使用Resilience4j代替</td>
</tr>
<tr>
<td>Spring Cloud</td>
<td>Resilience4j</td>
<td>轻量级服务熔断库 <br>提供类似于Hystrix的功能 - 具有更好的性能和更简洁的API <br>可与Spring Cloud其他组件无缝集成</td>
</tr>
<tr>
<td>Spring Cloud Alibaba</td>
<td>Sentinel</td>
<td>阿里巴巴开源的流量控制和熔断降级组件 <br>提供实时监控、流量控制、熔断降级等功能 <br>与Spring Cloud Alibaba生态系统紧密集成</td>
</tr>
<tr>
<td>Dubbo</td>
<td>Dubbo自带熔断降级机制</td>
<td>Dubbo框架本身提供的熔断降级机制 <br>可通过配置实现服务熔断和降级 <br>与Dubbo的RPC框架紧密集成</td>
</tr>
</tbody>
</table>
<h3 id="什么是hystrix">什么是Hystrix?</h3>
<p>Hystrix是一个延迟和容错库,旨在隔离远程系统,服务和第三方库的访问点,当出现故障是不可避免的故障时,停止级联故障并在复杂的分布式系统中实现弹性。</p>
<p>通常对于使用微服务架构开发的系统,涉及到许多微服务。这些微服务彼此协作。</p>
<p>思考一下微服务:</p>
<p><img src="https://seven97-blog.oss-cn-hangzhou.aliyuncs.com/imgs/202411021825449.png" alt="" loading="lazy"></p>
<p>假设如果上图中的微服务9失败了,那么使用传统方法我们将传播一个异常。但这仍然会导致整个系统崩溃。</p>
<p>随着微服务数量的增加,这个问题变得更加复杂。微服务的数量可以高达1000.这是hystrix出现的地方 我们将使用Hystrix在这种情况下的Fallback方法功能。我们有两个服务employee-consumer使用由employee-consumer公开的服务。</p>
<p>简化图如下所示</p>
<p><img src="https://seven97-blog.oss-cn-hangzhou.aliyuncs.com/imgs/202411021825516.png" alt="" loading="lazy"></p>
<p>现在假设由于某种原因,employee-producer公开的服务会抛出异常。我们在这种情况下使用Hystrix定义了一个回退方法。这种后备方法应该具有与公开服务相同的返回类型。如果暴露服务中出现异常,则回退方法将返回一些值。</p>
<h3 id="hystrix如何实现容错">Hystrix如何实现容错?</h3>
<p>尽管已经不再更新,但是Hystrix是非常经典的服务容错开源库,它提供了多种机制来保护系统,Hystrix服务容错六大机制:</p>
<ol>
<li>服务熔断(Circuit Breaker):Hystrix通过设置阈值来监控服务的错误率或响应时间。当错误率或响应时间超过预设的阈值时,熔断器将会打开,后续的请求将不再发送到实际的服务提供方,而是返回预设的默认值或错误信息。这样可以快速隔离故障服务,防止故障扩散,提高系统的稳定性和可用性。</li>
<li>服务降级(Fallback):当服务熔断打开时,Hystrix可以提供一个备用的降级方法或返回默认值,以保证系统继续正常运行。开发者可以定义降级逻辑,例如返回缓存数据、执行简化的逻辑或调用其他可靠的服务,以提供有限但可用的功能。</li>
<li>请求缓存(Request Caching):Hystrix可以缓存对同一请求的响应结果,当下次请求相同的数据时,直接从缓存中获取,避免重复的网络请求,提高系统的性能和响应速度。</li>
<li>请求合并(Request Collapsing):Hystrix可 以将多个并发的请求合并为一个批量请求,减少网络开销和资源占用。这对于一些高并发的场景可以有效地减少请求次数,提高系统的性能。</li>
<li>实时监控和度量(Real-time Monitoring and Metrics):Hystrix提供了实时监控和度量功能,可以对服务的执行情况进行监控和统计,包括错误率、响应时间、并发量等指标。通过监控数据,可以及时发现和解决服务故障或性能问题。</li>
<li>线程池隔离(Thread Pool Isolation):Hystrix将每个依赖服务的请求都放在独立的线程池中执行,避免因某个服务的故障导致整个系统的线程资源耗尽。通过线程池隔离,可以提高系统的稳定性和可用性。</li>
</ol>
<h3 id="说下hystrix与sentinel的区别">说下Hystrix与Sentinel的区别</h3>
<p>Hystrix和Sentinel都是服务熔断器,用于提高分布式系统的弹性。它们的主要区别在于实现方式、适用场景和资源模型设计。</p>
<p>Hystrix基于命令模式设计,将外部资源的调用封装在命令对象中,通过线程池或信号量来实现隔离。它提供了丰富的配置选项,如线程池大小、超时时间等,以实现对系统资源的有力控制。Hystrix更适用于需要高并发、快速响应的场景,因为它可以快速隔离和恢复故障。</p>
<p>Sentinel则基于流量控制和熔断降级的思想,可以与Spring Cloud、gRPC、Dubbo等框架集成。它通过定义资源规则和应用策略来实现对系统资源的控制。Sentinel更适用于需要流量控制和熔断降级的场景,它可以根据系统负载和响应时间来实现自动熔断和降级操作。</p>
<p>总之,Hystrix和Sentinel都是服务熔断器,用于提高系统的弹性。它们在实现方式、适用场景和资源模型设计等方面存在一些不同。具体选择哪个工具取决于系统的具体需求和场景。</p>
<h3 id="sentinel采用的什么限流算法">Sentinel采用的什么限流算法?</h3>
<p>Sentinel使用滑动窗口限流算法来实现限流。</p>
<p>滑动窗口限流算法是一种基于时间窗口的限流算法。它将一段时间划分为多个时间窗口,并在每个时间窗口内统计请求的数量。通过动态地调整时间窗口的大小和滑动步长,可以更精确地控制请求的通过速率。</p>
<h3 id="sentinel是怎么实现限流的">Sentinel是怎么实现限流的?</h3>
<p>首先需要定义具体需要限流的资源,然后指定一定的规则(基于QPS(每秒查询数)、线程数等维度),限制资源的访问频次。然后根据一定的限流算法(固定窗口、滑动窗口、令牌桶和漏桶),对指定的资源进行访问的流量控制。具体流程如下:</p>
<ol>
<li>当一个请求进入系统时,Sentinel 会首先对请求进行统计(如当前的 QPS、并发数)</li>
<li>接着 Sentine| 检查配置的限流规则,如果当前请求的速率超过了设定的限流阈值,Sentinel 将触发限流措施</li>
<li>对于被限流的请求,可以选择直接拒绝、排队等待、或返回降级响应等方式来处理,保证系统核心功能的稳定</li>
</ol>
<h3 id="sentinel怎么实现集群限流">Sentinel怎么实现集群限流?</h3>
<p>Sentinel利用了Token Server和Token Client的机制来实现集群限流。</p>
<p>开启集群限流后,Client向Token Server发送请求,Token Server根据配置的规则决定是否限流。</p>
<p><img src="https://seven97-blog.oss-cn-hangzhou.aliyuncs.com/imgs/202501051359028.png" alt="" loading="lazy"></p>


</div>
<div id="MySignature" role="contentinfo">
    <p>本文来自在线网站:seven的菜鸟成长之路,作者:seven,转载请注明原文链接:www.seven97.top</p><br><br>
来源:https://www.cnblogs.com/sevencoding/p/19226209
頁: [1]
查看完整版本: SpringCloud 常见面试题(二)