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

关于apollo配置发布的问题 #652

Closed
chinaHewei opened this issue Jul 10, 2017 · 18 comments
Closed

关于apollo配置发布的问题 #652

chinaHewei opened this issue Jul 10, 2017 · 18 comments

Comments

@chinaHewei
Copy link

我看源码中 DatabaseMessageSender 会有一个定时任务定时清理 release message. 针对 release message 没有一些标记来标记他是否已经推送给 client,是通过定时任务来清理过时的 release message是吗?那有没有可能 client 会重复收到 release message呢?

@nobodyiam
Copy link
Member

release message只是一个无状态的通知,重复收到release message也没关系,因为处理逻辑是幂等的。

就算客户端没有收到推送通知,过30秒后重连的时候,服务端也会识别出该客户端漏了消息,会重新推送的。

清理过时的release message只是不希望release message表持续增长。

@chinaHewei
Copy link
Author

谢谢,看到了,对于 release message 还有一个缓存,对于所有发布的配置最新的缓存。在重连的时候就能将客户端因为网络问题导致的丢失解决了。之前没有注意,感谢你的回答。

@chinaHewei
Copy link
Author

还有个问题,看代码时候没看太明白。

    List<ReleaseMessage> latestReleaseMessages =
        releaseMessageService.findLatestReleaseMessagesGroupByMessages(watchedKeys);

ReleaseMessageServiceWithCache中是不是所有更新过的配置。

通过他获取配置好像是直接获取,没有做什么判断,这样client端每一次发起http会不会就直接获取到结果了,不需要经过异步处理了。还是我看漏了什么地方?

@nobodyiam
Copy link
Member

这段代码用到了Spring DeferredResult,所以看上去可能有些费劲。

如果客户端的notification不是最新的,就会执行154行,直接返回。
如果客户端的notification是最新的,就会执行157行,异步处理。

image

ReleaseMessageServiceWithCache中存放的是ReleaseMessage(对应表ReleaseMessage),不是真正的配置(对应表release)。

@chinaHewei
Copy link
Author

这个关于 Spring DeferredResult 的能看明白。ReleaseMessageServiceWithCache中存放了ReleaseMessage,当client端发起 http long polling 后,服务端先从ReleaseMessageServiceWithCache获取相关的ReleaseMessage,然后通过一定的方法比较出client端的缓存是不是最新的。如果不是,就返回新的,是的话就挂起,等待发布事件。这个比较的方法没太看明白( ╯□╰ )。能麻烦讲个大概吗?

@nobodyiam
Copy link
Member

NotificationController不负责判断客户端的配置是不是最新的,它只负责判断客户端是不是收到了最新的推送消息。

判断的逻辑就是
https://github.com/ctripcorp/apollo/blob/master/apollo-configservice/src/main/java/com/ctrip/framework/apollo/configservice/controller/NotificationControllerV2.java#L149

@chinaHewei
Copy link
Author

嗷嗷,我想我应该明白了,之前看走偏了。NotificationController发布的更新的消息,消息中会告诉client端那个配置变了,但不会携带变化的配置,当client端收到变化的提醒,然后再请求config server获取最新的配置。是这样理解吗?

@nobodyiam
Copy link
Member

对的~

@chinaHewei
Copy link
Author

非常感谢。为什么不在 long polling 的返回结果中直接返回更新的结果呢?

@nobodyiam
Copy link
Member

这样推送消息就是有状态了,做不到幂等了,会带来很多问题。

@chinaHewei
Copy link
Author

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

@dumbdonkey
Copy link

这样推送消息就是有状态了,做不到幂等了,会带来很多问题。

麻烦请教下。

能否详细举些例子说下如果推送的时候携带数据都会带来哪些问题呢?

因为个人觉得在推送时携带数据也有它的好处:

  1. 减少一次后续client与server的交互.

  2. push的时候可以引入一些计算,比如灰度什么的,如果当前机器不在灰度列表内也不需要返回任何信息。

谢谢

@wkcaeser
Copy link
Contributor

这样推送消息就是有状态了,做不到幂等了,会带来很多问题。

麻烦请教下。

能否详细举些例子说下如果推送的时候携带数据都会带来哪些问题呢?

因为个人觉得在推送时携带数据也有它的好处:

  1. 减少一次后续client与server的交互.
  2. push的时候可以引入一些计算,比如灰度什么的,如果当前机器不在灰度列表内也不需要返回任何信息。

谢谢

对于第一点,有没有减少交互不好说,比如我在短时间内操作了多次,那么主动去查询反而交互更少。同时也是这个点,由于网络不可控,可能后面的更新反而新到达,这样无效的网络开销还挺多的。同时服务必须要主动查询,不然无法保证各个服务拿到的配置是一样的,反而增加了复杂度,而且解决这个问题其实又回到了现在这种实现。

第二点没太看懂

@dumbdonkey
Copy link

dumbdonkey commented Nov 29, 2019

这样推送消息就是有状态了,做不到幂等了,会带来很多问题。

麻烦请教下。
能否详细举些例子说下如果推送的时候携带数据都会带来哪些问题呢?
因为个人觉得在推送时携带数据也有它的好处:

  1. 减少一次后续client与server的交互.
  2. push的时候可以引入一些计算,比如灰度什么的,如果当前机器不在灰度列表内也不需要返回任何信息。

谢谢

对于第一点,有没有减少交互不好说,比如我在短时间内操作了多次,那么主动去查询反而交互更少。同时也是这个点,由于网络不可控,可能后面的更新反而新到达,这样无效的网络开销还挺多的。同时服务必须要主动查询,不然无法保证各个服务拿到的配置是一样的,反而增加了复杂度,而且解决这个问题其实又回到了现在这种实现。

第二点没太看懂

现在的设计下每次long polling返回如果发现有变动都会产生一次查询操作。
短时间操作多次应该产生多条通知吧,那么下一次long polling发起时应该只管最后一次通知就可以了,那么push携带数据的话,就不需要再pull啦。 不太理解你说的主动查询为什么会减少交互。

第二点针对一些灰度的配置,如果修改了灰度配置A, 支持的机器为h1,h2. 那针对h1,h2发起的long polling把变更的数据带回去就行。其他机器返回未变更就好.

ps: 我并没看过源码,只是昨天有个同事分享,恰好聊到了这个问题. 😊

@wkcaeser
Copy link
Contributor

这样推送消息就是有状态了,做不到幂等了,会带来很多问题。

麻烦请教下。
能否详细举些例子说下如果推送的时候携带数据都会带来哪些问题呢?
因为个人觉得在推送时携带数据也有它的好处:

  1. 减少一次后续client与server的交互.
  2. push的时候可以引入一些计算,比如灰度什么的,如果当前机器不在灰度列表内也不需要返回任何信息。

谢谢

对于第一点,有没有减少交互不好说,比如我在短时间内操作了多次,那么主动去查询反而交互更少。同时也是这个点,由于网络不可控,可能后面的更新反而新到达,这样无效的网络开销还挺多的。同时服务必须要主动查询,不然无法保证各个服务拿到的配置是一样的,反而增加了复杂度,而且解决这个问题其实又回到了现在这种实现。
第二点没太看懂

现在的设计下每次long polling返回如果发现有变动都会产生一次查询操作。
短时间操作多次应该产生多条通知吧,那么下一次long polling发起时应该只管最后一次通知就可以了,那么push携带数据的话,就不需要再pull啦。

假设网络极度不可靠的时候,您可以分析下各种场景,您的说法都是建立在网络极度理想的情况下

@dumbdonkey
Copy link

这样推送消息就是有状态了,做不到幂等了,会带来很多问题。

麻烦请教下。
能否详细举些例子说下如果推送的时候携带数据都会带来哪些问题呢?
因为个人觉得在推送时携带数据也有它的好处:

  1. 减少一次后续client与server的交互.
  2. push的时候可以引入一些计算,比如灰度什么的,如果当前机器不在灰度列表内也不需要返回任何信息。

谢谢

对于第一点,有没有减少交互不好说,比如我在短时间内操作了多次,那么主动去查询反而交互更少。同时也是这个点,由于网络不可控,可能后面的更新反而新到达,这样无效的网络开销还挺多的。同时服务必须要主动查询,不然无法保证各个服务拿到的配置是一样的,反而增加了复杂度,而且解决这个问题其实又回到了现在这种实现。
第二点没太看懂

现在的设计下每次long polling返回如果发现有变动都会产生一次查询操作。
短时间操作多次应该产生多条通知吧,那么下一次long polling发起时应该只管最后一次通知就可以了,那么push携带数据的话,就不需要再pull啦。

假设网络极度不可靠的时候,您可以分析下各种场景,您的说法都是建立在网络极度理想的情况下

网络不可靠的情况下,您提到可能后面的更新反而先到,这个感觉不会发生啊
现在是一次long polling结束才发起第二次long polling,自身是串行的

@jackie-coming
Copy link

这里有个问题
如果是采取客户端轮询直接返回变更的配置的信息,而不是变更的namesapce
我不理解,为什么会有以下问题:
比如两次修改操作的通知,由于网络问题,客户端接收到的顺序可能是反的,如果这两次修改的是同一个key,就有问题了

我在想客户端的实现不是每次都会做merge操作吗? 如果收到的顺序是反的,会根据releaseId的大小判断,最终还是可以保证拿到的是最新的

@whitefeather2018
Copy link

这里有个问题 如果是采取客户端轮询直接返回变更的配置的信息,而不是变更的namesapce 我不理解,为什么会有以下问题: 比如两次修改操作的通知,由于网络问题,客户端接收到的顺序可能是反的,如果这两次修改的是同一个key,就有问题了

我在想客户端的实现不是每次都会做merge操作吗? 如果收到的顺序是反的,会根据releaseId的大小判断,最终还是可以保证拿到的是最新的

如果长轮询带着配置回来,在并发场景下,长轮询和配置获取的配置可能会有冲突。当前的设计下,长轮询只负责通知,不会出现配置冲突情况

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants