SpringCloud中Eureka、feign、ribbon、Zuul、Hystrix的应用实践

文章目录

    • Eureka的搭建过程
        • 1.新建spring模块
        • 2.修改pom.xml,添加eureka server
        • 3.yml配置
        • 4.启动类注解:@EnableEurekaService触发eureka server的自动配置
    • Eureka的四条运行机制
        • 1. 注册
        • 2. 拉取
        • 3. 心跳
        • 4. 自我保护模式(特殊情况下)
    • Eureka客户端的配置
        • 1. 修改host文件(位置:C:\Windows\System32\drivers\etc)
        • 2. 修改2,3,4三个模块,添加 Eureka client依赖
        • 3. 修改2,3,4三个模块的yml模块,添加 Eureka的IP地址
    • (重要)java -jar java文件 --server port:8001与yml中的server port重复了,生效的是命令行的server port
    • Eureka高可用配置
        • 1.新建并修改yml文件
        • 2.然后在运行,打开Edit Configurations设置启动配置
        • 修改2,3,4,连接两台eureka服务器
    • 给项目设置远程调用feign
        • 1.给项目添加feign依赖
        • 2.启动类添加注解@EnableFeignClients(触发feign的自动配置,自动扫描远程接口,自动创建动态代理对象)
        • 3.创建一个接口,并在类上加上注解@FeignClient
        • 4.在实现类注入并使用即可
    • Feign集成Ribbon
        • Ribbon重试
    • Zuul - API网关
        • 功能:
      • 统一的调用入口配置:
        • Zuul统一权限校验
    • Zuul集成Ribbon
    • Hystrix(Zuul默认启动了Hystrix)
      • 容错和限流工具
        • 添加降级的配置
    • Hystrix数据监控
      • Actuator
      • Actuator添加配置

Eureka的搭建过程

1.新建spring模块

2.修改pom.xml,添加eureka server

<dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </dependency>

3.yml配置

  禁用自我保护模式
  设置主机名:eureka1
  针对单台服务器,buxiang自己注册,不从自己拉取注册表

spring:
  application:
    name: eureka-server

#2001  3001  4001  5001 6001
server:
  port: 2001
eureka:
  server:
    enable-self-preservation: false #禁用自我保护模式
  instance:
    hostname: eureka1
  client:
    #针对单台服务器,不向自己注册,不从自己拉取注册表
    register-with-eureka: false
    fetch-registry: false

4.启动类注解:@EnableEurekaService触发eureka server的自动配置

Eureka的四条运行机制

1. 注册

客户端一次次的反复连接注册中心进行注册,直到注册成功为止

2. 拉取

客户端每30秒拉取一个注册表,刷新注册表

3. 心跳

客户端每30秒发送一次心跳包,如果服务器端连续三次收不到一个服务的心跳,会删除它的注册信息

4. 自我保护模式(特殊情况下)

由于网络故障,15分钟内,85%服务器出现心跳异常,会自动进入自我保护模式(保护所有注册信息都不删除),网络恢复后,自动退出保护模式
【开发调试时,要把保护模式关闭,避免引起测试】

Eureka客户端的配置

1. 修改host文件(位置:C:\Windows\System32\drivers\etc)

127.0.0.1          eureka1
127.0.0.1          eureka2  

2. 修改2,3,4三个模块,添加 Eureka client依赖

  <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
  </dependency>

3. 修改2,3,4三个模块的yml模块,添加 Eureka的IP地址

eureka:
  client:
    service-url: 
      #默认地点,如果使用的是云服务,可以通过云服务商购买不同地点的注册中心服务器
      #自己搭建的注册中心只能使用defaultZone
      defaultZone: http://eureka1:2001/eureka

(重要)java -jar java文件 --server port:8001与yml中的server port重复了,生效的是命令行的server port

Eureka高可用配置

1.新建并修改yml文件

新建application-eureka1.yml,并修改yml文件

eureka:
  instance:
    hostname: eureka1
  client:
    register-with-eureka: true
    fetch-registry: true
    service-url:
      defaultZone: http://eureka2:2002/eureka
server:
  port: 2001

新建application-eureka2.yml,并修改yml文件

eureka:
  instance:
    hostname: eureka2
  client:
    register-with-eureka: true
    fetch-registry: true
    service-url:
      defaultZone: http://eureka1:2001/eureka
