【微服务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