SpringCloud入门学习(三)服务注册中心Eureka介绍

SpringCloud系列:
1.SpringCloud入门学习(一)微服务介绍:https://www.jianshu.com/p/6a17391b9568
2.SpringCloud入门学习(二)IDEA搭建多模块SpringCloud项目:https://www.jianshu.com/p/3e18db91ae2b
3.SpringCloud入门学习(三)服务注册中心Eureka介绍
https://www.jianshu.com/p/dedf8a938557

一、服务间调用

通过第二节我相信你已经可以把简单的微服务搭建起来了,下面我来展示一下我搭建的微服务的目录结构:


image.png

consumer:消费者模块(会进行远程调用)
provider:提供者模块(提供调用接口)
common-api:公共模块

与第二章所展示的结构不同的就是我增加了一个common-api模块。这个common-api模块的作用就是可以放我们公共的实体类或者工具类等等,例如用户类可能在很多服务都会被用到,所以就可以把它提取出来放在一个模块里,用mvn install将它安装,各个模块在使用的时候直接导jar就可以了。

1.1 RestTemplate类:

之前我们要使用 Rest方式的远程调用一般使用 Apache的 HttpClient ,但是由于HttpClient使用起来比较繁琐,所以这里稍微介绍一下Spring提供的 RestTemplate。

1.2 使用getForObject()发起get请求
public <T> T getForObject(URI url, Class<T> responseType) throws RestClientException {
    RequestCallback requestCallback = this.acceptHeaderRequestCallback(responseType);
    HttpMessageConverterExtractor<T> responseExtractor = new HttpMessageConverterExtractor(responseType, this.getMessageConverters(), this.logger);
    return this.execute(url, HttpMethod.GET, requestCallback, responseExtractor);
}

图中是RestTemplate类的一个方法,很明显,两个参数:第一个是调用的URL,第二个是返回值的类型。但是getForObject没有处理response的能力。因为它拿到手的就是成型的pojo。省略了很多response的信息。

想了解更多关于RestTemplate的API可以看看这篇。转自:https://www.cnblogs.com/javazhiyin/p/9851775.html

1.3 编写提供者:

端口号8085,首先在提供方写一个接口,以供调用。省略内部查询细节。

image.png
1.4 编写消费者:

端口号8086.
1.4.1 配置RestTemplate

@Configuration
public class CloudConfig {
    @Bean
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }
}

1.4.2 编写业务

@RestController
@RequestMapping("/movie")
public class TicketController {

    @Autowired
    RestTemplate restTemplate;

    public static final String USER_URL = "http://127.0.0.1:8085/user/";

    @GetMapping("/user/{id}")
    public User selectUserById(@PathVariable("id")String id){
        User user = restTemplate.getForObject(USER_URL + id, User.class);
        return user;
    }
}

OK,到这里我们运行之~ 先启动提供者,后启动消费者。

image.png

这里可以看到,我用调用了消费者的接口,然后消费者使用RestTemplate调用了提供者。目前为止看似一切顺利。

二、上述调用方式的缺陷

1.硬编码问题: 基础较好的同学可能早就看出来了,最明显的问题就是硬编码。在消费者端IP地址和端口号已经被我们写死在代码里,如果提供方更改了URL,或者将接口名给改了,那么消费方必定是调用失败的。此时想调用成功必然要让消费方做出改变,并重新发布。这显然不可取。
2.无法动态调节:在正式开发中,一般一个服务要部署多个实例,用来提供可用性和负载均衡请求分发,并且还需要动态的增删节点。我们这种开发模式要做到这一点是很麻烦的。

如果我们能针对某一服务进行调用而不是特指服务中某个实例,让服务自己去选择其中某一实例对请求进行处理就,不管它实例怎么变化,他只要把自己的信息与服务相互映射,而我们只关心服务就好了。解决办法继续往下看。

三、服务注册中心

服务发现组件Eureka就具备解决这种问题的能力,并且在微服务体系中是一个非常非常重要的组件。


image.png

对上图进行概述:

  • 每个微服务在启动时就会将自己的信息注册到服务注册中心里,并且服务注册中心会保存这些信息。
  • 服务消费方在进行远程调用时会从服务注册中心拉取提供者们的网络地址,并使用该地址调用接口。
  • 每个微服务与注册中心使用心跳机制进行通信,用来确定某实例是否存活,如果长时间失去心跳同步,就会注销该实例或采取其他策略。
  • 如果微服务的网络地址发生变化,他会重新注册自己到注册中心。此时消费者就不用人工的改地址了。

