第六篇:微服务框架(SpringBoot、SpringCloud)
一. SpringBoot二. SpringCloud
一. 微服务框架
1. 微服务架构概念
单体架构 ——> 集群 ——> 垂直化 ——> 服务化(SOA:面向服务的架构) ——> 微服务化(SOA的细粒度化)
SOA和微服务的区别?
- SOA是面向服务的架构:解耦,解决信息孤岛问题,数据之间要互联互通
- 微服务是SOA的细粒度化:比如把用户服务拆成账户服务、积分服务等
服务注册中心的作用?
- 服务的动态感知:服务上线下线
- 服务地址的高效管理:不需要每个客户端都去管理服务地址,而是可以通过服务名直接调用服务
注:服务注册中心有Zookeeper、Eureka、Nacos、consul
网关的作用?
路由、权限认证、日志记录、限流、熔断
限流、降级、熔断?
- 限流:限流算法有令牌桶、漏桶、滑动窗口,限流框架有阿里的sentinel(滑动窗口)、springcloud的hystrix(信号量)
- 降级:关闭某些服务接口或者页面,以保证核心服务可用。被动降级是限流或熔断导致的降级,主动降级指的是关闭评论、广告等不重要功能保证核心服务可用。
- 熔断:当某些服务异常,则及时熔断此微服务的调用,快速返回错误响应信息。防止雪崩的发生。(Hystrix默认5秒内20次错误调用,会启动熔断机制)
2. 微服务的利与弊(为什么要用微服务)
利:
高度模块化,边界清晰。高内聚、低耦合。
可独立部署,互不影响
弊:
分布式带来的高度复杂性,比较难看清楚整个大系统是如何运作的
数据一致性问题
运维复杂,可靠性、稳定性、监控、容量规划方面都有很高的要求
二. SpringBoot
1. SpringBoot是什么?
SpringBoot是基于Spring生态的微服务框架,能够快速构建微服务,并且提供了各种start,让开发者能快速上手。
2. SpringBoot核心注解是什么?
@SpringBootApplication。主要包含三个注解:
- @SpringBootConfiguration:该注解表明这SpringBoot的一个配置类
- @EnableAutoConfiguration:开启自动配置功能
- @ComponentScan:Spring组件扫描
3. 什么是SpringBoot的自动配置?原理是什么?
自动配置是在容器启动的时候,自动把一些配置类和bean对象放到Spring容器中,将来用户就能直接使用。
自动配置的原理是:在Springboot的主启动类的核心注解@SpringbootApplication中有一个自动配置注解@EnableAutoConfiguration,这个注解会自动扫描spring.factories和.imports(2.7.x之后使用)这两个配置文件,并将配置文件中的xxxAutoConfiguration及其中用@Bean标注的对象放到Spring容器中
SpringBoot采用 “约定大于配置” 的思想,把所有可能需要的配置提前写好,写在自动配置的jar包中。基本每个start都有对应的自动配置。总的来说就是把spring.factory里的xxxAutoConfiguration都加载到Spring容器中。
xxxAutoConfiguration:自动配置类
xxxProperties:封装配置文件中的相关属性
配置文件的加载顺序?
xxx.properties、yml、yaml
SpringBoot核心配置文件是什么?
application(.yml或.properties) 或 bootstrap(.yml或.properties)。application常用于springboot项目,bootstrap常用于springcloud项目加载远程配置文件。
4. 如何自定义starter
starter是起步依赖,主要作用是管理依赖和自动配置。自定义starter中要包含两个模块,starter模块(管理依赖)和 自动配置模块(管理自动配置)
- starter模块:主要是引入所需第三方依赖,以及自动配置模块的依赖,将来用户使用只需引入starer依赖
- 自动配置模块:主要包含自动配置文件和自动配置类。自动配置文件是 spring.factories 或 .import文件,其中配置了自动配置类的全路径类名(主要是为了加载自动洞配置类);自动配置类中使用了@Bean注解把对象放到Spring容器中
5. springboot监视器了解吗?
springboot actuator用于服务监测和管理。可以通过 http://localhost:8080/actuator/{端点} 的方式访问端点。常见的端点有:
- /health:检查应用健康状况。健康为UP,不健康为DOWN;
- /info:应用基础信息。比如服务名字,jdk版本,编码规则等;
- /beans:Spring容器中所有的bean;
- /loggers:应用程序配置的日志信息。比如日志级别,也可以修改日志级别;
- /threaddump:线程信息。比如线程id,线程状态,线程堆栈,是否等待锁资源等;
- /heapdump:会自动生成JVM堆文件;
- /metrics:应用各类度量指标。比如内存信息,线程信息,垃圾回收信息,数据库连接池;
- /shutdown:关闭SpringBoot应用。
6. SpringBoot怎么保证程序安全性?
使用spring-boot-starter-security依赖项,security主要核心功能有:
- 认证(你是谁)
- 授权(你能干什么)
- 攻击防护(防止伪造身份)
7. 微服务如何实现session共享?
一个完整的项目被拆分成微服务后,session就被物理隔离开了。这时候可以使用Spring Session + redis的方案,把session放到redis中,操作redis上的session,就能解决这个问题。
8. springboot如何实现定时任务?
使用Spring的@scheduled注解(单机),或者使用分布式任务调度框架xxl-job之类的。
三. SpringCloud 和 SpringCloud Alibaba
1. SpringCloud是什么?
Springcloud是一个微服务全家桶,是基于SpringBoot提供的一整套微服务解决方案
2. Spring、SpringBoot、SpringCloud 区别?
- Spring是以 Bean(对象)为中心 ,提供IOC、AOP等功能
- SpringBoot是以 Application(单个微服务应用)为中心,提供各种start,提供自动配置、监控等功能
- SpringCloud是以 Service(整个微服务治理框架)为中心,提供 网关、负载均衡、服务注册与发现、服务调用、服务容错等功能
3. SpringCloud 和 SpringCloud Alibaba (前五行 微服务五大件)
服务治理 | Spring Cloud落地技术 | Spring Cloud Alibaba落地技术 |
服务注册与发现 | Eureka、Zookeeper | Nacos |
服务调用 | Feign、OpenFeign | Dubbo(HSF) |
负载均衡 | Ribbon | Ribbon |
网关 | SpringCloud Zuul | Getway |
服务容错 | Hystrix | Sentinel |
分布式调度 | --(替代方案:xxl-job) | ScheduleX |
配置中心 | Spring Cloud Config | Diamond |
消息 | --(替代方案:RabbitMQ、Kafka) | RocketMQ |
服务总线 | Bus | Nacos |
服务部署 | Docker、Kubernetes、OpenStack | Docker |
分布式事务 | --(替代方案:2pc) | Seata |
服务监控 | 待补充 | AliMonitor(应用监控)、Arthas(在线诊断) |
链路追踪 | Spring Cloud Sleuth | SkyWalking |
总结目前市面上的技术使用,可以看到SpringCloudNetflix(Eureka、Feign、Ribbon、Hystix、Zuul) 的技术基本被SpringCloudAlibaba替代了:
四. 网关 - Gateway、zuul
前端调用后端的时候,统一走Gateway网关进入,通过Gateway网关转发请求给对应的服务。网关的主要作用就是路由和鉴权。
服务启动和请求全过程:
1. 服务启动的时候Eureka客户端会把自身注册到Eureka服务端,并且也能通过Eureka服务端发现其他服务。
2. 当前端发起请求时,先进入Gateway网关,网关通过Eureka服务端拿到服务提供者信息,通过路由策略转发请求给相应的服务,服务收到请求会先过Hystrix做服务容错(限流、熔断、降级),然后再根据业务逻辑处理请求。
3. 当后端服务之间相互请求时,Feign每5秒会从Eureka服务端同步一次服务器信息缓存到本服务器,ribbon直接从缓存中的服务器信息中选择一个,转发请求到相应服务器,依然是先到Hystrix,再做业务逻辑处理。
1. Gateway和Zuul的区别?
Zuul是Netflix开发的旧版网关服务,目前已经处于维护状态,不再更新新功能;
Gateway是Spring Cloud生态系统中的新一代API网关,在功能、性能和灵活性方面提供了更多的优势。
2. 网关的作用
- 统一入口:为全部微服务提供唯一入口点,网关起到外部和内部隔离,保障了后台服务的安全性
- 动态路由:动态的将请求路由到不同的后端集群中
- 鉴权校验:识别每个请求的权限,拒绝不符合要求的请求
- 限流
3. 如何配置SpringCloud Gateway的路由规则?有哪些常见的路由策略?
路由类似于映射,符合条件的请求会被转发到目标路径。一般在配置文件中配置路由规则。需要配置id、断言、uri。
路由策略通常由断言进行配置,可以根据路径、参数、请求头等对路径进行匹配。
4. 什么是断言?
断言是一种定义路由条件的机制。断言可以根据请求的路径、参数、请求头等,对请求进行过滤和匹配。符合断言条件的,Gateway才会进行相应的路由转发。
常见的路由工厂:
名称 | 说明 | 示例 |
Path | 请求路径必须符合指定规则 | - Path=red/{segment},/blue/** |
Query | 请求参数必须包含指定参数 | - Query=name,Jack |
Header | 请求必须包含某些Header | - Header=X-Request-Id,\d+ |
5. 什么是过滤器?
对路由的请求或响应做加工处理。
常见过滤器:
请求头示例:
如何集成自定义过滤器到Gateway中?
实现GlobalFilter接口,并实现接口中的filter()方法。再添加@Component注解。
6. Spring Cloud GateWay如何实现限流?
- 使用Gateway的RequestRateLimit过滤器实现基于redis的限流(令牌桶算法)
- 使用Sentinel结合Gateway来实现网关限流
RequestRateLimit过滤器:
Sentinel:
添加Sentinel依赖,在配置文件中配置Sentinel及控制台信息后,就能在控制台添加相关限流操作了。
7. Gateway网关的实现原理
客户端向Gateway发出请求,如果能找到与请求相匹配的路由,就交给过滤器处理,过滤器会在请求之前或之后执行过滤的逻辑,再把请求发送到真正的服务执行业务逻辑
8. 网关负载均衡算法
随机、轮询、权重轮询、最少连接、IP Hash
9. 如何监控和诊断SpringCloud Gateway的性能问题?有哪些常用的工具和技术?
可以使用SpringBoot Actuator,先引入依赖,再暴露端点,就可以通过Http请求监控端点了
management:
endpoints:
web:
exposure:
include: gateway
10. Nigix网关和Gateway网关有什么区别?
- Nigix一般用于做流量网关,属于用户访问的入口,用来做反向代理和负载均衡
- Gateway一般用于做业务网关,通过属性配置把请求转发到对应的业务微服务中去
正向代理:对服务端来讲,来源地址是一个整体(和客户端是一个整体)
反向代理:对客户端来讲,后端地址是一个整体(和服务端是一个整体)
五. 服务注册与发现 - Eureka、Zookeeper、Nacos
服务注册就是维护一个登记簿,它管理系统内所有的服务地址。当新服务启动后,会把自身注册到注册中心,服务消费方可以通过注册中心拿到其他服务的信息。
(一)Eureka
服务启动的时候,服务上的Eureka客户端会把自身注册到Eureka服务端,并且可以通过Eureka服务端的注册表知道其他注册的服务。
1. Eureka使用的是CP还是AP?
Eureka是AP,它更注重系统的可用性,而一致性方面,它使用了最终一致性的方案来处理节点之间的数据同步,这意味着在某些情况下,Eureka可能出现短时间数据不一致或延迟同步的情况。因此,Eureka更适合对可用性要求较高的场景,例如微服务架构中的服务注册与发现。
2. Eureka怎么作为注册中心?
- (1)搭建Eureka Server端。引入eureka-server的依赖,配置文件中添加服务名、地址、端口
- (2)服务注册。引入eureka-client依赖,配置文件中添加Eureka服务端地址和端口。
- (3)服务发现。引入eureka-client依赖,配置文件中添加Eureka服务端地址和端口;再用负载均衡注解@LoadBalance拉取服务列表并根据策略选择要访问的服务。
3. Eureka的底层原理能说一下吗 / Eureka的注册发现功能是如何实现的?
Eureka是一款服务注册与发现组件,它的原理包含以下几个方面:
- 服务注册:Eureka中心维护了一个服务注册表,用于存储服务信息,包括IP、端口、服务名等
- 服务发现:客户端通过向Eureka中心发请求来获取注册表中的服务信息
- 心跳和健康检查(服务续约):注册到Eureka中心的服务会定期发送心跳信号,以表明自己的健康状态。如果长时间未收到心跳信号,则认为服务已下线
- 负载均衡:Eureka通常会和Ribbon结合使用,当获取到服务列表后,会通过负载均衡算法选择一个合适的服务进行通信
- 服务同步:多个Eureka Server之间会相互复制服务注册信息,保证数据的一致性
服务向Eureka发送的心跳信息是什么内容?
服务实例的基本信息(ip、端口、服务名)以及健康状态。
Eureka接收到心跳后做了什么事情?
更新了把注册表中该实例的一个字段:最后更新时间。
Eureka怎么知道某个节点挂掉了?
Eureka通过心跳机制来检测服务的健康状态。服务会定期(默认30s)向Eureka发送心跳,如果超过一定时间(默认90s)没有发送,则认为该服务已下线。
Eureka宕机了其他服务还能正常使用吗?
如果Eureka和客户端负载均衡Ribbon配合使用,那么Ribbon会在客户端缓存服务列表信息,短时间内其他服务还可以正常使用。
4. Eureka如何进行数据同步 / Eureka复制的底层原理?
分布式系统中多个节点数据同步有两种方式:主从复制、对等复制(所有节点是平等的,都可以接收写请求,再复制给其他节点),Eureka使用的就是对等复制。
Eureka Server本身依赖了Eureka Client,也就是说每个Eureka Server是作为其他Server的Client。当Eureka Server启动后,会任意请求一个Eureka Server节点把自身注册到server上,并获取服务列表。Eureka Server每当自己的信息变更后,就会通过HTTP请求把最新服务列表信息通知给其他Eureka Server,保持数据同步。
复制死循环问题怎么解决的?
复制死循环指的是自己的信息变更是从另一个Eureka Server同步过来的,再同步回去就发生复制死循环了。
解决:使用HEADER_REPLICATION请求头来说明这是一个复制请求,而非普通实例请求,这样其他节点在接收到请求时,就不会再对其进行复制操作了。
数据冲突问题是怎么解决的?
数据冲突指的是:比如server A向server B发起同步请求,如果A的数据比B的还旧,B如何知道A数据是旧的,以及A应该怎么办。
解决:数据的新旧是通过版本号来定义的。比如当A节点向B发起同步请求,A的数据新,则B接收更新;否则拒绝更新,并反向更新数据(也就是B向A同步数据)。
5. 如何监测本地Eureka存活?
本地Eureka指的是在开发和测试阶段启动的单机Eureka,要检测其健康状况,有几种方式:
- 健康检查端点:Eureka提供了一个健康检查端点来检查服务的健康状态,通常是“/health”。可以向该端点发送HTTP请求来获取Eureka的健康状态,如果响应码为200,则表示服务正常。
- Eureka RESTFul API:Eureka还提供了一组RESTFul API,可以调用API获取服务的基本信息
- 日志监控:可以监控Eureka日志来检查服务是否正常
6. Eureka的多级缓存?
Eureka有三级缓存:只读缓存、读写缓存、注册表
- 客户端获取注册信息先从只读缓存获取,只读缓存没有再去读写缓存取,读写缓存没有再去内存注册表取,取出的数据会放到读写缓存
- 服务注册和下线的时候直接写内存注册表,写完表后主动失效读写缓存;并且读写缓存默认每180秒失效一次
- 只读缓存默认每30s从读写缓存同步一次数据
为什么Eureka需要三级缓存?
需要缓存是因为可以提高读取效率;三级缓存是因为注册表的底层结构是ConcurrentHashMap,如果每次操作它,必然会因为锁的存在降低性能。因此三级缓存主要是为了做读写分离,使写操作不阻塞读操作。
7. 为什么选择Eureka?
Eureka和Zookeeper对比的话,ZK是基于CP的,如果正在进行leader选举,那么集群是不可用的;而Eureka基于AP,更注重可用性,及时集群都挂了,也能拿到本地缓存的数据。
8. 使用Eureka有没有遇到过什么问题?
使用Eureka有服务安全下线问题。Eureka会跟服务器之间保持心跳,三次心跳失败,就会把服务器节点拿掉。但是就有一个问题,服务下线和Eureka知晓之间的时间请求都会失败。
如何解决这个问题?
这个需要服务提供方来保证。Eureka服务端提供了一个接口,可以调用接口把服务器节点信息拿掉,服务下线前有一个回调钩子,可以在这个回调里边调用Eureka,先把节点信息拿到再shutdown服务,就可以保证服务安全下线。
9. 谈谈Eureka的保护机制
默认情况下,如果Eureka在一定时间内(默认90s)没有收到某个服务的心跳,Eureka就会移除该实例。但当网络分区故障时,Eureka和微服务之间无法正常通信,而微服务本身是正常的,此时不该移除微服务,所以引入了自我保护机制。
自我保护机制:如果在15分钟内,超过85%的微服务都没有正常心跳,则认为是Eureka和微服务之间出现了故障,那么就进入自我保护机制,此时有如下状态:
- Eureka不再因长时间没收到心跳而移除服务
- Eureka依然接收新服务的注册和查询,但不会同步到其他节点,保证当前节点依然可用;当网络恢复后,再把新的注册同步到其他节点
自我保护机制的优点:可以很好应对由于网络分区导致的部分节点失联情况,而不是整个集群瘫痪
缺点:Eureka不会剔除不可用节点,所以会造成访问不可用节点的问题。解决方案是Ribbon的重试机制以及Hystrix断路器。
(二)Zookeeper
1. Zookeeper是什么?能做什么事情?
Zookeeper是一个分布式协调框架,可以用来做分布式协调、配置中心、分布式锁等。
Zookeeper 并不是用来专门存储数据的,它的作用主要是用来维护和监控你存储的数据的状态变化,通过监控这些数据状态的变化,从而可以达到基于数据的集群管理,ZooKeeper节点的数据上限是1MB。
什么是分布式协调?
分布式系统中不同节点需要交换信息,协同工作,以达到一致状态,这个过程就需要分布式协调组件。
比如A系统发送请求到MQ,B系统消费消息后处理了,那么A系统如何知道B系统的处理结果?用Zookeeper就可以实现分布式系统之间的协调工作。
A系统发送请求后可以在Zookeeper上对某个节点的值注册个监听器,一旦B系统处理完了就修改Zookeeper那个节点的值,A系统立马就可以收到通知,完美解决。
2. Zookeeper保证的是CP还是AP?
Zookeeper保证的是CP,也就是说Zookeeper会更优先保证数据的一致性,在可用性方面,如果zk集群正在选举,那么集群处于不可用状态。因此,Zookeeper更适合对一致性和数据正确性要求较高的场景。
3. Zookeeper是怎么保证主从同步的?
- zk使用了原子广播机制来保证各个server的同步。它的核心是ZAB协议,ZAB协议有两个模式,恢复模式和广播模式。
- 恢复模式,当leader不可用时,ZAB就进入了恢复模式,新领导选取出来后,恢复模式结束,进入广播模式;
- 广播模式,只有leader能够处理写请求,当leader在本机写完之后,用广播通知其他follower,如果超过半数的follower都返回ACK,则commit。
也就是说,ZAB协议主要用于处理leader选举和主从服务器间的数据复制。
ZooKeeper使用的ZAB协议与Paxos算法的异同?
Paxos算法是分布式选举算法,Zookeeper使用的 ZAB协议(Zookeeper原子广播)
- 相同之处:比如都有一个类似于Leader的角色,用来协调N个Follower的运行;Leader要等待超半数的Follower做出正确反馈达成一致之后才进行提案
- 不同之处:ZAB有明确的leader,但Paxos任何节点都可以成为提案者,并且要求接受者不能接受比当前提案编号更小的提案;而且ZAB协议主要用于构建分布式数据主备系统,paxos主要用于分布式系统数据一致性
4. Zookeeper的底层是怎么实现的?
- 服务注册:Zookeeper的数据模型是一个树形结构,其中的每个节点称为Node。当服务注册的时候,他会在Zookeeper中创建一个临时节点来表示自己的存在,并在节点中存储自己的信息。服务停止也会删除对应节点。
- 服务发现:客户端会监听服务节点,当服务节点状态变化时(增加或减少子节点)会通知客户端,客户端就能获取到最新的服务列表
- watch机制:它允许客户端注册Watch监听器监听节点,当节点或子节点状态变化,客户端就能及时收到通知并响应变化。
- 心跳机制:客户端需要定期向Zookeeper发送心跳,超时没有发送则认为该节点不可用,并移除该节点
- 主从同步:利用了Zookeeper的ZAB协议。ZAB协议有两种模式,恢复模式是在leader不可用时选举出新leader,广播模式下leader接收所有写请求,并广播给其他follower,超过半数的follower正确反馈则写请求成功
为什么服务注册创建的是临时节点?
因为临时节点会在客户端断开连接后自动删除,这意味着当服务提供者意外退出或主动注销时,对应的节点会被自动删除,从而能动态反应出服务实例的可用状态。
那什么时候会创建永久节点?
根节点或配置信息相关的节点会创建永久节点。
5. Zookeeper的 通知/监听 机制是什么样的?
Zookeeper允许客户端向服务端节点注册一个watcher监听,当节点状态变化(主要是节点数据变化或子节点有增减),客户端就能及时收到通知并响应变化。
Zookeeper的监听原理是什么?
Zookeeper的监听原理是基于观察者模式实现的。客户端在注册监听器的时候会把节点路径和监听器信息发给服务端,服务端会将其存储在WatchManager中,当节点状态发生变化,服务端会给客户端发送通知,客户端收到通知后会执行监听器的回调方法。
6. Zookeeper是怎么选举的?
涉及到两个概念:
zxid:为了保证顺序性,每次更新请求都会有一个全局的时间戳,叫zxid
myid:每个集群的server都有一个唯一标识,server1,server2,1、2就是myid
PK规则:
每一轮投票,服务器都需要把自己的投票跟别人PK。PK规则是:先判断Zxid,谁的zxid大就投给谁,如果一样,则判断myid。
投票过程:假设有5台服务器
- server1给自己投了一票,并把(myid,zxid)发给其他服务器,此时server1的选票为(1,0)
- server2给自己投了一票, 同时跟server1交换结果,zxid都是0,server2的myid为2,所以server2胜出。但投票还没有超过半数,所以选举没结束
- server3给自己投了一票,同时跟server1、server2交换结果,server3的myid为3最大,所以server3胜出。此时投票超过半数,server3成为leader
- server4给自己投了一票,发现server3已经成为leader,则把自己的状态改为follower
- server5和server4一样
7. Zookeeper如果宕机了怎么办?
Zookeeper只要有超过半数的服务器可用,集群就可用。Zookeeper集群至少有3台服务器,如果是follower宕机还有其他follower可用,如果是leader宕机,就重新选取leader。
Zookeeper集群为啥最好是奇数台?
Zookeeper集群如果有服务器宕机,剩下的服务器个数大于宕机的个数,整个集群才依然可用。比如集群有3台服务器,最多允许宕机一台,集群有4台服务器也是最多允许宕机一台,所以就不必要多浪费一台服务器了。
Zookeeper 过半选举机制为什么能防止脑裂?
脑裂字面意思是有多个大脑。一个集群的多台服务器通常会部署在多个机房,如果有网络故障导致机房之间网络不通,整个集群就被割裂成多个子集群,子集群各自选举出自己的leader,就像脑裂。
Zookeeper的过半选举不可能会产生2个leader,因为少于等于一半不可能产生leader
8. Zookeeper是如何保证事务的顺序一致性的?
Zookeeper采用了全局递增的事务Id来标识事务,进而保证顺序性
zk高级面试题:大数据面试题——Zookeeper面试题_牛客网
9. Zookeeper的分布式锁是如何实现的
- “临时”是因为 如果是永久节点获取锁的机器宕机后,节点无法删除、锁无法释放;但是临时节点会话结束后会自动删除
- “顺序”是为了找最小节点,所以排了个顺序
(三)Nacos
1. Nacos是什么?
nacos是SpringCloudAlibaba的组件,可以用作服务注册中心和配置中心。
2. 如何在Nacos中注册服务和实现服务发现?
先安装nacos安装包,再访问网址即可看到nacos的管理页面。
- 服务注册:引入nacos-discovery依赖,在配置文件中配置nacos地址和端口,主启动类上添加@EnableDiscoveryClient,重启服务后就能在管理页面看到已注册的服务。
- 服务发现:一般配合Ribbon使用负载均衡从nacos拉取服务列表以及选择要访问的服务
3. 如何在nacos中管理配置?
引入nacos-config依赖,在nacos管理后台按照规则添加配置文件,再在工程中使用注解配置的拉取和热更新(单个拉取使用@Value 批量拉取使用@ConfigurationProperties)
从nacos中获取配置文件中属性的具体流程:
4. Nacos的原理是什么?
服务注册与发现:
- 服务注册:服务实例启动时注册到nacos注册中心,关闭时注销
- 服务发现:服务消费者通过查询nacos注册中心来获得可用的服务实例
- 心跳机制:nacos注册中心使用心跳机制和健康检查即时感知服务的可用性
- 数据同步:nacos作为注册中心时使用AP模式,所有节点都能进行读写,数据复制使用对等复制;如果作为配置中心则使用CP模式,需要leader,只有leader可写,然后进行主从复制
配置中心(热更新):
- Nacos使用了Pull + 长轮训的方式从服务端获取数据
- 客户端会循环向服务端发起pull请求,客户端发起请求后,服务端不会立即返回请求结果,而是将请求挂起等待一段时间,如果此段时间内服务端数据变更,立即响应客户端请求,若是一直无变化则等到指定的超时时间后响应请求。
客户端会循环向服务端发起pull请求,并且设置超时时间为30s,当配置发生变化时,会立即返回响应;否则服务端会设置一个定时任务,挂起请求,一直等待29.5s后再返回响应,这29.5s内,任何时刻配置发生变化,都会触发事件机制,把变更的数据通过http请求进行返回。(29.5s是为了防止因为网络原因导致请求超时)响应之后就会再次发起pull+长轮询。
服务发现是推拉结合的方式,配置热更新是拉的方式
客户端和服务端数据交互方式:
- pull模式:表示客户端主动从服务端拉取数据
pull模式下,客户端定时从服务端拉取数据,有时间间隔,因此不能保证数据的实时性;并能且如果配置长时间不更新,客户端做的就都是无效pull操作
- push模式:表示服务端主动把数据推送给客户端
好处是实时性好;缺点是服务端需要和每个客户端都保持长连接,如果客户端数量多会耗费大量内存资源保存连接;并且为了检验连接的有效性,还需要心跳机制来维持状态
为什么nacos在配置热更新时要采用拉的方式?
要保证更新的实时性,最好选择推,但是push的方式耗费连接资源过多,还需要心跳机制维持连接;而拉的方式,客户端值需要通过http请求就能获取数据,时效性用长轮训解决
5. Nacos 支持 CP 还是 AP?
Nacos支持CP+AP的方式,可以在注册节点注册时配置CP或AP。nacos作为注册中心时使用AP模式,作为配置中心则使用CP模式
6. 说一下Nacos心跳机制的底层原理?
Nacos客户端会和服务端保持一个长连接,这个长连接本身5s一次的心跳机制可以让客户端向服务端发送心跳证明自己的可用状态,如果服务端超过一定的时间阈值没有收到心跳,就会主动向客户端发起健康检查,如果客户端健康状态异常的话就会断开连接。
7. Nacos中的负责均衡底层是如何实现的
通过Ribbon实现,Ribbon中定义了一些负载均衡算法,然后基于这些算法从服务实例中获取一个实例为消费方法提供服务
8. Nacos如何支撑阿里巴巴内部上百万服务实例的访问
Nacos内部接收到注册的请求时,不会立即写数据,而是将服务注册的任务放入一个阻塞队列就立即响应给客户端。然后利用线程池读取阻塞队列中的任务,异步来完成实例更新,从而提高并发写能力。
9. ZK、Eureka、Nacos、consul的优缺点?
- CP和AP的选择:Eureka是AP,ZK和consul是CP,NacosAP CP可选择。作为注册中心更需要AP
- 技术体系:Consul是Go开发,其他都是java,一般项目会偏向选择对应的技术体系
- 功能选择:nacos的功能最为完善,包括了雪崩保护、自动注销实例、spring cloud集成、dubbo集成、k8s集成,这些都支持,其他的几个技术基本都支持部分罢了
- 服务下线:nacos能自动或手动下线服务,使用消息机制通知客户端,服务实例的修改很快响应;Eureka只能通过任务定时剔除无效的服务。
10. 作为配置中心,SpringCloud Config、Apollo、Nacos的优缺点?
- Config和SpringCloud生态结合的比较好,但是其有一些明显的缺点,比如没有UI界面、没有权限管理、如需实现配置批量刷新还需借助其他MQ组件等
- Apollo功能完善,配置管理流程完善,缺点是容器化困难,nacos有官网镜像可以直接部署
- Nacos功能强大,支持的并发量很高,更适合要求高性能的大规模场景,而且nacos也能作为服务注册中心,降低了运维的成本
六. 服务调用 - Feign、Dubbo
(一)Feign
1. 说一下你理解的Feign
Feign是一个声明式的Http客户端,可以帮我们优雅的发送Http请求。
“声明式” 指的是:以接口或注解的方式定义对外部服务的访问
Feign的好处:主要是使代码更简洁,只需要定义一个接口,就可以轻松访问远程服务
2. Feign和OpenFeign的区别?
OpenFeign是对Feign的增强,使其能更好的支持SpringBoot和SpringCloud,比如SpringMvc、Ribbon、Hystrix。
3. Feign如何使用?
1)引入OpenFeign依赖,在主启动类上添加 @EnableFeignClients注解,编写Feign客户端
2)测试
4. Feign的原理是什么 / Feign具体是怎么实现远程过程调用的?
Feign只有一个@FeignClient注解和一个RESTFul风格的接口,并没有实现类。因此Feign的原理就是通过JDK动态代理对这个接口生成了一个代理对象,在内部先通过Ribbon从注册中心获取远程服务并进行负载均衡选择,再对远程服务进行HTTP调用,最后将HTTP响应封装成JavaBean
5. Feign和Dubbo的区别是什么?
- Feign是基于HTTP协议实现的,每次远程调用都需要建立TCP连接,开销比较大。通过短连接的方式进行通信,不适合高并发的访问。Feign的好处在于简单、代码侵入少。(服务端而言,Feign不需要做额外操作,而Dubbo需要配置开放的Dubbo接口)
- Dubbo是通过RPC实现远程调用的,服务间建立的长连接,每次调用只需要发送小的二进制数据包,开销相对小,适合高并发的场景
- 总的来说,如果项目对性能要求不是很严格,可以使用Feign,它使用起来更方便;如果要实现高并发、高可用的分布式系统,Dubbo更适合
6. Feign和Dubbo都工作在网络模型的哪一层
Feign基于HTTP协议,属于应用层协议;Dubbo基于RPC协议,属于传输层协议
7. 使用Feign有没有踩过坑?
- OpenFeign发起HTTP请求时,默认使用的是HttpUrlConnection,这个是没有连接池的,性能比较低,有可能会导致系统性能方面的故障。可以使用HttpClient或者OKHttp,这两者都有连接池。
- OpenFeign默认的超时时间比较长,默认连接超时10s,读超时60s。但是如果某个并发量很高,连接一直不释放导致连接耗尽,可能会造成系统崩溃。所以最好在配置文件中设置Timeout时间。
(二)Dubbo
1. 什么是Dubbo?Dubbo的工作流程知道吗?
Dubbo是分布式系统中常用的RPC框架,可以帮我们做服务地址的管理、服务的注册与发现、服务监控等。Dubbo一般配合Zookeeper使用。
Dubbo工作流程:
角色:Container-容器、Provider-服务提供方、Consumer-服务消费方、Register-注册中心、Monitor-监控器
- Provider在Container上启动服务;
- Provider在Register上注册服务,Dubbo一般使用Zookeeper作为注册中心;
- Consumer在Register上订阅服务,注册中心返回服务器列表,如果列表有变更就通知Consumer;
- Conusmer根据负载均衡算法调用Provider;
- Monitor实时监控服务调用次数和时间。
2. Dubbo如何使用?
服务提供者:
服务消费者:
3. 在Provider上可以配置的Consumer属性有哪些?
- 超时时间 @Service(timeout=3000) @Reference(timeout=3000)
- 失败重试次数 @Service(retries=2) @Reference(retries=2)
- 负载均衡策略 @Service(loadbalance="random") @Reference(loadbalance="random")
- 集群容错方案 @Service(cluster="failfast") @Reference(cluster="failfast")
Dubbo如何配置服务超时时间?
服务提供者或服务消费者上都可以配置,提供者上通常都需要配置,因为提供者自己最清楚服务的情况,但超时时间最终决定权通常在消费者手中
Dubbo负载均衡策略有哪些?
随机、轮循、最少活跃测策略、一致性hash(相同参数或ip打到同一台机器上)
集群容错方案有哪些?
- Failover Cluster:失败重试,是默认模式,会自动重试下一个节点,直到达到失败次数,一般用于读操作。
- Failfast Cluster:快速失败,只发起一次调用,失败立即报错,通常用于写操作。
- Failback Cluster:失败自动恢复,后台记录失败请求,定时重发
4. Dubbo启动时如果服务不可用怎么办?
Dubbo启动时会监测服务可用性,不可用的话会抛出异常,阻止Spring启动。
5. Dubbo使用什么序列化框架和通信框架,都支持什么协议?
- 序列化框架:推荐Hessian,还有Dubbo,fastjson;
- 通信框架:默认Netty;
- 协议:Dubbo(推荐)、HTTP、Hessian、RMI等。
Dubbo的各个协议分别有什么优缺点?
- Dubbo:是默认的通信协议。优点是高性能、轻量级,适合高并发分布式场景;缺点是不适合传输大数据量,如文件视频等,除非请求量很低
- HTTP:优点是标准、通用、易于调试;缺点是性能低,不适合高并发大规模服务调用
- Hessian:RPC协议,dubbo是优化后的Hessian。优点是简单易用跨语言,但是性能低
- RMI:是java的标准协议,可以用于java对象在远程进程间的通信。优点是简单易用跨平台;缺点传输大对象时性能较差。
6. 注册中心挂了,服务是否可以正常访问?
可以,因为Dubbo服务消费者在第一次调用时,会把从注册中心拿到的服务提供方地址缓存到本地。当服务提供者地址发生变化时,注册中心会通知消费者。
7. Dubbo 和 Spring Cloud 的区别是什么?
Dubbo主要是做服务调用;SpringCloud是一整套的服务治理生态。SpringCloud中有一个组件Feign,它实现远程调用是基于HTTP请求,数据包大,而且每次请求都会建立一个连接,消耗性能;而Dubbo是基于RPC协议,每次请求只需要发送小的二进制数据包,开销相对小。
8. 讲一下RPC的原理
RPC(Remote Procedure Call)远程过程调用,向调用本地服务一样调用远程服务。
Dubbo中的RPC调用在Java中通常是通过动态代理实现的。@Reference注解会生成一个动态代理,当客户端调用服务端方法时,实际上执行的是代理对象的逻辑,代理对象内部会把调用信息(接口、方法名、参数等)封装成RPC请求,并通过网络传输给服务端,服务端接收请求后,执行相应的方法并将结果返回给客户端。
七. 负载均衡 - Ribbon
1. 什么是Ribbon?
Ribbon是客户端负载均衡。服务间发起请求的时候,服务消费者方基于Ribbon服务做到负载均衡,从服务提供者的多台机器中选择一台。
2. 如何使用Ribbon?
引入Ribbon依赖,在声明RestTemplate bean的时候加上@LoadBalance注解,最后用RestTemplate发起Http请求即可。
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}
3. Ribbon提供了哪些负载均衡策略?
随机、轮询、权重、最佳可用(选最健康的服务)、最少并发(选连接数最少的服务)
4. 如何配置Ribbon的负载均衡策略?
- 方式一:在配置文件中配置LoadBalanceRule
# 配置Ribbon使用轮询策略
service-name: # 服务名
ribbon:
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RoundRobinRule
- 方式二:使用配置类上使用@RibbonClient注解
@RibbonClient(name="stock-service",configruation=RibbonRandomConfig.class)
5. Ribbon中如何自定义负载均衡策略?
实现IRule接口,并在其中的choose()方法中实现负载均衡逻辑
public class MyRule implements IRule {
@Override
public Server choose(Object key) {
// 负载均衡逻辑
}
}
6. Ribbon实现负载均衡的原理是什么?
Ribbon的底层是使用了一个拦截器,拦截了所有RestTemplate发起的请求,使用请求中的服务名到注册中心拉取服务列表并存储,再通过负载均衡算法选取一台服务器,最后修改请求地址。
7. Ribbon如何处理服务实例的故障 / 在Ribbon中如何实现容错处理?
自动重试、选择另一个可用的服务实例、如果没有可用的实例将等待一段时间后再次尝试
8. Ribbon缓存了服务列表,那如果注册中心有服务下线怎么办呢
服务列表有两个缓存,一个是注册中心,一个是Ribbon。注册中心如果是Nacos,那么服务下线会及时感知到;但如果是Eureka就需要心跳机制去发现,有一定的延迟,这时可以让服务消费方通过钩子函数去调用Eureka服务下线的API,就能保证服务下线及时感知。
但Ribbon的缓存是30s,每30s从注册中心拉取一次服务实例更新缓存。每10s还会ping服务地址,如果返回状态不是200,那么默认该服务下线。如果在这个间隙中请求到了不可用的服务实例,Ribbon会自动请求下一个可用的服务实例。
八. 服务容错 - Hystrix、Sentinel
(一)Hystrix
发起的请求是通过Hystrix的线程池去访问服务,不同的服务通过不同的线程池,实现不同的服务调度隔离。如果服务出现故障,通过服务熔断,避免服务雪崩问题;并且通过服务降级,保证服务核心功能正常提供。
- 隔离:服务之间请求用线程池隔离,防止所有线程都卡在某一个异常的下游节点
- 熔断:服务异常及时熔断,返回错误响应信息,防止服务雪崩(下游节点异常从而超时影响到上游节点,从而影响到整个链路),Hystrix默认5秒20次异常请求则熔断。
- 降级:需要有降级逻辑,请求走熔断器过程中,需要把该请求记录到故障数据库,方便后续回补数据
(二)Sentinel
1. Sentinel是什么?
Sentinel是阿里开源的服务容错组件,提供了 限流、熔断、降级等多个维度来保障服务稳定性。
2. 为什么需要Sentinel?
在微服务系统中,难免遇到个别服务故障的情况。如果调用链路中的某个服务故障,请求阻塞,导致连接被耗尽,就有可能拖垮整个调用链路上的所有服务。为了避免这种服务雪崩现象,就需要使用Sentinel这种流量控制和服务保护组件。(主要为了防止服务雪崩)
什么是服务雪崩?
微服务系统中,由于调用链中的一个服务故障,导致整个链路都无法访问
如何解决服务雪崩?
限流可以预防雪崩;超时处理、线程隔离、降级熔断可以把故障控制在一定范围内,属于补救措施。
3. Sentinel和Hystrix的区别是什么?
Hystrix以隔离和熔断为主,而Sentinel提供了更加丰富的功能,如限流、熔断降级、流量整形等,最重要的是Sentinel有非常好用的控制台页面,操作更方便。
4. 怎么使用Sentinel的?
先引入Sentinel依赖,在配置文件中配置Sentinel控制台地址,再启动Sentinel jar包即可访问控制台。
- 限流:对某个资源的QPS设置阈值
- 线程隔离:对某个资源能使用的线程数设置阈值
- 熔断降级:对某个资源的慢调用比例、异常比例或异常数设置阈值,超过阈值则熔断
5. Sentinel中有哪些流控模式?
- 直接:统计当前资源的请求,触发阈值时对当前资源直接限流,也是默认的模式
- 关联:统计与当前资源相关的另一个资源,触发阈值时,对当前资源限流
- 链路:统计从某个请求来源访问到本资源的请求,触发阈值时,对请求来源限流
6. 限流的流控效果有哪些?
- 快速失败:QPS超过阈值时,拒绝新的请求
- warm up: QPS超过阈值时,拒绝新的请求;QPS阈值是逐渐提升的,可以避免冷启动时高并发导致服务宕机。
- 排队等待:请求会进入队列,按照阈值允许的时间间隔依次执行请求;如果请求预期等待时长大于超时时间,直接拒绝
7. Sentinel实现限流的原理是什么?
Sentinel主要通过滑动窗口算法进行限流。也就是通过维护一个滑动窗口,对这个窗口内的请求进行限流。
限流常用算法:
- 固定窗口:在固定时间内限制请求的数量。缺点是在两个窗口临界点容易造成请求高峰
- 滑动窗口:维护一个滑动窗口,对整个窗口内的请求限流。切分的越细,流量越平滑。缺点是无法承接突发流量,且切分太细对系统性能要求高。
- 漏桶:请求都进入桶中,桶的容量就是最大承接的请求量,再以恒定的速度放出请求。缺点面对突发流量的时候,漏桶还是循规蹈矩的处理请求。
- 令牌桶:往桶中以恒定的速率放入令牌,请求来的时候,从桶中获取令牌。拿到令牌可以正常处理,否则丢弃请求。好处是可以控制令牌生成速度和桶大小进行精准的限流,且能承接突发的请求。
8. 什么是降级熔断?Sentinel实现熔断降级的原理是什么?
- 降级:关闭某些服务接口或者页面,以保证核心服务可用。被动降级是限流或熔断导致的降级,主动降级指的是关闭评论、广告等不重要功能保证核心服务可用。(关闭一部分功能)
- 熔断:当某些服务异常比例过高,则及时熔断此微服务的调用,快速返回错误响应信息。防止雪崩的发生。(直接拦截该服务所有请求)
Sentinel熔断的原理:
其思路是由断路器统计服务调用的异常比例、慢请求比例,如果超出阈值则会熔断该服务。即拦截访问该服务的一切请求;而当服务恢复时,断路器会放行访问该服务的请求。
断路器控制熔断和放行是通过状态机来完成的:
状态机包括三个状态:
- Closed:关闭状态,断路器放行所有请求,并开始统计异常比例、慢请求比例。超过阈值则切换到open状态
- Open:打开状态,服务调用被熔断,访问被熔断服务的请求会被拒绝,快速失败,直接走降级逻辑。Open状态5秒后会进入half-open状态
- Half-open:半开状态,放行一次请求,根据执行结果来判断接下来的操作。
- 请求成功:则切换到Closed状态
- 请求失败:则切换到Open状态
断路器熔断策略有三种:慢调用、异常比例、异常数
9. 项目中使用熔断降级吗?
在阿里的compass项目中用过,compass系统是tam(对客的技术服务经理,技术客服)在线工作平台,给客户做的所有交付、扩容、变更都要在这个平台上落工单。如果阿里云做活动,工单量就会激增,那必然需要提前配置熔断降级的策略。
- 熔断:比如配置某个服务的异常比例达到阈值就熔断
- 降级:优先保对客的功能,对tam自己操作的功能进行降级
d10. Sentinel限流、降级的异常父类是谁?
Sentinel限流、熔断抛出的都是FlowLimiting,这样并不友好,因此最好自定义异常。
自定义异常需要实现BlockExceptionHandler接口中的handler(),判断形参的异常类型,设置合适的msg,通过response返回给前端。
更多推荐
所有评论(0)