为什么用springcloud,和传统rpc相比有什么好处?和dubbo相比呢?
一.答:在传统rpc(如httpclient)远程调用中,服务与服务依赖关系,管理比较复杂,所以需要使用
服务治理,管理服务与服务之间依赖关系,可以实现
1.服务调用、负载均衡、容错等;(注意是本地负载均衡,即:调用者拿到服务方调用信息之后,就像本地调用一样的使用调用方法。和传统nginx负载均衡是有区别的)
2.实现服务注册与发现。(
服务提供者会把当前自己服务器的信息 比如服务地址通讯地址等以别名方式注册到注册中心上;
调用者以别名的方式去注册中心上获取到实际的服务器的信息,然后在实现本地rpc调用远程
还有一个很好的优点,动态注册与发现,即服务注册中心不用重启,提供者可以开启一个新的服务,注册中心会检测到它。
)
二.答:Dubbo仅仅是一个实现了远程调用的RPC框架,服务化的中间件则需要自己开发;而SpringCloud则是实施微服务的一系列套件,包括:远程调用负载均衡、服务注册与发现、断路器服务保护、服务状态监控、分布式配置中心、智能路由网关、一次性令牌、全局锁、分布式会话管理、集群状态管理等
springcloud和dubbo组件运行流程对比
下图中的每个组件都是需要部署在单独的服务器上,gateway用来接受前端请求、聚合服务,并批量调用后台原子服务。每个service层和单独的DB交互。
▲Dubbo组件运行流程
- gateWay:前置网关,具体业务操作,gateWay通过dubbo提供的负载均衡机制自动完成
- Service:原子服务,只提供该业务相关的原子服务
- Zookeeper:原子服务注册到zk上
▲Spring Cloud 组件运行
Spring Cloud
- 所有请求都统一通过 API 网关(Zuul)来访问内部服务。
- 网关接收到请求后,从注册中心(Eureka)获取可用服务。
- 由 Ribbon 进行均衡负载后,分发到后端的具体实例。
- 微服务之间通过 Feign 进行通信处理业务。
点评:业务部署方式相同,都需要前置一个网关来隔绝外部直接调用原子服务的风险。Dubbo需要自己开发一套API 网关,而Spring Cloud则可以通过Zuul配置即可完成网关定制。使用方式上Spring Cloud略胜一筹。
什么是分布式,什么是集群:,什么是RPC
不同模块部署在不同服务器上,作用:分布式解决网站高并发带来问题
多台服务器部署相同应用模块构成一个集群,作用:通过负载均衡设备共同对外提供服务
RPC 是调用另一个地址空间,由于不在一个内存空间,不能直接调用就可以应用RPC框架的实现来解决
rpc远程调用框架
几种比较典型的RPC的实现和调用框架。
(1)RMI实现,利用java.rmi包实现,基于Java远程方法协议(Java Remote Method Protocol)
和java的原生序列化。
(2)Hessian,是一个轻量级的remoting onhttp工具,使用简单的方法提供了RMI的功能。 基于HTTP协议,采用二进制编解码。
(3)thrift是一种可伸缩的跨语言服务的软件框架。thrift允许你定义一个描述文件,描述数据类型和服务接口。依据该文件,编译器方便地生成RPC客户端和服务器通信代码。(4)SpringCloud 提供了快速构建分布式系统的一些工具,包括配置管理、服务发现、断路器、路由、微代理、事件总线、全局锁、决策竞选、分布式会话等等。
5)DUBBO
-------------------Eureka(自搭Eureka服务端)-------------
?工作原理(Eureka集群下)?
Applecation-server :服务提供者
Application-cliene:服务消费者
服务提供者启动后向Eureka注册,Eureka Server会将注册信息向其他Eureka Server进行同步,当服务消费者要调用服务提供者,则向服务注册中心获取服务提供者地址,然后会将服务提供者地址缓存在消费者本地,下次再调用时,则直接从本地缓存中取,完成一次调用。
?的作用或优点?
?我搭建过,如何搭建?
?搭建和使用过程中遇到哪些问题?
?Eureka 自身集群原理?
假设有三台 Eureka Server 组成的集群,第一台 Eureka Server 在北京机房,另外两台 Eureka Server 在深圳和西安机房。这样三台 Eureka Server 就组建成了一个跨区域的高可用集群。
集群相互之间通过 Replicate 来同步数据,相互之间不区分主节点和从节点,所有的节点都是平等的。
在这种架构中,节点通过彼此互相注册来提高可用性,每个节点需要添加一个或多个有效的 serviceUrl 指向其他节点。如果某台 Eureka Server 宕机,Eureka Client 的请求会自动切换到新的 Eureka Server 节点。当宕机的服务器重新恢复后,Eureka 会再次将其纳入到服务器集群管理之中。当节点开始接受客户端请求时,所有的操作都会进行节点间复制,将请求复制到其它 Eureka Server 当前所知的所有节点中。完美地解决了注册中心的稳定性和高可用性。
?Eurka集群 保证 AP?
Eureka Server 各个节点都是平等的,几个节点挂掉不会影响正常节点的工作,剩余的节点依然可以提供注册和查询服务。而 Eureka Client 在向某个 Eureka 注册时,如果发现连接失败,则会自动切换至其它节点。只要有一台 Eureka Server 还在,就能保证注册服务可用(保证可用性),只不过查到的信息可能不是最新的(不保证强一致性)。
Eureka自我保护机制是什么?目前的最好解决办法是什么?
一.答:默认情况下,是不会走自我保护机制的,会正常清除Eureka客户端(比如提供者)90秒内未发送心跳至Eureka服务端的Eureka客户端。
Eureka自我保护的产生原因:
Eureka在运行期间会统计心跳失败的比例,短时间内大量出现(在15分钟内是否低于85%)客户端和服务端之间中断无法通讯,走自我保护机制,不再删除服务注册表中的数据。也就是不会注销任何微服务。
二.答:
开发过程中关闭,生产打开
Eureka Server端:配置关闭自我保护,并按需配置Eureka Server清理无效节点的时间间隔。
eureka.server.enable-self-preservation# 设为false,关闭自我保护
eureka.server.eviction-interval-timer-in-ms # 清理间隔(单位毫秒,默认是60*1000)
Eureka Client端:配置开启健康检查,并按需配置续约更新时间和到期时间
eureka.client.healthcheck.enabled# 开启健康检查(需要spring-boot-starter-actuator依赖)
eureka.instance.lease-renewal-interval-in-seconds# 续约更新时间间隔(默认30秒)
eureka.instance.lease-expiration-duration-in-seconds # 续约到期时间(默认90秒)
Eureka与zookeeper/consul的特点区别?分别怎么使用?
一个分布式系统不可能同时满足C(一致性)、A(可用性)和P(分区容错性)。
一.答:
Zookeeper和Consul :CP设计,保证了一致性,集群中,某个节点失效,则会选举出新的主节点leader;但半数以上节点不可用,则无法提供服务,因此可用性没法满足
Eureka:AP原则,无主从节点,一个节点挂了,自动切换其他节点可以使用,去中心化;eureka大量因网络通讯中断(可用低于85%)是不会删宕机节点,就是它的自我保护机制(还是会返回错误页)。
如果要求一致性,则选择zookeeper、Consul,如金融行业----集群同步来保证一致性
如果要求可用性,则Eureka,如电商系统----节点通过彼此互相注册来提高可用性
二.答:用法区别:
注册中心的客户端,把配置里的eureka:相关属性,换成spring:cloud:zookeeper:或spring:cloud:consul的属性;把启动类的注解@EnableEurekaClient换成@EnableDiscoveryClient
注册中心的服务端,(eureka就是个servlet程序,跑在servlet容器中,)eureka需要单独运行java系统运行服务端;(Consul则是go编写而成) ,Consul和zk都是下载第三方工具运行服务端
-------------------Ribbon和feign(只存在于客户端)-------------
?Ribbon与Nginx区别?
服务器端负载均衡Nginx
nginx是客户端所有请求统一交给nginx,由nginx进行实现负载均衡请求转发,属于服务器端负载均衡(软负载均衡,即Nginx软件)。
请求由nginx服务器端进行转发。适合于Tomcat
客户端负载均衡Ribbon
Ribbon是从eureka注册中心服务器端上获取服务注册信息列表,缓存到本地,让后在本地实现轮训负载均衡策略。
既在客户端实现负载均衡。适合于微服务中RPC远程调用实现本地服务负载均衡,如Dubbo、SpringCloud
?Ribbon与feign区别?
选择feign来进行负载均衡:
原因有以下几点:
1. feign本身里面就包含有了ribbon
2. feign不需要借用restTemplate调用提供者,自身底层默认包含httpurlconnection去调用提供者,写起来更加思路清晰和方便
3. fegin是一个采用基于接口和注解的编程方式,更加简便
?Ribbon如何配置超时时间?(要主动设置,不要去依赖服务器的超时)
ribbon:ConnectTimeout 建立连接所用的时间
ribbon:ReadTimeout 服务器读取到可用资源
? Ribbon组件工作原理?
1、调用者首先通过@LoadBalanced注解放在RestTemplate实例方法上,注解里面的intercept方法,拦截RestTemplate的每一次HTTP请求,在里面来实现负载均衡、别名切换成服务地址。
2、用RestTemplate的调用方式,以别名方式调用提供者接口,实际上@LoadBalanced里有拦截处理负载、切换别名等。
? feign组件工作原理?
1、调用者首先通过@EnableFeignCleints注解开启扫描FeignCleint(第3步启动会扫描)
2、调用者根据Feign的规则在本地写个接口类去继承但不实现提供者的接口(这样以少重写里面的方法;你若不继承重写一个提供者相同的方法也行)(提供者肯定是pom工程可以被引用),并加注解@FeignCleint(value="提供者服务别名",fallback=本地某个降级类或当前类指定任意方法),这里提一下本地某个降级类,必须需要重写一个和提供者方法名相同的方法,一般建议用它,因为服务隔离新线程池范围仅限执行调用者方法那一步。
3、调用者程序启动后,会进行扫描所有的@FeignCleint的注解的类,并将其注入到ioc容器中。(因为第1步加注解了)
4、当调用者本地继承的接口方法被调用,通过jdk的动态代理(注解@FeignCleint),来生成具体的请求对象RequesTemplate
5、RequestTemplate再生成Request
6、Request交给Client去处理,其中Client默认是HttpUrlConnection去处理(也可以是HttpClient或Okhttp,需要配置)
7、最后Client被封装到LoadBalanceClient类,这个类结合类Ribbon做到了负载均衡。拿到远程调用的结果返回。(这里再提一下,是通过别名从Eureka拿到的具体的提供者端口列表,才能远程调用的)
? Feign的作用或功能?
将服务提供者服务接口暴露出来,方便调用者调用。@FeignCleint注解暴露提供服务别名
2、配合服务降级熔断。
3、负载均衡,因为集成了Ribbon,最后要调的Client被封装到LoadBalanceClient类。(用ribbon的话,还得单独加这个负载均衡注解) 4、省却了feign中转码编码的过程,同时将接口和实现都整合成一个对象,更加符合面向对象的编程方法
服务提供者和调用者都在启动类加上@EnableFeignClients,提供者只需要暴露接口,由调用者来实现该接口比如实现类d2,但要加 @FeignClient("app-itmayiedu-member")来指明要用httpclient调提供者的哪个服务,如果没有这个就没有远程调用,调用方想调提供者接口时就调到自已写的实现类d2了。 @FeignClient("app-itmayiedu-member")这个注解下的接口服务提供者的实现类要写在调用者的系统里的原因是:方便做服务降级熔断(比如网络中断,提供者是无法返回降级页面,只能由调用者提供)
?Ribbon与feign你搭建过吗,如何搭建?(就是加几个注解看一下就行,重点背原理)
?feign搭建和使用过程中遇到哪些问题?
1)有一些注解并不支持,如@GetMapping,@PutMapping 等,仅支持使用@RequestMapping 等。后来看源码才发现,Spring Cloud 没有基于Spring MVC 全部注解来做Feign 客户端注解协议解析,
个人认为这个是一个不小的坑。
2)默认会使用Java HttpURLConnection 进行Http请求,每次访问时都会创建一个 Connection对象,这种代价是很大。这也解释了Feign默认情况下性能不高的问题。
可以使用OkHttp3进行Http请求,这样消耗时间基本花费在处理Http请求上,像对象处理、数据转换消耗的时间基本上可以做到忽略不计。
-------------------Hystrix断路器(Hystrix只支持放在调用端做降级等)-------------
“服务熔断”和“服务降级”的类似性和区别?
类似性:
目的很一致,都是从可用性可靠性着想,为防止系统的整体缓慢甚至崩溃,采用的技术手段;
最终表现类似,对于两者来说,最终让用户体验到的是某些功能暂时不可达或不可用;
粒度一般都是服务级别,当然,业界也有不少更细粒度的做法,比如做到数据持久层(允许查询,不允许增删改);
自治性要求很高,熔断模式一般都是服务基于策略的自动触发,降级虽说可人工干预,但在微服务架构下,完全靠人显然不可能,开关预置、配置中心都是必要手段;
区别:
看下图里有说明区别,Hystrix工作原理的图
?Hystrix工作原理?(或者问断路器实现服务保护的原理)
把三个都答出来,一般三个一起用的:服务降级、服务熔断、服务隔离
?Hystrix的作用或功能?
通过注解@HystrixCommand(fallbackMethod = "降级方法名")// 默认开启线程池隔离方式,服务降级(默认1秒就超时走降级方法),服务熔断
隔离(线程池隔离和信号量隔离):限制调用分布式服务的资源使用,某一个调用的服务出现问题不会影响其他服务调用。
优雅的降级机制:超时降级、资源不足时(线程或信号量)降级,降级后可以配合降级接口返回托底数据。
融断:当失败率达到阀值自动触发降级(如因网络故障/超时造成的失败率高),熔断器触发的快速失败会进行快速恢复。
缓存:提供了请求缓存、请求合并实现。支持实时监控、报警、控制(修改配置)
?你搭建过吗,如何搭建?
Hystrix只支持放在调用端做降级等,
Hystrix的两种方式:fallback=本地某个降级类或当前类指定任意名称的方法,如下图的4.1,4.2.
这里提一下本地某个降级类,必须需要重写一个和提供者方法名相同的方法,一般建议用它,因为服务隔离新线程池范围仅限执行调用者方法那一步。
服务雪崩的应对策略?
1.流量控制:nginx+Lua的网关进行流量控制
2.改进缓存模式:缓存预加载、同步改为异步刷新
3.服务调用者降级服务:
-------------------分布式配置中心(自搭配置服务端)-------------
?Cloud分布式配置中心-工作原理?
简单看过,配置服务器pull git上最新变化值的源码:@EnableConfigServer注解跟进去之后,里面有个方法refresh(String label) 会去执行git的pull请求。(spring-cloud-config-server这个Pom引用包里面自已内嵌了jgit的pom引用)。
如果改动配置,默认是需要重启服务才能刷新。但是有两种方式不用重启服务就可加载新值:
手动---actuator开启监控断点pom及配置,引用refreshscope注解
自动---BUS开启消息队列总线
这里提一下bus和手动的对比,手动需要每个服务都调一下,几百个服务太麻烦了,所以最后还是引入bus消息总线,调一个服务,其他服务会通过发布-订阅方式全部刷新配置。
顺便讲一下消息总线BUS实时刷新配置原理:
配置服务端和所有配置客户端都需要引入spring-cloud-starter-bus-amqp和队列集群,
配置客户端需要引入监控断点spring-boot-starter-actuator和队列集群,开启监控断点为bus刷新方式(手动的是*方式)。include: bus-refresh
配置好之后,启动客户端时会默认绑定要同一个bus关联名称的交换机上面,构成发布到一个交换机,多个订阅模式。
?分布式配置中心-的作用?
?cloud.config你搭建过吗,如何搭建?
没有单独的注解,cloud.config只要配置了,配置客户端启动就会通过配置服务器把值从git加载进配置客户端JVM,配置客户端这里就能用了。看第二张图有追加说明
如果要开启手动刷新,需要注意引用监控中心Pom包,开启所有监控中心接口才能用手动刷新配置接口;
还有,zuul配置加上refreshscope注解能实现动态实时刷新。
?搭建和使用过程中遇到哪些问题?
1、默认不实时刷新----解决:手动去刷新是最好的。还有一种方法是:标有@RefreshScope的Bean将得到特殊处理来实时生效配置
2、生产和测试环境没有分开,配置混乱问题----解决:不同环境分离、不同项目分离
-------------------bus消息总线-------------
?工作原理?
顺便讲一下消息总线BUS实时刷新配置原理:
一般bus是与cloud config整合,以bus集成的RabbitMq作为消息代理,实现了应用配置的动态更新。
集成了队列,比如mq,采用发布订订阅模式。
手动去调一个服务A拉取到配置改动(访问/bus/refresh接口),A会发布消息总线的队列,其他订阅监听事件的服务会接收变更事件消息,也会去消费拉取一次最新的配置。
概念及作用
bus整合java的事件处理机制和消息中间件的发送和接收,主要是由发送端、接收端和事件组成。
避免了机器太多,人工参与麻烦
?我搭建过,如何搭建?
配置服务端和所有配置客户端都需要引入spring-cloud-starter-bus-amqp和队列集群,
配置客户端需要引入监控断点spring-boot-starter-actuator和队列集群,开启监控断点为bus刷新方式(手动的是*方式)。include: bus-refresh
配置好之后,启动客户端时会默认绑定要同一个bus关联名称的交换机上面,构成发布到一个交换机,多个订阅模式
------------------stream 消息驱动(整合mq/kafka)(生产者和消费者各自注解整合就行)-------------
?stream工作原理?
提供一个中间层,实现了应用程序与消息中间件细节之间的隔离。使应用程序不需要再考虑各种不同的消息中间件的实现。当需要升级消息中间件,或者是更换其他消息中间件产品时,我们需要做的就是更换对应的Binder绑定器而不需要修改任何应用逻辑 。
?我搭建过,如何搭建?
?搭建和使用过程中遇到哪些问题?
消费组
集群部署启动了两个应用的实例,消息被重复消费了两次。为解决这个问题,Spring Cloud Stream 中提供了消费组,通过配置 spring.cloud.stream.bindings.myInput.group 属性为应用指定一个组名,同一组的只能有一个消费成功。
-------------------Zuul(某个微服务做为zuul,自已整合zuul路由filter等)-------------
?工作原理?
zuul的所有功能都是基于过滤器Filter去实现的。
启动类加上@EnbaleZuulProxy,里面有ZuulFilter(里面默认开启了Ribbon本地负载均衡功能)
写一个自定义类来继承ZuulFilter抽象类,来做一些过滤功能:
登录验证和安全性--自定义写
动态智能路由----application.yml或配置中心配置路由转发,将请求routes到不同的提供者服务集群,实现反向代理。
Zuul限流----漏桶算法/令牌算法
负载均衡----里面默认开启了Ribbon本地负载均衡功能
饥饿加载----开启zuul:ribbon的饥饿加载配置(可以启动加载完,后面每次调用体验快)
重试机制----引入spring-retry包,打开重试机制配置(网关调其他提供者时,请求失败就会重试)
洞察和监控——--在边缘跟踪有意义的数据和统计数据
聚合API接口,统一接口转发
?的作用?
同上
?我搭建过,如何搭建?
在网关那个系统,加上注解@EnableZuulProxy// 开启网关代理,配上各服务提供者的路由信息。
Zuul版本与Cloud Gateway关系及时间线
Gateway只是一个网关的统称,目前较新的包括Cloud Gateway和Zuul2,发展时间线如下:
SpringBoot1.0自带集成的Zuul1的IO采用的是BIO,
Cloud基于SpringBoot2.0推出了基于NIO模型的Cloud Gateway来取代Zuul1。
然后支持NIO的Zuul2后发布,没有默认集成SpringBoot2.0,使用NIO对Zuul1进行了重构,如果要升级Zuul1至Zuul2的话,得先升级到SpringBoot2.0,并单独引入Zuul2的版本依赖(还不如直接用SpringBoot2.0支持NIO的Cloud GateWay)
Zuul1版本原理-(类似过滤器)
Zuul框架中的核心是ZuulServlet,类似于SpringMvc的DispatcherServlet,负责路由到各个内部微服务。
ZuulServlet中有3个核心的方法,它们分别是:preRoute()前置路由,route()正式路由, postRoute()提交路由结果。
?搭建和使用过程中遇到哪些问题?
为什么不用nginx来做转发,Nginx与Zuul的区别?
(nginx来做的话,日志有点难管理;网关可以统一管理日志,aop)
Nginx是采用服务器负载均衡进行转发
Zuul依赖Ribbon和eureka实现本地负载均衡转发
相对来说Nginx功能比Zuul功能更加强大,能够整合其他语言比如lua脚本实现强大的功能,同时Nginx可以更好的抗高并发,Zuul网关适用于请求过滤和拦截等。
注解api,网关统一收集
-------------------Swagger2(每个服务注解api,网关统一收集)-------------
?工作原理?
?的作用?
如果人工单独去更新API文档,久而久之,很容易出现和代码不一致的问题。
1.功能丰富:支持多种注解,自动生成接口文档界面,支持在界面测试API接口功能;
2.及时更新:开发过程中花一点写注释的时间,就可以及时的更新API文档,省心省力;
3.整合简单:通过添加pom依赖和简单配置,内嵌于应用中就可同时发布API接口文档界面,不需要部署独立服务。
?我搭建过,如何搭建?
-------------------监控中心Actuator+可视化AdminUI(自搭AdminUI服务端)-------------
?工作原理?
先运行一个独立的监控AdminUI服务器,在所有微服务里打开监控配置并注册到AdminUI服务器的地址。
实现将所有服务的监控中心管理存放在admin ui平台上.
?的作用或优点?
微服务器监控、服务器内存变化(堆内存,线程,日志管理等)、检测服务配置连接池是否可用(模拟访问、懒加载)、统计现有Bean(通过Spring容器)、Http接口(@RequestMapping)的一系列数据管理。Actuator监控应用只通过JSON形式返回数据统计结果,没有UI界面处理;AdminUI则内置Actuator服务监控,并对返回JSON数据进行图形化处理展示。
?我搭建过,如何搭建?
?搭建和使用过程中遇到哪些问题?
接口调用,返回JSON格式的信息。
解决:可以用Admin-UI,进行图形化处理展示。
--------------Sleuth+Zipkin(底层集成了RabbitMQ)(Zipkin UI服务端是个JAR,运行即可;zipkin客户端配置一下zipkin和Sleuth)-------------
?链路监控服务跟踪工作原理?(Sleuth+MQ+Zipkin+ES)
服务跟踪原理
一、Sleuth作用:为了实现请求跟踪,当请求发送到分布式系统的入口端点时, 服务跟踪框架为该请求创建一个唯的跟踪标识Trace ID放在请求头里, 保持传递该唯一标识, 直到返回给请求方为止。通过Trace ID的记录,我们就能将所有请求过程的日志关联起来。 为了统计各处理单元的时间延迟,当请求到达各个服务组件时,或是处理逻辑到达某个状态时,创建唯一 标识Span ID来标记各个服务组件的开始、 具体过程以及结束。对于每个Span来说,它必须有开始和结束两个节点,通过记录开始Span和结束Span的时间戳,就能统计出该Span的时间延迟,除了时间戳记录之外,它还可以包含一些其他元数据, 比如事件名称、请求信息等
SpanId记录每一次请求, TraceID记录整个调用链全局ID
二、Zipkin作用:Sleuth收集事件、请求信息等,通过MQ通配符方式,多往一方式(zipkin消费),发送给Zipkin服务器,Zipkin服务器有两个作用:
把Sleuth收集的信息,从MQ读出来,然后存在数据库ES里
在UI界面访问Zipkin服务器去读取ES的数据。
?的作用或优点?
背景原因:微服务系统变得越来越大,调用关系越来越复杂,某个服务出现网络延迟过高或发送错误导致请求失败,这个时候,查询日志分析问题就变得很复杂。
Sleuth 可以对请求调用进行链路监控,提供了分布式服务链路监控的解决方案。
?我搭建过,如何搭建?
搭建Zipkin集成RabbitMQ异步传输:
1、运行Zipkin链路监控服务端的JAR,就可以访问Zipkin服务器UI了,
2、然后配置链路监控客户端。(客户端收集信息传给zipkin)
服务启动时,加载流程:
1、启动RabbitMQ
2、启动Zipkin(自动会创建一个Zipkin 队列)
3、启动ZipkinClient以队列形式异步传输