前言:springboot整合springcloud的eureka、配置中心、服务调用、Hystrix、Zuul网关
项目结构:
一、环境准备
1、创建maven父工程,并导入依赖
<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.source>1.8</maven-compiler.source>
<maven-compiler.target>1.8</maven-compiler.target>
<junit-version>4.12</junit-version>
</properties>
<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.22</version>
</dependency>
<!--springboot启动器-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.1</version>
</dependency>
<!--junit-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit-version}</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>1.2.3</version>
</dependency>
<!--lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.18</version>
</dependency>
<!--log4j日志-->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
</configuration>
</plugin>
</plugins>
</build>
二、Eureka注册中心
1、Eureka单机模式
1.1、创建maven子工程(服务),并导入依赖
<!--导入父工程依赖-->
<parent>
<artifactId>springcloud-001</artifactId>
<groupId>com.springcloud</groupId>
<version>1.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<!--导入项目依赖-->
<dependencies>
<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>
</dependencies>
1.2、创建application.yaml配置文件
server:
port: 7001
#Eureka的配置
eureka:
instance:
hostname: springcloud-eureka #Eureka服务端的实例名称(如果配置集群,此处不能写localhost或127.0.0.1)
client:
register-with-eureka: false # 表示是否想eureka注册中心注册自己
fetch-registry: false #结果为false表示自己为注册中心
service-url:
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
1.3、开启eureka服务注册功能
@SpringBootApplication
@EnableEurekaServer //服务端的启动类,可以接受别人注册进来
public class SpringCloudEurekaApplication {
public static void main(String[] args) {
SpringApplication.run(SpringCloudEurekaApplication.class,args);
}
}
2、eureka集群模式
2.1、改造单机模式
修改application.yaml文件
注:集群模式下eureka.instance.hostname属性不能写localhost或127.0.0.1
server:
port: 7001
#Eureka的配置
eureka:
instance:
hostname: springcloud-eureka #Eureka服务端的实例名称(如果配置集群,此处不能写localhost或127.0.0.1)
client:
register-with-eureka: false # 表示是否想eureka注册中心注册自己
fetch-registry: false #结果为false表示自己为注册中心
service-url:
defaultZone: http://springcloud-eureka02:7002/eureka/,http://springcloud-eureka03:7003/eureka/ #监控页面
2.2、创建maven子工程(eureka2)
2.2.1、步骤参照eureka单机模式
2.2.2、修改application.yaml文件
server:
port: 7002
#Eureka的配置
eureka:
instance:
hostname: springcloud-eureka02 #Eureka服务端的实例名称(如果配置集群,此处不能写localhost或127.0.0.1)
client:
register-with-eureka: false # 表示是否想eureka注册中心注册自己
fetch-registry: false #结果为false表示自己为注册中心
service-url:
defaultZone: http://springcloud-eureka:7001/eureka/,http://springcloud-eureka03:7003/eureka/ #监控页面
2.3、创建maven子工程(eureka3)
2.3.1、步骤参照eureka单机模式
2.3.2、修改application.yaml文件
server:
port: 7003
#Eureka的配置
eureka:
instance:
hostname: springcloud-eureka03 #Eureka服务端的实例名称(如果配置集群,此处不能写localhost或127.0.0.1)
client:
register-with-eureka: false # 表示是否想eureka注册中心注册自己
fetch-registry: false #结果为false表示自己为注册中心
service-url:
defaultZone: http://springcloud-eureka02:7002/eureka/,http://springcloud-eureka:7001/eureka/ #监控页面
2.4、修改hosts配置文件
添加:
- 127.0.0.1 springcloud-eureka
- 127.0.0.1 springcloud-eureka02
- 127.0.0.1 springcloud-eureka03
# Copyright (c) 1993-2009 Microsoft Corp.
#
# This is a sample HOSTS file used by Microsoft TCPIP for Windows.
#
# This file contains the mappings of IP addresses to host names. Each
# entry should be kept on an individual line. The IP address should
# be placed in the first column followed by the corresponding host name.
# The IP address and the host name should be separated by at least one
# space.
#
# Additionally, comments (such as these) may be inserted on individual
# lines or following the machine name denoted by a '#' symbol.
#
# For example
#
# 102.54.94.97 rhino.acme.com # source server
# 38.25.63.10 x.acme.com # x client host
# localhost name resolution is handled within DNS itself.
# 127.0.0.1 localhost
# 1 localhost
127.0.0.1 activate.navicat.com
#添加如下配置
127.0.0.1 springcloud-eureka
127.0.0.1 springcloud-eureka02
127.0.0.1 springcloud-eureka03
2.5、分别启动eureka服务
三、springcloud配置中心
1、在远程服务(github)创建配置文件
2、创建配置中心服务端
2.1、创建maven子工程,导入依赖
<!--导入父工程依赖-->
<parent>
<artifactId>springcloud-001</artifactId>
<groupId>com.springcloud</groupId>
<version>1.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<!--导入项目依赖-->
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
</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>
</dependencies>
2.2、创建application.yaml文件
server:
port: 3344
spring:
application:
name: springcloud-config-service
#连接远程仓库
cloud:
config:
server:
git:
uri: https://github.com/ces/git_test01.git
username: 用户名 #github用户名
password: 密码 #github用户密码
2.3、启动服务
@SpringBootApplication
@EnableConfigServer //开启远程配置服务
public class SpringCloudConfigService3344 {
public static void main(String[] args) {
SpringApplication.run(SpringCloudConfigService3344.class,args);
}
}
访问方式:/{label}/{name}-{profile}.想要展示的文件类型,即/节点/文件名-环境/
如:http://127.0.0.1:3344/master/spring_config-dev.json
3、创建配置中心客户端
3.1、创建maven子工程,导入依赖
<!--导入父工程依赖-->
<parent>
<artifactId>springcloud-001</artifactId>
<groupId>com.springcloud</groupId>
<version>1.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<!--导入项目依赖-->
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</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>
</dependencies>
3.2、创建配置文件
application.yaml
#用户级别的配置
spring:
application:
name: springcloud-config-client3355
server:
port: 3355
bootstrap.yml
#系统级别的配置
spring:
cloud:
config:
uri: http://localhost:3344
name: spring_config #从远程仓库上读取的资源名称,不需要后缀名
profile: dev
label: master #指定被读取资源所在节点名称
3.3、创建controller类(便于测试)
@RestController
public class ConfigClientController {
@Value("${spring.application.name}") //获取远程配置文件的属性值
private String applicationName;
@Value("${eureka.service}") //获取远程配置文件的属性值
private String eurekaService;
@Value("${server.port}") //获取远程配置文件的属性值
private String port;
@RequestMapping("/getConfig")
public String getConfig(){
return "applicatin:" + applicationName +
" eurekaService:" + eurekaService +
" port:" + port;
}
}
3.4、启动客户端测试
@SpringBootApplication
public class ConfigClient_3355 {
public static void main(String[] args) {
SpringApplication.run(ConfigClient_3355.class,args);
}
}
四、服务调用
1、概括
spring cloud的 Netflix 中提供了两个组件实现负载均衡调用:ribbon 和 feign 。
- Ribbon:是一个基于 HTTP 和 TCP 客户端 的负载均衡的工具。Ribbon需要自己构建http请求,模拟http请求然后使用RestTemplate发送给其他服务,步骤相当繁琐。启动类注解Ribbon是 @RibbonClient
- Feign:是在 Ribbon的基础上进行了一次改进,是一个使用起来更加方便的 HTTP 客户端。采用接口的方式, 只需要创建一个接口,然后在上面添加注解即可 ,将需要调用的其他服务的方法定义成抽象方法即可, 不需要自己构建http请求。启动类注解feign的是 @EnableFeignClients
1.1、 区别
- 1、协议
Dubbo:支持多传输协议(Dubbo、Rmi、http、redis等等),可以根据业务场景选择最佳的方式。非常灵活。默认的Dubbo协议:利用Netty,TCP传输,单一、异步、长连接,适合数据量小、高并发和服务提供者远远少于消费者的场景。
Feign:基于Http传输协议,短连接,不适合高并发的访问。 - 2、负载均衡
Dubbo: 支持4种算法(随机、轮询、活跃度、Hash一致性),而且算法里面引入权重的概念。配置的形式不仅支持代码配置,还支持Dubbo控制台灵活动态配置。负载均衡的算法可以精准到某个服务接口的某个方法。
Feign: 只支持N种策略:轮询、随机、ResponseTime加权。负载均衡算法是Client级别的。 - 3、容错策略
Dubbo: 支持多种容错策略:failover、failfast、brodecast、forking等,也引入了retry次数、timeout等配置参数。
Feign: 利用熔断机制来实现容错的,处理的方式不一样。
注:以下均基于整合mybatis测试
2、创建服务提供端
2.1、创建maven子工程,并导入依赖
<!--导入父工程依赖-->
<parent>
<artifactId>springcloud-001</artifactId>
<groupId>com.springcloud</groupId>
<version>1.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<!--导入项目依赖-->
<dependencies>
<!--完善监控信息-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.api</groupId>
<artifactId>springcloud-api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
<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>
<!--test-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
<!--web-->
<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>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
2.2、创建pojo类
@Data
@NoArgsConstructor
@Accessors(chain = true) //开启支持链式写法
public class Dept implements Serializable {
private int id;
private String dname;
private String dbSource;
public Dept(String dname){
this.dname = dname;
}
}
2.3、创建dao接口类
@Mapper //org.apache.ibatis.annotations.Mapper
@Repository
public interface DeptDao {
List<Dept> findList();
Dept findById(int id);
}
2.4、创建service接口类
public interface DeptService {
List<Dept> findList();
Dept findById(int id);
}
2.5、创建service接口实现类
@Service
public class DeptServiceImpl implements DeptService {
@Autowired
DeptDao deptDao;
public List<Dept> findList() {
return deptDao.findList();
}
public Dept findById(int id) {
return deptDao.findById(id);
}
}
2.6、创建dao的mapper文件
在目录resources/mybatis/mapper创建
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.provicer.dao.DeptDao">
<select id="findList" resultType="dept">
select * from dept
</select>
<select id="findById" parameterType="int" resultType="dept">
select * from dept where id = #{id}
</select>
</mapper>
2.7、创建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"/>
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
</configuration>
2.8、创建application.yaml文件
server:
port: 8081
mybatis:
type-aliases-package: com.api.pojo
mapper-locations: classpath:mybatis/mapper/*.xml
config-location: classpath:mybatis/mybatis-config.xml
spring:
application:
name: springcloud-provider-dept
datasource:
type: com.alibaba.druid.pool.DruidDataSource
username: root
driver-class-name: com.mysql.jdbc.Driver
password: 123456
url: jdbc:mysql://localhost:3306/spring_cloud_test?useUnicode=true&characterEncoding=utf8&useSSL=false&useSSL=false&serverTimezone=UTC
#Eureka配置
eureka:
client:
service-url:
defaultZone: http://springcloud-eureka:7001/eureka/,http://springcloud-eureka02:7002/eureka/,http://springcloud-eureka03:7003/eureka/ #注册地址
instance:
instance-id: springcloud-provider-dept #修改eureka上的默认描述
#点击eureka的描述,显示信息
info:
app.name: springcloud-provider
company.name: zyhlwgs
2.9、创建启动类并启动应用
@SpringBootApplication
@EnableEurekaClient //在服务启动后,自动注册到Eureka中
@EnableDiscoveryClient //服务发现
public class SpringCloudProviderApplication {
public static void main(String[] args) {
SpringApplication.run(SpringCloudProviderApplication.class,args);
}
}
3、Ribbon服务调用
3.1、创建maven子工程,并导入依赖
<!--导入父工程依赖-->
<parent>
<artifactId>springcloud-001</artifactId>
<groupId>com.springcloud</groupId>
<version>1.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<!--导入项目依赖-->
<!--消费者 实体类+web -->
<dependencies>
<!--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>
<dependency>
<groupId>org.api</groupId>
<artifactId>springcloud-api</artifactId>
<version>1.0-SNAPSHOT</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.2、自定义负载均衡策略(默认是轮询),可选
public class RandomRule extends AbstractLoadBalancerRule {
//每个服务,访问5次,换下一个服务(3个)
//total=0,默认=0,如果=5,我们指向下一个服务点
//index=0,默认=0,如果total=5,则index+1
private int total = 0; //被调用的次数
private int index = 0; //服务节点
public RandomRule() {
}
@SuppressWarnings({"RCN_REDUNDANT_NULLCHECK_OF_NULL_VALUE"})
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(index);
total++;
} else {
total = 0;
index++;
if (index > upList.size()){
index = 0;
}
server = upList.get(index);
}
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) {
}
}
3.3、将自定义负载均衡策略类注入spring容器中
@Configuration
public class MyRibbon {
@Bean
public IRule getRule() {
return new RandomRule(); //默认是轮询,现在我们自定义了算法
}
}
3.4、实现ribbon负载均衡
@Configuration
public class ConsumerConfig {
@Bean
@LoadBalanced //实现ribbon负载均衡
public RestTemplate getRestTemplate(){
return new RestTemplate();
}
}
3.5、创建controller类调用服务
@RestController
public class DeptConsumerController {
@Autowired
RestTemplate restTemplate;
//private final String PREFIX_URL = "http://localhost:8081/";
private final String PREFIX_URL = "http://SPRINGCLOUD-PROVIDER-DEPT/";
@RequestMapping("/findList")
public List<Dept> findList(){
return restTemplate.getForObject(PREFIX_URL + "findList",List.class);
}
@RequestMapping("/findById/{id}")
public Dept findById(@PathVariable("id") int id){
return restTemplate.getForObject(PREFIX_URL + "findById/"+id,Dept.class);
}
}
3.6、在启动类中开启ribbon功能,并启动
@SpringBootApplication
@EnableEurekaClient
//在微服务启动的时候就能自动加载我们自定义的Ribbon类
@RibbonClient(name = "SPRINGCLOUD-PROVIDER-DEPT",configuration = MyRibbon.class)
public class SpringConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(SpringConsumerApplication.class,args);
}
}
4、Feign服务调用
4.1、创建api子工程
4.1.1、创建maven子工程,并导入依赖
<parent>
<artifactId>springcloud-001</artifactId>
<groupId>com.springcloud</groupId>
<version>1.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<dependencies>
<!--feign-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-feign</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
</dependencies>
4.1.2、创建feign接口
@Component
@FeignClient(value = "SPRINGCLOUD-PROVIDER-DEPT")
public interface DeptFeignService {
@GetMapping("/findList")
List<Dept> findList();
@GetMapping("/findById/{id}")
Dept findById(@PathVariable("id") int id);
}
4.2、创建服务调用工程
4.2.1、创建maven子工程,并导入依赖
<parent>
<artifactId>springcloud-001</artifactId>
<groupId>com.springcloud</groupId>
<version>1.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<!--消费者 实体类+web -->
<dependencies>
<!--feign-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-feign</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>
<dependency>
<groupId>org.api</groupId>
<artifactId>springcloud-api</artifactId>
<version>1.0-SNAPSHOT</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>
4.2.2、创建controller接口调用类
@RestController
public class DeptConsumerController {
@Autowired
DeptFeignService service;
@GetMapping("/findList")
public List<Dept> findList(){
return service.findList();
}
@RequestMapping("/findById/{id}")
public Dept findById(@PathVariable("id") int id){
return service.findById(id);
}
}
4.2.3、创建application.yaml文件
server:
port: 8090
#配置eureka
eureka:
client:
register-with-eureka: false #不向eureka中注册自己
service-url:
defaultZone: http://springcloud-eureka:7001/eureka/,http://springcloud-eureka02:7002/eureka/,http://springcloud-eureka03:7003/eureka/ #注册地址
4.2.4、在启动类中开启feign功能,并启动
@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients(basePackages = {"com.api"})
@ComponentScan({"com.api","com.consumer"})
public class SpringConsumerFeignApplication {
public static void main(String[] args) {
SpringApplication.run(SpringConsumerFeignApplication.class,args);
}
}
五、Hystrix
- 分布式面临的问题:复杂分布式体系结构中的应用程序有数十个依赖关系,每个依赖关系在某些时候将不可避免的失败!(网络断开)
- 服务雪崩:多个服务之间调用的时候,假设服务A调用服务B和服务C,服务B和服务C又调用其他的微服务,这就是所谓的“扇出”,如果扇出的链路上,某个微服务的调用响应时间过长或者服务不可用,对微服务A的调用就会占用越来越多的系统资源,进而引起系统奔溃,这就是所谓的“雪崩效应”。我们需要“弃车保帅”!
1、概括
Hystrix是一个用于处理分布式系统的延迟和容错的开源库,在分布式系统里,许多依赖不可避免的出现调用失败,比如超时或者异常等等。Hystrix能够保证在一个依赖出现问题的情况下,不会导致整体服务失败,避免级联故障,以提高分布式系统的弹性。
- 服务熔断(服务端)
- 服务降级(客户端)
- 服务限流
- 实时监控
服务正常时:
服务异常时:
流量高峰时,一个单节点的宕机或延迟,会迅速导致所有服务负载达到饱和。应用中任何一个可能通过网络访问其他服务的节点,都有可能成为造成潜在故障的来源。更严重的是,还可能导致服务之间的延迟增加,占用队列、线程等系统资源,从而导致多系统之间的级联故障。
2、服务熔断
2.1、创建maven子工程,并导入依赖
<parent>
<artifactId>springcloud-001</artifactId>
<groupId>com.springcloud</groupId>
<version>1.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
<!--完善监控信息-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.api</groupId>
<artifactId>springcloud-api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
<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>
<!--test-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
<!--web-->
<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>
2.2、整合mybatis(参考上面服务提供端的步骤)
2.3、创建application.yaml文件
server:
port: 8084
mybatis:
type-aliases-package: com.api.pojo
mapper-locations: classpath:mybatis/mapper/*.xml
config-location: classpath:mybatis/mybatis-config.xml
spring:
application:
name: springcloud-provider-dept
datasource:
type: com.alibaba.druid.pool.DruidDataSource
username: root
driver-class-name: com.mysql.jdbc.Driver
password: 123456
url: jdbc:mysql://localhost:3306/spring_cloud_test03?useUnicode=true&characterEncoding=utf8&useSSL=false&useSSL=false&serverTimezone=UTC
#Eureka配置
eureka:
client:
service-url:
defaultZone: http://springcloud-eureka:7001/eureka/,http://springcloud-eureka02:7002/eureka/,http://springcloud-eureka03:7003/eureka/ #注册地址
instance:
instance-id: springcloud-provider-dept-hystrix #修改eureka上的默认描述
#点击eureka的描述,显示信息
info:
app.name: springcloud-provider-dept-hystrix
company.name: zyhlwgs
2.4、修改controller类
@RestController
public class DeptController {
@Autowired
DeptServiceImpl deptService;
@GetMapping("/findById/{id}")
@HystrixCommand(fallbackMethod = "hystrixGet") //服务熔断调用
public Dept findById(@PathVariable("id") int id) {
Dept dept = deptService.findById(id);
if (dept == null) {
throw new RuntimeException("id->"+id+":不存在该用户,或者信息无法查询到!");
}
return dept;
}
//备选方案,熔断
public Dept hystrixGet(@PathVariable("id") int id){
return new Dept()
.setId(id)
.setDname("id->"+id+":没有查询到对应的信息,null+@hystrix")
.setDbSource("no data in database");
}
}
2.5、修改启动类,测试
@SpringBootApplication
@EnableEurekaClient //开启自动注册
@EnableDiscoveryClient //服务发现
@EnableCircuitBreaker //开启熔断的支持
public class SpringCloudProvicerHystrixApplication {
public static void main(String[] args) {
SpringApplication.run(SpringCloudProvicerHystrixApplication.class,args);
}
}
3、服务降级(feign服务)
3.1、修改Feign服务的application.yaml,开启降级功能
#开启降级支持
feign:
hystrix:
enabled: true
3.2、在feign服务中的api服务,创建降级类
//服务降级
@Component
public class DeptFeignFallBackFactory implements FallbackFactory {
@Override
public DeptFeignService create(Throwable throwable) {
return new DeptFeignService() {
@Override
public List<Dept> findList() {
return null;
}
@Override
public Dept findById(int id) {
return new Dept()
.setId(id)
.setDname("id->"+id+":没有对应的信息,客户端提供了降级的信息,此服务已被关闭")
.setDbSource("没有数据~");
}
};
}
}
3.3、feign调用引入降级方法
@Component
@FeignClient(value = "SPRINGCLOUD-PROVIDER-DEPT",fallbackFactory = DeptFeignFallBackFactory.class)
public interface DeptFeignService {
@GetMapping("/findList")
List<Dept> findList();
@GetMapping("/findById/{id}")
Dept findById(@PathVariable("id") int id);
}
3.4、启动服务测试
4、实时监控
4.1、创建maven子工程,并导入依赖
<parent>
<artifactId>springcloud-001</artifactId>
<groupId>com.springcloud</groupId>
<version>1.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<dependencies>
<!--hystrix-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix-dashboard</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
<!--feign-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-feign</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>
<dependency>
<groupId>org.api</groupId>
<artifactId>springcloud-api</artifactId>
<version>1.0-SNAPSHOT</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>
4.2、创建application.yaml文件
server:
port: 9001
spring:
application:
name: hystrix-dashboard
#Eureka配置
eureka:
client:
service-url:
defaultZone: http://springcloud-eureka:7001/eureka/,http://springcloud-eureka02:7002/eureka/,http://springcloud-eureka03:7003/eureka/ #注册地址
instance:
instance-id: hystrix-dashboard #修改eureka上的默认描述
4.3、创建启动类,并开启监控功能
@SpringBootApplication
@EnableHystrixDashboard //开启监控
public class HystrixDashBoardApplication {
public static void main(String[] args) {
SpringApplication.run(HystrixDashBoardApplication.class,args);
}
}
4.4、修改服务熔断子工程
4.4.1、修改启动类
@SpringBootApplication
@EnableEurekaClient //开启自动注册
@EnableDiscoveryClient //服务发现
@EnableCircuitBreaker //开启熔断的支持
public class SpringCloudProvicerHystrixApplication {
public static void main(String[] args) {
SpringApplication.run(SpringCloudProvicerHystrixApplication.class,args);
}
//添加如下方法
@Bean
public ServletRegistrationBean hystrixMetricsStreamServlet(){
ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(new HystrixMetricsStreamServlet());
servletRegistrationBean.addUrlMappings("/actuator/hystrix.stream");
return servletRegistrationBean;
}
}
4.5、分别启动eureka、服务熔断服务、服务监控服务
访问:http://localhost:9001/hystrix
4.6、测试
六、zuul路由网关
经由zuul网关访问各个服务
1、创建maven子工程,并导入依赖
<parent>
<artifactId>springcloud-001</artifactId>
<groupId>com.springcloud</groupId>
<version>1.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<dependencies>
<!--zuul-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zuul</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
<!--hystrix-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix-dashboard</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
<!--feign-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-feign</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>
<dependency>
<groupId>org.api</groupId>
<artifactId>springcloud-api</artifactId>
<version>1.0-SNAPSHOT</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>
2、创建application.yaml文件
server:
port: 9527
spring:
application:
name: springcloud-zuul
eureka:
client:
service-url:
defaultZone: http://springcloud-eureka:7001/eureka/,http://springcloud-eureka02:7002/eureka/,http://springcloud-eureka03:7003/eureka/ #注册地址
instance:
instance-id: springcloud-zuul-9527
prefer-ip-address: true #隐藏IP
info:
app.name: test-zuul
company.name: ces
zuul:
routes:
mydept: springcloud-provider-dept
mydept.path: /mydept/** # /mydept/** 替换 springcloud-provider-dept
ignored-services: springcloud-provider-dept #不能使用这个路径访问
#ignored-services: "*" #隐藏全部的访问路径
prefix: /ces #设置公共的访问前缀
3、创建启动类,并启动测试
@SpringBootApplication
@EnableZuulProxy
public class SpringCloudZuulApplication {
public static void main(String[] args) {
SpringApplication.run(SpringCloudZuulApplication.class,args);
}
}
完成!!!