- Nacos = 配置中心 + 服务发现
- etcd = 分布式协调系统(强一致 KV)
两者协作:
- Nacos → 管配置
- etcd → 做 Leader 选举、分布式锁、元数据协调
Nacos
主要解决:
- 配置管理
- 服务注册发现
典型场景:
text
订单服务
支付服务
库存服务
都注册到 Nacos
订单服务通过 Nacos 找到支付服务
同时:
yaml
mailbox.capacity: 10000
partition.count: 128
这种配置也可以放 Nacos。
etcd
主要解决:
- 强一致 KV 存储
- Leader 选举
- 分布式锁
- 集群协调
典型场景:
text
订单节点A
订单节点B
订单节点C
选举一个Leader
这就是 etcd 的强项。
一致性能力
这是最大的区别。
etcd 基于 Raft Consensus Algorithm 实现。特点:
text
强一致
写入流程:
text
Leader
↓
多数节点确认
↓
提交成功
因此:
java
put(key,value)
返回成功后:
text
所有客户端看到的结果一致
不会出现:
text
A看到1
B看到2
这种情况。
Nacos 默认不是严格意义上的强一致存储。
对于配置:
text
最终一致
对于服务发现:
text
AP 优先
更关注可用性。
因此:
text
服务刚下线
可能几秒钟后其他节点才感知到。
这是允许的。
Leader选举
etcd 原生支持。
例如:
text
订单集群
100个实例。
要求:
text
只有一个实例负责:
- 重平衡
- Partition迁移
- 定时任务
直接:
java
Campaign()
即可。
Nacos 没有成熟的对外 Leader 选举 API。
虽然 Nacos 自己内部也有 Leader:
text
Nacos集群
但业务系统无法方便利用。
因此:
text
业务Leader选举
一般不用 Nacos。
Watch能力
Actor 系统特别关注这一点。
etcd
支持:
text
Watch
监听 Key 变化。
例如:
text
/order/partition/1
被修改。
所有节点立刻收到事件:
text
PUT
DELETE
UPDATE
延迟通常毫秒级。
非常适合:
text
Partition迁移
Actor重平衡
Nacos 也支持配置监听:
java
@NacosValue(autoRefreshed=true)
但它本质上是:
text
配置推送
不是协调系统。
如果拿它做:
text
Leader选举
Partition Ownership
会比较别扭。
性能特点
etcd 擅长:
text
小数据
高一致
频繁协调
例如:
text
Leader
Lock
Metadata
但不适合:
text
几百MB配置
Nacos 擅长:
text
大量配置
服务注册
例如:
text
1000个服务
50000个配置项
管理起来很方便。
etcd 更适合存运行时元数据(Runtime Metadata) ;Nacos 更适合存静态配置(Configuration)。不要把 etcd 当配置中心,也不要把 Nacos 当分布式协调系统,这样职责会更清晰。
对于一个以 Actor + Partition + Leader Election 为核心的系统来说,etcd 往往比 Nacos 更关键、更不可替代。而 Nacos 更像是锦上添花的配置中心。
etcd 强一致性
etcd 的"强一致性"是针对 etcd 集群自身的数据一致性,而不是业务系统一致性。在生产环境中 etcd 是集群部署的,比如说一主多从情况下,客户端在写入数据时要等到Leader 必须等到 Leader + 至少一个Follower 都写成功(超过半数节点确认)后,才会返回:OK
因此:
text
一旦写成功返回
↓
未来任何客户端读取
↓
看到的都是最新值
不会出现:
text
客户端A读到 nodeA
客户端B读到 nodeB
这种脑裂现象。
这就是 etcd 的强一致性。
至于在 etcd 配置内容发生变化后,所有的业务实例都 watch 到,这里就不再属于 etcd 的一致性保证范围了。因为网络的原因,可能有的节点并没有同步到,所以业务侧看到的数据是最终一致性,而不是瞬间一致性。
text
etcd强一致
≠
业务系统强一致
而是:
text
etcd强一致
+
Watch机制
+
业务节点刷新逻辑
=
业务侧最终一致
在 etcd 集群模式下,所有写操作最终都要经过 Leader,客户端请求可能打到任意节点,但 Follower 不会自己写数据,而是转发给 Leader,Leader 通过 Raft 日志复制,多数节点确认后,写入成功。
在这一点上 etcd 和 MySQL 是不一样的,MySQL 的主从复制是最终一致性,etcd 的多数确认成功,保证即使 Leader 节点挂掉,通过 Raft 选举机制选出的新 Leader 也一定会拥有这条数据,这正是 Raft 保证强一致性的核心来源。
etcd 集群并不保证全部节点都写入成功后才算成功,肯定有节点没有被同步到,存留的还是旧值,但是 etcd 却能做到所有的客户端都能读取到最新的数据,这里跟它的读取方式有关。
etcd 的默认读取方式是强一致性读,客户端在读取 etcd 集群时无论是请求到 Follow 节点还是 Leader 节点,都要经过 Leader 节点确保已经拥有当前最新提交日志后,才允许返回,因此在写成功后,紧接着读,一定能读取到最新的值。
etcd 也允许弱一致性读,这个时候如果客户端请求到 Follow 节点,Follow 不去寻找 Leader 节点确认,这个时候就可能读取到旧值,因为选择了高性能换取可能读取到旧数据。
Raft 投票時保证只投票给日志不比自己旧的候选人,也就是说那些还没有同步最新数据的 Follow 节点不可能被投票竞选成为新的 Leader 节点,新 Leader 节点是从拥有最新数据的 Follow 节点中通过获得大多数选票而选举出来的。因此,新 Leader 节点被选举出来后不会丢失集群的数据。
在生产环境中,不同的业务共用一个 etcd 集群,订单、风控、撮合这些是共用一个集群的。而多个 etcd 集群通常是因为环境隔离(开发/测试/生产)、地域隔离(东京/大阪)或多个独立系统,而不是为了共同维护同一份配置数据。超大规模情况下,不同的业务会有自己的一个 etcd 集群,一般情况下,共用一个集群即可。