springboot整合zookeeper实现分布式锁
目录
01 安装并允许zookeeper
- 安装jdk
- 去官网下载zookeeper的压缩包,我这里下载的是3.4.10版本
- 解压后进入到
zookeeper-3.4.10/conf,修改zoo_sample.cfg文件修改为zoo.cfg文件
mv zoo_sample.cfg zoo.cfg
- 1
- 打开zoo.cfg文件,修改dataDir路径。修改后在/usr/local/zookeeper-3.4.10目录创建文件夹
mkdir zkData
dataDir=/usr/local/zookeeper-3.4.10/zkData
- 1
- 启动zookeeper
/usr/local/zookeeper-3.4.10/bin/zkServer.sh start
- 1
02 springboot应用配置CuratorFramework
- 导入maven依赖
<!-- zookeeper 客户端 -->
<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>
- 配置CuratorFramework
zookeeper的默认端口是2181
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.retry.RetryNTimes;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
import org.springframework.scheduling.annotation.EnableScheduling;
@EnableScheduling
@EnableJpaAuditing
@SpringBootApplication
public class MyDemoApplication {
public static void main(String[] args) {
SpringApplication.run(MyDemoApplication.class, args);
}
@Bean
public CuratorFramework curatorFramework() {
return CuratorFrameworkFactory.newClient("127.0.0.1:2181", new RetryNTimes(5, 1000));
}
}
- 启动CuratorFramework客户端
import org.apache.curator.framework.CuratorFramework;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Service;
/**
* 实现了ApplicationRunner接口后,当容器启动后,会执行实现的run方法
*
* @author 594781919
*/
@Service
public class StartService implements ApplicationRunner {
@Autowired
private CuratorFramework curatorFramework;
@Autowired
private ListenerService listenerService;
@Override
public void run(ApplicationArguments applicationArguments) {
// 非常重要!!!Start the client. Most mutator methods will not work until the client is started
curatorFramework.start();
System.out.println("zookeeper client start");
// 初始化监听方法
listenerService.listener();
}
}
03 使用zookeeper实现集群只一个应用实例执行定时任务
当我们启动多个实例时,需要其中一个实例执行定时任务,其它实例不执行。
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.recipes.leader.LeaderLatch;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import java.io.IOException;
import java.util.Date;
/**
* 实现多个应用实例只一个执行定时任务
*
* @author 594781919@qq.com
*/
@Service
public class TimerTaskService {
@Autowired
private CuratorFramework curatorFramework;
@Value("${server.port}")
private String port;
@Scheduled(cron = "0/5 * * * * *")
public void task() {
LeaderLatch leaderLatch = new LeaderLatch(curatorFramework, "/timerTask");
try {
leaderLatch.start();
// Leader选举需要一些时间,等待2秒
Thread.sleep(2000);
// 判断是否为主节点
if (leaderLatch.hasLeadership()) {
System.out.println(new Date() + " port=" + port + " 是领导");
// 定时任务的业务逻辑代码
} else {
System.out.println(new Date() + " port=" + port + " 是从属");
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
leaderLatch.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
04 使用zookeeper实现分布式锁
import com.igola.domain.Employee;
import com.igola.repository.EmployeeRepository;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.recipes.locks.InterProcessSemaphoreMutex;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author 594781919@qq.com
*/
@RestController
public class EmployeeController {
@Autowired
private EmployeeRepository employeeRepository;
@Autowired
private CuratorFramework curatorFramework;
@GetMapping("/emp/save")
public Employee save(String name) {
// 获取锁
InterProcessSemaphoreMutex balanceLock = new InterProcessSemaphoreMutex(curatorFramework, "/zktest" + name);
Employee employee = new Employee();
try {
// 执行加锁操作
balanceLock.acquire();
System.out.println("已经加锁了, name=" + name);
employee.setName(name);
if ("abc".equals(name)) {
Thread.sleep(30000);
}
employee.setAge((int) (Math.random() * 100));
employee.setSex(false);
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
// 释放锁资源
balanceLock.release();
} catch (Exception e) {
e.printStackTrace();
}
}
employeeRepository.save(employee);
return employee;
}
}
- 1
- 2
05 使用zookeeper实现调度任务
当我们在启动多个服务后,访问了其中一个服务,执行了一些方法。然后我们需要其它服务也要执行这些方法,就需要用到NodeCache。
比如我们把一些数据缓存到Map对象中,当需要更新这个Map对象的数据时,我们就可以用NodeCache将每个服务都更新自己的Map对象。
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.recipes.cache.NodeCache;
import org.apache.curator.utils.CloseableUtils;
import org.apache.zookeeper.data.Stat;
import org.springframework.stereotype.Service;
import javax.annotation.PreDestroy;
import java.util.Date;
/**
* @author 594781919
*/
@Service
public class ListenerService {
private final CuratorFramework curatorFramework;
private NodeCache nodeCache;
public static final String path = "/hello/world";
public ListenerService(CuratorFramework curatorFramework) {
this.curatorFramework = curatorFramework;
}
public void listener() {
try {
// 创建路径
Stat stat = curatorFramework.checkExists().forPath(path);
if (stat == null) {
curatorFramework.create().creatingParentsIfNeeded().forPath(path);
}
} catch (Exception e) {
e.printStackTrace();
}
nodeCache = new NodeCache(curatorFramework, path);
// 添加监听的路径改变后需要执行的任务
nodeCache.getListenable().addListener(this::run);
try {
nodeCache.start();
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("开始监听......");
}
@PreDestroy
public void preDestroy() {
CloseableUtils.closeQuietly(nodeCache);
}
public void notifyNodeCache() {
try {
curatorFramework.setData().forPath(path);
} catch (Exception e) {
e.printStackTrace();
}
}
// 需要执行的调度任务
private void run() {
System.out.println(new Date().toLocaleString() + ", 开始执行监听任务");
}
}
springboot整合zookeeper实现分布式锁的更多相关文章
- springboot整合curator实现分布式锁
理论篇: Curator是Netflix开源的一套ZooKeeper客户端框架. Netflix在使用ZooKeeper的过程中发现ZooKeeper自带的客户端太底层, 应用方在使用的时候需要自己处 ...
- SpringBoot电商项目实战 — Zookeeper的分布式锁实现
上一篇演示了基于Redis的Redisson分布式锁实现,那今天我要再来说说基于Zookeeper的分布式现实. Zookeeper分布式锁实现 要用Zookeeper实现分布式锁,我就不得不说说zo ...
- java springboot整合zookeeper入门教程(增删改查)
java springboot整合zookeeper增删改查入门教程 zookeeper的安装与集群搭建参考:https://www.cnblogs.com/zwcry/p/10272506.html ...
- ZooKeeper学习(二)ZooKeeper实现分布式锁
一.简介 在日常开发过程中,大型的项目一般都会采用分布式架构,那么在分布式架构中若需要同时对一个变量进行操作时,可以采用分布式锁来解决变量访问冲突的问题,最典型的案例就是防止库存超卖,当然还有其他很多 ...
- 6 zookeeper实现分布式锁
zookeeper实现分布式锁 仓库地址:https://gitee.com/J_look/ssm-zookeeper/blob/master/README.md 锁:我们在多线程中接触过,作用就是让 ...
- zookeeper实现分布式锁服务
A distributed lock base on zookeeper. zookeeper是hadoop下面的一个子项目, 用来协调跟hadoop相关的一些分布式的框架, 如hadoop, hiv ...
- [ZooKeeper.net] 3 ZooKeeper的分布式锁
基于ZooKeeper的分布式锁 ZooKeeper 里实现分布式锁的基本逻辑: 1.zookeeper中创建一个根节点(Locks),用于后续各个客户端的锁操作. 2.想要获取锁的client都在L ...
- 基于 Zookeeper 的分布式锁实现
1. 背景 最近在学习 Zookeeper,在刚开始接触 Zookeeper 的时候,完全不知道 Zookeeper 有什么用.且很多资料都是将 Zookeeper 描述成一个“类 Unix/Linu ...
- zookeeper的分布式锁
实现分布式锁目前有三种流行方案,分别为基于数据库.Redis.Zookeeper的方案,其中前两种方案网络上有很多资料可以参考,本文不做展开.我们来看下使用Zookeeper如何实现分布式锁. 什么是 ...
随机推荐
- Js中关于构造函数,原型,原型链深入理解
在 ES6之前,在Javascript不存在类(Class)的概念,javascript中不是基于类的,而是通过构造函数(constructor)和原型链(prototype chains)实现的.但 ...
- SQLITE数据库不支持远程访问
SQLITE数据库不支持远程访问 import sqlite3 conn=sqlite3.connect("dailiaq.db") cur=conn.cursor() def c ...
- C语言:异或
异或运算符"∧"也称XOR运算符.它的规则是若参加运算的两个二进位同号,则结果为0(假):异号则为1(真).即 0∧0=0,0∧1=1, 1^0=1,1∧1=0. 相同为0,不相同 ...
- java集合(3)-Java8新增的Predicate操作集合
Java8起为Collection集合新增了一个removeIf(Predicate filter)方法,该方法将批量删除符合filter条件的所有元素.该方法需要一个Predicate(谓词)对象作 ...
- SpringMvc接受请求参数的几种情况演示
说明: 通常get请求获取的参数是在url后面,而post请求获取的是请求体当中的参数.因此两者在请求方式上会有所不同. 1.直接将接受的参数写在controller对应方法的形参当中(适用于get提 ...
- RHEL7通过Rsyslog搭建集中日志服务器
说明:这里是Linux服务综合搭建文章的一部分,本文可以作为单独搭建rsyslog日志服务器的参考. 注意:这里所有的标题都是根据主要的文章(Linux基础服务搭建综合)的顺序来做的. 如果需要查看相 ...
- 第四篇 -- Go语言string转其他类型
1. string转int // 法1:string转int num_str := "1234567" /* ParseInt():查看文档https://studygolang. ...
- Tr0ll靶机
一.主机探测 二.信息收集 进入21端口 发现文件并下载 下载文件 作为字典进行登录爆破 用字典爆破 ssh登录 查找信息 /etc/init.d/ssh start scp root@192.1 ...
- Cookie、Session、JWT在koa中的应用及实现原理
目录 Cookie 重要属性 实现原理 cookie签名实现原理 注意事项 Session 实现原理 JWT 使用方式 组成 实际应用 实现原理 前端存储方式 cookie session local ...
- Qt学习-ListView的拖拽
最近在学习Qt 里面的QML, 使用DropArea和MouseArea实现了ListView的拖拽. 想起了当年用Delphi, 差不多一样的东西, 不过那是2000了. Delphi也是不争气啊, ...