Spring Cloud分布式架构总结
一、远程调用服务的模式1、RPC:同技术栈,基于语言的API2、HTTP:平台、语言无关性,基于应用来定义二、Spring Cloud-Eureka1、涉及到的组件(一部分)Eureka:注册中心Zuul:服务网关(不再维护,可以使用spring-gateway来代替)Ribbon:负载均衡Feign:服务调用Hystrix:熔断器springcloud和springboot版本存在一一对应关系:
本文目录
一、远程调用服务的模式
1、RPC:同技术栈,基于语言的API
2、HTTP:平台、语言无关性,基于应用来定义
二、Spring Cloud-Eureka
1、涉及到的组件(一部分)
-
Eureka:注册中心
-
Zuul:服务网关(不再维护,可以使用spring-gateway来代替)
-
Ribbon:负载均衡
-
Feign:服务调用
-
Hystrix:熔断器
springcloud和springboot版本存在一一对应关系:
Release Train | Boot Version |
---|---|
Hoxton | 2.2.x |
Greenwich | 2.1.x |
Finchley | 2.0.x |
Edgware | 1.5.x |
Dalston | 1.5.x |
Spring提供了一个RestTemplate模板工具类,对基于HTTP的客户端进行了封装,并且实现了对象与json的序列化和反序列化,非常方便。RestTemplate并没有限定HTTP的客户端类型,而是进行了抽象,目前常用的3种都有支持:
- HTTPClient <= apache
- OkHTTP
- JDK原生的URLConnection(默认的)
//Bean注解默认生成的对象名为方法名
@Bean
public RestTemplate restTemplate(){
return new RestTemplate();
}
也可以使用HTTPClient和OkHTTP,需要引入相应的依赖,并将HTTPClient和OkHTTP作为参数传入new RestTemplate()构造方法中。
服务提供者(json) => 服务调用者(object) => 用户(json)
1、Eureka
就是服务注册中心(可以是一个集群),对外暴露自己的地址
负载均衡算法:随机或轮询
Eureka架构中的三个核心角色:
-
服务注册中心
Eureka的服务端应用,提供服务注册和发现功能,就是刚刚我们建立的eureka-server
-
服务提供者
提供服务的应用,可以是Spring Boot应用,也可以是其它任意技术实现,只要对外提供的是REST风格服务即 可。本例中就是我们实现的user-service
-
服务消费者
消费应用从注册中心获取服务列表,从而得知每个服务方的信息,知道去哪里调用服务方。本例中就是我们 实现的consumer-demo
2、高可用的的Eureka Server
Eureka Server即服务的注册中心,在刚才的案例中,我们只有一个EurekaServer,事实上EurekaServer也可以是 一个集群,形成高可用的Eureka中心 。
Eureka Server是一个web应用,可以启动多个实例(配置不同端口)保证Eureka Server的高可用
服务同步
多个Eureka Server之间也会互相注册为服务,当服务提供者注册到Eureka Server集群中的某个节点时,该节点会 把服务的信息同步给集群中的每个节点,从而实现数据同步。因此,无论客户端访问到Eureka Server集群中的任 意一个节点,都可以获取到完整的服务列表信息。
而作为客户端,需要把信息注册到每个Eureka中
3、Eureka客户端和服务端配置
-
Eureka客户端工程
-
user-service 服务提供
- 服务地址使用ip方式 —— 影响serviceInstance.getHost()
- 续约
-
consumer-demo 服务消费
- 获取服务地址的频率
-
-
Eureka服务端工程
- eureka-server 失效剔除
- 自我保护
二、Spring Cloud-Ribbon
在刚才的案例中,我们启动了一个user-service,然后通过DiscoveryClient来获取服务实例信息,然后获取ip和端口来访问。
但是实际环境中,我们往往会开启很多个user-service的集群。此时我们获取的服务列表中就会有多个,到底该访问哪一个呢?
一般这种情况下我们就需要编写负载均衡算法,在多个实例列表中进行选择。
不过Eureka中已经帮我们集成了负载均衡组件:Ribbon,简单修改代码即可使用。
什么是Ribbon:
三、Spring Cloud-Hystrix
1.服务器雪崩
Hystix是Netflix开源的一个延迟和容错库,用于隔离访问远程服务,防止出现级联失败。
服务器支持的线程和并发数有限,请求一直阻塞,会导致服务器资源耗尽,从而导致所有其它服务都不可用,形成雪崩效应。
这就好比,一个汽车生产线,生产不同的汽车,需要使用不同的零件,如果某个零件因为种种原因无法使用,那么 就会造成整台车无法装配,陷入等待零件的状态,直到零件到位,才能继续组装。 此时如果有很多个车型都需要这个零件,那么整个工厂都将陷入等待的状态,导致所有生产都陷入瘫痪。一个零件的波及范围不断扩大。
Hystrix解决雪崩问题的手段,主要包括:
- 线程隔离
- 服务降级
2.线程隔离&服务降级
服务降级虽然会导致请求失败,但是不会导致阻塞,而且最多会影响这个依赖服务对应的线程池中的资源,对其它服务没有响应。
触发Hystrix服务降级的情况:
- 线程池已满
- 请求超时
3.服务降级
要注意;因为熔断的降级逻辑方法必须跟正常逻辑方法保证:相同的参数列表和返回值声明。
失败逻辑中返回User对象没有太大意义,一般会返回友好提示。所以把queryById的方法改造为返回String, 反正也是Json数据。这样失败逻辑中返回一个错误说明,会比较方便。
刚才把fallback写在了某个业务方法上,如果这样的方法很多,那岂不是要写很多。所以可以把Fallback配置加在 类上,实现默认fallback;
在之前的案例中,请求在超过1秒后都会返回错误信息,这是因为Hystrix的默认超时时长为1,我们可以通过配置 修改这个值;
4.服务熔断
熔断原理:
在服务熔断中,使用的熔断器,也叫断路器,其英文单词为:Circuit Breaker 熔断机制与家里使用的电路熔断原理类似;当如果电路发生短路的时候能立刻熔断电路,避免发生灾难。在分布式系统中应用服务熔断后;服务调用方可以自己进行判断哪些服务反应慢或存在大量超时,可以针对这些服务进行主动熔断,防止整个系统被拖垮。 Hystrix的服务熔断机制,可以实现弹性容错;当服务请求情况好转之后,可以自动重连。通过断路的方式,将后续请求直接拒绝,一段时间(默认5秒)之后允许部分请求通过,如果调用成功则回到断路器关闭状态,否则继续打开,拒绝请求的服务。
不过,默认的熔断触发要求较高,休眠时间窗较短,为了测试方便,我们可以通过配置修改熔断策略;
四、Spring Cloud-Feign
在前面的学习中,我们使用了Ribbon的负载均衡功能,大大简化了远程调用时的代码:
String baseUrl = "http://user-service/user/";
User user = this.restTemplate.getForObject(baseUrl + id, User.class)
如果就学到这里,你可能以后需要编写类似的大量重复代码,格式基本相同,无非参数不一样。有没有更优雅的方式,来对这些代码再次优化呢?
这就是我们接下来要学的Feign的功能了。
1.Feign
为什么叫伪装? Feign可以把Rest的请求进行隐藏,伪装成类似SpringMVC的Controller一样。你不用再自己拼接url,拼接参数等等操作,一切都交给Feign去做。
完全使用SpringMVC的注解来生成url
在 ConsumerApplication 启动类上,添加注解,开启Feign功能
Feign中已经自动集成了Ribbon负载均衡,因此不需要自己定义RestTemplate进行负载均衡的配置
2.feign-ribbon负载均衡
Fegin内置的ribbon默认设置了请求超时时长,默认是1000,我们可以通过手动配置来修改这个超时时长;
因为ribbon内部有重试机制,一旦超时,会自动重新发起请求。如果不希望重试,可以添加配置;
3.Feign默认也有对Hystrix的集成
只不过,默认情况下是关闭的,需要手动开启。
(1) 首先要定义一个类,实现刚才编写的UserFeignClient,作为fallback的处理类,继承UserClient。同样需要保证实现的queryById()方法返回值和参数与接口中保持一致。
(2) 然后在UserClient中,指定刚才编写的实现类
4.请求压缩
Spring Cloud Feign 支持对请求和响应进行GZIP压缩,以减少通信过程中的性能损耗。通过下面的参数即可开启请求与响应的压缩功能。
5.日志级别
前面讲过,通过 logging.level.lxs.xx=debug 来设置日志级别。然而这个对Fegin客户端而言不会产生效果。因为 @FeignClient 注解修改的客户端在被代理时,都会创建一个新的Fegin.Logger实例。我们需要额外指定这个日志的级别才可以。
这里指定的Level级别是FULL,Feign支持4种级别:
- NONE:不记录任何日志信息,这是默认值。
- BASIC:仅记录请求的方法,URL以及响应状态码和执行时间
- HEADERS:在BASIC的基础上,额外记录了请求和响应的头信息
- FULL:记录所有请求和响应的明细,包括头信息、请求体、元数据。
五、Spring Cloud-Gateway
1.Gateway网关
- Spring Cloud Gateway是Spring官网基于Spring 5.0、 Spring Boot 2.0、Project Reactor等技术开发的网关服务。
- Spring Cloud Gateway基于Filter链提供网关基本功能:安全、监控/埋点、限流等。
- Spring Cloud Gateway为微服务架构提供简单、有效且统一的API路由管理方式。
- Spring Cloud Gateway是替代Netflix Zuul的一套解决方案。
Spring Cloud Gateway组件的核心是一系列的过滤器,通过这些过滤器可以将客户端发送的请求转发(路由)到对应的微服务。 Spring Cloud Gateway是加在整个微服务最前沿的防火墙和代理器,隐藏微服务结点IP端口信息, 从而加强安全保护。Spring Cloud Gateway本身也是一个微服务,需要注册到Eureka服务注册中心。
网关的核心功能是:过滤和路由
gaetway的鉴权依靠assert
- 路由(route) 路由信息的组成:由一个ID、一个目的URL、一组断言工厂、一组Filter组成。如果路由断言为 真,说明请求URL和配置路由匹配。
- 断言(Predicate) Spring Cloud Gateway中的断言函数输入类型是Spring 5.0框架中的 ServerWebExchange。Spring Cloud Gateway的断言函数允许开发者去定义匹配来自于HTTP Request中的任何信息比如请求头和参数。
- 过滤器(Filter) 一个标准的Spring WebFilter。 Spring Cloud Gateway中的Filter分为两种类型的Filter,分 别是Gateway Filter和Global Filter。过滤器Filter将会对请求和响应进行修改处理。
2.面向服务的路由
在刚才的路由规则中,把路径对应的服务地址写死了!如果同一服务有多个实例的话,这样做显然不合理。 应该根据服务的名称,去Eureka注册中心查找服务对应的所有实例列表,然后进行动态路由!
3.路由前缀
客户端的请求地址与微服务的服务地址如果不一致的时候,可以通过配置路径过滤器实现路径前缀的添加和去除。
添加前缀:在gateway中可以通过配置路由的过滤器PrefixPath,实现映射路径中地址的添加;
去除前缀:在gateway中可以通过配置路由的过滤器StripPrefix,实现映射路径中地址的去除;
4.过滤器
Gateway作为网关的其中一个重要功能,就是实现请求的鉴权。而这个动作往往是通过网关提供的过滤器来实现的。前面的路由前缀章节中的功能也是使用过滤器实现的。
Gateway自带过滤器有几十个,常见自带过滤器有:
过滤器名称 | 说明 |
---|---|
AddRequestHeader | 对匹配上的请求加上Header |
AddRequestParameters | 对匹配上的请求路由添加参数 |
AddResponseHeader | 对从网关返回的响应添加Header |
StripPrefix | 对匹配上的请求路径去除前缀 |
可以配置局部默认过滤器(作用上算全局过滤),对所有路由都生效
全局过滤器:不需要在配置文件中配置,作用在所有的路由上;实现 GlobalFilter 接口即可。
执行生命周期:类似Spring MVC的拦截器有两个:“pre” 和 “post”。“pre”和 “post” 分别会在请求被执行前调用和被执行后调用。(Spring MVC多出一个调用后环节)
使用场景:
-
请求鉴权:一般 GatewayFilterChain 执行filter方法前,如果发现没有访问权限,直接就返回空。
-
异常处理:一般 GatewayFilterChain 执行filter方法后,记录异常并返回。
-
服务调用时长统计: GatewayFilterChain 执行filter方法前后根据时间统计。在执行filter方法前后各自记录一个时间戳,时间戳的差值就是服务调用时长。
5.自定义过滤器
自定义过滤器分为自定义局部过滤器和自定义全局过滤器
6.自定义全局过滤器
直接在浏览器中无法模拟请求头携带token发送,需要用到postman辅助测试
7.负载均衡和熔断
Gateway中默认就已经集成了Ribbon负载均衡和Hystrix熔断机制。但是所有的超时策略都是走的默认,比如熔断超时时间只有1S,很容易就触发了。因此建议手动进行配置;
8.Gateway跨域配置
9.Gateway的高可用
启动多个Gateway服务,自动注册到Eureka,形成集群。如果是服务内部访问,访问Gateway,自动负载均衡,没问题。
但是,Gateway更多是外部访问,PC端、移动端等。它们无法通过Eureka进行负载均衡,那么该怎么办? 此时, 可以使用其它的服务网关,来对Gateway进行代理。比如:Nginx
10.Gateway与Feign的区别
- 对外接口:Gateway 作为整个应用的流量入口,接收所有的请求,如PC、移动端等,并且将不同的请求转发至不同的处理微服务模块,其作用可视为nginx;大部分情况下用作权限鉴定、服务端流量控制;
- 微服务间的内部互访:Feign 则是将当前微服务的部分服务接口暴露出来,并且主要用于各个微服务之间的服务调用。
六、Spring Cloud-Config
1.分布式配置中心
在分布式系统中,由于服务数量非常多,配置文件分散在不同的微服务项目中,管理不方便。为了方便配置文件集中管理,需要分布式配置中心组件。在Spring Cloud中,提供了Spring Cloud Config,它支持配置文件放在配置服务的本地,也支持放在远程Git仓库(GitHub、码云)。
使用Spring Cloud Config配置中心后的架构如下图:
配置中心本质上也是一个微服务,同样需要注册到Eureka服务注册中心!
2.获取配置中心配置
bootstrap和application的区别
-
bootstrap.yml文件也是Spring Boot的默认配置文件,而且其加载的时间相比于application.yml更早。
-
application.yml和bootstrap.yml虽然都是Spring Boot的默认配置文件,但是定位却不相同。bootstrap.yml 可以理解成系统级别的一些参数配置,这些参数一般是不会变动的。application.yml 可以用来定义应用级别 的参数,如果搭配 spring cloud config 使用,application.yml 里面定义的文件可以实现动态替换。
-
总结就是,bootstrap.yml文件相当于项目启动时的引导文件,内容相对固定。application.yml文件是微服务 的一些常规配置参数,变化比较频繁。
七、Spring Cloud Bus服务总线
1.仍然留存的问题
通过查看用户微服务控制台的输出结果可以发现,我们对于Git仓库中配置文件的修改并没有及时更新到用户微服务,只有重启用户微服务才能生效。
如果想在不重启微服务的情况下更新配置该如何实现呢? 可以使用Spring Cloud Bus来实现配置的自动更新。
需要注意的是Spring Cloud Bus底层是基于RabbitMQ实现的,默认使用本地的消息队列服务,所以需要提前启动本地RabbitMQ服务(安装RabbitMQ以后才有),如下:
2.Spring Cloud Bus
Spring Cloud Bus是用轻量的消息代理将分布式的节点连接起来,可以用于广播配置文件的更改或者服务的监控管理。也就是消息总线可以为微服务做监控,也可以实现应用程序之间相互通信。 Spring Cloud Bus可选的消息代理有RabbitMQ和Kafka。
使用了Bus之后 :
3.Spring Cloud 完整体系架构图
更多推荐
所有评论(0)