apolloconfig / apollo

Apollo is a reliable configuration management system suitable for microservice configuration management scenarios.
https://www.apolloconfig.com
Apache License 2.0
28.95k stars 10.19k forks source link

请教一下,修改配置实时生效后,线上老代码不兼容新配置导致容易出现生产问题,有没有什么好的实践 #5031

Closed shuai-huaman closed 5 months ago

shuai-huaman commented 7 months ago

描述bug

先修改了apollo某个配置,新的配置在线上实时生效了,但是因为新代码还在部署中,线上老代码不支持新配置,导致出现生产问题 想问一下大家针对这种场景有没有比较好的处理方案

(有人可能会说先部署代码再变更配置就好了,确实是一种方案,但是实际运行过程中往往很多开发没有评估到哪些配置会产生这种兼容问题,所以还是经常出问题,想看看大家有没有更可靠更有保障的方案流程)

复现

通过如下步骤可以复现:

期望

简介明了地描述你希望正常情况下应该发生什么

截图

如果可以,附上截图来描述你的问题

额外的细节和日志

dosubot[bot] commented 7 months ago

🤖

Hello @shuai-huaman,

Nice to meet you! I'm Dosu, a bot that's here to assist you with questions, bugs, and contributing to the apollo repository while we wait for a human maintainer. Feel free to ask anything you need, I'm here to help!

针对您的问题,我找到了一个类似的已解决问题:配置和服务需要同步更新,不同步会出错。请教下,应该如何做。在这个问题中,建议的解决方案是:对于需要同步更新配置和代码的场景,建议添加一个新的配置项。这样,新旧代码对同一配置的兼容性更好,更有利于灰度测试和回滚。如果你真的不想添加配置项,可以考虑为新代码指定一个新的集群。这样,新旧集群的配置可以在Apollo中独立配置。

关于Apollo如何实时处理配置更改,Apollo使用长轮询机制。当客户端请求配置时,它会保持连接开放,直到服务器有新的配置推送给客户端,或者请求超时。这在NotificationController类的pollNotification方法中实现。客户端发送一个带有appIdclusternamespacedataCenternotificationId参数的GET请求。服务器然后检查是否有新的配置(ReleaseMessage)可供客户端使用。如果有,它立即发送带有新配置的响应。如果没有,它注册客户端的请求,并保持连接开放,直到有新的配置可用或请求超时。

当有新的配置可用时,会调用handleMessage方法。此方法检查是否有任何客户端在等待新的配置。如果有,它会向所有等待的客户端发送带有新配置的响应。

这是相关的代码:

// Check if there is a new configuration available
ReleaseMessage latest = releaseMessageService.findLatestReleaseMessageForMessages(watchedKeys);
if (latest != null && latest.getId() != notificationId) {
  deferredResult.setResult(new ResponseEntity<>(
      new ApolloConfigNotification(namespace, latest.getId()), HttpStatus.OK));
} else {
  // Register the client's request and keep the connection open
  for (String key : watchedKeys) {
    this.deferredResults.put(key, deferredResult);
  }
}

// When a new configuration is available, send a response to all waiting clients
public void handleMessage(ReleaseMessage message, String channel) {
  ...
  List<DeferredResult<ResponseEntity<ApolloConfigNotification>>> results =
      Lists.newArrayList(deferredResults.get(content));
  for (DeferredResult<ResponseEntity<ApolloConfigNotification>> result : results) {
    result.setResult(notification);
  }
}

源码链接:apollo-configservice/src/main/java/com/ctrip/framework/apollo/configservice/controller/NotificationController.java

希望这些信息能帮助您解决问题。如果您有任何其他问题或需要更多的信息,请随时告诉我。

Sources


This response is meant to be useful and save you time. It is not meant to be a precise solution, but rather a starting point for your own research.

Help me be more useful! Please leave a 👍 if this is helpful and 👎 if it is irrelevant.

If you want to continue the conversation, start your reply with @dosu-bot.

shuai-huaman commented 6 months ago

@nobodyiam 大佬,之前的帖子已经看过了,但是感觉帮助不大,因为我们当前只用了一个apollo集群,并且一个服务正常也只有一套配置,每次增量变化

如果每次发布版本想要变更配置,还得增加新配置key或者放在新集群,那成本太高了,我们希望的是始终维护同一套配置

因为只有唯一一套配置,所以必然面临新老代码的兼容,当前的处理方式是完全依靠开发人工判断哪些key需要等到新代码上线后再变更,哪些key可以直接变更线上,但是太容易评估遗漏了

nobodyiam commented 6 months ago

建议还是新配置不能影响老代码,不然发布过程中的灰度会很复杂,以及如果遇到问题回滚代码也会比较麻烦

stale[bot] commented 5 months ago

This issue has been automatically marked as stale because it has not had activity in the last 30 days. It will be closed in 7 days unless it is tagged "help wanted" or other activity occurs. Thank you for your contributions.

stale[bot] commented 5 months ago

This issue has been automatically closed because it has not had activity in the last 7 days. If this issue is still valid, please ping a maintainer and ask them to label it as "help wanted". Thank you for your contributions.