SpringBoot2 integrates Zookeeper components to manage service coordination in the architecture

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

Keywords: Programming Zookeeper Apache github Linux

Added by mesz on Fri, 10 Jan 2020 02:01:38 +0200