【微服务01】Nacos + OpenFeign + LoadBalancer 的入门级用法
本文主要有以下内容:
- 创建
Maven工程进行项目依赖同一管理- 使用
Nacos组件进行服务注册和发现- 使用
OpenFeign + LoadBalance组件进行远程服务调用和负载均衡
搭建Maven父工程进行项目依赖管理
- 使
idea工具创建maven工程,取名为misco-service-simple

- 创建完成后,修改
pom.xml文件,打包方式为pom则说明此工程只管理Maven依赖
<!--指定springboot版本 -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.2</version>
</parent>
<dependencyManagement>
<dependencies>
<!-- Spring Cloud依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>2020.0.1</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- Spring Cloud Alibaba依赖-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>2021.1</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
其中需要注意的是如果 maven 父工程中使用的是 dependencies 标签,则子工程中可以直接使用父工程的引用。如果父工程中使用的是 dependencyManagement 则子工程中不能直接使用父工程引入的依赖,需要在自己的 pom 文件中引入,此时只需要添加坐标即可,不需要添加版本号。因为 dependencyManagement 对依赖进行了统一的版本管理。
用一个不恰当的例子说明:dependencyManagement就相当于餐馆的老板,老板把菜、调味品等所需要的东西备好了,厨师 子工程 只负责使用老板已备好的东西进行出菜即可。
-
依次创建
consumer-service和produce-service项目,具体步骤如下- 选中
misco-service-simple文件夹 - 右键 new module 选择Maven
- 输入项目名
- 选中
-
创建完成后项目文件结构如下图

-
分别在两个子工程的
pom.xml文件中引入如下依赖<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency>
引入上述依赖之后,我们就可以在相应的工程中使用 @SpringBootApplication、@RestController、@RequestMapping 等注解。
- 在
consumer-server子工程中添加如下文件和代码,文件结构如下图所示:

其中 ConsumerController 的代码如下所示,在 application.yml中指定端口号 10001
@RestController
@RequestMapping("consume/")
public class ConsumerController {
@GetMapping("string")
public String consumer(){
return "consumer user";
}
}
ConsumerApplication 的代码如下所示
@SpringBootApplication
public class ConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(ConsumerApplication.class);
}
}
按照相同的方法在 produce-service 子工程中创建如下的文件和代码

ProduceDataService 和 ProduceDataController 的代码如下所示
public interface ProduceDataService {
Map<String,String> getData();
}
@Service
public class ProduceDataServiceImpl implements ProduceDataService{
@Override
public Map<String, String> getData() {
Map<String,String> result = new HashMap<>();
result.put("produce","produce a map");
return result;
}
}
@RestController
@RequestMapping("produce/")
public class ProduceDataController {
@Resource
ProduceDataService dataService;
@GetMapping("get")
public Map<String,String> getData(){
return dataService.getData();
}
}
最后在 application.yml 中指定和 consumer-service 的 application.yml 文件中不同的端口号,避免端口冲突。
上面的所以步骤都是在做一些准备工作,此时可以分别启动这两个服务,通过 postman都能够正确运行。
Nacos 注册中心
在使用 postman工具进行测试的时候,我们通常会输入 ip:port/path1/subpath 等信息;调用后端接口,获取后端的数据,当接口不多的时候,可能觉得没什么问题。但是当接口很多且应用端口号发生变化时,我们需要维护的接口就让人头疼,尤其是在前后端分离开发的情况下,前后端同事们在对接接口这件事上,总是让人打脑壳。

图片来源于:juejin.cn/pin/7041953…
同样的情况在后端也会出现。如果说 consumer-service 要调用 produce-service中的服务时,使用OkHttp3或者HttpClient等网络请求框架时,如果 produce-service的端口信息或者其他信息发生变更没有告诉开发 consumer-service 服务的开发时,难免少不了一场甩锅大战。这就是Nacos或者eureka等注册中心出现的原因。
怎么去理解注册中心呢?使用过自如或者找过链家等中介平台进行租房的朋友们就知道。通常房东把自己的房子信息交给中介平台,然后为我们询问中介平台有无合适的房源进行租房。房东就相当于上面的 produce-service ,而我们就相当于消费者服务,去消费房子。
就如同有不同的中介平台一样,注册中心也很多种,只是我这里选择了 nacos 进行服务的注册。有利就有弊,注册中心帮助我们更好的管理服务,带来的最直接的影响就是我们需要去学习怎么使用注册中心。
Nacos 安装
在官方提供的下载页面选择自己需要的版本,注意是在Assets节点下,我选择的版本是 2.0.3。 以 Windows 系统为例,下载之后解压文件,解压后进入 conf 目录下,需要修改以下几项:
-
打开
application.properites需要打开如下几项的注释,并添加相关配置信息,# 默认端口号 server.port=8848 # 指定Nacos持久化所需要的数据库 spring.datasource.platform=mysql ### Count of DB: db.num=1 ### Connect URL of DB: db.url.0=jdbc:mysql://127.0.0.1:3306/nacos?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useUnicode=true&useSSL=false&serverTimezone=Asia/Shanghai db.user.0=root db.password.0="root password" -
创建
nacos数据库,sql文件在conf目录下的nacos-mysql.sql里create schema nacos; -- 运行nacos-mysql.sql 中的sql语句 -
如果是单机
nacos,则在bin目录下,点击startup.cmd启动,如果要搭建集群则,需要在conf目录下搭建创建cluster.conf文件配置集群的ip信息- ip: port 这里的ip地址不能是127.0.0.1 - IP 应该使用你本机分配到的内网 IP 地址 - 如果你使用的是 mac 或者 linux 系统,可以在命令行使用 ifconfig | grep “inet” 命令来获取本机 IP 地址 - windows 使用 ipconfig来获取
以 windows 为例,在命令行输入 ipconfig 图中红色圈中的信息就是内网地址。

