正文
服务调用方式
常见的远程调用方式有以下2种:
RPC:Remote Produce Call远程过程调用,RPC基于Socket,工作在会话层。自定义数据格式,速度快,效率高。早期的webservice,现在热门的dubbo,都是RPC的典型代表。
Http:http其实是一种网络传输协议,基于TCP,工作在应用层,规定了数据传输的格式。现在客户端浏览器与服务端通信基本都是采用Http协议,也可以用来进行远程服务调用。缺点是消息封装臃肿,优势是对服务的提供和调用方没有任何技术限定,自由灵活,更符合微服务理念。现在热门的Rest风格,就可以通过http协议来实现。
区别:RPC的机制是根据语言的API(language API)来定义的,而不是根据基于网络的应用来定义的。如果全部采用Java技术栈,那么使用Dubbo作为微服务架构是一个不错的选择。相反,如果公司的技术栈多样化,而且你更青睐Spring家族,那么Spring Cloud搭建微服务是不二之选。在我们的项目中,会选择Spring Cloud套件,因此会使用Http方式来实现服务间调用。
Eureka注册中心
Eureka架构中的三个核心角色:
服务注册中心
Eureka的服务端应用,提供服务注册和发现功能。
服务提供者
提供服务的应用,可以是SpringBoot应用,也可以是其它任意技术实现,只要对外提供的是Rest风格服务即可。
服务消费者
消费应用从注册中心获取服务列表,从而得知每个服务方的信息,知道去哪里调用服务方。
案例:eureka注册中心,userService服务提供方,userConsumer客户消费方,userConsumer通过eureka进行远程服务调用(userService)
1.eureka注册中心
1)依赖
2)启动类
3)配置文件
2、userService服务提供方
1)依赖
2)启动类
3)配置文件
4)实体类
5)mapper接口
6)service
7)控制器
3、userConsumer客户消费方
1)依赖
2)启动类
3)配置文件
4)控制器
访问:http://localhost:8082/han01/3 可以获取user-service模块中的数据
源码:链接:https://pan.baidu.com/s/1S8aeYWbfRzXytF1fj2TRGw 提取码:r2ry
高可用的Eureka Server
Eureka Server即服务的注册中心,EurekaServer也可以是一个集群,形成高可用的Eureka中心。
服务同步
多个Eureka Server之间也会互相注册为服务,当服务提供者注册到Eureka Server集群中的某个节点时,该节点会把服务的信息同步给集群中的每个节点,从而实现数据同步。因此,无论客户端访问到Eureka Server集群中的任意一个节点,都可以获取到完整的服务列表信息。
集群搭建:假设要搭建两台EurekaServer的集群,端口分别为:10086和10087
1)修改原来的EurekaServer配置;修改 eureka-server\src\main\resources\application.yml 如下:
2)另外一台在启动的时候可以指定端口port和defaultZone配置:
-DdefaultZone=http:127.0.0.1:10087/eureka
-Dport=10087 -DdefaultZone=http:127.0.0.1:10086/eureka
3)userService进行服务注册
4)访问时,假设有一台eureka挂机,也能正常访问
Eureka客户端
服务提供者要向EurekaServer注册服务,并且完成服务续约等工作。
服务注册
服务提供者在启动时,会检测配置属性中的: eureka.client.register-with-erueka=true 参数是否正确,事实上
默认就是true。如果值确实为true,则会向EurekaServer发起一个Rest请求,并携带自己的元数据信息,Eureka
Server会把这些信息保存到一个双层Map结构中。
第一层Map的Key就是服务id,一般是配置中的 spring.application.name 属性
第二层Map的key是服务的实例id。一般host+ serviceId + port,例如: localhost:user-service:8081值则是服务的实例对象,也就是说一个服务,可以同时启动多个不同实例,形成集群。
服务续约
在注册服务完成以后,服务提供者会维持一个心跳(定时向EurekaServer发起Rest请求),告诉EurekaServer:“我还活着”。这个我们称为服务的续约(renew);有两个重要参数可以修改服务续约的行为;可以在 user-service 中添加如下配置项:
lease-renewal-interval-in-seconds:服务续约(renew)的间隔,默认为30秒.
lease-expiration-duration-in-seconds:服务失效时间,默认值90秒.
默认情况下每隔30秒服务会向注册中心发送一次心跳,证明自己还活着。如果超过90秒没有发送心跳,
EurekaServer就会认为该服务宕机,会定时(eureka.server.eviction-interval-timer-in-ms设定的时间)从服务列表中移除,这两个值在生产环境不要修改,默认即可.
获取服务列表
当服务消费者启动时,会检测 eureka.client.fetch-registry=true 参数的值,如果为true,则会从Eureka Server服务的列表拉取只读备份,然后缓存在本地。并且 每隔30秒 会重新拉取并更新数据。可以在 userConsumer项目中通过下面的参数来修改:
失效剔除和自我保护
服务下线
当服务进行正常关闭操作时,它会触发一个服务下线的REST请求给Eureka Server,告诉服务注册中心:“我要下线
了”。服务中心接受到请求之后,将该服务置为下线状态。
失效剔除
有时我们的服务可能由于内存溢出或网络故障等原因使得服务不能正常的工作,而服务注册中心并未收到“服务下
线”的请求。相对于服务提供者的“服务续约”操作,服务注册中心在启动时会创建一个定时任务,默认每隔一段时间
(默认为60秒)将当前清单中超时(默认为90秒)没有续约的服务剔除,这个操作被称为失效剔除。
可以通过 eureka.server.eviction-interval-timer-in-ms 参数对其进行修改,单位是毫秒。
自我保护
我们关停一个服务,很可能会在Eureka面板看到一条警告:
这是触发了Eureka的自我保护机制。当服务未按时进行心跳续约时,Eureka会统计服务实例最近15分钟心跳续约的比例是否低于了85%。在生产环境下,因为网络延迟等原因,心跳失败实例的比例很有可能超标,但是此时就把服务剔除列表并不妥当,因为服务可能没有宕机。Eureka在这段时间内不会剔除任何服务实例,直到网络恢复正常。生产环境下这很有效,保证了大多数服务依然可用,不过也有可能获取到失败的服务实例,因此服务调用者必须做好服务的失败容错。
可以通过下面的配置来关停自我保护:
负载均衡Ribbon
开启负载均衡
因为Eureka中已经集成了Ribbon,所以我们无需引入新的依赖。
在RestTemplate的配置方法上添加 @LoadBalanced 注解:
修改 userConsumer控制器调用方式,不再手动获取ip和端口,而是直接通过服务名称调用
Ribbon默认的负载均衡策略是轮询。SpringBoot也帮提供了修改负载均衡规则的配置入口在userConsumer的配置文件中添加如下,就变成随机的了:
Hystrix
Hystrix解决雪崩问题的手段主要是服务降级,包括:线程隔离、服务熔断
1)导入依赖
2)开启熔断:@EnableCircuitBreaker,加在启动类(或者用@SpringCloudApplication)
3)编写降级逻辑
写在方法上
默认的Fallback,写在类上
超时设置(Hystrix的默认超时时长为1s)
hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=2000
服务熔断
在服务熔断中,使用的熔断器,也叫断路器,其英文单词为:Circuit Breaker.
Hystrix的服务熔断机制,可以实现弹性容错;当服务请求情况好转之后,可以自动重连。通过断路的方式,将后续请求直接拒绝,一段时间(默认5秒)之后允许部分请求通过,如果调用成功则回到断路器关闭状态,否则继续打开,拒绝请求的服务。
状态机有3个状态:
Closed:关闭状态(断路器关闭),所有请求都正常访问。
Open:打开状态(断路器打开),所有请求都会被降级。Hystrix会对请求情况计数,当一定时间内失败请求百分比达到阈值,则触发熔断,断路器会完全打开。默认失败比例的阈值是50%,请求次数最少不低于20次。
Half Open:半开状态,不是永久的,断路器打开后会进入休眠时间(默认是5S)。随后断路器会自动进入半开状态。此时会释放部分请求通过,若这些请求都是健康的,则会关闭断路器,否则继续保持打开,再次进行休眠计时.
熔断参数设置:
hystrix.command.default.circuitBreaker.requestVolumeThreshold=10
hystrix.command.default.circuitBreaker.sleepWindowInMilliseconds=10000
hystrix.command.default.circuitBreaker.errorThresholdPercentage=50
hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=2000
Feign
Feign也叫伪装。Feign可以把Rest的请求进行隐藏,伪装成类似SpringMVC的Controller一样。你不用再自己拼接url,拼接参数等等操作,一切都交给Feign去做。
1)在userConsumer中添加依赖
2)编写Feign的客户端
3)在启动类开启Feign功能
4)修改控制器
负载均衡(Feign中本身已经集成了Ribbon依赖和自动配置)
Fegin内置的ribbon默认设置了请求超时时长,默认是1000,可以通过手动配置来修改这个超时时长:
Hystrix支持(默认情况下是关闭的)
1)首先,要定义一个类,实现刚才编写的UserFeignClient,作为fallback的处理类
2)然后在UserFeignClient中,指定刚才编写的实现类
3)重启测试
请求压缩
Spring Cloud Feign 支持对请求和响应进行GZIP压缩,以减少通信过程中的性能损耗。通过下面的参数即可开启请求与响应的压缩功能:
可以对请求的数据类型,以及触发压缩的大小下限进行设置:
日志级别
@FeignClient 注解修改的客户端在被代理时,都会创建一个新的Fegin.Logger实例。我们需要额外指定这个日志的级别才可以。
1)在userComsumer项目的yml文件中,设置某个包的日志级别
2)在 userComsumer 编写FeignConfig配置类,定义日志级别
3)在 userConsumer 的 UserClient 接口类上的@FeignClient注解中指定配置类
4)访问
日志如下:
Spring Cloud Gateway网关
1.简介
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服务注册中心。
网关的核心功能是:过滤和路由
2.核心概念
路由(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将会对请求和响应进行修改处理。
项目:userGateway,作为上面几个项目的网关,配合使用
1)添加依赖
2)启动类
3)配置文件
4)访问
http://localhost:10010/user/han01/3
由于添加了去除前缀,所以访问的是http://127.0.0.1:9091/han01/3
添加前缀
去除前缀
过滤器
Spring Cloud Gateway
Gateway作为网关的其中一个重要功能,就是实现请求的鉴权。而这个动作往往是通过网关提供的过滤器来实现的。
配置全局默认过滤器
自定义局部过滤器
实现,过滤器获取到url请求的?name的值
(如http://localhost:10010/user/han01/3?name=23123131)
1)编写过滤器继承AbstractGatewayFilterFactory
2)修改配置文件
name 是匹配规则,url中包含?name=xxx,获取name值
3)启动测试
自定义全局过滤器
模拟一个登录的校验。基本逻辑:如果请求中有token参数,则认为请求有效,放行。
1)在userGateway工程编写全局过滤器类MyGlobalFilter
2)启动测试,在地址栏中加入token,能正常访问,不加,不能访问