1、Eureka注册中心
微服务核心就是注册中心,所有服务启动必须向注册中心注册,
配置中心:集中管理维护配置文件。
限流通过熔断,容错通过降级实现。
Api网关Zuul
1.1 Eureka运行机制
- 注册:客户端向服务器注册时,会一次次返回的注册,直到注册成功为止
- 拉取:客户端每30秒拉取一次注册表。更新本地的缓存的注册表
- 心跳:客户端每30秒发送一次心跳数据,服务器连续3次收不到服务的心跳,就会删除该服务。
- 自我保护模式:
1、在网络中断时,15分钟之内,==85%==的服务器出现心跳异常(一次心跳丢失),
2、自动进入保护模式,保留注册信息不删除。
3、网络恢复后,可以自动退出保护模式
4、开发调试期间,禁用保护模式,避免影响测试。
1.2 Eureka 服务端
- 创建eureka项目
- 配置依赖 pom.xml
- 配置 application.yml
- 主程序启用 eureka 服务器
- 启动,访问测试
1.3 Eureka 客户端
- 添加eureka client依赖
- yml配置eureka地址
- 修改hosts,添加eureka1和eureka
添加eureka的IP映射
172.0.0.1 eureka1
172.0.0.1 eureka2
1.3 Eureka与服务提供者 高可用
1.3.1 服务提供者高可用
1、启动参数 --server.port 可以覆盖yml中的端口配置
–server.port=8001
相同的服务以不同的端口开启多个,模拟高可用。
当加入了eureka客户端依赖之后,就会自动向eureka注册中心注册。
1.3.2 Eureka高可用
1、添加两个服务的profile配置文件
application-eureka1.yml
eureka:
instance:
hostname: eureka1
client:
register-with-eureka: true #profile的配置会覆盖公用配置
fetch-registry: true #profile的配置会覆盖公用配置
service-url:
defaultZone: http://eureka2:2002/eureka #eureka1启动时向eureka2注册
application-eureka2.yml
eureka:
instance:
hostname: eureka2
client:
register-with-eureka: true #profile的配置会覆盖公用配置
fetch-registry: true #profile的配置会覆盖公用配置
service-url:
defaultZone: http://eureka1:2001/eureka #eureka2启动时向eureka1注册
2、配置启动参数 --spring.profiles.active 和 --server.port
- eureka1 启动参数:
–spring.profiles.active=eureka1 --server.port=2001 - eureka2 启动参数:
–spring.profiles.active=eureka2 --server.port=2002 - 如果在命令行:
java -jar xxx.jar --spring.profiles.active=eureka1 --server.port=2001
访问eureka服务器
2 Ribbon 负载均衡(网关层面)
ribbon 提供了负载均衡和重试功能, 它底层是使用 RestTemplate 进行 Rest api 调用
2.1 负载均衡实现
2.1.1 添加依赖
eureka 依赖中已经包含了 ribbon
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>
2.1.2 启动Ribbon功能
@LoadBalanced 负载均衡注解,会对 RestTemplate 实例进行封装,创建动态代理对象,并切入(AOP)负载均衡代码,把请求分发到集群中的服务器
@EnableDiscoveryClient
@SpringBootApplication
public class Sp06RibbonApplication {
@LoadBalanced //负载均衡注解
@Bean
public RestTemplate getRestTemplate() {
return new RestTemplate();
}
public static void main(String[] args) {
SpringApplication.run(Sp06RibbonApplication.class, args);
}
}
2.1.3 测试访问
访问测试,ribbon 会把请求分发到 8001 和 8002 两个服务端口上
2.2 Riboon 重试
- 调用后台服务时,如果失败由Ribbon重试调用服务。
- Feign集成了Ribbon,默认启动重试。
- 重试参数:
1、ribbon.MaxAutoRetries:单台服务器的重试次数 0
2、ribbon.MaxAutoRetresNextServer:更换服务器次数 1
2.2.1 Ribbon重试实现
1、添加依赖
<dependency>
<groupId>org.springframework.retry</groupId>
<artifactId>spring-retry</artifactId>
</dependency>
2、配置yml文件
spring:
application:
name: ribbon
server:
port: 3001
eureka:
client:
service-url:
defaultZone: http://eureka1:2001/eureka, http://eureka2:2002/eureka
ribbon:
MaxAutoRetriesNextServer: 2
MaxAutoRetries: 1
OkToRetryOnAllOperations: true
ConnectionTimeout
ReadTimeout
OkToRetryOnAllOperations=true
默认只对GET请求重试, 当设置为true时, 对POST等所有类型请求都重试
MaxAutoRetriesNextServer
更换实例的次数
MaxAutoRetries
当前实例重试次数,尝试失败会更换下一个实例
3 Zuul API网关
背景:在微服务项目中,服务多,需要一个统一的API网关入口。网关面向用户,网关转发客户端请求,访问后台服务。
功能:
zuul API 网关,为微服务应用提供统一的对外访问接口。
zuul 还提供过滤器,对所有微服务提供统一的请求校验。
3.1 统一入口 (功能一)
配置步骤:
3.1.1 添加依赖
<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-netflix-zuul</artifactId>
</dependency>
spring-cloud-starter-netflix-eureka-client 注册发现
spring-cloud-starter-netflix-zuul zuul网关
3.1.3 yml配置文件
zuul 路由配置可以省略,缺省以服务 id 作为访问路径
# 应用名称
spring:
application:
name: zuul
server:
port: 3001
eureka:
client:
service-url:
defaultZone: http://eureka1:2001/eureka,http://eureka2:2002/eureka
zuul:
routes:
item-service: /item-service/**
user_service: /user-service/**
order_service: /order-service/**
3.1.4 启动类注解
添加 @EnableZuulProxy 和 @EnableDiscoveryClient 注解
3.1.5 功能验证
前端请求访问Zuul网关暴露统一的接口 :localhost:3001(网关端口)/转发路径/**
http://localhost:3001/user-service/7/score?score=100
3.2 统一权限校验( 功能二)
zuul的过滤器zuulProxy,可以过滤客户端的请求,在过滤器中可以检查访问权限
1、新建过滤器类,AccessFilter按照Zuul规则实现
2、将该类交给spring管理
3、zuul的自动配置,会在spring容器中发现过滤器实,完成自动配置。
配置zuul过滤器
public class Fitller extends ZuulFilter {
@Override
public String filterType() {
return FilterConstants.PRE_TYPE;
}
@Override
public int filterOrder() {
//定义过滤器的执行顺序,第六个过滤器。
//第五个过滤器中,才向里面加入了serverId
return 6;
}
@Override
public boolean shouldFilter() {
/**调用商品需要权限
* 调用用户或订单不检查权限*/
//1、获取上下文对象
RequestContext ctx = RequestContext.getCurrentContext();
//2、从上下文中获取调用的服务
String serverId = (String) ctx.get(FilterConstants.SERVICE_ID_KEY);
return serverId.equals("item-service");
}
@Override
public Object run() throws ZuulException {
//获取token参数,从请求路径中获取
//获取上下文对象
RequestContext ctx = RequestContext.getCurrentContext();
//获得request对象
HttpServletRequest request = ctx.getRequest();
//接收token参数
String token = request.getParameter("token");
//如果token不存在
if (StringUtils.isBlank(token)){
//阻止继续调用
ctx.setSendZuulResponse(false);
String json = JsonResult.build().code(400).msg("未登录").toString();
ctx.addZuulResponseHeader("Context-Type",
"application/json;charset=UTF-8");
ctx.setResponseBody(json);
}
return null;//zuul当前版本不起任何作用
}
}
3.3 Zuul+Ribbon负荷均衡 ( 功能三)
3.3.1 负荷均衡
Zuul集成Ribbon以及默认实现了负载均衡
3.3.2 重试
负载均衡方式:轮询,hash,权重,随机等算法。
1、负载均衡默认启用,
2、重试默认禁用(减少后台服务器访问压力)
在最前面重试,能造成服务器大面积压力倍增,大面积出现故障。
3、启动重试
1)添加spring-retry依赖
<dependency>
<groupId>org.springframework.retry</groupId>
<artifactId>spring-retry</artifactId>
</dependency>
2)yml配置启动重试:zuul.retryable=true
3) 如果需要可以配置重试参数
重试两种配置方法:
#对所有服务有效
spring:
application:
name: zuul
server:
port: 3001
eureka:
client:
service-url:
defaultZone: http://eureka1:2001/eureka, http://eureka2:2002/eureka
zuul:
retryable: true
# routes:
# item-service: /item-service/**
# user-service: /user-service/**
# order-service: /order-service/**
ribbon:
ConnectTimeout: 1000
ReadTimeout: 1000
MaxAutoRetriesNextServer: 1
MaxAutoRetries: 1
3.4 Zuul+Hystrix降级( 功能四)
Hystrix是一个容错限流工具
Hystrix 容错:重试机制,与降级处理。
Hystrix 是一个延迟和容错库,旨在隔离远程系统,服务和第三方库的访问点,当出现故障是不可避免的故障时,停止级联故障
Hystrix 限流:熔断
3.4.1 Zuul网关使用Hystrix进行容错降级处理
Zuul默认以及启动Hystrix,任何基础配置不用做。
调用后台服务失败,执行签名模块中的降级代码,向客户端返回降级结果
降级结果:1、错误提示 2、返回缓存数据 3、根据业务逻辑,返回任何结果。
降级处理步骤:
1、新建降级类,ItemFB,实现FallbackProvider接口
2、添加@component注解,交给sping处理
3、Zuul的自动配置,可以自动发现降级类的实例,完成自动配置
@Component
public class ItemFB implements FallbackProvider {
/**设置针对哪个后台服务进行降级处理
* Item-service:只针对商品服务进行降级
* *:针对所有的服务都应用当前降级类
* null :对所有的服务都引用当前的降级类*/
@Override
public String getRoute() {
return "item-sevice";
}
/**向客户端返回的响应数据*/
@Override
public ClientHttpResponse fallbackResponse(String route, Throwable cause) {
//该对象是一个接口,返回的是匿名内部类
return new ClientHttpResponse() {
@Override
public HttpStatus getStatusCode() throws IOException {
//内部服务器出错-状态码
return HttpStatus.INTERNAL_SERVER_ERROR;
//可以在这里返回缓存的结构
}
//原始状态码
@Override
public int getRawStatusCode() throws IOException {
return HttpStatus.INTERNAL_SERVER_ERROR.value();
}
//返回文本字符串
@Override
public String getStatusText() throws IOException {
return HttpStatus.INTERNAL_SERVER_ERROR.getReasonPhrase();
}
@Override
public void close() {
//用来关闭下面的流,BAIS不占用底层系统资源,所以不需要关闭。
}
//设置协议体
@Override
public InputStream getBody() throws IOException {
//JsonResult - {code:500,msg:xxx,data:null}
String json = JsonResult
.build()
.code(500)
.msg("后台服务器出错请稍后重试")
.toString();
//将字符串封装到byte[]数组中返回。
return new ByteArrayInputStream(json.getBytes("UTF-8"));
}
//设置协议头
@Override
public HttpHeaders getHeaders() {
//告诉客户端我发送数据的格式
HttpHeaders headers = new HttpHeaders();
headers.add("Content-type","application/json;charset=UTF-8");
return headers;
}
};
}
}
3.4.2 Zuul集成Hystrix实现限流,熔断
当流量过大后台服务出现故障,可以断开链路,限制后台故障服务的流量,等待它从故障中恢复
实现:通过断路器实现
当短路器打开,前端请求过来直接执行降级逻辑,返回前端。不会调用远端服务,直接返回短路返回。效率高。
- 断路器打开的条件:
1)10秒20次请求(必须首先满足条件)
2)50%请求出错,执行了降级代码 - 断路器打开后,会进入半开状态
在半开状态下,会向后端服务器尝试发送一次客服端调用
3.4.3Hystrix dashboard(监控工具)
对Hystrix降级和熔断的情况进行监控,可以通过监控快速定位故障模块。
在Zuul网关模块抓取日志,然后分析,生成图表。
Hystrix使用Actuator暴露自己监控的日志
Actuator是springBoot提供的项目监控指标工具,可以暴露项目的多种监控指标
- 健康状态
- springcontext容器中所有的对象
- spring mvc 映射的所有路径
- 环境变量
- 堆内存镜像
3.4.4暴露Actuator监控指标
1、添加Actuator依赖
2、yml
m.e.w.e.i="*" #暴露全部
m.e.w.e.i=health,beans,hystryix.stream
m.e.w.e.i=hystryix.stream
3、访问(暴露的监控指标)
http://localhost:3001/actuator
MAT分析工具。分析堆内存占用情况。
3.4.5 搭建Hystrix-dashboard仪表盘
1.新建spring模块
2.添加Hystrix-dashbard依赖
3.yml配置 允许抓取日志的服务区列表
4.启动类注解 @EnableHystrixDashboard
5.访问
http://localhost:/hystrix
输入框填入:http://localhost:3001/actuator/hystrix
3.4.4 Turbine
从多态服务器聚合 Hystrix 监控数据,Hystrix dashboard仪表盘可以从Turbine抓取聚合后的日志数据
新建 spring 模块: sp08-turbine
pom.xml 添加 eureka client、turbine
yml
聚合的服务的id列表: zuul,aaa,bbb,ccc
为聚合后的数据命名: new String(“aaa”)
启动类注解: @EnalbeTurbine
访问日志数据: http://localhost:5001/turbine.stream
4 SpringCloud-Config 配置中心
作用:集中维护管理配置文件。
yml 配置文件保存到 git 服务器,例如 github.com 或 gitee.com
微服务启动时,从服务器获取配置文件
4.1 配置中心服务端
Config默认配置文件存储位置是git,也可以存储在数据库,与本地
配置步骤
1、git上新建厂库,上传配置文件
2、新建spring模块
1)添加依赖:eureka-client(注册发现),config-server(配置中心)
2)yml配置 :
spring:
application:
name: config-server
cloud:
config:
server:
git:
#远程厂库路径
uri: https://gitee.com/hai-ting/spring-cloud1
#配置文件存放的文件夹
search-paths: config
server:
port: 6001
eureka:
client:
service-url:
defaultZone: http://eureka1:2001/eureka,http://eureka2:2002/eureka
3、添加启动类注解
@EnableConfigServer
4.2 配置中心的客户端模块
服务端获取配置过程:从注册表得到配置中心的地址,再从配置中心下载配置文件
1、注释本地配置文件。
2、添加依赖:config client
spring-cloud-starter-config
3、配置 bootstrap.yml
eureka:
client:
service-url:
defaultZone: http://eureka1:2001/eureka,http://eureka2:2002/eureka
spring:
cloud:
config:
discovery:
service-id: config-server
enabled: true
name: user-service #文件名
profile: dev
启动项目,控制台能够看连接config模块下载配置
5 Rabbitmq&Bus 刷新配置
post 请求消息总线刷新端点,服务器会向 rabbitmq 发布刷新消息,接收到消息的微服务会向配置服务器请求刷新配置信息
1、BUS配置刷新
刷新指令消息发送到rabbitmq,其他模块接收执行刷新操作。
5.1 功能配置
5.1.1 添加依赖
需要动态更新配置的微服务,添加 spring cloud bus 依赖,并添加 rabbitmq 连接信息
服务模块添加RabbitMQ于Bus依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-stream-binder-rabbit</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-bus</artifactId>
</dependency>
配置中心添加依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-stream-binder-rabbit</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-bus</artifactId>
</dependency>
5.1.2 配置中心添加Rabbitmq连接信息
服务配置文件:修改之后需要推送至远程厂库
rabbitmq:
host: 192.168.64.128
port: 5672
username: admin
password: admin
config-server 暴露 bus-refresh 刷新端点
修改 sp12-config 项目的 application.yml, 暴露bus-refresh端点
配置中心模块
management:
endpoints:
web:
exposure:
include: bus-refresh
5.2 验证
查看暴露端点:http://localhost:6001/actuator
Post请求:刷新所有服务配置,
POST http://localhost:6001/actuator/bus-refresh–刷新所有服务配置
POST http://localhost:6001/actuator/bus-refresh/user-service–刷新指定服务配置
5.3 配置刷新-获取配置中心配置
1、修改配置中心的配置文件 --添加用户
2、服务端获取配置中心修改的配置文件
@RefreshScope//刷新配置,可以注入到对象中
3、测试
首先通过rabbitmq和bus拿到git配置中心配置
POST http://localhost:6001/actuator/bus-refresh/user-service
访问user-service服务拿到获取配置中心添加的用户
GET http://localhost:3001/user-service/9
6 选择正确网卡,注册ip不注册主机名
eureka客户端向eureka注册时, 会自动选择网卡, 并可能注册主机名而不是ip地址.
6.1 选择正确的网卡
bootstr.yml 修改引导配置文件
下面两个配置二选一
spring:
cloud:
inetutils:
ignored-interfaces: # 忽略的网卡
- VM.*
preferred-networks: # 要是用的网卡的网段
- 192\.168\.0\..+
6.2 注册ip而不注册主机名
注册时,有可能自动选择主机名进行注册,而不使用ip地址. 主机名在局域网内有可能不会被正确的解析
最好使用ip地址进行注册,而不注册主机名
在应用配置application.yml中配置:
eureka:
instance:
prefer-ip-address: true # 使用ip进行注册
instance-id: ${spring.cloud.client.ip-address}:${spring.application.name}:${server.port} # 界面列表中显示的格式也显示ip
6.3 验证结果
7 sleuth + zipkin 链路跟踪
7.1 sleuth 简单实现
随着系统规模越来越大,微服务之间调用关系变得错综复杂,一条调用链路中可能调用多个微服务,任何一个微服务不可用都可能造整个调用过程失败
spring cloud sleuth 可以跟踪调用链路,分析链路中每个节点的执行情况
7.2 zipkin链路分析
日志通过rabbitmq发送到Zipkin服务器
7.2.1 服务以及网关添加zipkin client依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zipkin</artifactId>
</dependency>
7.2.2 网关添加Rabbitmq配置
1、pom文件配置
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
2、yml配置
rabbitmq:
host: 192.168.64.128
port: 5672
username: admin
password: admin
#日志发送方式
zipkin:
sender:
type: rabbit
7.2.3 启动Zipkin
java -jar zipkin-server-2.23.5-exec.jar --zipkin.collector.rabbitmq.uri=amqp://admin:admin@192.168.64.128:5672