一,概述
1.什么是微服务
要了解什么是微服务首先要了解什么是面向服务(SOA)
面向服务就是将应用程序的不同功能单元(称之为服务)进行拆分,并将这些服务通过接口等联系起来(各服务之间松耦合),想要使用哪个功能,直接进行调用,不会将功能与整个项目紧紧绑定
微服务不是一种技术而是一种思想,是SOA架构下的产物,只要系统的架构符合这种思想,就可以说它是微服务 ,它是聚焦在单一的职责和业务功能,具有独立的进程,能够单独运行的服务,并且与外部服务是通过HTTP进行交互通信的服务
2.微服务与单体架构区别
(1)单体架构所有的模块全都耦合在一块,代码量大,维护困难。
(2)单体架构所有的模块都共用一个数据库,存储方式比较单一。
(3)单体架构所有的模块开发所使用的技术一样。微服务各功能模块可以使用 不同的技术
3.微服务架构的优点
-
易于开发和维护,一个微服务只关注一个业务,业务清晰,代码量少
-
单个微服务代码量少,启动快
-
局部修改容易部署
-
技术不受限制
二,SpringCloud介绍
springcloud是一个完整的微服务架构,提供了所有功能,整个开发项目中所需要的架构功能微服务都有,也就是说整个springcloud就是一个完整的项目,这个架构已经搭建完毕了,用到了直接获取即可,只需要往架构中注入自己的业务代码就可以。
springcloud是基于springboot 开发的微服务框架,是目前比较完整的微服务解决方案框架,它的内容包括:服务注册(eureka),服务调用(feign) ,负载均衡(Ribbon) ,熔断器(Hystrix)等
组件介绍
-
注册中心:Netflix Eureka;
-
负载均衡:Netflix Ribbon(2020 版本前)、Spring Cloud Loadbalancer(2020 版本后);
-
熔断器:Netflix Hystrix(2020 版本前)、Resilience4j(2020 版本后);
-
声明式服务调用组件:Feign(最初属 Netflix 公司,后来移交给 OpenFeign 组织);
-
网关:Netflix Zuul(2020 版本前)、Spring Cloud Gateway(2020 版本后);
-
配置中心:Spring Cloud Config;
1.注册中心-Eureka
Spring Cloud Eureka 是 Spring Cloud Netflix 微服务套件的一部分,基于 Netflix Eureka 做了二次封装,主要负责实现微服务架构中的服务治理功能。
Spring Cloud Eureka 是一个基于 REST 的服务,并且提供了基于 Java 的客户端组件,能够非常方便地将服务注册到 Spring Cloud Eureka 中进行统一管理。
CAP原则
CAP 原则又称 CAP 定理,指的是在一个分布式系统中, Consistency(一致性)、 Availability(可用性)、Partition tolerance(分区容错性),三者不可得兼。
Eureka是基于AP原则建立的
为了保证高可用性,data1和data2都有在有限时间内返回。同样由于网络的不可靠,在有限时间内,data2有可能还没收到data1发来的数据更新消息,这时候返回给客户端的可能是旧的数据,和访问data1的数据是不一致的,也就是违法了C。
也就是说,在保证A和P的情况下,是无法同时保证C的。
2.负载均衡-Ribbon
Ribbon 又叫 负载均衡器
负载均衡是我们处理高并发、缓解网络压力和进行服务器扩容的重要手段之一,但是一般情况下我们所说的负载均衡通常都是指服务器端负载均衡
目前主流的负载方案分为以下两种:
-
集中式负载均衡,在消费者和服务提供方中间使用独立的代理方式进行负载,有硬件的(比如 F5),也有软件的(比如 Nginx)。
-
客户端自己做负载均衡,根据自己的请求情况做负载,Ribbon 就属于客户端自己做负载。
Ribbon常用负载均衡策略
主要使用轮询策略,轮询权重策略
配置负载均衡策略有很多种方式
①文件配置负载均衡策略
在yml文件中设置
#设置负载均衡策略
eureka-client-user-service.ribbon.NFLoadBalancerRuleClassName=com.netflix.loadbalancer.RandomRule
②代码配置负载均衡策略
在代码中创建一个类
@Configuration
public class MyRule {
@Bean
public IRule iRule() {
return new WeightedResponseTimeRule();
}
}
并在springboot启动类加注解
@RibbonClient(name = "eureka-client-user-service", configuration = MyRule.class)
其中:name为服务提供者的名称,configuration为定义的策略类
③自定义负载均衡策略
通过实现 IRule 接口可以自定义负载策略,主要的选择服务逻辑在 choose 方法中。
超时配置
在进行服务调用的时候,如果网络情况不好,可能会出现超时问题,这里我们需要配置请求超时时间
调用服务连接数和并发处理配置一样也需要配置
ribbon.http.client.enabled=true
# 请求连接的超时时间(单位:毫秒)
ribbon.ConnectTimeout=2000
# 请求处理的超时时间(单位:毫秒)
ribbon.ReadTimeout=5000
# 并发最大连接数
ribbon.MaxTotalConnections=500
# 每个主机最大连接数
ribbon.MaxConnectionsPerHost=500
也可以为每个Ribbon客户端设置不同的超时时间, 通过服务名称进行指定:如下:
eureka-client-user-service 是服务提供者服务名称
eureka-client-user-service.ribbon.ConnectTimeout=2000
eureka-client-user-service.ribbon.ReadTimeout=5000
饥饿加载
在进行服务调用的时候,如果网络情况不好,超时的问题也是一样,Ribbon 的客户端是在第一次请求的时候初始化的,如果超时时间比较短的话,初始化 Client 的时间再加上请求接口的时间,就会导致第一次请求超时。除了采取更改超时时间以外,Spring Cloud 也提供了第二个种方式:饥饿加载,配置如下:
#开启 Ribbon 的饥饿加载模式
ribbon.eager-load.enabled=true
#指定需要饥饿加载的服务名,也就是你需要调用的服务,若有多个则用逗号隔开
ribbon.eager-load.clients=eureka-client-user-service
3.声明式服务调用组件-Feign
Feign 是一个声明式的 REST 客户端,它能让 REST 调用更加简单。Feign 供了 HTTP 请求的模板,通过编写简单的接口和插入注解,就可以定义好 HTTP 请求的参数、格式、地址等信息。而 Feign 则会完全代理 HTTP 请求,我们只需要像调用方法一样调用它就可以完成服务请求及相关处理。
Spring Cloud对Feign进行了封装,Feign可以与Eureka、Ribbon和Hystrix组合使用,引入Feign依赖的同时这两个组件也会被一同引入。
Ribbon:利用负载均衡策略选定目标机器
Hystrix:根据熔断器的开启状态,决定是否发起此次调用。
feign使用分为get请求和post请求
Get请求
1.在服务提供者项目中,定义提供数据的控制器方法
@RestController
public class UserController {
@Value("${server.port}")
private String port;
@GetMapping("/user/hello")
public String hello(String userName) {
String info = "端口号:"+port+" 请求参数userName="+userName;
return info;
}
}
2.在消费者项目,添加依赖
<!-- feign组件所需依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
3.在消费者项目的启动类添加@EnableFeignClients 注解,该注解表示启动feign组件服务
4.在消费者项目定义访问服务提供者项目的接口
@Component
@FeignClient(value = "eureka-client-user-service")//服务提供者服务名称
public interface FeignService {
@GetMapping("/user/hello")
String hello(@RequestParam("userName") String userName);
}
@FeignClient(value = "eureka-client-user-service") :连接服务提供者项目的服务,value的值是服务提供者项目的服务名称
@GetMapping("/user/hello") get提交方式注解 ,要和服务提供者项目的服务的控制器方法的提交注解一致,/user/hello 是服务提供者项目的服务的控制器方法的地址
@RequestParam("userName") 请求参数,该注解不能省略,"userName" 是服务提供者项目的服务的控制器方法的参数名称
5 在消费者项目中定义访问接口的控制器方法
@RestController
@RequestMapping("/feign")
public class FeignController {
@Autowired
FeignService feignService;
@GetMapping("/hello")
public String callHello(String userName) {
return feignService.hello(userName);
}
}
Post请求:
与get请求大体相同,只是在接口中使用@RequestBody注解来描述方法参数
日志配置
有时候我们遇到 Bug,比如接口调用失败、参数没收到等问题,或者想看看调用性能,就需要配置 Feign 的日志了,以此让 Feign 把请求信息输出来。步骤如下:
1 定义一个日志配置类,注意Logger的包不要导错。
日志级别有4个:
-
NONE:不输出日志。
-
BASIC:只输出请求方法的 URL 和响应的状态码以及接口执行的时间。
-
HEADERS:将 BASIC 信息和请求头信息输出。
-
FULL:输出完整的请求信息。
配置步骤:
1.首先创建一个配置类
@Configuration
public class FeignConfiguration {
/**
* 日志级别
*
* @return
*/
@Bean
Logger.Level feignLoggerLevel() {
return Logger.Level.FULL;
}
}
2. 配置类建好后,我们需要在 启动类@FeignClient 注解中指定使用的配置类
@Component
@FeignClient(value = "eureka-client-user-service",configuration = FeignConfiguration.class)//FeignConfiguration是日志配置类
public interface FeignService {
@PostMapping("/user/hello")
String hello( UserInfo userInfo);
}
3.在yml配置文件中执行 Client 的日志级别才能正常输出日志,格式是“logging.level. 类地址=级别”
# 日志等级
logging.level.com.hqyj.service.FeignService=DEBUG
4.熔断器- Hystrix
首先了解
雪崩效应: 一个微服务中可能会调用多个微服务接口才能完成, 形成复杂的链式调用. 当其中一个服务接口出现异常访问, 会导致整个线程堵塞. 越来越多的用户请求就会有越来越多的线程堵塞,资源无法释放, 导致当前微服务的服务器资源耗尽, 当前服务挂掉, 从而引起雪崩效应。
Hystrix 是 Netflix 针对微服务分布式系统采用的熔断保护中间件,相当于电路中的保险丝。
Hystrix 是一个库,通过添加延迟容忍和容错逻辑,帮助控制这些分布式服务之间的交互。Hystrix 通过隔离服务之间的访问点、停止级联失败和提供回退选项来实现这一点,所有这些都可以提高系统的整体弹性。
在微服务架构下,很多服务都相互依赖,如果不能对依赖的服务进行隔离,那么服务本身也有可能发生故障,Hystrix 通过 HystrixCommand 对调用进行隔离,这样可以阻止故障的连锁效应,能够让接口调用快速失败并迅速恢复正常,或者回退并降级。
熔断器原理
熔断器有三种状态, 关闭是说明请求访问正常
打开: 所有请求都被降级
关闭: 正常访问所有请求
半开状态: 不是长久状态, 熔断器打开后, 过了默认的时间会变成半开状态, 下一次被访问后, 如果访问成功则开关关闭, 如果失败则开关打开, 进行下一轮循环。
熔断触发时机
-
访问超时
-
访问服务器抛异常
-
访问服务器挂掉了
-
错误次数达到了阈值
Feign整合Hystrix实现容错处理
1 消费者项目中 添加依赖
<!--熔断组件所需依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
2 消费者项目中 配置yml文件,开启熔断组件
#开启熔断器组件
feign.hystrix.enabled=true
3 创建处理熔断的熔断类FeignServiceFallBack,并加上注解@Service 或者@Component,该类要实现自定义的FeignService接口。熔断的业务逻辑在实现方法里写,这里就写个简单的逻辑,返回一个‘’服务停用‘提示
@Service
public class FeignServiceFallBack implements FeignService {
@Override
public String hello(UserInfo userInfo) {
return "服务停用!";
}
}
4 在自定义的FeignService的接口上的@FeignClient 注解里添加处理这个接口的熔断类:fallback = FeignServiceFallBack.class
@Component
@FeignClient(value = "eureka-client-user-service",fallback = FeignServiceFallBack.class)//服务提供者服务名称
public interface FeignService {
@PostMapping("/user/hello")
String hello( UserInfo userInfo);
}
5 控制器代码不变
@RestController
@RequestMapping("/feign")
public class FeignController {
@Autowired
FeignService feignService;
@PostMapping("/hello")
public String callHello(UserInfo userInfo) {
return feignService.hello(userInfo);
}
}
Hystrix 降级处理
在微服务开发中,由于每个服务器的环境不一样,例如:网络延迟,可能会导致访问每个服务请求时间不同,有的服务处理请求时间快,有的服务处理请求时间慢,为了让用户有更好的服务体验,我们需要让处理请求慢的服务,把请求交给处理请求快的服务来做。
Feign降级超时配置
完成步骤如下:
1 在服务提供者,定义一个睡眠程序,模拟请求是 3秒后处理,代码如下
@GetMapping("/hello")
public String hello(String userName) {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "端口:" + port + "userName:" + userName;
}
2 在服务消费者的application.properties文件中配置如下信息:
feign.hystrix.enabled=true
# 请求连接的超时时间(单位:毫秒),超时时间要大于程序执行时间,否则会被ribbon先熔断
ribbon.ConnectTimeout=5000
# 请求处理的超时时间(单位:毫秒)
ribbon.ReadTimeout=5000
hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=4000
或者
feign.hystrix.enabled=true
# 请求连接的超时时间(单位:毫秒),超时时间要大于程序执行时间,否则会被ribbon先熔断
feign.client.config.default.connect-timeout=5000
feign.client.config.default.read-timeout=5000
hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=4000
feign和ribbon的配置二选一即可,因为这两个配置都相当于是ribbon的配置,不同点在于feign的配置在ribbon的基础上做了扩展,可以支持配置服务级别的超时时间。
如果没有设置过feign超时,也就是等于默认值的时候,就会读取ribbon的配置,使用ribbon的超时时间和重试设置。否则使用feign自身的设置。两者是二选一的,且feign优先。
hystrix配置的超时时间理论上应该要比 feign和ribbon的要大,因为feign和ribbon可以配置失败重试。当然最终的超时时间是以feign(或ribbon)和hystrix中最小时间为准。所以在设置hystrix超时时间时,如果设置的超时时间比feign的要小,则可以生效。如果设置的时间比feign的要大,则会以feign的超时时间为准。