此时配置文件如下
192.168.1.7:8848
192.168.1.7:9848
注:需要复制一份解压文件,分别配置相关信息!两个服务的端口号如果连续有时候会出现问题,建议设置隔开一点。
- 在正确配置集群之后就可以启动
nacos服务器,启动成功后可见到如下画面。

-
通过终端的输出就可以看到访问
127.0.0.1:8848/nacos/index.html可以登录到控制台,默认账户密码均为nacos,第二个红色框框表示集群的 IP 地址,第三个红框表示正确启动Nacos -
登录
Nacos控制台之后,在左侧侧边栏点击—命名空间—点击新建命名空间—新建dev、pre-production、production供我们后续使用

微服务改造
安装完毕后,在各自的 pom.xml添加如下依赖
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
在各自的 application.yml 添加 nacos 配置信息,以 produce-service 为例
server:
port: 20000
spring:
application:
name: produce-application
cloud:
nacos:
discovery:
# Nacos的服务注册地址,可以配置多个,逗号分隔
server-addr: http://192.168.1.7:8848
# 服务注册到Nacos上的名称,一般不用配置
# nacos客户端向服务端发送心跳的时间间隔,时间单位其实是ms
heart-beat-interval: 5000
# 服务端没有接受到客户端心跳请求就将其设为不健康的时间间隔,默认为15s
# 注:推荐值该值为15s即可,如果有的业务线希望服务下线或者出故障时希望尽快被发现,可以适当减少该值
heart-beat-timeout: 20000
# 元数据部分 - 可以自己随便定制
metadata:
mydata: abc
naming-load-cache-at-start: false
# 命名空间ID,Nacos通过不同的命名空间来区分不同的环境,进行数据隔离,将服务进行分组
namespace: dev
cluster-name: Cluster-A
group: myGroup
register-enabled: true
配置信息给出了详细的注释,就不过多介绍。在正确配置之后,启动 nacos 、consumer-service 、produce-service 打开 nacos 控制台,可以看到我们启动的服务,

OpenFeign + LoadBalancer 组件
在通过上面的步骤之后,我们相当于把服务注册到 nacos 上了,但是如何调用服务?答案就是使用 OpenFeign 组件,如果你使用过其他 Http库进行服务调用如RestTemplate + @LoadBalanced 注解组合通过服务名调用远程服务,或者RestTemplate 直接 ip + port 的访问方式就能够体验到 OpenFeign 带来的快感。
前面所描述的两种调用方式,不是说他们不好,只是使用 OpenFeign 让我们开发更加丝滑,如调用本地服务一样。
在consumer-service 的 pom.xml 文件中,引入如下依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!-- 负载均衡组件 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
注意: 如果不引入 LoadBalancer 组件,使用 OpenFeign组件后,直接启动服务,会提示缺少 LoadBalancer组件。
在 consumer-service创建consumer.service.feign.ProduceDataInt接口, 并添加如下代码
@FeignClient(value = "produce-application",path = "produce/")
public interface ProduceDataInt {
@GetMapping("get")
Map<String,String> getData();
}
value 属性指向 produce-service 的 spring.application.name, path+ getMapping 指向我们要代理的方法,方法名要和我们调用的方法名一致,包括参数顺序、个数 。只是在本例子中没有使用带参数的方法。我想用最简单的方法和最少的代码来演示各个组件的使用。这也是没有创建 entity、dao等包和类的原因。
添加完上述的代码之后在启动类上添加注解@EnableFeignClients(basePackages = "consumer.service.feign"),并通过basePackages 指向我们创建ProduceDataInt的接口所在的包,这样 Spring 就可以扫描到使用 @FeignClient 的注解,生成动态代理对象,帮助我进行服务调用。
接着修改 ConsumerController的代码
@RestController
@RequestMapping("consumer/")
public class ConsumerController {
@Resource
ProduceDataInt produceDataInt;
@GetMapping("string")
public String consumer(){
System.out.println(produceDataInt.getData().get("produce"));
return "consumer user";
}
}
再修改 ProduceDataController 的方法如下,方便我们看日志信息。
@GetMapping("get")
public Map<String,String> getData(){
System.out.println("service1: time = " + LocalDateTime.now());
return dataService.getData();
}
启动produce-service服务后,修改端口 20000-->20010 通过Edit configuration修改服务允许服务并行运行。

然后修改输出流为System.out.println("service2: time = " + LocalDateTime.now()); 在启动produce-service服务。通过 nacos 控制台观察服务

此时通过postman 进行服务调用 consumer/string 两次,可以看到 produce1/produce2 各输出了一次,再调用一次produce1又输出了相应的时间信息。这是因为LoadBalancer 默认情况下时采用轮询算法进行负载均衡的。LoadBalancer 默认提供了两种算法进行负载均衡,一个是轮询算法,一个是随机算法,也可以自定义负载均衡算法。

consumer-service 获取到了所有的 produce-service 服务实例,依次进行服务调用,这是在客户端consumer-sercice进行的。
思考&说明
- 为什么服务注册时,需要配置
namespace以及group? 答案在Nacos官网。LoadBalancer组件的负载均衡算法可以改变,也可以自定义负载均衡算法,先挖坑后面再填。RestTemplate + LoadBalance实现服务名调用的demo在后面有时间也写一下。
转载自:https://juejin.cn/post/7227128420358422565