什么是BookKeeper
BookKeeper是一个提供日志条目流存储持久化的服务框架。特别适合日志流存储,一个比较经典的应用是作为消息队列Pulsar的持久框架。
那么BookKeeper是怎样产生的呢?
这个灵感来源于Hadoop生态系统。我们知道,Haddop生态系统的文件存储是HDFS,HDFS包含一种节点叫做NameNode,用于记录所有的操作,在宕机的时候可以通过这些记录进行恢复。
基于NameNode,BookKeeper拓展了其功能,设计成了一个基于递增存储的存储系统,主要用于:
- 高效写
- 基于复制的高容错(消息在ensembles之间复制,这个概念之后会讲)
- 高吞吐量写
快速部署
我们这里只为了部署一个调试环境,并不是生产环境:
首先,拉下来BookKeeper的代码:
git clone https://github.com/apache/bookkeeper.git
之后,我们在conf目录下可以看到:
conf
└─bk_cli_env.sh
└─bk_server.conf
└─bkenv.sh
└─jaas_example.conf
└─log4j.properties
└─log4j.cli.properties
└─log4j.shell.properties
└─nettyenv.sh
└─standalone.conf
└─zookeeper.conf
└─zookeeper.conf.dynamic
Bookeeper提供了本地启动测试的类org.apache.bookkeeper.util.LocalBookKeeper,但是这个不太好调试,我们想搞清楚实际BookKeeper的工作模式还有部署,最好做一个相对完整的本地环境出来
编译代码,之后先在本地启用一个ZooKeeper,这个直接下载最新版的,直接默认配置启动即可(默认端口是2181)
之后,我们编写三个不同Bookie(就是一个BookKeeper Server)的配置文件,用于之后启动:
Bookie1:
#############################################################################
## Server parameters
#############################################################################
bookiePort=3181
extraServerComponents=
#############################################################################
## server settings
#############################################################################
httpServerEnabled=false
httpServerPort=8080
httpServerClass=org.apache.bookkeeper.http.vertx.VertxHttpServer
############################################## Bookie Storage ##############################################
#############################################################################
## Journal settings
#############################################################################
journalDirectories=d:/tmp1/bk-txn
#############################################################################
## Ledger storage settings
#############################################################################
ledgerDirectories=d:/tmp1/bk-data
indexDirectories=d:/tmp1/bk-data
############################################## Metadata Services ##############################################
#############################################################################
## Metadata Service settings
#############################################################################
metadataServiceUri=zk+hierarchical://localhost:2181/ledgers
#############################################################################
## ZooKeeper Metadata Service settings
#############################################################################
zkServers=localhost:2181
zkTimeout=10000
zkEnableSecurity=false
##################################################################
##################################################################
# Settings below are used by stream/table service
##################################################################
##################################################################
### Grpc Server ###
storageserver.grpc.port=4181
### Dlog Settings for table service ###
#### Replication Settings
dlog.bkcEnsembleSize=3
dlog.bkcWriteQuorumSize=2
dlog.bkcAckQuorumSize=2
### Storage ###
# local storage directories for storing table ranges data (e.g. rocksdb sst files)
storage.range.store.dirs=d:/tmp1/bookkeeper/ranges
# whether the storage server capable of serving readonly tables. default is false.
storage.serve.readonly.tables=false
# the cluster controller schedule interval, in milliseconds. default is 30 seconds.
storage.cluster.controller.schedule.interval.ms=30000
Bookie2:
#############################################################################
## Server parameters
#############################################################################
bookiePort=3182
extraServerComponents=
#############################################################################
## server settings
#############################################################################
httpServerEnabled=false
httpServerPort=8081
httpServerClass=org.apache.bookkeeper.http.vertx.VertxHttpServer
############################################## Bookie Storage ##############################################
#############################################################################
## Journal settings
#############################################################################
journalDirectories=d:/tmp2/bk-txn
#############################################################################
## Ledger storage settings
#############################################################################
ledgerDirectories=d:/tmp2/bk-data
indexDirectories=d:/tmp2/bk-data
############################################## Metadata Services ##############################################
#############################################################################
## Metadata Service settings
#############################################################################
metadataServiceUri=zk+hierarchical://localhost:2181/ledgers
#############################################################################
## ZooKeeper Metadata Service settings
#############################################################################
zkServers=localhost:2181
zkTimeout=10000
zkEnableSecurity=false
##################################################################
##################################################################
# Settings below are used by stream/table service
##################################################################
##################################################################
### Grpc Server ###
storageserver.grpc.port=4182
### Dlog Settings for table service ###
#### Replication Settings
dlog.bkcEnsembleSize=3
dlog.bkcWriteQuorumSize=2
dlog.bkcAckQuorumSize=2
### Storage ###
# local storage directories for storing table ranges data (e.g. rocksdb sst files)
storage.range.store.dirs=d:/tmp2/bookkeeper/ranges
# whether the storage server capable of serving readonly tables. default is false.
storage.serve.readonly.tables=false
# the cluster controller schedule interval, in milliseconds. default is 30 seconds.
storage.cluster.controller.schedule.interval.ms=30000
Bookie3:
#############################################################################
## Server parameters
#############################################################################
bookiePort=3183
extraServerComponents=
#############################################################################
## server settings
#############################################################################
httpServerEnabled=false
httpServerPort=8082
httpServerClass=org.apache.bookkeeper.http.vertx.VertxHttpServer
############################################## Bookie Storage ##############################################
#############################################################################
## Journal settings
#############################################################################
journalDirectories=d:/tmp3/bk-txn
#############################################################################
## Ledger storage settings
#############################################################################
ledgerDirectories=d:/tmp3/bk-data
indexDirectories=d:/tmp3/bk-data
############################################## Metadata Services ##############################################
#############################################################################
## Metadata Service settings
#############################################################################
metadataServiceUri=zk+hierarchical://localhost:2181/ledgers
#############################################################################
## ZooKeeper Metadata Service settings
#############################################################################
zkServers=localhost:2181
zkTimeout=10000
zkEnableSecurity=false
##################################################################
##################################################################
# Settings below are used by stream/table service
##################################################################
##################################################################
### Grpc Server ###
storageserver.grpc.port=4182
### Dlog Settings for table service ###
#### Replication Settings
dlog.bkcEnsembleSize=3
dlog.bkcWriteQuorumSize=2
dlog.bkcAckQuorumSize=2
### Storage ###
# local storage directories for storing table ranges data (e.g. rocksdb sst files)
storage.range.store.dirs=d:/tmp3/bookkeeper/ranges
# whether the storage server capable of serving readonly tables. default is false.
storage.serve.readonly.tables=false
# the cluster controller schedule interval, in milliseconds. default is 30 seconds.
storage.cluster.controller.schedule.interval.ms=30000
可以看到,这三个实例用的是同一个ZK,这样他们就形成了集群。
但是ZK中的原始元数据,需要手工初始化,这就用到了一个类:org.apache.bookkeeper.bookie.BookieShell
我们用任意一个配置文件作为参数,即可完成初始化
我用的IDE是IDEA,这里配置BookieShell运行初始化:
- 主类选择
org.apache.bookkeeper.bookie.BookieShell
- VM options填写:
-DentryFormatterClass=${ENTRY_FORMATTER_CLASS:-org.apache.bookkeeper.util.StringEntryFormatter}
- Program aruguments填写:
--conf ./conf/bk_server_1.conf metaformat
之后启动,可以看到日志:
2018-10-16 15:43:14,766 - INFO - [main:MetadataDrivers@107] - BookKeeper metadata driver manager initialized
然后,开始配置三个Bookie的启动:
- 主类选择
org.apache.bookkeeper.server.Main
- Program aruguments填写:
--conf ./conf/bk_server_1.conf
, 另外两个分别填写--conf ./conf/bk_server_2.conf
和--conf ./conf/bk_server_3.conf
编写配置好后,启动三个Bookie(为何启动三个,默认配置情况下,一个ledger至少要写到两个Bokkie中,Bookies需要选举出最合适的,这个选举算法至少需要三个Bookie):
2018-10-16 16:00:01,923 - INFO - [main:Main@110] - Using configuration file ./conf/bk_server_1.conf
2018-10-16 16:00:01,935 - INFO - [main:Main@267] - Hello, I'm your bookie, listening on port 3181. Metadata service uri is zk+hierarchical://localhost:2181/ledgers. Journals are in [d:/tmp1/bk-txn]. Ledgers are stored in d:/tmp1/bk-data.
2018-10-16 16:00:02,045 - INFO - [main:Main@296] - Load lifecycle component : org.apache.bookkeeper.server.service.StatsProviderService
2018-10-16 16:00:02,304 - INFO - [main:BookieServer@94] - {
"storage.cluster.controller.schedule.interval.ms" : "30000",
"zkEnableSecurity" : "false",
"dlog.bkcAckQuorumSize" : "2",
"indexDirectories" : "d:/tmp1/bk-data",
"zkServers" : "localhost:2181",
"storage.range.store.dirs" : "d:/tmp1/bookkeeper/ranges",
"httpServerPort" : "8080",
"dlog.bkcWriteQuorumSize" : "2",
"bookiePort" : "3181",
"storage.serve.readonly.tables" : "false",
"ledgerDirectories" : "d:/tmp1/bk-data",
"zkTimeout" : "10000",
"httpServerClass" : "org.apache.bookkeeper.http.vertx.VertxHttpServer",
"httpServerEnabled" : "false",
"metadataServiceUri" : "zk+hierarchical://localhost:2181/ledgers",
"dlog.bkcEnsembleSize" : "3",
"journalDirectories" : "d:/tmp1/bk-txn",
"storageserver.grpc.port" : "4181",
"extraServerComponents" : ""
}
2018-10-16 16:00:03,032 - INFO - [main:MetadataDrivers@107] - BookKeeper metadata driver manager initialized
2018-10-16 16:00:03,033 - INFO - [main:MetadataDrivers@107] - BookKeeper metadata driver manager initialized
2018-10-16 16:00:03,033 - INFO - [main:MetadataDrivers@107] - BookKeeper metadata driver manager initialized
2018-10-16 16:00:03,167 - INFO - [main:Bookie@399] - Stamping new cookies on all dirs [d:\tmp1\bk-txn\current] [d:\tmp1\bk-data\current, d:\tmp1\bk-data\current]
2018-10-16 16:00:03,368 - WARN - [main:Bookie@302] - Dirs: [d:\tmp1\bk-data\current, d:\tmp1\bk-data\current] are in same DiskPartition/FileSystem: (d:)
2018-10-16 16:00:03,373 - INFO - [main:Bookie@644] - instantiate ledger manager org.apache.bookkeeper.meta.HierarchicalLedgerManagerFactory
2018-10-16 16:00:03,415 - ERROR - [main:Journal$LastLogMark@244] - Problems reading from d:\tmp1\bk-data\current\lastMark (this is okay if it is the first time starting this bookie
2018-10-16 16:00:03,420 - INFO - [main:Bookie@700] - Using ledger storage: org.apache.bookkeeper.bookie.SortedLedgerStorage
2018-10-16 16:00:03,500 - INFO - [main:IndexPersistenceMgr@107] - openFileLimit = 20000
2018-10-16 16:00:03,539 - INFO - [main:IndexInMemPageMgr@377] - maxDirectMemory = 259522560, pageSize = 8192, pageLimit = 10560
2018-10-16 16:00:03,594 - INFO - [main:ScanAndCompareGarbageCollector@107] - Over Replicated Ledger Deletion : enabled=true, interval=86400000
2018-10-16 16:00:03,603 - INFO - [main:GarbageCollectorThread@253] - Minor Compaction : enabled=true, threshold=0.20000000298023224, interval=3600000
2018-10-16 16:00:03,603 - INFO - [main:GarbageCollectorThread@255] - Major Compaction : enabled=true, threshold=0.800000011920929, interval=86400000
2018-10-16 16:00:03,734 - INFO - [main:Main@303] - Load lifecycle component : org.apache.bookkeeper.server.service.BookieService
2018-10-16 16:00:03,748 - INFO - [main:ComponentStarter@79] - Starting component bookie-server.
2018-10-16 16:00:03,753 - INFO - [main:Bookie@853] - Finished replaying journal in 3 ms.
2018-10-16 16:00:03,756 - INFO - [SyncThread-7-1:SyncThread@136] - Flush ledger storage at checkpoint CheckpointList{checkpoints=[LogMark: logFileId - 0 , logFileOffset - 0]}.
2018-10-16 16:00:03,786 - INFO - [main:Bookie@892] - Finished reading journal, starting bookie
2018-10-16 16:00:03,787 - INFO - [BookieJournal-3181:Journal@932] - Starting journal on d:\tmp1\bk-txn\current
2018-10-16 16:00:03,789 - INFO - [ForceWriteThread:Journal$ForceWriteThread@471] - ForceWrite Thread started
2018-10-16 16:00:03,828 - INFO - [BookieJournal-3181:JournalChannel@154] - Opening journal d:\tmp1\bk-txn\current\1667be392ce.txn
2018-10-16 16:00:04,078 - INFO - [main:ComponentStarter@81] - Started component bookie-server.
2018-10-16 16:00:04,309 - INFO - [BookieJournal-3181:NativeIO@48] - Unable to link C library. Native methods will be disabled.
之后我们简单编写个测试程序,来看下日志写入读取效果:
public class TestClient {
public static void main(String[] args) throws InterruptedException, BKException, IOException {
BookKeeper bkc = new BookKeeper("localhost:2181");
// A password for the new ledger
byte[] ledgerPassword = "test".getBytes();
// Create a new ledger and fetch its identifier
LedgerHandle lh = bkc.createLedger(BookKeeper.DigestType.MAC, ledgerPassword);
long ledgerId = lh.getId();
// Create a buffer for four-byte entries
ByteBuffer entry = ByteBuffer.allocate(4);
int numberOfEntries = 10;
// Add entries to the ledger, then close it
for (int i = 0; i < numberOfEntries; i++) {
entry.putInt(i);
entry.position(0);
lh.addEntry(entry.array());
}
lh.close();
// Open the ledger for reading
lh = bkc.openLedger(ledgerId, BookKeeper.DigestType.MAC, ledgerPassword);
// Read all available entries
Enumeration<LedgerEntry> entries = lh.readEntries(0, numberOfEntries - 1);
while (entries.hasMoreElements()) {
ByteBuffer result = ByteBuffer.wrap(entries.nextElement().getEntry());
Integer retrEntry = result.getInt();
// Print the integer stored in each entry
System.out.println(String.format("Result: %s", retrEntry));
}
// Close the ledger and the client
lh.close();
bkc.close();
}
}
运行,可以看到输出:
Result: 0
Result: 1
Result: 2
Result: 3
Result: 4
Result: 5
Result: 6
Result: 7
Result: 8
Result: 9
BookKeeper基本概念
在BookKeeper中:
- 每一块日志是一个entry
- 日志流被定义为ledgers
- 每个独立的保存ledges的服务器叫做bookies
Entries
Entries包含真正的数据,其中也包含一些元数据:
每个entry有如下的fields:
Field | 类型 | 描述 |
---|---|---|
Ledger number | long | 属于的Ledger的ID标识 |
Entry number | long | 标识自身的全局唯一ID |
Last confirmed (LC) | long | 上一个entry的全局唯一ID |
Data | byte[] | 日志数据 |
Authentication code | byte[] | 校验码 |
Ledgers
Ledgers是BookKeeper中的基本存储单元
Ledgers是一组Entries,每个Entry有序的并且至多一次写入到Ledgers中。一旦写入Ledgers,将不能再修改。所以,写入保持有序写入是客户端应用应该考虑的事情。
Bookies 和 Ensemble
Bookie是一个独立的BookKeeper服务器,处理Ledgers片段(因为每个Bookie保存的是每个Ledgers的片段,不是完整的Ledgers)。
一个Ensemble是一个Bookies集合,他们共同保存着一个Ledger的所有entries。通常一个Ensemble是整个Bookies集群的子集。
BookKeeper API简介
BookKeeper的客户端主要负责创建删除ledgers,并且从ledgers中读取entries。
BookKeeper提供两种API,Ledger API还有DistributedLog API;顾名思义,Ledger API提供了直接与Ledger交互的接口,DistributedLog API不直接与ledger交互而是与Bookeeper集群交互。
BookKeeper 元数据存储
BookKeeper需要第三方存储用于保存关于ledgers的信息还有可用的Bookies(相当于分布式协调)。
目前BookKeeper利用ZooKeeper实现元数据存储
转载自原文链接, 如需删除请联系管理员。
原文链接:BookKeeper全解(1)-BookKeeper简介和快速上手,转载请注明来源!