服务注册和发现

搭建Eureka注册中心服务器

  1. 新建模块
  2. 调整pom.xml
    • 父项目
    • 添加eureka serve依赖
  3. yml配置
    • 关闭自我保护模式
    • 主机名
    • 针对单台服务器,不向自己注册,不从自己拉取
  • yaml配置如下:
    1. server:
    2. port: 2001
    3. spring:
    4. application:
    5. name: eureka-serve
    6. eureka:
    7. server:
    8. enable-self-preservation: false #关闭自我保护模式
    9. instance:
    10. hostname: eureka1 #设置主机名
    11. client:
    12. register-with-eureka: false #不向自己注册
    13. fetch-registry: false #不从自己拉取
  1. 启动类添加注解@EnableEurekaServe触发eureka服务器自动配置

    Eureka四条运行机制

  2. 客户端启动时,会反复连接注册中心尝试注册,知道注册成功为止

  3. 客户端每30秒发送一次心跳数据,表示服务存活,eurwka服务器连续3次收不到一个服务的心跳会由注册列表中删除此服务.
  4. 客户端每30秒拉取一次注册表,刷新本地注册缓存
  5. 自我保护模式,由于网络中断或网络不稳定,15分钟内85%服务器出现心跳异常(每有一次接受不到心跳则算一次心跳异常)自动进入自我保护模式,自我保护模式下的所有注册信息都不删除,网络恢复后自动退出自我保护模式,开发调试期间可以关闭自我保护模式,避免影响调试

    客户端连接Eureka客户端

  6. 添加eureka client依赖

    1. <dependency>
    2. <groupId>org.springframework.cloud</groupId>
    3. <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    4. </dependency>
  7. 修改yml配置;eureka服务端连接地址:http://eureka1:2001/eureka

    1. eureka:
    2. client:
    3. service-url:
    4. defaultZone: http://localhost:2001/eureka

    image.png

    Feign远程调用

  8. 订单服务调用商品服务和用户服务

添加远程调用feign依赖

  1. <dependency>
  2. <groupId>org.springframework.cloud</groupId>
  3. <artifactId>spring-cloud-starter-openfeign</artifactId>
  4. </dependency>
  1. 启动类添加注解@EnableFeignClients,触发feign自动配置
  2. 定义远程调用接口
    • ItemClient
    • UserClient
  3. 修改OrderServiceImpl,实现远程调用

    Feign集成Ribbon实现负载均衡和重试

  4. Feign集成了Ribbon,默认实现了负载均衡和重试

  5. Ribbon远程调用失败可自动发起调用重试
    • 异常
    • 服务器宕机
    • 后台服务器堵塞
  • 重试参数:
    • MaxAutoRetries:单台服务器的重试次数,默认为0
    • MaxAutoRetriesNextServer更换服务器次数,默认为1
    • ReadTime,等待响应的超时时间,默认为1000毫秒
    • OkToRetryOnAllOperations是否对所有类型请求都重试,默认只对GET请求重试
    • ConnectTimeout与后台服务器建立连接的等待超时时间,默认为1000毫秒

      API网关Zuul

  1. 统一的访问入口
  2. 统一的权限校验
  3. 集成Ribbon负载均衡和重试
  4. 集成Hystrix容错和限流

    统一的访问入口

  5. 新建模块

  6. 添加依赖
    • eureka client
    • zuul
    • sp01
  7. yml配置

