Setting Up Zookeeper¶
We shall be running Zookeeper using the official Docker images. All data volumes etc will be mounted on the host machines.
The following ports will be exposed:
2181
- This is the main port for ZK clients to connect to the server2888
- The port used by Zookeeper for in-cluster communications between peers3888
- Port used for internal leader election8080
- Admin server port. We are going to turn this off.
Danger
The ZK admin server does not shut down cleanly from time to time. And is not needed for anything related to Drove. If not needed, you should turn it off.
We assume the following to be the IP for the 3 zookeeper nodes:
- 192.168.3.10
- 192.168.3.11
- 192.168.3.12
Relevant directories¶
Location for data and logs are as follows:
/etc/drove/zk
- Configuration files/var/lib/drove/zk/
- Data and data logs/var/log/drove/zk
- Logs
Important files¶
The zookeeper container stores snapshots, transaction logs and application logs on /data
, /datalog
and /logs
directories respectively. We shall be volume mounting the following:
/var/lib/drove/zk/data
to/data
on the container/var/lib/drove/zk/datalog
to/datalog
on the container/var/logs/drove/zk
to/logs
on the container
Docker will create these directories when container comes up for the first time.
Tip
The zk server id (as set above using the ZOO_MY_ID
) can also be set by putting the server number in a file named myid
in the /data
directory.
Prerequisite Setup
If not done already, lease complete the prerequisite setup on all machines earmarked for the cluster.
Setup configuration files¶
Let's create the config directory:
mkdir -p /etc/drove/zk
We shall be creating 3 different configuration files to configure zookeeper:
zk.env
- Environment variables to be used by zookeeper containerjava.env
- Setup JVM related optionslogbaxk.xml
- Logging configuration
Setup environment variables¶
Let us prepare the configuration. Put the following in a file: /etc/drove/zk/zk.env
:
#(1)!
ZOO_TICK_TIME=2000
ZOO_INIT_LIMIT=10
ZOO_SYNC_LIMIT=5
ZOO_STANDALONE_ENABLED=false
ZOO_ADMINSERVER_ENABLED=false
#(2)!
ZOO_AUTOPURGE_PURGEINTERVAL=12
ZOO_AUTOPURGE_SNAPRETAINCOUNT=5
#(3)!
ZOO_MY_ID=1
ZOO_SERVERS=server.1=192.168.3.10:2888:3888;2181 server.2=192.168.3.11:2888:3888;2181 server.3=192.168.3.12:2888:3888;2181
- This is cluster level configuration to ensure the cluster topology remains stable through minor flaps
- This will control how much data we retain
- This section needs to change per server. Each server should have a different
ZOO_MY_ID
set. And the same numbers get referred to inZOO_SERVERS
section.
Warning
-
The
ZOO_MY_ID
value needs to be different on every server.So it would be:- 192.168.3.10 - 1
- 192.168.3.11 - 2
- 192.168.3.12 - 3
-
The format for
ZOO_SERVERS
isserver.id=<address1>:<port1>:<port2>[:role];[<client port address>:]<client port>
.
Info
Exhaustive set of options can be found on the Official Docker Page.
Setup JVM parameters¶
Put the following in /etc/drove/zk/java.env
export SERVER_JVMFLAGS='-Djute.maxbuffer=0x9fffff -Xmx4g -Xms4g -Dfile.encoding=utf-8 -XX:+UseG1GC -XX:+UseNUMA -XX:+ExitOnOutOfMemoryError'
Configuring Max Data Size
Drove data per node can get a bit on the larger side from time to time depending on your application configuration. To be on the safe side, we need to increase the maximum data size per node. This is achieved by setting the JVM option -Djute.maxbuffer=0x9fffff
on all cluster nodes in Drove. This is 10MB (approx). The actual payload doesn't reach anywhere close. However we shall be picking up payload compression in a future version to stop this variable from needing to be set.
For the Zookeeper Docker, the environment variable SERVER_JVMFLAGS
needs to be set to -Djute.maxbuffer=0x9fffff
.
Please refer to Zookeeper Advanced Configuration for further properties that can be tuned.
JVM Size
We set 4GB JVM heap size for ZK by adding appropriate options in SERVER_JVMFLAGS
. Please make sure you have sized your machines to have 10-16GB of RAM at the very least. Tune the JVM size and machine size according to your needs.
q
JVMFLAGS
environment variable
Do not set this variable in zk.env
. Couple of reasons:
- This will affect both the zk server as well as the client.
- There is an issue and the flag (nor the
SERVER_JVMFLAGS
) are not used properly by the startup scripts.
Configure logging¶
We want to have physical log files on disk for debugging and audits and want the container to be ephemeral to allow for easy updates etc. To achieve this, put the following in /etc/drove/zk/logback.xml
:
<!--
Copyright 2022 The Apache Software Foundation
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Define some default values that can be overridden by system properties
-->
<configuration>
<!-- Uncomment this if you would like to expose Logback JMX beans -->
<!--jmxConfigurator /-->
<property name="zookeeper.console.threshold" value="INFO" />
<property name="zookeeper.log.dir" value="/logs" />
<property name="zookeeper.log.file" value="zookeeper.log" />
<property name="zookeeper.log.threshold" value="INFO" />
<property name="zookeeper.log.maxfilesize" value="256MB" />
<property name="zookeeper.log.maxbackupindex" value="20" />
<!--
console
Add "console" to root logger if you want to use this
-->
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{ISO8601} [myid:%X{myid}] - %-5p [%t:%C{1}@%L] - %m%n</pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>${zookeeper.console.threshold}</level>
</filter>
</appender>
<!--
Add ROLLINGFILE to root logger to get log file output
-->
<appender name="ROLLINGFILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<File>${zookeeper.log.dir}/${zookeeper.log.file}</File>
<encoder>
<pattern>%d{ISO8601} [myid:%X{myid}] - %-5p [%t:%C{1}@%L] - %m%n</pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>${zookeeper.log.threshold}</level>
</filter>
<rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">
<maxIndex>${zookeeper.log.maxbackupindex}</maxIndex>
<FileNamePattern>${zookeeper.log.dir}/${zookeeper.log.file}.%i</FileNamePattern>
</rollingPolicy>
<triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
<MaxFileSize>${zookeeper.log.maxfilesize}</MaxFileSize>
</triggeringPolicy>
</appender>
<!--
Add TRACEFILE to root logger to get log file output
Log TRACE level and above messages to a log file
-->
<!--property name="zookeeper.tracelog.dir" value="${zookeeper.log.dir}" />
<property name="zookeeper.tracelog.file" value="zookeeper_trace.log" />
<appender name="TRACEFILE" class="ch.qos.logback.core.FileAppender">
<File>${zookeeper.tracelog.dir}/${zookeeper.tracelog.file}</File>
<encoder>
<pattern>%d{ISO8601} [myid:%X{myid}] - %-5p [%t:%C{1}@%L] - %m%n</pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>TRACE</level>
</filter>
</appender-->
<!--
zk audit logging
-->
<property name="zookeeper.auditlog.file" value="zookeeper_audit.log" />
<property name="zookeeper.auditlog.threshold" value="INFO" />
<property name="audit.logger" value="INFO, RFAAUDIT" />
<appender name="RFAAUDIT" class="ch.qos.logback.core.rolling.RollingFileAppender">
<File>${zookeeper.log.dir}/${zookeeper.auditlog.file}</File>
<encoder>
<pattern>%d{ISO8601} %p %c{2}: %m%n</pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>${zookeeper.auditlog.threshold}</level>
</filter>
<rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">
<maxIndex>10</maxIndex>
<FileNamePattern>${zookeeper.log.dir}/${zookeeper.auditlog.file}.%i</FileNamePattern>
</rollingPolicy>
<triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
<MaxFileSize>10MB</MaxFileSize>
</triggeringPolicy>
</appender>
<logger name="org.apache.zookeeper.audit.Slf4jAuditLogger" additivity="false" level="${audit.logger}">
<appender-ref ref="RFAAUDIT" />
</logger>
<root level="INFO">
<appender-ref ref="CONSOLE" />
<appender-ref ref="ROLLINGFILE" />
</root>
</configuration>
Tip
This is a customization of the original file from Zookeeper source tree. Please refer to documentation to configure logging.
Create Systemd File¶
Create a systemd
file. Put the following in /etc/systemd/system/drove.zookeeper.service
:
[Unit]
Description=Drove Zookeeper Service
After=docker.service
Requires=docker.service
[Service]
User=drove
TimeoutStartSec=0
Restart=always
ExecStartPre=-/usr/bin/docker pull zookeeper:3.8
ExecStart=/usr/bin/docker run \
--env-file /etc/drove/zk/zk.env \
--volume /var/lib/drove/zk/data:/data \
--volume /var/lib/drove/zk/datalog:/datalog \
--volume /var/log/drove/zk:/logs \
--volume /etc/drove/zk/logback.xml:/conf/logback.xml \
--volume /etc/drove/zk/java.env:/conf/java.env \
--publish 2181:2181 \
--publish 2888:2888 \
--publish 3888:3888 \
--rm \
--name drove.zookeeper \
zookeeper:3.8
[Install]
WantedBy=multi-user.target
Verify the file with the following command:
systemd-analyze verify drove.zookeeper.service
Set permissions
chmod 664 /etc/systemd/system/drove.zookeeper.service
Start the service on all servers¶
Use the following to start the service:
systemctl daemon-reload
systemctl enable drove.zookeeper
systemctl start drove.zookeeper
You can check server status using the following:
echo srvr | nc localhost 2181
Tip
Replace localhost
on the above command with the actual ZK server IPs to test remote connectivity.
Note
You can access the ZK client from the container using the following command:
docker exec -it drove.zookeeper bin/zkCli.sh
To connect to remote host you can use the following:
docker exec -it drove.zookeeper bin/zkCli.sh -server <server name or ip>:2181