Apache BookKeeper简介及集群搭建

826 阅读4分钟

Apache BookKeeper是什么

Apache BookKeeper是一种可扩容、容错、低延迟的存储服务,针对实时工作负载进行了优化,并提供持久性、可复制性和强一致性作为构建可靠实时应用程序的必要条件。

BookKeeper 各种实例使用场景:

Use CaseExample
WAL(write-ahead logging)The HDFS namenode
WAL(write-ahead logging)Twitter Manhattan
WAL(write-ahead logging)HerdDB
Message storageApache Pulsar
Offset/cursor storageApache Pulsar
Object/BLOB storageStoring snapshots to replicated state machines

笔者记录时Release的版本为4.15.0

运行环境为VMvare 上运行的CentOS 7,Java为OpenJDK 11

[root@localhost bookkeeper3]# java -version
openjdk version "11.0.15" 2022-04-19 LTS
OpenJDK Runtime Environment 18.9 (build 11.0.15+9-LTS)
OpenJDK 64-Bit Server VM 18.9 (build 11.0.15+9-LTS, mixed mode, sharing)

下载bookkeeper到CentOS

wget https://dlcdn.apache.org/bookkeeper/bookkeeper-4.15.0/bookkeeper-server-4.15.0-bin.tar.gz

解压并重命名为bookeeper

--strip-components N 表示删除目录结构(n=1表示删除最外【或前1】层结构)

mkdir ~/bookkeeper && tar -zxvf bookkeeper-server-4.15.0-bin.tar.gz -C ~/bookkeeper --strip-components 1 

此时~目录下就有bookkeeper文件夹。

要想运行bookkepper集群,首先要搭建zookeeper,因为bookkepper的元数据就是存储在zookeeper集群中。

为了演示我只运行了一台zookeeper,zookeeper集群请自行查阅资料搭建。

下载zookeeper并解压到~目录下为apache-zookeeper.

cd apache-zookeeper

#创建数据目录和logs目录
mkdir -p data logs
cd conf
cp zoo_sample.cfg zoo.cfg
vim zoo.cfg
#修改数据目录和日志目录 
dataDir=/root/apache-zookeeper/data
dataLogDir=/root/apache-zookeeper/logs
退出保存
sh bin/zkServer.sh start  #后台运行
sh bin/zkServer.sh start-foreground #前台运行

binding to port 0.0.0.0/0.0.0.0:2181 说明zookeeper运行正常。

下面修改三台bookeeper配置。

cp bookkeeper bookkeeper1 bookkeeper2 bookkeeper3
rm -rf bookkeeper
cd bookkeeper1
vim conf/bk_server.conf
#修改以下这些参数
#############################################################################
## Server parameters
#############################################################################
bookiePort=3181
advertisedAddress=192.168.236.188 #为centos7的IP地址
extraServerComponents=
#############################################################################
##  server settings
#############################################################################
httpServerEnabled=false
httpServerPort=8181
httpServerClass=org.apache.bookkeeper.http.vertx.VertxHttpServer
############################################## Bookie Storage ##############################################
#############################################################################
## Journal settings
#############################################################################
journalDirectories=/tmp/bk1-txn
#############################################################################
## Ledger storage settings
#############################################################################
ledgerDirectories=/tmp/bk1-data
indexDirectories=/tmp/bk1-data
############################################## Metadata Services ##############################################
#############################################################################
## Metadata Service settings
#############################################################################
metadataServiceUri=zk+hierarchical://192.168.236.188:2181/ledgers
#############################################################################
## ZooKeeper Metadata Service settings
#############################################################################
zkServers=192.168.236.188: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=/tmp/bookkeeper1/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

由于在同一台机器运行bookkeeper,所以需要将bookkeeper2,bookkeeper3的端口号修改一下

bookeeper2
#修改以下这些参数
#############################################################################
## Server parameters
#############################################################################
bookiePort=3182
advertisedAddress=192.168.236.188 #为centos7的IP地址
extraServerComponents=
#############################################################################
##  server settings
#############################################################################
httpServerEnabled=false
httpServerPort=8182
httpServerClass=org.apache.bookkeeper.http.vertx.VertxHttpServer
############################################## Bookie Storage ##############################################
#############################################################################
## Journal settings
#############################################################################
journalDirectories=/tmp/bk2-txn
#############################################################################
## Ledger storage settings
#############################################################################
ledgerDirectories=/tmp/bk2-data
indexDirectories=/tmp/bk2-data
############################################## Metadata Services ##############################################
#############################################################################
## Metadata Service settings
#############################################################################
metadataServiceUri=zk+hierarchical://192.168.236.188:2181/ledgers
#############################################################################
## ZooKeeper Metadata Service settings
#############################################################################
zkServers=192.168.236.188: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=/tmp/bookkeeper2/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
bookkeeper3
#修改以下这些参数
#############################################################################
## Server parameters
#############################################################################
bookiePort=3183
advertisedAddress=192.168.236.188 #为centos7的IP地址
extraServerComponents=
#############################################################################
##  server settings
#############################################################################
httpServerEnabled=false
httpServerPort=8183
httpServerClass=org.apache.bookkeeper.http.vertx.VertxHttpServer
############################################## Bookie Storage ##############################################
#############################################################################
## Journal settings
#############################################################################
journalDirectories=/tmp/bk3-txn
#############################################################################
## Ledger storage settings
#############################################################################
ledgerDirectories=/tmp/bk3-data
indexDirectories=/tmp/bk3-data
############################################## Metadata Services ##############################################
#############################################################################
## Metadata Service settings
#############################################################################
metadataServiceUri=zk+hierarchical://192.168.236.188:2181/ledgers
#############################################################################
## ZooKeeper Metadata Service settings
#############################################################################
zkServers=192.168.236.188: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=/tmp/bookkeeper3/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

