SpringCloud 微服务实战(服务发现组件)

上一节我们搭建了最基础的两个微服务,他们分别是服务提供者 microservice-provider-user 与服务消费者 microservice-provider-movie,并使用 RestTemplate 成功的在消费者端调用了提供者的服务,但是也看到了存在一些问题:每次调用的时候需要传入服务提供者的 IP 地址和端口号。想象一下如果 user 服务改变了地址和端口,那些服务消费者(可能有多个)都需要更改,有人可能会说可以把 user 服务的地址和端口写成配置文件,这样相比硬编码在代码中确实要好一些,但是仍然不够优雅

为了解决这个问题,服务的消费者需要一个强大的服务发现机制,它可以使用这种机制获取服务提供者的网络信息。重点来了:不仅如此,即使服务提供者的信息发生了变化,服务消费者也无需修改任何配置

在微服务架构中,提供这种能力的组件叫做 服务发现组件,这是一个非常关键的组件

有了服务发现组件后,各个微服务(包括服务消费者和提供者)在启动的时候会将自己的网络地址等信息注册到服务发现组件上,服务发现组件会存储这些信息。服务消费者从发现组件中查询提供者的网络信息,并使用该地址调用提供者提供的服务。各个微服务与服务发现组件使用一定机制通信,如果服务发现组件发现某个微服务长时间没有与自己通信就会认为这个服务出现了故障,接下来就会注销它。

服务发现组件架构图

SpringCloud 中提供了多种服务发现组件的支持,例如 Eureka、Consul 和 Zookeeper,本节以 Eureka 为例简单说明它的使用

Eureka Server

在父工程下新建一个模块,artifactId 为 microservice-eureka-server,需要引入 eureka 相关的依赖,pom 如下(给 server 加入了密码功能所以同时引入了 security)

1
2
3
4
5
6
7
8
9
10
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
</dependencies>

其中 resources 目录下新建 application.yml,增加如下配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
server:
port: 8761
eureka:
instance:
hostname: eureka-server # 指定该Eureka实例的主机名
client: # 一个eureka-server同时也是一个eureka-client,ha下配成server的集群 每个server对于其他server就是client 因为现在不是集群,所以下面两个选项都是false
registerWithEureka: false
fetchRegistry: false
serviceUrl:
defaultZone: http://${security.user.name}:${security.user.password}@localhost:${server.port}/eureka
security:
basic:
enabled: true
user:
name: user
password: password123

新建主类入口如下,声明成一个 EurekaServer 非常简单,只需要加上 @EnableEurekaServer 注解即可

1
2
3
4
5
6
7
@SpringBootApplication
@EnableEurekaServer
public class EurekaServerApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaServerApplication.class, args);
}
}

启动它,访问 8761 端口看到如下界面(需要输入密码,就是在配置文件中的 user 和 password123),这时可以看到没有实例注册在本服务中心

改造 user 和 movie 模块

将这两个模块添加 eureka 相关的依赖并注册到 eureka-server上,首先修改 pom 文件,增加

1
2
3
4
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>

在主类上增加注解 @EnableEurekaClient

模块的配置文件增加如下

1
2
3
4
5
6
eureka:
client:
service-url:
defaultZone: http://user:password123@localhost:8761/eureka
instance:
prefer-ip-address: true

这时候启动 user 和 movie,刷新 eureka-server 的监控页面,可以在最下面标红处看到新注册了两个服务(这时候中间有一些红字提示我们 eureka-server 进入了安全模式,有兴趣的同学可以自己去了解下)

这时候就可以将调用服务的语句改为

1
return this.restTemplate.getForObject("http://microservice-provider-user/user/" + id, User.class);

这里 movie 调用 user 的服务的时候没有显式的指明 user 模块的网络信息,而是仅仅指定了 user 在 eureka-server 上的 virtual-name 就可以实现调用。那么这时候如果再出现 user 模块的网络信息的变动,我们不用改动这里的调用语句依然可以实现正确的调用,这就是服务发现组件为我们提供的便利。

到这里一个简答的服务发现组件就介绍完了,我们知道微服务的出现为服务的横向拓展提供了便利,当 user 模块部署了多个的时候,其他的消费者的请求如何分发到不同的服务提供者呢?下一节我们介绍微服务框架中的负载均衡