记一次黑名单方案设计引发的设计思考

背景

接到需求: 某些ECS规格族天然不具备宕机迁移的能力, 例如某些软件License与硬件ID绑定, 或者加密信息与硬件绑定, 宕机迁移会导致License失效或者加密信息无法解密.
而在正常宕机迁移流程里默认所有规格族都会无差别执行.
因此需要代码改造下, 识别这些规格族, 然后跳过执行流程.

解决方案1: 黑名单模式

即在配置项里维护一个黑名单List, 伪代码如下:

blackList = getFromConf();
if(flavorFamily in blackList) {
    return;
}
down_migration_execute();
  • 优点: 开发起来简便, 灵活. 也是第一反应想到的方案.
  • 缺点: 使用该方案, 后续发现问题很多:
    • 代码容易踩坑:
      • 如果配置项是用数据库字段存储, 那么一定要注意字段的类型&size, 如果太小会导致后续如果名单扩容, 字段溢出, 从而无法实现效果.
    • 运维成本过高:
      • 因为黑名单与实例规格族本身属性是分散开来的.
      • 如果后续新增规格族, 需要有个地方来通知产品的同学, 规格族需要有是否宕机迁移这个属性, 然后需要他们跑到另外一个地方去维护下这个黑名单.
      • 尤其是在不同类别的规格族由不同产品同学负责且人员流动性大时, 没办法通知到每位同学.
      • 但一旦遗漏, 可能会导致线上问题.

解决方案2: 属性模式

  1. 是否宕机迁移作为一个天然属性/字段, 添加在规格族/规格表上.
  2. 该属性作为必填属性, 在新规格族上线时, 对应产品在填写其他属性时(例如cpu/mem配比等), 该属性也需要一并填写.

伪代码如下:

flavorDef = getFlavorDef(flavor)
if(!flavorDef.canDownMigration) {
    return;
}
down_migration_execute();
  • 优点:
    • 后续运维成本极低, 新规格族/规格上线时, 该字段与其他属性类似, 作为一个必填选项, 让产品同学统一维护.
    • 代码整体也更面向对象一些, 即更加高内聚, 低耦合.
  • 缺点:
    • 前期改造量&风险较大:
      • 表里需要增加字段, 尤其是针对大表且访问频发的表, 有可能锁表, 导致线上问题.
      • 如果有存量大量的规格族数据, 需要进行一波批量订正.

适用场景探讨

总的来说,

  • 黑白名单只适合作为一个短期内临时的方案/开关, 且在不久之后, 黑白名单需要全部清空.
    • 例如上述例子中, 某些规格需要 临时 禁止宕机迁移, 但一周之后, 这些规格需要重新enable.
    • 这个时候临时使用黑白名单机制凑合下还行.
  • 而属性方案, 就更适合作为一个常态化的机制.
    • 例如上述例子中, 某些规格需要的是否禁止宕机迁移是天然的一个属性, 规格一旦设定为 禁止宕机迁移 就不会再修改了.

总结

更加推荐使用”属性模式”, 这也是一次之前自己错误设计的反思, 也吃到了很大的苦果.
后续在使用”黑/白名单”作为方案前, 一定要再想下是否是临时方案, 如果不是, 那么尽量能作为实体上的一个属性来维护.
虽然属性方案, 前期改造量可能较大, 但长期来看, 优点是远远大于缺点的.