跳转到: 导航, 搜索

结构化工作流锁

起草人: Harlowja

修订日期:2014年3月7日,Harlowja

原理

锁(和信号量)是大多数典型应用程序的关键组成部分。对于以允许应用工作流的实体确保它是唯一处理该工作流及其相关资源(例如,同时修改共享资源的多个服务器可能导致数据不一致)的方式构建工作流而言,这一点尤其如此。确保正确的锁定和锁定顺序通常是创建可靠且容错的分布式工作流的非常困难的部分。即便如此,它们也是确保一致的工作流操作的绝对必要条件。这在 OpenStack 等大型分布式系统中尤其相关且重要,这些系统同时处理许多并发工作流,并且由许多不同的服务(nova、cinder、quantum...)处理。

需求

由于不同的工作流将需要不同类型的 ['mutex', 'semaphore'],因此提供解决方案需要内置的灵活性,允许使用该解决方案的开发人员提供一组期望的要求,并获得一个与这些要求(或与其密切匹配)匹配的 ['mutex', 'semaphore']。

Oslo (进行中)

  • 使用 eventlet 的进程内(线程)锁
  • 使用本地文件系统进行进程间锁

Ironic (进行中)

  • 在主机之间分布式时具有排他性(只有一台主机可以获得它)
  • 线程之间共享和排他性(只有一个获得排他性,其他线程可以获取共享锁)
  • 从锁到所有持有者的引用(允许手动销毁锁)

解决方案 (进行中)

为了适应不同 ['mutex', 'semaphore'] 类型的多样化需求,此 wiki 建议创建一个 API,该 API 将接收一组 ['mutex', 'semaphore'] 要求,并提供对象以尝试满足这些要求(或如果要求无法满足则引发异常)。提供的 API 将由各种且可配置的实现支持。每个后端实现都能够查询其可以满足的要求,并且提供的 API 将从最兼容的后端提供程序处检索 ['mutex', 'semaphore'] 对象。这允许此 API 的部署者配置他们信任的后端(例如 memcache、redis、zookeeper...),同时允许使用该 API 的开发人员只关心某些后端匹配他们期望的要求(如果该要求不可满足,则应用程序不应工作,或者应回退到使用不太严格的要求)。

API

# Lock types that can be requested.
DISTRIBUTED = 1
INTER_PROCESS = 2
INTRA_PROCESS = 4

# Lock properties that can be requested.
MULTI_READER_SINGLE_WRITER = 1
HIGHLY_AVAILABLE = 2
REFERENCEABLE = 4
AUTOMATIC_RELEASE = 8

# These two can not be both requested at the same time.
ALWAYS_CONSISTENT = 32
USUALLY_CONSISTENT = 64

class InvalidLockSpecification(Exception):
    pass

def provide(type, requirements, resource_identifer):
    """Provides a lock object on the given resource identifier that attempts to
    meet the given requirement or combination of requirements. The requirement
    should be an a 'or' of different desired requirements that you want your
    lock to have."""
    if ((type & DISTRIBUTED) and
        (type & INTER_PROCESS or type & INTRA_PROCESS)):
        raise InvalidLockSpecification("A lock can not be distributed and "
                                       "inter-process or intra-process at the same"
                                       "time.")

提供者

文件系统

优点

  • 简单
  • 与本地系统进程一致。

缺点

  • 并非所有文件系统都可行(例如,NFS,据我所知)。
  • 不具有分区容错性(当托管文件系统的机器崩溃时,锁会丢失)。
  • 不可高度可用。
  • 非分布式。

相关的 python 库

内置语言:

Zookeeper

优点

  • 分布式。多主。
  • 容忍后端故障(可用性)。
  • 在锁持有者故障时自动释放锁(生存性)。
  • 复制。
  • 优先考虑一致性而非分区容错性(也可能是一个缺点?)。
  • 可以轻松地增加或减少额外的容量。
  • 强大的持久性保证。
  • 成熟且经过充分测试(被 hbase、许多公司...使用)。
  • 文档完善且经过同行评审。

缺点

  • 有些复杂,难以部署和配置(它是 java)。

相关的 python 库

内置语言:Java

Raft

优点

  • 分布式。
  • 容忍后端故障(可用性)。
  • 在锁持有者故障时自动释放锁(生存性)。
  • 复制。
  • 优先考虑一致性而非分区容错性(也可能是一个缺点?)。
  • 可以轻松地增加或减少额外的容量。
  • 强大的持久性保证。
  • 文档完善且经过同行评审。

缺点

  • 单主
  • 且仍在完善中(一些公司使用,仍在积极开发和部署)。
  • 许多不同的且许多部分完成的实现。

内置语言:许多

Concoord

优点

  • 分布式。
  • 容忍后端故障(可用性)。
  • 复制。
  • 强大的持久性保证。

缺点

  • 未知成熟度(??)。
  • 较小的审查者和所有权数量(似乎是来自康奈尔的两名人员)。
  • 较少的同行评审(?)。

内置语言:python

Doozer

优点

  • 分布式。
  • 容忍后端故障(可用性)。
  • 优先考虑一致性而非分区容错性。

缺点

  • 未知成熟度(??)。
  • 缺乏内置持久性。
  • 未知的部署/升级/额外容量策略。
  • 似乎没有经过同行评审。

相关的 python 库

内置语言:Go

Memcached

优点

  • 通过密钥哈希到不同服务器进行分布式(可用性)。
  • 易于部署。

缺点

  • 在锁使用者故障时不会自动释放(但锁超时是可能的)。
  • 不处理网络分区(密钥将在故障时重新哈希到不同的服务器)。
  • 优先考虑分区容错性而非一致性。
  • 由于服务器翻转问题,可能存在不一致性。
    • 例如:服务器 A 启动,获取锁,崩溃,服务器 B 接管 A 的密钥范围,服务器 B 崩溃,现在服务器 A 具有原始密钥范围,但值不一致。
  • 无法轻松地增加或减少额外的容量(一致性哈希有所帮助)。
  • 不持久。

相关的 python 库

内置语言:C

Redis

优点

缺点

  • 即使设置了复制,锁也可能不一致。
  • 在锁持有者故障时不会自动释放(但锁超时是可能的)。
  • 不处理网络分区(密钥将在故障时重新哈希到不同的服务器)。
  • 内置复制是非阻塞的,不能依赖于其一致性。
  • 优先考虑分区容错性而非一致性(也可能是一个优点?)。
  • 无法轻松地增加或减少额外的容量(一致性哈希有所帮助)。
  • 由于服务器翻转问题,可能存在不一致性。
    • 例如:服务器 A 启动,获取锁,崩溃,服务器 B 接管 A 的密钥范围,服务器 B 崩溃,现在服务器 A 具有原始密钥范围,但值不一致。

相关的 python 库

内置语言:C

数据库

如果绝对需要,可以提供有限的语义和有限的功能。

请参阅:http://www.percona.com/doc/percona-xtradb-cluster/wsrep-system-index.html#wsrep_causal_reads,了解一些使其成为可能的潜在可能性。

可能需要 galera。

相关链接

锁顺序