SpringCloud
一、引言
1.1 什么是SpringCloud?
SpringCloud是基于SpringBoot的一整套实现微服务的框架。他提供了微服务开发所需的配置管理、服务发现、断路器、智能路由、微代理、控制总线、全局锁、决策竞选、分布式会话和集群状态管理等组件。最重要的是,跟spring boot框架一起使用的话,会让你开发微服务架构的云服务非常好的方便。
1.2 什么是微服务?
单体架构中,所有的代码集中在同一个项目中。虽然便于管理,但是当项目足够庞大时,所有的业务模块都集中在一个JVM进程中,会面临很多问题:
1、项目过于臃肿,难以维护
2、资源无法隔离,某个资源出现问题,整个系统崩溃
3、拓展性差,通常只能水平拓展,缺乏灵活性
什么是微服务?
简单来说,微服务架构风格是一种将一个单一应用程序开发为一组小型服务的方法,每个服务运行在自己的进程中,服务间通信采用轻量级通信机制(通常用HTTP资源API)。这些服务围绕业务能力构建并且可通过全自动部署机制独立部署。这些服务共用一个最小型的集中式的管理,服务可用不同的语言开发,使用不同的数据存储技术。
微服务的特点:
1、根据业务模块划分服务
2、每个服务可以独立部署并且互相隔离
3、通过轻量的 API 调用服务
4、服务需要保证良好的高可用性
三高(高并发、高性能、高可用)
二、SpringCloud的注册中心 - Eureka
2.1 什么是注册中心?为什么要注册中心?
2.2 Eureka注册中心的搭建
1)创建父工程(继承SpringBoot工程、SpringCloud依赖)
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<!-- 当前工程继承了SpringBoot父工程 -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.1.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.qf</groupId>
<artifactId>springcloud_demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>Hoxton.SR5</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter</artifactId>
</dependency>
</dependencies>
<!-- 相当于让当前的工程继承了spring-cloud-dependencies工程 -->
<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>
<!--<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>-->
</project>
2)创建Eureka微服务(继承自定义的父工程)
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<!-- 继承自定义父工程 -->
<groupId>com.qf</groupId>
<artifactId>springcloud_demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<artifactId>microserver_eureka</artifactId>
<dependencies>
<!-- 添加Eureka Server依赖 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
3)启用Eureka服务(启动类)
@SpringBootApplication
@EnableEurekaServer
public class MicroserverEurekaApplication {
public static void main(String[] args) {
SpringApplication.run(MicroserverEurekaApplication.class, args);
}
}
4)配置application.yml
#配置注册中心的端口
server:
port: 20000
#配置微服务的名字(重要,千万别写下划线)
spring:
application:
name: eureka-server
#配置注册中心的地址
eureka:
client:
service-url:
defaultZone: http://localhost:20000/eureka
#当前微服务是否可以去调用其他微服务,默认为true,如果当前微服务是注册中心的话,则必须设置为false
fetch-registry: false
#当前微服务就不会注册到注册中心上(其他的微服务就不能调用当前微服务了,但是当前微服务仍然可以调用其他微服务)
register-with-eureka: false
5)启动注册中心,查看控制页面
2.3 服务的注册 - 微服务
1)添加相关依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
2)配置启动类
@SpringBootApplication
@EnableEurekaClient
public class MicroserverStuApplication {
public static void main(String[] args) {
SpringApplication.run(MicroserverStuApplication.class, args);
}
}
3)配置application.yml
server:
port: 8080
spring:
application:
name: micro-stu
eureka:
client:
service-url:
#配置注册中心的地址
defaultZone: http://localhost:20000/eureka
4)编写微服务提供的接口(controller)
package com.qf.controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/stu")
public class StuController {
@RequestMapping("/query/{sid}")
public String queryNameById(@PathVariable("sid") Integer sid){
switch (sid){
case 1:
return "小明";
case 2:
return "小红";
}
return "查无此人";
}
}
5)启动微服务实现注册
2.4 Eureka集群的搭建
Eureka集群的工作模式
注意:Eureka集群最多可以挂掉n-1台机器,仍然可以对外提供服务
集群搭建的步骤:
1)准备3个Eureka服务,错开端口
2)修改本机的hosts文件,给每个Eureka服务分配一个主机别名(实际的集群中不需要)
127.0.0.1 eureka1
127.0.0.1 eureka2
127.0.0.1 eureka3
hosts文件的路径:
window - C:\Windows\System32\drivers\etc\hosts
linux - /etc/hosts
3)修改eureka服务的注册地址
eureka:
client:
service-url:
defaultZone: http://eureka1:20000/eureka,http://eureka2:20001/eureka,http://eureka3:20002/eureka
2.5 Eureka的自我保护机制 - ?????
三、微服务的调用 - Ribbon + RestTemplate
3.1 什么是Ribbon?
Ribbon本质上是一个客户端负载均衡器,在SpringCloud中主要的作用包含两个:
1、去Eureka上发现服务
2、负载均衡调用指定微服务
什么是服务端负载均衡?
什么是客户端负载均衡?
注意:客户端负载均衡往往会配合注册中心一起使用
3.2 Ribbon的服务调用
1)创建一个班级服务,注册到注册中心之上,实现学生服务对班级服务的调用
2)调用方添加依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>
3)注册RestTemplate对象
/**
* 注册RestTemplate对象
* @return
*/
@Bean
@LoadBalanced
public RestTemplate getRestTemplate(){
return new RestTemplate();
}
4)在调用方使用RestTemplate发送请求
@Autowired
private RestTemplate restTemplate;
...
String clsName = restTemplate
.getForObject("http://micro-cls/cls/queryName/" + sid, String.class);
注意:
1、RestTemplate需要添加**@LoadBalanced才会配合Ribbon进行负载均衡和服务发现
2、RestTemplate请求的地址必须填写微服务的名称**
3.3 Ribbon负载均衡的策略
Ribbon实现负载均衡策略的核心接口 - IRule
设置负载均衡策略
/**
* 设置负载均衡策略
* @return
*/
@Bean
public IRule getRule(){
return new RandomRule();
}
四、微服务的调用 - Feign
Feign其实本质上就是Ribbon + Hystrix,提供了更加面向对象的服务调用方式
4.1 Feign的服务调用
1)创建教师微服务,注册到注册中心上
2)调用方(班级服务)添加依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
3)编写Feign的调用接口
@FeignClient(name = "micro-tea")
public interface TeaFeign {
@RequestMapping("/tea/queryName/{tid}")
String queryTeaName(@PathVariable Integer tid);
}
4)启动类添加注解,配置Feign接口的扫描
@EnableFeignClients(basePackages = "com.qf.feign")
5)使用Feign调用微服务
4.2 Feign的超时时间和重试
Feign本身拥有超时和重试的设定,但是默认是关闭的。Feign默认采用的是底层Ribbon的重试和超时的设定,一旦Feign的超时和重试开启,那么就会覆盖Ribbon的设置。
Ribbon的读超时默认是1s,连接超时默认也是1s,跨服务重试的次数默认1次,同服务重试的次数默认1次
feign的超时和重试的设置
ribbon:
ConnectTimeout: 1000 #毫秒 连接超时时间
ReadTimeout: 1000 #毫秒 读超时时间
MaxAutoRetries: 0 # 对当前实例的最大重试次数
MaxAutoRetriesNextServer: 1 # 切换实例的最大重试次数(如果还失败就切换下
注意:
1、实际开发过程中,可以根据业务适当的调整Read超时的大小
2、实际开发过程中,根据需要可以开启或者关闭重试,但是需要注意,如果开启了重试,就有重复请求的风险,尽可能的需要保证服务的被调用方的接口幂等
如何构造一个幂等的接口?
1、给数据库的某些字段设置唯一性
2、结合缓存服务器Redis实现接口幂等
五、断路器 - Hystrix
什么Hystrix(豪猪)?
Hystrix是微服务架构体系的保险丝
为什么要Hystrix?
在微服务架构中,根据业务来拆分成一个个的服务,服务与服务之间可以相互调用。
为了保证其高可用,单个服务通常会集群部署。由于网络原因或者自身的原因,
服务并不能保证100%可用,如果单个服务出现问题,调用这个服务就会出现线程阻塞,
此时若有大量的请求涌入,Servlet容器的线程资源会被消耗完毕,导致服务瘫痪。
服务与服务之间的依赖性,故障会传播,会对整个微服务系统造成灾难性的严重后果,
这就是服务故障的“雪崩”效应。为了解决这个问题,业界提出了断路器模型。
Hystrix是如何保证服务的可用性的
资源的隔离:Hystrix会通过一些方式(线程池隔离、信号量隔离),对Tomcat的线程池资源进行隔离限制,让Tomcat不要将所有的线程资源都用在一个微服务请求上
服务的降级:对于一些超时或者失败的请求,可以自动的去调用一个托底方法,返回一个默认值,这种方式称之为服务降级
请求的熔断:如果对某个微服务的请求失败达到一定的比例,熔断器就会自动的开启,一旦熔断器开启,所有发送给该微服务的请求,会立刻判定失败,调用降级方法。
5.1 在Feign中使用Hystrix
1)开启Feign中Hystrix的功能(默认关闭)
feign:
hystrix:
enabled: true
2)编写Feign接口的实现类(Hystrix的降级方法实现类)
@Component
public class TeaFeignHystrix implements TeaFeign {
/**
* 重写的方法就是所谓的降级方法(托底方法)
* @param tid
* @return
*/
@Override
public String queryTeaName(Integer tid) {
return "服务繁忙,请稍后再试!";
}
}
3)去设置Feign接口的注解
@FeignClient(name = "micro-tea", fallback = TeaFeignHystrix.class)
5.2 Hystrix的相关配置
hystrix:
command:
default:
execution:
isolation:
#资源隔离方法,THREAD:线程池隔离(默认值),SEMAPHORE:信号量隔离
strategy: THREAD
thread:
#调用的超时时间,默认1s
timeoutInMilliseconds: 5000
#是否开启Hystrix的超时,默认是开启,如果关闭了,Feign本身的超时仍然起作用
timeout:
enabled: true
#熔断器的配置,默认开启
circuitBreaker:
enabled: true
#单位时间内,使熔断器跳闸的最小异常请求(访问失败或者超时等)次数。如果失败的请求达到该值,则熔断器就会打开,默认值为20
requestVolumeThreshold: 2
#多久时间熔断器进入半开状态
sleepWindowInMilliseconds: 5000
#设置线程池隔离时,线程池大小,默认是10
threadpool:
default:
coreSize: 10
注意:如果开启了Hystrix,服务调用的超时时间,就取决于Ribbon和Hystrix中最小读取超时时间
5.3 搭建Hystrix的监控仪表盘
Hystrix 仪表盘主要用来监控微服务和微服务之间的调用情况
1)创建Hystrix仪表盘工程
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
</dependency>
2)启动类添加注解
@EnableHystrixDashboard
3)修改端口启动工程
4)访问浏览器地址,查看仪表盘的监控的页面
5)配置被监控的微服务(案例中,需要配置班级服务)
<!-- 添加依赖 -->
<dependency>
<groupId>com.netflix.hystrix</groupId>
<artifactId>hystrix-metrics-event-stream</artifactId>
</dependency>
/**
* @Author ken
* @Date 2019/2/11
* @Version 1.0
*/
@Configuration
public class HystrixConfiguration {
@Bean
public ServletRegistrationBean<HystrixMetricsStreamServlet> getServlet(){
HystrixMetricsStreamServlet hystrixMetricsStreamServlet = new HystrixMetricsStreamServlet();
ServletRegistrationBean<HystrixMetricsStreamServlet> servletRegistrationBean = new ServletRegistrationBean();
servletRegistrationBean.setServlet(hystrixMetricsStreamServlet);
servletRegistrationBean.addUrlMappings("/hystrix.stream");
servletRegistrationBean.setName("HystrixMetricsStreamServlet");
return servletRegistrationBean;
}
}
6)在仪表盘的监控路径中,添加班级服务的监控路径
sStreamServlet hystrixMetricsStreamServlet = new HystrixMetricsStreamServlet();
ServletRegistrationBean<HystrixMetricsStreamServlet> servletRegistrationBean = new ServletRegistrationBean();
servletRegistrationBean.setServlet(hystrixMetricsStreamServlet);
servletRegistrationBean.addUrlMappings("/hystrix.stream");
servletRegistrationBean.setName("HystrixMetricsStreamServlet");
return servletRegistrationBean;
}
}
6)在仪表盘的监控路径中,添加班级服务的监控路径
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200708205836200.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L01lbW9yeV95YW5nY2hhbw==,size_16,color_FFFFFF,t_70)