1-ZooKeeper in-depth understanding

Posted by imaprogramur on Mon, 08 Nov 2021 02:44:41 +0100

1 ZooKeeper details

ZooKeeper is an open source distributed Apache project that provides coordination services for distributed applications.

1-1 ZooKeeper working mechanism

Zookeeper is understood from the perspective of design pattern: it is a distributed service management framework based on the observer design pattern. It is responsible for storing and managing the data concerned by the rich, and then receiving and registering the observers. Once the status of these data changes, zookeeper is responsible for notifying the observers registered on zookeeper to respond.

1-1-1 ZooKeeper features

  • 1)Zookeeper: a cluster composed of one leader and multiple followers.
  • 2) As long as more than half of the nodes in the cluster survive, the ZooKeeper cluster can serve normally.
  • 3) Global data consistency: each server saves a copy of the same data. No matter which server the Client connects to, the data is the same.
  • 4) The update requests are made in sequence, and the update requests from the same client are executed in sequence according to their sending order.
  • 5) Data update is atomic. A data update either succeeds or fails.
  • 6) Real time. Within a certain time range, the client can read the latest data.

1-1-2 data structure

The structure of ZooKeeper data model is very similar to Unix file system. On the whole, it can be regarded as a tree, and each node name has a znode. Each ZMNode can store 1MB of data by default, and each znode can be uniquely identified by its path.

1-1-3 application scenario

The services provided include: unified naming service, unified configuration management, unified cluster management, server dynamic node online and offline, soft balance, etc.

1-1-4 unified naming service

In the distributed environment, it is often necessary to uniformly name applications and services for easy identification.
For example, ip is not easy to remember, while domain name is easy to remember.

    1. In distributed environment, profile synchronization is very common.
    • (1) Generally, the configuration information of all nodes in a cluster is always. For example, in the Kafka cluster.
    • (2) After modifying the configuration file, you want to be able to quickly synchronize to each node.
    1. Configuration management can be implemented by Zookeeper.
    • (1) Configuration information can be written to Znode on ZooKeeper.
    • (2) Each client server listens to this Znode.
    • (3) Once the data in Znode is modified, ZooKeeper notifies each client server.

1-1-5 unified cluster management

  • 1) In distributed environment, it is necessary to master the state of each node.
    • (1) Some adjustments can be made according to the real-time status of the node.
    1. ZooKeeper can monitor node status changes in real time
    • (1) Node information can be written to Znode on ZooKeeper
    • (2) Monitoring this ZNode can obtain its real-time status

1-1-5 soft load balancing

Record the number of accesses on each server in ZooKeeper, and let the server with the least number of accesses handle the client requests.

2. Zookeeper single machine installation

2-1 ZooKeeper installation - windows local installation steps

2-1-1 download address

Address: https://zookeeper.apache.org/

2-1-2 configuring java environment

2-1-3 configuring data and log directories

  • 1. Enter the conf directory of Apache zookeeper and click zoo_ Rename sample.cfg to zoo.cfg
  • 2. Modification information in the configuration file:
	dataDir=D:\install\apache-zookeeper-3.5.7-bin\data
	dataLogDir=D:\install\apache-zookeeper-3.5.7-bin\log

2-1-4 interpretation of configuration parameters

ZooKeeper In the configuration file zoo.cfg The meaning of parameters in is interpreted as follows:	

 1)tickTime=2000: Number of communication heartbeats, ZooKeeper Heartbeat time of server and client, in milliseconds
 
ZooKeepper The basic time used, the time interval between servers or between clients and servers to maintain heartbeat, that is, each tickTime Time will send a heartbeat,Time unit: ms
 It is used for the heartbeat mechanism and sets the minimum session The timeout is twice the heartbeat time.(Session The minimum timeout for is 2*ticTime)
	
 2)initLimit=10: LF Initial communication time limit
	 
In cluster Follower Follow the server and Leaader Maximum number of heartbeats that can be tolerated during initial connection between leader servers(tickTime Number of),Use it to limit the number of users in the cluster zookeeper Connect to on server Leadder Time limit for.
	
 3)syncLimit=5 : LF Synchronous communication time limit
	
In cluster Leader And Follower The maximum response time unit of self-test, including response timeout suncLimit*tickTime,Leader think Follower Dead, remove from server list Follower. 
	
 4)dataDir:  Data price inquiry directory+Data persistence path
	
Mainly used to save ZooKeeper Data in
		
 5)clientPort=2181 : Client connection port
	
Listen to the port of the client connection

2-1-5 configuration files are as follows:

    # The number of milliseconds of each tick
	#The time interval between Zookeeper servers or between clients and servers to maintain heartbeat. Is that a heartbeat will be sent every time period
	tickTime=2000
	# The number of ticks that the initial 
	# synchronization phase can take
	initLimit=10
	# The number of ticks that can pass between 
	# sending a request and getting an acknowledgement
	syncLimit=5
	# the directory where the snapshot is stored.
	# do not use /tmp for storage, /tmp here is just 
	# example sakes.
	#The directory where the data is saved. If the log is not set, the log file will also be stored
	dataDir=D:\install\apache-zookeeper-3.5.7-bin\data
	#File directory where logs are saved
	dataLogDir=D:\install\apache-zookeeper-3.5.7-bin\log
	# the port at which the clients will connect
	#The client connects to the products of the zookeeper server. Zookeeper will listen to this port and accept the access request of the client
	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
	admin.serverPort=8888