到这里三台bookkeeper配置完成。 我们可以通过集群中任何一台bookie中运行下面命令来为集群设置集群元数据:

cd ~/bookkeeper1
sh bin/bookkeeper shell metaformat 

一旦集群元数据格式化完成,你的BookKeeper集群就准备好了。

开始启动bookkeeper集群

sh ~/bookkeeper1/bin/bookkeeper bookie
sh ~/bookkeeper2/bin/bookkeeper bookie
sh ~/bookkeeper3/bin/bookkeeper bookie
 INFO org.apache.bookkeeper.common.component.ComponentStarter - Started component bookie-server.
#出现这句话说明bookie server 启动成功。

此时我们使用IDEA构建一个java客户端来进行测试消息。

引入依赖项

    <dependency>
        <groupId>org.apache.bookkeeper</groupId>
        <artifactId>bookkeeper-server</artifactId>
        <version>4.15.0</version>
        <scope>test</scope>
    </dependency>

    <dependency>
        <groupId>org.apache.bookkeeper</groupId>
        <artifactId>bookkeeper-common</artifactId>
        <version>4.15.0</version>
        <scope>test</scope>
    </dependency>

客户端API测试代码如下:

public class Test {
    public static final String GISONWIN = "gisonwin";
    public static final String ZK_SERVER = "zk+hierarchical://192.168.236.188/ledgers";
    public static final int CONNECT_TIMEOUT_MILLIS = 3000000;

    static void test2() {
        try {
            ClientConfiguration config = new ClientConfiguration();
            config.setMetadataServiceUri(ZK_SERVER);
            config.setTimeoutMonitorIntervalSec(CONNECT_TIMEOUT_MILLIS);
            org.apache.bookkeeper.client.api.BookKeeper bkClient = org.apache.bookkeeper.client.api.BookKeeper.newBuilder(config).build();
            System.out.println("BookKeeper client init success.");

            WriteHandle writeHandle = bkClient.newCreateLedgerOp().withDigestType(org.apache.bookkeeper.client.api.DigestType.MAC).withPassword(GISONWIN.getBytes()).execute().get();


            for (int i = 0; i < 10; i++) {
                byte[] data = new String(GISONWIN + ":message-" + i).getBytes();
                writeHandle.append(data);
                System.out.println("write to ==> " + new String(data));
            }
            writeHandle.close();
            long ledgerId = writeHandle.getLedgerMetadata().getLedgerId();
            ReadHandle readHandle = bkClient.newOpenLedgerOp().withLedgerId(ledgerId).withDigestType(org.apache.bookkeeper.client.api.DigestType.MAC).withPassword(GISONWIN.getBytes()).execute().get();

            System.out.println("ledgerId = " + ledgerId);

            Iterator<org.apache.bookkeeper.client.api.LedgerEntry> iterable = readHandle.read(0, writeHandle.getLastAddConfirmed()).iterator();
            while (iterable.hasNext()) {
                org.apache.bookkeeper.client.api.LedgerEntry entry = iterable.next();
                System.out.println("read => " + new String(entry.getEntryBytes()));
            }
            readHandle.close();
        } catch (Exception e) {
            e.printStackTrace();
        }


    }
    public static void main(String[] args) {
        test2();
    }
    }

测试代码在windows10下运行。

read => gisonwin:message-0
read => gisonwin:message-1
read => gisonwin:message-2
read => gisonwin:message-3
read => gisonwin:message-4
read => gisonwin:message-5
read => gisonwin:message-6
read => gisonwin:message-7
read => gisonwin:message-8
read => gisonwin:message-9
#说明消息存储成功并读取成功

服务器上截图

bookkeeper1

image.png

bookeeper2

image.png

bookeeper3

image.png

写在最后:

遇到的问题

1.客户端代码 API连接集群时一直在报错误: ConnectionLossException: KeeperErrorCode = ConnectionLoss

解决方案: windows下将192.168.236.188添加到hosts文件中。

192.168.236.188 localhost.localdomain
#后面是192.168.236.188对应的hostname

2.bookie重启后会报一个instanceID不匹配,这个情况是将zookeeper重启后会遇到

我的解决方案简单粗暴:

zookeeper重启后,使用任意一个bookeeper上面进行元数据重新格式化
sh bin/bookkeeper shell metaformat
然后将/tmp/bk1-* bk2-* bk3-* 数据全部删掉。