使用Avro处理不兼容的架构变动 - Elliot


Apache Avro有数据结构模式兼容性的概念,它允许我们确定一个数据结构是否与一个或多个较早或较新的数据结构在某些兼容性约束方面兼容。我们可以有兼容的变化,这必然意味着我们也可以有不兼容的变化。
在这种情况下,我们可以做什么来实现这些破坏性的变化,同时尽量减少对消费者的干扰,不管是流媒体还是批处理。
 
假设我们有一个业务需求,我们需要把一个包含复合全名的字符串字段,变成一个有记录封装的独立名字元素的字段。从字符串到记录的转变显然是一个状态的变化。
当前状态:

record Person {
   string name; // example: "Joan Smith"
}

最终的变化状态:

record Person {
   Name name;
}
record Name {
   string first_name; // example: "Joan"
   string last_name;  // example: "Smith"
}

第1步 - 添加一个默认值
你可以删除有默认值的字段,所以我们现在添加一个默认值,以便以后可以删除该字段。选择一个默认值,这个默认值在消费者系统中没有任何意义,以后可以用来识别这个字段是废弃的。继续为你的消费者用数据填充该字段。

record Person {
   string name = "<DEPRECATED>"; // example: "Joan Smith"
}

 
第2步 - 引入新的字段(可能有一个默认值)
我们正在引入我们在最终状态下想要的字段。但是我们还不能使用所需的字段名,因为它将被重载。
此外,对于FORWARDS或FORWARDS_TRANSITIVE以外的兼容模式,我们必须提供一个默认值。
生产者应该用有效的数据来填充这两个字段--现有的和新的。现在向所有消费者传达他们应该开始使用新字段。

record Person {
   string name        = "<DEPRECATED>"; // example: "Joan Smith"
   Name   person_name = {"first_name":"<NOT_IN_USE>","last_name":"<NOT_IN_USE>"};
}
record Name {
   string first_name; // example: "Joan"
   string last_name;  // example: "Smith"
}

 
第3步 - 删除旧字段
因为我们的旧字段有一个默认值,而且现在没有消费者在使用它--我们现在可以删除它。
record Person {
   Name person_name = {"first_name":"<NOT_IN_USE>","last_name":"<NOT_IN_USE>"};
}
record Name {
   string first_name; // example: "Joan"
   string last_name;  // example: "Smith"
}

 
第4步 - 删除默认值
现在我们可以从新字段中删除默认值。请注意,这不适用于FORWARDS,因为该字段可以在步骤2中声明,而没有默认值。
record Person {
   Name person_name;
}
record Name {
   string first_name; // example: "Joan"
   string last_name;  // example: "Smith"
}

 
 
第5步 - 重命名字段
最后,我们可以通过提供一个带有所需名称的别名来有效地重命名它。
record Person {
   @aliases(["name"])
   Name person_name;
}
record Name {
   string first_name; // example: "Joan"
   string last_name;  // example: "Smith"
}