服务注册和发现
搭建Eureka注册中心服务器
- 新建模块
- 调整pom.xml
- 父项目
- 添加eureka serve依赖
- yml配置
- 关闭自我保护模式
- 主机名
- 针对单台服务器,不向自己注册,不从自己拉取
- yaml配置如下:
server:
port: 2001
spring:
application:
name: eureka-serve
eureka:
server:
enable-self-preservation: false #关闭自我保护模式
instance:
hostname: eureka1 #设置主机名
client:
register-with-eureka: false #不向自己注册
fetch-registry: false #不从自己拉取
启动类添加注解
@EnableEurekaServe
触发eureka服务器自动配置Eureka四条运行机制
客户端启动时,会反复连接注册中心尝试注册,知道注册成功为止
- 客户端每30秒发送一次心跳数据,表示服务存活,eurwka服务器连续3次收不到一个服务的心跳会由注册列表中删除此服务.
- 客户端每30秒拉取一次注册表,刷新本地注册缓存
自我保护模式,由于网络中断或网络不稳定,15分钟内85%服务器出现心跳异常(每有一次接受不到心跳则算一次心跳异常)自动进入自我保护模式,自我保护模式下的所有注册信息都不删除,网络恢复后自动退出自我保护模式,开发调试期间可以关闭自我保护模式,避免影响调试
客户端连接Eureka客户端
添加eureka client依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
修改yml配置;eureka服务端连接地址:
http://eureka1:2001/eureka
eureka:
client:
service-url:
defaultZone: http://localhost:2001/eureka
Feign远程调用
订单服务调用商品服务和用户服务
添加远程调用feign依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
- 启动类添加注解
@EnableFeignClients
,触发feign自动配置 - 定义远程调用接口
- ItemClient
- UserClient
-
Feign集成Ribbon实现负载均衡和重试
Feign集成了Ribbon,默认实现了负载均衡和重试
- Ribbon远程调用失败可自动发起调用重试
- 异常
- 服务器宕机
- 后台服务器堵塞
- 重试参数:
配置路由转发规则
# 服务id设置为访问子路径是默认规则
# zuul根据注册表的注册信息完成自动配置,最好手动配置,防止注册表不全
zuul:
routes:
# 其中**包含深层路径 *只包含一层路径
item-service: /item-service/**
user-service: /user-service/**
order-service: /order-service/**
-
统一权限校验
http://localhost:3001/item-service/123
—-没有登陆不可访问商品服务接口http://localhost:3001/item-service?token=12345
已经登陆可以访问 新建
ZuulFilter
类的子类,继承ZuulFilter
类- 按Zuul的规则实现
- 添加
@commpont
注解
zuul的自动配置类可以在spring容器中自动发现过滤器实例,完成自动配置
Zuul集成Ribbon
- 容错-降级
调用后台服务出错(异常,堵塞,服务崩溃),可以执行当前服务的一段代码,直接向客户端返回降级结果
可返回一下两种结果:
- Zuul默认启用Hystrix
- 实现FallbackProvider,按zuul的规则实现接口的方法
- 添加
@component
将商品服务降级
package cn.tedu.sp06.fallback;
import cn.tedu.web.util.JsonResult;
import org.springframework.cloud.netflix.zuul.filters.route.FallbackProvider;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.stereotype.Component;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
/**
* @Author: 一拳超人
* @Date: 2021/10/20 9:50
*/
@Component
public class ItemFallback implements FallbackProvider {
/**
* 设置当前降级类,表示调用哪个后台服务会调用当前降级类
* "item-service" 只针对商品降级
* *和null 表示对所有服务都降级
*/
@Override
public String getRoute() {
return "item-service";
}
/**
* 设置降级响应,返回至客户端
*/
@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();
}
/**
* 用于关闭下面方法中的流
* ByteArrayInputStream为内存数组中的流,不占用底层资源不需要关闭
*/
@Override
public void close() {
}
@Override
public InputStream getBody() throws IOException {
String json = JsonResult.err().code(500).msg("你tm能不能不访问").toString();
return new ByteArrayInputStream(json.getBytes(StandardCharsets.UTF_8));
}
@Override
public HttpHeaders getHeaders() {
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.add("Content-Type", "application/json;charset=UTF-8");
return httpHeaders;
}
};
}
}
将订单服务降级
package cn.tedu.sp06.fallback;
import cn.tedu.web.util.JsonResult;
import org.springframework.cloud.netflix.zuul.filters.route.FallbackProvider;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.stereotype.Component;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
/**
* @Author: 一拳超人
* @Date: 2021/10/20 10:32
*/
@Component
public class OrderFallback implements FallbackProvider {
@Override
public String getRoute() {
return "order-service";
}
/**
* 设置降级响应,返回至客户端
*/
@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();
}
/**
* 用于关闭下面方法中的流
* ByteArrayInputStream为内存数组中的流,不占用底层资源不需要关闭
*/
@Override
public void close() {
}
@Override
public InputStream getBody() throws IOException {
String json = JsonResult.err().code(500).msg("你tm能不能不访问").toString();
return new ByteArrayInputStream(json.getBytes(StandardCharsets.UTF_8));
}
@Override
public HttpHeaders getHeaders() {
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.add("Content-Type", "application/json;charset=UTF-8");
return httpHeaders;
}
};
}
}
Hystrix限流-熔断
- 当流量过大,造成后台服务故障,可以断开链路,限制后台服务的访问流量,等待后台服务恢复
- 断路器打开条件
- 10秒20次请求(默认,必须首先满足)
- 50%的请求出错,执行降级代码
半开状态
健康状态
- spring容器中的所有对象
- spring mvc映射的所有路径
- jvm堆内存对象
Actuator使用
- 添加actuator依赖
yml配置,暴露监控日志
#暴露所有日志
m.e.w.e.i="*"
management:
endpoint:
health:
show-components: always
endpoints:
web:
exposure:
include: "*"
m.e.w.e.i=health #暴露健康状态日志
m.e.w.e.i=health,beans,mappings,hystrix.stream #暴露多种日志
查看日志 http://localhost:3001/actuator
搭建Hystrix dashboard
新建模块
添加依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
</dependency>
yml配置
#允许抓取服务器列表
hystrix:
dashboard:
proxy-stream-allow-list:
- localhost
启动类添加注解
@EnableHystrixDashboard
Turbine
局和多态服务器日志数据,提供给仪表盘显示
新建模块
- 添加依赖
- eureka client
- turbine
yml配置
#需要聚合的服务
#命名聚合后的日志数据
启动类注解
@EnableTurbine
- 合并的日志地址
http://localhost:5001/turbine.stream