我们以与SpringCloud整合的最好的,也是目前比较流行的Eureka为例进行探讨。

四、Eureka

image.png
4.1 Eureka架构:
  • Provider和Consumer对应着我们项目里的提供者消费者,引入了Eureka以后,他们也是Eureka客户端。由于消费者也可以是提供者,提供者也可以是消费方,他们都是相互调用的,所以都叫Eureka客户端在逻辑上是没有问题的。

  • Remote Call 即为远程调用。

  • 服务注册到Eureka后会每30秒向Eureka发送自己的心跳(默认,可配置),表示自己还存活。

  • 如果超过90秒还没有向服务中心注册的话,Eureka会注销该实例。(默认,可配置)

  • 在默认情况下Eureka Server也是Eureka Client,多个Eureka 可以通过相互注册的方式,实现数据复制。(Eureka集群)

  • Eureka客户端拿到注册信息后会缓存到自己本地。优点就是不用每次调用都去查询注册信息,这样大大降低了Eureka Server的压力。就算Eureka Server节点都宕机,也可以从缓存进行查找并调用。缺点就是如果Eureka Server都宕机了,缓存就不会更新,那么如果再有其他服务宕机会导致调用失败。

So,Eureka优点多多。下面来搭建一个单机版的Eureka Server吧。

4.2 Eureka Server搭建
    <!--Eureka服务端 -->
    <dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-eureka-server</artifactId>
    </dependency>

yml:

server:
  port: 8761

spring:
  application:
    name: eureka
eureka:
  client:
    register-with-eureka: false #表示是否向Eureka注册自己,由于本服务自身就是Eureka服务端所以没必要。
    #表示是否从Eureka拉取服务注册信息,这是一个单节点的Eureka,不需要从其他节点同步信息,所以也是false
    fetch-registry: false
    #配置与Eureka交互的地址,注册和拉取服务信息都需要通过这个地址
    service-url:
      defaultZone: http://127.0.0.1:8761/eureka/

在启动类标上@EnableEurekaServer注解

@SpringBootApplication
@EnableEurekaServer
public class EurekaApplication {

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

}

启动后访问 http://localhost:8761 。出现此页面说明搭建成功啦

image.png

注册中心既然已经搭建好,现在就把我们的Provider和Consumer改造成Eureka Client,然后让他们注册进来。

五、搭建客户端:

5.1服务提供端:

POM:

        <!--Eureka客户端 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-eureka</artifactId>
        </dependency>

yml:

server:
  port: 8085

spring:
  application:
    name: user-service
  datasource:
    type:
      com.alibaba.druid.pool.DruidDataSource
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://localhost:3306/test
    username: root
    password: 123456
    
mybatis:
  configuration:
    map-underscore-to-camel-case: true
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/  #与哪个Eureka交互
  instance:
    prefer-ip-address: true #向Eureka注册自己的ip地址,如果false(默认)就是本机hostname注册到Eureka
    lease-renewal-interval-in-seconds: 10 #续约更新时间 ,每间隔多少秒发一次心跳
    lease-expiration-duration-in-seconds: 10 #续约到期时间
    instance-id: user-service-1
/**
 * 用户微服务
 * 
 */
@EnableDiscoveryClient
@SpringBootApplication
@MapperScan(basePackages = {"com.hukaihan.cloud.provider.business.dao"})
public class ProviderApplication {

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

@EnableEurekaClient注解也可以但是它只能与Eureka工作,
@ EnableDiscoveryClient更通用,它可以与其它注册中心配合(Zookeeper等)
所以使用EnableDiscoveryClient

5.2搭建服务消费端:

与上述配置几乎一样,唯一不同的是RestTemplate的配置上需要加上一个@LoadBalanced注解,这个注解稍后说下为什么要加。

@Configuration
public class CloudConfig {

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

启动后发现两个服务已经注册好了。

image.png
5.3解决硬编码问题:

有了服务发现我们就可以不把地址写死调用了,请看代码。

image.png

将url的ip地址+端口号改成我们提供方的spring.application.name ,也就是该服务的名字。这样我们就可以用服务名调用了,服务方不管怎么改网络地址它的服务名不会改。至于具体调用该服务的哪个实例,就由负载均衡策略来决定了,也就是@LoadBalanced的作用。(由于我们没有搭建提供者的集群所以负载均衡没卵用,但是不加的话会报错的)

关于springcloud负载均衡我会在后续的章节进行探讨。

调用测试成功。

image.png

下一节讲讲Eureka的自我保护机制、健康检查等其它功能。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容