Hadoop接口分类:受众与稳定性分级

动机

此处提供的接口分类法旨在为接口的开发者和用户提供指导。该分类法引导开发者声明接口的目标受众或用户群体,以及其稳定性。

  • 用户使用接口的好处:了解哪些接口可以使用或避免使用,以及它们的稳定性。

  • 对开发者的好处:防止接口的意外变更,从而避免对用户或其他组件或系统造成意外影响。这在拥有众多开发者的大型系统中尤为有用,因为开发者们可能并不都了解项目的共享状态/历史。

接口分类

Hadoop采用以下接口分类,该分类源自OpenSolaris的分类法,并在某种程度上参考了雅虎内部使用的分类法。接口具有两个主要属性:受众群体和稳定性。

目标受众

受众(Audience)表示该接口的潜在使用者。许多接口是内部/私有实现,而其他则是面向应用程序和/或客户端更广泛使用的公共/外部接口。例如在POSIX中,libc属于外部或公共接口,而内核的大部分属于内部或私有接口。此外,某些接口专门面向其他特定子系统。

明确界面的受众有助于评估其变更带来的影响。例如,如果某个界面的受众仅限于少数特定子系统,那么破坏其兼容性可能是可以接受的。反之,若某个协议界面被数百万互联网用户所依赖,破坏其兼容性则很可能不可取。

Hadoop 按照可见性递增/范围扩大的顺序使用以下类型的受众:

Hadoop没有公司私有分类,该分类适用于公司内部其他项目使用的API,因为它不适用于开源项目。此外,某些API被标注为@VisibleForTesting(来自com.google.common.annotations.VisibleForTesting)——这些API严格用于单元测试,应被视为"私有"API。

私有

Private接口仅供项目内部使用(例如HDFS或MapReduce),不应被应用程序或其他项目调用。项目中的大多数接口都属于Private类型(也称为项目私有接口)。除非某个接口是专门设计给外部使用的,否则都应标记为Private。

受限私有

受限私有接口由一组指定的项目或系统使用(通常是紧密相关的项目)。其他项目或系统不应使用该接口。对该接口的更改将与指定项目进行沟通/协商。例如,在Hadoop项目中,某些接口被标记为LimitedPrivate{HDFS, MapReduce},表示它们专属于HDFS和MapReduce项目。

公共

公共接口可供任何应用程序通用。

变更兼容性

API的变更可分为两大类:兼容性和非兼容性。兼容性变更指符合以下标准的变更:

  • 不删除现有功能,
  • 现有功能不会被修改,从而妨碍那些为使用变更前接口而构建的客户端继续使用这些功能,并且
  • 新增的功能不会对之前构建使用该接口的客户端造成任何需要修改的影响。

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

  • 向Java类添加方法,
  • 向RESTful网络服务添加可选参数,或
  • 向XML文档添加标签。
  • 使接口的受众注释更广泛(例如从私有改为公共)或更改兼容性注释更严格(例如从演进改为稳定)

这些示例是不兼容的变更:

  • 从Java类中移除一个方法,
  • 向Java接口添加方法,
  • 向RESTful网络服务添加必需参数,或
  • 重命名JSON文档中的字段。
  • 缩小接口的受众范围注释(例如从公开改为有限私有)或使变更兼容性注释更加严格(例如从演进改为不稳定)

稳定性

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

稳定版

稳定接口作为首选的通信方式对外公开。稳定接口预计不会在主版本发布中进行不兼容的更改,因此可作为安全的开发目标。稳定接口可能会在次版本发布之间进行兼容性演进。

允许的不兼容变更:主版本号 (X.0.0) 允许的兼容变更:维护版本号 (x.y.Z)

演进中

演化接口通常会被公开,以便用户或外部代码能在功能稳定前使用它。然而,接口"最终"应趋于稳定并升级为稳定版这一预期,并不是将该接口标记为演化版的必要条件。

不兼容的变更仅允许在次要版本发布时对演进接口进行。

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

不稳定

不稳定接口是指不提供兼容性保证的接口。不稳定接口并不一定意味着它本身不稳定。通常,暴露不稳定接口是因为用户或外部代码需要访问一个并非设计为公开使用的接口。将该接口标记为不稳定接口是为了明确声明:尽管该接口已公开暴露,但它并非首选的访问路径,且不对其提供任何兼容性保证。

除非有理由对接口提供兼容性保证,无论其是否公开,都应标记为不稳定。在大多数情况下,私有接口也应标记为不稳定。

对不稳定接口的不兼容更改随时可能发生。

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

