本节书摘来自华章出版社《大数据系统构建:可扩展实时数据系统构建原理与最佳实践》一书中的第3章,第3.2节,南森·马茨(Nathan Marz) [美] 詹姆斯·沃伦(JamesWarren) 著 马延辉 向 磊 魏东琦 译,更多章节内容可以访问云栖社区“华章计算机”公众号查看。
3.2 Apache Thrift
Apache Thrift(http://thrift.apache.org/)是一个可以用来定义静态类型化的、可实施模式的工具。它提供了接口定义语言,以通用数据类型的术语来描述模式,之后该描述可以用来自动生成多种编程语言的实现。
我们对APACHE THRIFT的使用:Thrift最初由Facebook开发,用来构建跨语言服务。它可以用于诸多目的,但我们将缩小讨论范围,只关注它作为一个序列化框架的使用。
其他序列化框架
还有其他类似于Apache Thrift的工具,如Protocol Buffers和Avro。记住,本书不是对每种情况的所有可能的工具提供调研,而是选用适当的工具来说明基本概念。作为一种序列化框架,Thrift已经经过了生产环境的完全测试并得到了广泛使用。
Thrift的核心是结构体(Struct)和联合体(Union)的类型定义。它们是由其他字段组成的,如:
原始数据类型(string,integer,long与double)
其他类型的集合(list,map与set)
其他结构体和联合体
一般来说,用联合体来表示节点是很有用的,结构体是边的自然表示,属性则将联合体和结构体结合起来使用。这对于需要表示SuperWebAnalytics.com模式组件的类型定义来说是有效的。
3.2.1 节点
对于SuperWebAnalytics.com用户节点,通过用户ID或浏览器Cookie标识某个人,而不会同时用这两个元素标识他。这种模式对于节点是常见的,且完全匹配联合体数据类型—单个值可能有几种表示方式。
在Thrift中,联合体通过罗列出所有可能的表示来定义。下面的代码使用Thrift联合体定义SuperWebAnalytics.com节点:
注意:联合体还可用于单一表现形式的节点。联合体允许模式随着数据的演变而演变—我们稍后将在本节中进一步讨论这个问题。
3.2.2 边
每条边都可以表示为包含两个节点的结构体。边结构体的名称表明了它所代表的关系,边结构体中的字段包含了参与该关系的实体。
该模式定义非常简单:
Thrift结构体的字段可以表示为required或optional。如果一个字段被定义为required,那么必须为该字段提供一个值,否则Thrift会在序列化或反序列化时给出一个错误。因为图模式中的每条边都必须有两个节点,所以在这个例子中它们是必需的字段。
3.2.3 属性
最后让我们来定义属性。属性包含一个节点和属性的值。因为值可以是诸多类型中的一种,所以最好使用联合体结构来表示。
首先定义页面属性的模式。页面只有一个属性,所以很简单:
接下来定义人的属性。正如你看到的,位置属性更为复杂,需要另一个结构体来定义:
位置结构体是很有意思的,因为city、state和country字段可能被存储为单独的数据片。在这种情况下,它们是密切相关的,因此把它们都放在一个结构体作为可选字段是讲得通的。当使用位置信息时,你可能会希望得到所有字段。
3.2.4 把一切组合成数据对象
此时,边和属性被定义为不同的类型。在理想情况下,你想将所有数据存储在一起,为访问你的信息只提供一个接口。此外,如果存储在单个数据集中,还能使得数据更容易管理。这可以通过将每个属性和边的类型封装到DataUnit联合体来实现—如代码清单3-1。
代码清单3-1 完成SuperWebAnalytics.com模式
每个DataUnit与其元数据成对保存在一个Pedigree结构体中。Pedigree包含了信息的时间戳,但也可能包含调试信息或数据源。最后的Data结构体对应了基于行为模型中的一个行为。
3.2.5 模式演变
Thrift的设计使得模式可以随时间而演变。这是一个至关重要的属性,因为随着业务需求的改变,你将需要添加新类型的数据,并且想尽可能轻松地这样做。
演变Thrift模式的关键是与每个字段相关联的数值标识符。把这些序列化形式的ID用于标识字段。当想要改变模式但仍要向下兼容现有的数据时,你必须遵守以下规则:
字段可能被重新命名。这是因为对象的序列化形式使用字段ID而不是名称来标识字段。
一个字段可能被删除,但你绝不能重用那个字段ID。当反序列化现有数据时,Thrift将忽略字段ID没有包含在模式中的所有字段。如果你重用之前删除的字段ID,Thrift会尝试反序列化旧数据到新的字段,这将导致无效或不正确的数据。
只有可选的字段可以被添加到现有的结构体。你不能添加必需的字段,因为现有的数据不会有这些字段,所以不能被反序列化。(注意:这并不适用于联合体,因为联合体没有必需和可选字段的概念)
作为一个例子,如果想要改变SuperWebAnalytics.com模式来存储一个人的年龄和网页之间的链接,那么应对Thrift定义文件做出以下改变(变化的用粗体表示)。
代码清单3-2 扩展SuperWebAnalytics.com
注意:添加新的年龄属性是通过添加到相应的联合体结构完成的,并且新的边可以通过将它添加到DataUnit联合体来实现内嵌。