Nacos
Nacos(Dynamic Naming and Cofiguration Service):一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台。
Nacos = 注册中心 + 配置中心 = Eureka + Config + Bus
安装部署
从Github上下载Nacos的发行包:nacos-server-1.4.1.zip
需要的系统环境:
- 64位系统
- JDK8以上
- Maven 3.3以上
修改启动的startup.cmd文件:
默认的启动模式为集群模式,可以使用命令
startup.cmd -m standalone进入单机模式,也可以修改cmd文件中的MODE为单机模式。
rem .....rem 修改启动的模式为单机模式,默认为集群模式rem set MODE="cluster"set MODE="standalone"rem .........
执行startup.cmd启动nacos,浏览器访问:http://localhost:8848/nacos
用户名密码默认为:nacos/nacos
nacos 1.2.0以后,打开web页面直接就已经登录了nacos账户
服务注册
不同注册中心的对比
不同注册中心对比:
| 服务注册与发现框架 | CAP | 控制台管理 | 社区活跃度 |
|---|---|---|---|
| Eureka | AP | 支持 | 低 |
| ZooKeeper | CP | 不支持 | 中 |
| Consul | CP | 支持 | 高 |
| Nacos | AP + CP (一般使用AP) |
支持 | 高 |
Nacos既支持AP模型,又支持CP模型,可以进行切换:
C是所有节点在同一时间看到的数据是一致的;
A是所有的请求都会收到响应。
模式如何选择:
一般来说,如果不需要存储服务级别的信息且服务实例是通过nacos-client注册,并能够保持心跳上报,那么就可以选择AP模式。当前主流的服务如 Spring Cloud、Dubbo服务,都适用于AP模式,AP模式为了服务的可能性而减弱了一致性,因此AP模式下只支持注册临时实例。
如果需要在服务级别编辑或者存储配置信息,那么CP是必须,K8S服务和DNS服务则适用于CP模式。CP模式下支持注册持久化实例,此时是以Raft协议为集群运行模式,该模式下注册实例之前必须先注册服务,如果服务不存在则会返回错误
nacos切换模式为CP:
curl -X PUT '$NACOS_SERVER:8848/nacos/v1/ns/operator/switches?entry=serverMode&value=CP'
临时实例:
Eureka、Zookeeper
- 客户端上报健康状态
- 摘除不健康实例
- 非持久化
持久化实例:
Consul、CoreDNS
- 服务端探测健康状态
- 保留不健康实例
- 持久化 | | Nacos | Eureka | Consul | CoreDNS | Zookeeper | | —- | —- | —- | —- | —- | —- | | 一致性协议 | CP + AP | AP | CP | / | CP | | 健康检查 | TCP/HTTP/MySQL/Client_Beat | Client_Beat | TCP/HTTP/gRPC/Cmd | / | Client_Beat | | 负载均衡 | 权重/DSL/metadata/CMDB | Ribbon | Fabio | RR | / | | 雪崩保护 | 支持 | 支持 | 不支持 | 不支持 | 不支持 | | 自动注销实例 | 支持 | 支持 | 不支持 | 不支持 | 支持 | | 访问协议 | HTTP/DNS/UDP | HTTP | HTTP/DNS | DNS | TCP | | 监听支持 | 支持 | 支持 | 支持 | 不支持 | 支持 | | 多数据中心 | 支持 | 支持 | 支持 | 不支持 | 不支持 | | 跨注册中心 | 支持 | 不支持 | 支持 | 不支持 | 不支持 | | SpringCloud集成 | 支持 | 支持 | 支持 | 不支持 | 不支持 | | Dubbo集成 | 支持 | 不支持 | 不支持 | 不支持 | 支持 | | K8s继承 | 支持 | 不支持 | 支持 | 支持 | 不支持 |
服务提供者注册示例
- 在父pom中引入spring cloud alibaba的依赖管理
<dependencies> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-alibaba-dependencies</artifactId> <version>2.2.2.RELEASE</version> <type>pom</type> </dependency> </dependencies>
- 创建模块,在模块pom中加入 nacos服务发现的依赖
<dependencies> <!-- nacos服务发现依赖 --> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> </dependencies>
- 在application.yml配置文件中配置 nacos服务的地址
server: port: 9002 spring: application: name: nacos-payment-provider cloud: nacos: discovery: server-addr: localhost:8848 # Nacos地址 management: endpoints: web: exposure: include: '*'
- 在主启动类加上服务发现注解
@SpringBootApplication @EnableDiscoveryClient public class PaymentMain9001 { public static void main(String[] args) { SpringApplication.run(PaymentMain9001.class, args); } }
编写示例controller
@RestController public class PaymentController { @Value("${server.port}") private String serverPort; @GetMapping("/payment/nacos/{id}") public String getPayment(@PathVariable("id") Integer id) { return "nacos registry, serverPort: " + serverPort + "\t id: " + id; } }
- 启动项目后,在 nacos的web控制台服务列表中即可看到该服务nacos-payment-provider
service名称通过
spring.cloud.nacos.discovery.service配置,如果未配置该属性,则取spring.application.name
nacos集成了ribbon,自带负载均衡。
服务消费者示例
- 创建模块,在模块pom中加入nacos的服务发现依赖
<dependencies> <!-- nacos服务发现依赖 --> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> </dependencies>
- 修改application.yml配置文件
server: port: 83 spring: application: name: nacos-order-consumer cloud: nacos: discovery: server-addr: localhost:8848 # 自定义的变量,消费者将要去访问的微服务名称 service-url: nacos-user-service: http://nacos-payment-provider
因为nacos中加入了ribbon,所以需要创建配置类,在restTemplate中加上
@LoadBalance负载均衡注解@Configuration public class ApplicationContextConfig { @Bean @LoadBalanced public RestTemplate getRestTemplate() { return new RestTemplate(); } }
- 编写主启动类,加上服务发现注解
@SpringBootApplication @EnableDiscoveryClient public class OrderConsumer83 { public static void main(String[] args) { SpringApplication.run(OrderConsumer83.class, args); } }
编写示例controller
@RestController @Slf4j public class OrderNacosController { @Autowired private RestTemplate restTemplate; @Value("${service-url.nacos-user-service}") private String serviceURL; @GetMapping("/consumer/payment/nacos/{id}") public String paymentInfo(@PathVariable("id") Integer id) { return restTemplate.getForObject(serviceURL + "/payment/nacos/" + id, String.class); } }
配置中心
使用配置中心的配置
- 创建项目,在pom中加入nacos的服务发现依赖、配置中心依赖
<dependencies> <!-- nacos注册中心依赖 --> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId> </dependency> <!-- nacos服务发现依赖 --> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> </dependencies>
- 创建配置文件:bootstrap.yml和application.yml
nacos同springcloud-config一样,在项目初始化时,要保证先从配置中心进行配置拉取。拉取配置之后,才能保证项目的正常启动。
springboot中配置文件的加载是存在优先级顺序的,bootstrap优先级高于application。
bootstrap.yml
server:
port: 3377
spring:
application:
name: nacos-config-client # spring.application.name作为dataId的一部分
cloud:
nacos:
discovery:
server-addr: localhost:8848 # nacos服务注册中心地址
config:
server-addr: localhost:8848 # nacos配置中心地址
file-extension: yaml # 指定yaml格式的配置
application.yml
spring:
profiles:
active: dev
- 编写主启动类,添加服务发现注解
@SpringBootApplication @EnableDiscoveryClient public class NacosConfigClientMain3377 { public static void main(String[] args) { SpringApplication.run(NacosConfigClientMain3377.class, args); } }
编写controller示例
@RestController @RefreshScope // 通过Spring Cloud的 @RefreshScope注解实现配置的自动更新 public class ConfigClientController { @Value("${config.info}") private String configInfo; @GetMapping("/config/info") public String getConfigInfo() { return configInfo; } }
配置中心的配置
在 Nacos Spring Cloud中,dataId的完整格式如下:
${prefix}-${spring.profiles.active}.${file-extension}
prefix:默认为spring.application.name的值。也可以通过配置项spring.cloud.nacos.config.prefix进行配置spring.profiles.active:当前环境对应的profile。当spring.profiles.active为空时,对应的连接符-也将不存在,即dataId的格式变为${prefix}.${file-extension}file-extension:配置内容的数据格式,可以通过配置项spring.cloud.nacos.config.file-extension来配置,只支持properties和yaml类型
例如上面的示例项目中:
spring.application.name为:nacos-config-client
spring.profiles.active为:dev
spring.cloud.nacos.config.file-extension为:yaml。
则需要在nacos中的配置管理—>配置列表中添加配置:
DataId:nacos-config-client-dev.yaml
配置内容中填入相关配置,例如:
config:
info: nacos config center, version = 1
发布后,访问示例程序的controller中即可读到 config.info的值。
在nacos中修改config info的值,点击发布后, 项目不需要重启即可直接获取到最新的配置信息。
分类配置
Nacos支持基于Namespace和Group的配置分组管理,以便用户更灵活的根据自己的需要按照环境或者应用、模块等分组管理微服务以及Spring的大量配置,在配置管理中主要提供了配置历史版本、回滚、订阅者查询等核心管理能力。
Nacos 基于 Namespace(命名空间)帮助用户逻辑隔离多个命名空间,帮助用户更好的管理测试、预发、生产等多环境服务和配置,让每个环境的统一配置(如数据库数据源)可以定义不同的值。
Group和DataId逻辑上区分两个目标对象。Group可以把不同的微服务划分到同一个分组中。
Service就是微服务,一个service可有包含多个Cluster(集群),Nacos默认Cluster是DEFAULT。
Cluster是对指定微服务的一个虚拟划分。比如为了容灾,将Service分别部署在杭州机房和广州机房,就可以给杭州机房的Service起一个集群名称(HZ),给广州的Service起一个集群名称(GZ),还可以尽量让同一个机房的微服务互相调用以提升性能。
Instance就是微服务实例。
默认情况:Namespace=public,Group=DEFAULT_GROUP,默认Cluster是DEFAULT
DataID方案:
指定spring.profile.active和配置文件的DataID来使不同环境下读取不同的配置。
默认空间、默认分组情况下,创建dev和test两个DataID。
Group方案:
通过Group实现环境区分。
示例:
在Nacos的配置列表中添加两个配置:
DataID= nacos-config-client-info.yaml ,Group=DEV_GROUP
DataID= nacos-config-client-info.yaml ,Group=TEST_GROUP
在项目的bootstrap.yml中加group的配置:
spring:
cloud:
nacos:
config:
group: DEV_GROUP # 配置中心的配置分组
修改application.yaml中的环境配置:
spring:
profiles:
active: info # DataID中的环境配置
Namespace方案:
创建dev、test的Namespace,通过Namespace实现环境区分。
示例:
在Nacos的命名空间中创建两个命名空间:dev、test。
Nacos1.4之后,命名空间的ID可以自定义。之前版本的命名空间ID是自动生成的一串UUID。
到配置列表中,在对应的命名空间下添加对应的配置。
在项目的bootstrap.yml中加入命名空间的配置:
spring:
cloud:
nacos:
config:
namespace: test # 此处配置的是命名空间的ID,在旧版本的Nacos中,该ID为一串UUID
Namespace、Group、DataID可以搭配一起使用。
集群和持久化配置
架构:
默认Nacos使用嵌入式derby数据库实现数据的存储,所以如果启动多个默认配置下的Nacos节点,数据存储是存在一致性问题的。为了解决这个问题,Nacos采用了集中式存储的方式来支持集群化部署,目前只支持MySQL的存储。
Nacos支持三种部署模式:
- 单机模式:用于测试和单机使用
- 集群模式:用于生产环境,确保高可用
- 多集群模式:用于多数据中心场景
创建Mysql环境:
使用docker启动Mysql:
# 从docker官方镜像库拉取最新的 MySQL 8.0.24 的镜像
docker pull mysql
# 将镜像运行为一个容器
docker run -d -p 3306:3306 -e MYSQL_DATABASE=nacos -e MYSQL_ROOT_PASSWORD=nacos --name mysql_nacos mysql
Dbeaver连接 Mysql 8.0.24 技巧:
- 驱动的下载:
进入MySQL驱动下载官网;
操作系统选择:
Platform Independent,下载对应的压缩包跳转到登录页面后,点击下方的
No thanks, just start my download
Public Key Retrieval is not allowed报错:如果是URL访问,则在URL后面加上参数:
allowPublicKeyRetrieval=true。
使用Dbeaver访问,则在
驱动属性中将allowPublicKeyRetrieval设置为true
Nacos使用MySQL数据库做持久化:
将 conf/nacos-mysql.sql 在 mysql数据库中执行一下。
修改配置文件:conf/application.properties
放开注释并修改配置文件中的Mysql数据库配置
### If use MySQL as datasource:
spring.datasource.platform=mysql
### Count of DB:
db.num=1
### Connect URL of DB:
db.url.0=jdbc:mysql://192.168.29.131:3306/nacos?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useUnicode=true&useSSL=false&serverTimezone=UTC
db.user.0=root
db.password.0=nacos
nacos 1.4.1支持 MySQL 8+。
如果使用的低版本的nacos,需要更换nacos依赖的mysql驱动版本。
集群配置:
在Linux服务器上安装 JDK8,并配置环境变量:
rpm -ivh jdk-8u181-linux-x64.rpm
安装后的 JDK 位于:/usr/java/jdk1.8.0_181-amd64。
将nacos-server-1.4.1.tar.gz上传到服务器并解压:
tar -zxvf nacos-server-1.4.1.tar.gz
修改conf/application.properties中数据库的配置,修改为使用Mysql数据库。
将conf/cluster.conf.example 复制出一份 conf/cluster.conf,里面编写每个nacos集群节点的IP和端口号:
端口号为8848时,可以只写IP不写端口号
# 192.168.29.142:3333
# 192.168.29.142:4444
# 192.168.29.142:5555
# 一台服务器启动多个nacos比较占用内存,使用三台服务器进行启动
192.168.29.142:3333
192.168.29.143 # 端口号为8848时可以省略
192.168.29.144
此处使用单机的不同端口模拟集群环境。编辑Nacos的启动脚本 startup.sh,使它能够接受不同的启动端口:
希望达到的目标:
startup.sh -o 指定端口号即可指定端口号启动nacos
# .........
export PORT=8848 # 声明一个PORT变量
while getopts ":m:f:s:c:p:o:" opt # 此处加上一个参数o
do
case $opt in
m)
MODE=$OPTARG;;
f)
FUNCTION_MODE=$OPTARG;;
s)
SERVER=$OPTARG;;
c)
MEMBER_LIST=$OPTARG;;
p)
EMBEDDED_STORAGE=$OPTARG;;
o)
PORT=$OPTARG;; # 将参数o的值赋给 PORT 变量
?)
echo "Unknown parameter"
exit 1;;
esac
done
# .........
JAVA_OPT="${JAVA_OPT} -Dserver.port=${PORT}"
配置143服务器的Nginx负载均衡:
/usr/local/nginx/conf/nginx.conf
upstream nacoscluster {
server 192.168.29.142:3333; # 142服务器上的Nacos
server 192.168.29.143:8848; # 143服务器上的Nacos
server 192.168.29.144:8848; # 144服务器上的Nacos
}
server {
listen 8888; # Nginx的端口
server_name localhost;
location / {
#root html;
#index index.html index.htm;
proxy_pass http://nacoscluster;
}
# ......
}
启动nginx后,在浏览器访问:http://192.168.29.143:8888/nacos 即可访问Nacos;
项目中原来配置Nacos路径的位置,改为Nginx的代理路径
server:
port: 9003
spring:
application:
name: nacos-payment-provider
cloud:
nacos:
discovery:
server-addr: 192.168.29.143:8888 # nginx地址
# server-addr: localhost:8848 # Nacos地址
management:
endpoints:
web:
exposure:
include: '*'
