zoukankan      html  css  js  c++  java
  • [Java复习] Spring Cloud

    Spring Cloud Netflix常用组件

    服务注册与发现:Eureka

    服务负载均衡:Ribbon

    服务声明式客户端:Feign

    服务熔断:Hystrix

    服务网关: Zuul

    Eureka:

    Eureka分客户端client和服务端server。各微服务为client,将自己的信息注册到server。

    微服务启动后(默认每隔30秒),client做2件事:1. 拉取最新注册服务信息。2. 向server发送心跳,告诉server自己没有挂。

    如果server在一定时间(默认90秒)内没有收到某个微服务节点的心跳,server将会注销该微服务节点。

    每个Eureka Server同时也是Eureka Client,多个Eureka Server之间通过复制的方式完成服务注册表的同步。

    server存储客户端端口号,IP地址等。

    Q:作为服务中心Eureka比ZooKeeper好在哪里?

    参考《阿里巴巴为什么不用 ZooKeeper 做服务发现?》

    在分布式的CAP理论中,ZK保证CP, Eureka保证AP。向服务中心查询服务时,可以容忍返回的时几分钟之前的注册信息,但不能接收服务挂掉不可用。

    ZK多机房会出现网络孤岛,导致本机房的服务B不能新部署,重启,扩容或缩容。本机房的服务A则不能调用服务B。破坏服务之间本身的可连通性,违反注册中心的原则!

    ZK更适用于分布式协调。

    Eureka优先保证可用性,各节点平等,某节点连接失败,自动切换其他节点,只要一台Eureka Server还在,就能保证服务可用,只不过查到的信息可能不是最新。

    Eureka源码分析:

    图中的这个名字叫做registry的CocurrentHashMap,就是注册表的核心结构。Eureka Server的注册表直接基于纯内存,即在内存里维护了一个数据结构。

    ConcurrentHashMap的key就是服务名称,比如“inventory-service”,就是一个服务名称。value则代表了一个服务的多个服务实例。

    再看作为value的Map:Map<String, Lease<InstanceInfo>>.Map的key就是服务实例的id,value是一个叫做Lease的类,它的泛型是一个叫做InstanceInfo的类。

    InstanceInfo就代表了服务实例的具体信息,比如机器的ip地址、hostname以及端口号。这个Lease,里面则会维护每个服务最近一次发送心跳的时间。

    Eureka Server为了避免同时读写内存数据结构造成的并发冲突问题,还采用了多级缓存机制来进一步提升服务请求的响应速度。

    总结:Eureka通过设置适当的请求频率(拉取注册表30秒间隔,发送心跳30秒间隔),可以保证一个大规模的系统每秒请求Eureka Server的次数在几百次。同时通过纯内存的注册表,保证了所有的请求都可以在内存处理,确保了极高的性能。另外,多级缓存机制,确保了不会针对内存数据结构发生频繁的读写并发冲突操作,进一步提升性能。

    Ribbon:

    Spring Cloud Ribbon是一个基于HTTP和TCP的客户端负载均衡工具,它基于Netflix Ribbon实现。通过Spring Cloud的封装,可以让我们轻松地将面向服务的REST模版请求自动转换成客户端负载均衡的服务调用。

    用法:只需要在RestTemplate的Bean上加上@LoadBalanced注解即可。

    实现原理:Ribbon的负载均衡,主要通过LoadBalancerClient来实现的,而LoadBalancerClient具体交给了ILoadBalancer来处理,ILoadBalancer通过配置IRule、IPing等信息,并向EurekaClient获取注册列表的信息,并默认10秒一次向EurekaClient发送“ping”,进而检查是否更新服务列表,最后,得到注册列表后,ILoadBalancer根据IRule的策略进行负载均衡。IRule有轮询,最小请求数,随机,权重等算法。

    而RestTemplate 被@LoadBalanced注解后,能够用负载均衡,主要是维护了一个被@LoadBalanced注解的RestTemplate列表,并给列表中的RestTemplate添加拦截器,进而交给负载均衡器去处理。

    Feign:

    Feign是一个声明式的伪HttpClient。它使得写Http客户端变得更简单。使用Feign,只需要创建一个接口并注解。

    Feign Client会在底层根据注解,和指定的服务建立连接、构造请求、发起请求、获取响应,解析响应。关键机制时使用动态代理。

    • 首先,如果你对某个接口定义了@FeignClient注解,Feign就会针对这个接口创建一个动态代理
    • 接着你要是调用那个接口,本质就是会调用Feign创建的动态代理,这是核心中的核心

    Feign的动态代理会根据你在接口上的@RequestMapping等注解,来动态构造出你要请求的服务的地址.

    Hystrix:

    用法:引入spring-cloud-starter-netflix-hystrix依赖。

    启动app类上加:@EnableCircuitBreaker。

    具体方法上加:@HystrixCommand(fallbackMethod = "fallbackCreateOrder")

    断路器工作原理:当Hystrix Command请求后端服务失败数量超过一定比例(默认50%),断路器切换到开路状态(OPEN),请求会直接失败。断路器保持在开路一段时间后(默认5s),自动切换到半开路状态(HALF-OPEN),会判断下一次请求的返回情况,如果成功,切回闭路(CLOSED),否则重新切换为开路(OPEN)。

     Fall back:

          降级操作。对于查询操作, 我们可以实现一个fallback方法, 当请求后端服务出现异常的时候, 可以使用fallback方法返回的值. fallback方法的返回值一般是设置的默认值或者来自缓存。

    Zuul:

    Zuul的主要功能是路由和过滤器。

    路由功能是微服务的一部分,比如/api/a映射到a服务,/api/b映射到b服务。zuul实现了负载均衡。

    用法:

    1.dependency引入spring-cloud-starter-zuul

    2.在其入口applicaton类加上注解@EnableZuulProxy,开启zuul

    3. 加上配置文件:

    eureka:
      client:
        serviceUrl:
          defaultZone: http://localhost:8761/eureka/
    server:
      port: 8769
    spring:
      application:
        name: service-zuul
    zuul:
      routes:
        api-a:
          path: /api-a/**
          serviceId: service-a
        api-b:
          path: /api-b/**
          serviceId: service-b

    首先向eureka注册自己,端口为8769,服务名为service-zuul;以/api-a/ 开头的请求都指向service-a;以/api-b/开头的请求都指向service-b。

    Zuul不仅可以路由,还可以做过滤器:

    @Component
    public class MyFilter extends ZuulFilter{
        @Override
        public String filterType() {
            return "pre";
        }
        @Override
        public int filterOrder() {
            return 0;
        }
        @Override
        public boolean shouldFilter() {
            return true;
        }
        @Override
        public Object run() {
         // filter logic ...
        }
    }

      filterType():返回一个字符串代表过滤器的类型

    • pre:路由之前
    • routing:路由之时
    • post: 路由之后
    • error:发送错误调用

      filterOrder():过滤的顺序

      shouldFilter():这里可以写逻辑判断,是否要过滤,true:过滤

      run():过滤器的具体逻辑

  • 相关阅读:
    jdk1.8 LongAdder源码学习
    linux 下 vi 文本编辑如何复制一行粘贴删除一行数据
    远程调试
    本机与远程主机指定端口的网络是否连通
    自定义弹窗
    Windows查看占用端口的进程及其对应的应用程序并关闭之
    超实惠:99元阿里云服务器1核2G内存40G硬盘(SSD)
    Java显式锁学习总结之六:Condition源码分析
    Maven使用国内镜像
    深入理解读写锁—ReadWriteLock源码分析
  • 原文地址:https://www.cnblogs.com/fyql/p/11739147.html
Copyright © 2011-2022 走看看