Aetherance commented on issue #3166:
URL: https://github.com/apache/dubbo-go/issues/3166#issuecomment-3765119269

   目前除了 config center 导致的router 规则变化,还有 registry center 变更导致的源 provider 
列表变更会导致旧 router cache 不可用。现在将 registry center 和 config center 导致的变化一并讨论。
   
   简单介绍一下这两种变化:
   1. Config Center:路由规则发生变化
   2. Registry Center:Provider 列表发生变化
   
   最直接的方式是在发生变化的时候直接删除相应 router chain cache
   
   1. config center change:
   
   用户动态修改路由规则(如 YAML 内容)。有些Router支持“原地热更新”,导致Router Chain 中部分 Router 
在运行时发生规则变化。而 Router Chain 目前无法获知路由规则变化,Router Chain Cache 继续返回按照旧规则计算的内容。
   
   解决方法:
   
   Router 监听 config center 的能力来自于对 ConfigurationListener 接口的实现
   
   
[config_center/configuration_listener.go](https://github.com/apache/dubbo-go/blob/main/config_center/configuration_listener.go)
   
   ```go
   type ConfigurationListener interface {
        // Process the notification event once there's any change happens on 
the config
        Process(*ConfigChangeEvent)
   }
   ```
   
   Process 接口会在 config center 发生规则变化的时候被以回调函数的方式被调用。
   
   以 nacos 为例:
   
   
[config_center/nacos/listener.go:40](https://github.com/apache/dubbo-go/blob/main/config_center/configuration_listener.go#L40)
   ```go
   func callback(listenersMap *sync.Map, _, group, dataId, data string) {
        listenersMap.Range(func(key, value any) bool {
                
key.(config_center.ConfigurationListener).Process(&config_center.ConfigChangeEvent{Key:
 dataId, Value: data, ConfigType: remoting.EventTypeUpdate})
                metrics.Publish(metricsConfigCenter.NewIncMetricEvent(dataId, 
group, remoting.EventTypeUpdate, metricsConfigCenter.Nacos))
                return true
        })
   }
   ```
   
   config center 会将Process包装成一个`callback()` 然后在规则发生变化的时候调用这个函数。
   
   
[config_center/nacos/listener.go:61](https://github.com/apache/dubbo-go/blob/main/config_center/configuration_listener.go#L61)
   
   ```go
   OnChange: func(namespace, group, dataId, data string) {
        go callback(listenersMap, namespace, group, dataId, data)
   },
   ```
   
   OnChange 最终会被 nacos-SDK 执行。
   
   除了 nacos 外 config_center 目录下的其他注册中心也有这样的实现 (这个功能其实是 DynamicConfiguration 
接口所要求的)
   
   
[config_center/dynamic_configuration.go:35](https://github.com/apache/dubbo-go/blob/main/config_center/dynamic_configuration.go#L35)
   
   ```go
   // DynamicConfiguration is the interface which modifys listener and gets 
properties file.
   type DynamicConfiguration interface {
        Parser() parser.ConfigurationParser
        SetParser(parser.ConfigurationParser)
        AddListener(string, ConfigurationListener, ...Option)
        RemoveListener(string, ConfigurationListener, ...Option)
        // GetProperties get properties file
        GetProperties(string, ...Option) (string, error)
   
        // GetRule get Router rule properties file
        GetRule(string, ...Option) (string, error)
   
        // GetInternalProperty get value by key in Default properties 
file(dubbo.properties)
        GetInternalProperty(string, ...Option) (string, error)
   
        // PublishConfig will publish the config with the (key, group, value) 
pair
        // for zk: path is /$(group)/config/$(key) -> value
        // for nacos: group, key -> value
        PublishConfig(string, string, string) error
   
        // RemoveConfig will remove the config white the (key, group) pair
        RemoveConfig(string, string) error
   
        // GetConfigKeysByGroup will return all keys with the group
        GetConfigKeysByGroup(group string) (*gxset.HashSet, error)
   }
   ```
   
   Process 方法完美契合 router cache 的错误 cache 销毁,它能够做到:
   1. 自动检测配置中心的规则变化
   2. 自动执行销毁 wrong cache 的代码
   3. 实现的代码不会分散在各个文件中,并且实现代码量不至于过多(实际上应该会很少
   
   我们只要让 Router Chain 也实现 Process 方法,并将其添加到配置中心的 Listener 中,就能在 Process 
方法中完成配置中心导致的错误缓存的自动销毁。并且可以涵盖任何由配置中心导致的规则变化产生的变更。
   
   2. registry center
   
   registry center 对于源 provider 列表的推送也由 `Process` 方法承担(对于这个方法这里不再过多赘述)。
   
   在获取到 registry center 的变化后,direcotry 会通过 Process 自动执行 refreshInvokers 然后调用 
setNewInvokers
   
   
[registry/directory/directory.go:190](https://github.com/apache/dubbo-go/blob/main/config_center/dynamic_configuration.go#190)
   
   ```go
   // refreshInvokers refreshes service's events.
   func (dir *RegistryDirectory) refreshInvokers(event *registry.ServiceEvent) {
        if event != nil {
                logger.Debugf("refresh invokers with %+v", event)
        } else {
                logger.Debug("refresh invokers with nil")
        }
   
        var oldInvoker []protocolbase.Invoker
        if event != nil {
                oldInvoker, _ = dir.cacheInvokerByEvent(event)
        }
        dir.setNewInvokers()
        for _, v := range oldInvoker {
                if v != nil {
                        v.Destroy()
                }
        }
   }
   ```
   
   这个方法最终调用 router chain 的 SetInvokers,我们可以直接在 SetInvokers 做对旧缓存的处理。
   
   这样可以在 router chain 层面实现对 router chain cache 
的旧缓存的处理,并且侵入性低,实现的代码量非常少。(可能只需要几行)


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to