Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Nacos 1.4.1 集群部署 扩缩容 导致协议失效 稳定复现 #4877

Closed
MajorHe1 opened this issue Feb 4, 2021 · 15 comments
Closed

Nacos 1.4.1 集群部署 扩缩容 导致协议失效 稳定复现 #4877

MajorHe1 opened this issue Feb 4, 2021 · 15 comments
Labels
kind/question Category issues related to questions or problems

Comments

@MajorHe1
Copy link
Collaborator

MajorHe1 commented Feb 4, 2021

背景
部署了三台机器,分别是 172.21.1.116(记为116),172.21.1.134(记为134),172.21.1.150(记为150)
启动均采用 nacos.core.member.lookup.type=address-server 模式获取集群列表

缩容场景
执行步骤:

  1. kill - 9 134机器上的nacos进程
    image

  2. 查看150机器上的控制台
    image

3.刷新再查看150机器上的控制台
image

  1. 查看116机器上的控制台
    image

5.查看nacos.log文件的错误日志
image

注意,无论是从控制台看,还是用OpenAPI直接访问获取数据,在116、150这两台机器上看134这台机器上的状态,都是不断的在down 和 up 之间来回跳转。

问题1:对于distro协议计算权威节点或者其他涉及到要获取nacos server状态的逻辑来说,这样的情况会不会造成问题?比如说我看到就有其他issue在反馈说请求被转发到已经杀掉进程的机器上。

扩容场景

  1. 无论是使用 cluster.conf 还是 address-server 应该无论哪种寻址模式都能复现这个问题
  2. 跟上面相同的背景,此时新增一台机器A,从同一个address-server获取集群列表(注意,集群列表没有改动)
  3. 机器A发现获取的集群列表没有自己的IP地址,根据nacos的代码,它将 members.add(this.self);
  4. 已有的三台机器,116,134,150并不承认新加入的机器A,nacos.log抛出异常说机器A的ip不在 ip list 里面
  5. 但是raft协议会将机器A的ip加入到raft group里面
  6. 如果我尝试kill 116,134,150这些机器,有可能会出现选主选机器A为leader的情况
  7. 这个时候,整个nacos的CP协议都失效了,在控制台无法查询配置、无法查看命名空间、无法查询集群列表,报出来的异常也都是 No leader at term xx.
  8. 个人测试,重启116,134,150这些机器也没用,重启后也是处于CP协议失效的状态,除非kill掉机器A,然后rm -rf 原来的nacos的文件并重新解压运行(embedded storage),不知道你们能不能复现这个场景

问题2:扩容是不是要严格遵循,先更改address-server里面的集群列表,再启动进程的过程?如果不是,那扩缩容同时进行就有可能出现我说的这个问题;如果是,那为什么在机器A启动的时候,发现没有自己的ip地址,没有报错终止启动?

感谢解答。

@KomachiSion
Copy link
Collaborator