配置路由转发规则

  1. # 服务id设置为访问子路径是默认规则
  2. # zuul根据注册表的注册信息完成自动配置,最好手动配置,防止注册表不全
  3. zuul:
  4. routes:
  5. # 其中**包含深层路径 *只包含一层路径
  6. item-service: /item-service/**
  7. user-service: /user-service/**
  8. order-service: /order-service/**
  1. 启动类添加@EnableZuulProxy注解

    统一权限校验

    http://localhost:3001/item-service/123—-没有登陆不可访问商品服务接口
    http://localhost:3001/item-service?token=12345 已经登陆可以访问

  2. 新建ZuulFilter类的子类,继承ZuulFilter

  3. 按Zuul的规则实现
  4. 添加@commpont注解

zuul的自动配置类可以在spring容器中自动发现过滤器实例,完成自动配置

Zuul集成Ribbon

  • zuul集成ribbon默认启用了负载均衡
  • 默认没有启用重试
    • 在入口位置进行重试,会造成后台大面积服务压力翻倍,可能造成系统故障传播或服务雪崩

      启用Zuul重试(不推荐)

  1. 添加spring retry依赖
  2. 修改yml配置,将zuul.retryable=true
  3. 配置重试参数

    Zuul集成Hystrix

    Hystrix是容错和限流工具,与阿里Sentinel作用相同
  • 容错-降级

调用后台服务出错(异常,堵塞,服务崩溃),可以执行当前服务的一段代码,直接向客户端返回降级结果
可返回一下两种结果:

  • 错误提示
  • 缓存结果
  • 根据业务逻辑,返回任意结果

    添加Hystrix降级

  • Zuul默认启用Hystrix
  • 实现FallbackProvider,按zuul的规则实现接口的方法
  • 添加@component

将商品服务降级

  1. package cn.tedu.sp06.fallback;
  2. import cn.tedu.web.util.JsonResult;
  3. import org.springframework.cloud.netflix.zuul.filters.route.FallbackProvider;
  4. import org.springframework.http.HttpHeaders;
  5. import org.springframework.http.HttpStatus;
  6. import org.springframework.http.client.ClientHttpResponse;
  7. import org.springframework.stereotype.Component;
  8. import java.io.ByteArrayInputStream;
  9. import java.io.IOException;
  10. import java.io.InputStream;
  11. import java.nio.charset.StandardCharsets;
  12. /**
  13. * @Author: 一拳超人
  14. * @Date: 2021/10/20 9:50
  15. */
  16. @Component
  17. public class ItemFallback implements FallbackProvider {
  18. /**
  19. * 设置当前降级类,表示调用哪个后台服务会调用当前降级类
  20. * "item-service" 只针对商品降级
  21. * *和null 表示对所有服务都降级
  22. */
  23. @Override
  24. public String getRoute() {
  25. return "item-service";
  26. }
  27. /**
  28. * 设置降级响应,返回至客户端
  29. */
  30. @Override
  31. public ClientHttpResponse fallbackResponse(String route, Throwable cause) {
  32. return new ClientHttpResponse() {
  33. @Override
  34. public HttpStatus getStatusCode() throws IOException {
  35. return HttpStatus.INTERNAL_SERVER_ERROR;
  36. }
  37. @Override
  38. public int getRawStatusCode() throws IOException {
  39. return HttpStatus.INTERNAL_SERVER_ERROR.value();
  40. }
  41. @Override
  42. public String getStatusText() throws IOException {
  43. return HttpStatus.INTERNAL_SERVER_ERROR.getReasonPhrase();
  44. }
  45. /**
  46. * 用于关闭下面方法中的流
  47. * ByteArrayInputStream为内存数组中的流,不占用底层资源不需要关闭
  48. */
  49. @Override
  50. public void close() {
  51. }
  52. @Override
  53. public InputStream getBody() throws IOException {
  54. String json = JsonResult.err().code(500).msg("你tm能不能不访问").toString();
  55. return new ByteArrayInputStream(json.getBytes(StandardCharsets.UTF_8));
  56. }
  57. @Override
  58. public HttpHeaders getHeaders() {
  59. HttpHeaders httpHeaders = new HttpHeaders();
  60. httpHeaders.add("Content-Type", "application/json;charset=UTF-8");
  61. return httpHeaders;
  62. }
  63. };
  64. }
  65. }

