目录
配置启动参数 --spring.profiles.active 和 --server.port
Eureka
Eureka的四条运行机制
- 注册
客户端一次次的反复连接注册中心进行注册,直到注册成功为止
- 拉取
客户端每30秒拉取一次注册表,刷新注册表
- 心跳
客户端每30秒发送一次心跳数据,如果服务器端连续三次收不到一个服务的心跳,会删除它的注册信息
- 自我保护模式
- 由于网络故障,15分钟内,85%服务器出现心跳异常,会自动进入自我保护模式
- 保护所有注册信息不删除
- 等待网络恢复后,可以退出保护模式,恢复正常
- 开发调试期间应该关闭保护模式,避免影响测试
依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
application.yml
spring:
application:
name: eureka-server
server:
port: 2001
eureka:
server:
enable-self-preservation: false
instance:
hostname: eureka1
client:
register-with-eureka: false
fetch-registry: false
- eureka 集群服务器之间,通过 hostname 来区分
- eureka.server.enable-self-preservation
- eureka 的自我保护状态:心跳失败的比例,在15分钟内是否超过85%,如果出现了超过的情况,Eureka Server会将当前的实例注册信息保护起来,同时提示一个警告,一旦进入保护模式,Eureka Server将会尝试保护其服务注册表中的信息,不再删除服务注册表中的数据。也就是不会注销任何微服务
- eureka.client.register-with-eureka=false
- 不向自身注册
- eureka.client.fetch-registry=false
- 不从自身拉取注册信息
- eureka.instance.lease-expiration-duration-in-seconds
- 最后一次心跳后,间隔多久认定微服务不可用,默认90
启动类添加@EnableEurekaServer
注解
修改 hosts 文件,添加 eureka 域名映射
C:\Windows\System32\drivers\etc\hosts
添加内容
127.0.0.1 eureka1
127.0.0.1 eureka2
微服务注册到Eureka服务器
在pom.xml中添加以下依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
application.yml 添加 eureka注册配置
eureka:
client:
service-url:
defaultZone: http://eureka1:2001/eureka
- eureka.instance.lease-renewal-interval-in-seconds
- 心跳间隔时间,默认 30 秒
- defaultZone,默认位置,可以修改为具体地理位置,比如:beiJing, shangHai, shenZhen 等,表示 eureka 服务器的部署位置, 需要云服务器提供
- eureka.client.registry-fetch-interval-seconds
- 拉取注册信息间隔时间,默认 30 秒
启动类添加@EnableDiscoveryClient注解
Eureka 高可用
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注册
server:
port: 2001
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注册
server:
port: 2002
配置启动参数 --spring.profiles.active
和 --server.port
--spring.profiles.active=eureka1 --server.port=2001
如果在命令行运行,可以在命令行中添加参数
java -jar xxx.jar --spring.profiles.active=eureka1 --server.port=2001
Feign 集成 Ribbon
- 负载均衡 -- 默认启用了负载均衡
- 重试 -- 默认启用了重试:调用后台服务失败(异常、服务器崩溃、超时),可以自动发起重试调用
重试参数
- ribbon.MaxAutoRetries - 单台服务器的重试次数,默认0
- ribbon.MaxAutoRetriesNextServer - 更换服务器的次数,默认1
- ribbon.ReadTimeout - 接收响应的超时时间,默认1000
- ribbon.ConnectTimeout - 与后台服务器建立连接等待超时时间,默认1000
- ribbon.OkToRetryOnAllOperations - 是否对所有类型请求都进行重试,默认只对 GET 请求重试
Zuul网关
依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
application.yml
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/**
启动类添加@EnableZuulProxy
和 @EnableDiscoveryClient
注解
Zuul 统一权限校验
1. 新建过滤器类:AccessFilter,继承 ZuulFilter
2.添加注解:`@Component`
package cn.tedu.sp06.filter;
import cn.tedu.web.util.JsonResult;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
@Component
@Slf4j
public class AccessFilter extends ZuulFilter {
//设置过滤器的类型:pre,routing,post,error
//zuul自动配置的回调方法
@Override
public String filterType() {
//return "pre";
log.info("Zuul自动配置过滤器类型");
return FilterConstants.PRE_TYPE;
}
//过滤器的顺序号
@Override
public int filterOrder() {
/*
在默认的第5个过滤器中,向上下文对象放入了serviceId
后面过滤器中才能访问这个数据
*/
log.info("Zuul自动配置过滤器的顺序号");
return 6;
}
//针对当前请求进行判断,是否要执行过滤代码
@Override
public boolean shouldFilter() {
//如果客户端调用商品,要判断权限
//否则调用用户或订单,不判断权限
//获得当前请求的上下文对象
RequestContext ctx = RequestContext.getCurrentContext();
//从上下文对象取出正在访问的serviceId
String serviceId = (String) ctx.get("serviceId");
//判断serviceId是否是“item-service”
return "item-service".equalsIgnoreCase(serviceId);
}
//过滤代码
@Override
public Object run() throws ZuulException {
//获得上下文对象
RequestContext ctx = RequestContext.getCurrentContext();
//从上下文对象取出request对象
HttpServletRequest request = ctx.getRequest();
//用request接收token参数
String token = request.getParameter("token");
//如果token不存在
if(StringUtils.isBlank(token)){
//阻止继续访问
ctx.setSendZuulResponse(false);
//直接返回响应:JsonResult{code:500,msg:"xxx",data:null}
String json = JsonResult.build().code(500).msg("没有登录!").toString();
ctx.addZuulResponseHeader("Content-Type","application/json;charset=UTF-8");
ctx.setResponseBody(json);
}
return null;//zuul当前版本没有使用这个返回值,返回任何数据都可以,不起任何作用
}
}
Zuul 集成 Ribbon
- 默认已经启动 ribbon 的负载均衡
- 默认不启用 ribbon 的重试
- 在网关重试,可能造成后台服务大面积出现压力翻倍
- 重试功能应该尽量往后放
- 启用重试
1. 添加 spring-retry 依赖
<dependency>
<groupId>org.springframework.retry</groupId>
<artifactId>spring-retry</artifactId>
</dependency>
2. yml配置启用重试: zuul.retryable=true
zuul:
retryable: true
Zuul集成Hystrix
- zuul默认已经启用了Hystrix
- 添加降级
1. 添加降级类,实现 FallbackProvider 接口
2. 添加 `@Component`
- zuul的自动配置会从spring容器自动发现降级类的实例,完成自动配置
package cn.tedu.sp06.fb;
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;
/*
当调用后台商品服务失败,执行网关中的这个降级类,向客户端返回降级结果
*/
@Component
public class ItemFB 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();
}
@Override
public void close() {
//用来关闭下面的输入流
//ByteArrayInputStream 不占用底层系统资源
}
@Override
public InputStream getBody() throws IOException {
//JsonResult {code:500,msg:调用后台服务失败,data:null}
String json = JsonResult.build().code(500).msg("调用后台服务失败").toString();
return new ByteArrayInputStream(json.getBytes("UTF-8"));
}
@Override
public HttpHeaders getHeaders() {
HttpHeaders h = new HttpHeaders();
h.add("Content-Type", "application/json;charset=UTF-8");
return h;
}
};
}
}
Hystrix
- 容错 -- 通过降级来容错
- 调用后台服务失败,执行当前模块的一段降级代码,返回降级结果
- 错误提示
- 缓存数据
- 根据具体业务逻辑,返回任何结果都可以
- 限流 -- 通过熔断来限制后台服务的流量
- 流量过大时,后台服务出现大量错误,会自动触发熔断
- 10秒20次请求(必须首先满足)
- 50%出错,执行了降级
- 半开状态
- 断路器打开后一段时间,会进入半开状态
- 会尝试发送一次客户端调用
调用成功,关闭断路器,恢复正常链路
调用失败,继续保持打开状态
Hystrix数据监控
Hystrix利用 springboot 的 Actuator 工具来暴露自己的监控数据
依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
</dependency>
application.yml
server:
port: 4001
hystrix:
dashboard:
#允许抓取日志的服务器列表
proxy-stream-allow-list: localhost
启动类添加注解:@EnableHystrixDashboard
Actuator
springboot提供的项目监控指标工具,提供了多种监控数据
- 健康状态
- 环境变量、配置参数
- spring mvc 的映射路径
- JVM 虚拟机堆内存镜像
- spring 容器中所有的对象
- .....
1. 添加 actuator 依赖:已经被Zuul集成,添加zuul依赖后无需添加
2. 在网关模块的yml配置暴露的监控数据
#暴露所有监控数据
management:
endpoints:
web:
exposure:
include: "*"
Turbine
从多台服务器抓取 Hystrix 日志,进行聚合,
Hystrix dashboard从Turbine抓取聚合后的日志数据
依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-turbine</artifactId>
</dependency>
application.yml
spring:
application:
name: turbine
server:
port: 5001
eureka:
client:
service-url:
defaultZone: http://eureka1:2001/eureka,http://eureka2:2002/eureka
turbine:
app-config: zuul
cluster-name-expression: new String("default")
turbine.app-config 聚合的服务列表:zuul,a,b,c
turbine.cluster-name-expression 对聚合的日志数据命名:new String("default")
启动类注解:@EnableTurbine