SpringCloud微服务学习日志-Eureka

 

微服务远程调用——提供者和消费者

服务提供者:一次业务中,被其他微服务调用的的服务。(提供接口给其他微服务)

服务消费者:一次业务中,调用其他微服务的服务。

消费者和提供者

消费者与提供者的关系是相对的消费者可以是提供者,提供者也可以是消费者。

 

 服务C既是提供者也是消费者

为什么要使用Eureka?什么是Eureka?

在使用Eureka之前,我们不同服务之间的调用是使用RestTemplate来实现的,RestTemplate需要指定请求服务的URL连接以及请求的参数。

        String url = "http://127.0.0.1:8081/user/" + order.getUserId();

        User user = restTemplate.getForObject(url, User.class);

但是在实际开发过程中,有时会遇到大量不同服务的URL请求以及同一服务多实例集群的负载均衡成为了一个问题。

如何在三台服务B之间实现负载均衡

这个时候,Eureka出现了

它充当了一个注册中心的作用,将所有服务的信息注册在这个中心里面。

 注册完了后,服务消费者拉取提供者的信息,进行负载均衡地调用。这样的话RestTemplate只需要把URL地址改为注册的服务名就可以进行远程调用了。

        String url = "http://ServiceB/user/" + order.getUserId();

        User user = restTemplate.getForObject(url, User.class);

 搭建Eureka注册中心

1.创建新的模块Eureka_Server

2.导入依赖

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

 3.在启动类上加上注解@EnableEurekaServer

@EnableEurekaServer
@SpringBootApplication
public class EruekaApplication {
    public static void main(String[] args) {
        SpringApplication.run(EruekaApplication.class,args);
    }
}

4.在application.yml文件里面写入相关配置信息:

server:
  port: 6689
spring:
  application:
#配置注册中心的名称
    name: EurekaServer
eureka:
  client:
    service-url:
    #配置注册中心的地址,注意"/"后面只能是eureka,不能是别的,否则会报错
      defaultZone: http://127.0.0.1:6689/eureka

 启动完成后会看到这样的界面

在启动的时候Springboot可能会报以下两个异常:

1.Request execution error

Request execution error. endpoint=DefaultEndpoint{ serviceUrl='http://127.0.0.1:6689/eureka/}, exception=java.net.ConnectException: Connection refused: no further information stacktrace=com.sun.jersey.api.client.ClientHandlerException: java.net.ConnectException: Connection refused: no further information

2.EurekaServer:6689 - was unable to refresh its cache!

 DiscoveryClient_EUREKASERVER/host.docker.internal:EurekaServer:6689 - was unable to refresh its cache! This periodic background refresh will be retried in 30 seconds. status = Cannot execute request on any known server stacktrace = com.netflix.discovery.shared.transport.TransportException: Cannot execute request on any known server

 以上两个问题,第一个是因为Eureka在启动的时候会获取其他服务的信息,获取不到会报这个异常。第二个是因为,Eureka会把自己当作一个服务注册在注册中心里面。以上两个异常都不会影响程序的正常运行。如果需要修复,需要在配置文件里面加入:

server:
  port: 6689
spring:
  application:
    name: EurekaServer
eureka:
  client:
    service-url:
      defaultZone: http://127.0.0.1:6689/eureka
    register-with-eureka: false #Eureka不把自己注册为服务
    fetch-registry: false #不拉取其他服务的信息

 Eureka服务注册

我准备了两个Service来进行本次测试,分别准备了一个简单的Controller来查看调用结果:

 ServiceA

@RestController
@RequestMapping("/serviceA")
public class ServiceAController {
    @GetMapping("test")
    public String ServiceATest(){
        return "ServiceA Working";
    }
}

 ServiceB(查看是哪个服务被调用了)

@RestController
@RequestMapping("/serviceB")
@Slf4j
public class ServiceBController {
    @GetMapping("test")
    public String ServiceBTest(){
        log.info("B被调用了");
        return "ServiceB Working";
    }
}

准备好了后就可以开始将他们注册进Eureka了。

所有步骤ServiceB同理,这里就只展示ServiceA的。

1.导入依赖:

server:
  port: 8080
spring:
  application:
    name: ServiceA
eureka:
  client:
    service-url:
      defaultZone: http://127.0.0.1:6689/eureka/       #Eureka注册中心的地址

2. 在启动类上加入@EnabkeEurekaClient

@SpringBootApplication
@EnableEurekaClient
public class ServiceApplication {
    public static void main(String[] args) {
        SpringApplication.run(ServiceApplication.class,args);
    }
}

3.在启动之前务必先启动Eureka服务,否则会抛出异常。

打开Eureka管理页面,可以看到两个服务都成功地注册进来了。

我们可以多准备一个ServiceB来模拟负载均衡的效果:

 启动后也成功注册进了Eureka

 使用Eureka进行服务拉取

我们完成Eureka的服务注册以后,就可以在消费者上进行服务拉取。

1.添加RestTemplate的Bean,并为其添加@LoadBalanced(我这里为了方便加在了启动类里面)

@SpringBootApplication
@EnableEurekaClient
public class ServiceApplication {

    public static void main(String[] args) {
        SpringApplication.run(ServiceApplication.class,args);
    }

    @Bean
    @LoadBalanced //添加负载均衡
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }
}

 2.修改消费者的Controller,用RestTemplate对提供者进行调用

