Comments (19)
from go-archaius.
是的这个问题其实几年前我就提出过,只是一直没能落地优化
为什么没有落地啊?有什么困难?
from go-archaius.
涉及接口变更,生态已经长成,这会导致太多开发者需要重新适配
from go-archaius.
涉及接口变更,生态已经长成,这会导致太多开发者需要重新适配
我倒是觉得这是个修 bug 的更改啦。目前这个设计,业务是很难正确响应配置变更的。且不说前面提到的把配置值复合成单一项对业务带来的不便,go-chassis 自己里面的配置组织,就不是同模块做成一个yaml配置的了,这些配置上的热更新已然很难做好了,比如 go-chassis 里的 CircuitBreakerEventListener,是一次更新多项,就会响应多次、Flush多次的吧,也许还不到bug的程度,但总不是很好的行为。(稍微跑题一个,router 的具体逻辑我还没太搞懂,看到里有个 NewServiceRule函数有个yaml.Unmarshal 的调用,这不是穿透了 archaius 的设计了吗?可以假设所有配置源都能给出 yaml 格式的配置值吗?)
目前这个库star 75,也还没有到不能改的程度吧?相关两头:配置源和业务。配置源主要就是 archaius 内置的这些加一个 apollo 吧?业务方面我不知道你们还有哪些业务要考虑,我的角度最主要的业务方就是 go-chassis 自己。若是真是担心关联的业务方太多,加一个 RegisterModulerListener 之类的API,在不打破原有 RegisterListener (标记为 deprecated, 择机再删掉)的支持基础上,增加模块变更整体通知的支持,如何呢?
from go-archaius.
嗯 关于go chassis配置文件设计,确实有问题。要解决这个问题我们有两个做法,
方案一:从配置中心去做。
我们的新配置中心kie,做出了如下改变
除了key,value之外扩展出了value type,内容是yaml,json,ini,java properties这种。基于这个机制我们会更改自己的设计,用户在设置key value时就可以整段的录入,比如你说的CircuitBreaker配置,value内容是整段内容,触发更新后 listener就可以根据value type进行处理了,这个时候key字段只需要定死,比如只要是以“servicecomb.circuit.”开头都是熔断类配置, 就可以注册监听器了
方案二:如2位所述
from go-archaius.
我们的新配置中心kie,做出了如下改变
kie 不是也从 archaius 接入?还是说准备完全弃用 archaius ? 如果kie 只是archaius 的一个配置源,那这个问题就还在,archaius 既然想要支持多配置源,就不能只有 kie 一个配置源没问题吧
而且kie 听起来,一个key 对应的value 是一段 json/yaml/ini ,一定是一整段的意思?那么原先 archaius 的 Get / GetBool/ GetInt 等等接口又准备何去何从?准备如何支持用户读取一整配置里的一项呢?
from go-archaius.
kie 不是也从 archaius 接入?还是说准备完全弃用 archaius ? 如果kie 只是archaius 的一个配置源,那这个问题就还在,archaius 既然想要支持多配置源,就不能只有 kie 一个配置源没问题吧
-- 没错,多source的话,关于apollo的适配可以考虑定义key的规范为xxx.json,xxx.yaml也就是像系统文件扩展名那样定义key来使archaius适配。
而且kie 听起来,一个key 对应的value 是一段 json/yaml/ini ,一定是一整段的意思?
-- 对于不同类型archaius有两种处理方式(通过options中的配置项决定),一种方式是不管value type是什么都当正常raw数据处理,直接返回给业务调用者,一种方式是根据value type进行key value的切分(或者说拍平yaml,json)
那么原先 archaius 的 Get / GetBool/ GetInt 等等接口又准备何去何从?准备如何支持用户读取一整配置里的一项呢?
-- 无论value type是什么,都可以用Get搞定
from go-archaius.
没错,多source的话,关于apollo的适配可以考虑定义key的规范为xxx.json,xxx.yaml也就是像系统文件扩展名那样定义key来使archaius适配。
似乎扯远了一点,我们讨论的问题,不是具体的单一个配置源的问题。它不是apollo 的问题(File 配置源/Memory配置源不是都一样),也不是 kie 能解决的问题。archaius 设计要支持多配置源,为业务屏蔽了配置源的细节,配置源应该是对等的。虽然看上去你们从 kie 得到了一些启发,但是希望别把它做成特例。
回到现在的问题:
我理解的 archaius 主要接口目前
- Get/GetXxx : 用于读取单个配置项的值,GetXxx 接口提供了轻量的使用方式(无须反射反序列化等)给用户,还是有价值的。这些接口目前只能读完整 key对应的配置,Get/GetValue 可以扩展到支持读一个前缀,来支持读一个模块的所有配置(当然我觉得这样没有意义,要配合反序列化对业务才有用,不如直接给个 Unmarshal(key, &conf) 接口)。
- RegisterListener 支持订阅配置变更,变更通知行为是,n个 key 匹配到订阅的 pattern 时,会分 n 次通知。
在这个现状基础上,可以清楚地看到 RegisterListener 的通知行为是不符合实际业务场景的,我对你们的思路理解是:
设计一个返回 Raw 配置的能力,跟解决上述问题没有一点关系。把问题解决了的是,为业务设定了一个非明文的限制:有更新关联的配置项,只能做成一项,值做成复合结构。一方面,未满足这个非明文限制的业务,比如 go-chassis 里的那些,还是要改的,要改配置设计。其它业务方仿照这个方式设计理念都要硬改过来,这不是也一样破坏兼容破坏生态?另一方面必然导致 GetXxx 这些接口能力受限,复合的配置值,业务关心的最终还是内部的每一项,GetXxx 接口没有能力拿到的。所以做完这些之后,似乎 archaius 没有变得更好。
然后关于返回 Raw 的能力,正如前述,业务拿到Raw 的配置意义并不大,最终还是解析得到具体的配置项。所以对于你提到的
一种方式是不管value type是什么都当正常raw数据处理,直接返回给业务调用者
我其实不是很理解,新增这个选项这个能力的意义。似乎就是因为,限制业务配置值必须是复合结构,处理复合结构需要 raw 数据?
from go-archaius.
回到这个场景:
项目中配置的使用,一般都是多个配置项合在一起使用,比如mysql的配置一般都会有账号、密码、端口地址等。如果在项目运行过程中,需要修改该项配置,同时修改了账号、密码和端口。event就会通知同一个模块多次,业务方没有考虑这种情况的时候,就会热更新多次,存在问题,即使订阅多个key,感觉也不能避免回调方回调多次的情况。
既然archaius事件是多个,这说明你一次在配置中心改了好几个key value对,这操作真的很繁琐,没从运维人员的真实需求出发去设计,我作为运维人员改好db的配置了,然后去业务配置管理改配置,要操作好几个kv记录,这就像go chasssis的circuit breaker配置一样反人类。我的答案是:运维人员其实希望操作一条配置记录就可以管理业务方的db配置,所以把配置作为整体的段落保存在远程配置中心,archaius拉过来把这个段落当做value用。从使用者的真实需求出发,从设计一开始就考虑他们是怎么操作的
“要改配置设计。其它业务方仿照这个方式设计理念都要硬改过来,这不是也一样破坏兼容破坏生态?“
--- 回答你的关于我这边也重新设计的问题,没错,我必须重新设计将反人类的部分重做
from go-archaius.
既然archaius事件是多个,这说明你一次在配置中心改了好几个key value对,这操作真的很繁琐,没从运维人员的真实需求出发去设计,我作为运维人员改好db的配置了,然后去业务配置管理改配置,要操作好几个kv记录,这就像go chasssis的circuit breaker配置一样反人类。我的答案是:运维人员其实希望操作一条配置记录就可以管理业务方的db配置,所以把配置作为整体的段落保存在远程配置中心,archaius拉过来把这个段落当做value用。从使用者的真实需求出发,从设计一开始就考虑他们是怎么操作的
archaius的设计不应该为特定的某一种配置中心的操作而定制,工具应该是解放业务的,而不是反过来让业务束手束脚。
针对你提到的这个运维操作很麻烦的事情,虽然我觉得同时改两个配置居然很麻烦一定是配置中心没做好,与archaius 不太相关。但既然觉得业务要因为archaius去为运维考虑这个,我们不妨来分析分析:
实际的业务场景下,一个mysql 的配置何止用户名密码,还有连接读写各种超时及连接池几个大小的各种配置,如果你真的了解这个场景的话。除去 mysql 之外,各种业务模块也会有各自的多项配置的场景。
业务的配置项的个数,是由业务的特性而定的。你把它做成一个key,运维人员操作时,需要修改的,依然是具体的业务配置项。我假设你把它串成一段json 吧,像这样:
- mysql : {"user": "root", "pwd": "123", ...}
那运维的修改是
- mysql : {“user”: "rootnew", "pwd": "456"}
一样是两处编辑,何来的简化?
运维的大脑里处理的,不会是一个复合的结构,而依然是具体的用户密码超时连接数(用户名密码也不需要可读不需要理解,但超时连接数就很需要了。反倒是做成一个复合结构的值展示在他眼前的时候,如果配置中心没有做好的话,他要自行解析修改再打包成所要的格式,这是不是更反人类?)。
退一万步,那怕业务配置项拆成了100个,配置中心一样可以提供输入复合配置的功能给运维用(现实中也已经有这种产品这种功能存在),编辑好后一次页面操作一次发布,何来不便?
下面还有另两个问题,相关性不那么大,同样是配置中心做得够好的话可以解决的。
打成了复合结构了之后,复合结构内的
其一、配置中心在发布配置前需要要差异对比展示,发布配置后需要有历史变更的展示。
一个这样的差异展示:
- 旧 mysql: {"user": "root", "pwd": "123", ...}, 新 mysql:{“user”: "rootnew", "pwd": "456"}
和一个这样的差异
- 旧 mysql.user: root 新 mysql.user: rootnew
- 旧 mysql.pwd: 123 新 mysql.pwd: 456
是否高下立判?更别提如果有连接数之类的需要可读需要理解的配置。
其二、分折配置项的形式,配置建立好后,配置key 已定,修改只涉及值。合并配置项成复杂结构的形,复杂结构内的 key 就凭白多了被改到的风险了。这是不是也是反人类呢?
这里的种种,源头都在于复合的结构是存储是传输用的,运维的人脑处理的,依然是单项的值。
from go-archaius.
旧 mysql: {"user": "root", "pwd": "123", ...}, 新 mysql:{“user”: "rootnew", "pwd": "456"}
这个json按照pretty格式输出后,不就好对比了么
一样是两处编辑,何来的简化?
三种接口 cli,rest api,ui,改几个mysql配置项交互几次,不是反人类么,尤其是ui的加载速度,现在go chassis有好几个治理规则都有这种错误的设计
from go-archaius.
旧 mysql: {"user": "root", "pwd": "123", ...}, 新 mysql:{“user”: "rootnew", "pwd": "456"}
这个json按照pretty格式输出后,不就好对比了么
是的,我不怀疑特定的配置中心可以做更多的工作去帮助运维。这只是配置中心的问题。串穿始终的思路,是解放业务。
archaius 既然想要支持多个配置源,就不要为特定的配置中心适配,还请匆忘初心。kie 我并不关心。
一样是两处编辑,何来的简化?
三种接口 cli,rest api,ui,改几个mysql配置项交互几次,不是反人类么,尤其是ui的加载速度,现在go chassis有好几个治理规则都有这种错误的设计
这里我没有理解。是否误解了我的问题或误解了编辑?
针对这一句一样是两处编辑,何来的简化,我对比的两方,是
- 折开配置项的运维工作
与
- 合并配置为复杂值单一配置项的运维工作
我结论是它们并无区别,区别是由于配置中心的造成的而非以上的两种设计选择造成的,与 archaius 无关。折开配置项,也要编辑两处,合并也是编辑两处。编辑与发布配置从来是两个分开的动作。想象一下,你打开一个 mysql.yaml 或 mysql.json ,编辑它的两处,保存,使用 archaius 的业务把这个文件的内容当作单一的配置项,还是当作折开的多项,与你的编辑有任何关系吗?
from go-archaius.
嗯 那我是说编辑+之后的生效操作
你期望:
- 点开userid文件/ui表单
- 编辑一个userid
- 点击提交/执行命令/调API
- 点开密码文件/ui表单
- 编辑一个密码
- 点击提交/执行命令/调API
我期望
1.点开mysql配置文件/ui表单
2.编辑一个userid
3.编辑一个密码
4.点击提交/执行命令/调API
archaius 既然想要支持多个配置源,就不要为特定的配置中心适配,还请匆忘初心。kie 我并不关心。
看下最早的提交对接的config center,也没有value type字段,我们的方式就是key是文件名,value是文件内容。
from go-archaius.
回到本身我说的这个问题
涉及接口变更,生态已经长成,这会导致太多开发者需要重新适配
因为一开始的设计,所以我才从配置项设计给出了别的规划方式。并不是说我一定非得这么设计archaius,而是接口已形成,没法改(另外接口的设计人也不是我)
from go-archaius.
你期望:
点开userid文件/ui表单
编辑一个userid
点击提交/执行命令/调API
点开密码文件/ui表单
编辑一个密码
点击提交/执行命令/
啊,我上面无论任何表述都得不出这个结论吧?
同一模块的配置当然是一起的啊。当然编辑两处,发布一次啊。至于页面编辑,点一次点两次都可以毫无难度。本质跟编辑配置文件再保存没区别。
因为一开始的设计,所以我才从配置项设计给出了别的规划方式。并不是说我一定非得这么设计archaius,而是接口已形成,没法改(另外接口的设计人也不是我)
那我们考虑下加接口不动原有listener的方向呢?
from go-archaius.
点开userid文件/ui表单
编辑一个userid
点击提交/执行命令/调API
点开密码文件/ui表单
编辑一个密码
点击提交/执行命令/调API
看起来是,你们的配置中心改一项就要提交一次。
from go-archaius.
加接口可以,你们设计提PR即可
from go-archaius.
加接口可以,你们设计提PR即可
好。
那我考虑做成这样:
- 新增一个 RegisterModuleListener(event.ModuleListener, prefix ... string) 接口
- 针对 File/Mem/Apollo/Kie/ConfigCenter 等配置源,在对应的 Watch 函数中,加上触发一次ModuleListener 回调的修改。ENV配置源 原本就没有Watch,本身也不是一个实用的配置源,不改。
可能有争议的点:
- ModuleListener 这个命名,不知有无更好的建议
- 区配 prefix 还是正则?这里我的考虑是,
- 一般有关联的配置是相同模块的配置,业务的热更新也是以模块来组织的。而相同模块的配置有相同的前缀应该是合情合理的要求。
- 即便有不同模块的配置有关联需要同时更新(假设假设假设我有一份很烂很烂很烂的代码,redis 模块用了mysql.user 和 redis.pwd 去联 redis),配置源的组织本来就很难保证它们的修改同时被发现被下发。
- 正则带来一个不便是,如果我没有写成 ‘^xxxx$’ ,就很容易匹配到其他的配置
所以选择了 prefix。不知道你这边有无其它考虑?
from go-archaius.
嗯 不一定所有source都需要适配ModuleListener,这个你实现你需要的就行
叫BatchEventsListener,就prefix吧,没问题
from go-archaius.
Related Issues (20)
- 与servicecomb-kie项目相互依赖
- 对 kie status进行支持
- Ohhh, this is a bigger than bigger bug HOT 1
- 对于配置文件的配置读取,新增环境变量语法的兼容。 HOT 1
- 添加一个优先级为5的配置源 HOT 1
- 当获取不到配置的时候,指针类型应该赋予nil HOT 1
- replace open-logging with zerolog
- ssl不支持有bool类型的参数 HOT 3
- Add GetConfigsWithSourceNames() api to get all configs and its sources
- 模块事件行为优化 HOT 1
- 实现内存配置项备份特性 HOT 3
- Set方法存在锁没有释放问题
- apollo 配置支持解析 yaml json 等 HOT 2
- 华为云官网配置中心指导配置type为config_center,实际应该是config-center
- configmap can not be UnmarshalConfig HOT 2
- 希望增加kie project参数配置 HOT 3
- github.com/go-chassis/[email protected]: invalid pseudo-version: does not match version-control timestamp (expected 20180927015433) HOT 1
- 访问空指针 HOT 1
- go const更新导致代码检查不通过
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from go-archaius.