简介

r-nacos是一个用rust实现的nacos服务。

r-nacos是一个轻量、 快速、稳定、高性能的服务;包含注册中心、配置中心、web管理控制台功能,支持单机、集群部署。

r-nacos设计上完全兼容最新版本nacos面向client sdk 的协议(包含1.x的http OpenApi,和2.x的grpc协议), 支持使用nacos服务的应用平迁到 r-nacos。

r-nacos相较于java nacos来说,是一个提供相同功能,启动更快、占用系统资源更小、性能更高、运行更稳定的服务。

适用场景

  1. 开发测试环境使用nacos,nacos服务可以换成r-nacos。启动更快,秒启动。
  2. 个人资源云服务部署的 nacos,可以考虑换成r-nacos。资源占用率低: 包10M 出头,不依赖 JDK;运行时 cpu 小于0.5% ,小于5M(具体和实例有关)。
  3. 使用非订制nacos服务 ,希望能提升服务性能与稳定性,可以考虑迁移到 r-nacos。

功能说明

这里把 nacos 服务的功能分为三块 1、面向 SDK 的功能 2、面向控制台的功能 3、面向部署、集群的功能

每一块做一个对nacos服务的对比说明。

一、面向 SDK 的功能

访问认证:

  1. 有提供获取认证token的接口
  2. 实际请求暂不支持认证,都算认证通过。

配置中心:

  1. 支持配置中心的基础功能、支持维护配置历史记录
  2. 兼容配置中心的SDK协议
  3. 暂不支持灰度发布、暂不支持tag隔离

注册中心:

  1. 支持注册中心的基础功能
  2. 兼容配置中心的SDK协议
  3. 暂不支持1.x的 udp 实例变更实时通知,只支持 2.x 版本grpc实例变更实时通知 。最开始的版本也有支持过udp实例变更 通知,后面因支持 grpc 的两者不统一,就暂时去掉,后继可以考虑加回去。

二、面向控制台的功能

访问认证: 暂时不开启认证

命名空间:

  1. 支持管理命名空间列表
  2. 支持切换命名空间查询配置、服务数据。

配置中心:

  1. 支持配置中心信息管理
  2. 支持配置导入、导出,其文件格式与nacos兼容
  3. 支持配置历史记录查看与恢复
  4. 暂不支持tag的高级查询
  5. 暂不支持查询配置监听记录

服务中心:

  1. 支持注册中心的服务、服务实例管理
  2. 暂不支持查询监听记录

三、面向部署、集群的功能

  1. 支持单机部署
  2. 支持集群部署。集群部署配置中心数据使用raft+节点本地存储组成的分布式存储,不需要依赖mysql。具体参考 集群部署说明

快速开始

一、 安装运行 r-nacos

【单机部署】

方式1:从 github release 下载对应系统的应用包,解压后即可运行。

linux 或 mac

# 解压
tar -xvf rnacos-x86_64-apple-darwin.tar.gz
# 运行
./rnacos

windows 解压后直接运行 rnacos.exe 即可。

方式2: 通过docker 运行

#stable是最新正式版本号,也可以指定镜像版本号,如: qingpan/rnacos:v0.4.0
docker pull qingpan/rnacos:stable  
docker run --name mynacos -p 8848:8848 -p 9848:9848 -p 10848:10848 -d qingpan/rnacos:stable

docker 的容器运行目录是 /io,会从这个目录读写配置文件

docker 版本说明

应用每次打包都会同时打对应版本的docker包 ,qingpan/rnacos:$tag 。

每个版本会打两类docker包

docker包类型tag 格式示例说明
gnu debian包$versionqingpan/rnacos:v0.4.0docker包基于debian-slim,体积比较大(压缩包36M,解压后102M),运行性能相对较高;
musl alpine包$version-alpineqingpan/rnacos:v0.4.0-alpinedocker包基于alpine,体积比较小(压缩包11M,解压后34M),运行性能相对较低;

如果不观注版本,可以使用最新正式版本tag:

  • 最新的gnu正式版本: qingpan/rnacos:stable
  • 最新的alpine正式版本: qingpan/rnacos:stable-alpine

方式3:通过 cargo 编译安装

# 安装
cargo install rnacos
# 运行
rnacos

方式4: 下载源码编译运行

git clone https://github.com/heqingpan/rnacos.git
cd rnacos
cargo build --release
cargo run --release

方式5: MacOS支持通过brew安装

# 把r-nacos加入taps
brew tap r-nacos/r-nacos 

# brew 安装 r-nacos
brew install r-nacos

# 运行
rnacos

# 后续可以直接通过以下命令更新到最新版本
# brew upgrade r-nacos 

测试、试用推荐使用第1、第2种方式,直接下载就可以使用。

在linux下第1、第2种方式默认是musl版本(性能比gnu版本差一些),在生产服务对性能有要求的可以考虑使用第3、第4种在对应环境编译gnu版本部署。

