从本篇开始就算是开启Spring Cloud 的旅程了。Spring Cloud 其实并不复杂,它由各个组件构成,也可说整合了各个组件,同类型组件之间也可以选择使用,比如注册中心的zk、eureka、consul、nacos等等,这些都可以成为组成cloud 体系的注册中心组件,但是因为各种不同的原因,还有技术选型的淘汰,最后各个企业使用的方案也有一定区别,也有一些大企业使用的是自研的组件,但这些最后都会被cloud 整合使用。
目前最常使用的还是阿里提供出来的一套组件方案:微服务网关-getway、服务调用-openFeign、注册和配置中心-nacos、限流和降级-sentinel、分布式事务管理-seata,这五大组件就构建出一个分布式微服务系统。当然一个完整的项目除了这些之外一定还有其余的中间件,比如:链路追踪的skywalking、缓存的Redis、平台任务调度的xxl-job等等。
nacos 的安装和使用
上面简介中也说了cloud 体系的注册和配置中心的选择有很多,但是目前市面是最常用的还是nacos,或者往nacos 上面套一层弄一个自研的中间件。
说回nacos 本身,nacos 可以说是非常好学,原因很简单,它是阿里的,换句话说它的文档和社区分享的内容基本都是中文的,官方文档中就有docker、cloud、boot 等多方面的结合使用说明,本身也有极其优秀的可视化视图,易上手、操作简单。
这里说一句,因为cloud 项目是一个整体,所以学习单个组件的时候会不可避免的涉及到其余组件,但是不要过于纠结其余组件的使用,只关注当前的单个组件的内容即可。
nacos 概述
正式开始之前还是要精简的抄一下官网的概述和基本概念。
nacos 是一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台,它提供了一组简单易用的特性集,能够快速实现动态服务发现、服务配置、服务元数据及流量管理。
nacos 概念比较多,有兴趣的可以去官网了解,但是有几个基础概念一定要了解:
- 命名空间:这个是重点,Namespace 也就是命令空间,是用于进行租户粒度的配置隔离。在不配置的情况nacos 只提供一个命名为public 的命令空间,要做不同环境的配置的区分隔离的话,一定是要自己配置的。
- 服务注册中心:存储服务实例和服务负载均衡策略的数据库。
- 配置管理:系统配置的编辑、存储、分发、变更管理、历史版本管理、变更审计等所有与配置相关的活动。
- 实例:提供一个或多个服务的具有可访问网络地址(IP:Port)的进程。
- 权重:实例级别的配置。权重为浮点数。权重越大,分配给该实例的流量越大。
- 健康检查:nacos 提供出来检查注册服务的运行时情况的。
在众多的概念里面,最重要的就是上面的前三个,Namespace 命令空间是一切开始的基础,nacos 本身也提供出了一个最基础的public 命令空间,同时这个命令空间也不可删除;服务注册中心,服务的注册和发现都是在这个基础上做的;同理,配置管理,就是项目的配置中心,这个模块里面存储着所有注册上的配置信息。
nacos 还有一些角色、权限之类的配置,可以用于对项目的隔离管理等,这些后面都会有一点一点的演示。
nacos 的docker 安装流程
因为docker 本身要做配置管理、权限管理的话,需要数据持久化,这样就需要使用数据库,一般老说使用nacos 的话,都是选择mysql 作为数据持久化的插件,但是这样同时会导致直接安装会比较麻烦,而且占用内存比较多,启动也不是很方便。我们这里是可以结合docker 来安装使用,个人学习的话,也不用安装体量很大的k8,直接用docker-compose 来编排就行。
docker 和docker-compose 的安装和使用这里就不说了,暂时没有接触这类知识的,可以先去看我之前关于docker 的文章,也可以直接跳过这段安装的内容,直接去看结合项目的使用内容。
docker 和docker-compose 安装完成之后,就可以nacos 的官网下载一份对应版本的tar.gz 的包,我下载的是2.2.1 版本 的,访问链接拉倒做底部就能看到了。
下载下来之后,解压得到一个nacos-docker 的版本文件,其中example 文件夹中就有关于nacos 的单点和集群启动的docker-compose 文件,我们找一个结合mysql 的单点启动文件分析一下。
下面是standalone-mysql-8.yaml 文件
version: "3.8"
services:
nacos:
image: nacos/nacos-server:${
NACOS_VERSION}
container_name: nacos-standalone-mysql
env_file:
- ../env/nacos-standlone-mysql.env
volumes:
- ./standalone-logs/:/home/nacos/logs
ports:
- "8848:8848"
- "9848:9848"
depends_on:
mysql:
condition: service_healthy
restart: always
mysql:
container_name: mysql
build:
context: .
dockerfile: ./image/mysql/8/Dockerfile
image: example/mysql:8.0.30
env_file:
- ../env/mysql.env
volumes:
- ./mysql:/var/lib/mysql
ports:
- "3306:3306"
healthcheck:
test: [ "CMD", "mysqladmin" ,"ping", "-h", "localhost" ]
interval: 5s
timeout: 10s
解析:
- version:docker-compose 版本3.8。
- services:层级下两个service,nacos 和mysql。
- image:引入的镜像。
- container_name:服务名称。
- build:构建镜像,context:构建镜像在当前目录下,dockerfile:Dockerfile 文件的位置。
- env_file:配置信息的文件位置。
- volumes:绑定挂载文件的位置。
- ports:暴露的端口集,这个有点需要注意nacos 一定要暴露容器的9848,因为2.0 以后的nacos 版本gRpc 请求会偏移端口。
- healthcheck:脚本配置。
- restart:启动策略。
- depends_on:这个是之前docker 文章缺失的内容,表示等待对应的服务先启动,比如这里就是mysql 先启动后,通过健康检查后再启动nacos 。其中的condition 规定了3.2 以上版本才能使用,它有三个属性,
service_started:表示在依赖的服务启动之后,才启动本服务;
service_healthy:表示在依赖的服务健康检查通过之后,才启动本服务;
service_completed_successfully:表示在依赖的服务成功执行之后,才启动本服务。
上面docker-compose 的内容还是较为复杂,而且必须在指定目录下才能使用,我这里改了一版,在任意目录下都能使用,不过前提是跟着我的路径放置上面解压出来的nacos-docker 文件。
version: "3.8"
services:
nacos:
image: nacos/nacos-server:v2.2.0
container_name: nacos
env_file:
- /app/nacos/nacos-docker/env/nacos-standlone-mysql.env
volumes:
- /app/nacos/log/:/home/nacos/logs
ports:
- "8848:8848"
- "9848:9848"
networks:
- liwq-tm
depends_on:
mysql:
condition: service_healthy
restart: always
mysql:
container_name: mysql
image: liwqtm/mysql:8.0.0
env_file:
- /app/nacos/nacos-docker/env/mysql.env
volumes:
- /app/mysql:/var/lib/mysql
ports:
- "3306:3306"
networks:
- liwq-tm
healthcheck:
test: [ "CMD", "mysqladmin" ,"ping", "-h", "localhost" ]
interval: 5s
timeout: 10s
retries: 10
networks:
liwq-tm:
external: true
相对上面,我加了一个网桥,所以需要先执行一下docker network create liwq-tm
命令,而且我没有在启动时构建mysql,而是先构建完成了,因为nacos 对应的mysql 的数据库中,要先做一些准备工作,要创建对应的数据库、表,还要新增部分表数据,所以分开操作会好一点。
我们先跟着步骤构建mysql 的镜像。进入对应目录:cd /app/nacos/nacos-docker/example/image/mysql/
,执行:docker build -t liwqtm/mysql:8.0.0 .
,执行:docker-compose -f 全路径/standalone-mysql-8.yaml up -d
,启动成功之后,可以进入用docker exec -t mysql sh
命令进入容器,查看是否存在nacos_devtest 数据库,或可视话软件进行了解数据库查看。
如果这个数据库的话,可以在nacos 官方提供的地址 中查看对应的SQL,然后手动执行。
如果已经有数据库了,需要进行关联的话,首先上面的mysql 文件挂载的时候需要修改/app/mysql
改为自己的mysql 数据存储地址,然后进入mysql 的配置文件中/app/nacos/nacos-docker/env/mysql.env
修改用户名和用户密码,修改为自己的,然后进nacos 的配置文件中/app/nacos/nacos-docker/env/nacos-standlone-mysql.env
,修改用户名、用户密码、数据库名,mysql 端口暴露的宿主机端口不是3306 的话,也要修改。
然后重启,也可以执行docker-compose -f 全路径/standalone-mysql-8.yaml down
,成功之后,再执行上面执行过的up 语句即可。
这样其实就已经成功安装好了nacos 以及对应的mysql。我们直接访问http://00.00.00.00:8848/nacos 即可,用户名:nacos、用户密码:nacos。
如果没有访问成功的话,可以看下nacos 挂载的日志,进入日志目录后,执行tail -1000f nacos.log
找到具体原因再解决。
这里我说明一个我遇到的最坑的异常,NACOS_AUTH_IDENTITY_KEY,这个问题最开始的时候,我以为是没有配置对应的数据库和表导致的,虽然我的确没有,但是后面我配置了还是有这个问题,最会网上找了半天,发现nacos 2.2.1 之后的版本需要配置三个属性才能使用,我简单的看了一下,一堆的秘钥之类的,我懒得配置,直接切换使用2.2.0,当场解决。
nacos 在我们上面的内容中就已经启动成功了,但是不算是配置成功,因为之前也说过,Namespace 命名空间是一切开始的基础,如果不配置,就是使用nacos 提供的默认空间public,一般情况下都是需要提前配置的。
命名空间的配置也非常简单,直接在nacos 的视图页面上找到命令空间,然后点击创建按钮即可,几乎没有什么要注意的,傻瓜式操作。
mysql 数据持久化的注意点
这块内容是我后面加的,原因就是有天早上起来,mysql 里面nacos 数据库被黑了,配置和用户数据全部丢失,被勒索了。
mysql 的创建用户修改权限的命令如下,主要是修改root 账户的密码,可以进去容器直接命令修改,然后在root 账户下创建nacos 的数据库,再将数据库中表的CRUD 权限赋予nacos 的用户。
有条件的话,项目启动的时候最好不要将nacos 的服务暴露在公网上,直接用docker 的网桥命名,之后再开一个私服单独启动nacos 的配置中心,因为挂载的mysql 都是同一个,所以不用担心数据不同步的问题。
mysql 创建用户:
CREATE USER '用户名' @'%' IDENTIFIED BY '密码';
mysql 数据库赋予用户权限:
GRANT SELECT, INSERT, UPDATE, DELETE ON nacos_config.* TO 'nacos' @'%';
nacos 在项目中的配置管理使用
首先pom.xml 文件中的配置引入修改,我这里用的版本是2.2.7 的,不同的项目需要注意spring cloud 的版本问题,我这里cloud 的版本是Hoxton.SR12 的。
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
<version>2.2.7.RELEASE</version>
</dependency>
maven 刷新之后,可以再将application.yml 修改为bootstrap.yml 因为在spring boot 的自动加载中后者比前者优先加载,但是要注意,还是cloud 的版本问题,2022.* 之类的版本是禁用了bootstrap.yml 的读写的,所以需要再引入一个spring boot 的bootstrap 读写的starter。
结束之后,我们就可以编写yml 中的配置信息了,还是要注意,不要复制,因为如果nacos 的starter 导入成功之后,是有提示的,如果没有则说明starter 没有导入成功。
spring:
profiles:
active: dev #版本名称
application:
name: driver # 项目名称
cloud:
nacos:
config:
server-addr: IP:8848 # nacos 的地址和端口
namespace: d2f4c55b-815c-4efa-86b2-b1ebb21b6663 # 命令空间的ID
file-extension: yaml # 配置中心对应的配置文件类型
项目中这样配置就结束了,yml 的配置还有很多其余的选择配置,但是都不是必须的,算是nacos 的功能强化,比如:扩展配置、公共配置之类的。因为nacos 上面也说了账户、密码默认都是nacos,如果修改了账户和密码的话,最好还配置一个username 和password。
如果要做nacos 配置的版本隔离的话,可以在spring.profiles.active
配置一个对应的版本,还有application.name
是一定要配置的,这个涉及到nacos 的配置文件命名。
之后就可以在nacos 的控制面板上面配置配置文件了。在nacos 的配置管理中,创建配置按钮或者+ 号按钮都能创建配置。但是要注意namespace 命名空间的选择,这里一定是要和项目中的一致。
这里的配置信息跟着下面截图的信息填就行,填好之后,一定要点击发布按钮即可。
配置可以说是相当的简单,发布之后的编辑然后再次发布的话,nacos 会给一个事件发布到spring 的多播器,然后由对应的响应逻辑修改对应的配置信息,这样也就做到了动态配置。
同时编辑的话,还可以勾选beta 发布,这样的可以做到只更新部分环境,比如上正式生产之前的灰度发布。
![image-20230426162539141](https://liwqtm-blog.oss-cn-shanghai.aliyuncs.com/blog/image-20230426162539141.png)
上述基本就结束了spring cloud 项目中的nacos 配置文件的管理。还有一点就是nacos 本身是可以集群发布的,但是访问的数据库还是同一个或高性能的集群数据库,也就是始终保持着数据的一致性,对于项目而言并没有什么区别,就是配置nacos 地址的时候配置多个而已,或者配置一个Nginx,然后再由Nginx 路由到对应的nacos。
补充一点:对于nacos 配置中心的版本控制,因为上面的是dev 所以是直接在项目中配置的spring.profiles.active
为dev,如果是别的版本,同时不修改bootstrap.yml 的情况下,可以运行时执行-Dspring.profiles.active=版本号
,比如:-Dspring.profiles.active=test
,如果是idea 启动的话可以直接编辑,如果是docker 的话,打docker 镜像的时候直接塞进去就行。
下面是docker 的配置,因为我这个项目中没有使用docker,就暂时没有配置,有兴趣的朋友可以去看我docker 文章的详情。
nacos 在项目中的服务发现使用
跟配置管理一样,先导入nacos 对应的服务发现的starter,一样是在pom.xml 文件中,这里注意一下版本。
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
<version>2.2.7.RELEASE</version>
</dependency>
然后是yml 配置,跟上面配置文件的时候一样,要注意看nacos 的starter 有没有成功导入,如果用户名和密码做了管理的话,最好配置一下。
spring:
profiles:
active: dev #版本名称
application:
name: driver # 项目名称
cloud:
nacos:
discovery:
server-addr: IP:8848 # nacos 的地址和端口
namespace: d2f4c55b-815c-4efa-86b2-b1ebb21b6663 # 命令空间的ID
最后是spring boot 的启动类配置,也就是被@SpringBootApplication 注解修饰的类,再加一个注解@EnableDiscoveryClient,用于服务发现和注册。
@SpringBootApplication
@EnableDiscoveryClient
public class DriverApplication {
public static void main(String[] args) {
SpringApplication.run(DriverApplication.class,args);
}
}
这样所有的配置就结束了,因为nacos 事先配置了namespace 命名空间,所以也不需要配置nacos 的内容,直接启动项目即可。
这里我配置了一个getway,两个driver 服务,这样可以看到两者都注入到了nacos 中,而且driver 服务还被监听到了两个注册。
总结
nacos 在cloud 项目中的配置中心和服务发现的使用基本就是上述内容了,至于nacos 的集群部署,因为我这里没有多台服务器,就不演示了,同台服务的多节点部署,nacos 的官方压缩包中就有,跟单节点部署没有太大出入。最后后续的源码流程,还有Getway 和openfeign 之前的联合调用完成流程,在后续源码解析中再说。
可。
这里我配置了一个getway,两个driver 服务,这样可以看到两者都注入到了nacos 中,而且driver 服务还被监听到了两个注册。