文章目录
SpringCloud
解决方案: Spring Cloud 生态: SpringBoot
1.Spring Cloud NetFlix 一站式解决方案
api网关 ,zuul组件
Feign —HttpClinet—Http通信方式,同步,阻塞
服务器足额从发现 Eureka
熔断机制:Hystrix
2.Apache Dubbo Zookeeper 半自动 ,需要整合别人
API :没有,找第三方,或者自己实现
Dubbo:
Zookeeper
借助 Hystrix
Dubbo 不完善
3.Spring Cloud Alibaba 一站式解决方案 简单
解决关键
1.api
2.HTTP,RPC
3.注册和发现
4.熔断机制
SpringCloud入门
1.新建maven项目
2.导包
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<junit.version>4.12</junit.version>
<lombok.version>1.16.10</lombok.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Greenwich.SR1</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<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>
<!-- 启动器-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.2</version>
</dependency>
<!-- log4j-->
<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>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
</dependencies>
</dependencyManagement>
3.新建一个api的 model 模块
导入相应的依赖,有的是 父类里面有 就可以不用导入
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>com.it</artifactId>
<groupId>org.example</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>springclound-api</artifactId>
<!-- 写需要的依赖,父依赖有就不用写-->
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
</project>
api 的 model --写实体类的(pojo)
package com.it.pojo;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import java.io.Serializable;
@Data
@NoArgsConstructor
@Accessors(chain = true)
public class Dept implements Serializable { //Dept 实体类
private Long id; //主键
private String name;
//一个服务对应一个数据库,同一个信息可能存在不同数据库
private String db_source;
public Dept(String name) {
this.name = name;
}
}
4.新建一个实现功能的model
1.导入相应的依赖
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>com.it</artifactId>
<groupId>org.example</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>springcloud-dept-8001</artifactId>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<!--完善监控-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!--开启eureka-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka-server</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
<!--拿到实体类-->
<dependency>
<groupId>org.example</groupId>
<artifactId>springclound-api</artifactId>
<version>1.0-SNAPSHOT</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>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
</dependency>
<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>
<dependency>
<groupId>org.example</groupId>
<artifactId>springclound-api</artifactId>
<version>1.0-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
</dependencies>
</project>
2.配置相应的yml
server:
port: 8001
#mybatis配置
mybatis:
type-aliases-package: com.it.pojo
config-location: classpath:mybatis/mybatis-config.xml
mapper-locations: classpath:mybatis/mapper/*.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/db01?useUnicode=true&characterEncoding=utf-8
username: root
password: root
#Eureka配置
#Eureka配置
eureka:
client:
service-url: #监控页面
defaultZone: http://localhost:7001/eureka/ #发布位置, 可以设置集群 ,所有直接把所有集群 都加上去
instance:
instance-id: springcloud-dept-8001 #修改eureka 上的默认描述信息
#info配置
info:
app.name: song's first springcloud program
company.name: song666
3.然后写对应的service 和dao ,controller层 以及相应的mybatis配置等
DeptController类
package com.it.controller;
import com.it.pojo.Dept;
import com.it.service.DeptService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
//提供restful服务
@RestController
public class DeptController {
@Autowired
private DeptService deptService;
@Autowired
private DiscoveryClient client;
@PostMapping("/dept/add")
public boolean addDept(Dept dept)
{
return deptService.addDept(dept);
}
@GetMapping("/dept/get/{id}")
public Dept get(@PathVariable("id") Long id)
{
return deptService.queryById(id);
}
@GetMapping("/dept/list")
public List<Dept> queryAll()
{
return deptService.queryAll();
}
//注册进来的微服务,获取一些信息
@GetMapping("/dept/discovery")
public Object discovery()
{
//获取微服务列表清单
List<String> services=client.getServices();
System.out.println("discovery=>services: "+services);
//得到微服务的具体信息
List<ServiceInstance> instances = client.getInstances("SPRINGCLOUD-PROVIDER-DEPT");
for (ServiceInstance instance : instances) {
System.out.println(
instance.getHost()+"\t"+
instance.getPort()+"\t"+
instance.getUri()+"\t"+
instance.getServiceId()
);
}
return this.client;
}
}
Deptdao接口
package com.it.dao;
import com.it.pojo.Dept;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Repository;
import java.util.List;
@Mapper
@Repository
public interface DeptDao {
public boolean addDept(Dept dept);
public Dept queryById(Long id);
public List<Dept> queryAll();
}
DeptService接口
package com.it.service;
import com.it.pojo.Dept;
import java.util.List;
public interface DeptService {
public boolean addDept(Dept dept);
public Dept queryById(Long id);
public List<Dept> queryAll();
}
DeptServiceImpl实现类
package com.it.service;
import com.it.dao.DeptDao;
import com.it.pojo.Dept;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class DeptServiceImpl implements DeptService{
@Autowired
private DeptDao deptDao;
@Override
public boolean addDept(Dept dept)
{
return deptDao.addDept(dept);
}
public Dept queryById(Long id)
{
return deptDao.queryById(id);
}
public List<Dept> queryAll()
{
return deptDao.queryAll();
}
}
mybatis-config.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<settings>
<setting name="cacheEnabled" value="true"/>
</settings>
</configuration>
DeptMapper.xml
<?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.it.dao.DeptDao">
<insert id="addDept" parameterType="Dept">
insert into dept(name,source)
values (#{name},DATABASE())
</insert>
<select id="queryById" resultType="Dept" parameterType="Long">
select * from dept where id= #{id};
</select>
<select id="queryAll" resultType="Dept">
select * from dept
</select>
</mapper>
4.写启动类
package com.it;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
//启动类
@SpringBootApplication
@EnableEurekaServer
@EnableDiscoveryClient //服务发现
public class DeptProvide {
public static void main(String[] args) {
SpringApplication.run(DeptProvide.class,args);
}
}
5.写一个用户 module
1.导依赖
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>com.it</artifactId>
<groupId>org.example</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>springcloud-dept-user-80</artifactId>
<dependencies>
<dependency>
<groupId>org.example</groupId>
<artifactId>springclound-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>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
</project>
2.配置端口(yml)
server:
port: 8002
3.写ConfigBean
package com.it.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
@Configuration
public class ConfigBean {
@Bean
public RestTemplate getRestTemplate()
{
return new RestTemplate();
}
}
4.写相应的控制层,利用RestTemplate 调取其他moudel的方法
package com.it;
import com.it.pojo.Dept;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import java.util.List;
@RestController
public class DeptUserController {
//消费者 不应该有service层
//(url,实体:map,返回类型:Class<T> responseType)
@Autowired
private RestTemplate restTemplate;
private static final String REST_URL_PREFIX="http://localhost:8001";
@RequestMapping("/user/dept/add")
public boolean add(Dept dept)
{
return restTemplate.postForObject(REST_URL_PREFIX+"/dept/add",dept,Boolean.class);
}
@RequestMapping("/user/dept/get/{id}")
public Dept get(@PathVariable("id") Long id)
{
return restTemplate.getForObject(REST_URL_PREFIX+"/dept/get/"+id,Dept.class);
}
@RequestMapping("/user/dept/list")
public List<Dept> list()
{
return restTemplate.getForObject(REST_URL_PREFIX+"/dept/list",List.class);
}
}
5.写用户启动类
package com.it;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Deptuser80 {
public static void main(String[] args) {
SpringApplication.run(Deptuser80.class,args);
}
}
热部署
1.子类加依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
2.父类加插件
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<fork>true</fork>
<addResources>true</addResources>
</configuration>
</plugin>
</plugins>
</build>
3.开启自动编译
4.在子类 快捷键
ctrl+shift+alt+/ Registry
5.重启
Eureka服务注册与发现
1.开一个新的moudle 然后导包
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>com.it</artifactId>
<groupId>org.example</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>springcloud-Eureka-7001</artifactId>
<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>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
</project>
2.配置yml
server:
port: 7001
#Eureka配置
eureka:
instance:
hostname: localhost #服务端实例名称
client:
register-with-eureka: false #是否向eureka注册中心注册自己
fetch-registry: false #false 自己为注册中心
service-url: #监控页面
#设置关联 如果本身是 7001的 集群 下面就 连接http://eureka7001.com:7001/eureka/,http://eureka7002.com:7003/eureka/
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
3.写 启动类 测试
package com.it;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
@SpringBootApplication
@EnableEurekaServer //接收别人注册
public class Eureka7001 {
public static void main(String[] args) {
SpringApplication.run(Eureka7001.class,args);
}
}
集群
集群就相当于多个Eureka 然后让这些 moudle 模块相互关联
主要是让·1每个集群相互关联,导致有一个集群崩了,另外一个可以继续运行
直接配置多个Eureka
1.配置pom.xml
<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>
2.配置yml
server:
port: 7002
#Eureka配置
eureka:
instance:
hostname: localhost #服务端实例名称
client:
register-with-eureka: false #是否向eureka注册中心注册自己
fetch-registry: false #false 自己为注册中心
service-url: #监控页面
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
3.写启动类
package com.it;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
@SpringBootApplication
@EnableEurekaServer //接收别人注册
public class Eureka7002 {
public static void main(String[] args) {
SpringApplication.run(Eureka7002.class,args);
}
}
CAP
c 一致性 a可用性 p分区容错性 满足3选2
Zookeeper保证的是cp 服务注册功能对可用性的要求高于一致性 当一个节点 死了的时候,会重新选择一个节点,如果几个节点数据量比较大,选举的时候花的时间就会长一点,30-120s且选举的时候集群是不可用的,选举的时候会导致服务器瘫痪
Eureka保证的是ap
Eureka 先保证可用
Eureka可以很好的应对网络故障导致的部分节点失去联系的情况,几个节点挂掉后 不影响别的节点的工作,挂掉一台后,会自动跳到另一台节点,只是有带你慢,如果85%的节点不能用的话就会认为 崩溃.
Eureka可以很好的应对网络故障导致的部分节点失去联系的情况,不会像zookeeper使整个注册服务 瘫痪
Zookeeper
1.启动类添加注解
@EnableDiscoveryClient //该注解用于向使用consul或者zookeeper作为注册中心时注册服务
2.导相关的依赖和配置等
3.注意zookeeeper的版本依赖包 和服务器上的 不一致,可能会出现依赖包问题
4.及时的 相应,当检测不到心跳以后 直接就关了 ,不会像eurke那样有自我保护机制.
Consul
1.安装运行Consul
consul agent -dev
2.前端页面
localhost:8500
ribbon
客户端实现负载均衡
负载均衡就是将用户的请求平摊分配搭配多个服务上,从而达到系统的HA(高可用)
轮询,随机 算法
1.导包
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-ribbon</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka-server</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
2.配置yml
server:
port: 8002
#Eureka
eureka:
client:
register-with-eureka: false
service-url:
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
3.在启动类上加注解
@EnableEurekaServer
4.在ConfigBean里面配置负载均衡
直接在RestTemplate上加上注解就行
@LoadBalanced //Ribbin
5.修改控制器里面的地址,修改成变量
//Ribbon是一个变量,通过服务名来访问的,就是 获取提供者的地址
//private static final String REST_URL_PREFIX="http://localhost:8001";
private static final String REST_URL_PREFIX="SPRINGCLOUD-PROVIDER-DEPT";
自定义Ribbon算法(手写)
1.不能放在Component所扫描的本包和子包里面
2.启动类添加注解
3.在提供层(8000)增加负载均衡算法lb(自寻锁).
4.在消费层的config类里面取消LoadBalanced注解
5相应的lb接口来拿服务器的集群的台数 和实现类来自定义方法。
Feign负载均衡(OpenFeign)
feign一种声明式的web service客户端,集成了Ribbon 和Eureka,主要是社区,接口编程,调用微服务的2种方法
1.微服务的名字 ribbon
2.接口和注解 feign
只需要用接口 并且使用注解去配置在dao接口上标注mapper,并且一个微服务标注一个Feign注解即可
目录结构
.
1.Feign是通过接口的方式来实现的,因此需要改变 api
在接口服务器中添加提供服务器中的接口
package com.it.service;
import com.it.pojo.Dept;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import java.util.List;
@Component
@FeignClient(value = "SPRINGCLOUD-PROVIDER-DEPT")
public interface DeptClientService {
@GetMapping("/dept/get/{id}")
public Dept queryById(@PathVariable("id") Long id);
@GetMapping("/dept/list")
public List<Dept> queryAll();
@GetMapping("/dept/add")
public Boolean addDept(Dept dept);
}
2.控制器中直接用注解去接收
package com.it;
import com.it.pojo.Dept;
import com.it.service.DeptClientService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import java.util.List;
@RestController
public class DeptUserController {
@Autowired
private DeptClientService service=null;
@RequestMapping("/user/dept/add")
public boolean add(Dept dept)
{
return this.service.addDept(dept);
}
@RequestMapping("/user/dept/get/{id}")
public Dept get(@PathVariable("id") Long id)
{
return this.service.queryById(id);
}
@RequestMapping("/user/dept/list")
public List<Dept> list()
{
return this.service.queryAll();
}
}
3.添加启动类 就可以测试
package com.it;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.context.annotation.ComponentScan;
@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients(basePackages = {"com.it"})
@ComponentScan("com.it")
public class FeDeptuser80 {
public static void main(String[] args) {
SpringApplication.run(FeDeptuser80.class,args);
}
}
4.只需要通过控制器的方法,就可以访问相应接口的方法,然后接口的方法去调用提供者的接口方法来实现功能
OpenFeign
1.建模块,yml,
2.启动类加注解 @EnableFeginClients
3.控制器写方法,方法调用接口
4.写接口和相应的config配置
5.openfeign 默认超时1s 可以在yml设置ribbon多一点
6.打印日志yml(打印接口)
logging:
level:
# feign日志以 debug 级别监控 com.atguigu.springcloud.service.PaymentFeignService 接口
com.atguigu.springcloud.service.PaymentFeignService: debug
Hystrix服务熔断
雪崩: 用户去掉 客户端的服务,然后 一个服务会去调另外一个服务,多的几个服务,如果中间一个服务相应时间过长 或者不可用,然后就会在a服务有很多调用,占用很多资源,导致系统崩溃。然后就可以直接给他一个备用的服务,如果崩了 这个服务就只做一些熔断的措施,返回1用户这个服务崩了,然后继续下一层服务,保证服务尽可能正常运行。
Hystrix:处理分布式系统的延迟和容错的开源库,在分布式系统里面很多依赖不可避免调用失败超时等,Hystrix保证在一个依赖出问题的情况下,不会导致整体服务失败,避免连级故障,提高分布式系统弹性。
1.导入依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
2.编写配置文件
server:
port: 8009
#mybatis配置
mybatis:
type-aliases-package: com.it.pojo
config-location: classpath:mybatis/mybatis-config.xml
mapper-locations: classpath:mybatis/mapper/*.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/db01?useUnicode=true&characterEncoding=utf-8
username: root
password: root
#Eureka配置
#Eureka配置
eureka:
client:
service-url: #监控页面
defaultZone: http://localhost:7001/eureka/,http://localhost:7002/eureka/ #发布位置, 可以设置集群 ,所有直接把所有集群 都加上去
instance:
instance-id: springcloud-dept-hystrix-8009 #修改eureka 上的默认描述信息
#info配置
info:
app.name: song's first springcloud program
company.name: song666
3.开启功能
model层等的书写,如上面的提供者。
然后写相应的控制器来开启熔断
package com.it.controller;
import com.it.pojo.Dept;
import com.it.service.DeptService;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
//提供restful服务
@RestController
public class DeptController {
@Autowired
private DeptService deptService;
@GetMapping("/dept/get/{id}")
@HystrixCommand(fallbackMethod = "hystrixGet")
public Dept get(@PathVariable("id") Long id)
{
Dept dept=deptService.queryById(id);
if (dept==null)
{
throw new RuntimeException("id=>"+id+"不存在该用户,或者信息没找到");
}
return dept;
}
//熔断
public Dept hystrixGet(@PathVariable("id") Long id)
{
return new Dept()
.setId(id)
.setName("id=>"+id+"没有对应的信息,null--@Hystrix")
.setDb_source("no this database in Mysql");
}
}
Hystrix服务降级
客户端 多提供一个服务,然后 当客户端服务器崩了时,提供一个服务 来进行降级处理,输出处理的结果。客户正常运行,
服务熔断:是服务降级的一种特殊情况,防止服务器雪崩采取的措施
服务降级:释放服务资源来保证核心业务正常高效运行。当某个服务熔断或关闭之前,服务不再被调用,此时在客户端准备一个FallbackFactory,返回一个默认值,整体的服务水平下降。
实现步骤:
1.多设置一个服务端,在服务端设置降级 (端口和用户相同,此时的feign端 就相当于是 用户,不需要再开启一个用户端)
server:
port: 8002
#Eureka
eureka:
client:
register-with-eureka: false
service-url:
defaultZone: http://localhost:7002/eureka/,http://localhost:7001/eureka/
# defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
#feign 开启降级feign,hystrix
feign:
hystrix:
enabled: true
2.服务端启动类上加上 降级的注解
@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients(basePackages = {"com.it"})
@ComponentScan("com.it")
public class FeDeptuser80 {
public static void main(String[] args) {
SpringApplication.run(FeDeptuser80.class,args);
}
}
3.在接口端 设置对应的降级控制器
package com.it.service;
import com.it.pojo.Dept;
import feign.hystrix.FallbackFactory;
import org.springframework.core.annotation.AliasFor;
import org.springframework.stereotype.Component;
import java.util.List;
//降级
@Component
public class DeptClientServiceFallbackFactory implements FallbackFactory {
public DeptClientService create(Throwable throwable)
{
return new DeptClientService() {
@Override
public Dept queryById(Long id) {
return new Dept()
.setId(id)
.setName("id=>"+id+"没有对应的信息,客户端提供降级的信息,这个服务器现在已经关闭")
.setDb_source("空,没有数据");
}
@Override
public List<Dept> queryAll() {
return null;
}
@Override
public Boolean addDept(Dept dept) {
return null;
}
};
}
}
4.接口端的接口开启降级注解
@Component
@FeignClient(value = "SPRINGCLOUD-PROVIDER-DEPT",fallbackFactory = DeptClientServiceFallbackFactory.class)
public interface DeptClientService {
@GetMapping("/dept/get/{id}")
public Dept queryById(@PathVariable("id") Long id);
@GetMapping("/dept/list")
public List<Dept> queryAll();
@GetMapping("/dept/add")
public Boolean addDept(Dept dept);
}
5.测试
当客户 访问服务的时候,提供端 8001如果崩了的话,就会直接进行服务降级,进行提示。
Dashboard流监控
1.新建一个模块然后导包 还有 配置端口
<dependencies>
<!--完善监控信息-->
<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-dashboard</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>
<!--Rinbbon-->
<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-server</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.example</groupId>
<artifactId>springclound-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.写启动类 开启 监控页面
package com.it;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.hystrix.EnableHystrix;
import org.springframework.cloud.netflix.hystrix.dashboard.EnableHystrixDashboard;
@SpringBootApplication
@EnableHystrixDashboard //开启监控页面
public class DeptUserDashboard_9001 {
public static void main(String[] args) {
SpringApplication.run(DeptUserDashboard_9001.class, args);
}
}
3.测试
4.在提供服务的服务端 中 添加 相应的监控依赖
<!--完善监控-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
5.然后在服务端启动类上添加监控
//启动类
@SpringBootApplication
@EnableEurekaServer
@EnableDiscoveryClient //服务发现
public class DeptProvide {
public static void main(String[] args) {
SpringApplication.run(DeptProvide.class,args);
}
//增加一个servlet
@Bean
public ServletRegistrationBean hystrixMetricsStreamServlet()
{
ServletRegistrationBean registrationBean=new ServletRegistrationBean(new HystrixMetricsStreamServlet());
registrationBean.addUrlMappings("/actuator/hystrix.stream");
return registrationBean;
}
}
6.在 监控页面 添加相应的地址 也就是 上面启动类上的流 然后就可以进行监控
7.在提供服务端 的控制器内 需要监控的方法上加上 @HystrixCommand注解
路由网关Zuul
路由,代理,过滤
路由的请求: 外部的请求转发到具体的微服务实例上,用来跳转的
路由的过滤: 对七八个球的处理过程进行干预,校验服务聚合
Zuul和Eureka进行整合,把Zuul自身注册为Eureka下的应用,同时从Eureka获得其他微服务的消息,访问微服务也是用Zuul跳转
1.新建模块,导包
<!--zuul-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zuul</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
2.写控制器 加相应的 注解
@SpringBootApplication
@EnableZuulProxy
public class ZuulApplication_9527 {
public static void main(String[] args) {
SpringApplication.run(ZuulApplication_9527.class,args);
}
}
3.配置yml
server:
port: 9528
spring:
application:
name: springcloud-zuul
#Eureka
eureka:
client:
service-url:
defaultZone: http://localhost:7002/eureka/,http://localhost:7001/eureka/
instance:
instance-id: zuul9527.com
prefer-ip-address: true
info:
app.name: song
company.name: aaa
zuul:
routes:
mydept.serviceId: springcloud-provider-dept #这里其实就是提供者的服务名字 http://localhost:9528/springcloud-provider-dept/dept/get/2
mydept.path: /mydept/** #代替上面的路径 http://localhost:9528/mydept/dept/get/3
ignored-services: "*" #不在使用服务的那个路径 只能使用指定的
prefix: /song #设置公共前缀 http://localhost:9528/song/mydept/dept/get/3
4.直接进行访问
Gateway网关
Springcloud Gateway是Spring Cloud生态系统的网关,来替代Zuul, 在SpringCloud2.0以上没有对应新版本zuul2.0来集成。为了提高性能,SpringCloud Gateway基于Webflux框架实现,而Webflux底层是采用高性能的Reactor模式通信框架Netty。
zuul1是阻塞型IO,也就是servlet
Gateway是非阻塞的
组成
1.Route(路由)
2.Predicate(断言) 匹配HTTP请求头或请求参数
3.Filter(过滤)
配置
1.yml中配置
2.注入到容器
断言
1.yml进行配置
过滤器
1.自定义过滤器,
package com.atguigu.springcloud.filter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
import java.util.Date;
@Component
@Slf4j
public class MyLogGateWayFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
log.info("***********come in MyLogGateWayFilter: " + new Date());
// 获取请求参数中的 uname
String uname = exchange.getRequest().getQueryParams().getFirst("uname");
if (uname == null) {
log.info("*******用户名为null,非法用户,o(╥﹏╥)o");
exchange.getResponse().setStatusCode(HttpStatus.NOT_ACCEPTABLE);
return exchange.getResponse().setComplete();
}
return chain.filter(exchange);
}
/**
* 加载过滤器顺序,数字越小优先级越高
*
* @return
*/
@Override
public int getOrder() {
return 0;
}
}
Springcloud Config分布式配置中心
1.优点:
1.集中管理配置
2.不同环境不同配置,动态更新
3.把配置信息以REST接口的形式暴露
1.动态配置管理
1.服务端:3344 就
2.客户端
config手动刷新
1.导b
2.暴露监控端口(yml加配置)
# 暴露监控端点 否则 curl -X POST "http://localhost:3355/actuator/refresh" 不可使用
management:
endpoints:
web:
exposure:
include: "*"
3.config控制器加上 注解 @RefreshScope
4.执行命令 curl -X POST “http://localhost:3355/actuator/refresh” 进行手动刷新
消息总线(Spring Cloud Bus)
作用:分布式执行器,用于广播状态的更改,事件推送等,相当于微服务间的通信通道
1.差异形刷新
2.动态刷新
RabbitMQ
设计思想
1.利用消息总线触发一个服务端ConfigServe 配置中心 的/bus/refresh端点,而刷新所有客户端的配置,
2.利用消息总线出发一个客户端/bus/refresh而刷新所有客户端配置
1.安装链接添加链接描述
配置
1.导包
<!--添加消息总线RabbitMQ支持-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>
2.yml添加支持
server:
port: 3366
spring:
application:
name: config-client
cloud:
#Config客户端配置
config:
label: main #分支名称
name: config #配置文件名称
profile: dev #读取后缀名称 上述3个综合:master分支上config-dev.yml的配置文件被读取http://config-3344.com:3344/master/config-dev.yml
uri: http://localhost:3344 #配置中心地址
#服务注册到eureka地址
eureka:
client:
service-url:
defaultZone: http://localhost:7001/eureka
# 暴露监控端点
management:
endpoints:
web:
exposure:
include: "*"
#rabbitmq相关配置 15672是Web管理界面的端口;5672是MQ访问的端口
rabbitmq:
host: localhost
port: 15672
username: guest
password: guest
4.开启rabbitMQ启动
5.执行命令 curl -X POST “http://localhost:3344/actuator/refresh” 进行手动刷新
动态化通知
全局通知 curl -X POST “http://localhost:3344/actuator/bus-refresh”
局部通知 curl -X POST “http://localhost:3344/actuator/bus-refresh/config-client:3366” 微服务名+端口号
SpringCloud 连接github
1.本地连接上github
可以去看我的这个博客来链接git和github操作
2.传送到github上的appliaction配置
spring:
profiles:
active:
---
spring:
profiles: dev
application:
name: springcloud-config-dev
---
spring:
profiles: test
application:
name: springcloud-config-test
3.开始配连接github的模块来连接远程
1.导报
<dependencies>
<!--config-->
<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>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
</dependencies>
1.在yml里面配置自己的远程地址
server:
port: 3344
spring:
application:
name: springcloud-config-server
#连接远程仓库
cloud:
config:
server:
git:
uri: https://github.com/project-oys/springcloud.git #http的
2.启动类去连接
@SpringBootApplication
@EnableConfigServer
@EnableEurekaClient
public class config_serve3344 {
public static void main(String[] args) {
SpringApplication.run(config_serve3344.class,args);
}
}
4.直接在后面加上要读的文件就可以读取
http://localhost:3344/main/application-dev.yml
客户端连接github配置
1.在github上传入客户端的相关配置
spring:
profiles:
active: dev
---
server:
port:8201
#spring配置
spring:
profiles: dev
application:
name: springcloud-provider-dept
#Eureka配置
eureka:
client:
service-url: #监控页面
defaultZone: http://localhost:7001/eureka/ #发布位置, 可以设置集群 ,所有直接把所有集群 都加上去
---
server:
port:8201
#spring配置
spring:
profiles: test
application:
name: springcloud-provider-dept
#Eureka配置
eureka:
client:
service-url: #监控页面
defaultZone: http://localhost:7001/eureka/ #发布位置, 可以设置集群 ,所有直接把所有集群 都加上去
2.开启客户端模块并且导依赖
<dependencies>
<!--客户端是 启动config-->
<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.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
</dependencies>
3.配置bootstrap.yml(系统级别的配置)
spring:
cloud:
config:
name: config-client #需要获取的文件
profile: dev
label: main
uri: http://localhost:3344
4.配置application.yml
spring:
application:
name: springcloud-config-client-3355
5.调一个控制层来调取github上获取的东西
package com.it.controller;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class ConfigClientController {
@Value("${spring.application.name}")
private String applicationName;
@Value("${eureka.client.service-url.defaultZone}")
private String eurekaServer;
@Value("${spring.application.name}")
private String port;
@RequestMapping("/config")
public String getConfig()
{
return "application.name"+applicationName+"eureka"+eurekaServer+"port"+port;
}
}
6.启动类测试
package com.it;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class ConfigClient_3355 {
public static void main(String[] args) {
SpringApplication.run(ConfigClient_3355.class,args);
}
}
SpringCloud Stream消息驱动
常见中间件:1.ActiveMQ 2.RabbitMQ 3.RocketMQ 4.Kafka
作用: 比如 后端 和 后面大数据平台 可能会有很多 后端用RabbitMQ 大数据用Kafka 就会有差异, SpringCloud Stream是一个构建消息驱动微服务的框架,可以屏蔽底层中间件的差异,统一消息的编程模型。
原理: