动机

此处提供的接口分类用于指导接口的开发人员和用户。该分类指导开发人员声明接口的目标受众或用户以及其稳定性。

对接口用户的好处:了解使用或不使用哪些接口以及它们的稳定性。

对开发人员的好处:防止意外更改接口,从而意外地影响用户、其他组件或系统。这在具有许多开发人员的大型系统中特别有用,这些开发人员可能没有项目的共享状态/历史记录。

接口分类

Hadoop采用以下接口分类,这个分类是从OpenSolaris分类派生出来的,也在一定程度上借鉴了Yahoo内部使用的分类。接口具有两个主要属性:受众和稳定性。

受众

受众表示接口的潜在使用者。虽然许多接口是内部/私有的,供实现内部使用,另一些是外部/公共接口,面向更广泛的应用程序和/或客户。例如,在posix中,libc是一个外部或公共接口,而内核的大部分是内部或私有接口。此外,一些接口针对其他特定的子系统。

识别接口的受众有助于定义打破它的影响。例如,打破一个受众是一些特定子系统的接口的兼容性可能是可以接受的。另一方面,打破数百万互联网用户依赖的协议接口可能是不可接受的。

Hadoop使用以下种类的受众,按照可见性逐渐增加/扩大的顺序:

  • Private(私有)
    • Private接口是项目内部使用的(例如HDFS或MapReduce),不应被应用程序或其他项目使用。大多数项目的接口都是Private(也称为项目私有)。除非有意将接口公开供外部使用,否则应将其标记为Private。
  • Limited-Private(有限私有)
    • Limited-Private接口由指定的一组项目或系统使用(通常是密切相关的项目)。其他项目或系统不应使用该接口。对接口的更改将与指定的项目进行通信/协商。例如,在Hadoop项目中,某些接口是LimitedPrivate{HDFS,MapReduce},它们是专用于HDFS和MapReduce项目的。
  • Public(公共)
    • Public接口可供任何应用程序通用使用。

变更兼容性

对API的更改可以分为两大类:兼容和不兼容。兼容的更改是指符合以下标准的更改:

  • 没有删除任何现有功能,
  • 没有以阻止构造为在更改之前使用接口的客户端使用它们的方式修改任何现有功能,并且
  • 没有添加需要更改在更改之前构造为使用接口的客户端的功能。

不符合这三个标准的任何更改都是不兼容的更改。简而言之,兼容的更改不会破坏现有的客户端。以下是兼容更改的一些示例:

  • 向Java类添加一个方法,
  • 向RESTful Web服务添加可选参数,或者
  • 向XML文档添加一个标签。
  • 将接口的受众注释更改为更广泛的(例如从Private到Public),或将更改兼容性注释更改为更严格的(例如从Evolving到Stable)。

以下是不兼容的更改的一些示例:

  • 从Java类中删除一个方法,
  • 向Java接口添加一个方法,
  • 向RESTful Web服务添加一个必需的参数,或者
  • 在JSON文档中重命名字段。
  • 将接口的受众注释更改为更狭窄的(例如从Public到Limited Private),或将更改兼容性注释更改为更严格的(例如从Evolving到Unstable)。

稳定性

稳定性表示接口有多稳定以及何时允许对接口进行兼容和不兼容的更改。Hadoop的API具有以下稳定性级别。

Stable(稳定)

稳定的接口作为首选的通信手段公开。预期在一个主要版本内不会对稳定的接口进行不兼容的更改,因此它是一个安全的开发目标。稳定的接口在次要版本之间可能进行兼容的演变。

允许的不兼容更改:主要(X.0.0) 允许的兼容更改:维护(x.y.Z)

Evolving(演进中)

演进的接口通常是为了让用户或外部代码在其稳定之前就能够使用某个功能。但是,对于接口应该“最终”稳定并被提升为稳定,这并不是将接口标记为演进的要求。

对于演进接口,只有在次要版本中才允许不兼容的更改。

允许的不兼容更改:次要(x.Y.0) 允许的兼容更改:维护(x.y.Z)

Unstable(不稳定)

不稳定的接口不提供兼容性保证。不稳定的接口不一定是不稳定的。通常会公开不稳定的接口,因为用户或外部代码需要访问不用于消费的接口。将接口公开为不稳定的接口是为了明确指出,尽管公开了接口,但这不是首选的访问路径,并且对其不提供兼容性保证。

对不稳定接口的不兼容更改可以在任何时候进行。

允许的不兼容更改:维护(x.y.Z) 允许的兼容更改:维护(x.y.Z)

