Source code for this article: GitHub. Click here || GitEE. Click here
1. Introduction to Zookeeper Foundation
1. Introduction to concepts
Zookeeper is an Apache open source, distributed application that provides a coordinated service for the system architecture.Viewed from the design mode perspective, this component is a framework based on the observer mode design, responsible for storing and managing data, accepting observer registration. Once the status of the data changes, Zookeeper will be responsible for notifying observers already registered on Zookeeper to respond accordingly, thus implementing a Master/Slave-like management mode in the cluster.ZooKeeper's goal is to encapsulate complex and error-prone critical services, providing users with easy-to-use interfaces and efficient, functionally stable systems.
2. Basic Theory
- data structure
ZooKeeper records data in a structure similar to that of the Linux file system, which can be viewed as a tree, with each node called ZNode.Each Znode can store 1MB of data by default, and each ZNode can be uniquely identified by its path.
- Node type
ephemeral: The created node is automatically deleted when the client and server are disconnected. persistent: A node created after the client and server are disconnected persists.
- Cluster Services
Cluster services in Zookeeper are clusters of one leader and many follower s.Leaders are responsible for voting initiation and resolution, updating cluster service status.Followers are used to receive customer requests and return results to the client to vote during the Leader selection process.As long as more than half of the nodes in the cluster survive, the Zookeeper cluster will function properly.
- Data Consistency
Each server keeps a copy of the same data, and the data that the client requests to be processed by any server in the cluster is consistent.
3. Application Scenarios
- Classic applications: service registration and discovery of the Dubbo framework;
- Distributed message synchronization and coordination mechanism;
- Server nodes dynamically go up and down;
- Unified configuration management, load balancing, cluster management;
2. Safety Management Operations
1. Operational privileges
ZooKeeper's nodes have five operating privileges: CREATE, READ, WRITE, DELETE, ADMIN and other related privileges, which can be abbreviated as crwda with the first character of each word stitched together.
2. Authentication methods:
- world
By default, open access means that the world is free to access.
- auth
Authorized and certified users are only accessible.
- digest
User name: Password authentication, the most common method in the actual business development.
- IP Whitelist
Authorizes the specified Ip address and the specified permission point to control access.
3. Digest authorization process
- Add Authenticated User
addauth digest username: password
- Set permissions
SetAcl/path auth: User name: Password: Permissions
- View Acl Settings
getAcl /path
- Complete operation flow
-- Add Authorized User [zk: localhost:2181] addauth digest smile:123456 -- Create Node [zk: localhost:2181] create /cicada cicada -- Node Authorization [zk: localhost:2181] setAcl /cicada auth:smile:123456:cdrwa -- View Authorization [zk: localhost:2181] getAcl /cicada
3. Integrating SpringBoot2 Framework
1. Core Dependency
Curator is a component of Apache's open source Zookeeper client connections and operations, and the Curator framework wraps twice on Zookeeper's native API interface.Provides various scenarios for ZooKeeper applications such as distributed lock services, cluster leadership elections, shared counters, caching mechanisms, distributed queues, and other API encapsulations.
<dependency> <groupId>org.apache.curator</groupId> <artifactId>curator-framework</artifactId> <version>2.12.0</version> </dependency> <dependency> <groupId>org.apache.curator</groupId> <artifactId>curator-recipes</artifactId> <version>2.12.0</version> </dependency> <dependency> <groupId>org.apache.curator</groupId> <artifactId>curator-client</artifactId> <version>2.12.0</version> </dependency>
2. Zookeeper parameters
zoo: keeper: #Open Sign enabled: true #server address server: 127.0.0.1:2181 #Namespace, called ZNode namespace: cicada #Permission Control, Encryption digest: smile:123456 #Session Timeout sessionTimeoutMs: 3000 #Connection timeout connectionTimeoutMs: 60000 #max retries maxRetries: 2 #Initial Sleep Time baseSleepTimeMs: 1000
3. Service Initialization Configuration
@Configuration public class ZookeeperConfig { private static final Logger LOGGER = LoggerFactory.getLogger(ZookeeperConfig.class) ; @Resource private ZookeeperParam zookeeperParam ; private static CuratorFramework client = null ; /** * Initialization */ @PostConstruct public void init (){ //Retry policy, 1 second initial, 10 retries RetryPolicy policy = new ExponentialBackoffRetry( zookeeperParam.getBaseSleepTimeMs(), zookeeperParam.getMaxRetries()); //Create Curator from Factory client = CuratorFrameworkFactory.builder() .connectString(zookeeperParam.getServer()) .authorization("digest",zookeeperParam.getDigest().getBytes()) .connectionTimeoutMs(zookeeperParam.getConnectionTimeoutMs()) .sessionTimeoutMs(zookeeperParam.getSessionTimeoutMs()) .retryPolicy(policy).build(); //Open Connection client.start(); LOGGER.info("zookeeper Initialization complete..."); } public static CuratorFramework getClient (){ return client ; } public static void closeClient (){ if (client != null){ client.close(); } } }
4. Packaging Series Interfaces
public interface ZookeeperService { /** * Determine whether a node exists */ boolean isExistNode (final String path) ; /** * Create Node */ void createNode (CreateMode mode,String path ) ; /** * Set Node Data */ void setNodeData (String path, String nodeData) ; /** * Create Node */ void createNodeAndData (CreateMode mode, String path , String nodeData) ; /** * Get node data */ String getNodeData (String path) ; /** * Get data under nodes */ List<String> getNodeChild (String path) ; /** * Whether to recursively delete nodes */ void deleteNode (String path,Boolean recursive) ; /** * Acquire read-write locks */ InterProcessReadWriteLock getReadWriteLock (String path) ; }
5. Interface implementation
@Service public class ZookeeperServiceImpl implements ZookeeperService { private static final Logger LOGGER = LoggerFactory.getLogger(ZookeeperServiceImpl.class); @Override public boolean isExistNode(String path) { CuratorFramework client = ZookeeperConfig.getClient(); client.sync() ; try { Stat stat = client.checkExists().forPath(path); return client.checkExists().forPath(path) != null; } catch (Exception e) { LOGGER.error("isExistNode error...", e); e.printStackTrace(); } return false; } @Override public void createNode(CreateMode mode, String path) { CuratorFramework client = ZookeeperConfig.getClient() ; try { // Recursively create the required parent node client.create().creatingParentsIfNeeded().withMode(mode).forPath(path); } catch (Exception e) { LOGGER.error("createNode error...", e); e.printStackTrace(); } } @Override public void setNodeData(String path, String nodeData) { CuratorFramework client = ZookeeperConfig.getClient() ; try { // Set Node Data client.setData().forPath(path, nodeData.getBytes("UTF-8")); } catch (Exception e) { LOGGER.error("setNodeData error...", e); e.printStackTrace(); } } @Override public void createNodeAndData(CreateMode mode, String path, String nodeData) { CuratorFramework client = ZookeeperConfig.getClient() ; try { // Create nodes, associate data client.create().creatingParentsIfNeeded().withMode(mode) .forPath(path,nodeData.getBytes("UTF-8")); } catch (Exception e) { LOGGER.error("createNode error...", e); e.printStackTrace(); } } @Override public String getNodeData(String path) { CuratorFramework client = ZookeeperConfig.getClient() ; try { // Data Read and Convert byte[] dataByte = client.getData().forPath(path) ; String data = new String(dataByte,"UTF-8") ; if (StringUtils.isNotEmpty(data)){ return data ; } }catch (Exception e) { LOGGER.error("getNodeData error...", e); e.printStackTrace(); } return null; } @Override public List<String> getNodeChild(String path) { CuratorFramework client = ZookeeperConfig.getClient() ; List<String> nodeChildDataList = new ArrayList<>(); try { // Dataset under node nodeChildDataList = client.getChildren().forPath(path); } catch (Exception e) { LOGGER.error("getNodeChild error...", e); e.printStackTrace(); } return nodeChildDataList; } @Override public void deleteNode(String path, Boolean recursive) { CuratorFramework client = ZookeeperConfig.getClient() ; try { if(recursive) { // Delete nodes recursively client.delete().guaranteed().deletingChildrenIfNeeded().forPath(path); } else { // Delete a single node client.delete().guaranteed().forPath(path); } } catch (Exception e) { LOGGER.error("deleteNode error...", e); e.printStackTrace(); } } @Override public InterProcessReadWriteLock getReadWriteLock(String path) { CuratorFramework client = ZookeeperConfig.getClient() ; // Write Lock Mutual Exclusion, Read Write Mutual Exclusion InterProcessReadWriteLock readWriteLock = new InterProcessReadWriteLock(client, path); return readWriteLock ; } }
6. Based on Swagger2 interface
@Api("Zookeeper Interface Management") @RestController public class ZookeeperApi { @Resource private ZookeeperService zookeeperService ; @ApiOperation(value="Query node data") @GetMapping("/getNodeData") public String getNodeData (String path) { return zookeeperService.getNodeData(path) ; } @ApiOperation(value="Determine whether a node exists") @GetMapping("/isExistNode") public boolean isExistNode (final String path){ return zookeeperService.isExistNode(path) ; } @ApiOperation(value="Create Node") @GetMapping("/createNode") public String createNode (CreateMode mode, String path ){ zookeeperService.createNode(mode,path) ; return "success" ; } @ApiOperation(value="Set Node Data") @GetMapping("/setNodeData") public String setNodeData (String path, String nodeData) { zookeeperService.setNodeData(path,nodeData) ; return "success" ; } @ApiOperation(value="Create and set node data") @GetMapping("/createNodeAndData") public String createNodeAndData (CreateMode mode, String path , String nodeData){ zookeeperService.createNodeAndData(mode,path,nodeData) ; return "success" ; } @ApiOperation(value="Recursively get node data") @GetMapping("/getNodeChild") public List<String> getNodeChild (String path) { return zookeeperService.getNodeChild(path) ; } @ApiOperation(value="Whether to recursively delete nodes") @GetMapping("/deleteNode") public String deleteNode (String path,Boolean recursive) { zookeeperService.deleteNode(path,recursive) ; return "success" ; } }
4. Source code address
GitHub·address https://github.com/cicadasmile/middle-ware-parent GitEE·address https://gitee.com/cicadasmile/middle-ware-parent