简单介绍
微服务是系统架构上的一种设计风格它的主旨是将一个原本独立的系统拆分成多个小型服务,这些小型服务都在各自独立的进程中运行,服务之间一般通过HTTP的RESTfuLAPI进行通信协作被拆分成的每一个小型服务都围绕着系统中的某一项或些耦合度较高的业务功能进行构建,并且每个服务都维护着白身的数据存储、业务开发自动化测试案例以及独立部署机制。由于有了轻量级的通信协作基础,所以这些微服务可以使用不同的语言来编写
Spring Cloud是一系列框架的有序集合
Spring Cloud 并没有重复制造轮子,它只是将目前各家公司开发的比较成熟、经得起实际考验的服务框架组合起来.
通过 Spring Boot 风格进行再封装屏蔽掉了复杂的配置和实现原理,最终给开发者留出了一套简单易懂、易部署和易维护的分
布式系统开发工具包。
它利用Sprin Boot的开发便利性巧妙地简化了分布式系统基础设施的开发,如服务发现注册、配置中心、消息总线、负载均衡、断路器、数据监控等,都可以用Spring Boot的开发风格做到一键启动和部署。
Spring loud 版本命名万式采用了伦敦地铁的名称,同时根据学母表的顺序来对应版本时间顺序,比如:最早的Release版
Angel,第二个Release版本: Brixton,然后是Camden、Dalston、Edgware, Finchley, Greenwich,Hoxton。
Spring Cloud与Dubbo都是实现微服务有效的工具
Dubbo只是实现了服务治理,而Spring Cloud子项目分别覆盖了微服务架构下的众多部件。
Dubbo使用 RPC通讯协议,Spring Cloud 使用 RESTful 完成通信,Dubbo效率略高于Spring Cloud。
微服务就是将项目的各个模块拆分为可独立运行、部署、测试的架构设计风格。
Spring公司将其他公司中微服务架构常用的组件整合起来,并使用SpringBoot简化其开发、配置称为Spring Cloud
SpringCloud 与Dubbo都是实现微服务有效的工具。Dubbo性能更好而Spring Cloud功能更全面
服务治理
Eureka
Eureka是Netflix公司开源的一个服务注册与发现的组件
Eureka 和其他 Netflix 公司的服务组件(例如负载均衡、断器、网关等) 一起被SpringCloud社区整合为Spring-Cloud-Netflix模块。
Eureka 包含两个组件: EurekaServer (注册中心)和 Eureka Client(服务提供者、服务消费者).
使用步骤
1.搭建 Provider 和 Consumer 服务。
2.使用 RestTemplate完成远程调用
package com.cqh.controller;
import com.cqh.entity.Goods;
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.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;
/**
* @author cqh
* @date 2024/1/22
* @Description
*/
@RestController
@RequestMapping("/consumer")
public class ConsumerController {
@Autowired
private RestTemplate restTemplate;
@Autowired
private DiscoveryClient discoveryClient;
@RequestMapping("/goods/{id}")
public Goods findById(@PathVariable("id")Integer id){
List<ServiceInstance> instances = discoveryClient.getInstances("EUREKA-PROVIDER");
ServiceInstance serviceInstance = instances.get(0);
String host = serviceInstance.getHost();
int port = serviceInstance.getPort();
String url="http://"+host+":"+port+"/provider/findById/"+id;
System.out.println("url = " + url);
Goods forObject = restTemplate.getForObject(url, Goods.class);
return forObject;
}
}
3.搭建 Eureka Server 服务。(创建 eureka-server模块、引入SpringCloud和euraka-server相关依赖、完成 Eureka Server 相关配置、启动该模块)
<?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>cloud-parent</artifactId>
<groupId>cpm.cqh</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>eureka-server</artifactId>
<dependencies>
<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-server</artifactId>
</dependency>
</dependencies>
</project>
server:
port: 8761
# Eureka配置
#eureka 一共有4部分配置
#1.dashboard:eureka的web控制台配置
#2.server:eureka的服务端配置
#3.cLient:eureka的客户端配置
#4.instance:eureka的实例配置
eureka:
instance:
hostname: localhost #主机名
#euraka的web端访问是否开启,和访问路径
dashboard:
enabled: true
path: /
client:
#eureka服务端地址, 将来客户端和服务端通信就用这个
service-url:
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka
#是否将自己的路径注册到eureka上
register-with-eureka: false
#是否需要从eureka中抓取路径
fetch-registry: false
4.改造 Provider 和 Consumer称为 Eureka Client。
<?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>cloud-parent</artifactId>
<groupId>cpm.cqh</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>eureka-consumer</artifactId>
<dependencies>
<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>
</dependencies>
</project>
server:
port: 8001
eureka:
instance:
hostname: localhost
client:
service-url:
defaultZone: http://localhost:8761/eureka
spring:
application:
name: eureka-consumer
package com.cqh.controller;
import com.cqh.entity.Goods;
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.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;
/**
* @author cqh
* @date 2024/1/22
* @Description
*/
@RestController
@RequestMapping("/consumer")
public class ConsumerController {
@Autowired
private RestTemplate restTemplate;
@Autowired
private DiscoveryClient discoveryClient;
@RequestMapping("/goods/{id}")
public Goods findById(@PathVariable("id")Integer id){
List<ServiceInstance> instances = discoveryClient.getInstances("EUREKA-PROVIDER");
ServiceInstance serviceInstance = instances.get(0);
String host = serviceInstance.getHost();
int port = serviceInstance.getPort();
String url="http://"+host+":"+port+"/provider/findById/"+id;
System.out.println("url = " + url);
Goods forObject = restTemplate.getForObject(url, Goods.class);
return forObject;
}
}
package com.cqh.entity;
/**
* @author cqh
* @date 2024/1/22
* @Description
*/
public class Goods {
private Integer id;
private String name;
private Double price;
public Goods() {
}
public Goods(Integer id, String name, Double price) {
this.id = id;
this.name = name;
this.price = price;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Double getPrice() {
return price;
}
public void setPrice(Double price) {
this.price = price;
}
@Override
public String toString() {
return "Goods{" +
"id=" + id +
", name='" + name + '\'' +
", price=" + price +
'}';
}
}
5.Consumer 服务通过从Eureka Server 中抓取 Provider
地址完成远程调用
Spring提供的一种简单便捷的模板类,用于在java代码里访问restful 服务
package com.cqh.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
/**
* @author cqh
* @date 2024/1/22
* @Description
*/
@Configuration
public class RestTemplateConfig {
@Bean
public RestTemplate restTemplate(){
return new RestTemplate();
}
}
依次启动
Eureka相关配置及特性
eureka一共有4部分配置
1.server:eureka 的服务端配置
2. client:eureka 的客户端配置
3.instance:eureka 的实例配置
4. dashboard:eureka 的web控制台配置
Eureka -相关配置及特性 -instance
Eureka -相关配置及特性 - server
运行过程中,Eureka服务突然挂了,微服务还能调用吗?
还可以调用,Eureka客户端有服务端记录的服务地址缓存 (在这期间,服务的IP端口不能变)
1.服务注册
2.提供注册表,将注册的服务以及IP端口做成一张表,只要有客户端来请求,就会将这张表缓存在究户端
3.同步状态,通过注册,心跳机制等,实时更新每个注册的服务的最新信息
Eureka-高可用
搭建集群
1.准备两个Eureka Server
2.分别进行配置,相互注册
3. Eureka Client分别注册到这两个Eureka Server中
server:
port: 8762
# Eureka配置
#eureka 一共有4部分配置
#1.dashboard:eureka的web控制台配置
#2.server:eureka的服务端配置
#3.cLient:eureka的客户端配置
#4.instance:eureka的实例配置
eureka:
instance:
hostname: 127.0.0.1 #主机名
client:
#eureka服务端地址, 将来客户端和服务端通信就用这个
service-url:
defaultZone: http://localhost:8761/eureka
#是否将自己的路径注册到eureka上
register-with-eureka: true
#是否需要从eureka中抓取路径
fetch-registry: true
spring:
application:
name: EUREKA-HA
server:
port: 8761
# Eureka配置
#eureka 一共有4部分配置
#1.dashboard:eureka的web控制台配置
#2.server:eureka的服务端配置
#3.cLient:eureka的客户端配置
#4.instance:eureka的实例配置
eureka:
instance:
hostname: localhost #主机名
client:
#eureka服务端地址, 将来客户端和服务端通信就用这个
service-url:
defaultZone: http://127.0.0.1:8762/eureka
#是否将自己的路径注册到eureka上
register-with-eureka: true
#是否需要从eureka中抓取路径
fetch-registry: true
spring:
application:
name: EUREKA-HA
riboon客户端负载均衡
创建·随机策略(ribbon客户端负载均衡)
方法一配置类
方法二配置文件
Feign声明式服务调用
Feign是一个声明式的REST客户端,它用了基于接口的注解方式,很方便实现客户端配置
Feign最初由Netflix公司提供,但不支持SprinaMVC注解,后由SprinaCloud 对其封装,支持了SprinaMVC注解,让使用者更易于接受。
使用步骤
1、导入依赖
2.创建接口,添加@FeignClient(value = "FEIGN-PROVIDER")注解指明服务、编写抽象方法、方法声明要和调用接口方法一模一样要加上类路径
3、启动类添加@EnableFeignClients开启服务
4、服务类注入接口方法调用
<?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>cloud-parent</artifactId>
<groupId>cpm.cqh</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>fegin-consumer</artifactId>
<dependencies>
<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>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
</dependencies>
</project>
package com.cqh.fegin;
import com.cqh.entity.Goods;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
/**
* @author cqh
* @date 2024/1/24
* @Description
*/
// value属性指明当前接口针对哪一个服务
@FeignClient(value = "FEIGN-PROVIDER")
public interface GoodsFeignClient {
// 编写抽象方法、方法声明要和调用接口方法一模一样要加上类路径
@RequestMapping("/consumer/goods/{id}")
public Goods findById(@PathVariable("id")Integer id);
}
package com.cqh.entity;
/**
* @author cqh
* @date 2024/1/22
* @Description
*/
public class Goods {
private Integer id;
private String name;
private Double price;
public Goods() {
}
public Goods(Integer id, String name, Double price) {
this.id = id;
this.name = name;
this.price = price;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Double getPrice() {
return price;
}
public void setPrice(Double price) {
this.price = price;
}
@Override
public String toString() {
return "Goods{" +
"id=" + id +
", name='" + name + '\'' +
", price=" + price +
'}';
}
}
package com.cqh.fegin;
import com.cqh.entity.Goods;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
/**
* @author cqh
* @date 2024/1/24
* @Description
*/
// value属性指明当前接口针对哪一个服务
@FeignClient(value = "FEIGN-PROVIDER")
public interface GoodsFeignClient {
// 编写抽象方法、方法声明要和调用接口方法一模一样要加上类路径 http://EUREKA-PROVIDER/provider/findById/id
@RequestMapping("/provider/findById/{id}")
public Goods findById(@PathVariable("id") Integer id);
}
package com.cqh;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.ribbon.RibbonClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
/**
* @author cqh
* @date 2024/1/22
* @Description
*/
@SpringBootApplication
@EnableEurekaClient
// 开启feign服务
@EnableFeignClients
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class,args);
}
}
server:
port: 9000
eureka:
instance:
#是否将自己的ip地址注册到eureka中,默认是false(默认注册主机名)
# true 就是将本机非回环地址(127.0.0.1)的第一个ip注册到eureka中,这个ip不一定是公网ip,所以我们在公网环境下一般手动指定ip
prefer-ip-address: true
ip-address: 127.0.0.1 #手动指定公网ip
instance-id: ${eureka.instance.ip-address}:${spring.application.name}:${server.port}
hostname: localhost #主机名
client:
service-url:
defaultZone: http://localhost:8761/eureka #,http://127.0.0.1:8762/eureka
spring:
application:
name: feign-consumer
Feign 其他功能-超时设置
Feign 其他功能-日志记录
效果
# 对数据进行压缩处理
feign:
compression:
request:
enabled: true
mime-type: text/xml,application.xml,application/json
min-request-size: 2048
response:
enabled: true
mime-type: text/xml,application.xml,application/json
min-request-size: 2048
Hystrix熔断器
Hystrix 概述
Hystix:是Netflix 开源的一个延迟和容错库,用于隔离访问远程服务、第三方库,防止出现级联失败(雪崩)。
雪崩: 一个服务失败,导致整条链路的服务都失败的情形
Hystrix降级
Hystix降级:当服务发生异常或调用超时,返回默认数据
Hystrix 降级-服务提供方
1.在服务提供方,引入hystrix依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
2.定义降级方法
上面图片有点细节有问题对照下面这个图片
3.使用@HystrixCommand注解配置降级方法
在启动类上开启Hystrix功能: @EnableCircuitBreaker
测试
Hystrix降级-服务消费方
1.feign组件已经集成了hystrix组件
2.定义feign调用接口实现类,复写方法,即降级方法
3.在@FeignClient注解中使用fallback属性设置降级处理类.
4.配置开启feign.hystrix.enabled = true
只开启server和消费者
Hystix熔断
Hystrix熔断机制,用于监控微服务调用情况,当失败的情况达到预定的闽值(5秒失败20次),会打开断路器,拒绝所有请求,直到服务恢复正常为止。
circuitBreaker.sleepWindowlnMilliseconds: 监控时间
circuitBreaker.requestVolumeThreshold: 失败次数
circuitBreaker.errorThresholdPercentage: 失败率
package com.cqh.controller;
import com.cqh.entity.Goods;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author cqh
* @date 2024/1/22
* @Description
*/
@RestController
@RequestMapping("/provider")
public class ProviderController {
@Value("${server.port}")
private Integer port;
@RequestMapping("/findById/{id}")
@HystrixCommand(fallbackMethod = "findById_fallback",commandProperties = {
// 双击shift 搜索HystrixCommandProperties 复制超时时长设置设置超时时长为5秒
@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",value = "5000"),
// 设置熔断监控时长默认5秒
@HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds",value = "5000"),
// 设置熔断的单位时间内内访问次数 默认20次
@HystrixProperty(name = "circuitBreaker.requestVolumeThreshold",value = "20"),
// 设置熔断单位时间内的的失败率
@HystrixProperty(name = "circuitBreaker.errorThresholdPercentage",value = "50")
}) // 指明当前接口降级方案 超时时长默认1秒,超过1秒发生降级
public Goods findById(@PathVariable("id") Integer id) {
int a=1/id;
return new Goods(id, "西瓜" + port + "", 12.3);
}
//findById的降级方案
public Goods findById_fallback(@PathVariable("id") Integer id) {
return new Goods(null, "服务端降级方案" + port + "", 0.0);
}
}
Hytrix熔断监控
Hystrix提供了Hystrix-dashboard 功能,用于时监控微服务运行状态。但是Hystrix-dashboard只能监控一个微服务Netflix还提供了Turbine,进行聚合监控
<?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>cloud-parent</artifactId>
<groupId>cpm.cqh</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>Hystrix-moniter</artifactId>
<dependencies>
<!--Hystrix提供的单个仪表盘监控依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
</dependency>
<!--netflix提供的聚会监控依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-turbine</artifactId>
</dependency>
<!--springBoot提供监控依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!--Eureka的客户端依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!--测试依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
</dependencies>
</project>
spring:
application:
name: hystrix-monitor
server:
port: 8766
turbine:
combine-host-port: true
app-config: FEIGN-CONSUMER,FEIGN-PROVIDER # 配置需要监控的微服务
cluster-name-expression: "'default'"
被监控模块添加依赖(提供者,消费者)
提供者
<!-- springboot暴露端点的依赖-->
<!--springBoot提供监控依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!--Hystrix提供的单个仪表盘监控依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
</dependency>
package com.cqh;
import com.netflix.hystrix.contrib.metrics.eventstream.HystrixMetricsStreamServlet;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.hystrix.dashboard.EnableHystrixDashboard;
import org.springframework.context.annotation.Bean;
/**
* @author cqh
* @date 2024/1/22
* @Description
*/
@SpringBootApplication
@EnableEurekaClient
// 开启Hystrix
@EnableCircuitBreaker
// 开启单个仪表盘监控
@EnableHystrixDashboard
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class,args);
}
@Bean
public ServletRegistrationBean getServlet(){
HystrixMetricsStreamServlet streamservlet=new HystrixMetricsStreamServlet();
ServletRegistrationBean registrationBean=new ServletRegistrationBean(streamservlet);
registrationBean.setLoadOnStartup(1);
registrationBean.addUrlMappings("/actuator/hystrix.stream");
registrationBean.setName("HystrixMetricsStreamServlet");
return registrationBean;
}
}
消费者
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
<!-- springboot暴露端点的依赖-->
<!--springBoot提供监控依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!--Hystrix提供的单个仪表盘监控依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
</dependency>
package com.cqh;
import com.netflix.hystrix.contrib.metrics.eventstream.HystrixMetricsStreamServlet;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.hystrix.dashboard.EnableHystrixDashboard;
import org.springframework.cloud.netflix.ribbon.RibbonClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.context.annotation.Bean;
/**
* @author cqh
* @date 2024/1/22
* @Description
*/
@SpringBootApplication
@EnableEurekaClient
// 开启feign服务
@EnableFeignClients
// 开启单个仪表盘监控
@EnableHystrixDashboard
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class,args);
}
@Bean
public ServletRegistrationBean getServlet(){
HystrixMetricsStreamServlet streamservlet=new HystrixMetricsStreamServlet();
ServletRegistrationBean registrationBean=new ServletRegistrationBean(streamservlet);
registrationBean.setLoadOnStartup(1);
registrationBean.addUrlMappings("/actuator/hystrix.stream");
registrationBean.setName("HystrixMetricsStreamServlet");
return registrationBean;
}
}
测试
启动服务端、生产者、消费者、监控端
监控端日志
访问http://localhost:8766/hystrix
http://localhost:8766/turbine.stream
显示不是上面的就访问接口后再刷新一下该页面
实心圆:它有颜色和大小之分,分别代表实例的监控程度和流量大小。如上图所示,它的健康度从绿色、黄色、橙色、红色递减。通过该实心圆的展示,我们就可以在大量的实例中快速的发现故障实例和高压力实例曲线: 用来记录 2 分钟内流量的相对变化,我们可以通过它来观察到流量的上升和下降趋势。
GateWay网关
概述
网关旨在为微服务架构提供一种简单而有效的统一的API路由管理方式。
在微服务架构中,不同的微服务可以有不同的网络地址,各个微服务之间通过互相调用完成用户请求,客户端可能通过调用N个微服务的接口完成一个用户请求。
存在的问题
客户端多次请求不同的微服务,增加客户端的复杂性
认证复杂,每个服务都要进行认证
http请求不同服务次数增加,性能不高
网关就是系统的入口,封装了应用程序的内部结构,为客户端提供统一服务,一些与业务本身功能无关的公共逻辑可以在这里实现诸如认证、鉴权、监控、缓存、负载均衡、流量管控、路由转发等
静态路由
在目前的网关解决方案里,有Nginx+ Lua、NetflixZuul、Spring Cloud Gateway等等
步骤
1.搭建网关模块
2.引入依赖:starter-gateway
<?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>cloud-parent</artifactId>
<groupId>cpm.cqh</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>gateway-server</artifactId>
<dependencies>
<!--gateway网关依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<!--eureka客户端依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
</dependencies>
</project>
3.编写启动类
package com;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* @author cqh
* @date 2024/1/31
* @Description
*/
@SpringBootApplication
public class GatewayApp {
public static void main(String[] args) {
SpringApplication.run(GatewayApp.class,args);
}
}
4.编写配置文件
server:
port: 8088 # 80是默认端口号
spring:
application:
name: gateway-server
cloud:
gateway: # 网关配置
routes: # 路由规则,集合形式
- id: FEIGN-PROVIDER # 路由规则唯一标识 默认是uuid
uri: http://localhost:8001/ # 转发路径转发到哪个服务器去
predicates: #判断条件,用于判断请求应该转到哪个微服务,可以写多个
- Path=/provider/**
- id: FEIGN-CONSUMER # 路由规则唯一标识 默认是uuid
uri: http://localhost:9000/ # 转发路径转发到哪个服务器去
predicates: # 判断条件,用于判断请求应该转到哪个微服务,可以写多个
- Path=/consumer/**
动态路由
5.启动测试
启动服务、生产者、消费者、gateway网关模块
访问看有问题不
微服务名称配置
gateway过滤器
Gateway支持过滤器功能,对请求或响应进行拦截,完成一些通用操作。
Gateway提供两种过滤器方式:“pre”和“post”
pre过滤器,在转发之前执行,可以做参数校验、权限校验、流量监控、日志输出、协议转换等.
post过滤器,在响应之前执行,可以做响应内容、响应头的修改日志的输出,流量监控等
Gateway还提供了两种类型过滤器
GatewayFilter:局部过滤器,针对单个路由
GlobalFilter:全局过滤器,针对所有路由
Gateway 过滤器-局部过滤器
GatewayFilter局部过滤器,是针对单个路由的过滤器
在SpringCloudGateway组件中提供了大量内置的局部过滤器,对请求和响应做过滤操作。
遵循约定大于配置的思想,只需要在配置文件配置局部过滤器名称并为其指定对应的值,就可以让其生效。
Gateway 过滤器-全局过滤器
GlobalFilter全局过滤器,不需要在配置文件中配置,系统初始化时加载,并作用在每个路由上
Spring Cloud Gateway核心的功能也是通过内置的全局过滤器来完成
自定义全局过滤器步骤
1.定义类实现GlobalFilter和 Ordered接口
2.复写方法
3.完成逻辑处理
内置局部过滤器网址
https://www.cnblogs.com/dalianpai/p/12288884.html
config分布式配置中心
概述
Spring Cloud Config 解决了在分布式场景下多环境配置文件的管理和维护
好处:
集中管理配置文件
不同环境不同配置,动态化的配置更新
配置信息改变时,不需要重启即可更新配置信息到服务
步骤
config server:
1.使用gitee创建远程仓库,上传配置文件
添加远程仓库配置文件
2.搭建 config server 模块
3.导入config-server依赖
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
</dependency>
</dependencies>
4.编写配置,设置gitee 远程仓库地址
server:
port: 9527
spring:
application:
name: config-server
cloud:
config:
server:
git:
uri: https://gitee.com/sqhshr/config-test2.git
#username: git仓库公开就不用账号密码
#password:
label: master # 使用的分支
5.测试访问远程配置文件
config client:
1.导入starter-config 依赖
<dependencies>
<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>
<!--config依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
</dependencies>
2.配置config server 地址,读取配置文件名称等信息
server:
port: 8000
spring:
application:
name: config-demo1
eureka:
client:
service-url:
defaultZone: http://localhost:8791/eureka
# bootstrap.yml 优先级高于application.yml
spring:
cloud:
config:
label: master #分支名称
uri: http://localhost:9527/ # configServer路径
name: config # 配置文件名称
profile: dev # 环境标识
3.获取配置值
4.启动测试
为了防止读取到同名的其他值我后面将前面所有username改为了username1
还有就是key value 要有空格 因为他是yml文件
Config 客户端刷新
1.在config 客户端引入actuator依赖
2.获取配置信息类上,添加@RefreshScope注解
3.添加配置 management.endpoints.web.exposure.include: refresh
4.使用curl工具发送post请求 curl -X POST http://localhost:8001/actuator/refresh
curl -X POST http://localhost:8000/actuator/refresh
测试
win+r
cmd
Config集成eureka
<dependencies>
<!--config依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
</dependency>
<!--eureka客户端依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
</dependencies>
server:
port: 9527
spring:
application:
name: config-server
cloud:
config:
server:
git:
uri: https://gitee.com/sqhshr/config-test2.git
#username: git仓库公开就不用账号密码
#password:
label: master # 使用的分支
#Eureka地址
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka
Bus消息总线
Spring Cloud Bus 是用轻量的消息中间件将分布式的节点连接起来,可以用于广播配置文件的更改或者服务的监控管理,关键的思想就是,消息总线可以为微服务做监控,也可以实现应用程序之间相通信。
Spring Cloud Bus 可选的消息中间件包括RabbitMQ和 Kafka
步骤
如果没有rabbitMQ文章最后有教程
1.分别在config-server和 config-client中引入bus依赖: bus-amqp
<dependencies>
<!--config依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
</dependency>
<!--eureka客户端依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!--Bus消息总线依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>
<!--springboot监控-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
</dependencies>
<dependencies>
<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>
<!--config依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!--Bus消息总线依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>
</dependencies>
2.分别在config-server和 config-client中配置RabbitMQ
# bootstrap.yml 优先级高于application.yml
spring:
cloud:
config:
label: master #分支名称
#uri: http://localhost:9527/ # configServer路径
name: config # 配置文件名称
profile: dev # 环境标识
#结合eureka,从注册中心根据服务名称获取地址
discovery:
enabled: true
service-id: CONFIG-SERVER
#配置rabbitMQ信息
rabbitmq:
host: localhost
port: 5672
username: guest
password: guest
virtual-host: /
management:
endpoints:
web:
exposure:
include: 'refresh' #暴露刷新端点
3.在config-server中设置暴露监控断点: bus-refresh
server:
port: 9527
spring:
application:
name: config-server
cloud:
config:
server:
git:
uri: https://gitee.com/sqhshr/config-test2.git
#username: git仓库公开就不用账号密码
#password:
label: master # 使用的分支
#配置rabbitMQ信息
rabbitmq:
host: localhost
port: 5672
username: guest
password: guest
virtual-host: /
#暴露bus刷新端点
management:
endpoints:
web:
exposure:
include: 'bus-refresh'
#Eureka地址
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka
测试
启动eureka服务、configServer、configClient1 、configClient2
客户端2换个端口号就可以了具体如下
访问
http://localhost:8000/hello/test
http://localhost:9000/hello/test
修改git仓库配置文件属性值
再次访问上面地址
发现无变化
win+r cmd
输入
curl -X POST http://localhost:9527/actuator/bus-refresh
Stream消息驱动
概述
SpringCloudStream是一个构建消息驱动微服务应用的框架
Stream解决了开发人员无感知的使用消息中间件的问题,因为Stream对消息中间件的进一步封装,可以做到代码层面对中间件的无感知,甚至于动态的切换中间件,使得微服务开发的高度解耦,服务可以关注更多自己的业务流程。
Spring Cloud Stream目前支持两种消息中间件RabbitMQ和Kafka
stream组件
SpringCloudStream构建的应用程序与消中间件之间是通过绑定器Bindel相关联的。绑定器对于应用程序而言起到了隔离作用,它使得不同消息中间件的实现细节对应用程序来说是透明的。
binding是我们通过配置把应用和spring cloudstream的 binder绑定在一起
output: 发送消息Channel,内置Source接口
input: 接收消息Channel,内置Sink接口
stream消息生产者
1.创建消息生产者模块,引入依赖starter-stream-rabbit
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-stream-rabbit</artifactId>
</dependency>
</dependencies>
2.编写配置,定义binder,和bingings
server:
port: 8000
spring:
cloud:
stream:
binders: #绑定器
cqh_bind: #自定义绑定器
type: rabbit #中间件类型
enviroment: #指明中间件环境
spring:
rabbitmq:
host: localhost
port: 5672
username: guest
password: guest
virtual-host: /
bindings:
output:
binder: cqh_bind
dstination: cqh_exchange
3.定义消息发送业务类。添加@EnableBinding(Source.class),注入MessageChanneloutput,完成消息发送
package com.producer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.stream.annotation.EnableBinding;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.stereotype.Component;
import javax.xml.transform.Source;
/**
* @author cqh
* @date 2024/2/1
* @Description
*/
@Component
@EnableBinding(Source.class)
public class MessageProducer {
@Autowired
private MessageChannel output;
public void send(String message){
//构建消息体
Message<String> build = MessageBuilder.withPayload(message).build();
output.send(build);
}
}
package com.web;
import com.producer.MessageProducer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author cqh
* @date 2024/2/1
* @Description
*/
@RestController
@RequestMapping("/producer")
public class ProducerController {
@Autowired
private MessageProducer messageProducer;
@RequestMapping("/send")
public String sendMessage(String message){
messageProducer.send(message);
return "success";
}
}
4.编写启动类,测试
stream消息消费者
1.创建消息消费者模块,引入依赖starter-stream-rabbit
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-stream-rabbit</artifactId>
</dependency>
</dependencies>
2.编写配置,定义binder,和bingings
server:
port: 9000
spring:
cloud:
stream:
binders: #绑定器
cqh_bind: #自定义绑定器
type: rabbit #中间件类型
enviroment: #指明中间件环境
spring:
rabbitmq:
host: localhost
port: 5672
username: guest
password: guest
virtual-host: /
bindings:
input:
binder: cqh_bind
dstination: cqh_exchange
3.定义消息接收业务类。添加@EnableBinding(Sink.class),使用@StreamListener(SinkINPUT),完成消息接收
package com.listener;
import org.springframework.cloud.stream.annotation.EnableBinding;
import org.springframework.cloud.stream.annotation.StreamListener;
import org.springframework.cloud.stream.messaging.Sink;
import org.springframework.messaging.Message;
import org.springframework.stereotype.Component;
/**
* @author cqh
* @date 2024/2/1
* @Description
*/
@Component
@EnableBinding({Sink.class})
public class MassageListener {
// 配置监听目标
@StreamListener(Sink.INPUT)
public void receive(Message message){
Object payload = message.getPayload();
System.out.println("payload = " + payload);
}
}
4.编写启动类,测试
Sleuth+Zipkin 链路追踪
概述
SpringCloud Sleuth 其实是一个工具,它在整个分布式系统中能跟踪一个用户请求的过程,捕获这些跟踪数据,就能构建微服务的整个调用链的视图,这是调试和监控微服务的关键工具。
耗时分析
可视化错误
链路优化
Zipkin是Twitter 的一个开源项目,它致力于收集服务的定时数据,以解决微服务架构中的延迟问题,包括数据收集、存储、查找和展现
步骤
1.安装启动zipkin。
java -jar zipkin-server-2.12.9-exec.jar
2. 访问zipkin web界面。
http://localhost:9411/
3.在服务提供方和消费方分别引入 sleuth 和 zipkin依赖
4.分别配置服务提供方和消费方
server:
port: 9000
eureka:
instance:
#是否将自己的ip地址注册到eureka中,默认是false(默认注册主机名)
# true 就是将本机非回环地址(127.0.0.1)的第一个ip注册到eureka中,这个ip不一定是公网ip,所以我们在公网环境下一般手动指定ip
# prefer-ip-address: true
# ip-address: 127.0.0.1 #手动指定公网ip
# instance-id: ${eureka.instance.ip-address}:${spring.application.name}:${server.port}
hostname: localhost #主机名
client:
service-url:
defaultZone: http://localhost:8761/eureka #,http://127.0.0.1:8762/eureka eureka服务注册地址
spring:
application:
name: feign-consumer # 服务名称,会在eureka 服务的监控页面进行展示
zipkin:
base-url: http://localhost:9411 #zipkin服务路径,用于提交收集的数据
sender:
type: web
sleuth:
sampler:
probability: 1 #采集率 默认0.1(10%)
# 设置ribbon 的超时时长
#ribbon:
# ConnectTimeout: 2000 # 客户端连接服务器时长
# ReadTimeout: 3000 # 连接服务器后,方法执行的时长
# 指明当前日志级别
logging:
level:
com: debug #com是包名
## 对数据进行压缩处理
#feign:
# compression:
# request:
# enabled: true
# mime-type: text/xml,application.xml,application/json
# min-request-size: 2048
# response:
# enabled: true
# mime-type: text/xml,application.xml,application/json
# min-request-size: 2048
# 开启feign对Hystrix的支持
feign:
hystrix:
enabled: true
测试
启动eureka服务器和生产者消费者
访问http://localhost:9000/consumer/goods/1
rabbitMQ安装
win+r cmd 输入erl查看是否安装
安装教程放在本文章绑定资源中
安装后
双击
登录账号guest
密码guest