table of Contents
2. Create a configuration file zoo.cfg
4. Data structures and the basic command
Second, the integrated SpringBoot common api and implementation of 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
3. Start the server
Go to the bin directory, run zkServer:
./zkServer.sh start
./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
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();
}
}