概述:
微服务其实就是将一个大的架构进行模块化的拆分,每个模块就是一个微服务,各个微服务组合成一个整体:
实现微服务管理的方式:
Dubbo:
SpringCloud:
dubbo和SpringCloud对比:
dubbo只是实现类微服务的治理,但是springCloud实现微服务架构下的诸多组件
dubbo使用的是RPC通讯协议,SpringCloud采用的是RESTful完成通讯,由于SpringCloud实现的组件比较的多,所以SpringCloud的效率低于dubbo
1 不使用微服务管理工具远程调用示例:
生产端:
@RestController
public class StudentController {
@GetMapping("/find/{age}")
public Student find(@PathVariable int age) {
return new Student("张三", age);
}
}
消费端:
@RestController
@RequestMapping("/consumer")
public class ComtstumerController {
@Autowired
private RestTemplate restTemplate;
@GetMapping("{age}")
public Student find(@PathVariable int age) {
System.out.println(age);
//知道访问的接口,然后完成拼串
String url="http://localhost:8080/find/"+age;
return restTemplate.getForObject(url, Student.class) ;
}
}
RestTemplate引入:
@Configuration
public class RestTemplateConfig {
@Bean
public RestTemplate restTemplate(){
return new RestTemplate();
}
}
SpringBoot环境下,依赖引入web的即可
RestTemplate远程调用是Spring进行封装的,但是跨域问题,底层已经解决!关于Resttemplate的api查看源码即可!
2 SpringCloud注册中心Eureka(使用这些注册中心会动态得到服务的提供方url)
Eureka的架构图(看图秒懂,其实其他的注册中心大同小异):
关于Eureka的相关介绍,.......无关紧要的,废话就算啦:
Eureka的配置分为4部分:
server : eureka 的服务端配置
client : eureka 的客户端配置
instance : eureka 的实例配置
dashboard : eureka 的web控制台配置
其实烦的就是这些配置...所以我才在做模板,方便日后使用粘贴修改
eureka: server:
enable-self-preservation: false #是否开启自我保护机制,默认true即使服务有问题,也会保存(防止网络抖动等),
eviction-interval-timer-in-ms: 50000 #清理死服务时间间隔,默认是60000
dashboard:
enabled: true #是否启用service的web控制台
path: / #设置web控制台的访问路径
eureka: instance:
hostname: localhost #主机名字
prefer-ip-address: true #否将自己的ip注册Eureka上,默认是不注册ip,注册的是主机名
ip-address: #设置当前实例的ip
instance-id: #修改instance显示的id
lease-renewal-interval-in-seconds: 20 #Eureka客户端向服务端发送心跳的时间间隔
lease-expiration-duration-in-seconds: 100 #超过该时间没有收到心跳,剔除服务
client:
service-url:
defaultZone: #Eureka的service地址
register-with-eureka: true #是否将自己的路径注册到eurea上
fetch-registry: true # 是否从eureka上抓取数据
使用Eureka做为注册中心(这块注册中心使用集群实现高可用):
创建父项目使用maven进行统一的依赖管理(可以分开,看习惯):
实例搭建:
parent中pom.xml
<!--spring boot 环境 --><parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.0.RELEASE</version>
<relativePath/>
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<maven.compiler.encoding>UTF-8</maven.compiler.encoding>
<!--spring cloud 版本-->
<spring-cloud.version>Greenwich.RELEASE</spring-cloud.version>
</properties>
<!--引入Spring Cloud 依赖-->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
eureka的service:
pom依赖:
<dependencies> <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- eureka-server -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
</dependencies>
service1配置:
#直接访问该端口就是Eureka的web控制台server: port: 8762 eureka: instance: hostname: nanfeng # 主机名 client: service-url: # 将本机服务注册到其他集群节点,这块设置的是两个节点,所以需要将本机的服务注册到另外一个服务上, # 若是单节点,这块就可以不配置了 # 下面这块改成需要注册的主机名,注意并不是本地主机名,是目标主机名名,在开发阶段采用端口识别,但是在上线后采用ip识别(端口号可以修改) defaultZone: http://localhost:8761/eureka register-with-eureka: true # 是否将自己的路径 注册到eureka上。eureka server 单节点不需要的,集群需要,eureka provider client 需要 fetch-registry: true # 是否需要从eureka中抓取路径。eureka server单节点不需要,集群需要 ,eureka consumer client 需要 server: enable-self-preservation: true # 是否开启自我保护机制(开启后即使注册到客户端的服务出现问题,也不会被清除,在开发测试不开启,上线后开启) eviction-interval-timer-in-ms: 3000 # 检查服务的时间间隔 spring: application: name: server #这个名字必须相同,同一个节点
service2
server: port: 8761 eureka: instance: hostname: localhost # 主机名 client: service-url: # 将本机服务注册到其他集群节点,这块设置的是两个节点,所以需要将本机的服务注册到另外一个服务上, # 若是单节点,这块就可以不配置了 # 下面这块改成需要注册的主机名,注意并不是本地主机名,是目标主机名名,在开发阶段采用端口识别,但是在上线后采用ip识别(端口号可以修改) defaultZone: http://nanfeng:8762/eureka register-with-eureka: true # 是否将自己的路径 注册到eureka上。eureka server 单节点不需要的,集群需要,eureka provider client 需要 fetch-registry: true # 是否需要从eureka中抓取路径。eureka server单节点不需要,集群需要 ,eureka consumer client 需要 server: enable-self-preservation: true # 是否开启自我保护机制(开启后即使注册到客户端的服务出现问题,也不会被清除,在开发测试不开启,上线后开启) eviction-interval-timer-in-ms: 3000 # 检查服务的时间间隔 spring: application: name: server #节点名字保证相同
service启动类添加注解@EnableEurekaServer,标注是一个Eureka的service服务:
@SpringBootApplication
@EnableEurekaServer
public class EurekaServiceApp {
public static void main(String[] args) {
SpringApplication.run(EurekaServiceApp.class, args);
}
}
注意:在搭建集群的时候启动两个服务相互注册的时候会报错,当两个服务都启动了,这个错误就不存在了!
客户端生产者和消费者的依赖:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- eureka-client --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> </dependencies>
生产端:
配置文件:
# 本地主机的启动端口号server:
port: 8002
# eureka客户端服务的标准配置
eureka:
instance:
hostname: localhost # 主机名
prefer-ip-address: true # 将当前实例的ip注册到eureka server 中。默认是false 注册主机名
ip-address: 127.0.0.1 # 设置当前实例的ip
# 设置web控制台显示的 实例id,就是在注册中心显示的示实例的信息
instance-id: ${eureka.instance.ip-address}:${spring.application.name}:${server.port}
lease-renewal-interval-in-seconds: 3 # 每隔3 秒发一次心跳包,服务续约
# 如果9秒没有发心跳包,服务器呀,你把我干掉吧,一般上线的服务都会在服务端开启自我服务的保护,
#即使自己的服务出现问题,也不会将自己的服务杀掉,(可能指网络抖动,等文体,随后服务会回恢复正常)
lease-expiration-duration-in-seconds: 9
client:
service-url:
# eureka服务端地址,将来客户端使用该地址和eureka进行通信
defaultZone: http://localhost:8761/eureka,http://nanfeng:8762/eureka
spring:
application:
name: provider # 设置当前应用的名称。将来会在eureka中Application显示。将来需要使用该名称来获取路径
controller:
@RestController
public class StudentController {
@GetMapping("/find/{age}")
public Student find(@PathVariable int age) {
return new Student("张三", age);
}
}
启动类添加注解@EnableEurekaClient(生产端和消费端的启动类相同,就是添加注解):
@SpringBootApplication
@EnableEurekaClient
public class ProviderApp {
public static void main(String[] args) {
SpringApplication.run(ProviderApp.class,args);
}
}
消费端:
消费端配置文件:
# 本地主机的启动端口server:
port: 8001
# eruake客户端消费的配置
eureka:
instance:
hostname: nanfeng # 主机名
client:
service-url:
# eureka服务端地址,将来客户端使用该地址和eureka进行通信,这块需要将服务自己的信息注册到集群环境中(下面的主机名在使用时修改即可),
defaultZone: http://localhost:8761/eureka,http://nanfeng:8762/eureka
spring:
application:
# 设置当前应用的名称。将来会在eureka中Application显示。将来需要使用该名称来获取路径,
# 若是不设置会在eureka的控制台上无法显示信息
name: consumer
RestTemplate配置类(这块使用了ribbon的注解@LoadBalanced 简化开发,ribbon和Eureka是同一家产品,Eureka中集成有ribbon,关于ribbon使用:Ribbon实现客户端负载均衡_楠~枫的博客-CSDN博客):
@Configuration
public class RestTemplateConfig {
/*
* 注入远程调用
* */
@LoadBalanced //ribbon注解:添加这个注解以后可以通过服务名字掉进行地址的绑定
@Bean
public RestTemplate restTemplate(){
return new RestTemplate();
}
}
controller(代码含有注释,参考):
@RestController
@RequestMapping("/consumer")
public class ComtstumerController {
@Autowired
private RestTemplate restTemplate;
//使用注册中心后
@Autowired
private DiscoveryClient discoveryClient;
@GetMapping("{age}")
public Student find(@PathVariable int age) {
//知道访问的接口,然后完成拼串
String url = "http://localhost:8080/find/" + age;
return restTemplate.getForObject(url, Student.class);
}
@GetMapping("discover/{age}")
public Student findDiscovery(@PathVariable int age) {
//通过discovery获取服务对象
List<ServiceInstance> instances = discoveryClient.getInstances("provider");
//判断集合是否有数据
if (instances == null || instances.size() == 0) {
//集合没有数据
return null;
}
ServiceInstance instance = instances.get(0);
String host = instance.getHost();//获取ip
int port = instance.getPort();//获取端口
//知道访问的接口,然后完成拼串
String url = "http://"+host+":"+port+"/find/" + age;
return restTemplate.getForObject(url, Student.class);
}
/*
*使用aribbon后的简化调用,使用ribbon上面find2就不能使用原来的方式访问了,要痛过服务提供方的名称访问
* */
@GetMapping("ribbon/{age}")
public Student findDiscoveryRibbon(@PathVariable int age) {
String url = "http://provider/find/" + age;
return restTemplate.getForObject(url, Student.class);
}
}
关于Eureka的基本使用完结!配置文件超级烦,参考修改,为了偷懒,,,,,,,,,,,,,啦啦啦啦啦啦
3 SpringCloud注册中心Consul
Consul是go语言写的,是个软件包:
度盘:https://pan.baidu.com/s/1tRvNmrG7-olM7UXjNiPoeg
提取码:0vm6
废话不多说,直接用:
下载下来直接解压即可:
启动(解压目录下):
.\consul.exe agent -dev # 开发形式启动,dev开发模式启动,不会持久化数据
访问控制台:localhost:8500
实例(基本上代码层面没啥改变,就是配置文件的形式):
父项目pom同Eureka实例:
pom依赖生产端和消费端相同
<!--consul 客户端--><dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-consul-discovery</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
消费端配置:
server: port: 8001
spring:
cloud:
consul:
# 将服务的信息注册到端口
host: localhost # consul 服务端的 ip
port: 8500 # consul 服务端的端口 默认8500.consul的默认启动端口号
discovery:
service-name: ${spring.application.name} # 当前应用注册到consul的名称
prefer-ip-address: true # 注册ip
application:
name: consumer # 应用名称
生产端配置文件:
# 常规服务启动的端口server:
port: 8002
spring:
cloud:
consul:
# 将自己的信息注册到指定的地址
host: localhost # consul 服务端的 ip
port: 8500 # consul 服务端的端口 默认8500
discovery:
service-name: ${spring.application.name} # 当前应用注册到consul的名称
prefer-ip-address: true # 注册ip
application:
name: provider # 应用名称
其实这两个配置没为神马区别:
消费端启动类:
@SpringBootApplication
@EnableDiscoveryClient//开启dis...
public class ConsumerApp {
public static void main(String[] args) {
SpringApplication.run(ConsumerApp.class, args);
}
}
消费端RestTemplate引入:
@Configuration
public class RestTemplateConfig {
@Bean
public RestTemplate restTemplate(){
return new RestTemplate();
}
}
消费端Controller:
@RestController
@RequestMapping("/consumer")
public class ComtstumerController {
@Autowired
private RestTemplate restTemplate;
//使用注册中心后
@Autowired
private DiscoveryClient discoveryClient;
@GetMapping("{age}")
public Student find(@PathVariable int age) {
//知道访问的接口,然后完成拼串
String url = "http://localhost:8080/find/" + age;
return restTemplate.getForObject(url, Student.class);
}
@GetMapping("discover/{age}")
public Student findDiscovery(@PathVariable int age) {
//通过discovery获取服务对象
List<ServiceInstance> instances = discoveryClient.getInstances("provider");
//判断集合是否有数据
if (instances == null || instances.size() == 0) {
//集合没有数据
return null;
}
ServiceInstance instance = instances.get(0);
String host = instance.getHost();//获取ip
int port = instance.getPort();//获取端口
//知道访问的接口,然后完成拼串
String url = "http://"+host+":"+port+"/find/" + age;
return restTemplate.getForObject(url, Student.class);
}
}
其他的省略,主要是配置文件!!!关于Consul基础使用就这啦,主要是配置文件
4 SpringCloud注册中心nacos
nacos是阿里巴巴的产物,是一个软件包:下载地址:https://github.com/alibaba/nacos/releases
度盘链接:https://pan.baidu.com/s/1_ZvotToFjgn0sHhYr92mow
提取码:3ik4
啦啦啦啦啦,```````````````````````````````~~~~~~~~~~~~~~~~~~,直接使用吧!
解压后:
bin目录下的staetup.cmd双击启动
默认端口:8848
控制台:localhost:8848/nacos/#/login
控制台的账号:nacos
密码:nacos
linux和window相同,只是启动文件变成sh
启动完事
其实还是学配置文件,真的是很烦这些配置文件
实例:
父项目依赖同Eureka实例
依赖(生产消费相同):
<!--nacos--><dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
<version>0.2.2.RELEASE</version>
</dependency>
<dependency>
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-client</artifactId>
<version>1.1.0</version>
</dependency>
<!--web的起步依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--监控包-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
配置文件生产消费两边相同(修改即可):
server: port: 8002 spring: cloud: nacos: discovery: server-addr: 127.0.0.1:8848 # 配置nacos 服务端地址 8848默认端口号 application: name: provider # 服务名称
代码和Consul相同,同样的代码粘贴,,,,,
关于Nacos就这样吧
5 dubbo实现微服务管理:
明天吧...............................
6 SpringCloud声明式服务调用Feign
概述:
Feign是一种http客户端(主要用于消费端),用来实现http远程调用的,可以实现远程端调用像在本地方法一样,和Eureka是一家产品,在feign基层封装了ribbon和restful风格请求
实现原理:
接口加注解的形式
Feign的日志级别为Debug,只识别Debug级别的日志
Feign超时设置(Feign的超时机制是建立在ribbon的基础上的),其实就是设置ribbon的超时机制,设置服务响应和处理的时间限制!若是服务端节点出现问题会雪崩!
雪崩:
所谓雪崩就是服务全部瘫痪,根本原因是某个服务调用过程中,由于服务端出现问题,调用端不断的调用,线程积压,最终瘫痪形成的链式反应:图示:
案例示例(基于上面搭建的Eureka做改进的):
消费端:
消费端添加feign的pom依赖:
<!--声明式服务调用--><!--feign-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
消费端配制文件(超时配置,日志配置)
# 本地主机的启动端口server:
port: 8001
# eruake客户端消费的配置
eureka:
instance:
hostname: nanfeng # 主机名
client:
service-url:
# eureka服务端地址,将来客户端使用该地址和eureka进行通信,这块需要将服务自己的信息注册到集群环境中(下面的主机名在使用时修改即可),
defaultZone: http://localhost:8761/eureka,http://nanfeng:8762/eureka
spring:
application:
# 设置当前应用的名称。将来会在eureka中Application显示。将来需要使用该名称来获取路径,
# 若是不设置会在eureka的控制台上无法显示信息
name: consumer
# 设置当前的日志级别 debug,feign只支持记录debug级别的日志
logging:
level:
com.itheima: debug
# 设置Feign的超时时间,但是Feign的底层实际是Ribbon
# 设置Ribbon的超时时间,
ribbon:
ConnectTimeout: 1000 # 连接超时时间 默认1s
ReadTimeout: 3000 # 逻辑处理的超时时间 默认1s
消费端Feign的接口(代码写法在注释中)
/**
* feign的接口其实就是将RestTemplat的bean加载进来,将原来的请求地址:String url = "http://provider/find/" + age;进行了封装
*/
/*
* @FeignClient完成服务主机地址和名字以及端口的封装,SpringCloud对feign进行了封装,SpringMVC支持识别feign注解
**/
@FeignClient(value = "provider",configuration = FeignLogConfig .class)
public interface MyFeign {
/*
* @GetMapping保持和服务提供方的路径同即可
*/
@GetMapping("/find/{age}")
Student find(@PathVariable int age);
}
MyResttemplateConfig其实就是一个引入RestTemplate的配置类(这个在这可以不要,但是在controller中之前的案例还在,所以这块保存,否则之前的案例报错看不到对比)
/**
* 其实就是一个RestTemplate的配置类
*/
@Configuration
public class MyResttemplateConfig {
/*
ribbon的注解,其实在这块有没有都可以,会自动识别的
*/
@LoadBalanced
@Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
FeignLogConfig 日志配置类:
@Configuration
public class FeignLogConfig {
/*
NONE,不记录
BASIC,记录基本的请求行,响应状态码数据
HEADERS,记录基本的请求行,响应状态码数据,记录响应头信息
FULL;记录完成的请求 响应数据
*/
@Bean
public Logger.Level level(){
return Logger.Level.FULL;
}
}
controller类
@RestController
@RequestMapping("/consumer")
public class ComtstumerController {
@Autowired
private RestTemplate restTemplate;
//使用注册中心后
@Autowired
private DiscoveryClient discoveryClient;
/**
* 注入feign
*/
@Autowired
private MyFeign myFeign;
@GetMapping("{age}")
public Student find(@PathVariable int age) {
//知道访问的接口,然后完成拼串
String url = "http://localhost:8080/find/" + age;
return restTemplate.getForObject(url, Student.class);
}
@GetMapping("discover/{age}")
public Student findDiscovery(@PathVariable int age) {
//通过discovery获取服务对象
List<ServiceInstance> instances = discoveryClient.getInstances("provider");
//判断集合是否有数据
if (instances == null || instances.size() == 0) {
//集合没有数据
return null;
}
ServiceInstance instance = instances.get(0);
String host = instance.getHost();//获取ip
int port = instance.getPort();//获取端口
//知道访问的接口,然后完成拼串
String url = "http://"+host+":"+port+"/find/" + age;
return restTemplate.getForObject(url, Student.class);
}
/*
*使用aribbon后的简化调用,使用ribbon上面find2就不能使用原来的方式访问了,要痛过服务提供方的名称访问
* */
@GetMapping("ribbon/{age}")
public Student findDiscoveryRibbon(@PathVariable int age) {
String url = "http://provider/find/" + age;
return restTemplate.getForObject(url, Student.class);
}
/**
* 通过Feigen接口调用
*/
@GetMapping("feign/{age}")
public Student findFeign(@PathVariable int age) {
return myFeign.find(age);
}
}
启动类开启Feign支持:
/**
* 新版本部分SpringCloud组件的注解默认已经开启
*/
@SpringBootApplication
@EnableEurekaClient
@EnableDiscoveryClient//开启dis支持...
/**
* 开启feign的支持
*/
@EnableFeignClients
public class ConsumerApp {
public static void main(String[] args) {
SpringApplication.run(ConsumerApp.class, args);
}
}
生产端和注册中心基于上面Eureka原来案例不变化,关于Feign声明式服务调用就这样了!!!!!!~~~使用参考修改即可!
7 SpringCloud的容错处理Hystix
概述:Hystix ,Eureka,Feign,Robbon都是一家的,Hystix是开源的一个延迟和容错库,防止出现雪崩的.......反正就是很溜!
作用:
隔离:信号量隔离/线程池隔离
信号量隔离,其实就是某个节点发来请求统计次数,在某个时间端内达到多少次限制请求,过一段时间然后缓慢释放一部分请求,若是没有问在逐渐放行请求
线程池隔离:设置线程数量,有空闲线程放行新的请求(实际使用的也是这个)
服务降级:针对某个服务出现异常/超时
下面案例编码实现
熔断:这个实现原理在隔离中已经说了,两个关系很密切,隔离的条件达到后就会熔断,其实就是阻止请求
限流:就是熔断后缓慢放行请求的过程,根据限号量.空闲线程量
隔离,熔断,限流,只是Hystix不同时期的状态而已,三个组成hystix的工作过程!服务降级是对异常或者熔断的一种处理!
概念说明白了,案例实现:
案例(基于Feign案例添加和改动):
生产端:需要做的就是引入hystix依赖,编写降级方法,设置降级参数,启动类开启Hystixz支持
生产段pom依赖(生产端不需要):
<!-- hystrix --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-hystrix</artifactId> </dependency>
生产端配置文件(基于Feign的配置文件无需修改/没有提及的都是基于之前案例的代码或者文件):
生产端代码(配置hystix降级注解的参数,写降级方法):
@RestController
public class StudentController {
/**
* @HystrixCommand设置服务降级的一些参数,注解参数解析: fallbackMethod:字符串类型参数,参数是同类的降级方法的方法名
* commandProperties:设置一些降级参数信息,数组
*/
@HystrixCommand(fallbackMethod = "findDomate", commandProperties = {
//设置Hystrix的超时时间,默认1s
@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "3000"),
//监控时间 默认5000 毫秒
@HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds", value = "5000"),
//失败次数。默认5000毫秒内失败20次,开启熔断器
@HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value = "20"),
//失败率 默认50%,也会开启熔断器
@HystrixProperty(name = "circuitBreaker.errorThresholdPercentage", value = "50")
})
@GetMapping("/find/{age}")
public Student find(@PathVariable int age) throws InterruptedException {
Thread.sleep(5000);
return new Student("张三", age);
}
/**
* 降级方法的写法:
* 1 和原来的方法参数相同
* 2 和原来方法的返回值相同
*/
public Student findDomate(int age) {
return new Student("生产端降级了", 0);
}
}
启动类开启hystix支持:
@SpringBootApplication
@EnableEurekaClient
@EnableHystrix//开启Hystix支持
public class ProviderApp {
public static void main(String[] args) {
SpringApplication.run(ProviderApp.class,args);
}
}
消费端
消费端pom依赖基于feign不变:
消费端配置文件:
# 本地主机的启动端口server:
port: 8001
# eruake客户端消费的配置
eureka:
instance:
hostname: nanfeng # 主机名
client:
service-url:
# eureka服务端地址,将来客户端使用该地址和eureka进行通信,这块需要将服务自己的信息注册到集群环境中(下面的主机名在使用时修改即可),
defaultZone: http://localhost:8761/eureka,http://nanfeng:8762/eureka
spring:
application:
# 设置当前应用的名称。将来会在eureka中Application显示。将来需要使用该名称来获取路径,
# 若是不设置会在eureka的控制台上无法显示信息
name: consumer
# 设置当前的日志级别 debug,feign只支持记录debug级别的日志
logging:
level:
com.itheima: debug
# 设置Feign的超时时间,但是Feign的底层实际是Ribbon
# 设置Ribbon的超时时间,超时会降级
ribbon:
ConnectTimeout: 1000 # 连接超时时间 默认1s
ReadTimeout: 3000 # 逻辑处理的超时时间 默认1s
#注意:在生产端也可以设置降级,但是设置的生产端的超时设置大于消费端的超时,
#会执行生产端的超时,消费端满足降级会先执行消费端降级
#开启Hystix支持
feign:
hystrix:
enabled: true
Feign接口(配置降级方法):
/**
* feign的接口其实就是将RestTemplat的bean加载进来,将原来的请求地址:String url = "http://provider/find/" + age;进行了封装
*/
/*
* @FeignClient完成服务主机地址和名字以及端口的封装,设置降级的实现类!SpringCloud对feign进行了封装,SpringMVC支持识别feign注解
**/
@FeignClient(value = "provider",configuration = FeignLogConfig.class,fallback = Demote.class)
public interface MyFeign {
/*
* @GetMapping保持和服务提供方的路径同即可
*/
@GetMapping("/find/{age}")
Student find(@PathVariable int age);
}
Feign接口实现类中写降级方法:
/**
* feign的降级实现:
* 定义类实现feign接口
* 将实现类加入到ioc中
*/
@Component//需要ioc识别这个bean
public class Demote implements MyFeign {
@Override
public Student find(int age) {
return new Student("消费端降级",0);
}
}
启动类基于feign案例:
基本上代码实现就到这了,该有的解释代码中已经做了说明,参考修改即可!
关于熔断器的工作机制:在解释hystix隔离时已经说明白了,这块在说一下:
达到隔离条件,进行熔断,过一段时间进行部分放行(即限流),若是放行的请求依然有问题,继续熔断,若是没有问题,全部放行,依次循环!
熔断器监控:啦啦啦,是有这个东西,但是应该是运维人员搞的,和我应该没多大关系!
8 SpringCloud的网关配置Gateay(网关)
概述:Gateway其实就是为诸多分布式服务提供统一的 Api管理,解决前端访问各个服务时路径的不同和身份验证等诸多问题!
理解图:
Nginx+ Lua.这个我目前还不是很熟悉,回头学习一下,再做整理!
理论都简单,烦人的还是配置文件:
主要使用:
静态路由:配置文件中写死
动态路由:将自己注册到注册中心,然后从注册中心获取uri
服务名称配置: 访问路径必须携带服务的名称:大写名称/小写名称
过滤器:主要是在请求的前后做一些操作
过滤器方式:
pre :前置操作:在转发之前执行,可以做参数校验、权限校验、流量监控、日志输出、协议转换
post 后置操作:在响应之前执行,可以做响应内容、响应头的修改,日志的输出,流量监控等
GatewayFilter: 针对单个路由
GlobalFilter :针对所有路由
全局路由主要处理的实现有(这些实现百度有):
以上配置全部在下面的案例中体现,参考修改即可:
案例(基于Hystix案例进行修改添加,从头搭建环境太繁琐):
在parent下新建网关模块:
模块依赖:
<dependencies> <!--引入gateway 网关-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<!-- eureka-客户端-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
</dependencies>
Getway的配置:
server: port: 80
spring:
application:
name: Gateway_API
cloud:
# 网关配置
gateway:
# 路由配置:转发规则
routes: # 参数是一个集合。
# id: 唯一标识。默认是一个UUID,一般设置为节点服务的name
# uri: 转发服务提供者的访问路径
# predicates: 条件集合,用于请求网关路径的匹配规则,就是该路径下的某个处理器(具体到某个方法)
# filters:配置局部过滤器的
- id: provider
# 静态路由:直接写死的服务提供方的路径
# uri: http://localhost:8002
# 动态路由:从EurekaServer上获取的路经,PROVIDER是服务提供方的EurekaServer上注册的name,必须大写
uri: lb://ROVIDER
predicates: #/student/路径下的某个处理器
- Path=/find/**
#filters: #集合参数,局部过滤器,实现一系列的前置后置的处理
# - AddRequestParameter=username,zhangsan #参数username赋值张三
- id: consumer
# uri: http://localhost:8001
uri: lb://CONSUMER
predicates:
- Path=/consumer/**
# 微服务名称配置:开启后必须配置服务的名称:http://localhost/服务的名字/consumer/feign//2
discovery:
locator:
enabled: true # 服务名字必须为大写:http://localhost/CONSUMER/consumer/feign//2
#lower-case-service-id: true # 服务名字必须小写:http://localhost/consumer/consumer/feign//2
##注册到EurekaServer上获取相关的路径端口信息
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka,http://localhost:8762/eurekaq
全局过滤器(实现接口GlobalFilter, Ordered,并且让ioc容器识别):
/**
* 配置全局过滤器:无需任何配置,完成编码会自动识别
* 需要被ioc识别
*/
@Component
public class Filter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
/**
* 做全局的相关操作
*/
//处理完相应的业务需要放行
return chain.filter(exchange);
}
/**
* 排序
* @return 返回数字越小会先执行
*/
@Override
public int getOrder() {
return 0;
}
}
启动类:
@EnableEurekaClient
@SpringBootApplication
public class GatewayApp {
public static void main(String[] args) {
SpringApplication.run(GatewayApp.class,args);
}
}
其他模块不需要做改动:
然后就可以通过网关访问微服务:
如路径:http://localhost/PROVIDER/find/2,http://localhost/consumer/feign//2
全局过滤器的添加是一个重量级的操作,添加局部过滤器参考官方文档:https://cloud.spring.io/spring-cloud-static/spring-cloud-gateway/2.1.0.RELEASE/single/spring-cloud-gateway.html#_gatewayfilter_factories
自备参考文档:链接:https://pan.baidu.com/s/1OaboaCoK8u608JQEh0LpJg
提取码:myname
9 SpringCloud的配置文档Config(从这开始就偏向运维了):
概述:这个组件主要是动态的更新各个微服务的配置文件用的,但是只单纯的使用这个去更新配置文件比较的繁琐,还需要结合bus(中间需要mq搭配)组件一起进行配置文件的更新!!!
这些他喵的都是为运维服务的!若是没有明确的要求,一般搭建微服务实在是懒得弄这个,配置文件太烦太烦,多还繁琐...................烦死了!
实现原理,搭建git仓库,然后在微服中搭建一个ConfigServer(pom3)服务,将git仓库绑定到ConfigServer,将该服务注册到EurekaServer上(EurekaClient依赖)!然后在各个需要动态更新配置文件的微服务上引入ConfigClient(pom1),同时需要添加SpringBoot的健康监控组件(pom2),在获取配置文件数据的类上添加@RefreshScope注解,开启动态刷新,其实核心还是使用Spring的健康监控!
刷新哪个微服务执行哪个微服务的请求,例如: http://localhost:8001/actuator/refresh
上面的 这个请求链接的只用根据项目改主机和端口,使用post发起请求即可(postman或者使用命令:curl -X POST http://localhost:8001/actuator/refresh )
pom1:
<!--config client --><dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
pom2:
<dependency> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
pom3:
<!-- config-server --><dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
</dependency>
配置文件参考,ConfigServer的配置文件名字为bootstrap,yml(这个名字的配置文件居然他喵的优先于application.*的配置文件):具体的配置参考百度吧,有点烦,用到了去百度吧!!!!!一般这个轮不到我配置,除非真他喵的没人了!太多了,记不住了,也不想整理这块的啦,
最主要的是知道这个东西干嘛的,大概咋用,百度贼多!!!!
10 SpringCloud的bus:
简述:其实就是为了解决使用Config每次更新配置文件还需要去每个微服务都执行请求刷新,实现原理其实就是mq,通过发送刷新命令到mq消息队列实现刷新呗!
11 SpringCloud的Stream:
简述:构建消息驱动微服务...........还是开发无感知的........
12SpringCloud的Sleuth+Zipkin:
简述:sleuth负责收集微服务请求链的相关参数(主要还是效率检测),Zipkin负责将前者收集的数据做web控制台的展示,还是服务运维的...
具体搭建,百度吧!好像只是jar包,跑起来就行!微服务需要导入相关坐标!
前面的案例代码包:链接:https://pan.baidu.com/s/1eyt9UX_rq_iTZ4b-FKJHrQ
提取码:MyReallyName