项目现状:
在做排序模型时,需要大量的模块,模块内部需要配置,模块之间彼此耦合,配置与代码耦合,配置参数上百项。特征修改一次,上线一般需要2周,甚至一个月。
具体衡量:
目前有7个垂直业务的排序项目,涉及pc m app三端,假设每个客户端有100个参数。将是100*7*3=共2100个参数。如果所有参数由统一的安排和默认规则,大家统一遵守,还比较好。——可惜,项目持续2年左右,人员流动,代码迭代,导致很多参数彼此耦合,且分散在不同的模块,设置配置与代码耦合在一起,改配置必须动代码。改了A的配置,需要动B的代码。你要修改A,你就必须找到所有耦合的其他模块,并正确的修改。
长期的成本代价:假设每次修改,你有0.8可能性都找到所有耦合模块;且有0.8的可能性都改好,那么你成功的概率只有0.64。当前没有文档,没有测试程序,每次修改完,运行需要2小时左右。一个团队10人左右,每日协作,效率折扣10*0.64=6.4。——简单按照200万计算,每月浪费72万,人力成本非常高,且代码维护成本高,设置导致人员流失。
以下以自行车 m端 为例:配置文件大概有(都是采用 KV键值对的方式)
2015 trainingsample.properties.pc_zixingche
2015 zixingche_m_cal.cfg
2015 zixingche_m_ctr.properties
2015 zixingche_m_docfea.properties
2015 zixingche_m_personal.properties
2015 zixingche_m_trainingsample.properties
以及:scorer.conf; plugin.conf
分析问题点:
1. 代码与配置耦合。甚至模块A的配置与B的代码耦合在一起。
2. 配置与配置耦合。多个配置文件,分散在不同的目录。彼此不能协调。
3. 模块间代码耦合。某些配置硬编码在代码中,且硬编码的配置耦合。
4. 变量定义混乱。例如:zixingche secondBike ershouBike
原因:
1. 根本原因:管理问题。多人工作按照模块划分,导致不能全局、统一管理配置。(戴明说90%的问题是管理问题。)
2. 配置混乱,导致代码不能自动化,代码重复拷贝修改不重用。配置作用下降,导致开始在代码中硬编码配置参数。
3. 代码是多种语言混合在一起的。shell java python scala c/c++
方案:
统一采用python来做胶水,粘合多语言代码的协作。丢弃KV对的ini配置方式,统一采用xml,且配置合并在一个文件中。仅仅用shell来进行调度——简化shell的使用量,作为低级脚本语言,代码可读性差,各种lib库缺乏。
结果:
耗时4个月,配置理顺,代码完全重构,解耦,所有类目、三端,都复用一份代码。——加快项目的迭代速度。——减少配置,采用YII提倡的理念:用规范代替配置。
具体方案:
XML统一配置所有参数都统一到这一份文件中。
4个要点:
1.每个模块作为一个Section, 模块配置内聚。
2.模块间的耦合,采用KV映射的方式,格式Section:Label 。——设计点:彼此的依赖,只需要修改一处,不需要跨模块修改。
3.用规范代替无约束的自由配置。——设计点:方便代码自动化;方便编写测试代码。
4.采用featureList ——设计点:由于特征较多,字段不同,导致XML解析函数膨胀,修改频繁。
5.跨语言模块,可将XML dump成json格式,方便java scala 等使用。——设计点:文档结构模块,是java代码,解析XML需要编写XML解析函数,这会导致XML解析有python java scala 等多个版本,彼此需要保持一致。为此,将XML中文档结构对应section的XML配置转换为json格式,方便java解析——google提供的Gson 解析工具,非常方便,极大的简化了配置解析 。
6,XML解析后,全部转换为python的dict结构,且内容都是静态的,不再有${cate} 以及hadoopLog:baseLog之类的KV对,都已经是具体的、静态的参数、路径。python再去调用其他模块的业务代码时,将具体的、不需要转化的参数传递给业务模块。例如:创建hive表,采用python 代码os.system(hiveCmd_To_CreateHiveTable)—— 其中,hiveCmd_To_CreateHiveTable是很长的创建复杂hive表的长字符串,其内容都是python阶段处理好的,已经是静态的参数、路径。例如:python 调用shell 脚本进行业务处理,os.system(shellCmd_hadoop_job),其中,shellCmd_hadoop_job是hadoop steaming的长字符串,其内容都是python阶段处理好的,已经是静态的参数、路径。