server:
  port: 2002

2.然后在运行,打开Edit Configurations设置启动配置

先改名xxxx-端口号,然后在Environment---->Program arguments写入:

--spring.profiles.active=eureka1

先改名xxxx-端口号,然后在Environment---->Program arguments写入:

--spring.profiles.active=eureka2

修改2,3,4,连接两台eureka服务器

02YML文件的样子:

#向注册中心注册的名字
spring:
  application:
    name: item-service

#item 8001,  user 8101,  order 8201
server:
  port: 8001
eureka:
  client:
    service-url:
      #默认地点,如果使用的是云服务,可以通过云服务商购买不同地点的注册中心服务器
      #自己搭建的注册中心只能使用defaultZone
      defaultZone: http://eureka1:2001/eureka,http://eureka2:2002/eureka

03YML文件的样子:

spring:
  application:
    name: user-service
server:
  port: 8101

#自定义配置属性
#用户的demo数据
#"[{7},{8},{9}]"
sp:
  user-service:
    users: "[{\"id\":7, \"username\":\"abc\",\"password\":\"123\"},
             {\"id\":8, \"username\":\"def\",\"password\":\"456\"},
             {\"id\":9, \"username\":\"ghi\",\"password\":\"789\"}]"
eureka:
  client:
    service-url:
      #默认地点,如果使用的是云服务,可以通过云服务商购买不同地点的注册中心服务器
      #自己搭建的注册中心只能使用defaultZone
      defaultZone: http://eureka1:2001/eureka,http://eureka2:2002/eureka

04YML文件的样子:

spring:
  application:
    name: order-service
server:
  port: 8201

#eureka的注册与发现
eureka:
  client:
    service-url:
      #默认地点,如果使用的是云服务,可以通过云服务商购买不同地点的注册中心服务器
      #自己搭建的注册中心只能使用defaultZone
      defaultZone: http://eureka1:2001/eureka,http://eureka2:2002/eureka

给项目设置远程调用feign

1.给项目添加feign依赖

2.启动类添加注解@EnableFeignClients(触发feign的自动配置,自动扫描远程接口,自动创建动态代理对象)

3.创建一个接口,并在类上加上注解@FeignClient

/*
* 通过注解配置:
* 调用哪个服务
* 调用服务的哪个路径
* 向这个路径提交什么参数
* */
/**
 * 通过name发现服务器的地址
 * */
@FeignClient(name = "item-service")
public interface ItemClient {
    @GetMapping("/{orderId}")
    JsonResult<List<Item>> getItem(@PathVariable("orderId") String orderId);
    @PostMapping("/decreaseNumber")
    JsonResult<?> getDecreaseNumber(@RequestBody List<Item> Item);
}

4.在实现类注入并使用即可

    @Autowired
    private UserClient userClient;
    @Autowired
    private ItemClient itemClient;

Feign集成Ribbon

   负载均衡——默认启用
   重  试——默认启用

Ribbon重试

调用后台服务失败(异常、服务器崩溃、超时),可以自动发起重试调用
重试参数:
   ribbon.MaxAutoRetries - 单台服务器的重试次数,默认0
   ribbon.MaxAutoRetriesNextServer - 更换服务器的次数,默认1
   (公式为x+1*y+1)
   ribbon.ReadTimeout - 响应的超时时间,默认1000ms
   ribbon.ConnectTimeout - 与后台服务器建立连接等待超时时间,默认1000ms
   ribbon.OkToRetryOnAllOperations - 是否对所有类型请求都进行重试,默认只对GET请求重试

 ribbon:
  MaxAutoRetries: 1
  MaxAutoRetriesNextServer: 2

Zuul - API网关

功能:

   统一的调用入口
   统一的权限校验
   集成Ribbon
   集成Hystrix

统一的调用入口配置:

  1. 先建Spring模块
  2. pom.xml添加依赖:zuul、eureka client
  3. yml配置路由规则
spring:
  application:
    name: zuul
#2001,3001,4001,5001,6001
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/**
  1. 启动类添加注解@EnableZuulProxy

Zuul统一权限校验

继承Zuul的过滤器,在过滤器中判断用户权限
实现步骤:
  1.新建过滤器:AccessFilter,继承ZuulFilter
  2.按照规则实现过滤器
  添加注解:@Component
zuul的自动配置,会从Spring容器自动发现过滤器实例,完成自动配置
代码如下:

package cn.tedu.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() {
        /**
         * 在默认的第五个过滤器中,向上下文对象放入了serviceId
         * 后面过滤器中才能访问这个数据
         * */
        log.info("Zuul自动配置过滤器的顺序号");
        return 6;
    }
    //针对当前请求进行判断,是否要执行过滤代码
    @Override
    public boolean shouldFilter() {
        //如果客户端调用商品,要判断权限
        //否则调用用户或订单,不判断权限
        //第一步:获得当前请求的上下文对象
        RequestContext context = RequestContext.getCurrentContext();
        //第二步:从上下文对象取出正在访问的serviceId
        String o = (String) context.get(FilterConstants.SERVICE_ID_KEY);
        //判断serviceId是否是“item-Service”
        //equalsIgnoreCase忽略大小写进行比较
        return "item-Service".equalsIgnoreCase(o);
    }
    //过滤代码
    @Override
    public Object run() throws ZuulException {
        //第一步:获得当前请求的上下文对象
        RequestContext context = RequestContext.getCurrentContext();
        //第二步:从上下文对象取出request
        HttpServletRequest request = context.getRequest();
        //第三步:用request接收token参数
        String token = request.getParameter("token");
        //第四步:如果token不存在
        if (StringUtils.isBlank(token)){
            //第五步:阻止继续访问
            context.setSendZuulResponse(false);
            //第六步:直接返回响应
            String json = JsonResult.build().code(500).msg("没有登录").toString();
            //响应数据的协议头
            context.addZuulResponseHeader("Content-Type", "application/json;charset=UTF-8");
            //响应体
            context.setResponseBody(json);
        }
        return null;//当前版本没有使用这个返回值,设置什么数据都可以
    }
}