启动配置可以参考: 运行参数说明

二、运行nacos 应用

服务启动后,即可运行原有的 nacos 应用。

配置中心http api例子

# 设置配置
curl -X POST 'http://127.0.0.1:8848/nacos/v1/cs/configs' -d 'dataId=t001&group=foo&content=contentTest'

# 查询
curl 'http://127.0.0.1:8848/nacos/v1/cs/configs?dataId=t001&group=foo'

注册中心http api例子

# 注册服务实例
curl -X POST 'http://127.0.0.1:8848/nacos/v1/ns/instance' -d 'port=8000&healthy=true&ip=192.168.1.11&weight=1.0&serviceName=nacos.test.001&groupName=foo&metadata={"app":"foo","id":"001"}'

curl -X POST 'http://127.0.0.1:8848/nacos/v1/ns/instance' -d 'port=8000&healthy=true&ip=192.168.1.12&weight=1.0&serviceName=nacos.test.001&groupName=foo&metadata={"app":"foo","id":"002"}'

 curl -X POST 'http://127.0.0.1:8848/nacos/v1/ns/instance' -d 'port=8000&healthy=true&ip=192.168.1.13&weight=1.0&serviceName=nacos.test.001&groupName=foo&metadata={"app":"foo","id":"003"}'

# 查询服务实例

curl "http://127.0.0.1:8848/nacos/v1/ns/instance/list?&namespaceId=public&serviceName=foo%40%40nacos.test.001&groupName=foo&clusters=&healthyOnly=true"

具体的用法参考 nacos.io 的用户指南。

JAVA-SDK

其它语言

open-api

三、使用r-nacos控制台

从0.4.0版本开始,支持独立端口号的新控制台。新控制台有完备的用户管理、登陆校验、权限控制,支持对外网暴露。

启动服务后可以在浏览器通过 http://127.0.0.1:10848/rnacos/ 访问r-nacos新控制台。

老控制台http://127.0.0.1:8848/rnacos/ 标记废弃,默认不开启,可通过配置开启。老控制台不需要登陆鉴权、不支持用户管理。

主要包含用户管理、命名空间管理、配置管理、服务管理、服务实例管理。

1、用户登陆

在新控制台打开一个地址,如果检测到没有登陆,会自动跳转到登陆页面。 一个用户连续登陆失败5次,会被锁定1个小时。这个次数可以通过启动参数配置。

2、用户管理

系统会默认创建一个名为admin的用户,密码为admin(也可以通过环境变量 RNACOS_INIT_ADMIN_USERNAME 和 RNACOS_INIT_ADMIN_PASSWORD 修改默认账号的账户名和密码)。

进去控制台后可按需管理用户。

用户角色权限说明:

  1. 管理员: 所有控制台权限
  2. 开发者:除了用户管理的所有控制台权限
  3. 访客:只能查询配置中心与注册中心的数据,没有编辑权限。

注意: 对外暴露的nacos控制台端口前,建议增加一个自定义管理员,把admin用户删除或禁用。

3、配置管理

配置列表管理

新建、编辑配置

4、服务列表管理

5、服务实例管理

6、命名空间管理

集群部署

r-nacos 在v0.3.0版本后支持集群部署。

集群功能机制简介

集群部署的目标是通过多实例部署的方式,支持服务的水平扩容,支持部分节点异常后继续提供服务,提升稳定性。

配置中心

配置中心使用raft集群协议+本地存储,持久化数据,不需要再依赖 mysql 存储配置。其持久化机制类似etcd

请求方式说明性能
写入只有主节点能写入,其它节点收到写入请求后转发到主节点写入集群2千tps左右,有优化空间
读取每个节点都能读取全量数据单节点8万qps左右,集群总容量为n*8万

注册中心

注册中心使用类distor协议,同步集群间的数据。

注册中心复用配置中心节点列表信息,两者协议是分别单独实现的。

请求方式说明性能
写入注册中心每个节点平等,按hash划分每个节点负责的内容;节点对负责的服务可写,否则转发到对应负责的节点处理。集群1万tps左右
读取每个节点都能读取全量数据单节点3万qps左右,集群总容量为n*3万

集群部署

集群部署和单机部署步骤一致,只是对应的运行参数不同,增加了集群节点的配置。

一、取得r-nacos安装包

安装包的获取方式与 快速开始一致

二、配置集群规则

集群部署相关的配置参数有四个:RNACOS_RAFT_NODE_ID,RNACOS_RAFT_NODE_ADDR,RNACOS_RAFT_AUTO_INIT,RNACOS_RAFT_JOIN_ADDR。

具体参数说明参考 运行参数说明

