最近参与的项目是比较重数据的, 涉及的数据表非常之多 (MySQL表1000+). 总结的一些问题:
- 改表随意, 直接线上改字段加索引, 表结构缺少设计, 字段名不一致, 缺少整体性
- 线上环境 / 测试环境 / 本地开发 数据库环境 不一致, 本地测过就完事儿了, 没有办法做到问题的复现
- 数据字段定义不够清晰, 数据逻辑关系靠口口相传
- 缺少说明文档, 即便有, 也没能做到及时更新
- 各开发没有协调, 不算上各种手拼SQL的, 用到的ORM框架估计已经把市面上Python的都用上了 (peewee/sqlalchemy/django orm/pony/…), 此外ORM相关模型代码乱丢, 手工维护, 和数据库字段等没有做到严格对应
- 有各种冗余统计表, 更新靠人工脚本维护, 容易出错, 没有办法保证各统计表数据的一致性
针对以上问题, 推动改进的点:
- 将线上数据库定义一次性mysqldump出来, 创建一个管理线上DDL文件的项目(schema), 通过区域/实例/库的方式组织目录结构. 数据库定义变更先走项目MR, 充分讨论审阅. 引入CI检查, 并逐步收紧各项检查规则, 培养起大家表设计的”套路”. 线上改表语句通过MR差异分析自动生成并生成工单, 并在合并的时候做线上变更.
- 测试库数据写入语句导出也纳入项目, 在CI中生成各数据库的docker镜像, 并要求基于生成的数据库镜像做开发/单元测试, 从而去掉了基于数据库测试的不确定性, 避免”在我本地能跑通”类的问题
- 要求写字段注释, 表注释, 数据逻辑要求写清晰. 基于注释生成markdown/html文档, 丢在gitlab pages中供技术/业务同学搜索浏览. 虽然出于性能考虑线上禁止使用外键约束, 但是关联字段在注释中写字段引用关系, 并在CI中做字段类型/命名规范校验. 基于表注释链接生成ER图, 并带上超链接, 便于按图索骥. 禁止使用枚举定义, 通过外部链接关联起来. 总而言之, 全部以DDL文件为准, 生成相关必要的文档, 从而逐步替换掉了之前基于WIKI说明, 确保了数据一处定义, 保证了完整性和时效性
- 基于DDL文件 (实际上是基于生成的镜像) 反向生成各ORM框架的模型定义, 同样按照”ORM/区域/实例/库”的目录结构组织代码, 从而将对应关系固化下来. 由于各ORM的使用已经”病入膏肓”, 没有办法统一起来, 因此先保持各ORM的使用不变, 每种ORM需要的模型定义都生成出来, 现有代码里面手改字段名/表名等逻辑, 通过注入表字段注释的方式, 以及改写模型生成逻辑的方式来兼容, 但是严禁新的特殊处理引入. 逐步替代掉现有项目里散落的各种手工维护模型定义代码. 当然这一块儿是需要基于项目各代码整合到一个仓库的前提下来做, 在短期内项目仓库分散林立的现状下, 先通过子模块引入是比较现实的办法
- 每个统计表写清楚汇总SQL语句逻辑, 并通过脚本提取出来, 从而实现了统计表的自动更新, 跨库连表更新等逻辑框架层面去解决, 解放了人工维护更新脚本的工作量和负担
- “SQL血缘关系” 代码层面禁止掉动态拼SQL, 所有手写SQL的地方做好查询语句登记机制, 从而确保每条线上可能执行的语句都是有据可查的
- 涉及线上业务的相关表的查询/更新逻辑要求写清楚, 从而确保查询计划时可控的(索引覆盖的). 后续考虑在线上数据库中间件引入的过程中, 逐步做到线上查询语句登记准入制度
- 引入archery工具做线上数据库的变更管理流程, 及慢查询相关统计.
总结思路:
- CoC (Convention over Configuration): 不要太多毫无意义可配置的东西, 项目伊始, 就要有良好的框架顶层设计, 不要给太多自由, 用同一套规则/语言来约束下来. 这个字段A同学觉得不合适改个名字, B同学做的过程中觉得不合适又改个名字, 导致相同的东西, 在项目里面有了多个别名, 理解沟通起来特别困难. 要逐步建立起各种规则并执行下去. 规则执行的过程中”既往不咎”, 新的严格准入, 从而渐进式的改良.
- Dry: Dont repeat youself: 所有人都是烦写文档的, 我自己也是坚决不写文档派. 人写的文档都是有模糊歧义的, 尤其是各种API接口文档定义. 所以凡是能通过代码/或者IDL生成管理的, 就不要重复. protobuf / swagger / 等都是很好的工具. SQL本身就是表达能力很强的语言了, 很多简单的逻辑没有必要项目里面强行引入ORM再套一层. 一处定义并做变更管理, 他处自动生成, 根源上解决信息传导不一致的问题.