KomachiSion commented Feb 4, 2021

  1. 这个报错是必然的 因为这是个废弃的raft协议,集群已经全部升级到1.4以上并且运行后, 旧raft协议会被关闭,扩容时肯定找不到旧raft leader,而是去找新raft leader。

  2. 扩容可以先启动,再添加ip,也可以先添加ip,后启动程序。只要ip列表发生变化(无论cluster。conf还是addressserver, 都会触发server member update事件,重新读取和更新。

  3. 暂不支持自动扩缩容,需要手动到addressserver去添加或者修改cluster.conf

@MajorHe1
Copy link
Collaborator Author

MajorHe1 commented Feb 5, 2021

  1. 这个报错是必然的 因为这是个废弃的raft协议,集群已经全部升级到1.4以上并且运行后, 旧raft协议会被关闭,扩容时肯定找不到旧raft leader,而是去找新raft leader。
  2. 扩容可以先启动,再添加ip,也可以先添加ip,后启动程序。只要ip列表发生变化(无论cluster。conf还是addressserver, 都会触发server member update事件,重新读取和更新。
  3. 暂不支持自动扩缩容,需要手动到addressserver去添加或者修改cluster.conf

1.您说的这个报错是必然的,是指扩容场景下的那个错误 No leader at term xx ,还是缩容场景下的nacos-server节点状态在down 和 up之间来回跳转的错误?您能复现或者解释一下为什么进程被kill -9 之后,无论是控制台还是OpenAPI查到的节点状态都是在变化中么?

2.我的疑问在于,假如扩缩容同时进行,还没有来得及去更新ip列表,这个时候完全有可能会出现我在扩容场景描述的这个问题,整个集群跟CP协议相关的都是不可用的状态(我部署的都是1.4.1的版本),重启都不解决问题,(我还没有验证再更新ip列表能不能解决问题,我这就去试一下)

@MajorHe1
Copy link
Collaborator Author

MajorHe1 commented Feb 5, 2021

已经试了,我再描述一下全过程,所有的nacos-server版本都是1.4.1
1.原有集群节点三台机器分别是116,134,150,address-server里面配的也是这三个地址
2.另外启动一台机器A,也向该address-server获取集群列表
3.此时116,134,150除了报异常说机器A不在server list里面之外,还可以正常工作,leader为116
4.kill 掉 116的进程,leader切换到150
5.kill 掉 150的进程,这个时候剩下的134已经不能正常工作了,如图
image

6.在address server里面配上机器A的地址,134能够触发server member update事件,重新读取和更新,但是并不能解决CP协议不工作的问题,134这台机器和机器A也不能通过CP协议同步配置等信息

7.重启116和150两台机器(不一定能一次性重启成功,很容易陷入 Nacos is starting的状态几十分钟,不得已再重新启动),重启后,识别了新的集群信息,加入了机器A的ip,但是同样不能正常工作,如图
image
8.一段时间后,116,134,150三台机器重新组成CP集群,但是新的机器A依然不能正确的加入到该集群中,除非再度重启。

问题:看样子先启动进程再添加ip的方式就是会出错,建议将代码逻辑改为如果发现本ip不在指定的ip列表里面直接让nacos启动过程抛异常退出,请问这么做会有什么问题吗?

感谢解答!

@KomachiSion
Copy link
Collaborator

从你的流程来看,是符合预期的。

raft协议是比较强的一致性协议。无论何时都应该保证集群可用节点大于等于一半,以保证正常选主。

你的场景中,先添加了一台机器,但原集群并没有更新和感知,然后摘除2台机器,相当于旧集群只剩下一台机器,raft是无法选主和提供服务的。即使后来你加入了一台,但是由于raft已经无主,新的地址也无法写入raft元数据。因此导致扩容失败。这是raft协议决定的。

正确的做法扩容一台(可以先不添加address),然后缩容一台,然后添加地址服务器。

@MajorHe1
Copy link
Collaborator Author

MajorHe1 commented Feb 8, 2021

我还需要请教您三个问题:
1.当扩容失败,raft已经不能选主和提供服务,这时候如果不重启,nacos集群就不正常工作,一定要重启才可以,请问这个符合预期吗?
2.我自己测试发现,如果address并没有添加新机器ip就启动新机器进程,这个时候memberManager认为新ip不在集群列表里不合法,但是raftGroup却会把这个ip添加进去,这两个逻辑是否冲突?raft是否会选主选到memberManager认为不合法的节点?
3.请您再看一下我最开始提出的,关于被杀掉进程的节点在别的机器上看到的状态总是在down和up之间跳转的问题。
谢谢!

@KomachiSion
Copy link
Collaborator

我还需要请教您三个问题:
1.当扩容失败,raft已经不能选主和提供服务,这时候如果不重启,nacos集群就不正常工作,一定要重启才可以,请问这个符合预期吗?
2.我自己测试发现,如果address并没有添加新机器ip就启动新机器进程,这个时候memberManager认为新ip不在集群列表里不合法,但是raftGroup却会把这个ip添加进去,这两个逻辑是否冲突?raft是否会选主选到memberManager认为不合法的节点?
3.请您再看一下我最开始提出的,关于被杀掉进程的节点在别的机器上看到的状态总是在down和up之间跳转的问题。
谢谢!

  1. 如果raft已经无法选主,nacos集群应该只能提供部分功能。
  2. raftGroup不会添加这个ip,raftGroup需要收到memberManager发出的事件之后才会添加ip,如果有收到新ip的请求,应该只是会打印日志。
  3. 这是另外一个问题了,最好能再提一个新issue,在新issue单独讨论这个问题,避免issue内容和标题不符

@MajorHe1
Copy link
Collaborator Author

  1. 如果raft已经无法选主,nacos集群应该只能提供部分功能。
  2. raftGroup不会添加这个ip,raftGroup需要收到memberManager发出的事件之后才会添加ip,如果有收到新ip的请求,应该只是会打印日志。
  3. 这是另外一个问题了,最好能再提一个新issue,在新issue单独讨论这个问题,避免issue内容和标题不符

关于问题2我再复现一下,问题3我再单独提一个issue,感谢您的解答,祝您新年快乐,祝nacos社区蒸蒸日上 :)

@MajorHe1
Copy link
Collaborator Author

  1. raftGroup不会添加这个ip,raftGroup需要收到memberManager发出的事件之后才会添加ip,如果有收到新ip的请求,应该只是会打印日志。

@KomachiSion 您好,很容易复现这个问题

  1. 现有集群中部署三台机器,分别是 172.21.1.134(记为134),172.21.1.150(记为150),172.21.1.153(记为153)

  2. 集群寻址模式为 address-server

  3. 另外启动一台集群外的机器116,没有更新address-server,注意时间戳
    image

  4. 可以看到,原来集群中的机器认为116这台机器不合法,这没有问题
    image

5.但是用Postman访问OpenAPI,可以看到116这台机器已经在raftGroup当中了
image

@KomachiSion
Copy link
Collaborator

这个问题可能是 jraft直接从底层更新了他自己的raftMember元数据,是jraft自己的机制,nacos可能不是太好干预。

但是应该不太影响使用,如果是扩一台,然后再下线一台的话。只要能选出leader,就不会有问题。

@MajorHe1
Copy link
Collaborator Author

MajorHe1 commented Mar 1, 2021

这个问题可能是 jraft直接从底层更新了他自己的raftMember元数据,是jraft自己的机制,nacos可能不是太好干预。

但是应该不太影响使用,如果是扩一台,然后再下线一台的话。只要能选出leader,就不会有问题。

注意到 nacos 只在JRaftServer.java 文件和 JRaftOps.java文件里面调用了 jraft 的 Configuration的addPeer()方法,removePeer()方法没有被nacos调用过。
请问可不可以 nacos 自身的 serverMemberManager 在发现有集群节点变化的时候,显式调用去操作 removePeer(),您觉得怎么样?

@KomachiSion
Copy link
Collaborator

KomachiSion commented Mar 2, 2021

serverMemberManager发现节点有变化后,会发出时间,JraftServer会监听时间,调用peerChange。 JraftServer.peerChange

只在节点数量和ip发生变更时才会触发,如果是up down的状态变更不会触发。

但是最终jraft group config,还是由jraft的leader统一维护下发。

比如原来A,B,C3个节点, 启动D节点时,D节点的member是ABCD,那么D会尝试调用Jraft命令写入4个节点,Jraft leader收到写入请求之后下发到各个节点, 半数以上写入成功后,就会写入到raft metadata里,不会在期间调用上层serverMemberManager来校验。

@MajorHe1
Copy link
Collaborator Author

MajorHe1 commented Mar 2, 2021

serverMemberManager发现节点有变化后,会发出时间,JraftServer会监听时间,调用peerChange。 JraftServer.peerChange

只在节点数量和ip发生变更时才会触发,如果是up down的状态变更不会触发。

但是最终jraft group config,还是由jraft的leader统一维护下发。

比如原来A,B,C3个节点, 启动D节点时,D节点的member是ABCD,那么D会尝试调用Jraft命令写入4个节点,Jraft leader收到写入请求之后下发到各个节点, 半数以上写入成功后,就会写入到raft metadata里,不会在期间调用上层serverMemberManager来校验。

就是这种情况,假如在address-server或者cluster.conf没有更新的情况下,serverMemberManager只会认为合法的集群节点是ABC,但是raft集群认为ABCD都是集群的节点。
如果原来的leader下线重新选主选到D节点,这个时候依赖raft协议进行同步的数据,比如说持久化的服务信息或者配置信息,还能够正常进行吗?

@KomachiSion
Copy link
Collaborator

KomachiSion commented Mar 3, 2021

  1. 理论上不影响,nacos通过raft协议进行写入时,是通过raft的接口进行,raft会自动寻址到leader并通过leader下发指令,最后所有节点都会同步。比如原来是ABC,leader是A,扩容D后A停止,D成为leader,但是地址服务器还是ABC,此时请求会到B/C,然后B/C将操作汇报给D,D下发BC,BCD均执行写入操作,且此时客户端流量不会进入D,进入BC也只会在BC的状态机里找数据。所以只要raft能够正确选出主,理论上问题都不大。
  2. 但是这种场景应尽量避免,我们这边会尝试解决这种不一致问题,此期间可能需要社区人员的帮助和贡献。
  3. 这里可能还需要一些文档补充,将这种情况通过文档说明,提供一个建议的扩缩容流程。

@MajorHe1
Copy link
Collaborator Author

MajorHe1 commented Mar 3, 2021

好的,非常感谢您的耐心解答

@KomachiSion KomachiSion added kind/question Category issues related to questions or problems and removed status/need feedback labels Mar 4, 2021
@woshishitou
Copy link

  1. 这个报错是必然的 因为这是个废弃的raft协议,集群已经全部升级到1.4以上并且运行后, 旧raft协议会被关闭,扩容时肯定找不到旧raft leader,而是去找新raft leader。
  2. 扩容可以先启动,再添加ip,也可以先添加ip,后启动程序。只要ip列表发生变化(无论cluster。conf还是addressserver, 都会触发server member update事件,重新读取和更新。
  3. 暂不支持自动扩缩容,需要手动到addressserver去添加或者修改cluster.conf

您好,请问nacos2.0支持自动扩缩容吗?即,节点下线后,还需要做对应的配置吗?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
kind/question Category issues related to questions or problems
Projects
None yet
Development

No branches or pull requests

3 participants