###2-1-4 zkServer.cmd in bin directory after configuration

	2021-11-05 11:08:31,750 [myid:] - INFO  [main:QuorumPeerConfig@174] - Reading configuration from: D:\Program Files\apache-zookeeper-3.6.2-bin\bin\..\conf\zoo.cfg
	2021-11-05 11:08:31,769 [myid:] - WARN  [main:VerifyingFileFactory@65] - D:Program Filesapache-zookeeper-3.6.2-bindata is relative. Prepend .\ to indicate that you're sure!
	2021-11-05 11:08:31,788 [myid:] - INFO  [main:QuorumPeerConfig@460] - clientPortAddress is 0.0.0.0:2181
	2021-11-05 11:08:31,790 [myid:] - INFO  [main:QuorumPeerConfig@464] - secureClientPort is not set
	2021-11-05 11:08:31,791 [myid:] - INFO  [main:QuorumPeerConfig@480] - observerMasterPort is not set
	2021-11-05 11:08:31,792 [myid:] - INFO  [main:QuorumPeerConfig@497] - metricsProvider.className is org.apache.zookeeper.metrics.impl.DefaultMetricsProvider
	2021-11-05 11:08:31,794 [myid:] - INFO  [main:DatadirCleanupManager@78] - autopurge.snapRetainCount set to 3
	2021-11-05 11:08:31,795 [myid:] - INFO  [main:DatadirCleanupManager@79] - autopurge.purgeInterval set to 0
	2021-11-05 11:08:31,795 [myid:] - INFO  [main:DatadirCleanupManager@101] - Purge task is not scheduled.
	2021-11-05 11:08:31,795 [myid:] - WARN  [main:QuorumPeerMain@138] - Either no config or no quorum defined in config, running in standalone mode
	2021-11-05 11:08:31,803 [myid:] - INFO  [main:ManagedUtil@44] - Log4j 1.2 jmx support found and enabled.
	2021-11-05 11:08:31,908 [myid:] - INFO  [main:QuorumPeerConfig@174] - Reading configuration from: D:\Program Files\apache-zookeeper-3.6.2-bin\bin\..\conf\zoo.cfg
	2021-11-05 11:08:31,909 [myid:] - WARN  [main:VerifyingFileFactory@65] - D:Program Filesapache-zookeeper-3.6.2-bindata is relative. Prepend .\ to indicate that you're sure!
	2021-11-05 11:08:31,909 [myid:] - INFO  [main:QuorumPeerConfig@460] - clientPortAddress is 0.0.0.0:2181
	2021-11-05 11:08:31,910 [myid:] - INFO  [main:QuorumPeerConfig@464] - secureClientPort is not set
	2021-11-05 11:08:31,911 [myid:] - INFO  [main:QuorumPeerConfig@480] - observerMasterPort is not set
	2021-11-05 11:08:31,914 [myid:] - INFO  [main:QuorumPeerConfig@497] - metricsProvider.className is org.apache.zookeeper.metrics.impl.DefaultMetricsProvider
	2021-11-05 11:08:31,915 [myid:] - INFO  [main:ZooKeeperServerMain@122] - Starting server
	2021-11-05 11:08:31,997 [myid:] - INFO  [main:ServerMetrics@62] - ServerMetrics initialized with provider org.apache.zookeeper.metrics.impl.DefaultMetricsProvider@61443d8f
	2021-11-05 11:08:32,004 [myid:] - INFO  [main:FileTxnSnapLog@124] - zookeeper.snapshot.trust.empty : false
	2021-11-05 11:08:32,023 [myid:] - INFO  [main:ZookeeperBanner@42] -
	2021-11-05 11:08:32,023 [myid:] - INFO  [main:ZookeeperBanner@42] -   ______                  _                         
	2021-11-05 11:08:32,024 [myid:] - INFO  [main:ZookeeperBanner@42] -  |___  /                 | |                        
	2021-11-05 11:08:32,025 [myid:] - INFO  [main:ZookeeperBanner@42] -     / /    ___     ___   | | __   ___    ___   _ __     ___   _ __
	2021-11-05 11:08:32,025 [myid:] - INFO  [main:ZookeeperBanner@42] -    / /    / _ \   / _ \  | |/ /  / _ \  / _ \ | '_ \   / _ \ | '__|
	2021-11-05 11:08:32,026 [myid:] - INFO  [main:ZookeeperBanner@42] -   / /__  | (_) | | (_) | |   <  |  __/ |  __/ | |_) | |  __/ | |
	2021-11-05 11:08:32,029 [myid:] - INFO  [main:ZookeeperBanner@42] -  /_____|  \___/   \___/  |_|\_\  \___|  \___| | .__/   \___| |_|
	2021-11-05 11:08:32,031 [myid:] - INFO  [main:ZookeeperBanner@42] -                                               | |   
	2021-11-05 11:08:32,031 [myid:] - INFO  [main:ZookeeperBanner@42] -                                               |_|   
	2021-11-05 11:08:32,032 [myid:] - INFO  [main:ZookeeperBanner@42] -
	2021-11-05 11:08:41,078 [myid:] - INFO  [main:Environment@98] - Server environment:zookeeper.version=3.6.2--803c7f1a12f85978cb049af5e4ef23bd8b688715, built on 09/04/2020 12:44 GMT
	2021-11-05 11:08:41,079 [myid:] - INFO  [main:Environment@98] - Server environment:host.name=PC-202008122047
	2021-11-05 11:08:41,080 [myid:] - INFO  [main:Environment@98] - Server environment:java.version=1.8.0_144
	2021-11-05 11:08:41,081 [myid:] - INFO  [main:Environment@98] - Server environment:java.vendor=Oracle Corporation
	2021-11-05 11:08:41,082 [myid:] - INFO  [main:Environment@98] - Server environment:java.home=D:\development\Java\jdk1.8.0_144\jre
	...
	2021-11-05 11:08:41,087 [myid:] - INFO  [main:Environment@98] - Server environment:java.compiler=<NA>
	2021-11-05 11:08:41,089 [myid:] - INFO  [main:Environment@98] - Server environment:os.name=Windows 10
	2021-11-05 11:08:41,090 [myid:] - INFO  [main:Environment@98] - Server environment:os.arch=amd64
	2021-11-05 11:08:41,091 [myid:] - INFO  [main:Environment@98] - Server environment:os.version=10.0
	2021-11-05 11:08:41,091 [myid:] - INFO  [main:Environment@98] - Server environment:user.name=Administrator
	2021-11-05 11:08:41,092 [myid:] - INFO  [main:Environment@98] - Server environment:user.home=C:\Users\Administrator
	2021-11-05 11:08:41,093 [myid:] - INFO  [main:Environment@98] - Server environment:user.dir=D:\Program Files\apache-zookeeper-3.6.2-bin\bin
	2021-11-05 11:08:41,093 [myid:] - INFO  [main:Environment@98] - Server environment:os.memory.free=216MB
	2021-11-05 11:08:41,095 [myid:] - INFO  [main:Environment@98] - Server environment:os.memory.max=3401MB
	2021-11-05 11:08:41,100 [myid:] - INFO  [main:Environment@98] - Server environment:os.memory.total=230MB
	2021-11-05 11:08:41,101 [myid:] - INFO  [main:ZooKeeperServer@129] - zookeeper.enableEagerACLCheck = false
	2021-11-05 11:08:41,102 [myid:] - INFO  [main:ZooKeeperServer@137] - zookeeper.digest.enabled = true
	2021-11-05 11:08:41,102 [myid:] - INFO  [main:ZooKeeperServer@141] - zookeeper.closeSessionTxn.enabled = true
	2021-11-05 11:08:41,103 [myid:] - INFO  [main:ZooKeeperServer@1444] - zookeeper.flushDelay=0
	2021-11-05 11:08:41,104 [myid:] - INFO  [main:ZooKeeperServer@1453] - zookeeper.maxWriteQueuePollTime=0
	2021-11-05 11:08:41,104 [myid:] - INFO  [main:ZooKeeperServer@1462] - zookeeper.maxBatchSize=1000
	2021-11-05 11:08:41,105 [myid:] - INFO  [main:ZooKeeperServer@243] - zookeeper.intBufferStartingSizeBytes = 1024
	2021-11-05 11:08:41,116 [myid:] - INFO  [main:BlueThrottle@141] - Weighed connection throttling is disabled
	2021-11-05 11:08:41,120 [myid:] - INFO  [main:ZooKeeperServer@1256] - minSessionTimeout set to 4000
	2021-11-05 11:08:41,120 [myid:] - INFO  [main:ZooKeeperServer@1265] - maxSessionTimeout set to 40000
	2021-11-05 11:08:41,123 [myid:] - INFO  [main:ResponseCache@45] - Response cache size is initialized with value 400.
	2021-11-05 11:08:41,124 [myid:] - INFO  [main:ResponseCache@45] - Response cache size is initialized with value 400.
	2021-11-05 11:08:41,129 [myid:] - INFO  [main:RequestPathMetricsCollector@111] - zookeeper.pathStats.slotCapacity = 60
	2021-11-05 11:08:41,129 [myid:] - INFO  [main:RequestPathMetricsCollector@112] - zookeeper.pathStats.slotDuration = 15
	2021-11-05 11:08:41,130 [myid:] - INFO  [main:RequestPathMetricsCollector@113] - zookeeper.pathStats.maxDepth = 6
	2021-11-05 11:08:41,132 [myid:] - INFO  [main:RequestPathMetricsCollector@114] - zookeeper.pathStats.initialDelay = 5
	2021-11-05 11:08:41,133 [myid:] - INFO  [main:RequestPathMetricsCollector@115] - zookeeper.pathStats.delay = 5
	2021-11-05 11:08:41,134 [myid:] - INFO  [main:RequestPathMetricsCollector@116] - zookeeper.pathStats.enabled = false
	2021-11-05 11:08:41,139 [myid:] - INFO  [main:ZooKeeperServer@1481] - The max bytes for all large requests are set to 104857600
	2021-11-05 11:08:41,140 [myid:] - INFO  [main:ZooKeeperServer@1495] - The large request threshold is set to -1
	2021-11-05 11:08:41,182 [myid:] - INFO  [main:Log@169] - Logging initialized @9781ms to org.eclipse.jetty.util.log.Slf4jLog
	...
	2021-11-05 11:08:41,314 [myid:] - WARN  [main:ContextHandler@1520] - o.e.j.s.ServletContextHandler@32709393{/,null,UNAVAILABLE} contextPath ends with /*
	2021-11-05 11:08:41,314 [myid:] - WARN  [main:ContextHandler@1531] - Empty contextPath
	2021-11-05 11:08:41,340 [myid:] - INFO  [main:Server@359] - jetty-9.4.24.v20191120; built: 2019-11-20T21:37:49.771Z; git: 363d5f2df3a8a28de40604320230664b9c793c16; jvm 1.8.0_144-b01
	2021-11-05 11:08:41,399 [myid:] - INFO  [main:DefaultSessionIdManager@333] - DefaultSessionIdManager workerName=node0
	2021-11-05 11:08:41,401 [myid:] - INFO  [main:DefaultSessionIdManager@338] - No SessionScavenger set, using defaults
	2021-11-05 11:08:41,404 [myid:] - INFO  [main:HouseKeeper@140] - node0 Scavenging every 660000ms
	2021-11-05 11:08:41,408 [myid:] - WARN  [main:ConstraintSecurityHandler@757] - ServletContext@o.e.j.s.ServletContextHandler@32709393{/,null,STARTING} has uncovered http methods for path: /*
	2021-11-05 11:08:41,420 [myid:] - INFO  [main:ContextHandler@825] - Started o.e.j.s.ServletContextHandler@32709393{/,null,AVAILABLE}
	2021-11-05 11:08:41,853 [myid:] - INFO  [main:AbstractConnector@330] - Started ServerConnector@2f686d1f{HTTP/1.1,[http/1.1]}{0.0.0.0:8080}
	2021-11-05 11:08:41,869 [myid:] - INFO  [main:Server@399] - Started @10468ms
	2021-11-05 11:08:41,870 [myid:] - INFO  [main:JettyAdminServer@182] - Started AdminServer on address 0.0.0.0, port 8080 and command URL /commands
	2021-11-05 11:08:41,880 [myid:] - INFO  [main:ServerCnxnFactory@169] - Using org.apache.zookeeper.server.NIOServerCnxnFactory as server connection factory
	2021-11-05 11:08:41,883 [myid:] - WARN  [main:ServerCnxnFactory@309] - maxCnxns is not configured, using default value 0.
	2021-11-05 11:08:41,887 [myid:] - INFO  [main:NIOServerCnxnFactory@666] - Configuring NIO connection handler with 10s sessionless connection timeout, 2 selector thread(s), 16 worker threads, and 64 kB direct buffers.
	2021-11-05 11:08:41,892 [myid:] - INFO  [main:NIOServerCnxnFactory@674] - binding to port 0.0.0.0/0.0.0.0:2181
	2021-11-05 11:08:41,919 [myid:] - INFO  [main:WatchManagerFactory@42] - Using org.apache.zookeeper.server.watch.WatchManager as watch manager
	2021-11-05 11:08:41,919 [myid:] - INFO  [main:WatchManagerFactory@42] - Using org.apache.zookeeper.server.watch.WatchManager as watch manager
	2021-11-05 11:08:41,921 [myid:] - INFO  [main:ZKDatabase@132] - zookeeper.snapshotSizeFactor = 0.33
	2021-11-05 11:08:41,923 [myid:] - INFO  [main:ZKDatabase@152] - zookeeper.commitLogCount=500
	2021-11-05 11:08:41,931 [myid:] - INFO  [main:SnapStream@61] - zookeeper.snapshot.compression.method = CHECKED
	2021-11-05 11:08:41,935 [myid:] - INFO  [main:FileSnap@85] - Reading snapshot D:Program Filesapache-zookeeper-3.6.2-bindata\version-2\snapshot.0
	2021-11-05 11:08:41,940 [myid:] - INFO  [main:DataTree@1737] - The digest value is empty in snapshot
	2021-11-05 11:08:41,945 [myid:] - INFO  [main:ZKDatabase@289] - Snapshot loaded in 22 ms, highest zxid is 0x0, digest is 1371985504
	2021-11-05 11:08:41,947 [myid:] - INFO  [main:FileTxnSnapLog@470] - Snapshotting: 0x0 to D:Program Filesapache-zookeeper-3.6.2-bindata\version-2\snapshot.0
	2021-11-05 11:08:41,953 [myid:] - INFO  [main:ZooKeeperServer@529] - Snapshot taken in 7 ms
	2021-11-05 11:08:41,971 [myid:] - INFO  [main:RequestThrottler@74] - zookeeper.request_throttler.shutdownTimeout = 10000
	2021-11-05 11:08:41,971 [myid:] - INFO  [ProcessThread(sid:0 cport:2181)::PrepRequestProcessor@136] - PrepRequestProcessor (sid:0) started, reconfigEnabled=false
	2021-11-05 11:08:41,995 [myid:] - INFO  [main:ContainerManager@83] - Using checkIntervalMs=60000 maxPerMinute=10000 maxNeverUsedIntervalMs=0
	2021-11-05 11:08:41,998 [myid:] - INFO  [main:ZKAuditProvider@40] - ZooKeeper audit is enabled.
	2021-11-05 11:09:44,876 [myid:] - INFO  [SyncThread:0:FileTxnLog@284] - Creating new log file: log.1

2-2 ZooKeeper installation - centos local installation steps

Refer to the window steps, which are basically similar

3. Common commands of zookeeper

3-1 start zk service

  • ./zkServer.cmd start

    Refer to above

3-2 check zk's running status

  • ./zkServer.cmd status

3-3 client connection ZK

  • ./zkCli.cmd
D:\Program Files\apache-zookeeper-3.6.2-bin\bin>zkCli.cmd
Connecting to localhost:2181
2021-11-05 14:32:59,289 [myid:] - INFO  [main:Environment@98] - Client environment:zookeeper.version=3.6.2--803c7f1a12f85978cb049af5e4ef23bd8b688715, built on 09/04/2020 12:44 GMT
2021-11-05 14:32:59,296 [myid:] - INFO  [main:Environment@98] - Client environment:host.name=PC-202008122047
2021-11-05 14:32:59,299 [myid:] - INFO  [main:Environment@98] - Client environment:java.version=1.8.0_144
2021-11-05 14:32:59,303 [myid:] - INFO  [main:Environment@98] - Client environment:java.vendor=Oracle Corporation
2021-11-05 14:32:59,304 [myid:] - INFO  [main:Environment@98] - Client environment:java.home=D:\development\Java\jdk1.8.0_144\jre
...
2021-11-05 14:32:59,306 [myid:] - INFO  [main:Environment@98] - Client environment:java.io.tmpdir=C:\Users\ADMINI~1\AppData\Local\Temp\
2021-11-05 14:32:59,307 [myid:] - INFO  [main:Environment@98] - Client environment:java.compiler=<NA>
2021-11-05 14:32:59,308 [myid:] - INFO  [main:Environment@98] - Client environment:os.name=Windows 10
2021-11-05 14:32:59,309 [myid:] - INFO  [main:Environment@98] - Client environment:os.arch=amd64
2021-11-05 14:32:59,309 [myid:] - INFO  [main:Environment@98] - Client environment:os.version=10.0
2021-11-05 14:32:59,310 [myid:] - INFO  [main:Environment@98] - Client environment:user.name=Administrator
2021-11-05 14:32:59,311 [myid:] - INFO  [main:Environment@98] - Client environment:user.home=C:\Users\Administrator
2021-11-05 14:32:59,311 [myid:] - INFO  [main:Environment@98] - Client environment:user.dir=D:\Program Files\apache-zookeeper-3.6.2-bin\bin
2021-11-05 14:32:59,312 [myid:] - INFO  [main:Environment@98] - Client environment:os.memory.free=221MB
2021-11-05 14:32:59,315 [myid:] - INFO  [main:Environment@98] - Client environment:os.memory.max=3401MB
2021-11-05 14:32:59,315 [myid:] - INFO  [main:Environment@98] - Client environment:os.memory.total=230MB
2021-11-05 14:32:59,324 [myid:] - INFO  [main:ZooKeeper@1006] - Initiating client connection, connectString=localhost:2181 sessionTimeout=30000 watcher=org.apache.zookeeper.ZooKeeperMain$MyWatcher@41a4555e
2021-11-05 14:32:59,330 [myid:] - INFO  [main:X509Util@77] - Setting -D jdk.tls.rejectClientInitiatedRenegotiation=true to disable client-initiated TLS renegotiation
2021-11-05 14:32:59,870 [myid:] - INFO  [main:ClientCnxnSocket@239] - jute.maxbuffer value is 1048575 Bytes
2021-11-05 14:32:59,882 [myid:] - INFO  [main:ClientCnxn@1716] - zookeeper.request.timeout value is 0. feature enabled=false
Welcome to ZooKeeper!
2021-11-05 14:32:59,895 [myid:localhost:2181] - INFO  [main-SendThread(localhost:2181):ClientCnxn$SendThread@1167] - Opening socket connection to server localhost/127.0.0.1:2181.
2021-11-05 14:32:59,895 [myid:localhost:2181] - INFO  [main-SendThread(localhost:2181):ClientCnxn$SendThread@1169] - SASL config status: Will not attempt to authenticate using SASL (unknown error)
2021-11-05 14:32:59,899 [myid:localhost:2181] - INFO  [main-SendThread(localhost:2181):ClientCnxn$SendThread@999] - Socket connection established, initiating session, client: /127.0.0.1:53514, server: localhost/127.0.0.1:2181
JLine support is enabled
2021-11-05 14:32:59,918 [myid:localhost:2181] - INFO  [main-SendThread(localhost:2181):ClientCnxn$SendThread@1433] - Session establishment complete on server localhost/127.0.0.1:2181, session id = 0x100006597950001, negotiated timeout = 30000

WATCHER::

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

3-4 help view client help commands

  • help

    [zk: localhost:2181(CONNECTED) 2] help
    ZooKeeper -server host:port -client-configuration properties-file cmd args
    		addWatch [-m mode] path # optional mode is one of [PERSISTENT, PERSISTENT_RECURSIVE] - default is PERSISTENT_RECURSIVE
    		addauth scheme auth
    		close
    		config [-c] [-w] [-s]
    		connect host:port
    		create [-s] [-e] [-c] [-t ttl] path [data] [acl]
    		delete [-v version] path
    		deleteall path [-b batch size]
    		delquota [-n|-b] path
    		get [-s] [-w] path
    		getAcl [-s] path
    		getAllChildrenNumber path
    		getEphemerals path
    		history
    		listquota path
    		ls [-s] [-w] [-R] path
    		printwatches on|off
    		quit
    		reconfig [-s] [-v version] [[-file path] | [-members serverID=host:port1:port2;port3[,...]*]] | [-add serverId=host:port1:port2;port3[,...]]* [-remove serverId[,...]*]
    		redo cmdno
    		removewatches path [-c|-d|-a] [-l]
    		set [-s] [-v version] path data
    		setAcl [-s] [-v version] [-R] path acl
    		setquota -n|-b val path
    		stat [-w] path
    		sync path
    		version
    Command not found: Command not found help
    [zk: localhost:2181(CONNECTED) 3]
    

3-5 ls view

	
	[zk: localhost:2181(CONNECTED) 5] ls /
	[merryyou, zookeeper]
	[zk: localhost:2181(CONNECTED) 6] ls  /zookeeper
	[config, quota]
	[zk: localhost:2181(CONNECTED) 7] ls  /config
	Node does not exist: /config
	

3-6 get node data and update information

  • get content is empty
  • cZxid: id of the created node
  • ctime: creation time of the node
  • mZxid: modify node id
  • mtime: the time when the node was modified
  • pZxid: id of child node
  • cversion: version of the child node
  • dataVersion: the version of the current node data
  • aclVersion: the version of the permission
  • Ephemeral owner: judge whether it is a temporary node
  • dataLength: the length of the data
  • numChildren: number of child nodes
[zk: localhost:2181(CONNECTED) 8] get  /zookeeper
//#The following blank line indicates that the node content is empty

3-7 stat gets the update information of the node

  • stat
[zk: localhost:2181(CONNECTED) 9] stat /zookeeper
cZxid = 0x0
ctime = Thu Jan 01 08:00:00 CST 1970
mZxid = 0x0
mtime = Thu Jan 01 08:00:00 CST 1970
pZxid = 0x0
cversion = -2
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 0
numChildren = 2

3-8 create node

  • create [node] [node content]
  • create /testZnode nodeData (the node name is testznode, and the content of the testznode node is nodeData. In actual business, nodeData is generally json data)
[zk: localhost:2181(CONNECTED) 10] create /testZnode  nodeData
Created /testZnode
[zk: localhost:2181(CONNECTED) 11] ls  /
[merryyou, testZnode, zookeeper]
[zk: localhost:2181(CONNECTED) 12] get /testZnode
nodeData
[zk: localhost:2181(CONNECTED) 13] stat /testZnode
cZxid = 0x7
ctime = Fri Nov 05 14:55:59 CST 2021
mZxid = 0x7
mtime = Fri Nov 05 14:55:59 CST 2021
pZxid = 0x7
cversion = 0
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 8
numChildren = 0

3-9 create -e create a temporary node

[zk: localhost:2181(CONNECTED) 9] create  /testZnode
Created /testZnode
[zk: localhost:2181(CONNECTED) 10] create -e   /testZnode/childrenNode
Created /testZnode/childrenNode
[zk: localhost:2181(CONNECTED) 11] Terminate batch operation(Y/N)? y

D:\Program Files\apache-zookeeper-3.6.2-bin\bin>zkCli.cmd
Connecting to localhost:2181
...
WATCHER::

WatchedEvent state:SyncConnected type:None path:null
[zk: localhost:2181(CONNECTED) 0] stat /testZnode
cZxid = 0xe
ctime = Fri Nov 05 15:06:06 CST 2021
mZxid = 0xe
mtime = Fri Nov 05 15:06:06 CST 2021
pZxid = 0x11
cversion = 2
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 0
numChildren = 0
//After reconnection, the node does not exist

3-10 create -s automatic accumulation of creation order nodes

[zk: localhost:2181(CONNECTED) 2] create  -s  /testZnode/test
Created /testZnode/test0000000001
[zk: localhost:2181(CONNECTED) 3] create  -s  /testZnode/test
Created /testZnode/test0000000002
[zk: localhost:2181(CONNECTED) 4] create  -s  /testZnode/test
Created /testZnode/test0000000003
[zk: localhost:2181(CONNECTED) 5] stat /testZnode/test
Node does not exist: /testZnode/test
[zk: localhost:2181(CONNECTED) 6] create  -s  /testZnode
Created /testZnode0000000003
[zk: localhost:2181(CONNECTED) 7] stat /testZnode
cZxid = 0xe
ctime = Fri Nov 05 15:06:06 CST 2021
mZxid = 0xe
mtime = Fri Nov 05 15:06:06 CST 2021
pZxid = 0x14
cversion = 5
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 0
numChildren = 3

3-11 set path data [version] modify node

[zk: localhost:2181(CONNECTED) 19] set /znode-1 testdata 1
[zk: localhost:2181(CONNECTED) 20] stat /znode-1
cZxid = 0x18
ctime = Fri Nov 05 15:16:11 CST 2021
mZxid = 0x1a
mtime = Fri Nov 05 15:17:37 CST 2021
pZxid = 0x18
cversion = 0
dataVersion = 2
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 8
numChildren = 0
// dataVersion has changed
[zk: localhost:2181(CONNECTED) 22] set /znode-1 changedata 1
[zk: localhost:2181(CONNECTED) 24] stat /znode-1
cZxid = 0x18
ctime = Fri Nov 05 15:16:11 CST 2021
mZxid = 0x1c
mtime = Fri Nov 05 15:18:20 CST 2021
pZxid = 0x18
cversion = 0
dataVersion = 3
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 10
numChildren = 0
// dataVersion has changed
[zk: localhost:2181(CONNECTED) 25] get /znode-1
changedata
// get data

3-12 delete path [version] delete node

[zk: localhost:2181(CONNECTED) 29] ls /
[changDataZnode, merryyou, testZnode, testZnode0000000003, znode-1, zookeeper]
[zk: localhost:2181(CONNECTED) 30] delete changeDataZnode
Path must start with / character
[zk: localhost:2181(CONNECTED) 31] delete /changeDataZnode
Node does not exist: /changeDataZnode
[zk: localhost:2181(CONNECTED) 32] delete /merryyou
Node not empty: /merryyou
[zk: localhost:2181(CONNECTED) 33] ls  /merryyou
[sec0000000000, sec0000000001]
[zk: localhost:2181(CONNECTED) 34] delete /merryyou/sec
Node does not exist: /merryyou/sec
[zk: localhost:2181(CONNECTED) 35] delete /merryyou/sec0000000000
[zk: localhost:2181(CONNECTED) 36] delete /merryyou/sec0000000001
[zk: localhost:2181(CONNECTED) 37] ls /
[changDataZnode, merryyou, testZnode, testZnode0000000003, znode-1, zookeeper]
[zk: localhost:2181(CONNECTED) 38] delete /merryyou
[zk: localhost:2181(CONNECTED) 39] stat /testZnode
cZxid = 0xe
ctime = Fri Nov 05 15:06:06 CST 2021
mZxid = 0xe
mtime = Fri Nov 05 15:06:06 CST 2021
pZxid = 0x14
cversion = 5
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 0
numChildren = 3
[zk: localhost:2181(CONNECTED) 40] ls  /testZnode
[test0000000001, test0000000002, test0000000003]
[zk: localhost:2181(CONNECTED) 41] delete /testZnode/test0000000001
[zk: localhost:2181(CONNECTED) 42] delete /testZnode/test0000000002
[zk: localhost:2181(CONNECTED) 43] delete /testZnode/test0000000003
[zk: localhost:2181(CONNECTED) 44] delete /testZnode
[zk: localhost:2181(CONNECTED) 45] ls  /
[changDataZnode, testZnode0000000003, znode-1, zookeeper]
[zk: localhost:2181(CONNECTED) 46] delete /testZnode0000000003
[zk: localhost:2181(CONNECTED) 47] ls /znode-1
[]
[zk: localhost:2181(CONNECTED) 48] delete /znode-1
[zk: localhost:2181(CONNECTED) 49] ls /
[changDataZnode, zookeeper]
[zk: localhost:2181(CONNECTED) 50] delete /changDataZnode
[zk: localhost:2181(CONNECTED) 51] ls /
[zookeeper]

3-12 watcher notification mechanism

The general understanding of the watcher mechanism is that when each node changes, the watcher event will be triggered, which is similar to the trigger of mysql. The watcher in zk is one-time and is destroyed immediately after triggering.

  • stat path [watch] set the watch event
  • get path [watch] set the watch event
  • A watch event is triggered when a child node is created and deleted, and will not be triggered when a child node is modified

3-13 stat path [watch] set the watch event

3-13-1 adding a watch event

[zk: localhost:2181(CONNECTED) 18] stat /longfei watch
Node does not exist: /longfei

3-13-2 trigger the watcher event when creating a longfei node

[zk: localhost:2181(CONNECTED) 19] create /longfei test

WATCHER::

WatchedEvent state:SyncConnected type:NodeCreated path:/longfei
Created /longfei
get path [watch] set up watch event

3-13-3 add a watch event using the get command

[zk: localhost:2181(CONNECTED) 20] get /longfei watch
test
cZxid = 0x20000000e
ctime = Sat Jun 02 14:43:15 UTC 2018
mZxid = 0x20000000e
mtime = Sat Jun 02 14:43:15 UTC 2018
pZxid = 0x20000000e
cversion = 0
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 4
numChildren = 0

3-13-3 trigger the watcher event when modifying a node

[zk: localhost:2181(CONNECTED) 21] set /longfei new_test

WATCHER::

WatchedEvent state:SyncConnected type:NodeDataChanged path:/longfei
cZxid = 0x20000000e
ctime = Sat Jun 02 14:43:15 UTC 2018
mZxid = 0x20000000f
mtime = Sat Jun 02 14:45:06 UTC 2018
pZxid = 0x20000000e
cversion = 0
dataVersion = 1
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 8
numChildren = 0
[zk: localhost:2181(CONNECTED) 22] 

3-13-4 delete trigger watcher event

[zk: localhost:2181(CONNECTED) 23] get /longfei watch
new_test
cZxid = 0x20000000e
ctime = Sat Jun 02 14:43:15 UTC 2018
mZxid = 0x20000000f
mtime = Sat Jun 02 14:45:06 UTC 2018
pZxid = 0x20000000e
cversion = 0
dataVersion = 1
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 8
numChildren = 0
[zk: localhost:2181(CONNECTED) 24] delete /longfei

WATCHER::

WatchedEvent state:SyncConnected type:NodeDeleted path:/longfei
[zk: localhost:2181(CONNECTED) 25] 

4 Distributed installation and deployment

4-1 cluster planning

Deploy Zookeeper on hdp-2, hdp-3 and hdp-4 nodes.

4-2 decompression and installation

4-2-1 unzip the Zookeeper installation package to the / opt/module / directory

4-2-2 synchronize / opt/module/zookeeper-3.4.10 directory contents to hdp-3 and hdp-4

[root@hdp-2 software]$ tar -zxvf zookeeper-3.4.10.tar.gz -C /opt/module/

4-2-2 synchronize / opt/module/zookeeper-3.4.10 directory contents to hdp-3 and hdp-4

[root@hdp-2 module]$ xsync zookeeper-3.4.10/

4-3 configuration server number

4-3-1 create zkData in / opt/module/zookeeper-3.4.10 /

[root@hdp-2 zookeeper-3.4.10]$ mkdir -p zkData

4-3-2 create a myid file in / opt/module/zookeeper-3.4.10/zkData directory

[root@hdp-2 zkData]$ touch myid
 add to myid File, be sure to linux Created inside, in notepad++It's probably garbled

4-3-3 edit myid file

[root@hdp-2 zkData]$ vi myid
	Add and to the file server Corresponding No.: 2

4-3-4 copy the configured zookeeper to other machines

[root@hdp-2 zkData]$ xsync myid
 And in hdp-3,hdp-4 Upper modification myid The contents in the document are 3 and 4
```shell
### 4-4 configuration zoo.cfg file
#### 4-4-1 rename the zoo in the directory / opt/module/zookeeper-3.4.10/conf_ Sample.cfg is zoo.cfg
```shell
[root@hdp-2 conf]$ mv zoo_sample.cfg zoo.cfg

4-4-2 open the zoo.cfg file

[root@hdp-2 conf]$ vim zoo.cfg
Modify data storage path configuration
dataDir=/opt/module/zookeeper-3.4.10/zkData
 Add the following configuration
#######################cluster##########################
server.2=hdp-2:2888:3888
server.3=hdp-3:2888:3888
server.4=hdp-4:2888:3888

4-4-3 synchronize the zoo.cfg configuration file

[root@hdp-2 conf]$ xsync zoo.cfg

4-4-4 interpretation of configuration parameters

server.A=B:C:D. 
A Is a number indicating the server number;
Configure a file in cluster mode myid,This file is in dataDir Under the directory, there is a data in this file A The value of, Zookeeper Read this file at startup,
Get the data and zoo.cfg Compare the configuration information inside to determine which one it is server. 
B Is the address of this server;
C This is the server Follower With in the cluster Leader The port where the server exchanges information;
D It's in the cluster Leader The server is down. You need a port to re elect and choose a new one Leader,This port is used to execute the election time service
 The port through which the devices communicate with each other.

4-4-4 cluster operation

4-4-4-1 start Zookeeper respectively

[root@hdp-2 zookeeper-3.4.10]$ bin/zkServer.sh start
[root@hdp-3 zookeeper-3.4.10]$ bin/zkServer.sh start
[root@hdp-4 zookeeper-3.4.10]$ bin/zkServer.sh start

4-4-4-2 viewing status

[root@hdp-2 zookeeper-3.4.10]# bin/zkServer.sh status
JMX enabled by default
Using config: /opt/module/zookeeper-3.4.10/bin/../conf/zoo.cfg
Mode: follower
[root@hdp-3 zookeeper-3.4.10]# bin/zkServer.sh status
JMX enabled by default
Using config: /opt/module/zookeeper-3.4.10/bin/../conf/zoo.cfg
Mode: leader
[root@hdp-4 zookeeper-3.4.5]# bin/zkServer.sh status
JMX enabled by default
Using config: /opt/module/zookeeper-3.4.10/bin/../conf/zoo.cfg
Mode: follower

5 Api Application

5-1 create a new spingboot project

5-1-1 add dependency to POM file

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.zt</groupId>
    <artifactId>springboot-zookeeper-practice</artifactId>
    <version>1.0-SNAPSHOT</version>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.2.RELEASE</version>
    </parent>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.16</version>
        </dependency>
        <dependency>
            <groupId>org.apache.curator</groupId>
            <artifactId>curator-framework</artifactId>
            <version>4.0.0</version>
            <exclusions>
                <exclusion>
                    <groupId>org.apache.ZooKeeper</groupId>
                    <artifactId>ZooKeeper</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.apache.curator</groupId>
            <artifactId>curator-recipes</artifactId>
            <version>4.0.0</version>
        </dependency>
        <dependency>
            <groupId>org.apache.zookeeper</groupId>
            <artifactId>zookeeper</artifactId>
            <version>3.4.13</version>
        </dependency>
    </dependencies>
</project>

5-1-2 modify application.yml

server:
  port: 11000
  servlet:
    application-display-name: zooKeeperServerDemo

5-2 realize node monitoring

5-2-1 monitor the node itself

5-2-1-1 create test Controller

RestController
@RequestMapping("/hanxi/watcher")
@Slf4j
public class WatcherController {

    private final String ZK_ADDRESS = "hdp-1:2181,hdp-2:2181,hdp-3:2181";
    private final String workerPath = "/test/listener/remoteNode";
    private final String subWorkerPath = "/test/listener/remoteNode/id-";

    /**
     * Listen to the node itself
     */
    @PostMapping("/watch")
    public void watch() throws Exception {
        // Check whether the node exists, and create if it does not exist
        CuratorFramework client = ClientFactory.createSimple(ZK_ADDRESS);
        client.start();

        Stat stat = client.checkExists().forPath(workerPath);
        if (null == stat) {
            String data = "hello";
            byte[] payload = data.getBytes("UTF-8");
            client.create()
                    .creatingParentContainersIfNeeded()
                    .withMode(CreateMode.PERSISTENT)
                    .forPath(workerPath, payload);
        }

        NodeCache nodeCache = new NodeCache(client, workerPath, false);
        NodeCacheListener listener = new NodeCacheListener() {
            @Override
            public void nodeChanged() throws Exception {
                ChildData childData = nodeCache.getCurrentData();
                if (null != childData) {
                    log.info("Znode Node status changes, path={}", childData.getPath());
                    log.info("Znode Node status changes, data={}", new String(childData.getData(), "UTF-8"));
                    log.info("Znode Node status changes, stat={}", childData.getStat());
                }
                else {
                    log.info("Znode Node has been deleted, path={}", workerPath);
                }

            }
        };
        // Start event listening
        nodeCache.getListenable().addListener(listener);
        try {
            nodeCache.start();
            // Change node data for the first time
            client.setData().forPath(workerPath, "First change".getBytes(Charset.forName("UTF-8")));
            Thread.sleep(1000);
            // Change node data for the second time
            client.setData().forPath(workerPath, "Second change".getBytes(Charset.forName("UTF-8")));
            Thread.sleep(1000);
            // Change node data for the third time
            client.setData().forPath(workerPath, "Third change".getBytes(Charset.forName("UTF-8")));
            Thread.sleep(1000);
            // The 4th change of node data

            client.delete().forPath(workerPath);
            Thread.sleep(Integer.MAX_VALUE);
        } catch (Exception e) {
            log.info("Failed to create listener, path={}", workerPath);
        } finally {
            client.close();
        }
    }
}

5-2-1-2 summary

5-2-2 listening sub node

5-2-2-1 create test Controller

RestController
@RequestMapping("/hanxi/watcher")
@Slf4j
public class WatcherController {

    private final String ZK_ADDRESS = "hdp-1:2181,hdp-2:2181,hdp-3:2181";
    private final String workerPath = "/test/listener/remoteNode";
    private final String subWorkerPath = "/test/listener/remoteNode/id-";

    /**
     * Listening child node
     */
    @PostMapping("/watchChild")
    public void watchChild() throws Exception {
        // Check whether the node exists, and create if it does not exist
        CuratorFramework client = ClientFactory.createSimple(ZK_ADDRESS);
        client.start();

        Stat stat = client.checkExists().forPath(workerPath);
        if (null == stat) {
            String data = "hello";
            byte[] payload = data.getBytes("UTF-8");
            client.create()
                    .creatingParentContainersIfNeeded()
                    .withMode(CreateMode.PERSISTENT)
                    .forPath(workerPath, payload);
        }

        PathChildrenCache cache = new PathChildrenCache(client, workerPath, true);
        PathChildrenCacheListener listener = new PathChildrenCacheListener() {
            @Override
            public void childEvent(CuratorFramework client, PathChildrenCacheEvent event) throws Exception {
                ChildData childData = event.getData();
                switch (event.getType()) {
                    case CHILD_ADDED:
                        log.info("Child nodes increase, path={}, data={}", childData.getPath(), new String(childData.getData(), "UTF-8"));
                        break;
                    case CHILD_UPDATED:
                        log.info("Child node update, path={}, data={}", childData.getPath(), new String(childData.getData(), "UTF-8"));
                        break;
                    case CHILD_REMOVED:
                        log.info("Child node deletion, path={}, data={}", childData.getPath(), new String(childData.getData(), "UTF-8"));
                        break;
                    default:
                        break;
                }
            }
        };
        // Start event listening
        cache.getListenable().addListener(listener);
        cache.start(PathChildrenCache.StartMode.BUILD_INITIAL_CACHE);
        Thread.sleep(1000);

        try {
            // Create 3 nodes
            for (int i = 1; i <= 3; i++) {
                String payload = "The first" + i + "Changes";
                client.create()
                        .creatingParentContainersIfNeeded()
                        .withMode(CreateMode.PERSISTENT)
                        .forPath(subWorkerPath + i, payload.getBytes(Charset.forName("UTF-8")));
            }
            Thread.sleep(1000);
            // Delete 3 nodes
            for (int i = 1; i <= 3; i++) {
                client.delete().forPath(subWorkerPath + i);
            }
        } catch (Exception e) {
            log.info("Failed to create listener, path={}", workerPath);
        } finally {
            client.close();
        }
    }
}

5-2-2-2 summary

5-2-3 monitoring child nodes and themselves

5-2-3-1 create test Controller

RestController
@RequestMapping("/hanxi/watcher")
@Slf4j
public class WatcherController {

    private final String ZK_ADDRESS = "hdp-1:2181,hdp-2:2181,hdp-3:2181";
    private final String workerPath = "/test/listener/remoteNode";
    private final String subWorkerPath = "/test/listener/remoteNode/id-";

    /**
     * Monitor child nodes and themselves
     */
    @PostMapping("/watchChildAndOwn")
    public void watchChildAndOwn() throws Exception {
        // Check whether the node exists, and create if it does not exist
        CuratorFramework client = ClientFactory.createSimple(ZK_ADDRESS);
        client.start();

        Stat stat = client.checkExists().forPath(workerPath);
        if (null == stat) {
            String data = "hello";
            byte[] payload = data.getBytes("UTF-8");
            client.create()
                    .creatingParentContainersIfNeeded()
                    .withMode(CreateMode.PERSISTENT)
                    .forPath(workerPath, payload);
        }

        TreeCache treeCache = new TreeCache(client, workerPath);
        TreeCacheListener listener = new TreeCacheListener() {
            @Override
            public void childEvent(CuratorFramework client, TreeCacheEvent event) throws Exception {
                ChildData data = event.getData();
                if (null == data) {
                    log.info("Data is empty");
                    return;
                }
                switch (event.getType()) {
                    case NODE_ADDED:
                        log.info("[TreeCache]Nodes increase, path={}, data={}", data.getPath(), new String(data.getData(), "UTF-8"));
                        break;
                    case NODE_UPDATED:
                        log.info("Child node update, path={}, data={}", data.getPath(), new String(data.getData(), "UTF-8"));
                        break;
                    case NODE_REMOVED:
                        log.info("Child node deletion, path={}, data={}", data.getPath(), new String(data.getData(), "UTF-8"));
                        break;
                    default:
                        break;
                }
            }
        };
        // Start event listening
        treeCache.getListenable().addListener(listener);
        treeCache.start();
        Thread.sleep(1000);

        try {
            // Create 3 nodes
            for (int i = 1; i <= 3; i++) {
                String payload = "The first" + i + "Changes";
                client.create()
                        .creatingParentContainersIfNeeded()
                        .withMode(CreateMode.PERSISTENT)
                        .forPath(subWorkerPath + i, payload.getBytes(Charset.forName("UTF-8")));
            }
            Thread.sleep(1000);
            // Delete 3 nodes
            for (int i = 1; i <= 3; i++) {
                client.delete().forPath(subWorkerPath + i);
            }
        } catch (Exception e) {
            log.info("Failed to create listener, path={}", workerPath);
        } finally {
            client.close();
        }
    }
}

5-2-3-2 summary

5-3 locking nodes

5-3-1 implementation code

5-3-1-1 Lock

package com.hanxi.lock;

public interface Lock {
    /**
     * Locking method
     *
     * @return Successfully locked
     */
    boolean lock() throws Exception;

    /**
     * Unlocking method
     *
     * @return Successfully unlocked
     */
    boolean unlock();
}

5-3-1-2 ZkLock

package com.hanxi.lock;

import com.hanxi.idgenerator.ClientFactory;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.recipes.cache.ChildData;
import org.apache.curator.framework.recipes.cache.TreeCache;
import org.apache.curator.framework.recipes.cache.TreeCacheEvent;
import org.apache.curator.framework.recipes.cache.TreeCacheListener;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.data.Stat;
import org.springframework.util.StringUtils;

import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

@Slf4j
public class ZkLock implements Lock {

    private static final String ZK_PATH = "/test/lock";
    private static final String LOCK_PREFIX = ZK_PATH + "/";
    private static final long WAIT_TIME = 1000;
    private final String ZK_ADDRESS = "hdp-1:2181,hdp-2:2181,hdp-3:2181";
    CuratorFramework client = null;
    private String locked_short_path = null;
    private String locked_path = null;
    private String prior_path = null;
    final AtomicInteger lockCount = new AtomicInteger(0);
    private Thread thread;

    @SneakyThrows
    public ZkLock() {
        CuratorFramework client = ClientFactory.createSimple(ZK_ADDRESS);
        client.start();
        Stat stat = client.checkExists().forPath(ZK_PATH);
        if (null == stat) {
            String data = "hello";
            byte[] payload = data.getBytes("UTF-8");
            client.create()
                    .creatingParentContainersIfNeeded()
                    .withMode(CreateMode.EPHEMERAL)
                    .forPath(ZK_PATH, payload);
        }
        this.client = client;

    }

    @Override
    public boolean lock() {
        synchronized (this) {
            if (lockCount.get() == 0) {
                thread = Thread.currentThread();
                lockCount.incrementAndGet();
            } else {
                if (!thread.equals(Thread.currentThread())) {
                    return false;
                }
                lockCount.incrementAndGet();
                return true;
            }
        }

        try {
            boolean locked = false;
            //First try to lock it
            locked = tryLock();
            if (locked) {
                return true;
            }
            //If locking fails, wait
            while (!locked) {
                await();
                //Get the waiting child node list
                List<String> waiters = getWaiters();
            //Judge whether locking is successful
                if (checkLocked(waiters)) {
                    locked = true;
                }
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            unlock();
        }

        return false;
    }

    private void await() throws Exception {

        if (null == prior_path) {
            throw new Exception("prior_path error");
        }
        final CountDownLatch latch = new CountDownLatch(1);
        //Subscribe to the deletion events of nodes in smaller order than yourself
        Watcher w = new Watcher() {
            @Override
            public void process(WatchedEvent watchedEvent) {
                System.out.println("Monitored changes watchedEvent = " + watchedEvent);
                log.info("[WatchedEvent]Node deletion");

                latch.countDown();
            }
        };
        client.getData().usingWatcher(w).forPath(prior_path);
        //Subscribe to the deletion events of nodes in smaller order than yourself
      /*  TreeCache treeCache = new TreeCache(client, prior_path);
        TreeCacheListener l = new TreeCacheListener() {
            @Override
            public void childEvent(CuratorFramework client,
                                   TreeCacheEvent event) throws Exception {
                ChildData data = event.getData();
                if (data != null) {
                    switch (event.getType()) {
                        case NODE_REMOVED:
                            log.debug("[TreeCache]Node deletion, path={}, data = {} ",
                                    data.getPath(), data.getData());

                            latch.countDown();
                            break;
                        default:
                            break;
                    }
                }
            }
        };

        treeCache.getListenable().addListener(l);
        treeCache.start();*/
        latch.await(WAIT_TIME, TimeUnit.SECONDS);
    }

    @Override
    public boolean unlock() {
        //Only locked threads can be unlocked
        if (!thread.equals(Thread.currentThread())) {
            return false;
        }
        //Reduce reentrant count
        int newLockCount = lockCount.decrementAndGet();
        //Count cannot be less than 0
        if (newLockCount < 0) {
            throw new IllegalMonitorStateException("Lock count has gone negative for lock: " + locked_path);
        }
        //If the count is not 0, return directly
        if (newLockCount != 0) {
            return true;
        }
        //Delete temporary node
        try {
            if (Objects.nonNull(client.checkExists().forPath(locked_path))) {
                client.delete().forPath(locked_path);
            }
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }

    /**
     * Try locking
     * @return Whether locking succeeded
     * @throws Exception abnormal
     */
    private boolean tryLock() throws Exception {
        //Create temporary Znode
        String data = "hello son";
        byte[] payload = data.getBytes("UTF-8");
        locked_path = client.create()
                .creatingParentContainersIfNeeded()
                .withMode(CreateMode.EPHEMERAL_SEQUENTIAL)
                .forPath(LOCK_PREFIX, payload);
        //Then get all nodes
        List<String> waiters = getWaiters();
        if (StringUtils.isEmpty(locked_path)) {
            throw new Exception("zk error");
        }
        //Gets the queue number of the lock
        locked_short_path = getShortPath(locked_path);
        //Get the waiting child node list. Determine your location. If it is the first, lock it successfully.
        if (checkLocked(waiters)) {
            return true;
        }
        // Judge your rank
        int index = Collections.binarySearch(waiters, locked_short_path);
        if (index < 0) { // Due to network jitter, you may no longer have yourself in the obtained child node list
            throw new Exception("Node not found: " + locked_short_path);
        }
        //If you don't get the lock, listen to the previous node
        prior_path = ZK_PATH + "/" + waiters.get(index - 1);
        return false;
    }

    /**
     * Get all waiting nodes from zookeeper
     */
    protected List<String> getWaiters() {

        List<String> children = null;
        try {
            children = client.getChildren().forPath(ZK_PATH);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
        return children;
    }

    private String getShortPath(String locked_path) {

        int index = locked_path.lastIndexOf(ZK_PATH + "/");
        if (index >= 0) {
            index += ZK_PATH.length() + 1;
            return index <= locked_path.length() ? locked_path.substring(index) : "";
        }
        return null;
    }

    private boolean checkLocked(List<String> waiters) {

        //Nodes are numbered in ascending order
        Collections.sort(waiters);
        // If it is the first one, it means that you have obtained the lock
        if (locked_short_path.equals(waiters.get(0))) {
            log.info("Successful acquisition of distributed locks,Node is{}", locked_short_path);
            return true;
        }
        return false;
    }
}

5-3-1-3 LockController

package com.hanxi.controller;

import com.hanxi.lock.ZkLock;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/hanxi/lock")
@Slf4j
public class LockController {

    int count = 0;

    /**
     * Listen to the node itself
     */
    @PostMapping("/test")
    public void watch() throws Exception {
        ZkLock lock = new ZkLock();
        for (int i = 0; i < 10; i++) {
            final int temp = i;
            new Thread(() -> {
                lock.lock();
                for (int j = 0; j < 10; j++) {
                    count++;
                }
                log.info(Thread.currentThread().getName() + " : count = " + count);
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                lock.unlock();
            }, "zt" + temp).start();

        }

    }
}

5-3-1-4 summary

6. Internal principle of zookeeper

6-1 node type

Node type

  • Persistent: after the client and server are disconnected, the created node cannot be deleted
  • Short: after the client and server are disconnected, the created node is deleted by itself

Creating a znode is to set the sequence ID. a value will be appended to the znode name. The sequence number is a monotonically increasing counter maintained by the parent node

In the distributed system, the sequence number can be used to sort all times globally, so that the client infers the order of time through the sequence number.

6-1-1 durable

  • Persistent directory node

After the client disconnects from zookeeper, the node still exists

  • Persistent sequence number catalog node

After the client is disconnected from zookeeper, the node still exists, but zookeeper numbers the changed nodes sequentially

6-1-2 transient

  • Zero hour directory node

After the client disconnects from zookeeper, the node is deleted

  • Zero time sequence number node

After the client is disconnected from zookeeper, the node is deleted, but zookeeper numbers the node name sequentially.

6-2 stat structure

  • C zxid - create node transaction

Each time you modify the ZooKeeper state, you will receive a zxid form of timestamp, that is, the ZooKeeper transaction ID.
Transaction ID is the total order of all modifications in ZooKeeper. Each modification has a unique zxid. If zxid1 is less than zxid2, zxid1 occurs before zxid2.

  • CTime znode is a good description of the creation (since 1970)

  • Pzxid znode last updated child node zxid

  • Cversion - change number of znode child node, and modification times of znode child node

  • dataversion - znode data change number

  • Aclversion - change number of znode access control list

  • Ephemeral owner - if it is a temporary node, this is the session id of the znode owner. If it is not a temporary node, it is 0.

  • Datalength - the data length of znode

  • Numchildren - number of znode child nodes

6-3 listener principle

6-3-1 listener details

    1. First, there must be a main thread
    1. When you create a zookeeper client in the face thread, you will create two threads, one for network connection communication and the other for listener
    1. connect Xianchen to launch the registered listening time to zookeeper.
    1. In the registered listener list of zookeeper, the registered sub listener event is added to the list.
    1. When zookeeper listens to several data or paths, it will send this message to my listener thread.
    1. The process() method was called inside the listener thread.

6-3-2 common listeners

    1. Monitor changes in node data
get path[watch]
    1. Listen for changes in the increase or decrease of child nodes
ls path[watch]

6-4 Paxos algorithm

6-4-1 Paxos algorithm

Paxos The algorithm is a message passing Based Consistency Algorithm with high fault tolerance.
There are two models of node communication in distributed system: shared memory( Shared memory)And messaging( Messages passing). 
The distributed system based on message passing communication model will inevitably have the following errors: the process may be slow, killed or restarted, and the message can be
 Can delay, lose, repeat, on the basis Paxos In the scenario, the possible message tampering, that is, Byzantine error, is not considered. Paxos 
The problem solved by the algorithm is how to reach an agreement on a value in a distributed system where the above exceptions may occur, so as to ensure that no matter any of the above differences occur
 Often, it will not undermine the consistency of the resolution.

Paxos The algorithm is a message passing Based Consistency Algorithm with high fault tolerance.
There are two models of node communication in distributed system: shared memory( Shared memory)And messaging( Messages passing). 
The distributed system based on message passing communication model will inevitably encounter the following errors: the process may be slow, killed or restarted, and the message may
 Will delay, lose, repeat, on the basis Paxos In the scenario, the possible message tampering, that is, Byzantine error, is not considered. Paxos Algorithmic solution
 The problem to be solved is how to reach an agreement on a certain value in a distributed system where the above exceptions may occur, so as to ensure that no matter any of the above exceptions occur, it will not change
 It will undermine the consistency of the resolution.

6-4-1 Paxos algorithm flow description

Each message in Paxos algorithm flow is described as follows:

    1. Prepare: the proposer generates a globally unique and incremental Proposal ID (timestamp plus server ID can be used) and sends a prepare request to all Acceptors. There is no need to carry the proposal content here, just the Proposal ID.
    1. Promise: after receiving the Prepare request, acceptors will make "two promises and one response".
    • Two commitments:
      • a. Prepare requests with Proposal ID less than or equal to (Note: here is < =) the current request are no longer accepted.
      • b. Proposal requests whose Proposal ID is less than (Note: here is <) the current request are no longer accepted.
    • One response:
      • c. Without violating previous commitments, reply to the Value and Proposal ID of the proposal with the largest Proposal ID in the accepted proposal. If not, return a null Value.
    1. Proposal: after receiving the Promise response from most Acceptors, the proposer selects the Value of the proposal with the largest Proposal ID from the response as the proposal initiated this time. If the proposal values of all responses are null, you can decide the proposal Value at will. Then, carry the current Proposal ID and send a proposal request to all Acceptors.
    1. Accept: after receiving the proposal request, the acceptor accepts and persists the current Proposal ID and proposal Value without violating its previous commitments.
    1. Learn: after the proposer receives the acceptance of most Acceptors, the resolution is formed and sent to all Learners.

6-5 election mechanism

  • 1) Half mechanism: more than half of the machines in the cluster survive and the cluster is available. Therefore, Zookeeper is suitable for installing an odd number of servers.

  • 2) Although Zookeeper does not specify Master and Slave in the configuration file, when Zookeeper works, one node is Leader and the other is Follower, and the Leader is temporarily generated through the internal election mechanism.

  • 3) A simple example is given to illustrate the whole election process.
    Suppose that there is a Zookeeper cluster composed of five servers with IDS ranging from 1 to 5. At the same time, they are all newly started, that is, they have no historical data. In terms of the amount of data stored, they are the same. Suppose that these servers are started in order to see what will happen,

    • (1) Server 1 starts up and initiates an election. Server 1 has one vote for itself. At this time, server 1 has one vote, less than half (3 votes), the election cannot be completed, and the status of server 1 remains LOOKING;
    • (2) Server 2 starts up and initiates another election. Servers 1 and 2 vote for themselves and exchange vote information: at this time, server 1 finds that the ID of server 2 is higher than that of server 1 (server 1) Large, change the vote to recommend server 2. At this time, server 1 has 0 votes and server 2 has 2 votes. Without more than half of the results, the election cannot be completed, and the status of server 1 and 2 remains LOOKING
    • (3) Server 3 starts and initiates an election. At this time, both servers 1 and 2 will change the votes to server 3. The voting results: server 1 has 0 votes, server 2 has 0 votes, and server 3 has 3 votes. At this time, server 3 has more than half of the votes, and server 3 is elected Leader. The status of server 1 and 2 is changed to FOLLOWING, and the status of server 3 is changed to LEADING;
    • (4) Server 4 starts and initiates an election. At this time, servers 1, 2 and 3 are no longer in the voting state and will not change the ballot information. The result of ballot information exchange: server 3 has 3 votes and server 4 has 1 vote. At this time, server 4 obeys the majority, changes the ballot information to server 3 and changes the state to FOLLOWING;
    • (5) Server 5 starts, just like 4.
    1. Defects of Paxos algorithm: in the case of complex network, a distributed system using Paxos algorithm may not converge for a long time, or even fall into live lock