@RestController
@RequestMapping("/serviceA")
public class ServiceAController {

    @Autowired
    private RestTemplate restTemplate;

    @GetMapping("test")
    public String ServiceATest(){
        //这里的SERVICEB需要和Eureka注册中心的一致
        String url = "http://SERVICEB/serviceB/test";
        String forObject = restTemplate.getForObject(url, String.class);
        return "ServiceA Working and " + forObject;
    }
}

 3.查看结果:

我们可以刷新4次,来查看负载均衡的结果。

可以看到4次请求被均衡到了两个服务上。

Ribbon负载均衡

1.负载均衡的原理

通过@LoadBalanced我们实现了负载均衡,但是这个负载均衡究竟是怎么做到的。

 其实真正在做负载均衡的是Ribbon,Ribbon通过拦截我们的请求,找到我们对应的服务名。

  public ClientHttpResponse intercept(final HttpRequest request, final byte[] body, final ClientHttpRequestExecution execution) throws IOException {
        URI originalUri = request.getURI();
        //这里就取到了我们刚刚输入的SERVICEB
        String serviceName = originalUri.getHost();
        Assert.state(serviceName != null, "Request URI does not contain a valid hostname: " + originalUri);
        return (ClientHttpResponse)this.loadBalancer.execute(serviceName, this.requestFactory.createRequest(request, body, execution));
    }

LoadBalancerInterceptor.class 

然后通过excute方法来进行服务的一个负载均衡。

    public <T> T execute(String serviceId, LoadBalancerRequest<T> request, Object hint) throws IOException {
        //ILoadBalancer里面记录了我们的负载均衡的方法
        ILoadBalancer loadBalancer = this.getLoadBalancer(serviceId);
        Server server = this.getServer(loadBalancer, hint);
        if (server == null) {
            throw new IllegalStateException("No instances available for " + serviceId);
        } else {
            RibbonServer ribbonServer = new RibbonServer(serviceId, server, this.isSecure(server, serviceId), this.serverIntrospector(serviceId).getMetadata(server));
            return this.execute(serviceId, (ServiceInstance)ribbonServer, (LoadBalancerRequest)request);
        }
    }
RibbonLoadBalancerClient.class

在BaseLoadBalancer里面的IRule接口的实现类就是当前负载均衡器的不同实现方法。

我们现在默认使用的轮询负载均衡,就是RoundRobinRule。

2.负载均衡策略的切换

(1).负载均衡的七种策略

Ribbon的负载均衡策略 有七种,默认使用的RoundRobinRule(轮询)。

剩下的分别是:

权重策略(WeightedResponseTimeRule)-根据每个服务提供者的响应时间分配一个权重,响应时间越长,权重越小,被选中的可能性也就越低。

随机策略(RandomRule)-从服务提供者的列表中随机选择一个服务实例。

最小连接数策略(BestAvailableRule)-也叫最小并发数策略,它是遍历服务提供者列表,选取连接数最小的⼀个服务实例。

重试策略(RetryRule)-按照轮询策略来获取服务,如果获取的服务实例为 null 或已经失效,则在指定的时间之内不断地进行重试来获取服务。

可用性敏感策略(AvailabilityFilteringRule)-先过滤掉非健康的服务实例,然后再选择连接数较小的服务实例。

区域敏感策略(ZoneAvoidanceRule)-据服务所在区域(zone)的性能和服务的可用性来选择服务实例。

(2).负载均衡策略的切换(在消费者处配置)

一.采用Bean注入的方式(对所有提供者生效)

    @Bean
    public IRule RandomRule(){
        return new RandomRule();
    }

此时策略切换生效,重启服务后刷新4次页面会发现

  B1调用了一次,B2调用了3次,此时已经切换成了随机策略。

二.采用配置(对指定提供者生效)

SERVICEB: #提供者服务名(与Eureka注册中心一致)
  ribbon:
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule #填写策略类名

效果同上

3.Ribbon饥饿加载

Ribbon启动默认采用懒加载,即消费者去调用某个提供者的服务时才去创建LoadBalancerClient实例,这样的话会导致第一次的访问时间变长。

可以在消费者端的配置文件打开饥饿加载:

ribbon:
  eager-load:
    enabled: true
    clients:
      - SERVICEB #需要开启饥饿加载的服务名,与Eureka注册中心一致

开启前:

开启后:

 

以上就是关于Eureka的知识。

避坑:运行Eureka的时候请一定要把代理关了!! 

 

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值