将订单服务降级

  1. package cn.tedu.sp06.fallback;
  2. import cn.tedu.web.util.JsonResult;
  3. import org.springframework.cloud.netflix.zuul.filters.route.FallbackProvider;
  4. import org.springframework.http.HttpHeaders;
  5. import org.springframework.http.HttpStatus;
  6. import org.springframework.http.client.ClientHttpResponse;
  7. import org.springframework.stereotype.Component;
  8. import java.io.ByteArrayInputStream;
  9. import java.io.IOException;
  10. import java.io.InputStream;
  11. import java.nio.charset.StandardCharsets;
  12. /**
  13. * @Author: 一拳超人
  14. * @Date: 2021/10/20 10:32
  15. */
  16. @Component
  17. public class OrderFallback implements FallbackProvider {
  18. @Override
  19. public String getRoute() {
  20. return "order-service";
  21. }
  22. /**
  23. * 设置降级响应,返回至客户端
  24. */
  25. @Override
  26. public ClientHttpResponse fallbackResponse(String route, Throwable cause) {
  27. return new ClientHttpResponse() {
  28. @Override
  29. public HttpStatus getStatusCode() throws IOException {
  30. return HttpStatus.INTERNAL_SERVER_ERROR;
  31. }
  32. @Override
  33. public int getRawStatusCode() throws IOException {
  34. return HttpStatus.INTERNAL_SERVER_ERROR.value();
  35. }
  36. @Override
  37. public String getStatusText() throws IOException {
  38. return HttpStatus.INTERNAL_SERVER_ERROR.getReasonPhrase();
  39. }
  40. /**
  41. * 用于关闭下面方法中的流
  42. * ByteArrayInputStream为内存数组中的流,不占用底层资源不需要关闭
  43. */
  44. @Override
  45. public void close() {
  46. }
  47. @Override
  48. public InputStream getBody() throws IOException {
  49. String json = JsonResult.err().code(500).msg("你tm能不能不访问").toString();
  50. return new ByteArrayInputStream(json.getBytes(StandardCharsets.UTF_8));
  51. }
  52. @Override
  53. public HttpHeaders getHeaders() {
  54. HttpHeaders httpHeaders = new HttpHeaders();
  55. httpHeaders.add("Content-Type", "application/json;charset=UTF-8");
  56. return httpHeaders;
  57. }
  58. };
  59. }
  60. }

Hystrix限流-熔断

  • 当流量过大,造成后台服务故障,可以断开链路,限制后台服务的访问流量,等待后台服务恢复
  • 断路器打开条件
    • 10秒20次请求(默认,必须首先满足)
    • 50%的请求出错,执行降级代码
  • 半开状态

    • 断路器打开一段时间后进入半开状态
    • 半开状态会尝试发送一次客户端调用,成功关闭断路器,恢复正常,失败继续保持断路器打开状态

      Hystrix dashboard

      Hystrix数据监控仪表盘
      Hystrix日志通过Actuator工具暴露出来

      Actuator

      Actuator为Spring Boot提供的一个项目指标工具,可以通过Actuator可以获取项目的各种日志数据\
      可以获取以下数据:
  • 健康状态

  • spring容器中的所有对象
  • spring mvc映射的所有路径
  • jvm堆内存对象

    Actuator使用

  1. 添加actuator依赖
  2. yml配置,暴露监控日志

    1. #暴露所有日志
    2. m.e.w.e.i="*"
    3. management:
    4. endpoint:
    5. health:
    6. show-components: always
    7. endpoints:
    8. web:
    9. exposure:
    10. include: "*"
    11. m.e.w.e.i=health #暴露健康状态日志
    12. m.e.w.e.i=health,beans,mappings,hystrix.stream #暴露多种日志
  3. 查看日志 http://localhost:3001/actuator

    搭建Hystrix dashboard

  4. 新建模块

  5. 添加依赖

    1. <dependency>
    2. <groupId>org.springframework.cloud</groupId>
    3. <artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
    4. </dependency>
  6. yml配置

    1. #允许抓取服务器列表
    2. hystrix:
    3. dashboard:
    4. proxy-stream-allow-list:
    5. - localhost
  7. 启动类添加注解@EnableHystrixDashboard

    Turbine

    局和多态服务器日志数据,提供给仪表盘显示

  8. 新建模块

  9. 添加依赖
    • eureka client
    • turbine
  10. yml配置

    1. #需要聚合的服务
    2. #命名聚合后的日志数据
  11. 启动类注解@EnableTurbine

  12. 合并的日志地址http://localhost:5001/turbine.stream