alibaba / nacos

an easy-to-use dynamic service discovery, configuration and service management platform for building cloud native applications.
https://nacos.io
Apache License 2.0
30.25k stars 12.84k forks source link

write lock failed without retry #12557

Open ysfxc opened 2 months ago

ysfxc commented 2 months ago

Describe the bug A clear and concise description of what the bug is. nacos server版本: 2.1.0, 3节点部署 + derby client: go-sdk 如图所示

image

这里dump配置的时候, 如果有其他请求正在读配置(readLock), 是不是会导致dump失败? dump失败的话就只能等对账任务了, 在此之前, server的md5 cache都是错误的.

Expected behavior A clear and concise description of what you expected to happen. 获取写锁失败, 等待或者重试 Actually behavior A clear and concise description of what you actually to happen. 某个nacos server节点获取写锁失败后, md5缓存一直是旧的, 直到几个小时后的全量对账任务触发, 配置才刷新. 正常节点: 01:00:30, 配置更新, 该配置缓存md5刷新为: 8d1943c68eecedc84e431c912fbca0e5 config-pull-check.log.2024-08-20.0

image

异常节点: 01:00:30 获取写锁失败, md5缓存一直未能刷新, 还是旧的: b7ce55d429195cf56609bd68787ebedf config-dump.log.2024-08-20.0, 01:00:00

image

config-pull-check.log.2024-08-20.0, 01:00:00

image

直到几个小时后(06:19)的全量对账任务启动, md5才刷新 config-dump.log.2024-08-20.0, 06:00:00

image

config-pull-check.log.2024-08-20.0, 06:00:00

image

How to Reproduce Steps to reproduce the behavior: 未能稳定复现

Desktop (please complete the following information):

Additional context Add any other context about the problem here. 我们的客户端是go-sdk, 与java客户端不同的是, long-pulling和getInnerConfig可能会请求不同的nacos server

KomachiSion commented 2 months ago

能否试一下新版本,我看最新版本的逻辑应该有修改过。

ysfxc commented 2 months ago

能否试一下新版本,我看最新版本的逻辑应该有修改过。

不知道我理解的对不对, 新版本的代码似乎还是没有解决这个问题, 更新配置时没有关心dump动作是否成功, 也没有重试机制

写配置:

image

ConfigDumpEvent事件处理, 忽略了dump动作的返回值, 没有做失败重试

image

而dump动作中, 还是会出现"只要被上了读锁, dump就会失败"的情况

image

不同的是新版本增加了一个定时任务DumpChangeConfigWorker, 每30s让dump动作失败有一个兜底, 让不一致的情况会在较短时间内自动修复.

求帮忙看看, 是我理解的有问题, 还是确实存在上述情况, 需要修复?

ysfxc commented 2 months ago

@KomachiSion 后续更新, 我们现在已经可以稳定复现错误

  1. 部署三节点的nacos, 模式为 derby + raft
  2. 使用一个脚本持续定时更新nacos的某个配置, 周期两分钟
  3. 起10个 go-sdk的client的pod订阅这个配置,
  4. nacos的部分节点出现了write lock failed报错, dump失败, 缓存不一致.
  5. 由于subscriber client随机选择nacos节点轮询, 此时部分client pod在新老配置之间跳变.

测试了一整晚, 大概出现了两次上述问题

image

我们猜测这个问题之前没被发现的原因有两个:

  1. nacos企业级用户大多不会使用derby + raft的方式接入(但我们为了CP确实这么用了)
  2. 大部分nacos客户使用java-sdk, java-sdk中, 即使配置了多个nacos-endpoint, long-pulling和getConfig也会使用同一个endpoint, 这避免了一种情况: 收到配置变更的客户端跑去其他还没更新缓存的nacos节点上拉取数据, 上读锁, 导致nacos更新获取写锁失败. 而go-sdk的long-pulling和getConfig这两个步骤, 获取endpoint则是完全随机选取的.
KomachiSion commented 2 months ago

欢迎修复次问题后提交PR

关于问题2的描述: go-sdk在新版本中也是使用长连接来获取配置, 正常情况下也是在同一个节点上进行获取。