6-6 data writing process

---------------

  1. The client wants to write data on ZooKeeper's serverl and send a write request.

  2. If server1 is not a Leader, serverl will forward the received request to the Leader in one step, because there is a Leader in each ZooKeeper server.
    This Leader will broadcast the write request to each server, such as serverl and server2. Each server will add the learning request to the write queue and send a success message to the Leaade.

  3. When the Leader receives the success information from more than half of the servers, it indicates that the write operation can be performed. The Leader will send the submission information to each server. After receiving the information, each server will implement the write request in the queue. At this time, the write is successful.

  4. server1 will further notify the Client that the data is written successfully, and then the entire write operation of the task is successful.

7 understand the role of Zookeeper in Kafka

7-1 Broker registration

Broker It is distributed and independent of each other, but a registration system is required to be able to integrate the data in the whole cluster Broker Manage it,
This is used Zookeeper. stay Zookeeper There will be one dedicated to Broker Nodes recorded in server list:

/brokers/ids

each Broker At startup, it will arrive Zookeeper Register on, i.e/brokers/ids Create your own node under, such as/brokers
/ids/[0...N]. 

Kafka Globally unique numbers are used to refer to each Broker Server, different Broker Different must be used Broker ID Register,
After creating nodes, each Broker Will put their own IP The address and port information are recorded in the node. Among them, Broker Created node class
 Type is a temporary node, once Broker In case of downtime, the corresponding temporary node will also be deleted automatically.

7-2 Topic registration

stay Kafka In, the same Topic Messages are divided into multiple partitions and distributed across multiple domains Broker On, these partition information and Broker Yes
 Correspondence is also caused by Zookeeper During maintenance, special nodes are used to record, such as:

/borkers/topics

Kafka Each Topic Will be/brokers/topics/[topic]The form is recorded, such as/brokers/topics/login and/brokers
/topics/search Wait. Broker After the server is started, the corresponding Topic Node(/brokers/topics)Register your own on Broker 
ID And write to the Topic Total number of partitions, such as/brokers/topics/login/3->2,This node represents Broker ID One for 3
Broker Server, for"login"this Topic Two partitions are provided for message storage. Similarly, this partition node is also a temporary node.

7-3 producer load balancing

Because of the same Topic Messages are partitioned and distributed across multiple Broker Therefore, producers need to send messages to these distributed servers reasonably
 of Broker So how to realize the load balancing of producers, Kafka It supports traditional four-tier load balancing and Zookeeper Way to achieve negative
 Load balancing.

(1) Four layer load balancing, according to the producer's IP Address and port to determine an associated Broker. Usually, a producer only corresponds to
 single Broker,Then all messages generated by the producer are sent to the producer Broker. In this way, the logic is simple, and each producer does not need to build with other systems
 Set up additional TCP Connect, just and Broker Maintain single TCP However, it can not achieve real load balancing because of the actual system
 The amount of messages generated by each producer in the Broker The message storage capacity of is different, if some producers produce far more messages than their producers
 If he is a producer, it will lead to different results Broker The total number of messages received varies greatly, and producers cannot perceive it in real time Broker
 Add and delete.

(2) use Zookeeper Load balancing due to each Broker When started, it will be completed Broker During the registration process, the producer will pass through this node
 Changes are dynamically perceived Broker Change the server list, so as to realize the dynamic load balancing mechanism.

7-4 consumer load balancing

Similar to producers, Kafka Consumers also need load balancing to realize that multiple consumers reasonably from the corresponding Broker Receive on server
 Message. Each consumer group contains several consumers. Each message will be sent to only one consumer in the group. Different consumer groups consume from
 Specific Topic The following messages do not interfere with each other.

7-5 relationship between districts and consumers

Consumer group (Consumer Group): 
consumer group There are multiple Consumer(Consumer).
For each consumer group (Consumer Group),Kafka Will be assigned a globally unique Group ID,Group All internal
 Consumers share this ID. Subscribed topic Each partition under can only be assigned to one group Next consumer(Of course, the partition is OK
 Assigned to other group). 
At the same time, Kafka Assign one to each consumer Consumer ID,Usually used"Hostname:UUID"Formal representation.

stay Kafka It stipulates that each message partition can only be consumed by one consumer in the same group. Therefore, it is necessary to Zookeeper Upper record cancellation
 Information partition and Consumer Once each consumer has determined the consumption power of a message partition, it needs to change it Consumer 
ID Write to Zookeeper On the temporary node of the corresponding message partition, for example:

/consumers/[group_id]/owners/[topic]/[broker_id-partition_id]

Among them,[broker_id-partition_id]It is the identification of a message partition, and the node content is the content of consumers in the message partition
Consumer ID. 

7-6 message consumption progress Offset record

In the process of message consumption by consumers on the specified message partition, the consumption progress of partition messages needs to be updated regularly Offset Record to Zookeeper
 So that after the consumer restarts or other consumers take over the message consumption of the message partition again, it can continue from the previous progress
 Message consumption. Offset stay Zookeeper Is recorded by a special node whose node path is:

/consumers/[group_id]/offsets/[topic]/[broker_id-partition_id]

Node content is Offset Value of.

7-7 consumer registration

The steps for the consumer server to join the consumer group at initialization startup are as follows

Register with the consumer group. When each consumer server starts, it will Zookeeper Create your own consumer section under the specified node of
 Points, for example/consumers/[group_id]/ids/[consumer_id],After the node is created, the consumer will subscribe to it Topic
 Information is written to the temporary node.

Register and listen to the changes of consumers in the consumer group. Each consumer needs to pay attention to other consumer services in their consumer group
 The change of the device, i.e/consumers/[group_id]/ids Changes in node registration child nodes Watcher Monitoring, once a new consumer is found
 Increase or decrease will trigger the load balancing of consumers.

yes Broker Server change registration listening. Consumers need to/broker/ids/[0-N]Listen to the node in. If it is found Broker service
 If the list of devices changes, it is necessary to decide whether consumer load balancing is required according to the specific situation.

Consumer load balancing. To make the same Topic Messages in different partitions are consumed by multiple consumers as evenly as possible 
The process of message partition allocation. Generally, for a consumer group, if the consumer server in the group changes or Broker The server
 When a change occurs, a consumer load balancing is issued.

Topics: Big Data Zookeeper Distribution Cloud Native