SpringCloud笔记目录
1. 说明
1.1 相关连接
SpringCloud官网: https://spring.io/projects/spring-cloud#learn.
Spring Cloud Netflix: https://www.springcloud.cc/spring-cloud-netflix.html.
SpringCloud中文api文档: https://www.springcloud.cc/spring-cloud-dalston.html.
SpringCloud中文网: https://www.springcloud.cc/.
1.2 版本说明
大版本说明:
SpringBoot | SpringCloud | 关系 |
---|---|---|
1.2.x | Angel版本(天使) | 兼容Spring Boot 1.2.x |
1.3.x | Brixton版本(布里克斯顿) | 兼容Spring Boot 1.3.x,也兼容Spring Boot 1.4.x |
1.4.x | Camden版本(卡姆登) | 兼容Spring Boot 1.4.x,也兼容Spring Boot 1.5.x |
1.5.x | Dalston版本(多尔斯顿) | 兼容Spring Boot 1.5.x,不兼容Spring Boot 2.0.x |
1.5.x | Edgware版本(埃奇韦尔) | 兼容Spring Boot 1.5.x,不兼容Spring Boot 2.0.x |
2.0.x | Finchley版本(芬奇利) | 兼容Spring Boot 2.0.x,不兼容Spring Boot 1.5.x |
2.1.x | Greenwich版本(格林威治) |
实际开发版本关系:
spring-boot-starter-parent | spring-cloud-dependencies | ||
---|---|---|---|
版本号 | 发布日期 | 版本号 | 发布日期 |
1.5.2.RELEASE | 2017年3月 | Dalston.RC1 | 2017年未知月 |
1.5.9.RELEASE | Nov,2017 | Edgware.RELEASE | Nov, 2017 |
1.5.16.RELEASE | sep,2018 | Edgware.SR5 | Oct,2018 |
1.5.20.RELEASE | Apr, 2019 | Edgware.SR5 | oct, 2018 |
2.0.2.RELEASE | May, 2018 | Finchley.BUILD-SNAPSHOT | 2018年未知月 |
2.0.6.RELEASE | Oct,2018 | Finchley.SR2 | Oct, 2018 |
2.1.4.RE&EASE | Apr, 2019 | Greenwich.SR1 | Mar, 2019 |
注意:使用最后两个
2. Rest学习环境搭建(服务提供者)
2.1 父项目
- 1.新建一个maven项目,作为父项目(可以把src目录删掉)
- 2.父项目的pom文件进行编写
<!-- 打包方式-->
<packaging>pom</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<!--统一对下面部分版本号进行管理-->
<junit.version>4.12</junit.version>
<log4j.version>1.2.17</log4j.version>
<lombok.version>1.16.18</lombok.version>
</properties>
<!-- 使用dependencyManagement进行管理 -->
<dependencyManagement>
<dependencies>
<!-- springcloud的依赖 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Greenwich.SR1</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- springboot的依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.1.4.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- 数据库 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
<!-- 数据源 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.10</version>
</dependency>
<!-- SpringBoot启动器 -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.2</version>
</dependency>
<!-- 以下4个主要是日志与测试相关的依赖 -->
<!-- junit -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
</dependency>
<!-- lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</dependency>
<!-- log4j -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>${log4j.version}</version>
</dependency>
<!-- logback -->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>1.2.3</version>
</dependency>
</dependencies>
</dependencyManagement>
2.2 实体类微服务(该微服务只存放实体类)
- 1.新建一个maven模块 springcloud-api(以后都新建maven项目)
- 2.由于父项目使用了dependencyManagement管理依赖,所以子项目需要什么依赖,直接导入就行,版本号直接用父项目的。
<!--当前Moudle自己需要的依赖,如果父依赖中已经配置了版本,这里就不用写了-->
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
- 3.新建一个数据库cloud01,并建表dept
- 4.写实体类并序列化
@Data
@NoArgsConstructor
@Accessors(chain = true) // 链式写法,这里扩展以下知识点
public class Dept implements Serializable {
private Long deptno;
private String dname;
// 这个数据库存在哪个数据库的字段,因为微服务,一个服务对应一个数据库,同一个信息可能存在不同的数据库
private String db_source;
public Dept(String dname) {
this.dname = dname;
}
/*
Dept dept = new Dept();
本来:
dept.setDeptno();
dept.setName();
链式写法:
dept.setDeptno().setName();
*/
}
2.3 编写服务模块(需要连接数据库)
- 1.新建一个maven模块 springcloud-provider-dept-8001
- 2.导入相关依赖,第一个依赖是拿到刚刚写的api中的实体类,把刚刚写的模块导入进来。
<dependencies>
<!--我们需要拿到实体类,所以要配置api module-->
<dependency>
<groupId>com.hui</groupId>
<artifactId>springcloud-api</artifactId>
<version>1.0</version>
</dependency>
<!--junit-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
</dependency>
<!--test-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-test</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--jetty-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jetty</artifactId>
</dependency>
<!--热部署工具-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
</dependencies>
- 3.新建application.yml进行配置
server:
port: 8001
# mybatis配置
mybatis:
type-aliases-package: com.hui.springcloud.pojo
mapper-locations: classpath:mybatis/mapper/*.xml
config-location: classpath:mybatis/mybatis-config.xml
# spring 的配置
spring:
application:
name: springcloud-provider-dept
datasource:
type: com.alibaba.druid.pool.DruidDataSource # 数据源
driver-class-name: org.gjt.mm.mysql.Driver
url: jdbc:mysql://localhost:3306/cloud01?useSSL=false&useUnicode=true&characterEncoding=UTF-8
username: root
password: 991113
- 4.mybatis-config.xml(这个写不写都行,主要是用于回顾知识点)
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<settings>
<setting name="cacheEnabled" value="true"/>
</settings>
</configuration>
- 5.新建mapper层,service层,contoller层,开始编写代码。
实现该方法后:
代码编写完毕,可见服务提供没问题:
3. Rest学习环境搭建(服务消费者)
- 1.新建一个maven模块 springcloud-consumer-dept-80
- 2.导入依赖(实体类+web就行了)
<!--实体类 + web-->
<dependencies>
<dependency>
<groupId>com.hui</groupId>
<artifactId>springcloud-api</artifactId>
<version>1.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
</dependencies>
- 3.在application.yml将端口更改为80,与服务提供者不一样
server:
port: 80
- 4.写一个配置类,将RestTemplate注入到Spring中。
@Configuration
public class ConfigBean {
@Bean
public RestTemplate getRestTemplate(){
return new RestTemplate();
}
}
- 5.编写消费者代码,可以根据http的Rest风格,直接调用服务提供者的服务
注意:
下面的自定义的REST_URL_PREFIX 常量直接写到这了,再后续学习中,应该放到注册中心,在注册中心获取。
@RestController
public class DeptConsumerController {
// 理解:消费者不应该有service层
// RestTemplate 供我们直接调用 注册到Spring中
// (url, 实体 Map, Class<T> responseType)
@Autowired
private RestTemplate restTemplate; // 说白了就是提供了多种便捷访问远程http服务的方法,简单的restful服务模板
// 定义一个前缀
private static final String REST_URL_PREFIX = "http://localhost:8001";
// 服务要在http://localhost:8001去拿
@RequestMapping("/consumer/dept/get/{id}")
public Dept get(@PathVariable("id") Long id){
return restTemplate.getForObject(REST_URL_PREFIX+"/dept/get/"+id, Dept.class);
}
// 服务要在http://localhost:8001去拿
@RequestMapping("/consumer/dept/add")
public boolean add(Dept dept){
return restTemplate.postForObject(REST_URL_PREFIX+"/dept/add",dept, Boolean.class);
}
// 服务要在http://localhost:8001去拿
@RequestMapping("/consumer/dept/list")
public List<Dept> queryAll(){
return restTemplate.getForObject(REST_URL_PREFIX+"/dept/list", List.class);
}
}
4. Eureka服务注册与发现
4.1 Eureka概述
Eureka是Netflix的一个子模块,也是核心模块之一。Eureka是 一个基于REST的服务,用于定位服务,以实现云端中间层服务发现和故障转移,服务注册与发现对于微服务来说是非常重要的,有了服务发现与注册,只需要使用服务的标识符,就可以访问到服务,而不需要修改服务调用的配置文件了,功能类似于Dubbo的注册中心,比如Zookeeper;
4.2 原理
- SpringCloud封装了NetFlix公司开发的Eureka模块来实现服务注册和发现(对比Zookeeper)。
- Eureka采用了C-S的架构设计,EurekaServer 作为服务注册功能的服务器,他是服务注册中心。
- 而系统中的其他微服务。使用Eureka的客户端连接到EurekaServer并维持心跳连接。 这样系统的维护人员就可以通过EurekaServer来监控系统中各个微服务是否正常运行,SpringCloud的一 些其他模块(比如Zuul)就可以通过EurekaServer来发现系统中的其他微服务,并执行相关的逻辑;
两个组件:
- Eureka包含两个组件: Eureka Server 和 Eureka Client。
- Eureka Server提供服务注册服务,各个节点启动后,会在EurekaServer中进行注册,这样Eureka Server中的服务注册表中将会存储所有可用服务节点的信息,服务节点的信息可以在界面中直观的看到。
- Eureka Client是一个java客户端, 用于简化EurekaServer的交互,客户端同时也具备一个内置的, 使用轮询负载算法的负载均衡器。在应用启动后,将会向EurekaServer发送心跳(默认周期为30秒)。如果Eureka Server在多个心跳周期内没有接收到某个节点的心跳,EurekaServer将会从服务注册表中把这个服务节点移除掉(默认周期为90秒)。
三大角色:
- Eureka Server:提供服务的注册与发现。
- Service Provider:将自身服务注册到Eureka中,从而使消费方能够找到。
- Service Consumer:服务消费方从Eureka中获取注册服务列表,从而找到消费服务。
4.3 Eureka服务
- 1.新建maven模块 springcloud-eureka-7001
- 2.导入依赖 (导入服务的)
<!--eureka-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka-server</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
<!--热部署插件-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
- 3.编写配置文件application.yml
server:
port: 7001
# Eureka配置
eureka:
instance:
hostname: localhost # Eureka 服务端的实例名称
client:
register-with-eureka: false # 表示是否向eureka注册中心注册自己
fetch-registry: false # 如果为false,则表示自己为注册中心
service-url: # 监控页面
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
- 4.在启动类上加上 @EnableEurekaServer 注解,就可以启动服务了。
// 注册之后访问http://localhost:7001/ 就行了
@SpringBootApplication
@EnableEurekaServer // 服务端的启动类
public class EurekaServer_7001 {
public static void main(String[] args) {
SpringApplication.run(EurekaServer_7001.class,args);
}
}
- 5.启动之后访问http://localhost:7001/,如图所示:
4.4 服务提供者注册Eureka
- 1.使用2.3中的服务提供者 springcloud-provider-dept-8001
- 2.加入依赖(加入下图的第一个)
<!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-eureka -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
- 3.在配置文件application.yml中配置Eureka相关配置,url指到4.3中配置的7001模块Eureka服务。
# Eureka 的配置
eureka:
client:
service-url:
defaultZone: http://localhost:7001/eureka/
instance:
instance-id: springcloud-provider-dept8001 # 修改Eureka上的默认描述信息
- 4.开启注解支持,在启动类中增加 @EnableEurekaClient 注解
// 启动类
@SpringBootApplication
@EnableEurekaClient // 在服务启动后,自动注册到Eureka中
public class DeptProvider_8001 {
public static void main(String[] args) {
SpringApplication.run(DeptProvider_8001.class,args);
}
}
- 5.启动服务(先启动4.3的端口号为7001的服务,再启动这个)
- 6.完善监控信息
加入依赖:
<!--actuator完善监控信息-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
进行配置application.yml配置文件(随意配置,就是返回的信息)
# info配置
info:
app.name: huige-springcloud
查看监控信息
- 7.自我保护机制
某时刻某一个微服务不可以用了,eureka不会立刻清理,依旧会对该微服务的信息进行保存!
默认情况下,如果EurekaServer在一 定时间内没有接收到某个微服务实例的心跳,EurekaServer将 会注销该实例(默认90秒)。但是当网络分区故障发生时,微服务与Eureka之间无法正常通行,以上行为可能变得非常危险了–因为微服务本身其实是健康的,此时本不应该注销这个服务。Eureka通过自我保护机制来解决这个问题–当EurekaServer节点在短时间内丢失过多客户端时(可能发生了网络分区故障),那么这个节 点就会进入自我保护模式。一旦进入该模式, EurekaServer就会保护服务注册表中的信息 ,不再删除服务注册表中的数据(也就是不会注销任何微服务)。当网络故障恢复后,该EurekaServer节点会自动退出自我保护模式。
在自我保护模式中,EurekaServer会保护服务注册表中的信息, 不再注销任何服务实例。当它收到的心跳数重新恢复到阈值以上时,该EurekaServer 节点就会自动退出自我保护模式。它的设计哲学就是宁可保留错误的服务注册信息,也不盲目注销任何可能健康的服务实例。一句话:好死不如赖活着。
- 8.扩展知识,在服务提供者查看微服务信息。服务发现机制
// 获取配置的信息,得到具体的微服务
@Autowired
private DiscoveryClient client;
// 注册进来的微服务,获取一些信息
@GetMapping("/dept/discovery")
public Object discovery(){
// 获取微服务列表的清单
List<String> services = client.getServices();
System.out.println("disvocery=>services:"+services);
// 得到一个具体的微服务,通过具体的微服务id, 也就是applicationName
List<ServiceInstance> instances = client.getInstances("springcloud-provider-dept");
for (ServiceInstance instance : instances) {
System.out.println(instance.getHost() + "----" + instance.getPort()+ "----" + instance.getUri());
}
return instances;
}
在启动类处增加 @EnableDiscoveryClient // 服务发现 注解
可以看到相关信息:
4.5 配置Eureka集群(一个大坑)
一个大坑:注意修改本机的url映射,别用localhost,不然集群不成功。
修改主机url映射;
- 1.新建两个模块7002和7003,并把7001中的配置文件.yml文件复制过去并改端口号。把pom文件复制过去,把启动类(修改名字)复制过去。
- 2.进行配置,让他们之间产生关系
在配置文件中:(最后一行关联其他两个服务注册中心)此为端口号为7002注册中心的配置。另外两个类似。
注意:在进行集群的时候,除了把本机url映射改变,下面第四行也得改!!还有11行。
# Eureka配置
eureka:
instance:
hostname: host7002.com # localhost改成前面的 # Eureka 服务端的实例名称
client:
register-with-eureka: false # 表示是否向eureka注册中心注册自己
fetch-registry: false # 如果为false,则表示自己为注册中心
service-url: # 监控页面
# 进行集群的时候的时候
# defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
defaultZone: http://host7001.com:7001/eureka/,http://host7003.com:7003/eureka/
- 3.服务提供者发布服务的时候,同时发给三个注册中心
- 4.运行访问
4.6 Eureka与Zookeeper对比
CAP:一致性(Consistency, C)、可用性(Availability, A)、分区容错性(Partition Tolerance, P)。
- Zookeeper满足CP
- Eureka满足AP
因此,Eureka可以很好的应对因网络故障导致部分节点失去联系的情况,而不会像zookeeper那样使整 个注册服务瘫痪。
5. 负载均衡及Ribbon
5.1 Ribbon概述
是什么?
- Spring Cloud Ribbon是基于Netflix Ribbon实现的一套** 客户端负载均衡**的工具。
- 简单的说,Ribbon是Netflix发布的开源项目,主要功能是提供客户端的软件负载均衡算法,将NetFlix的中间层服务连接在一起。Ribbon的客户端组件提供一系列完整的配置项如:连接超时、重试等等。简单的说,就是在配置文件中列出LoadBalancer(简称LB:负载均衡)后面所有的机器,Ribbon会自动的帮助你基于某种规则(如简单轮询,随机连接等等)去连接这些机器。我们也很容易使用Ribbon实现自定义的负载均衡算法!
能干什么?
- LB,即负载均衡(Load Balance),在微服务或分布式集群中经常用的一种应用。
- 负载均衡简单的说就是将用户的请求平摊的分配到多个服务上,从而达到系统的HA(高可用)。
- 常见的负载均衡软件有Nginx,Lvs(Linux Virtual Server)等等。
- dubbo、SpringCloud中均给我们提供了负载均衡,SpringCloud的负载均衡算法可以自定义负
载均衡简单分类:
- 集中式LB
即在服务的消费方和提供方之间使用独立的LB设施,如Nginx,由该设施负责把访问请求通过某种策略转发至服务的提供方!
- 进程式LB
将LB逻辑集成到消费方,消费方从服务注册中心获知有哪些地址可用,然后自己再从这些地址中选出一个合适的服务器。
Ribbon就属于进程内LB,它只是一个类库,集成于消费方进程,消费方通过它来获取到服务提供方
5.2 应用到服务消费者
- 1.使用第3部分搭建的springcloud-consumer-dept-80 服务消费者。
- 2.添加依赖
<!-- ribbon -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-ribbon</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
<!--Eureka-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
- 3.编写配置(连接到3个注册中心)
# Eureka 的配置
eureka:
client:
register-with-eureka: false # 不向eureka注册自己
service-url:
defaultZone: http://host7001.com:7001/eureka/,http://host7002.com:7002/eureka/,http://host7003.com:7003/eureka/
- 4.启动类加上 @EnableEurekaClient 注解
- 5.在配置类中,将RestTemplate注入spring的方法上添加注解 @LoadBalanced
- 6.消费者控制层中的前缀名也改成服务提供者的主机名
- 7.访问成功
5.3 多个服务提供者时,提供负载均衡
多个数据库(cloud01,cloud02,cloud03),多个服务提供者(8001,8002,8003)
- 1.新建两个数据库,三个数据库分别为cloud01、could02、could03
三个数据库中的dept表只有db_source不一样。
- 2.新建两个服务提供者8002,8003
并将pom文件、resources资源文件复制过去,修改.yml文件中的端口号以及数据库名、id名。
- 3.把所有的业务逻辑代码(java文件夹下的)粘贴一份(并把启动类改一下)。
- 4.此时同时启动注册中心、三个服务提供者、一个服务消费者
可见服务都注册成功:
启动服务消费者:
可以看到Ribbon默认的负载均衡算法是轮询,也可以自定义。
5.4 自定义负载均衡算法
消费者启动类加注解 @RibbonClient(name=“服务名”,configuration = 自定义Ribbon类.class)
自定义配置类:(MyRule)
@Configuration
public class MyRule {
@Bean
public IRule myRule(){
return new HuiRule();
}
}
自定义算法:(HuiRule)
public class HuiRule extends AbstractLoadBalancerRule {
// 每个服务,访问5次,换下一个服务
// total=0, 默认为0,如果为5指向下一个节点
// index=0, 默认为0,如果total=5,index+1
private int total = 0;// 被调用次数
private int currentIndex = 0;
public Server choose(ILoadBalancer lb, Object key) {
if (lb == null) {
return null;
} else {
Server server = null;
while(server == null) {
if (Thread.interrupted()) {
return null;
}
List<Server> upList = lb.getReachableServers();
List<Server> allList = lb.getAllServers();
int serverCount = allList.size();
if (serverCount == 0) {
return null;
}
// int index = this.chooseRandomInt(serverCount);
// server = (Server)upList.get(index);
// ----------------------自定义
if(total<5){
server = upList.get(currentIndex);
total++;
}else{
total=0;
currentIndex++;
if(currentIndex>upList.size()){
currentIndex=0;
}
server = upList.get(currentIndex);
}
// ---------------------
if (server == null) {
Thread.yield();
} else {
if (server.isAlive()) {
return server;
}
server = null;
Thread.yield();
}
}
return server;
}
}
protected int chooseRandomInt(int serverCount) {return ThreadLocalRandom.current().nextInt(serverCount);}
public Server choose(Object key) {return this.choose(this.getLoadBalancer(), key);}
public void initWithNiwsConfig(IClientConfig clientConfig) {}
}
6. Hystrix
6.1 Hystrix概述
-
1.分布式系统面临的问题
复杂分布式体系结构中的应用程序有数十个依赖关系,每个依赖关系在某些时候将不可避免的失败! -
2.服务雪崩
多个微服务之间调用的时候,假设微服务A调用微服务B和微服务C,微服务B和微服务C又调用其他的微服务,这就是所谓的“扇出”、如果扇出的链路上某个微服务的调用响应时间过长或者不可用,对微服务A的调用就会占用越来越多的系统资源,进而引起系统崩溃,所谓的“雪崩效应"。
对于高流量的应用来说,单一的后端依赖可能会导致所有服务器上的所有资源都在几秒中内饱和。比失败更糟糕的是,这些应用程序还可能导致服务之间的延迟增加,备份队列,线程和其他系统资源紧张,导致整个系统发生更多的级联故障,这些都表示需要对故障和延迟进行隔离和管理,以便单个依赖关系的失败,不能取消整个应用程序或系统。
我们需要:弃车保帅。
-
3.什么是Hystrix?
Hystrix是一个用于处理分布式系统的延迟和容错的开源库,在分布式系统里,许多依赖不可避免的会调用失败,比如超时,异常等,Hystrix能够保证在一个依赖出问题的情况下,不会导致整体服务失败,避免级联故障,提高分布式系统的弹性。
“断路器” 本身是一种开关装置,当某个服务单元发生故障之后,通过断路器的故障监控(类似熔断保险丝), 向调用方返回一个服务预期的,可处理的备选响应(FallBack) ,而不是长时间的等待或者抛出调用方法无法处理的异常,这样就可以保证了服务调用方的线程不会被长时间,不必要的占用,从而避免了故障在分布式系统中的蔓延,乃至雪崩。 -
4.Hystrix能干嘛?
服务降级
服务熔断
服务限流
接近实时的监控 -
5.服务熔断是什么?
熔断机制是对应雪崩效应的一种微服务链路保护机制。
当扇出链路的某个微服务不可用或者响应时间太长时,会进行服务的降级,进而熔断该节点微服务的调用,快速返回错误的响应信息。当检测到该节点微服务调用响应正常后恢复调用链路。在SpringCloud框架里熔断机制通过Hystrix实现。Hystrix 会监控微服务间调用的状况,当失败的调用到一定阈值,缺省是5秒内20次调用失败就会启动熔断机制。熔断机制的注解是 @HystrixCommand .
6.2 Hystrix服务熔断
- 1.新建 springcloud-provider-dept-hystrix-8001 模块
将springcloud-provider-dept-8001内容复制过去。 - 2.新增依赖
<!--hystrix-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
- 3.在控制层使用 @HystrixCommand(fallbackMethod = “”) 注解
- 4.在启动类处使用 @EnableCircuitBreaker 添加熔断的支持.
- 5.运行,此时访问不存在的id时,会运行备选方法
- 6.扩展知识,在服务提供者的配置文件中配置Eureka时。
如果设置为false(默认):
改为true:
6.3 Hystrix服务降级
6.4 Hystrix:Dashboard流监控
- 1.新建模块 springcloud-consumer-hystrix-dashboard-9001
- 2.添加依赖
<!--hystrix-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
<!--hystrix-dashboard-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix-dashboard</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
- 3.配置文件更改端口号
server:
port: 9001
- 4.启动类使用注解 @EnableHystrixDashboard
- 5.启动项目,访问9001端口http://localhost:9001/hystrix(至此,监控页面写完了)
- 6.在需要被监控的服务提供者那添加依赖(服务提供者一定要有服务熔断)
<!--actuator完善监控信息-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!--hystrix-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
- 7.在服务提供者启动类增加一个Servlet(这是固定的)
// 启动类
@SpringBootApplication
@EnableEurekaClient // 在服务启动后,自动注册到Eureka中
@EnableDiscoveryClient // 服务发现
public class DeptProvider_8001 {
public static void main(String[] args) {
SpringApplication.run(DeptProvider_8001.class,args);
}
// 增加一个Servlet
@Bean
public ServletRegistrationBean hystrixMetricsStreamServlet(){
ServletRegistrationBean registrationBean = new ServletRegistrationBean(new HystrixMetricsStreamServlet());
registrationBean.addUrlMappings("/actuator/hystrix.stream");
return registrationBean;
}
}
- 8.把注册中心7001、监控面板9001、服务提供者8001同时启动。
访问http://localhost:8001/actuator/hystrix.stream:
注意:服务提供者一定要有服务熔断,不然都是ping!!!
然后进行填入:
可以看监控面板:
相关说明:
7. Zuul路由网关
7.1 Zuul概述
官网文档:https://github.com/Netflix/zuul.
- 1.什么是Zuul
Zuul包含了对请求的路由和过滤两个最主要的功能:
其中路由功能负责将外部请求转发到具体的微服务实例上,是实现外部访问统一入口的基础,而过滤器功能则负责对请求的处理过程进行干预,是实现请求校验,服务聚合等功能的基础。Zuul和Eureka进行整合,将Zuul自身注册为Eureka服务治理下的应用,同时从Eureka中获得其他微服务的消息,也即以后的访问微服务都是通过Zuul跳转后获得。
注意:Zuul服务最终还是会注册进Eureka。
提供:代理+路由+过滤三大功能!
- 2.Zuul能干嘛
路由
过滤
7.2 zuul代码
- 1.新建项目 springcloud-zuul-9527
- 2.导入依赖
<!--zuul-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zuul</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
<!-- ribbon -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-ribbon</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
<!--Eureka-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
<!--hystrix-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
<!--hystrix-dashboard-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix-dashboard</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
- 3.编写配置文件
server:
port: 9527
spring:
application:
name: springcloud-zuul
eureka:
client:
service-url:
defaultZone: http://host7001.com:7001/eureka/,http://host7002.com:7002/eureka/,http://host7003.com:7003/eureka/
instance:
instance-id: zuul9527.com
prefer-ip-address: true
info:
app.name: huige-springcloud-zuul
school.name: henu
- 4.启动类添加注解 @EnableZuulProxy // 开启(提前开启注册中心Eureka)
- 5.配置路由(重要)
# 路由网关
zuul:
routes:
mydept.serviceId: springcloud-provider-dept
mydept.path: /mydept/**
ignored-services: "*" # 隐藏原来所有的服务名,即不能通过所有的服务名进行访问
prefix: /hui # 设置公共的前缀
# ignored-services: springcloud-provider-dept # 不能通过原来的服务名进行访问
8.SpringCloud config分布式配置
8.1 概述
分布式系统面临的–配置文件的问题
微服务意味着要将单体应用中的业务拆分成一个个子服务,每个服务的粒度相对较小,因此系统中会出现大量的服务,由于每个服务都需要必要的配置信息才能运行,所以一套集中式的,动态的配置管理设施是必不可少的。SpringCloud提供了ConfigServer来解决这个问题,我们每一个微服务自己带着一个application.yml,那上百的的配置文件要修改起来,岂不是要发疯!
SpringCloud config分布式配置中心
SpringCloud Config为微服务架构中的微服务提供集中化的外部配置支持,配置服务器为各个不同微服务应用的所有环节提供了一个中心化的外部配置。
8.2 config服务端配置
- 1.新建模块 springcloud-config-server-3344
- 2.导入依赖
<dependencies>
<!-- config-server -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
<version>2.1.1.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
- 3.编写配置文件application.yml
server:
port: 3344
spring:
application:
name: springcloud-config-server
# 连接远程仓库
cloud:
config:
server:
git:
uri: https://gitee.com/liu_yaohui/springcloud-config.git # https的,不是ssh的
- 4.启动类添加注解 @EnableConfigServer
通过config-server.可以连接到git,访问其中的资源以及配置。
有如下方式访问资源文件:
/{application}/{profile}[/{label}] 这里的label的意思是分支,比如master
/{application}-{profile}.yml
/{label}/{application}-{profile}.yml
/{application}-{profile}.properties
/{label}/{application}-{profile}.properties
如下,就可以访问到码云(或github)上的文件了:
或者这么访问:
再或者:
8.3 config客户端配置
- 1.新建 springcloud-config-client-3355
- 2.导入依赖
<!-- config-client -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
<version>2.1.1.RELEASE</version>
</dependency>
<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>
- 3.新建两个配置文件:bootstrap.yml(系统级)和application.yml(用户级)
bootstrap.yml:连接到config服务端配置的某个文件
# 系统级别的配置spring:
spring:
cloud:
config:
uri: http://localhost:3344
name: config-client # 需要从git上读取的资源名称,不需要后缀
profile: dev
label: master
application.yml
# 用户级别的配置:
spring:
application:
name: springcloud-config-client-3355
此时使用的就是远程的配置信息了
- 4.测试效果(这里只为测试)
编写一个controller,把github上的配置信息注入到本地代码中:
@RestController
public class ConfigClientController {
@Value("${spring.application.name}")
private String applicationName;
@Value("${eureka.client.service-url.defaultZone}")
private String eurekaServer;
@Value("${server.port}")
private String port;
@RequestMapping("/")
public String getConfig(){
return applicationName + " , " + eurekaServer + " , " + port;
}
}
注意:运行项目,访问的端口号就是使用远程配置信息里的端口号: