The easiest way to build a Zookeeper server in history

What is ZooKeeper

ZooKeeper is a top-level project of Apache, providing efficient and highly available distributed coordination services for distributed applications, providing distributed foundations such as data publish/subscribe, load balancing, naming services, distributed coordination/notification, and distributed locks Serve. ZooKeeper is widely used in large distributed systems such as Hadoop, HBase, Kafka and Dubbo due to its convenient use, excellent performance and good stability.

Zookeeper has three operating modes: stand-alone mode, pseudo-cluster mode, and cluster mode.

  • Stand-alone mode: This mode is generally suitable for development and testing environments. On the one hand, we do not have so many machine resources, and on the other hand, the usual development and debugging do not require excellent stability.
  • Cluster mode: A ZooKeeper cluster is usually composed of a group of machines. Generally, more than 3 machines can form an available ZooKeeper cluster. Each machine that makes up a ZooKeeper cluster maintains the current server state in memory, and each machine communicates with each other.
  • Pseudo-cluster mode: This is a special cluster mode where all servers of the cluster are deployed on a single machine. When you have a good machine at hand, deploying as a stand-alone mode will waste resources. In this case, ZooKeeper allows you to start multiple ZooKeeper service instances on one machine by starting different ports to Therefore, the external service is provided by the characteristics of the cluster.

Knowledge of ZooKeeper

Roles in Zookeeper

  • Leader: responsible for the initiation and resolution of voting, and updating the system status
  • Follower: used to receive client requests and return results to the client, and vote in the process of electing the master
  • Observer: It can accept client connections and forward write requests to the leader, but the observer does not participate in the voting process, just to expand the system and improve the reading speed.

Roles in Zookeeper

Zookeeper's data model

  • Hierarchical directory structure, named according to regular file system conventions, similar to Linux
  • Each node is called znode in zookeeper, and it has a unique path identifier
  • A node Znode can contain data and child nodes, but a node of type EPHEMERAL cannot have child nodes
  • The data in Znode can have multiple versions. For example, if there are multiple data versions in a certain path, then you need to bring the version to query the data under this path.
  • Client applications can set monitors on nodes
  • The node does not support partial read and write, but a complete read and write at one time

Zookeeper's data model

Node Features of ZooKeeper

ZooKeeper nodes are life-cycle, depending on the type of node. In ZooKeeper, nodes can be divided into persistent nodes (PERSISTENT) and temporary nodes (EPHEMERAL) according to the duration, and can be divided into sequential nodes (SEQUENTIAL) and disordered nodes (the default is disordered) according to whether they are ordered.

Once a persistent node is created, unless it is actively removed, it will always be saved in Zookeeper (it will not disappear due to the invalidation of the session of the client that created the node), temporary nodes

Application scenarios of Zookeeper

ZooKeeper is a highly available distributed data management and system coordination framework. Based on the implementation of the Paxos algorithm, the framework ensures strong data consistency in a distributed environment. It is also based on this feature that ZooKeeper solves many distributed problems.

It is worth noting that ZooKeeper is not designed for these application scenarios. It is a typical use that many developers later explored based on the characteristics of its framework, using a series of API interfaces (or primitive sets) provided by it. method.

Data publishing and subscription (configuration center)

The publish and subscribe model, the so-called configuration center, as the name implies, is that the publisher publishes data to the ZK node for the subscriber to obtain the data dynamically, and realizes the centralized management and dynamic update of the configuration information. For example, global configuration information, service address list of service-based service framework, etc. are very suitable for use.

Some configuration information used in the application is placed on the ZK for centralized management. This kind of scenario is usually like this: the application will take the initiative to obtain a configuration when it starts, and at the same time, register a Watcher on the node, so that every time the configuration is updated in the future, it will notify the subscribed client in real time. Always achieve the purpose of obtaining the latest configuration information. In the distributed search service, the meta information of the index and the node status of the server cluster machine are stored in some designated nodes of ZK for each client to subscribe. Distributed log collection system. The core job of this system is to collect logs distributed across different machines. The collector usually allocates collection task units according to the application, so it is necessary to create a node P with the application name as the path on the ZK, and register all the machine IPs of this application on the node P in the form of child nodes, so that a When the machine changes, the collector can be notified in real time to adjust the task allocation. Some information in the system needs to be dynamically obtained, and there will be questions about manually modifying this information manually. Usually an interface is exposed, such as a JMX interface, to obtain some runtime information. After the introduction of ZK, there is no need to implement a set of solutions by yourself, as long as the information is stored on the designated ZK node. Note: In the application scenarios mentioned above, there is a default premise: the amount of data is small, but the data update may be faster.

load balancing

The load balancing mentioned here refers to soft load balancing. In a distributed environment, in order to ensure high availability, usually the same application or the same service provider will deploy multiple copies to achieve peer-to-peer services. Consumers need to choose one of these peer servers to execute related business logic, among which is the typical producer and consumer load balancing in message middleware.

Naming Service

Naming services are also a common type of scenario in distributed systems. In a distributed system, by using the naming service, the client application can obtain the address, provider and other information of the resource or service according to the specified name. The named entity can usually be a machine in the cluster, the address of the service provided, the remote object, etc. - these we can collectively call them the name (Name). One of the more common ones is the list of service addresses in some distributed service frameworks. By calling the API for creating nodes provided by ZK, it is easy to create a globally unique path, which can be used as a name.

The open source distributed service framework Dubbo of Alibaba Group uses ZooKeeper as its naming service to maintain a global list of service addresses. In the implementation of Dubbo: When the service provider starts, it /dubbo/${serviceName}/providerswrites its own URL address to the specified node directory on ZK, and this operation completes the service release. When the service consumer starts, it subscribes /dubbo/${serviceName}/providersto the provider URL address in the /dubbo/${serviceName} /consumersdirectory, and writes its own URL address to the directory. Note that all addresses registered with ZK are ephemeral nodes, which ensures that service providers and consumers can automatically sense resource changes.

In addition, Dubbo also provides monitoring for service granularity by subscribing /dubbo/${serviceName}to the information of all providers and consumers in the directory.

Distributed Notification/Coordination

ZooKeeper has a unique watcher registration and asynchronous notification mechanism, which can well realize notification and coordination between different systems in a distributed environment, and realize real-time processing of data changes. The method of use is usually that different systems register the same znode on the ZK, monitor the changes of the znode (including the content of the znode itself and sub-nodes), and one system updates the znode, then the other system can receive the notification and make corresponding deal with.

Another heartbeat detection mechanism: The detection system and the detected system are not directly associated, but are associated with a node on zk, which greatly reduces system coupling. Another system scheduling mode: a system consists of a console and a push system. The responsibility of the console is to control the push system to perform the corresponding push work. Some operations performed by administrators in the console actually modify the status of some nodes on ZK, and ZK notifies the clients of the changes to their registered Watcher clients, that is, the push system, and then performs corresponding push tasks.

Another work report mode: something similar to the task distribution system, after the subtask is started, go to zk to register a temporary node, and regularly report its progress (write the progress back to this temporary node), so that the task manager can Able to know the progress of the task in real time.

Distributed lock

Distributed lock, which is mainly due to the strong consistency of data guaranteed by ZooKeeper for us. Lock services can be divided into two categories, one is to keep exclusive, and the other is to control timing.

The so-called maintain exclusive means that all the clients who try to acquire the lock, only one can successfully acquire the lock in the end. The usual practice is to treat a znode on zk as a lock, which create znodeis implemented by the method. All clients create /distribute_locknodes , and the client that is finally successfully created also owns the lock. The control sequence is the client that all views acquire the lock, which will eventually be arranged for execution, but there is only a global sequence. The method is basically similar to the above, except that it /distribute_lockalready , and the client creates a temporary ordered node under it (this can be specified through the attribute control of the node: CreateMode.EPHEMERAL_SEQUENTIALto specify). The parent node ( /distribute_lock) of Zk maintains a sequence to ensure the timing of the creation of child nodes, thus forming the global timing of each client.

  1. Since the names of subnodes under the same node cannot be the same, as long as a znode is created under a node, the successful creation indicates that the locking is successful. Register a listener to monitor this znode, and notify other clients to lock as long as this znode is deleted.
  2. Create a temporary sequential node: Create a node under a node, and a request will create a node. Because it is sequential, the lock with the smallest serial number is obtained. When the lock is released, the next serial number is notified to obtain the lock.
Distributed queue

In terms of queues, there are two kinds of queues, one is the conventional first-in, first-out queue, and the other is to wait for the members of the queue to gather before executing in order. For the first type of queue, the basic principle of the sequence control scenario in the distributed lock service mentioned above is the same, so I won't go into details here.

The second type of queue is actually an enhancement based on the FIFO queue. Usually, a node can be pre-established under /queue this znode /queue/num , and the value is n (or n is directly assigned to /queue), indicating the queue size. After each queue member joins, it is judged whether the queue size has been reached, and whether it can be Executed. A typical scenario of this usage is that in a distributed environment, a large task Task A can only be performed when many subtasks are completed (or conditionally ready). At this time, if one of the sub-tasks is completed (ready), then go to /taskListthe next to build your own temporary timing node ( CreateMode.EPHEMERAL_SEQUENTIAL). When you /taskListfind that the sub-nodes below you meet the specified number, you can proceed to the next step in order.

Use dokcer-compose to build a cluster

Above we have introduced so many application scenarios for ZooKeeper, then we will first learn how to build a ZooKeeper cluster and then implement the above application scenarios.

The directory structure of the file is as follows:

├── docker-compose.yml

Write the docker-compose.yml file

docker-compose.ymlThe contents of the file are as follows:

version: '3.4'

services:
  zoo1:
    image: zookeeper
    restart: always
    hostname: zoo1
    ports:
      - 2181:2181
    environment:
      ZOO_MY_ID: 1
      ZOO_SERVERS: server.1=0.0.0.0:2888:3888;2181 server.2=zoo2:2888:3888;2181 server.3=zoo3:2888:3888;2181

  zoo2:
    image: zookeeper
    restart: always
    hostname: zoo2
    ports:
      - 2182:2181
    environment:
      ZOO_MY_ID: 2
      ZOO_SERVERS: server.1=zoo1:2888:3888;2181 server.2=0.0.0.0:2888:3888;2181 server.3=zoo3:2888:3888;2181

  zoo3:
    image: zookeeper
    restart: always
    hostname: zoo3
    ports:
      - 2183:2181
    environment:
      ZOO_MY_ID: 3
      ZOO_SERVERS: server.1=zoo1:2888:3888;2181 server.2=zoo2:2888:3888;2181 server.3=0.0.0.0:2888:3888;2181
      

In this configuration file, docker runs three zookeeper images, and binds the local ports 2181, 2182, and 2183 to the corresponding container's port 2181 through the ports field.

ZOO_MY_IDand ZOO_SERVERSare two environment variables required to build a Zookeeper cluster. ZOO_MY_IDThe id that identifies the service, an integer between 1-255, must be unique in the cluster. ZOO_SERVERSis a list of hosts in the cluster.

Execute in docker-compose.ymlthe directory where it is located docker-compose up, and you can see the startup log.

Connect to ZooKeeper

After the cluster is started, we can connect to ZooKeeper to perform node-related operations on it.

  1. First we need to download ZooKeeper. ZooKeeper download address .
  2. unzip it
  3. into its confdirectory, it will be zoo_sample .cfgchanged tozoo.cfg

Configuration file description

# The number of milliseconds of each tick
# tickTime:CS通信心跳数
# Zookeeper 服务器之间或客户端与服务器之间维持心跳的时间间隔,也就是每个 tickTime 时间就会发送一个心跳。tickTime以毫秒为单位。
tickTime=2000

# The number of ticks that the initial
# synchronization phase can take
# initLimit:LF初始通信时限
# 集群中的follower服务器(F)与leader服务器(L)之间初始连接时能容忍的最多心跳数(tickTime的数量)。
initLimit=5

# The number of ticks that can pass between
# sending a request and getting an acknowledgement
# syncLimit:LF同步通信时限
# 集群中的follower服务器与leader服务器之间请求和应答之间能容忍的最多心跳数(tickTime的数量)。
syncLimit=2

# the directory where the snapshot is stored.
# do not use /tmp for storage, /tmp here is just
# example sakes.
# dataDir:数据文件目录
# Zookeeper保存数据的目录,默认情况下,Zookeeper将写数据的日志文件也保存在这个目录里。
dataDir=/data/soft/zookeeper-3.4.12/data


# dataLogDir:日志文件目录
# Zookeeper保存日志文件的目录。
dataLogDir=/data/soft/zookeeper-3.4.12/logs

# the port at which the clients will connect
# clientPort:客户端连接端口
# 客户端连接 Zookeeper 服务器的端口,Zookeeper 会监听这个端口,接受客户端的访问请求。
clientPort=2181

# the maximum number of client connections.
# increase this if you need to handle more clients
#maxClientCnxns=60
#
# Be sure to read the maintenance section of the
# administrator guide before turning on autopurge.
#
# http://zookeeper.apache.org/doc/current/zookeeperAdmin.html#sc_maintenance
#
# The number of snapshots to retain in dataDir
#autopurge.snapRetainCount=3
# Purge task interval in hours
# Set to "0" to disable auto purge feature
#autopurge.purgeInterval=1


# 服务器名称与地址:集群信息(服务器编号,服务器地址,LF通信端口,选举端口)
# 这个配置项的书写格式比较特殊,规则如下:

# server.N=YYY:A:B

# 其中N表示服务器编号,YYY表示服务器的IP地址,A为LF通信端口,表示该服务器与集群中的leader交换的信息的端口。B为选举端口,表示选举新leader时服务器间相互通信的端口(当leader挂掉时,其余服务器会相互通信,选择出新的leader)。一般来说,集群中每个服务器的A端口都是一样,每个服务器的B端口也是一样。但是当所采用的为伪集群时,IP地址都一样,只能时A端口和B端口不一样。

You can do not modify zoo.cfg, the default configuration is fine, and then execute the command in the unzipped bin directory ./zkCli.sh -server 127.0.0.1:2181to connect.

Welcome to ZooKeeper!
2020-06-01 15:03:52,512 [myid:] - INFO  [main-SendThread(localhost:2181):ClientCnxn$SendThread@1025] - Opening socket connection to server localhost/127.0.0.1:2181. Will not attempt to authenticate using SASL (unknown error)
JLine support is enabled
2020-06-01 15:03:52,576 [myid:] - INFO  [main-SendThread(localhost:2181):ClientCnxn$SendThread@879] - Socket connection established to localhost/127.0.0.1:2181, initiating session
2020-06-01 15:03:52,599 [myid:] - INFO  [main-SendThread(localhost:2181):ClientCnxn$SendThread@1299] - Session establishment complete on server localhost/127.0.0.1:2181, sessionid = 0x100001140080000, negotiated timeout = 30000

WATCHER::

WatchedEvent state:SyncConnected type:None path:null
[zk: 127.0.0.1:2181(CONNECTED) 0]

Next we can use the command to view the node

  • Use the ls command to view what is currently contained in ZooKeeper

    Order:ls /

    	[zk: 127.0.0.1:2181(CONNECTED) 10] ls /
    

[zookeeper] ```

  • Created a new znode " zk " and the string associated with it

    Order:create /zk myData

    	[zk: 127.0.0.1:2181(CONNECTED) 11] create /zk myData
    

Created /zk [zk: 127.0.0.1:2181(CONNECTED) 12] ls / [zk, zookeeper] [zk: 127.0.0.1:2181(CONNECTED) 13] ```

  • Get znode nodezk

    Order:get /zk

    	[zk: 127.0.0.1:2181(CONNECTED) 13] get /zk
    

myData cZxid = 0x400000008 ctime = Mon Jun 01 15:07:50 CST 2020 mZxid = 0x400000008 mtime = Mon Jun 01 15:07:50 CST 2020 pZxid = 0x400000008 cversion = 0 dataVersion = 0 aclVersion = 0 ephemeralOwner = 0x0 dataLength = 6 numChildren = 0

```
  • delete znodezk

    Order:delete /zk

    	[zk: 127.0.0.1:2181(CONNECTED) 14] delete /zk
    

[zk: 127.0.0.1:2181(CONNECTED) 15] ls / [zookeeper] ```

Due to the limited space, the next article will implement the code one by one according to the ZooKeeper application scenarios mentioned above.

ZooKeeper's Docker configuration file repository

ZooKeeper's Docker configuration file repository

ZooKeeper's Docker configuration file repository

You can pull the project directly from above, and it only takes two steps to start RocketMQ

  1. Pull the project from GitHub
  2. docker-compose upExecute the command in the ZooKeeper folder

Reference article

{{o.name}}
{{m.name}}

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324147725&siteId=291194637