[TOC]
Zookeeper Animal administrator global control. Provides services such as configuration management and service discovery. It can itself be clustered. The implementation is based on the observer pattern. Don’t want eureka/ Consul to need a heartbeat mechanism. He himself supports observation and active triggering; A journey of a thousand miles begins with a single step. We have already explored middleware registered with Eureka and Consul. Today we continue learning about another service registered as a service.
This article will explain the installation of ZooKeeper from a single zooKeeper to a cluster. From the cluster leader election mechanism explained and data synchronization combed. To the final configuration management and distributed lock application based on ZooKeeper implementation. From point to surface to app take you on a roller coaster ride
Introduction to the
- Zookeeper is an animal keeper. His role in the big data family is also management. Let’s take a look at the beauty of ZK from installation to use
centralized
service | The characteristics of | centralized | CAP |
---|---|---|---|
eureka | Peer to peer By default, each Eureka service registers and removes information from other servers in the cluster | decentralized | AP |
consul | Virus spread to the entire cluster through its nodes | More centralized | CP |
zookeeper | A leader with multiple followes | centralized | CP |
The transaction
-
As mentioned above, Zookeeper is a leader with multiple followers.
-
In addition to centralization, another important feature of ZooKeeper is transactions. Zookeeper data operations are atomic.
-
Zookeeper transactions are internally transacted through version management data. Each ZooKeeper client initializes an operation. Each client connection has an internal session management. The same session operation will have the corresponding version record, so that the zxID can ensure a consistency of data.
downlaod
zookeeper3.5.9
Single machine installation
- Download it from the address above and unzip it
Tar ZXVF - apache - they are - 3.5.9 - bin. Tar. Gz
- The official equivalent is a template, this time direct start will report the error.
- The default zoo. CFG configuration file is missing according to the error message. The zoo_sample. CFG template configuration file is provided in the conf directory. All we need to do is copy the file to zoo.cfg and fix it based on that
cp zoo_sample.cfg zoo.cfg
- Let’s change the data path and start.
- After the zooKeeper is started, run the ‘zkServer.sh status’ command to check the ZooKeeper running status. We can see that it is now in single-machine mode.
- Through JPS we can also see that ZooKeeper started successfully.
The cluster structures,
-
The cluster here demonstrates the pseudo-cluster version for convenience. That is, deploy three ZK services on one server.
-
Mkdir {zk1,zk2,zk3}, first create zk1,zk2,zk3 folder store Zk
-
Copy the previously unzipped ZK folders into each of the three created ZKS
- In a ZooKeeper group, each service must have a number. We also need to write the number of each machine
- Then we repeat the process for our standalone version. Create a data folder in the root directory and modify the corresponding data configuration in the CONF. We just need to change the port number here. Different port numbers are required because they are on the same machine.
- Finally, internal communication ports of the cluster are added
Server. 1 = 192.168.44.130:28881-38881 for server 2 = 192.168.44.130:28882:38882 server. 3 = 192.168.44.130:28883-38883Copy the code
- As long as the above port is guaranteed to be available.
-
Above is the configuration of ZK1, other readers to configure.
-
In the configuration total we have more server configuration. This server is the focus of the cluster configuration
Server. 1 = 192.168.44.139:28881-38881
- Server is the fixed notation
- 1.1:1 is the number in myID written by each ZK service before us
- 192.168.44.130: indicates the service IP address of zK
- 28881: data backup communication port between the Leader and Follewers in the ZooKeeper cluster
- 38881: Port of the election mechanism
- Above I started different configuration files through zkServer. You can also launch them separately under different ZK packages. The end result is the same. After the startup is complete, we can see three more ZK services through JPS. In the standalone version of JPS we know that zK’s main boot is QuorumPeerMain.
-
The figure above shows the directory structure of one of the ZK services. We can see that data is generated in the data directory. This is the file generated after the ZK cluster is started.
-
Cluster startup is complete. But we still don’t seem to have much awareness of the ZK cluster. For example, we don’t know who the leader is. You can run the following command to view the role of each ZK
- Our ZK2 is the leader role. The other is the follower
Cli connection
- Zkcli. sh is the zK client in the ZooKeeper package. Through it, we can connect to the ZooKeeper service and perform operations.
Zkcli. sh -server 192.168.44.131:1181 Can connect to the ZK service
- Let’s test whether the operation on ZK will be clustered.
-
We zkCli connected to zk1 service 1181 and created a ZK node named Node. We can also see this node node on the zk2 service.
-
So far, our ZooKeeper cluster has been built and the test has passed.
The cluster tolerance
Master the election
- We have taken the above cluster startup as an example to briefly describe the cluster election process.
(1) When ZK1 is started, only one service is Zk1 in the cluster. At this point, zK1’s vote for the cluster is naturally obtained by Zk1 itself. At this time, Zk1 has one vote. When ZK2 starts, both Zk1 and ZK2 will give one vote to the cluster. Since zk1(myID) is less than Zk2 (myID) in the group, these two votes are taken by Zk2. How did Zk2 get it here? Each ZooKeeper node has a coordinate zk=(myID, zxID); Myid is unique to each ZK service configuration. Zxid is a 64-bit component of the ZK service. The high 32 no master election increments once and clears the low 32 bits simultaneously. The lower 32 bits are incremented each time a data transaction occurs. Therefore, the highest ZXID indicates the newer zK service data. 3. After ZK2 gets two votes, it has obtained more than half of the votes of the cluster. At this time, zK2 is the quasi-leader and Zk1 switches to the following. When ZK3 starts, zK3 should receive three votes. But because Zk1 has lined up with ZK2. It is impossible for ZK2 to vote for ZK3 as a quasi-leader. Therefore, ZK3 has only one vote at most, and ZK3 knows that ZK2 has more than half, which is already the return of public opinion. Therefore, ZK3 cast its vote to ZK2 for its own future.
- The voting mechanism of Zookeeper is simply bureaucratic. Full of hearts
The leader is down and re-elects
-
In fact, there is a PK logic in the initial stage of ZK2 to get two votes. The above initial stage of voting is an abstract understanding of the individual.
-
To say above that those with a high myID will not vote for those with a low myID is actually a partial understanding. In fact, there will be a vote. After the vote, two votes will be PK, and the vote with the highest weight will be cast to elect the leader. There are cluster managers who do statistical voting and counting.
-
Here’s a look at the logic of a new election. It is also the logic of real leader election.
Zk1 and zk3 immediately switch to the looking state and vote for other services in the cluster. (1,0), (3,0) Zk1 will consider these two tickets, based on the algorithm num=10*zxid+myid mentioned, so zk1 will put the ticket (3,0) into the counting box ③. Zk3 receives two kinds of tickets (3,0) and (1,0), and will also put the ticket (3,0) into the counting box ④. Finally, zk3 wins by two votes.
- The elections above are the real elections. At the beginning we just added our own understanding to it. After the election, the service switches to the leader and follower states to work
Data synchronization
- Again, figure above
- If the client sends the data change request to the leader, it sends the proposal request from step 3 in the figure and waits for the half-way mechanism before sending the commit proposal. Followers will start updating their local ZXID and synchronizing their data.
- If the client sends a follower, the follower must first forward the request to the leader and then repeat the above steps.
- To ensure data consistency during data synchronization. All proposals sent by the leader are orderly. The data changes performed by followers are also sequential. This ensures final consistency of data.
For a period of time let’s say you need to operate on variables a=5 and 1=1. If a=5 and a=1 are two things. If the leader notifies followers to synchronize, zk1 first a=1 and then a=5. Then, a in Zk1 is 5. Zk3 is conversely, a in Zk3 is 1. This will result in inconsistencies. However, ZooKeeper ensures orderly consumption of follower data through orderly arrangement of ZNodes. When Zk1 executes a=5 at mo yi, the client checks that THE A of Zk1 is 5. Although the data appears to be dirty, it actually indicates that Zk1 has not been executed. Wait for Zk1 to finish execution a=1. This is called final data consistency.
- The next image is perhaps even more graphic, from the Internet
features
Service governance
- Springcloud registration details are covered in our eureka, consul section. We’re going to do the same thing today. The payment and Order modules have registered the service with ZooKeeper. Look at the effect.
<! -- SpringBoot with ZooKeeper -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zookeeper-discovery</artifactId>
</dependency>
Copy the code
- Configuration file Adding ZooKeeper
Spring: cloud: Zookeeper: connect-string: 192.168.44.131:2181Copy the code
- As in Consul, the registration here registers the value spring.application.name. Eureka registers the uppercase name of Spring.application. name. This affects the address difference called in the order order.
Click me to see the source code
- It’s the same operation. After order and two Payments are started, we call
http://localhost/order/getpayment/123
You can see that the result is load balancing.
Configuration management
- As anyone familiar with springcloud knows, it has a configuration center. Git updates the configuration in real time. The details will be covered in later sections, but this time we show how to implement configuration center management using ZooKeeper.
- First we continued development in our Payment module, introducing the Zookeeper-Config module
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zookeeper-config</artifactId>
</dependency>
Copy the code
- The bootstrap file is loaded first and then the Application file is loaded in spring. For bootstrap, we also use yML files.
spring:
application:
name: cloud-payment-service
profiles:
active: dev
cloud:
zookeeper:
connect-string: 192.16844.131.: 2181
config:
enabled: true
root: config
profileSeparator: ', '
discovery:
enabled: true
enabled: true
Copy the code
- This part needs some explanation
key | explain |
---|---|
spring.application.name | The service name |
spring.profiles | The environment of |
spring.cloud.enabled | Used to enable automatic Config configuration |
spring.cloud.zookeeper.config.root | Zookeeper root |
spring.cloud.zookeeper.profilSeparator | The key delimiter |
@Component
@ConfigurationProperties(prefix = "spring.datasources")
@Data
@RefreshScope
public class Db {
private String url;
}
Copy the code
- The system reads the value of the spring.datasources.url property in the configuration file. Combine it with our bootstrap.yml file. At this point to zookeeper system find/config/cloud – payment – service, dev/spring. The datasources. Url this value.
– About how the Zookeeper key came about. A closer look will reveal his pattern
-
/${spring.cloud.zookeeper.root}/${spring.application.name}${spring.cloud.zookeeper.profileSeparator}${spring.profiles}/$ {actual key}
-
The only thing you notice is that you need to add @refreshScope on the class, which cloud provides. This annotation is indispensable to the following config center
-
In this case, connect to the ZK service through the zkCli mentioned above, and then create the corresponding node. The ZooKeeper service needs to be created layer by layer. Such as the above mentioned/config/cloud – payment – services/spring. The datasources. Url, we need to create/config and then create /config/cloud-payment-services to create the final content.
-
We can create content in ZK ahead of time. Then the localhost: 8001 / payment/getUrl access to content. Then through the set/config/cloud – payment – services/spring. The datasources. Url helloworld in can see the latest helloworld refresh interface. There’s no demo here.
-
Zookeeper’s native create command is cumbersome because it needs to be created layer by layer. And we have zkui. This provides a visual operation of ZooKeeper. We also support file import. For the above configuration, you only need to import the following files
/config/cloud-payment-services=spring.datasources.url=hello
Copy the code
Zkui is installed and used
- We mentioned a tool above
zkui
As the name implies, it is the ZooKeeper visualization tool. We’ll just download itMaking the source code.
- The installation of the official website is also easy because it is a JAR service.
- Execute Maven Clean Install to package the JAR at the poM level and then
Nohup java-jar zkui-2.0-snapshot-jar-with-dependencies. Jar &
Just start in the background. The default port is 9090 - The default username and password were given to the official website. admin:manager
- The ZooKeeper configuration template is provided on the official website of the jar package. Inside we can configure our ZooKeeper. If it is a cluster, configure multiple.
-
There is not much to say about the use of zKUI, just a visualization. The necessary skills of a programmer should be used.
-
In our project, we used stand-alone ZooKeeper, but we also had cluster ZooKeeper when we installed it. The ports are 1181,1182,1183 respectively. We can configure the cluster in the configuration file config.cfg of zkui.
A distributed lock
Distributed locks are commonly used to acquire shared resources. In distributed systems we need to coordinate the scheduling of each service. If not controlled, resources will be wasted or even overflow to a large extent. A common one is our inventory.
- Previously we had one Order and two Payment services in SpringCloud. Payment is mainly used to make payments. If the order is successful, payment will be called to deduct the payment. In this case, the amount is equivalent to resources. This resource is mutually exclusive for both payment services. The two Payments must be executed in sequence.
Mysql Isolation Control
- In the old days when distribution was not very common, we normally handled these operations by ending the transaction isolation level of the database.
Isolation level | Isolation level | The phenomenon of |
---|---|---|
read uncommit | Read uncommitted | Produce dirty read |
read commited | Reading has been submitted | Phantom read (INSERT, DELETE), unrepeatable read (update) |
repeatable read | Repeatable degrees | Phantom read |
serializable | serialization | No problems, slow efficiency |
- Based on the mysql isolation level we can set the database to serial mode. The problem is that it is slow and all SQL execution is sequential.
Mysql lock
- The isolation levels are acceptable but the problems are unacceptable. The mysql lock is derived. We can create a separate table with data that represents success. Otherwise, the lock fails. In this way, when we operate the amount deduction, we first determine whether this table has data locked. However, if it is locked, it will cause deadlock. Because the program is abnormal and slow to release the lock will cause program paralysis.
- At this point we can clear the lock on a regular task. This at least ensures that other threads are available.
Redis lock
- Because Redis itself has invalidation properties, we don’t have to worry about deadlocks. And Redis is a much faster memory operation than mysql. For details on how to implement redis locks, see my other article Redis Distributed Locks.
They are locked
- Because ZooKeeper is based on the observer mode, we can monitor the corresponding value when the lock fails until we carry out our operation, which can ensure that we orderly process the business, so as to realize the lock function.
- Above is a simple illustration of two threads locked. Implementing distributed locks in ZooKeeper relies heavily on
CuratorFramework
,InterProcessMutex
Two classes
CuratorFramework client = CuratorFrameworkFactory.newClient("192.168.44.131:2181".new ExponentialBackoffRetry(1000.3));
client.start();
InterProcessMutex mutex = new InterProcessMutex(client, "/config/test");
long s = System.currentTimeMillis();
boolean acquire = mutex.acquire(100, TimeUnit.SECONDS);
if (acquire) {
long e = System.currentTimeMillis();
System.out.println(e - s+"@@@ms");
System.out.println("lock success....");
}
Copy the code
- Finally InterProcessMutex realizes locking. Locking adds a new key with a number to the specified key. If the number in the thread is the same as the minimum set number in /config/test, the lock is successful. If T2 fails to lock, the listener will be added to the key of the previous serial number. That is, when 00001 fails, T2 corresponding to 00002 will acquire the lock. This keeps the queue in order.