微服务日志从0到1-----第二章引出Eureka And Ribbon

微服务日志从0到1-----第二章引出Eureka And Ribbon

01.Eureka的简介

Eureka是Netflix(奈飞/网飞)开发的服务发现框架,本身是一个基于REST的服务,主要用于定位运行在AWS域中的中间层服务,以达到负载均衡和中间层服务故障转移的目的。SpringCloud将它集成在其子项目spring-cloud-netflix中,以实现SpringCloud的服务发现功能。

1.Eureka包含两个组件:Eureka Server和Eureka Client。
	Eureka Server提供服务注册服务,各个节点启动后,会在Eureka Server中进行注册,这样EurekaServer中的服务注册表中将会存储所有可用服务节点的信息,服务节点的信息可以在界面中直观的看到。
	Eureka Client是一个java客户端,用于简化与Eureka Server的交互,客户端同时也就是一个内置的、使用轮询负载算法的负载均衡器。

2.在应用启动后,Eureka Client会向Eureka Server发送心跳,默认周期为30秒,如果Eureka Server在多个心跳周期内没有接收到某个节点的心跳,Eureka Server将会从服务注册表中把这个服务节点移除(默认90秒)。

3.Eureka Server之间通过复制的方式完成数据的同步,Eureka还提供了客户端缓存机制,即使所有的Eureka Server都挂掉,客户端依然可以利用缓存中的信息消费其他服务的API。综上,Eureka通过心跳检查、客户端缓存等机制,确保了系统的高可用性、灵活性和可伸缩性。

02.什么是服务发现

在微服务中有服务提供者服务消费者服务发现三个组件,三者之间的关系大致如下:

01.各个微服务在启动时时,将自己的网络地址等信息注册到服务发现组件上(eureka,zookeeper,Consul,spring cloud alibaba的nacos),服务发现组件会存储这些信息。
02.服务消费者会从服务发现组件查询服务提供者的网络地址,然后将服务地址列表缓存到本地,然后根据服务名负载均衡调用服务提供者的接口。
03.各个微服务与服务发现组件使用一定的机制来维持心跳,服务发现组件若发现有服务没有提供心跳,那么服务发现组件会将该服务剔除。
04.微服务网络地址发生变更(例如实例增减或者IP端口发生变化等),会重新注册到服务发现组件上,使用这种方式,可以避免因网络变化导致服务之间的通讯停止,服务消费者也无须人工的修改网络地址。

03.服务注册

01.搭建一个eureka服务

搭建一个eureka服务需要一个客户端 和一个 服务端(可以是一个项目,因为服务端也是一个微服务,也需要以客户端的身份注册进eureka,个人猜想之所以这样可能和eureka服务端集群有关系)

02.主要依赖

<!--服务端-->
<dependencies>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-netflix-eureka-server</artifactId>
        <version>3.1.3</version>
    </dependency>
</dependencies>

<!--客户端-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    <version>3.1.1</version>
</dependency>

03.具体操作

​ 01.首先需要创建一个服务端的模块

image-20220629150217801

​ 02.导入服务端依赖

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

​ 03.配置依赖

​ 01.在Application中开启Eureka

image-20220629150344778

​ 02.在配置文件中配置

spring:
  application:
  	//服务名称(必要)
    name: eureka-service
server:
	//服务端口
  port: 10086
//之所以给服务端也配置一个客户端连接是因为 服务端也是一个微服务,也需要连接上eureka注册进去,如果是集群类型的则使用 “,” 分开
eureka:
  client:
    service-url:
      defaultZone: http://127.0.0.1:10086/eureka

​ 04.客户端配置

​ 01.创建一个需要注册进eureka的服务

​ 02.导入依赖

<!--客户端-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    <version>3.1.1</version>
</dependency>

​ 03.配置文件

spring:
  application:
  	//服务名称(必要)
    name: user-service
server:
	//服务端口
  port: 8080
eureka:
  client:
    service-url:
      defaultZone: http://127.0.0.1:10086/eureka

​ 04.开启客户端

image-20220629151448619

至此一个Eureka就搭建完成了,访问地址 http://127.0.0.1:10086/ 即可

image-20220629150921938

04.服务发现(拉取)

01.使用eureka服务

服务拉取是基于服务器名称获取服务列表,然后在对服务列表做负载均衡

02.提出需求

在上一个项目中所,使用了RestTemplate实现了获取订单的同时获取对应的用户信息,但是有几个问题就是访问的路径是无法改变的,然后如果是服务集群的话服务做到负载均衡访问,需求就是使用eureka来实现负载均衡,并且不关注服务路径只关注服务名称来通过RestTemplate来调用用户服务获取信息

03.实现需求

​ 01.创建一个服务端 eureka-service

代码地址: https://github.com/codeXYW/Microservices/tree/main/eureka/eureka-service

​ 02.给客户端添加 eureka 依赖

代码地址: https://github.com/codeXYW/Microservices/tree/main/eureka

​ 03.在启动类上添加 @EnableEurekaClient 注解

image-20220629191820890

​ 04.给RestTemplate 添加负载均衡

image-20220629192057021

​ 05.重新编写service层的逻辑代码

image-20220629192326331

05.拓展知识点 实现集群效果

通过 idea 的多实例启动,来查看 Eureka 的集群效果。

image-20220629193044337

image-20220629193338713

image-20220629193419865

04.Ribbon是什么

在使用Eureka的时候有几个问题,Rest_template 请求是怎么通过服务名称访问到真实地址,又是怎么实现负载均衡的,又什么样的一种负载均衡策略

在了解这些前,首先可以了解一下使用了eureka后的工作流程

image-20220629194218413

01.源码分析

首先需要找到一个叫做负载均衡拦截器的类(LoadBalancerInterceptor) ,这个类主要实现了ClientHttpRequestInterceptor接口,而这个接口的作用如下

