C(Consistency):一致性,这里指的是有效时间内数据的强一致性。
A(Availability):可用性,要求即便系统故障,也能在有效的时间内返回结果(成功或失败)
P(Partition tolerance):分区容错性,在网络分区发生故障的情况下还是能向外提供服务。排除整体网络故障。
cap理论指的是在分布式的环境下仅能满足以上的2种,其中P是必须的,因为如果某个分区网络故障如果导致另外的分区不能继续向外提供相应的服务,那么分布式是没有意义的。CA的对立点在于,如果在有效的时间内系统是有问题的,那么我应该选择C保持数据的一致性还是选择A做出响应。
1、对于一个分布式环境,CAP理论应用在于节点之间的信息同步,那么其实对于Nosql或者关系型数据库都是一样的,都是在解决读写一致的问题,在中间做出一个权衡。
2、对于单节点而言,CAP理论在关系型数据库中应该对应的是多表关联,或者垂直分表模型下的同步机制,而Nosql则基本上弱化了表的关联,也就是选择了AP,但是其实CAP理论是基于分布式而提出的理论,针对这种场景提出的讨论其实没有什么意义。
BA(Basically Available):基本可用,允许损失部分可用(时间上或者降级服务)。
S(Soft sate):软状态,系统的一些状态不会影响系统的怎整体可用性。
E(Eventually consistent):最终一致性,允许系统在一段时间的同步中,最终能达到一个一致的状态。
Base是对CAP中的一致性和可用性权衡的结果,核心的思想就是即使无法做到强一致性,但是每个业务可以根据自身的特点,达到系统的最终一致性。
下载地址,选择当前比较新的稳定版本
http://mirror.bit.edu.cn/apache/zookeeper/
#下载zookepeer
wget http://mirror.bit.edu.cn/apache/zookeeper/zookeeper-3.4.13/zookeeper-3.4.13.tar.gz
tar -zxvf zookeeper-3.4.13.tar.gz
#进到/conf目录下
cp zoo_sample.cfg zoo.cfg
#进到/bin目录下,出现下图即成功(图2-0)
sh zkServer.sh start
#连接到zookeppeer
./zkCli.sh -server 127.0.0.1:2181
(图2-0)
获取Dockerfile文件
1.1 可以在https://github.com/31z4/zookeeper-docker
找到相应的Dockerfile文件。
1.2 附上一份zookepeer-3.4.12的Dockerfile文件
FROM openjdk:8-jre-alpine
# Install required packages
RUN apk add --no-cache \
bash \
su-exec
ENV ZOO_USER=zookeeper \
ZOO_CONF_DIR=/conf \
ZOO_DATA_DIR=/data \
ZOO_DATA_LOG_DIR=/datalog \
ZOO_PORT=2181 \
ZOO_TICK_TIME=2000 \
ZOO_INIT_LIMIT=5 \
ZOO_SYNC_LIMIT=2 \
ZOO_MAX_CLIENT_CNXNS=60
# Add a user and make dirs
RUN set -ex; \
adduser -D "$ZOO_USER"; \
mkdir -p "$ZOO_DATA_LOG_DIR" "$ZOO_DATA_DIR" "$ZOO_CONF_DIR"; \
chown "$ZOO_USER:$ZOO_USER" "$ZOO_DATA_LOG_DIR" "$ZOO_DATA_DIR" "$ZOO_CONF_DIR"
ARG GPG_KEY=586EFEF859AF2DB190D84080BDB2011E173C31A2
ARG DISTRO_NAME=zookeeper-3.4.12
# Download Apache Zookeeper, verify its PGP signature, untar and clean up
RUN set -ex; \
apk add --no-cache --virtual .build-deps \
ca-certificates \
gnupg \
libressl; \
wget -q "https://www.apache.org/dist/zookeeper/$DISTRO_NAME/$DISTRO_NAME.tar.gz"; \
wget -q "https://www.apache.org/dist/zookeeper/$DISTRO_NAME/$DISTRO_NAME.tar.gz.asc"; \
export GNUPGHOME="$(mktemp -d)"; \
gpg --keyserver ha.pool.sks-keyservers.net --recv-key "$GPG_KEY" || \
gpg --keyserver pgp.mit.edu --recv-keys "$GPG_KEY" || \
gpg --keyserver keyserver.pgp.com --recv-keys "$GPG_KEY"; \
gpg --batch --verify "$DISTRO_NAME.tar.gz.asc" "$DISTRO_NAME.tar.gz"; \
tar -xzf "$DISTRO_NAME.tar.gz"; \
mv "$DISTRO_NAME/conf/"* "$ZOO_CONF_DIR"; \
rm -rf "$GNUPGHOME" "$DISTRO_NAME.tar.gz" "$DISTRO_NAME.tar.gz.asc"; \
apk del .build-deps
WORKDIR $DISTRO_NAME
VOLUME ["$ZOO_DATA_DIR", "$ZOO_DATA_LOG_DIR"]
EXPOSE $ZOO_PORT 2888 3888
ENV PATH=$PATH:/$DISTRO_NAME/bin \
ZOOCFGDIR=$ZOO_CONF_DIR
COPY docker-entrypoint.sh /
ENTRYPOINT ["/docker-entrypoint.sh"]
CMD ["zkServer.sh", "start-foreground"]
1.3 附上docker-entrypoint.sh
#!/bin/bash
set -e
# Allow the container to be started with `--user`
if [[ "$1" = 'zkServer.sh' && "$(id -u)" = '0' ]]; then
chown -R "$ZOO_USER" "$ZOO_DATA_DIR" "$ZOO_DATA_LOG_DIR"
exec su-exec "$ZOO_USER" "$0" "$@"
fi
# Generate the config only if it doesn't exist
if [[ ! -f "$ZOO_CONF_DIR/zoo.cfg" ]]; then
CONFIG="$ZOO_CONF_DIR/zoo.cfg"
echo "clientPort=$ZOO_PORT" >> "$CONFIG"
echo "dataDir=$ZOO_DATA_DIR" >> "$CONFIG"
echo "dataLogDir=$ZOO_DATA_LOG_DIR" >> "$CONFIG"
echo "tickTime=$ZOO_TICK_TIME" >> "$CONFIG"
echo "initLimit=$ZOO_INIT_LIMIT" >> "$CONFIG"
echo "syncLimit=$ZOO_SYNC_LIMIT" >> "$CONFIG"
echo "maxClientCnxns=$ZOO_MAX_CLIENT_CNXNS" >> "$CONFIG"
for server in $ZOO_SERVERS; do
echo "$server" >> "$CONFIG"
done
fi
# Write myid only if it doesn't exist
if [[ ! -f "$ZOO_DATA_DIR/myid" ]]; then
echo "${ZOO_MY_ID:-1}" > "$ZOO_DATA_DIR/myid"
fi
exec "$@"
镜像
#构建镜像
docker build -t zookepeer:3.4.12 .
#后台运行
docker run --name zookeeper_single --restart always --privileged=true -d zookeeper:3.4.12
#直接连接
docker run -it --rm --link zookeeper_single:zookeeper zookeeper:3.4.12 zkCli.sh -server zookeeper
注意:这种模式是网上比较多的集群方式,启动的是bridge模式,就是docker之间是可以互相通讯的,但是并没有提供宿主端口访问。需要宿主机器做另外的处理。
编写yml文件
vim stack.yml
version: '3.1'
services:
zoo1:
image: zookeeper:3.4.12
restart: always
hostname: zoo1
ports:
- 2181:2181
environment:
ZOO_MY_ID: 1
ZOO_SERVERS: server.1=0.0.0.0:2888:3888 server.2=zoo2:2888:3888 server.3=zoo3:2888:3888
zoo2:
image: zookeeper:3.4.12
restart: always
hostname: zoo2
ports:
- 2182:2181
environment:
ZOO_MY_ID: 2
ZOO_SERVERS: server.1=zoo1:2888:3888 server.2=0.0.0.0:2888:3888 server.3=zoo3:2888:3888
zoo3:
image: zookeeper:3.4.12
restart: always
hostname: zoo3
ports:
- 2183:2181
environment:
ZOO_MY_ID: 3
ZOO_SERVERS: server.1=zoo1:2888:3888 server.2=zoo2:2888:3888 server.3=0.0.0.0:2888:3888
#启动集群
docker stack deploy -c stack.yml zookeeper
#查看日志
docker logs 容器id
#进入容器
docker exec -it 49ba50ad1c64 /bin/sh
#查看本机集群状态
/zookeeper-3.4.12/bin/zkServer.sh status
#如下
`
ZooKeeper JMX enabled by default
Using config: /conf/zoo.cfg
Mode: leader
`
#移除集群
docker stack rm zookeeper
注意:这种模式可以docker容器提供与宿主映射的端口,在自己测试的时候很方便。
修改Dockerfile,不在dockerfile中指定暴露端口
FROM openjdk:8-jre-alpine
# Install required packages
RUN apk add --no-cache \
bash \
su-exec
ENV ZOO_USER=zookeeper \
ZOO_CONF_DIR=/conf \
ZOO_DATA_DIR=/data \
ZOO_DATA_LOG_DIR=/datalog \
ZOO_TICK_TIME=2000 \
ZOO_INIT_LIMIT=5 \
ZOO_SYNC_LIMIT=2 \
ZOO_MAX_CLIENT_CNXNS=60
# Add a user and make dirs
RUN set -ex; \
adduser -D "$ZOO_USER"; \
mkdir -p "$ZOO_DATA_LOG_DIR" "$ZOO_DATA_DIR" "$ZOO_CONF_DIR"; \
chown "$ZOO_USER:$ZOO_USER" "$ZOO_DATA_LOG_DIR" "$ZOO_DATA_DIR" "$ZOO_CONF_DIR"
ARG GPG_KEY=586EFEF859AF2DB190D84080BDB2011E173C31A2
ARG DISTRO_NAME=zookeeper-3.4.12
# Download Apache Zookeeper, verify its PGP signature, untar and clean up
RUN set -ex; \
apk add --no-cache --virtual .build-deps \
ca-certificates \
gnupg \
libressl; \
wget -q "https://www.apache.org/dist/zookeeper/$DISTRO_NAME/$DISTRO_NAME.tar.gz"; \
wget -q "https://www.apache.org/dist/zookeeper/$DISTRO_NAME/$DISTRO_NAME.tar.gz.asc"; \
export GNUPGHOME="$(mktemp -d)"; \
gpg --keyserver ha.pool.sks-keyservers.net --recv-key "$GPG_KEY" || \
gpg --keyserver pgp.mit.edu --recv-keys "$GPG_KEY" || \
gpg --keyserver keyserver.pgp.com --recv-keys "$GPG_KEY"; \
gpg --batch --verify "$DISTRO_NAME.tar.gz.asc" "$DISTRO_NAME.tar.gz"; \
tar -xzf "$DISTRO_NAME.tar.gz"; \
mv "$DISTRO_NAME/conf/"* "$ZOO_CONF_DIR"; \
rm -rf "$GNUPGHOME" "$DISTRO_NAME.tar.gz" "$DISTRO_NAME.tar.gz.asc"; \
apk del .build-deps
WORKDIR $DISTRO_NAME
VOLUME ["$ZOO_DATA_DIR", "$ZOO_DATA_LOG_DIR"]
ENV PATH=$PATH:/$DISTRO_NAME/bin \
ZOOCFGDIR=$ZOO_CONF_DIR
COPY docker-entrypoint.sh /
ENTRYPOINT ["sh", "/docker-entrypoint.sh"]
CMD ["zkServer.sh", "start-foreground"]
docker build -t zookeeper-host:3.4.12 .
#宿主机器ip为192.168.1.10。 启动端口2001可访问zookeeper客户端,下面是一样的操作
docker run -d\
-p 2001:2181\
-p 2002:2888\
-p 2003:3888\
-e ZOO_MY_ID=1 \
-e ZOO_PORT=2001\
-e ZOO_SERVERS="server.1=192.168.1.10:2002:2003 server.2=192.168.1.10:2005:2006 server.3=192.168.1.10:2008:2009"\
--name=zookeeper_host_1 \
--net=host \
zookeeper-host:3.4.12
docker run -d\
-p 2004:2181\
-p 2005:2888\
-p 2006:3888\
-e ZOO_PORT=2004\
-e ZOO_MY_ID=2 \
-e ZOO_SERVERS="server.1=192.168.1.10:2002:2003 server.2=192.168.1.10:2005:2006 server.3=192.168.1.10:2008:2009"\
--name=zookeeper_host_2 \
--net=host \
--privileged \
zookeeper-host:3.4.12
~~~~
docker run -d\
-p 2007:2181\
-p 2008:2888\
-p 2009:3888\
-e ZOO_PORT=2007\
-e ZOO_MY_ID=3 \
-e ZOO_SERVERS="server.1=192.168.1.10:2002:2003 server.2=192.168.1.10:2005:2006 server.3=192.168.1.10:2008:2009"\
--name=zookeeper_host_3 \
--net=host \
--privileged \
zookeeper-host:3.4.12