Eureka实现微服务注册发现

微服务概念比较火,个人理解为多个单应用进行组装成一个复杂应用,而各个单应用之间可能互不影响。为了保证各部分单独运作的应用的稳定性,我们考虑用负载均衡的思想启动多个相同的单应用,使得服务请求能够均摊到不同的应用上,但是服务请求结果是相同的。这个时候就需要借助微服务注册发现的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为注册服务中心,如何进行指定呢。
    有两处地方需要进行设置,首先在启动类上方加上@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客户端服务给它。
同样按照前文生成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的服务注册中心页面能够看到:
success这个时候,如果我们访问http://localhost:8082/name,就会得到我们预期的结果,返回一个Client One的字符串给我们
在这里插入图片描述
但是如果只是直接访问单应用的服务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中提到的服务名称的作用。
启动这个消费者服务,开始准备“买猪”了。
在这里插入图片描述

这里能够看到注册中心里已经有了我们的消费者,同时前面准备的“猪仔”也已经有了。这个时候我们直接访问:http://localhost:8088/getName,神奇的事情发生了,我们访问到的内容与我们直接访问http://localhost:8082/name返回的请求结果一致。为了验证是否真的是请求到了localhost:8082/name上,我们可以打个断点并再次请求,发现断点确实进来了,证明我们买猪成功了。
在这里插入图片描述
同样的,一个猪场里怎么可能只有一头猪,我们这个时候再加入一头猪,即再向我们的服务注册中心中再注册一个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客户端:
suc
这说明我们的猪场里现在有了两头猪,在消费者那里也要通知一下表示我们现在有第二头猪了,在消费者客户端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的请求结果。
getName2
这个时候,我们的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端口的服务注册中心会发现,在第一个同名客户端下有两个应用了
在这里插入图片描述
一个是8082的应用,另一个则是8084的应用。这个时候,如果我们用8088端口的消费者去访问该同名服务会发生什么呢。
第一次访问,我们得到了Client One的请求结果
第二次访问,我们得到了Client Three的请求结果
之后每次刷新的请求结果,就仿佛在8082和8084端口的应用之间随机访问一样。
Client One
Client Three
这就实现了我们最简单的应用负载均衡。

三、总结

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

参考资料:

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值