Deprecated(已弃用)

已弃用的接口可能会在将来被删除,不应使用。即便如此,已弃用的接口将继续正常运作,直到被删除。可以删除已弃用接口的时间取决于它是稳定的、演进中的还是不稳定的。

如何记录分类?

Hadoop的API将使用org.apache.hadoop.classification包中的注解记录每个接口或类的受众和稳定性。

由maven目标javadoc:javadoc生成的文档中仅列出了公共API。

可以通过它们所在的包的受众来推导Java类和Java接口的受众。因此,将每个Java包的受众声明为public或private(以及私有受众变体)是有用的。

其他接口的分类记录如何进行,比如CLI?

请参阅Hadoop兼容性页面以获取详细信息。

FAQ

为什么不使用Java的作用域(private、包私有和public)?

Java的作用域不是很完整。人们经常被迫使一个类变为public,以便其他内部组件可以使用它。它还没有像C++那样的友元或子包私有。

但是如果它是Java public,我很容易访问Private接口。这里的保护和控制在哪里?

此分类方案的目的不是提供绝对的访问控制。其目的是向用户和开发人员传达信息。可以在libc中访问私有实现功能;然而,如果它们更改了内部实现细节,应用程序将会中断,并且对于提供libc的人来说,他们将会得到很少的同情。在使用非公共接口时,风险是可以理解的。

为什么要声明Private接口的稳定性?Private接口总是不稳定的吗?

Private接口并非总是不稳定的。在它们是稳定的情况下,它们捕获了系统的内部属性,并可以将这些属性传达给其内部用户和接口的开发人员。

例如,在HDFS中,NN-DN协议是Private但是Stable,可以帮助实现滚动升级。稳定性注解传达了该接口不应以不兼容的方式更改,即使它是私有的。

例如,在HDFS中,FSImage的Stabile指定提供了更灵活的回滚。

使用Private接口标记为Stable有什么害处?与Public Stable接口有何不同?

虽然将标记为Stable的Private接口仅定位为在主要发布版本时更改,但如果提供该接口的提供者也愿意更改该接口的内部使用者,则它可能会在其他时间中断。此外,公共稳定接口即使在主要发布版本中也不太可能中断(即使允许破坏兼容性),因为更改的影响较大。如果使用Private接口(无论其稳定性如何),都存在不兼容性的风险。

为什么要使用Limited-Private?这不是在给予某些项目特殊待遇吗?这不公平。

大多数接口应该是Public或Private。接口应该是Private,除非明确用于一般用途。

Limited-Private用于不打算供一般用途的接口。它们向需要特殊挂钩的相关项目公开。这种分类对接口的提供者和消费者都有成本。如果将来需要更改接口,两者将不得不共同努力;例如,提供者和消费者将不得不共同努力协调各自项目的发布。这个合同不应轻率对待 - 如果可能的话,请使用Private;如果接口确实是为所有应用程序的一般使用而设计的,则请使用Public。始终记住,将接口公开为Public伴随着巨大的责任负担。有时Limited-Private就是合适的。

Limited-Private接口的一个很好的例子是BlockLocations。这个接口是一个相当低

级的接口,对MapReduce和HBase进行了公开。接口可能会在将来发生变化,届时需要与MapReduce开发团队协调发布工作。尽管今天MapReduce和HDFS总是同步发布,但这个政策将来可能会改变。

如果有一个列出了许多项目的Limited-Private接口,那么该接口可能是使其变为Public的一个很好的候选者。

让我们将所有的Private接口都视为Hadoop的Limited-Private。如果Hadoop家族的项目可以访问私有类,那有什么危害?

代码中曾经存在许多情况,其中一个项目依赖于另一个项目的内部实现细节。付出了大量的努力来清理这些问题。对于Hadoop中的所有接口开放所有接口作为Hadoop的Limited-Private将打开重新引入此类耦合问题的大门。

不是所有Public接口都是稳定的吗?

在其早期,可以将Public接口标记为Evolving。在这里,人们承诺努力进行兼容的更改,但可能需要在次要版本中进行更改。

Public接口是不稳定的一个示例,其中人们提供了基于标准的接口的实现,该接口仍在开发中。例如,许多公司为新的NFS协议提供了实现,即使该协议尚未由IETF完全完成。实施者无法以导致最小破坏的方式发展接口,因为稳定性由标准机构控制。因此,将接口标记为不稳定是合适的。

参考资料

https://hadoop.apache.org/docs/stable/hadoop-project-dist/hadoop-common/InterfaceClassification.html