欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Eureka实现微服务注册发现

程序员文章站 2024-03-23 16:46:22
...

微服务概念比较火,个人理解为多个单应用进行组装成一个复杂应用,而各个单应用之间可能互不影响。为了保证各部分单独运作的应用的稳定性,我们考虑用负载均衡的思想启动多个相同的单应用,使得服务请求能够均摊到不同的应用上,但是服务请求结果是相同的。这个时候就需要借助微服务注册发现的Eureka,而诸如Zookeeper也能实现。

一、Eureka简介

Eureka是Netflix开发的服务发现框架,本身是一个基于REST的服务,主要用于定位运行在AWS域中的中间层服务,以达到负载均衡和中间层服务故障转移的目的。SpringCloud将它集成在其子项目spring-cloud-netflix中,以实现SpringCloud的服务发现功能。
Eureka包含两个组件:Eureka Server和Eureka Client。
Eureka Server提供服务注册服务,各个节点启动后,会在Eureka Server中进行注册,这样EurekaServer中的服务注册表中将会存储所有可用服务节点的信息,服务节点的信息可以在界面中直观的看到。
Eureka Client是一个java客户端,用于简化与Eureka Server的交互,客户端同时也就是一个内置的、使用轮询(round-robin)负载算法的负载均衡器。
在应用启动后,将会向Eureka Server发送心跳,默认周期为30秒,如果Eureka Server在多个心跳周期内没有接收到某个节点的心跳,Eureka Server将会从服务注册表中把这个服务节点移除(默认90秒)。
——摘录自Eureka (服务发现框架)百度百科

二、动手实现

预先准备,首先我们需要有个注册中心,是一个中控的作用,即EurekaServer服务端,一般只有一个。
然后是单个应用的生产者,即EurekaClient客户端,可以存在多个,且通过指定服务名称来识别。
最后是服务调用方,实际上也是EurekaClient客户端。
通过IDEA可以快捷生成一个Eureka服务,
Eureka实现微服务注册发现
Eureka实现微服务注册发现

  • 我们指定这个Eureka为注册服务中心,如何进行指定呢。
    有两处地方需要进行设置,首先在启动类上方加上@EnableEurekaServer注解,向应用解释我是一个服务端,其次是在application.yml文件里进行配置,
package com.euraka;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;

@EnableEurekaServer
@SpringBootApplication
public class EurekaApplication {

    public static void main(String[] args) {
        SpringApplication.run(EurekaApplication.class, args);
    }
}
server:
  port: 8081 #服务注册中心端口号
eureka:
  instance:
    hostname: 127.0.0.1 #服务注册中心IP地址
  client:
    registerWithEureka: false #是否向服务注册中心注册自己
    fetchRegistry: false #是否检索服务
    serviceUrl: #服务注册中心的配置内容,指定服务注册中心的位置
      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/

表示我用8081启动一个Eureka注册中心,配置完之后点击启动,访问localhost:8081即能看到以下界面
Eureka实现微服务注册发现
这里是一个空的注册中心,因为我们没有注册任何服务,接下来我们注册两个Eureka客户端服务给它。
同样按照前文生成Web、Eureka依赖的工程,在启动类上方的注解为@EnableEurekaClient,表示Eureka客户端,并且在yml中也要做相应变化

package com.eurekaclient;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@EnableEurekaClient
@SpringBootApplication
public class EurekaclientApplication {

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

	@GetMapping("/name")
	    private String myName(){
	        return "Client One";
	    }
	}
eureka:
  client:
    serviceUrl: #注册中心的注册地址
      defaultZone: http://127.0.0.1:8081/eureka/
server:
  port: 8082  #服务端口号
spring:
  application:
    name: service-client #服务名称--调用的时候根据名称来调用该服务的方法

这里表示注册一个8082端口的Eureka客户端到我们的注册中心中,其中service-client为我们的服务名称,后续的调用需要用到该服务名,且将该启动类同时作为控制层,并用/name路径作为入口。点击启动,刷新我们localhost:8081的服务注册中心页面能够看到:
Eureka实现微服务注册发现这个时候,如果我们访问http://localhost:8082/name,就会得到我们预期的结果,返回一个Client One的字符串给我们
Eureka实现微服务注册发现
但是如果只是直接访问单应用的服务ip和端口来直接请求,那我们的Eureka就发挥不出他的作用了,这个时候我们需要出来一个消费者。方便理解,可以将我们的8081端口Eureka注册中心理解为一个养猪场,而我们的8082Eureka客户端理解为一头猪,现在我们有了养猪场,也有了一头猪,但是没人来买怎么行,于是我们就应该有一个买猪的人,即为消费者。
其实消费者也是一个Eureka客户端,只不过比较特殊,同样新建一个Eureka工程,使用@EnableEurekaClient注解,并在yml配置文件中指定端口号为8088。

package com.consumer;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.context.annotation.Bean;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import java.util.HashMap;
import java.util.Map;

@RestController
@EnableEurekaClient
@SpringBootApplication
public class ConsumerApplication {

    @Autowired
    RestTemplate restTemplate;

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

    /**
     * 实例化RestTemplate
     * @return
     */
    @LoadBalanced
    @Bean
    public RestTemplate rest() {
        return new RestTemplate();
    }

