springBoot integrated zookeeper, and achieve common api Distributed Lock

table of Contents

First, install the zookeeper

1. Download

2. Create a configuration file zoo.cfg

3. Start the server

4. Data structures and the basic command

Second, the integrated SpringBoot common api and implementation of distributed lock

1.Curator of pom-dependent

2.JAVA profile

3.Curator common api

4. Distributed Lock

5.AOP achieve Distributed Lock


 

First, install the zookeeper

1. Download

Official Web site: https://zookeeper.apache.org/

Domestic Mirror Address: https://mirrors.tuna.tsinghua.edu.cn/apache/zookeeper/

Download the 3.5.5 version of this article

2. Create a configuration file zoo.cfg

zookeeper just extract can be used before starting to enter the conf directory, create a file named zoo.cfg, reads as follows:

tickTime=2000 
dataDir= .. /data 
clientPort=2181
Note:
    tickTime heartbeat time, the default is 2 seconds. It refers to a client in accordance with the predetermined frequency sent heartbeat packet to the server to maintain a network socket connection;
    dataDir is zookepeer save memory snapshots, and transaction logging.
    clientPort refers to the port, and zookepeer client connection start port.
 

3. Start the server

Go to the bin directory, run zkServer:

./zkServer.sh start
Run the client run zkCli
./bin/zkCli.sh

4. Data structures and the basic command

Name (namespace) zookeeper provides a similar file system, each node is represented by a path, except that the node may contain certain data (2MB bytes), these nodes can be used to store business information, such as configuration information Wait.

4.1 View directory: ls [-s] [-w] [-R] path

 ls /

4.2 Creating nodes: create [-s] [-e] [-c] [-t ttl] path [data] [acl]

-e temporary node

-s have a serial number of the node

For example, to create a temporary test at node / nodes, the node data for the data set

create -e /test data

4.3 Get the node data: get [-s] [-w] path

-s details

-w Set watched listening

get -s -w /test
Note: watch operation, LS commands and get commands so can increase a  watch operation, node change time of waiting will notify the client. After the notification is complete, we need to call again ls or get to prison Xin this node change.
 
4.4 Data set node: set [-s] [-v version] path data
 
 set -s /test lvjie

4.5 Delete node: delete [-v version] path

delete /test

Second, the integrated SpringBoot common api and implementation of distributed lock

ZooKeeper itself provides a low-level Java API to achieve speaking in front of node operation. Tool Curator Apache ZooKeeper for an access package, a package of these low-level operations also provide some advanced services, such as distributed locks, and so choose leadership.

1.Curator of pom-dependent

        <dependency>
            <groupId>org.apache.curator</groupId>
            <artifactId>curator-recipes</artifactId>
            <version>3.3.0</version>
        </dependency>

2.JAVA profile

package com.ztxy.module.log.controller.config;

import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.retry.ExponentialBackoffRetry;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * @author jie
 * @Description:
 * @date 2020/1/16 15:16
 */
@Configuration
public class ZookeeperConfig {

    /**
     * Curator Apache
     * 供的个访问Zookeeper的工具包,封装了这些低级别操作同时也提供一些高级服务,比如分布式锁、领导选取
     * @return
     */
    @Bean
    public CuratorFramework curatorFramework(){
        // ExponentialBackoffRetry是种重连策略,每次重连的间隔会越来越长,1000毫秒是初始化的间隔时间,3代表尝试重连次数。
        ExponentialBackoffRetry retry = new ExponentialBackoffRetry(1000, 3);
        // 创建client
        CuratorFramework curatorFramework = CuratorFrameworkFactory.newClient("xxx.xxx.xxx.xxx:2181", retry);
        // 添加watched 监听器
        curatorFramework.getCuratorListenable().addListener(new MyCuratorListener());
        curatorFramework.start();
        return curatorFramework;
    }

}

 watched listener when listening callback method eventReceived changed node data

package com.ztxy.module.log.controller.config;

import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.api.CuratorEvent;
import org.apache.curator.framework.api.CuratorEventType;
import org.apache.curator.framework.api.CuratorListener;
import org.apache.zookeeper.WatchedEvent;

/**
 * @author jie
 * @Description:
 * @date 2020/1/16 16:29
 */
public class MyCuratorListener implements CuratorListener {
    @Override
    public void eventReceived(CuratorFramework client, CuratorEvent event) throws Exception {
        CuratorEventType type = event.getType();
        if(type == CuratorEventType.WATCHED){
            WatchedEvent watchedEvent = event.getWatchedEvent();
            String path = watchedEvent.getPath();
            System.out.println(watchedEvent.getType()+" -- "+ path);
            // 重新设置改节点监听
            if(null != path)
                client.checkExists().watched().forPath(path);
        }

    }
}

3.Curator common api

CuratorFramework provides a simple API to operate zk node, as well as zk events, chaining style API is encountered forPath interfaces to trigger calls ZooKeeper

package com.ztxy.module.log.controller.rest.v;

import com.ztxy.module.log.common.InvokeResult;
import com.ztxy.module.log.service.v.CuratorLockService;
import com.ztxy.module.log.vo.v.VoluntaryActiveTypeVO;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.api.CuratorListener;
import org.apache.zookeeper.CreateMode;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