image-20220629215019057

看LoadBalancerInterceptor里面的核心代码

@Override
public ClientHttpResponse intercept(final HttpRequest request, final byte[] body,
      final ClientHttpRequestExecution execution) throws IOException {
    
    //获取请求地址
   final URI originalUri = request.getURI();
    //取出服务名称
   String serviceName = originalUri.getHost(); 
    //断言服务名称不为空
   Assert.state(serviceName != null,
         "Request URI does not contain a valid hostname: " + originalUri);
    //使用负载均衡客户端来执行请求
   return this.loadBalancer.execute(serviceName,
         this.requestFactory.createRequest(request, body, execution));
}

继续跟进.execute方法

//.execute方法的源代码
public <T> T execute(String serviceId, LoadBalancerRequest<T> request, Object hint)
    throws IOException {
    ILoadBalancer loadBalancer = getLoadBalancer(serviceId);
    Server server = getServer(loadBalancer, hint);
    if (server == null) {
        throw new IllegalStateException("No instances available for " + serviceId);
    }
    RibbonServer ribbonServer = new RibbonServer(serviceId, server,
                                                 isSecure(server, serviceId),
                                                 serverIntrospector(serviceId).getMetadata(server));

    return execute(serviceId, ribbonServer, request);
}
  • getLoadBalancer(serviceId):根据服务id获取 ILoadBalancer,而 ILoadBalancer 会拿着服务 id 去 eureka 中获取服务列表。
  • getServer(loadBalancer):利用内置的负载均衡算法,从服务列表中选择一个。

跟进一下getServer

image-20220629221804608

继续跟进

image-20220629221920510

继续

image-20220629222350673

image-20220629222245437

最后传进来的key是default也就是采用默认策略,所以只要查看一下rule的默认值就OK

image-20220629222559618

可以看出来默认采用的是轮询的方式来进行负载均衡,当然处理这个default的策略还可以自定义策略

image-20220629222702262

02.流程总结

SpringCloud Ribbon 底层采用了一个拦截器,拦截了 RestTemplate 发出的请求,对地址做了修改。

基本流程如下:

  • 拦截我们的 RestTemplate 请求 http://userservice/user/1
  • RibbonLoadBalancerClient 会从请求url中获取服务名称,也就是 user-service
  • DynamicServerListLoadBalancer 根据 user-service 到 eureka 拉取服务列表
  • eureka 返回服务列表
  • IRule 利用内置负载均衡规则,从列表中选择一个,例如 localhost:8081
  • RibbonLoadBalancerClient 修改请求地址,用 localhost:8081 替代 userservice,得到 http://localhost:8081/user/1,发起真实请求

img

03.负载均衡策略

负载均衡的规则都定义在 IRule 接口中,而 IRule 有很多不同的实现类:

img

在上面的源码分析里面,说过Rule是默认是轮询的策略,其实并不然,并不是纯粹的轮询策略,是在轮询的基础上进行一些加强,默认是采用一个叫做ZoneAvoidanceRule而ZoneAvoidanceRule extends PredicateBasedRule extends ClientConfigEnabledRoundRobinRule,可以看一下ClientConfigEnabledRoundRobinRule的说明

image-20220629224539448

所以在流程分析的时候,才会说默认采用的是轮询策略,而除了轮询策略外还有其他的不同策略,规则如下

内置负载均衡规则类规则描述
RoundRobinRule简单轮询服务列表来选择服务器。它是Ribbon默认的负载均衡规则。
AvailabilityFilteringRule对以下两种服务器进行忽略:(1)在默认情况下,这台服务器如果3次连接失败,这台服务器就会被设置为“短路”状态。短路状态将持续30秒,如果再次连接失败,短路的持续时间就会几何级地增加。 (2)并发数过高的服务器。如果一个服务器的并发连接数过高,配置了AvailabilityFilteringRule 规则的客户端也会将其忽略。并发连接数的上限,可以由客户端设置。
WeightedResponseTimeRule为每一个服务器赋予一个权重值。服务器响应时间越长,这个服务器的权重就越小。这个规则会随机选择服务器,这个权重值会影响服务器的选择。
ZoneAvoidanceRule以区域可用的服务器为基础进行服务器的选择。使用Zone对服务器进行分类,这个Zone可以理解为一个机房、一个机架等。而后再对Zone内的多个服务做轮询。
BestAvailableRule忽略那些短路的服务器,并选择并发数较低的服务器。
RandomRule随机选择一个可用的服务器。
RetryRule重试机制的选择逻辑

默认的实现就是 ZoneAvoidanceRule是一种轮询方案

04.自定义策略

所有的负载均衡策略是通过继承实现了IRule的AbstractLoadBalancerRule来实现的,如果需要自定义一个规则(默认不做修改)

方案01:可以通过自定义实现IRule来修改负载均衡

@Configuration
static class  MyIRule{
    @Bean
    public IRule iRule(){
        return new RoundRobinRule();
    }
}

方案02:配置文件方式:application.yml 中,添加新的配置也可以修改规则

user-service: # 给需要调用的微服务配置负载均衡规则,order-service服务去调用user-service服务
  ribbon:
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule # 负载均衡规则 

05.饥饿加载

Ribbon 默认是采用懒加载,即第一次访问时才会去创建 LoadBalanceClient,拉取集群地址,所以请求时间会很长。

而饥饿加载则会在项目启动时创建 LoadBalanceClient,降低第一次访问的耗时,通过下面配置开启饥饿加载:

ribbon:
  eager-load:
  	//项目启动时会主动去获取服务集群,如果需要获取多个可以使用“,”隔开
    clients: user-service
    enabled: true

image-20220629231420593

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

CodeWYX

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值