集群配置规则:

  1. 所有的集群节点都需要设置RNACOS_RAFT_NODE_ID,RNACOS_RAFT_NODE_ADDR ,其中不同节点的node_id和 node_addr不能相同;node_id为一个正整数,node_addr为ip:grpc_port
  2. 集群主节点: 初始设置RNACOS_RAFT_AUTO_INIT为true (如果节点为1,默认是 true,不用额外设置)。
  3. 集群从节点: 初始设置RNACOS_RAFT_AUTO_INIT为false (节点非1,默认就是false,不用额外设置);另外需要设置RNACOS_RAFT_JOIN_ADDR为当前主节点的地址,以方便启动时自动加入集群中。
  4. 第2、3点只是为了初始化组建集群。集群运行起来之后,后继启动配置从raft db中加载。
  5. 集群节点数量不要求,可以是1、2、3、4、... ; 不过raft协议只支持小于集群半数节点异常后继续提供写入服务(查询不影响)。例如:3个节点集群支持1个节点异常后提供写入服务,2个节点集群可以正常运行,不支持节点异常后提供服务。
  6. 从节点可以在使用过程中按需加入。比如原来3个节点,可能在使用一段时间后增加2个节点扩容。

实例:规划集群节点信息并编写对应的配置文件

按上面的配置规则,下面我们配置一个3节点集群例子。

初始化节信息

  1. 主节点id为1,地址为127.0.0.1:9848
  2. 第一个从节点id为2,地址为127.0.0.1:9849
  3. 第二个从节点id为3,地址为127.0.0.1:9849

正式集群部署的log等级建议设置为warn,不打正常的请求日志,只打报警或异常日志,减少日志量。

配置信息如下

env01

#file:env01 , Initialize with the leader node role
RUST_LOG=warn
#RNACOS_INIT_ADMIN_USERNAME=admin
#RNACOS_INIT_ADMIN_PASSWORD=admin
RNACOS_HTTP_PORT=8848
RNACOS_RAFT_NODE_ADDR=127.0.0.1:9848
RNACOS_CONFIG_DB_DIR=db01
RNACOS_RAFT_NODE_ID=1
RNACOS_RAFT_AUTO_INIT=true

env02:

#file:env02 , Initialize with the follower node role
RUST_LOG=warn
#RNACOS_INIT_ADMIN_USERNAME=admin
#RNACOS_INIT_ADMIN_PASSWORD=admin
RNACOS_HTTP_PORT=8849
RNACOS_RAFT_NODE_ADDR=127.0.0.1:9849
RNACOS_CONFIG_DB_DIR=db02
RNACOS_RAFT_NODE_ID=2
RNACOS_RAFT_JOIN_ADDR=127.0.0.1:9848

env03:

#file:env03 , Initialize with the follower node role
RUST_LOG=warn
#RNACOS_INIT_ADMIN_USERNAME=admin
#RNACOS_INIT_ADMIN_PASSWORD=admin
RNACOS_HTTP_PORT=8850
RNACOS_RAFT_NODE_ADDR=127.0.0.1:9850
RNACOS_CONFIG_DB_DIR=db03
RNACOS_RAFT_NODE_ID=3
RNACOS_RAFT_JOIN_ADDR=127.0.0.1:9848

注: 上面的地址是本机运行多实例的地址,实际使用时换成具体的服务ip和port即可。

三、启动集群

第一次启动

分别运行三个节点,需要先运行主节点成功后再运行

先运行主节点

nohup ./rnacos -e env01 > n01.log &

主节点功能启动后,再运行从节点

nohup ./rnacos -e env02 > n02.log &
nohup ./rnacos -e env03 > n03.log &

实例过程中不同的节点需要在不同的服务器运行服务。

集群重启

节点重启和第一次启动的配置和启动方式不变。

集群启动后,集群的节点信息已久化节点本地数据库中。 在节点重启时后直接从本地数据库加载集群节点的信息。这时就不需要读取需要加入的集群地址,RNACOS_RAFT_JOIN_ADDR不会再被使用(留在配置中也不影响)。

部分节点重启,在重启一个心跳时间(0.5秒)就会被重新加入集群。

全部节点重启, raft需要启动静默5秒+选举超时3秒后才重新选举主节点;10秒左右集群才提供配置写入服务。 期间配置查询,和注册中心的读写可以正常使用。

四、运行应用使用集群

集群服务启动后,即可运行原有的 nacos 应用。

配置中心http api例子

echo "\npublish config t001:contentTest to node 1"
curl -X POST 'http://127.0.0.1:8848/nacos/v1/cs/configs' -d 'dataId=t001&group=foo&content=contentTest'
sleep 1

echo "\nget config info t001 from node 1, value:"
curl 'http://127.0.0.1:8848/nacos/v1/cs/configs?dataId=t001&group=foo'

echo "\nget config info t001 from node 2, value:"
curl 'http://127.0.0.1:8849/nacos/v1/cs/configs?dataId=t001&group=foo'

echo "\nget config info t001 from node 3, value:"
curl 'http://127.0.0.1:8850/nacos/v1/cs/configs?dataId=t001&group=foo'
sleep 1

echo "\npublish config t002:contentTest02 to node 2"
curl -X POST 'http://127.0.0.1:8849/nacos/v1/cs/configs' -d 'dataId=t002&group=foo&content=contentTest02'
sleep 1

echo "\nget config info t002 from node 1, value:"
curl 'http://127.0.0.1:8848/nacos/v1/cs/configs?dataId=t002&group=foo'

echo "\nget config info t002 from node 2, value:"
curl 'http://127.0.0.1:8849/nacos/v1/cs/configs?dataId=t002&group=foo'

echo "\nget config info t002 from node 3, value:"
curl 'http://127.0.0.1:8850/nacos/v1/cs/configs?dataId=t002&group=foo'

注册中心http api例子

echo "\nregister instance nacos.test.001 to node 1"
curl -X POST 'http://127.0.0.1:8848/nacos/v1/ns/instance' -d 'port=8000&healthy=true&ip=192.168.1.11&weight=1.0&serviceName=nacos.test.001&groupName=foo&metadata={"app":"foo","id":"001"}'
echo "\nregister instance nacos.test.001 to node 2"
curl -X POST 'http://127.0.0.1:8849/nacos/v1/ns/instance' -d 'port=8000&healthy=true&ip=192.168.1.12&weight=1.0&serviceName=nacos.test.001&groupName=foo&metadata={"app":"foo","id":"002"}'
echo "\nregister instance nacos.test.001 to node 3"
curl -X POST 'http://127.0.0.1:8850/nacos/v1/ns/instance' -d 'port=8000&healthy=true&ip=192.168.1.13&weight=1.0&serviceName=nacos.test.001&groupName=foo&metadata={"app":"foo","id":"003"}'
sleep 1
echo "\n\nquery service instance nacos.test.001 from node 1, value:"
curl "http://127.0.0.1:8848/nacos/v1/ns/instance/list?&namespaceId=public&serviceName=foo%40%40nacos.test.001&groupName=foo&clusters=&healthyOnly=true"
echo "\n\nquery service instance nacos.test.001 from node 2, value:"
curl "http://127.0.0.1:8849/nacos/v1/ns/instance/list?&namespaceId=public&serviceName=foo%40%40nacos.test.001&groupName=foo&clusters=&healthyOnly=true"
echo "\n\nquery service instance nacos.test.001 from node 3, value:"
curl "http://127.0.0.1:8850/nacos/v1/ns/instance/list?&namespaceId=public&serviceName=foo%40%40nacos.test.001&groupName=foo&clusters=&healthyOnly=true"
echo "\n"

如果在本地源码编译,可使用或参考test_cluster.sh 创建、测试集群。

具体的用法参考 nacos.io 的用户指南。

JAVA-SDK

其它语言

open-api

集群管理工具

通过控制台查看集群状态

在控制台页面主要观注集群节点列表状态与raft主角点是否正常

通过接口查看集群状态

  1. 查询指定节点的raft 集群状态
curl "http://127.0.0.1:8848/nacos/v1/raft/metrics"
# {"id":1,"state":"Leader","current_term":1,"last_log_index":10,"last_applied":10,"current_leader":1,"membership_config":{"members":[1,2,3],"members_after_consensus":null}}
# 主要关注 current_leader和members
  1. 增加节点
curl -X POST "http://127.0.0.1:8848/nacos/v1/raft/add-learner" -H "Content-Type: application/json" -d '[2, "127.0.0.1:9849"]'

推荐通过启动新节点时设置RNACOS_RAFT_JOIN_ADDR加入集群。 如果配置时主节点不确定,可以启动后再调用主节点接口把新节点加入集群。

此接口也可以用于在集群运行期更新集群节点地址。

  1. 更新集群节点列表
curl -X POST "http://127.0.0.1:8848/nacos/v1/raft/change-membership" -H "Content-Type: application/json" -d '[1, 2, 3]'

如果通过手动方式增加节点,需要调用本接口更新集群节点列表。

此接口可以用于对集群缩容,下线指定节点。

附录介绍

rnacos实现raft和类distro协议,支持集群部署

部署参数说明

同一个应用包需要支持不同场景,就需要支持设置自定义参数。

r-nacos 运行参数支持通过环境变量,或指定配置文件方式设置。 如果不设置则按默认参数运行。

设置运行参数的方式

通过环境变更设置参数

例子:

RNACOS_HTTP_PORT=8848 ./rnacos

这种方式在自定义少量参数时比较方便

通过指定配置文件方式设置参数

例子

# 从0.3.0版本开始支持 -e env_file 运行参数
./rnacos -e env_file

如果不指定文件时也会尝试从当前目录下.env文件加载配置参数

env_file内容的格式是

KEY1=VALUE1
KEY2=VALUE2
KEY3=VALUE3

rnacos 运行时支持的环境变量,如果不设置则按默认配置运行。

运行参数说明

参数KEY内容描述默认值示例开始支持的版本
RNACOS_HTTP_PORTrnacos监听http端口884888480.1.x
RNACOS_GRPC_PORTrnacos监听grpc端口默认是 HTTP端口+100098480.1.x
RNACOS_HTTP_CONSOLE_PORTr-nacos独立控制台端口默认是 HTTP端口+2000;设置为0可不开启独立控制台108480.4.x
RNACOS_CONSOLE_LOGIN_ONE_HOUR_LIMITr-nacos控制台登录1小时失败次数限制默认是5,一个用户连续登陆失败5次,会被锁定1个小时50.4.x
RNACOS_HTTP_WORKERShttp工作线程数cpu核数80.1.x
RNACOS_CONFIG_DB_FILE配置中心的本地数据库文件地址【0.2.x后不在使用】config.dbconfig.db0.1.x
RNACOS_CONFIG_DB_DIR配置中心的本地数据库文件夹, 会在系统运行时自动创建【因语义原因,v0.6.x后推荐使用RNACOS_DATA_DIR】nacos_dbnacos_db0.2.x
RNACOS_DATA_DIR本地数据库文件夹, 会在系统运行时自动创建【与RNACOS_CONFIG_DB_DIR等价,用于替代RNACOS_CONFIG_DB_DIR】linux,MacOS默认为~/.local/share/r-nacos/nacos_db;windows,docker默认为nacos_dbnacos_db0.6.x
RNACOS_RAFT_NODE_ID节点id110.3.0
RNACOS_RAFT_NODE_ADDR节点地址Ip:GrpcPort,单节点运行时每次启动都会生效;多节点集群部署时,只取加入集群时配置的值127.0.0.1:GrpcPort127.0.0.1:98480.3.0
RNACOS_RAFT_AUTO_INIT是否当做主节点初始化,(只在每一次启动时生效)节点1时默认为true,节点非1时为falsetrue0.3.0
RNACOS_RAFT_JOIN_ADDR是否当做节点加入对应的主节点,LeaderIp:GrpcPort;只在第一次启动时生效127.0.0.1:98480.3.0
RNACOS_RAFT_SNAPSHOT_LOG_SIZEraft打包snapshot镜像的日志数量;即变更日志超过这个值则会触发一次打包镜像默认值10000100000.5.0
RUST_LOG日志等级:debug,info,warn,error;所有http,grpc请求都会打info日志,如果不观注可以设置为error减少日志量infoerror0.3.0
RNACOS_ENABLE_NO_AUTH_CONSOLE是否开启无鉴权控制台falsefalse0.5.2
RNACOS_CONSOLE_LOGIN_TIMEOUT控制台登陆有效时长(单位为秒)一天,86400秒864000.5.0
RNACOS_GMT_OFFSET_HOURS日志时间的时区,单位小时;默认为本机时区,运行在docker时需要指定local8(东8区),-5(西5区)0.5.7
RNACOS_ENABLE_OPEN_API_AUTH是否对openapi开启鉴权;(注:nacos切换到r-nacos过程中不要开启鉴权)falsetrue0.5.8
RNACOS_API_LOGIN_TIMEOUTopen api鉴权有效时长,单位为秒;(注:从不鉴权到开启鉴权,需要间隔对应时长以保证客户端token能更新生效)一小时,3600秒36000.5.8
RNACOS_CLUSTER_TOKEN集群间的通信请求校验token,空表示不开启校验,设置后只有相同token的节点间才可通讯空字符串1234567890abcdefg0.5.8
RNACOS_INIT_ADMIN_USERNAME初始化管理员用户名,只在主节点第一次启动时生效adminrnacos0.5.11
RNACOS_INIT_ADMIN_PASSWORD初始化管理员密码,只在主节点第一次启动时生效adminrnacos1234560.5.11
RNACOS_ENABLE_METRICS是否开启监控指标功能truetrue0.5.13
RNACOS_METRICS_LOG_INTERVAL_SECOND监控指标采集打印到日志的间隔,单位秒,最小间隔为5秒30100.5.13
RNACOS_CONSOLE_ENABLE_CAPTCHA验证码的开关truetrue0.5.14

注:从v0.3.0开始,默认参数启动的节点会被当做只有一个节点,当前节点是主节点的集群部署。支持其它新增的从节点加入。

性能与容量说明

压测工具

主要使用goose压测。

参考项目中的子工程 loadtest

性能压测结果

模块场景单节点qps/tps集群qps/tps总结/备注
配置中心配置写入,http协议1.76万7.6千集群写入压测是在同一台电脑运行3个节点,如果换成多个机器部署,tps应该还能有所提升。
配置中心配置查询,http协议8万n*8万集群的查询总qps是节点的倍数
注册中心服务实例注册,http协议4.8万2.4万集群写入压测是在同一台电脑运行3个节点,如果换成多个机器部署,tps应该还能有所提升。
注册中心服务实例注册,grpc协议4.8万2.4万grpc协议压测工具没有支持,目前没有实际压测,理论不会比http协议低
注册中心服务实例心跳,http协议4.8万2.4万心跳是按实例计算和服务实例注册一致共享qps
注册中心服务实例心跳,grpc协议8万以上n*8万心跳是按请求链接计算,且不过注册中心处理线程,每个节点只需管理当前节点的心跳,集群总心跳qps是节点的倍数
注册中心查询服务实例3万n*3万集群的查询总qps是节点的倍数

注: 具体结果和压测环境有关

压测记录

注册中心查询:

配置中心查询,两个进程分别限流4万qps同时压测(共8万qps),其中一个的压测记录:

容量分析

配置中心

  1. 配置中心的单机查询8万qps,很高,又支持水平扩容;集群基本没有查询瓶颈。
  2. 配置中心所占用的内存和配置内存有关,在内存没有满前,基本没有瓶颈。
  3. 配置中心集群写入时统一在主节点写入,写入可能有瓶颈;目前1.5千tps,后面优化后应该能到1万 tps以上。

注册中心

  1. 注册中心的单机查询3万qps,比较高,又支持水平扩容;集群基本没有查询瓶颈。
  2. 注册中心所占用的内存和配置内存有关,在内存没有满前,基本没有瓶颈。
  3. 注册中心集群写入时每个节点都要写一遍,整体集群的写入性能tps和单机理论上相当。
  4. http协议(v1.x版本)和grpc协议(v2.x)的心跳维护机制不同;http心跳是按实例计算和服务实例注册一致共享qps, grpc的心跳是按请求链接计算且不过注册中心处理线程。所有这类协议理论支持的容量差别很大。

注册中心集群注册容量推理

  1. http协议注册+心跳qps是1万,每个实例5秒钟一次心跳;理论上只能支持5万服务实例左右。
  2. grpc协议,注册qps假设也是1万,心跳qps单实例8万,3节点集群总心跳24万;如果平均一个应用实例1小时重连一次;支持注册的服务实例总数为:606010000 = 3600万,心跳支持的链接实例总数为:5*24万=120万个链接实例(和集群节点有关)。

结论: 如果使用v1.0x http协议,支持的实例在5万个左右。 如果使用v2.0x grpc协议,理论上基本没有瓶颈。


r-nacos与java nacos性能压测对比 (单机模式)

旧版本的单机压测记录,有和java 版本nacos的比较.

压测环境与工具

压测环境:macos i7四核 /16G , 施压、受压机器是同一台机器(会拉低压测结果)。 压测工具: * wrk ,qps: 24450左右 * goose, qps 17000左右 (单进程加限流施压比 wrk低) * 单进程施压请求wrk比goose 输出高

r-nacos server版本:v0.1.1 java nacos server版本: 2.1.0

因wrk,goose暂时不支持grpc协议,暂时只压测http协议接口

配置中心

配置中心,不会频繁更新,写入不做压测。

rust r-nacos server:

  1. 配置中心单机查询 wrk 压测 qps 在2.4万左右.

java nacos server:

  1. 配置中心单机查询 wrk 压测, qps 在7700左右

注册中心

rust r-nacos server:

  1. naming 注册1000 x 1个实例,每秒200qps,单核cpu: 4.5% 左右
  2. naming 单查询1.5万 QPS 左右
    1. wrk 查询单个服务 ,1.65万 qps
    2. goose 查询1000个服务 ,1.5万 qps
  3. naming 单注册服务
    1. goose,5万到7万实例数 0.7万 qps左右。
  4. 查询与注册混合
    1. wrk 查询单个服务(1.5万 qps) + goose 注册(0.075 万qps) 【5千实例】
    2. goose 查询1000个服务(1.3万 qps) + goose 注册(0.07万 qps) 【5千实例】
    3. wrk 查询单个服务(1.5万 qps) + goose 注册(0.15万qps) 【1万实例】
    4. goose 查询1000个服务(1.3万 qps) + goose 注册(0.13万 qps) 【1万实例】

java nacos server:

  1. 配置中心查询 wrk 压测, 7700 qps 左右
  2. naming 注册1000 x 1个实例,每秒200qps,单核cpu: 17% 左右
  3. naming 单查询
    1. wrk 查询单个服务 ,1.35万 qps 。
    2. goose 查询1000个服务,1万 qps(前期应该还能上去一些)。前30秒能稳定在1万左右,30秒后,跌到200左右之后再上下浮动,可能受 GC 影响。
  4. naming 单注册
    1. goose,5万到7万实例数 0.45万 qps左右。
  5. 查询与注册混合
    1. wrk 查询单个服务(1.3万 qps) + goose 注册(0.07 万qps) 【5千实例】
    2. goose 查询1000个服务(1万 qps) + goose 注册(0.07万 qps) 【5千实例】; 前期能保持,后期 qps 上下浮动比较大,最低小于50。
    3. wrk 查询单个服务(0.9万 qps) + goose 注册(0.12万qps) 【1万实例】
    4. goose 查询1000个服务(0.6万 qps) + goose 注册(0.08万 qps) 【1万实例】

性能压测总结

  1. r-nacos,除了服务服务注册不能稳定在1万以上,其它的接口qps都能稳定在1万以上。

  2. java 的查询接口基本能压到1万以上,但不平稳,后继浮动比较大。如果降低压测流程,qps 可以相对平稳。

  3. 在多服务查询叠加上多服务注册场景,r-nacos qps能稳定在1.3万左右, java nacos qps 下降明显在0.6万左右。

  4. r-nacos 综合 qps是 java版的2倍以上,因 java 有 GC,qps水位稳定性上 java较差(相同施压流量,qps 能从峰值1万能降到1百以下)。

  5. r-nacos 服务,线程数稳定在7,cpu 用例率最大200%左右(相当用个2核),内存在50M 以下

  6. java nacos 服务,线程数最大300左右, cpu 用例率最大500%左右,内存600M到900M。

版本说明

R-NACOS版本说明

版本对nacos兼容说明版本特点说明适用场景
v0.3.3以上支持2.x新最版nacos面向sdk的协议支持集群部署版本,使用1个节点的集群方式当做单机模式,配置中心raft 协议没有充分优化,配置中心集群写入tps在1.5千左右对配置中心没有太高频写入需求的应用都推荐使用这个版本 (后面会优化配置写入性能)
v0.2.3 (不再推荐,新版bugfix暂定不再同步)支持2.x新最版nacos面向sdk的协议单机部署版本,配置中心数据库使用sled, 初始内存多占用25M左右,配置中心单机写入tps在1.5万以上对配置中心有高频写入需求的应用可以考虑使用
v0.1.10 (不再推荐,新版bugfix暂定不再同步)支持1.x服务接口;除了查询服务中心服务列表外,支持2.x大部分接口单机部署版本,配置中心数据库使用sqlite,内存占用比较低,但配置写入tps不高,7百左右不使用2.x的注册中心服务,对内存占用敏感的小应用可以考虑使用

docker 版本说明

应用每次打包都会同时打对应版本的docker包 ,qingpan/rnacos:$tag 。

每个版本会打两类docker包

docker包类型tag 格式示例说明
gnu debian包$versionqingpan/rnacos:v0.4.2docker包基于debian-slim,体积比较大(压缩包36M,解压后102M),运行性能相对较高
musl alpine包$version-alpineqingpan/rnacos:v0.4.2-alpinedocker包基于alpine,体积比较小(压缩包11M,解压后34M),运行性能相对较低

如果不关注版本,可以使用最新正式版本tag。

  • 最新的gnu正式版本: qingpan/rnacos:stable
  • 最新的alpine正式版本: qingpan/rnacos:stable-alpine

MacOS arm系统补充说明 :目前MacOS arm系统运行stable镜像失败,可以先换成stable-alpine镜像。等后面解决arm stable镜像问题后再把这个注意事项去掉。

nacos client sdk

java nacos sdk

nacos-client

<dependency>
    <groupId>com.alibaba.nacos</groupId>
    <artifactId>nacos-client</artifactId>
    <version>${nacos.version}</version>
</dependency>
协议验证过版本推荐版本
grpc协议(2.x)2.1.0>2.1.x
http协议(1.x)1.4.1>1.4.x

go nacos sdk

nacos-sdk-go

nacos-sdk-go/v2 v2.2.5
协议验证过版本推荐版本
grpc协议(2.x)2.2.5>=2.2.5

rust nacos sdk

nacos-sdk-rust

nacos-sdk = "0.3.3"
协议验证过版本推荐版本
grpc协议0.3.3>=0.3.3

nacos_rust_client

nacos_rust_client = "0.3.0"
协议验证过版本推荐版本
同时支持http协议与grpc协议0.3.0>=0.3.0
http协议0.2.2>=0.2.2

常见问题

控制台查询不到信息

控制台查询配置信息,是按命名空间作隔离的。

要先确认创建的命名空间与控制台查询的命名空间是否一致。

如果不一致,先在命令空间管理页面维护对应的命名空间,再到配置列表或服务列表切换到对应名命空间查询。

架构

r-nacos架构图

架构图

说明:

  • r-nacos默认支持集群部署,单机就相当于一个节点的集群,后续有需要可以按需加入新的节点;
  • 数据持久化使用raft协议分布式数据库(raft协议+节点文件存储),类似etcd;
  • 只需对RNACOS_CONFIG_DB_DIR:nacos_db目录下的文件备份与恢复,即可实现数据的备份与恢复;
  • r-nacos控制台使用前后端分离架构;前端应用因依赖nodejs,所以单独放到另一个项目 r-nacos-console-web ,再通过cargo 把打包好的前端资源引入到本项目,避免开发rust时还要依赖nodejs。

