Eureka入门案例
原理图
使用
创建子工程eureka
添加eureka依赖
<dependencies>
<!-- Eureka服务端 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
</dependencies>
配置yml
server:
port: 10086
spring:
application:
name: eureka-server # 应用名称,会在Eureka中显示
eureka:
client:
service-url:
defaultZone: http://127.0.0.1:10086/eureka
在启动类中添加注解
配置eureka的client
在需要使用eureka的服务提供者或服务消费者中添加依赖
配置yml(通过查看源码可以得知,url以map的形式存储,key默认为defaultZone),注意url最后一定要加eureka
server:
port: 8080
spring:
application:
name: consumer-server
eureka:
client:
service-url:
defaultZone: http://127.0.0.1:10086/eureka
在启动类中添加注解
启动服务
eureka详细使用
server:
port: 10086 # 端口
spring:
application:
name: eureka-server # 应用名称,会在Eureka中显示
eureka:
client:
register-with-eureka: false # 是否注册自己的信息到EurekaServer,默认是true
fetch-registry: false # 是否拉取其它服务的信息,默认是true
service-url: # EurekaServer的地址,现在是自己的地址,如果是集群,需要加上其它Server的地址。
defaultZone: http://127.0.0.1:${server.port}/eureka
高可用
多个eureka相互注册形成集群
server:
port: 10086 # 端口
spring:
application:
name: eureka-server # 应用名称,会在Eureka中显示
eureka:
client:
service-url: # 配置其他Eureka服务的地址,而不是自己,比如10087
defaultZone: http://127.0.0.1:10087/eureka
可以向多个eureka注册
服务注册发现
- 心跳周期,在开发时可以将数据调小
eureka:
instance:
lease-expiration-duration-in-seconds: 90 #服务失效时间,默认值90秒
lease-renewal-interval-in-seconds: 30 #服务续约(renew)的间隔,默认为30秒
- 拉取周期
eureka:
client:
registry-fetch-interval-seconds: 5 #默认为30,在开发时可以相应调小
- 失效剔除
有些时候,我们的服务提供方并不一定会正常下线,可能因为内存溢出、网络故障等原因导致服务无法正常工作。Eureka Server需要将这样的服务剔除出服务列表。因此它会开启一个定时任务,每隔60秒对所有失效的服务(超过90秒未响应)进行剔除。
- 自我保护
我们关停一个服务,就会在Eureka面板看到一条警告:
这是触发了Eureka的自我保护机制。当一个服务未按时进行心跳续约时,Eureka会统计最近15分钟心跳失败的服务实例的比例是否超过了85%。在生产环境下,因为网络延迟等原因,心跳失败实例的比例很有可能超标,但是此时就把服务剔除列表并不妥当,因为服务可能没有宕机。Eureka就会把当前实例的注册信息保护起来,不予剔除。生产环境下这很有效,保证了大多数服务依然可用。
但是这给我们的开发带来了麻烦, 因此开发阶段我们都会关闭自我保护模式:
eureka:
server:
enable-self-preservation: false # 关闭自我保护模式(缺省为打开)
eviction-interval-timer-in-ms: 1000 # 扫描失效服务的间隔时间,开发时可以调小(缺省为60*1000ms)
- 负载均衡ribbon
添加依赖
添加注解
修改调用方式,直接使用服务名称调用
方法二
配置,默认为轮循
user-service:
ribbon:
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule #随机
Hystrix
雪崩问题
解决方法
- 线程隔离,服务降级
- 服务熔断
线程隔离
各个功能使用不同的线程池,每个线程池一定的线程数,及时否个服务出现问题也不会出现占用其他线程池的资源。
服务降级实现
在消费者中添加依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
添加注解
修改userservice
- 单个配置
- 在类中统一配置
定义超时时长(默认为1s)
该nama没有提示,可以去对应的依赖包中找
- 全局配置(yml)
同样没有提示
服务熔断
原理类似于家庭电路保险丝
Feign
远程调用
引入依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
添加注解
创建接口
feign的熔断与spring的不同
配置yml
feign:
hystrix:
enabled: true # 开启Feign的熔断功能
user-service:
ribbon:
ConnectTimeout: 250 # 连接超时时间(ms)
ReadTimeout: 1000 # 通信超时时间(ms)
OkToRetryOnAllOperations: true # 是否对所有操作重试
MaxAutoRetriesNextServer: 1 # 同一服务不同实例的重试次数
MaxAutoRetries: 1 # 同一实例的重试次数
创建UserClient的实现类
有几个方法就要写几个熔断逻辑
配置熔断的类
请求压缩
Zuul网关
配置xml
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
</dependencies>
路由
- 面向服务的路由
直接填写url将不会经过负载均衡等,需要使用eureka的服务。
添加依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
配置
简化配置:既然route名字随意,那么可以叫做user-service,而服务id是唯一的,就可以将他们都省略,只做如下配置
既然用都是服务id那么就可以自动配置,zuul会对路径做出上面这样的自动配置。若不想使用自动配置,可以自己定义。若微服务不想对外暴露,可使用如下配置
路由前缀
全局前缀
**权限控制 **
- 自定义拦截器
定义LoginFIlter类继承ZuulFIlterer类(注意要加注解)
@Component
public class LoginFilter extends ZuulFilter {
@Override
public String filterType() {
return FilterConstants.PRE_TYPE;
}
@Override
public int filterOrder() {
return FilterConstants.FORM_BODY_WRAPPER_FILTER_ORDER -1;
}
@Override
public boolean shouldFilter() {
return true;
}
@Override
public Object run() throws ZuulException {
//获取上下文
RequestContext ctx = RequestContext.getCurrentContext();
//获取request
HttpServletRequest request = ctx.getRequest();
//获取参数,判断是否登录
String token = request.getParameter("access-token");
//判断是存在
if (StringUtils.isBlank(token)){
//不存在,未登录,拦截
ctx.setSendZuulResponse(false);
//返回状态码403 禁用
ctx.setResponseStatusCode(HttpStatus.FORBIDDEN.value());
}
return null;
}
}
找实现ctrl alt b
ctrl h
ctrl + n 查找类