rnacos是一个用 rust 实现的 nacos 服务。
rnacos 是一个轻量、 快速、稳定、高性能的服务;包含注册中心、配置中心、web 管理控制台功能,支持单机、集群部署。
rnacos 设计上完全兼容最新版本 nacos 面向 client sdk 的协议(包含 1.x 的 http OpenApi ,和 2.x 的 grpc 协议), 支持使用 nacos 服务的应用平迁到 rnacos 。
rnacos 相较于 java nacos 来说,是一个提供相同功能,启动更快、占用系统资源更小、性能更高、运行更稳定的服务。
rnacos 之前只支持单机部署,不能水平扩容,同时存在单点稳定性问题,不太合适用于生产环境。所以 rnacos 一直有计划开发支持集群部署的功能。
目前 rnacos 0.3.1 版本已支持集群部署。其中配置中心通过 raft 协议支持集群部署,注册中心通过类 distro 协议支持集群部署。
rnacos 主要功能模块:
主要因为配置中心和注册中心的特点不一样。
配置中心的数据需要持久化,在多个服务节点中的数据需要强一致,raft 是一个逻辑完备的分页式共识协议。实现 raft 协议只要大于半数的节点正常,就可以正常提供服务。 同时实例 raft 协议就相当于实现一个分页式存储,配置中心可以不需要额外依赖 mysql 等外部数据库,部署依赖更简单。 所以配置中心选择通过 raft 协议支持集群部署。
注册中心的数据主要是临时的服务实例数据,这类数据不需要持久化,不追求多个服务节点中的数据强一致。同时注册中心更关注在部分节点异常时能提供完整的服务,更观注集群的读写性能。所以注册中心不选择 raft 协议,而是通过类 distro 协议支持集群部署。
现在模块协议的对比:
模块 | 协议 | 写性能 | 读性能 | 数据一致性 | 容错率 |
---|---|---|---|---|---|
配置中心 | raft | 一般(只有主节点可写) | 高,每个节点都可读 | 强一致 | 一般,大于半数节点正常则可以正常提供服务 |
注册中心 | raft | 高(每个节点都可写) | 高,每个节点都可读 | 一般 | 高,一个节点能不依赖其它依赖提供服务 |
raft 协议的主要逻辑:
具体协议可以参考 raft 协议论文
rnacos 接入 raft 的主要逻辑:
rnacos 一个三节点的配置中心请求处理示例:
写入:
请求:
协议主要逻辑:
具体协议可以参考 java nacos 的 distro 协议实现 。 rnacos 和 java 版主体逻辑相同,但实现的细节有些区别。
rnacos 一个三节点的注册中心请求处理示例:
http 写入:
grpc 写入(不路由,本节点直接处理):
查询:
因为 grpc 的心跳是按长链接来处理,一个客户端的链接段开,则这个链接的所用请求都失效。 [高效] 然后 http 的实例注册是无状态的,只能通过定时器按注册时间更新实例的状态;同时注册中心中实例是按服务分类维护的,所以 http 注册的实例需要按服务做路由,这样才能支持不同的节点负责不同范围的服务。 [低效]
所以在注册中心使用 grpc 协议的性能会比 http 协议性能好很多。
rnacos 支持集群后其性能与容量的水位是怎样的呢?
下面给出一组在我台式电脑(8 核 16 线程+16 内存)的压测性能对比数据.
主要使用 goose 压测,具体可以参考项目中的子压测工程 loadtest
模块 | 场景 | 单节点 qps | 集群 qps | 总结 |
---|---|---|---|---|
配置中心 | 配置写入,单机模式 | 1.5 万 | 1.5 万 | |
配置中心 | 配置写入,集群模式 | 1.8 千 | 1.5 千 | 接入 raft 后没有充分优化,待优化,理论上可接近单机模式 |
配置中心 | 配置查询 | 8 万 | n*8 万 | 集群的查询总 qps 是节点的倍数 |
注册中心 | 服务实例注册,http 协议 | 1.2 万 | 1.0 万 | 注册中心单机模式与集群模式写入的性能一致 |
注册中心 | 服务实例注册,grpc 协议 | 1.2 万 | 1.2 万 | grpc 协议压测工具没有支持,目前没有实际压测,理论不会比 http 协议低 |
注册中心 | 服务实例心跳,http 协议 | 1.2 万 | 1.0 万 | 心跳是按实例计算和服务实例注册一致共享 qps |
注册中心 | 服务实例心跳,grpc 协议 | 8 万以上 | n*8 万 | 心跳是按请求链接计算,且不过注册中心处理线程,每个节点只需管理当前节点的心跳,集群总心跳 qps 是节点的倍数 |
注册中心 | 查询服务实例 | 3 万 | n*3 万 | 集群的查询总 qps 是节点的倍数 |
注: 具体结果和压测环境有关
注册中心查询(单机 3 万 qps):
配置中心查询,两个进程分别限流 4 万 qps 同时压测(共 8 万 qps),其中一个的压测记录:
结论: 如果使用 v1.0x http 协议,支持的实例在 5 万个左右。 如果使用 v2.0x grpc 协议,理论上能到达千万实例,基本没有瓶颈。
方式 1:从 github release 下载对应系统的应用包,解压后即可运行。
linux 或 mac
# 解压
tar -xvf rnacos-x86_64-apple-darwin.tar.gz
# 运行
./rnacos -e envfine
windows 解压后直接运行 rnacos.exe 即可。
方式 2: 通过 docker 运行
#stable 是最新正式版本号,也可以指定镜像版本号,如:qingpan/rnacos:v0.3.0
docker pull qingpan/rnacos:stable
# 在/path/rnacos/.env 配置文件中配置好运行参数
docker run --name mynacos -p 8848:8848 -p 9848:9848 -d -v /path/rnacos:/io qingpan/rnacos:stable
docker 的容器运行目录是 /io ,会从这个目录读写配置文件
方式 3:通过 cargo 编译安装
# 安装
cargo install rnacos
# 运行
rnacos -e envfile
方式 4: 下载源码编译运行
git clone https://github.com/heqingpan/rnacos.git
cd rnacos
cargo build --release
cargo run --release -- -e envfile
测试、试用推荐使用第 1 、第 2 种方式,直接下载就可以使用。
在 linux 下第 1 、第 2 种方式默认是 musl 版本(性能比 gnu 版本差一些),在生产服务对性能有要求的可以考虑使用第 3 、第 4 种在对应环境编译 gnu 版本部署。
同一个应用包需要支持不同场景,就需要支持设置自定义参数。
rnacos 运行参数支持通过环境变量,或指定配置文件方式设置。 如果不设置则按默认参数运行。
例子
# 从 0.3.0 版本开始支持 -e env_file 运行参数
./rnacos -e env_file
如果不指定文件时也会尝试从当前目录下.env 文件加载配置参数
env_file 内容的格式是
KEY1=VALUE1
KEY2=VALUE2
KEY3=VALUE3
运行参数:
参数 KEY | 内容描述 | 默认值 | 示例 | 开始支持的版本 |
---|---|---|---|---|
RNACOS_HTTP_PORT | rnacos 监听 http 端口 | 8848 | 8848 | 0.1.x |
RNACOS_GRPC_PORT | rnacos 监听 grpc 端口 | 默认是 HTTP 端口+1000 | 9848 | 0.1.x |
RNACOS_HTTP_WORKERS | http 工作线程数 | cpu 核数 | 8 | 0.1.x |
RNACOS_CONFIG_DB_FILE | 配置中心的本地数据库文件地址 [ 0.2.x 后不在使用] | config.db | config.db | 0.1.x |
RNACOS_CONFIG_DB_DIR | 配置中心的本地数据库 sled 文件夹, 会在系统运行时自动创建 | nacos_db | nacos_db | 0.2.x |
RNACOS_RAFT_NODE_ID | 节点 id | 1 | 1 | 0.3.0 |
RNACOS_RAFT_NODE_ADDR | 节点地址 Ip:GrpcPort,单节点运行时每次启动都会生效;多节点集群部署时,只取加入集群时配置的值 | 127.0.0.1:GrpcPort | 127.0.0.1:9848 | 0.3.0 |
RNACOS_RAFT_AUTO_INIT | 是否当做主节点初始化,(只在每一次启动时生效) | 节点 1 时默认为 true,节点非 1 时为 false | true | 0.3.0 |
RNACOS_RAFT_JOIN_ADDR | 是否当做节点加入对应的主节点,LeaderIp:GrpcPort ;只在第一次启动时生效 | 空 | 127.0.0.1:9848 | 0.3.0 |
RUST_LOG | 日志等级:debug,info,warn,error;所有 http,grpc 请求都会打 info 日志,如果不观注可以设置为 error 减少日志量 | info | error | 0.3.0 |
注:从 v0.3.0 开始,默认参数启动的节点会被当做只有一个节点,当前节点是主节点的集群部署。支持其它新增的从节点加入。
配置集群规则
ip:grpc_port
按上面的配置规则,下面我们配置一个 3 节点集群例子。
初始化节信息
正式集群部署的 log 等级建议设置为warn
,不打正常的请求日志,只打报警或异常日志,减少日志量。
配置信息如下
env01
#file:env01 , Initialize with the leader node role
RUST_LOG=warn
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_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_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 &
实例过程中不同的节点需要在不同的服务器运行服务。
集群服务启动后,即可运行原有的 nacos 应用。
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'
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"
详细使用说明参考rnacos book
rnacos 单机版本发布已有 4 个月,期间有收到一些使用问题的反馈,目前主体功能已经算比较稳定,有使用 nacos 的同学欢迎试用。
使用过程中和什么问题或建议可以到 github 提 issues 反馈。
如果对你有帮助就给个 star 鼓励鼓励 :-)
对 rnacos 开发感兴趣的同学也欢迎到 github 提 rp 共建。rnacos 发布后已有一位同学参于共建,非常感谢一起共建的同学。
这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。
V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。
V2EX is a community of developers, designers and creative people.