    /**
     * Rest服务端使用RestTemplate发起http请求,然后得到数据返回给前端
     * @return
     */
    @GetMapping(value = "/getName")
    @ResponseBody
    public String getName(){
        /**
         * 因为他向注册中心注册了服务,服务名称service-client,我们访问service-client即可
         */
        String str = restTemplate.getForObject("http://service-client/name", String.class);
        return str;
    }
}
eureka:
  client:
    serviceUrl: #注册中心的注册地址
      defaultZone: http://127.0.0.1:8081/eureka/
server:
  port: 8088  #服务端口号
spring:
  application:
    name: service-consumer #服务名称--调用的时候根据名称来调用该服务的方法

这里需要重点关注启动类中的getName方法,我们将该启动类同时作为控制层入口,且用/getName路径来请求。使用RestTemplate来远程调用我们第一个Eureka客户端,我们能看到这里并不是直接使用http://localhost:8082/name地址来请求,而是使用了http://service-client/name,即服务名+请求地址的方式,这就需要注意前文我们在配置文件yml中提到的服务名称的作用。
启动这个消费者服务,开始准备“买猪”了。
Eureka实现微服务注册发现

这里能够看到注册中心里已经有了我们的消费者,同时前面准备的“猪仔”也已经有了。这个时候我们直接访问:http://localhost:8088/getName,神奇的事情发生了,我们访问到的内容与我们直接访问http://localhost:8082/name返回的请求结果一致。为了验证是否真的是请求到了localhost:8082/name上,我们可以打个断点并再次请求,发现断点确实进来了,证明我们买猪成功了。
Eureka实现微服务注册发现
同样的,一个猪场里怎么可能只有一头猪,我们这个时候再加入一头猪,即再向我们的服务注册中心中再注册一个Eureka客户端,

package com.eurekaclient2;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@EnableEurekaClient
@SpringBootApplication
public class Eurekaclient2Application {

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

    @GetMapping("/name")
    private String myName(){
        return "Client Two";
    }

}
eureka:
  client:
    serviceUrl: #注册中心的注册地址
      defaultZone: http://127.0.0.1:8081/eureka/
server:
  port: 8083  #服务端口号
spring:
  application:
    name: service-client2 #服务名称--调用的时候根据名称来调用该服务的方法

这里表示注册一个8083端口的客户端到Eureka注册中心,其中服务名称为service-client2,并将启动类同时作为控制层,并暴露一个endpoint为/name,访问返回“Client Two”字符串的结果。
启动之后,我们再刷新我们的注册中心界面,发现确实加入了一个新的Eureka客户端:
Eureka实现微服务注册发现
这说明我们的猪场里现在有了两头猪,在消费者那里也要通知一下表示我们现在有第二头猪了,在消费者客户端8088端口服务中加上以下代码:

/**
     * Rest服务端使用RestTemplate发起http请求,然后得到数据返回给前端
     * @return
     */
    @GetMapping(value = "/getName2")
    @ResponseBody
    public String getName2(){
        /**
         * 因为他向注册中心注册了服务,服务名称service-client,我们访问service-client
         */
        String str = restTemplate.getForObject("http://service-client2/name", String.class);
        return str;
    }

重启8088端口服务,在地址栏中请求http://localhost:8088/getName2,发现我们确实成功能够请求到8083端口的第二个Eureka客户端服务,并返回了Client Two的请求结果。
Eureka实现微服务注册发现
这个时候,我们的Eureka注册中心中已经有了两个不同服务名称的客户端,即两头不同名字的猪,一头叫佩奇,一头叫乔治。而这个时候,如果我们再来一头同样叫做佩奇名字的猪会怎么样呢。
比如,我们再注册一个8084的端口,且服务名称跟8082的服务名称一致,也叫service-client,同样在启动类也当做控制层,请求/name路径返回Client Three的请求结果。

package com.eurekaclient;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@EnableEurekaClient
@SpringBootApplication
public class EurekaclientApplication {

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

    @GetMapping("/name")
    private String myName(){
        return "Client Three";
    }
}
eureka:
  client:
    serviceUrl: #注册中心的注册地址
      defaultZone: http://127.0.0.1:8081/eureka/
server:
  port: 8084  #服务端口号
spring:
  application:
    name: service-client #服务名称--调用的时候根据名称来调用该服务的方法

启动该Eureka客户端,刷新一下8081端口的服务注册中心会发现,在第一个同名客户端下有两个应用了
Eureka实现微服务注册发现
一个是8082的应用,另一个则是8084的应用。这个时候,如果我们用8088端口的消费者去访问该同名服务会发生什么呢。
第一次访问,我们得到了Client One的请求结果
第二次访问,我们得到了Client Three的请求结果
之后每次刷新的请求结果,就仿佛在8082和8084端口的应用之间随机访问一样。
Eureka实现微服务注册发现
Eureka实现微服务注册发现
这就实现了我们最简单的应用负载均衡。

三、总结

以上只是Eureka微服务注册发现的入门,笔者也正好在学习这一块的内容,所以作此文以供参考。文中展示的是较为简单的应用示例,实际场景会比这复杂百倍,不过作为概念理解应该足够了。

参考资料: