Translator|布加迪评论|孙淑娟如果你熟悉Kafka、RocketMQ等消息系统,你可能知道服务在其架构中往往与存储密切相关。与它们不同,ApachePulsar采用两层架构设计,将存储与计算分开,这是在其无状态代理之上有效完成的。Pulsar依赖ApacheBookKeeper服务器(又名bookies)进行持久存储。本文重点介绍BookKeeper的基础知识,展示它如何实现其处理的数据的高可用性。图1ApacheBookKeeper简介BookKeeper最初由Yahoo开发,代表了一种可靠的高性能存储系统。它提供分布式、可扩展的存储服务,具有低延迟、强容错等优点。这些充分解释了为什么它可以作为Pulsar的存储层。BookKeeper将数据存储在分类账中,该分类账是仅追加且不可变的。得益于特殊的复制协议,BookKeeper可以在多个节点上同时安全地存储日志条目,使其具有高可用性。顾名思义,BookKeeper和Ledger在云原生环境中很有用。想象一个簿记员使用分类账记录所有相关账户信息以跟踪企业的财务状况。ApacheBookKeeper中的关键概念为了更好地理解BookKeeper是如何存储数据的,让我们看一下几个基本概念。BookieBookies是BookKeeper中的存储服务器或节点,彼此等同。BookKeeper强大的动态扩展能力(尤其是在容器化环境中)得益于其无领导设计。Ensemble用于存储分类帐条目的可用bookie的集合,即写入条目的节点。当一个bookie过期时,处理写入它的客户端将被一个新的bookie替换,这被称为“集成更改”。在Pulsar的计算存储分离架构中,客户端应用程序不需要关心存储层实际发生了什么。LedgerLedger是BookKeeper中的基本存储单元,在Pulsar中也称为Segment。BookKeeper客户端负责创建和删除分类账,并从分类账中读取条目。当满足某些条件时(例如条目数或年龄达到预设阈值),分类帐将关闭并且不能再向其中写入更多数据,只允许读取。任何客户都可以创建分类帐。理想情况下,创建分类账的所有者客户端应该是关闭它的那个。一旦关闭,账本是不可改变的。账本是最小的删除单位,这意味着您只能删除整个账本,不能删除账本中的单个条目。BookKeeper除了用来存储普通消息的账本外,还有一个特殊的账本,游标账本。游标为Pulsar中的消息消费和确认提供了一种跟踪机制。每个订阅都有一个与之关联的游标,它存储消息消费和确认的位置信息。消费者可能会根据订阅类型共享相同的游标。我们不在这里详细介绍这个主题。我们只需要知道Pulsar在BookKeeper中为每个订阅维护一个账本即可。消费者处理消息后(向代理发送确认),代理收到确认,然后代理相应地更新游标分类帐。更具体地说,Pulsar定期汇总来自绑定到同一订阅的所有消费者的所有确认作为条目,并将它们写入bookie。该过程与编写普通消息基本相同。FragmentsFragments在bookie的分类帐中存储连续的条目序列。分类帐可能包含一个或多个片段。作为BookKeeper中最小的分配单元,单个账本的碎片可以分散在不同的Bookie中。这意味着严格来说,存储在单个bookie中的数据是账本的一部分。对于单个fragment,如果写入bookie失败,会选择一个新的bookie进行写入(也就是上面说的“ensemblechange”)。结果,将在bookie上创建新的片段。请注意,这两个片段属于同一个分类帐,但属于不同的集合体。条目条目包含写入分类帐的实际数据。每个分类帐可能包含不同数量的条目。每个条目都有一个条目ID作为其在分类帐中的唯一标识符。消息消息是存储在条目中的特定信息。消息可以分为两种类型:单条消息和批量消息。群发消息本质上是一系列单独的消息。当在客户端上启用消息批处理时,消息在从生产者发送到代理之前被分组为一个整体。代理然后调用BookKeeper客户端向bookie写入批量消息。当消费者从代理读取消息时,代理会向他们分派消息批次。请注意,批量消息在客户端合并和拆分。您可以使用batchingMaxPublishDelay(批处理待处理消息的时间段)和batchingMaxMessages(一个批处理的最大消息数)等参数为生产者自定义批量消息配置。注意:每个条目可能包含一条或多条消息。如果禁用消息批处理,则每个条目仅存储一条消息。图2根据用例,您可以选择启用或禁用消息批处理。与大多数分布式消息系统不同,Pulsar支持消息队列和流式传输。在消息队列场景中,通常不需要高吞吐量,所以客户端很少开启消息批处理。相比之下,在流式场景中,消息的生成速度要快得多,这需要批处理,以便生产者可以将消息作为更大的包发送。数据高可用为了保证数据的高可用,BookKeeper采用仲裁机制将数据并行写入bookie。具体来说,我们可以为要创建的新分类账定义以下三个关键整数:EnsembleSize(E):可用于写入分类账中存储的消息的bookie数量。WriteQuorum(WQ):要写入的消息的副本数,或者同时持有该条目(或其所属的片段)的bookie数。WQ可以等于或小于E,但不能小于1或AQ。AckQuorum(AQ):在写入成功之前代理需要接收的确认数量。如果达到此值,代理将向客户端发回确认。否则,写入失败。这三个参数可以分别在代理、命名空间和主题级别进行配置。例如在broker级别,编辑Pulsar包的conf目录中的broker.conf文件并设置所需的值:=2#guaranteedcopies(ackstowaitbeforeawriteiscomplete)managedLedgerDefaultAckQuorum=2注意:我们可以根据一致性要求配置以上参数。例如,WQ=AQ表示最高级别的一致性。在这种情况下,消息无法成功持久化,直到它收到所有副本的确认。当AQ比较小时(比如AQ=1),延迟会更低,但数据丢失的风险更大。一般来说,最好设置AQ≥(WQ+1)/2。例如下图中,我们设置E=5,WQ=3,AQ=2。这意味着:有5个bookie可用于在账本中存储数据。一个条目的3个副本存储在3个不同的bookie上。当收到2个bookies的确认时,表示条目写入成功。图3数据使用循环分布写入bookie。这样设计是因为它可以充分利用池中所有bookie的处理能力。如下图,Entry1写入Bookie1、Bookie2、Bookie3,Entry2写入Bookie2、Bookie3、Bookie4,以此类推。图4中的循环方法提供了一种简单的方法来快速查找通过条目ID存储特定条目副本的bookie。例如,我们知道条目2在Bookie2、Bookie3和Bookie4上被复制。2mod5等于2,这意味着对于特定的条目X,如果Xmod5等于2,则条目X是存储在Bookie2、Bookie3和Bookie4上,比如entry7(X=7)。使用ApacheBookKeeper在安装Pulsar集群时,BookKeeper会被一起部署。如果你想运行BookKeeper,你不需要单独下载它的代码。相反,下载Pulsar并在bin目录中运行./pulsar-daemonstartbookie命令。如果使用Pulsar社区提供的Helmchart安装在Kubernetes集群上,则bookiePod部署在StatefulSet中。结语本文介绍了BookKeeper的基础知识,分析了如何向bookie写入数据实现高可用。我们可以简单的把BookKeeper看成一个数据库,因为它不包含任何业务逻辑。这个开源工具具有出色的可扩展性、强容错性和低延迟,具备成为合格的云原生存储系统所需的特性,为Pulsar独特的架构提供了坚实的支持。原标题:ApacheBookKeeper:WhatMakesAQualifiedStorageSystemforApachePulsar,作者:SherlockXu