多实例的raft和distro分布式协议说明待补充

配置中心

配置模型图

配置中心raft协议

raft协议的主要逻辑:

  1. 节点区分角色:leader(主节点),follower(从节点),candidate(选举节点);
  2. 稳定状态是一个主节点,多个从节点;
  3. 主节点负责写入,写入时需要先把写入日志同步到其它节点,超过半数节点写入日志成功后才能提交日志到状态机。
  4. 主节点需要定时发心跳到从节点,从节点如果超时未收到心跳,则会发起选举。选举时收到超过半数节点的同意,就可以切换成主节点。

具体协议可以参考 raft协议论文

r-nacos 接入 raft的主要逻辑:

  1. 基于 async-raft 库实现raft协议,主要实现网络层和存储层。在 r-nacos中存储层的状态机就是配置中心。
  2. 配置中心接入raft 协议的状态机,由 raft 状态机驱动更新配置中心的内容。

r-nacos一个三节点的配置中心请求处理示例:

写入:

  1. 客户端随机向一个节点发起一个更新配置请求
  2. 在请求入口层加一个raft路由判断,如果本节点是主节点则处理,否则路由到指定主节点处理
  3. 主节点写入请求到raft日志
  4. 将请求同步到其它从节点
  5. 如果超过半数节点写入日志成功(包含自身),则提交请求日志到状态机中,配置写入配置中心。(其它从节点的提交在下次日志同步或心跳时提交)
  6. 返回处理结果

请求:

  1. 客户端随机向一个节点发起一个查询配置请求
  2. 收到请求的节点和单机处理一样,直接查询本节点配置中心数据返回。

注册中心类distro协议

协议主要逻辑:

  1. 每个节点有全量的数据,都可提供注册信息查询服务。
  2. 注册中心每个节点平等,按hash划分每个节点负责的内容;节点对负责的服务可写,否则转发到对应负责的节点处理。
  3. 通过 grpc协议注册的服务,接收的节点直接处理。
  4. 一个节点更新服务实例信息后再同步给其它节点。

具体协议可以参考java nacos 的distro协议实现 。 r-nacos 和 java版主体逻辑相同,但实现的细节有些区别。

r-nacos一个三节点的注册中心请求处理示例:

http 写入:

  1. 客户端随机向一个节点发起一个注册服务实例请求
  2. 请求跳过服务路由判断,如果服务路由的节点是本节点则处理,否则路由到指定的其它节点处理
  3. 收到本节点负责的服务实例请求,把请求注册到注册中心中
  4. 返回处理结果
  5. 异步同步更新的数据到其它节点

grpc 写入(不路由,本节点直接处理):

  1. 客户端随机向一个节点发起grpc长链接
  2. 客户端发起一个注册服务实例请求
  3. 像单机一样,把请求注册到注册中心中
  4. 返回处理结果
  5. 异步同步更新的数据到其它节点

查询:

  1. 客户端随机向一个节点发起一个查询服务信息请求
  2. 收到请求的节点和单机处理一样,直接查询本节点注册中心数据返回。

为什么http的写入与grpc写入的路由逻辑不同?

因为grpc的心跳是按长链接来处理,一个客户端的链接段开,则这个链接的所用请求都失效。【高效】

然后http的实例注册是无状态的,只能通过定时器按注册时间更新实例的状态;同时注册中心中实例是按服务分类维护的。 所以http注册的实例需要按服务做路由,这样才能支持不同的节点负责不同范围的服务。【低效】

所以在注册中心使用grpc协议的性能会比http协议性能好很多。

待补充...

控制台接口

全局说明

公共对象

通用返回值

{
    "success": boolean, //调用结果是否成功
    "data: object, //返回对像
    "code": string, //返回的错误码,在success为false时有值
    "message": string , //返回的错误信息,在success为false时有值
}

通用分页对像

{
    "totalCount": int, //总记录数
    "list": [], //本次分页查询结果列表
}

对应的分页查询返回值为

{
    "success": boolean, //调用结果是否成功
    "data: {
        "totalCount": int, //总记录数
        "list": [], //本次分页查询结果列表
    },
    "code": string, //返回的错误码,在success为false时有值
    "message": string , //返回的错误信息,在success为false时有值
}

特殊错误码定义

错误码错误信息备注
SYSTEM_ERROR系统错误未明确的系统错误
NO_LOGIN用户没有登陆需要跳转到登陆页
NO_PERMISSION用户没有权限
CAPTCHA_CHECK_ERROR验证码校验不通过
LOGIN_LIMITE_ERROR用户频繁密码校验不通过被限制登陆

其它

重构后规范化的接口都放到/rnacos/api/console/v2/

接口

1. 登陆模块

登陆接口

'''

'''