/**
 * @Description:
 * @author: jie
 * @Createed Date: 2020-1-13 16:43:24
 * @ModificationHistory: Who  When  What
 * ---------     -------------   --------------------------------------
 **/
@RestController
@RequestMapping("api/v1/zookeeperApiRest")
@Api(value = "zookeeperApiRest", description = "ZookeeperApiRest相关API")
public class ZookeeperApiRest {

    @Autowired
    private CuratorLockService curatorLockService;

    @Autowired
    private CuratorFramework client;

    @GetMapping("set")
    @ApiOperation(value = "设置节点数据", notes = "xxx")
    public InvokeResult set(String path, String value) throws Exception{
        client.setData().forPath(path,value.getBytes());
        return  InvokeResult.success();
    }

    @GetMapping("get")
    @ApiOperation(value = "获取节点数据并监听")
    public InvokeResult get(String path) throws Exception {
        // watched() 监听节点 当节点变化时将通知Curator,需要添加一个监听器CuratorListener
        byte[] bytes = client.getData().watched().forPath(path);
        return InvokeResult.success(new String(bytes));
    }

    @GetMapping("create")
    @ApiOperation(value = "创建节点", notes = "xxx")
    public InvokeResult create(String path, String value) throws Exception{
        // 创建有序节点  CreateMode 指定节点类型
        client.create().withMode(CreateMode.EPHEMERAL_SEQUENTIAL).forPath(path,value.getBytes());
        return  InvokeResult.success();
    }

}

4. Distributed Lock

package com.ztxy.module.log.service.v.impl;

import com.ztxy.module.log.service.v.CuratorLockService;
import lombok.extern.slf4j.Slf4j;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.recipes.locks.InterProcessLock;
import org.apache.curator.framework.recipes.locks.InterProcessMutex;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.concurrent.TimeUnit;

/**
 * @author jie
 * @Description:
 * @date 2020/1/16 16:42
 */

@Service
@Slf4j
@Transactional(rollbackFor = Exception.class)
public class CuratorLockServiceImpl implements CuratorLockService {

    @Autowired
    private CuratorFramework client;

    /**
     * 分布式锁的初始路径
     */
    private String lockPath = "/lock/test";

    @Override
    public void lockTest(String value) {
        lockPath = lockPath + "/" + value;
        log.info("尝试执行业务"+value);

        // 创建分布式锁
        InterProcessMutex lock = new InterProcessMutex(client, lockPath);
        try {
            // 获取锁资源
            if(lock.acquire(10, TimeUnit.HOURS)){
                log.info("业务逻辑模拟,耗时25s");
                Thread.sleep(25000);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                lock.release();
                log.info("释放锁资源");
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

    }
}

Here distributed lock is complete, start multiple springBoot call this test the service on the line. call controller

    @GetMapping("lock/test")
    @ApiOperation(value = "分布式锁测试", notes = "xxx")
    public InvokeResult lock(String value) throws Exception{
        curatorLockService.lockTest(value);
        return  InvokeResult.success();
    }

5.AOP achieve Distributed Lock

Optimized code: Familiar aop aop also be used to achieve the above lock mechanism, so that the code looks more beautiful achieve the following :

pom-dependent

        <dependency>
            <groupId>commons-collections</groupId>
            <artifactId>commons-collections</artifactId>
            <version>3.2</version>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjrt</artifactId>
            <version>1.9.2</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>

Custom annotation

package com.ztxy.module.log.config;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * @author jie
 * @Description:
 * @date 2020/1/17 10:51
 */

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ClusterLock {
    String LOCK_PATH();
}

aspect section

package com.ztxy.module.log.controller.config;

import com.ztxy.module.log.config.ClusterLock;
import lombok.extern.slf4j.Slf4j;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.recipes.locks.InterProcessMutex;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.concurrent.TimeUnit;

/**
 * @author jie
 * @Description:
 * @date 2020/1/17 10:55
 */

@Component
@Slf4j
@Aspect
public class ClusterLockAdvice {

    @Autowired
    private CuratorFramework client;

    @Around("@annotation(clusterLock)")
    public void lockAround(ProceedingJoinPoint point, ClusterLock clusterLock){
        try {
            // 约定第一个参数就为业务类型
            Object value = point.getArgs()[0];
            if(null == value || !(value instanceof String) ){
                    point.proceed(point.getArgs());
                    return;
            }
            log.info("尝试执行业务"+value);
            String lockPath = clusterLock.LOCK_PATH();
            lockPath = lockPath + "/" + String.valueOf(value);
            InterProcessMutex lock = new InterProcessMutex(client, lockPath);
            try {
                if(lock.acquire(10, TimeUnit.HOURS)){
                    point.proceed(point.getArgs());
                }
            } catch (Exception e) {
                e.printStackTrace();
            }  finally {
                try {
                    lock.release();
                    log.info("释放锁资源");
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }

    }

}

use

    @ClusterLock(LOCK_PATH = "/lock/test2")
    @Override
    public void lockTest2(String value) {
        log.info("业务逻辑模拟,耗时25s");
        try {
            Thread.sleep(25000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

 

Published 13 original articles · won praise 5 · Views 4222

Guess you like

Origin blog.csdn.net/qq_42420773/article/details/104014574