服务调用问题
在业务分析当中,有个简单的功能点:会员可以开通月卡,开通月卡的同时,需要增加相应的积分。开通月卡功能在会员服务模块维护,但增加积分功能在积分服务模块维护,这就涉及到两个模块间的服务调用问题。
单实例(单机)情况:可以采用点对点的 HTTP 直接调用,采用 IP + Port + 接口的形式进行。在实际的业务开发过程中,越来越多的产品开发采用轻量级的 HTTP 协议进行数据交互。如果模块增多,将会形成蜘蛛网的形式,非常不利于开发维护。
多实例的情况:为应对服务的压力,采用多实例集群部署已成为简捷易用的解决方案。仅仅多实例部署后,将直接面临多个严峻问题:
- 调用方如何知晓调用哪个实例,当实例运行失败后,如何转移到别的实例上去处理请求?
- 如果采用了负载均衡,但往往是静态的,在服务不可用时,如何动态的更新负载均衡列表,保证调用者的正常调用呢?
面对以上两种情况,为了将所有的服务(实例)统一的、动态的管理起来,服务注册中心的需求迫在眉捷。
服务注册中心
服务注册中心作分布式服务框架的核心模块,可以看出要实现的功能是服务的注册、订阅,与之相应的功能是注销、通知这四个功能。
所有的服务都与注册中心发生连接,由注册中心统一配置管理,不再由实例自身直接调用。服务管理过程大致过程如下:
- 服务提供者启动时,将服务提供者的信息主动提交到服务注册中心进行服务注册。
- 服务调用者启动时,将服务提供者信息从注册中心下载到调用者本地,调用者从本地的服务提供者列表中,基于某种负载均衡策略选择一台服务实例发起远程调用,这是一个点到点调用的方式。
- 服务注册中心能够感知服务提供者某个实例下线,同时将该实例服务提供者信息从注册中心清除,并通知服务调用者集群中的每一个实例,告知服务调用者不再调用本实例,以免调用失败。
在开发过程中有很多服务注册中心的产品可供选择:
- Consul
- Zookeeper
- Etcd
- Eureka
- Nacos
比如 Dubbo 开发时经常配合 Zookeeper 使用,Spring Cloud 开发时会配合 Eureka 使用,社区都提供相当成熟的实施方案,本次将采用 Nacos
Nacos 应用
官网地址:https://nacos.io/en-us/,由阿里开源,一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台,已经作为 Spring Cloud Alibaba 的一个子项目,更好与 Spring Cloud 融合在一起。
下载应用
本次采用 1.4.1 版本,下载地址,Windows 版本下载后,目录结构如下:
启动应用
此时直接双击 startup.cmd 启动会报错,正确操作应该是打开命令行输入下面的命令:
1
2
# 单机启动 nacos
startup.cmd -m standalone
界面如下,用户密码都默认:nacos
服务中应用 nacos
首先在父项目工程中依赖管理中引入 Spring Cloud、Spring Cloud Alibaba(它是后来加的,所以与Spring Cloud 不是同一个依赖)和 Spring Boot:
SpringBoot、Spring Cloud、Spring Cloud Alibaba 版本之间的适配见:版本间的适配
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<!-- SpringBoot -->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.3.1.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- Spring Cloud 和 Spring cloud Alibaba -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Hoxton.SR9</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>2.2.6.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
然后再子模块中引入 nacos 依赖:
1
2
3
4
5
6
7
<dependencies>
<!-- nacos 服务注册中心 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
</dependencies>
最后在子模块启动类/配置类添加注解 @EnableDiscoveryClient,同时修改配置文件:
1
2
3
4
5
6
7
spring:
application:
name: paring-member
cloud:
nacos:
discovery:
server-addr: localhost:8848 # nacos 服务地址
启动子模块,然后刷新 nacos 页面,就可以看到你的服务了:
nacos 服务分级存储模型
分级模型如下:
- 服务:提供某项具体服务,如我们的 parking-member 就是提供会员信息管理服务的
- 实例:一个服务可以拥有多个实例,比如 parking-member 在不同端口启动,每个运行中的服务就是一个实例
- 集群:因为单机单实例部署服务,容灾性比较弱,现在都倡导多机器实例集群,即像很多大厂在不同的地域会有一处机房,按地域有华中、华东和华北等,一个机房可能会提供多种服务, 不同机房也会提供相同的服务,但服务调用都是优先本地集群 再跨集群调用,如下所示:
配置集群属性
1
2
3
4
5
6
spring:
cloud:
nacos:
discovery:
server-addr: localhost:8848 # nacos 服务地址
cluster-name: HZ # 集群名称:华中
如下所示,我针对 parking-member 服务设置了两个集群,分别是 HZ 和 HN: