设为首页 - 加入收藏 ASP站长网(Aspzz.Cn)- 科技、建站、经验、云计算、5G、大数据,站长网!
热搜: 创业者 手机 数据
当前位置: 首页 > 站长学院 > MySql教程 > 正文

为什么Zookeeper天生就是一副分布式锁的胚子?

发布时间:2020-03-15 20:08 所属栏目:115 来源:站长网
导读:副标题#e# 【金融特辑】光大****科技部DBA女神带你从0到1揭秘MGR 什么是分布式锁?分布式锁是控制分布式系统之间同步访问共享资源的一种方式。在分布式系统中,常常需要协调他们的动作。 图片来自 Pexels 如果不同的系统或是同一个系统的不同主机之间共享了
【金融特辑】光大****科技部DBA女神带你从0到1揭秘MGR

什么是分布式锁?分布式锁是控制分布式系统之间同步访问共享资源的一种方式。在分布式系统中,常常需要协调他们的动作。

为什么Zookeeper天生就是一副分布式锁的胚子?

图片来自 Pexels

如果不同的系统或是同一个系统的不同主机之间共享了一个或一组资源,那么访问这些资源的时候,往往需要互斥来防止彼此干扰来保证一致性,在这种情况下,便需要使用到分布式锁。

为什么要使用分布式锁

为了保证一个方法或属性在高并发情况下的同一时间只能被同一个线程执行。

在传统单体应用单机部署的情况下,可以使用 Java 并发处理相关的 API(如 ReentrantLock 或 Synchronized)进行互斥控制;在单机环境中,Java 中提供了很多并发处理相关的 API。

但是,随着业务发展的需要,原单体单机部署的系统被演化成分布式集群系统后,由于分布式系统多线程、多进程并且分布在不同机器上,这将使原单机部署情况下的并发控制锁策略失效,单纯的 Java API 并不能提供分布式锁的能力。

为了解决这个问题就需要一种跨 JVM 的互斥机制来控制共享资源的访问,这就是分布式锁要解决的问题!

举个例子:机器 A,机器 B 是一个集群。A,B 两台机器上的程序都是一样的,具备高可用性能。

A,B 机器都有一个定时任务,每天晚上凌晨 2 点需要执行一个定时任务,但是这个定时任务只能执行一遍,否则的话就会报错。

那 A,B 两台机器在执行的时候,就需要抢锁,谁抢到锁,谁执行,谁抢不到,就不用执行了!

锁的处理

锁的处理方式如下:

单个应用中使用锁:(单进程多线程)Synchronize。

分布式锁控制分布式系统之间同步访问资源的一种方式。

分布式锁是控制分布式系统之间同步访问共享资源的一种方式。

分布式锁的实现

分布式锁的实现方式如下:

基于数据的乐观锁实现分布式锁

基于 Zookeeper 临时节点的分布式锁

基于 Redis 的分布式锁

Redis 的分布式锁

获取锁

在 set 命令中,有很多选项可以用来修改命令的行为,以下是 set 命令可用选项的基本语法:

redis 127.0.0.1:6379>SET KEY VALUE [EX seconds] [PX milliseconds] [NX|XX] 

 

- EX seconds 设置指定的到期时间(单位为秒) 

- PX milliseconds 设置指定的到期时间(单位毫秒) 

- NX: 仅在键不存在时设置键 

- XX: 只有在键已存在时设置 

方式 1:推介

private static final String LOCK_SUCCESS = "OK"; 

  private static final String SET_IF_NOT_EXIST = "NX"; 

  private static final String SET_WITH_EXPIRE_TIME = "PX"; 

 

ublic static boolean getLock(JedisCluster jedisCluster, String lockKey, String requestId, int expireTime) { 

      // NX: 保证互斥性 

      String result = jedisCluster.set(lockKey, requestId, SET_IF_NOT_EXIST, SET_WITH_EXPIRE_TIME, expireTime); 

      if (LOCK_SUCCESS.equals(result)) { 

          return true; 

     } 

      return false; 

 } 

方式 2:

public static boolean getLock(String lockKey,String requestId,int expireTime) { 

    Long result = jedis.setnx(lockKey, requestId); 

    if(result == 1) { 

        jedis.expire(lockKey, expireTime); 

        return true; 

    } 

    return false; 

注意:推介方式 1,因为方式 2 中 setnx 和 expire 是两个操作,并不是一个原子操作,如果 setnx 出现问题,就是出现死锁的情况,所以推荐方式 1。

释放锁

方式 1:del 命令实现

public static void releaseLock(String lockKey,String requestId) { 

   if (requestId.equals(jedis.get(lockKey))) { 

       jedis.del(lockKey); 

  } 

方式 2:Redis+Lua 脚本实现(推荐)

public static boolean releaseLock(String lockKey, String requestId) { 

(编辑:ASP站长网)

网友评论
推荐文章
    热点阅读