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.
-
- 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.
-
- 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.
-
- 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
-
- First, there must be a main thread
-
- 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
-
- connect Xianchen to launch the registered listening time to zookeeper.
-
- In the registered listener list of zookeeper, the registered sub listener event is added to the list.
-
- When zookeeper listens to several data or paths, it will send this message to my listener thread.
-
- The process() method was called inside the listener thread.
6-3-2 common listeners
-
- Monitor changes in node data
get path[watch]
-
- 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:
-
- 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.
-
- 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.
-
- 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.
-
- Accept: after receiving the proposal request, the acceptor accepts and persists the current Proposal ID and proposal Value without violating its previous commitments.
-
- 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.
-
- 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
---------------
-
The client wants to write data on ZooKeeper's serverl and send a write request.
-
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. -
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.
-
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.