Zuul集成Ribbon

  1. 默认已经启用ribbon的负载均衡
  2. 默认不启用ribbon的重试
      在网关重试,可能造成后台服务大面积出现压力翻倍
      重试功能应尽量往后放
  3. 启用重试:
      (1)添加spring-retry依赖
 <dependency>
        <groupId>org.springframework.retry</groupId>
        <artifactId>spring-retry</artifactId>
    </dependency>

  (2)yml配置启用重试:zuul.retryable=true

spring:
  application:
    name: zuul
#2001,3001,4001,5001,6001
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/**
  retryable: true

#针对所有服务都有效
ribbon:
  MaxAutoRetries: 1

#针对商品单独配置重试服务
item-service:
  ribbon:
    MaxAutoRetries: 0

Hystrix(Zuul默认启动了Hystrix)

容错和限流工具

  1. 容错 – 通过降级来容错
      调用后台服务失败,执行当前模块的一段降级代码,返回降级结果
        ■错误提示
        ■缓存数据
        ■根据具体业务逻辑,返回任何结果皆可
  2. 限流 – 通过熔断来限制后台服务的流量
        ■流量过大时,后台服务出现大量错误,会自动触发熔断
        ■10秒20次请求(秒数和次数都可以设置,必须首先满足)
        ■50%出错,执行降级
        ■半开状态
          断路器打开一段时间,会进行半开状态
          会尝试发送一次客户端调用
          调用成功,关闭断路器,恢复正常链路
          调用失败,继续保持打开状态

添加降级的配置

  1. 添加降级类,实现FallbackProvider接口
  2. 添加@Component
      zuul的自动配置,会从Spring容器自动发现降级类实例,完成自动配置
    代码如下:
package cn.tedu.fb;

import cn.tedu.web.util.JsonResult;
import com.netflix.appinfo.RefreshableAmazonInfoProvider;
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 {
                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 null;
            }
        };
    }
}
  1. 复制一下,把类名改了并把服务名也改成对应的服务

Hystrix数据监控

Hystrix利用使用SpringBoot的Actuator工具来暴露自己的监控数据

Actuator

SpringBoot提供的项目监控指标工具,提供了多种监控数据
1.健康状态
2.环境变量、配置参数
3.Spring MVC的映射路径
4.JVM虚拟机堆内存镜像
5.Spring容器中的所有对象

Actuator添加配置

1.添加Actuator依赖
2.yml配置暴露的监控数据

你可能感兴趣的:(Spring,Cloud,eureka,spring,cloud,spring)