前言
继上篇文章, 有些小伙伴有些疑问, 比如 A 系统以来 B 系统的接口, 两个系统同时发布最新的代码版本不就不用考虑兼容性了, 但是这个受限于几个情况, 比如需要分组发布, 总共 30 台机器, 需要 10 个一组慢慢发布, 不然流量都打不过来了, 造成系统问题, 或者 A 系统是开放平台外面的系统或者是前端, 也需要给一定的时间来迭代或者灰度发布甚至要永久支持, 这样 B 系统是不得不考虑兼容性的. 不然就像下图这样, 神奇的默契,,,
兼容性场景
接口兼容性解决方案:
修改/删除现有出入参字段
需要和调用方通知到位, 统一评估如果没有影响, 可以删除或者修改现有字段
如果依赖这个字段的系统很多不容易拉齐或者需要尽快上线, 不方便修改/删除字段, 可以通过添加新的相似的字段来完成新的功能
也可以加新版本的相似接口来解决问题, 调用方逐步切换到新的接口
如果一开始考虑到后续版本有可能会变更这个字段, 可以给这个字段加上版本说明, 需要调用方判断版本正确的时候再使用这个字段, 当然要 A 系统考虑不用这个字段引发的问题, 而且一开始设计的时候就考虑到后续版本会变更的情况比较少
修改/删除老的接口方法
需要和调用方通知到位, 统一评估如果没有影响, 可以删除或者修改现有接口
如果依赖这个接口的系统很多不容易拉齐或者需要尽快上线, 不方便修改/删除即可, 可以通过添加新的相似的接口来完成新的功能, 并通知调用方尽快逐步切换到新的接口
如果一开始考虑到后续版本有可能会变更这个接口, 可以给这个接口加上版本前缀, 这样可以不同版本的同一个相似的接口共同存在, 这个要注意不要在接口实现层写更多的逻辑, 不然会造成更多的一些重复的代码
存储兼容性:
缓存兼容性
序列化方式: 这种改变是需要先关闭缓存开关, 让这个缓存 key 读和写的代码都关掉, 清空缓存, 发布最新的代码再打开开关, 让最新的代码写入缓存并消费, 清掉这个相关 key 所有的缓存要注意缓存没有了全部打到了数据库上的流量, 数据库能够撑住, 否则就弄巧成拙了
数据格式: 上面的方式同样可以适合这种场景, 但是这种场景对开发者要求比较高, 需要在用缓存的地方都留有开关, 如果没有这种前置条件, 对数据格式这种变化, 可以采取之前的灰度和弱依赖的方式来比较读取和写入的报错而影响了主要流程, 最好是根据缓存的格式/内容能判断出是否是新的缓存对象来序列化成不同的对象
数据库兼容性
新增字段历史数据问题: 新增的字段一般要设置默认值, 如果没有可能需要人工刷新, 或者应用程序考虑读取数据库的时候如果是空如何处理
字段的修改/删除: 删除的话需要考虑应用程序是否强依赖这个字段, 发布顺序上先发布新的应用程序, 再修改数据库, 修改字段尽量不要操作, 使用新的字段, 先新增字段, 然后发布应用程序来让应用程序来考虑处理新旧字段出现时候执行不同的代码
异步消息的兼容性:
消息和接口也比较像, 要更换格式的时候可以生产者通过添加新的字段(新的消费者代码要注意消费的时候如果没有新的字段, 还要按照旧的字段来消费, 以免有消息的积压, 旧的消息一直无法消费或者消费不正常)
另一个方案是更换成新的 topic + 版本作为新的 topic 来实现代码的兼容(但是要注意旧的消息要留有机器消费完成之后再完全下掉旧的消费者代码)
注册中心的兼容性:
换注册中心相当于开着汽车换发送机, 开着飞机换引擎, 最好是少做, 如果不得不做的时候需要停机, 验证好了再全量切换成最新的注册中心, 以免 rpc 大量报错或者分布式锁/事务失效等情况
日志的兼容性:
更改打印日志的格式的时候最好是在后面添加入参, 别在中间添加入参, 可能会影响报警/统计报表, 最好在修改的时候参考系列第一篇文章, 性能/稳定性上的问题也最好是灰度加弱依赖来保证安全
当然啦, 上面的也不是银弹, 不同的场景需要不同的思考方式, 兼容性只是一种思考的方式, 帮助我们提高系统的稳定性, 需要在实践中不断的踩坑填坑, 心中无兼容性, 手中有兼容性就成为大佬啦, 我们一起努力...
当然啦, 最稳定的做法就是不写代码不变更, 不用考虑兼容了, 这出事概率最低了, 这一秘诀分享给大家~