已弃用

已弃用的接口未来可能会被移除,不应继续使用。即便如此,已弃用的接口在被移除前仍可正常使用。一个已弃用接口何时能被移除取决于它是否同时属于稳定、演进或不稳定状态。

分类是如何记录的?

Hadoop API的分类将如何记录?

  • 每个接口或类都会使用org.apache.hadoop.classification包中的注解来记录其受众群体和稳定性。

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

  • 可以通过Java类和Java接口所在包的受众范围来推断它们的受众范围。因此,为每个Java包声明其受众范围是公开(public)还是私有(private)(包括私有受众的变体)非常有用。

其他接口(如CLI)的分类将如何记录?

常见问题

  • 为什么Java的作用域(private、package private和public)还不够好?

    • Java的作用域机制不够完善。开发者经常被迫将类声明为public,以便其他内部组件可以使用它。此外,Java也没有像C++那样的友元或子包私有访问权限。
  • 但如果它是Java公共接口,我可以轻松访问私有接口。保护和控制在哪里?

    • 此分类方案的目的并非提供绝对的访问控制,而是向用户和开发者传达信息。虽然可以访问libc中的私有实现函数,但如果更改内部实现细节,应用程序将会崩溃,并且很难获得libc提供者的同情。使用非公开接口时,需自行承担风险。
  • 为什么要费心声明私有接口的稳定性?私有接口不总是非稳定的吗?

    • Private interfaces are not always Unstable. In the cases where they are Stable they capture internal properties of the system and can communicate these properties to its internal users and to developers of the interface.
      • 例如,在HDFS中,NN-DN协议虽然是私有的但保持稳定,可用于实现滚动升级。稳定性注解表明即使该接口是私有的,也不应以不兼容的方式更改。
      • 例如,在HDFS中,FSImage的Stabile标识提供了更灵活的回滚功能。
  • 应用程序使用稳定的私有接口有什么危害?它与公共稳定接口有何不同?

    • 虽然标记为稳定的私有接口预计仅在主要版本中变更,但如果该接口的提供者也愿意更改其内部使用者,则它也可能在其他时间发生变更。此外,公共稳定接口即使在主要版本中也不太可能发生变更(尽管允许破坏兼容性),因为变更的影响更大。如果您使用私有接口(无论其稳定性如何),您将面临不兼容的风险。
  • 为什么要费心搞有限私有化?这不是给某些项目特殊待遇吗?这不公平。

    • 大多数接口应为公开(Public)或私有(Private)。除非明确设计为通用用途,否则接口应设为私有。
    • Limited-Private(有限私有)适用于不面向通用用途的接口。这些接口会暴露给需要特殊钩子的相关项目。这种分类对接口的提供方和使用方都会带来成本。如果未来需要破坏该接口,双方必须协同工作;例如,提供方和使用方必须协调各自项目的发布计划。这一约定不应被轻视——如有可能应优先使用Private(私有);如果接口确实面向所有应用程序的通用用途,则使用Public(公开)。始终谨记,将接口设为Public意味着承担巨大的责任负担。有时Limited-Private才是恰当之选。
    • BlockLocations是一个很好的Limited-Private接口示例。该接口是一个相当底层的接口,向MapReduce和HBase公开。该接口未来可能会发生变化,届时发布工作必须与MapReduce开发团队协调。虽然目前MapReduce和HDFS总是同步发布,但这一政策未来可能会改变。
    • 如果您有一个Limited-Private接口,其中列出了许多项目,那么这个接口很可能适合转为Public。
  • 让我们将Hadoop中所有私有接口视为有限私有。如果Hadoop家族中的项目能够访问私有类,会有什么危害?

    • 代码中曾有许多情况是一个项目依赖于另一个项目的内部实现细节。我们投入了大量精力来清理这些问题。如果为整个Hadoop将所有接口都开放为Limited-Private,将会为重新引入这类耦合问题打开方便之门。
  • 并非所有公共接口都是稳定的吗?

    • 在早期阶段,可以将公共接口标记为"Evolving"。这意味着承诺会努力保持兼容性变更,但在次要版本中仍可能需要进行破坏性更改。
    • 公共接口不稳定性的一个例子是,当某人提供一个基于标准组织仍在开发中的接口实现时。例如,许多公司为了抢占市场先机,甚至在IETF尚未完全确定新NFS协议时就提供了实现方案。由于接口稳定性由标准组织控制,实现者无法以最小破坏性的方式演进接口。因此,将该接口标记为"不稳定"是合适的。