【推荐】基于zookeeper简单实现分布式锁

纠结!分布式锁到底用Redis好还是ZooKeeper好? 前言 1. 什么是分布式锁 分布式锁是控制分布式系统之间同步访问共享资源的一种方式。在分布式系统中,常常需要协调他们的动作。如果不同的系统或是同一个系统的不同主机之间共享了一个或一组资源,那么访问这些资源的时候,往往需要互斥来防止彼此干扰来保证一致性,在这种情况下,便需要使用到分布式锁。 2. 为什么要使用分布式锁 为了保证一个方法或属性在高并发情况下的同一时间只能被同一个线程执行,在传统单体应用单机部署的情况下,可以使用Java并发处理相关的API(如ReentrantLock或Synchronized) 阅读详情

这里利用zookeeper的EPHEMERAL_SEQUENTIAL类型节点及watcher机制,来简单实现分布式锁。

 思路如下:

1、开启10个线程,在disLocks节点下各自创建名为sub的EPHEMERAL_SEQUENTIAL节点;

2、获取disLocks节点下所有子节点,排序,如果自己的节点编号最小,则获取锁;

3、否则watch排在自己前面的节点,监听到其删除后,进入第2步(重新检测排序是防止监听的节点发生连接失效,导致的节点删除情况);

4、删除自身sub节点,释放连接;

这里插播下zookeeper的4种节点类型:

public enum CreateMode {  

    /** 
     * 持久节点:节点创建后,会一直存在,不会因客户端会话失效而删除; 
     */  
    PERSISTENT (0, false, false),  
  
    /** 
    * 持久顺序节点:基本特性与持久节点一致,创建节点的过程中,zookeeper会在其名字后自动追加一个单调增长的数字后缀,作为新的节点名;  
    */  
    PERSISTENT_SEQUENTIAL (2, false, true),  
  
    /** 
     *  临时节点:客户端会话失效或连接关闭后,该节点会被自动删除,且不能再临时节点下面创建子节点,否则报如下错:org.apache.zookeeper.KeeperException$NoChildrenForEphemeralsException; 
     */  
    EPHEMERAL (1, true, false),  
  
    /** 
     * 临时顺序节点:基本特性与临时节点一致,创建节点的过程中,zookeeper会在其名字后自动追加一个单调增长的数字后缀,作为新的节点名;  
     */  
    EPHEMERAL_SEQUENTIAL (3, true, true);  
    private static final Logger LOG = LoggerFactory.getLogger(CreateMode.class);  
    private boolean ephemeral;  
    private boolean sequential;  
    private int flag;  
    CreateMode(int flag, boolean ephemeral, boolean sequential) {  
        this.flag = flag;  
        this.ephemeral = ephemeral;  
        this.sequential = sequential;  
    }  
    public boolean isEphemeral() {  
        return ephemeral;  
    }  
    public boolean isSequential() {  
        return sequential;  
    }  
    public int toFlag() {  
        return flag;  
    }  
    static public CreateMode fromFlag(int flag) throws KeeperException {  
        switch(flag) {  
        case 0: return CreateMode.PERSISTENT;  
        case 1: return CreateMode.EPHEMERAL;  
        case 2: return CreateMode.PERSISTENT_SEQUENTIAL;  
        case 3: return CreateMode.EPHEMERAL_SEQUENTIAL ;  
        default:  
            LOG.error("Received an invalid flag value to convert to a CreateMode");  
            throw new KeeperException.BadArgumentsException();  
        }  
    }  
}  

测试代码:

package zookeeper;  

import org.slf4j.Logger;  
import org.slf4j.LoggerFactory;  
import org.apache.zookeeper.*;  
import org.apache.zookeeper.data.Stat;  
import java.util.List;  
import java.io.IOException;  
import java.util.Collections;  
import java.util.concurrent.CountDownLatch;  
  
public class DistributedLock implements Watcher{  
    private int threadId;  
    private ZooKeeper zk = null;  
    private String selfPath;  
    private String waitPath;  
    private String LOG_PREFIX_OF_THREAD;  
    private static final int SESSION_TIMEOUT = 10000;  
    private static final String GROUP_PATH = "/disLocks";  
    private static final String SUB_PATH = "/disLocks/sub";  
    private static final String CONNECTION_STRING = "192.168.*.*:2181";  
      
    private static final int THREAD_NUM = 10;   
    //确保连接zk成功;  
    private CountDownLatch connectedSemaphore = new CountDownLatch(1);  
    //确保所有线程运行结束;  
    private static final CountDownLatch threadSemaphore = new CountDownLatch(THREAD_NUM);  
    private static final Logger LOG = LoggerFactory.getLogger(AllZooKeeperWatcher.class);  
    public DistributedLock(int id) {  
        this.threadId = id;  
        LOG_PREFIX_OF_THREAD = "【第"+threadId+"个线程】";  
    }  
    public static void main(String[] args) {  
        for(int i=0; i < THREAD_NUM; i++){  
            final int threadId = i+1;  
            new Thread(){  
                @Override  
                public void run() {  
                    try{  
                        DistributedLock dc = new DistributedLock(threadId);  
                        dc.createConnection(CONNECTION_STRING, SESSION_TIMEOUT);  
                        //GROUP_PATH不存在的话,由一个线程创建即可;  
                        synchronized (threadSemaphore){  
                            dc.createPath(GROUP_PATH, "该节点由线程" + threadId + "创建", true);  
                        }  
                        dc.getLock();  
                    } catch (Exception e){  
                        LOG.error("【第"+threadId+"个线程】 抛出的异常:");  
                        e.printStackTrace();  
                    }  
                }  
            }.start();  
        }  
        try {  
            threadSemaphore.await();  
            LOG.info("所有线程运行结束!");  
        } catch (InterruptedException e) {  
            e.printStackTrace();  
        }  
    }  
    /** 
     * 获取锁 
     * @return 
     */  
    private void getLock() throws KeeperException, InterruptedException {  
        selfPath = zk.create(SUB_PATH,null, ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);  
        LOG.info(LOG_PREFIX_OF_THREAD+"创建锁路径:"+selfPath);  
        if(checkMinPath()){  
            getLockSuccess();  
        }  
    }  
    /** 
     * 创建节点 
     * @param path 节点path 
     * @param data 初始数据内容 
     * @return 
     */  
    public boolean createPath( String path, String data, boolean needWatch) throws KeeperException, InterruptedException {  
        if(zk.exists(path, needWatch)==null){  
            LOG.info( LOG_PREFIX_OF_THREAD + "节点创建成功, Path: "  
                    + this.zk.create( path,  
                    data.getBytes(),  
                    ZooDefs.Ids.OPEN_ACL_UNSAFE,  
                    CreateMode.PERSISTENT )  
                    + ", content: " + data );  
        }  
        return true;  
    }  
    /** 
     * 创建ZK连接 
     * @param connectString  ZK服务器地址列表 
     * @param sessionTimeout Session超时时间 
     */  
    public void createConnection( String connectString, int sessionTimeout ) throws IOException, InterruptedException {  
            zk = new ZooKeeper( connectString, sessionTimeout, this);  
            connectedSemaphore.await();  
    }  
    /** 
     * 获取锁成功 
    */  
    public void getLockSuccess() throws KeeperException, InterruptedException {  
        if(zk.exists(this.selfPath,false) == null){  
            LOG.error(LOG_PREFIX_OF_THREAD+"本节点已不在了...");  
            return;  
        }  
        LOG.info(LOG_PREFIX_OF_THREAD + "获取锁成功,赶紧干活!");  
        Thread.sleep(2000);  
        LOG.info(LOG_PREFIX_OF_THREAD + "删除本节点:"+selfPath);  
        zk.delete(this.selfPath, -1);  
        releaseConnection();  
        threadSemaphore.countDown();  
    }  
    /** 
     * 关闭ZK连接 
     */  
    public void releaseConnection() {  
        if ( this.zk !=null ) {  
            try {  
                this.zk.close();  
            } catch ( InterruptedException e ) {}  
        }  
        LOG.info(LOG_PREFIX_OF_THREAD + "释放连接");  
    }  
    /** 
     * 检查自己是不是最小的节点 
     * @return 
     */  
    public boolean checkMinPath() throws KeeperException, InterruptedException {  
         List<String> subNodes = zk.getChildren(GROUP_PATH, false);  
         Collections.sort(subNodes);  
         int index = subNodes.indexOf( selfPath.substring(GROUP_PATH.length()+1));  
         switch (index){  
             case -1:{  
                 LOG.error(LOG_PREFIX_OF_THREAD+"本节点已不在了..."+selfPath);  
                 return false;  
             }  
             case 0:{  
                 LOG.info(LOG_PREFIX_OF_THREAD+"子节点中,我果然是老大"+selfPath);  
                 return true;  
             }  
             default:{  
                 this.waitPath = GROUP_PATH +"/"+ subNodes.get(index - 1);  
                 LOG.info(LOG_PREFIX_OF_THREAD+"获取子节点中,排在我前面的"+waitPath);  
                 try{  
                     zk.getData(waitPath, true, new Stat());  
                     return false;  
                 }catch(KeeperException e){  
                     if(zk.exists(waitPath,false) == null){  
                         LOG.info(LOG_PREFIX_OF_THREAD+"子节点中,排在我前面的"+waitPath+"已失踪,幸福来得太突然?");  
                         return checkMinPath();  
                     }else{  
                         throw e;  
                     }  
                 }  
             }                     
         }  
    } 
  /*
  process 方法是 Watcher 接口中的一个回调方法,当 ZooKeeper 向客户端发送一个 Watcher 事件通知时,
  客户端就会对相应的 process 方法进行回调 */
    @Override  
    public void process(WatchedEvent event) {  
        if(event == null){  
            return;  
        }  
        Event.KeeperState keeperState = event.getState();  
        Event.EventType eventType = event.getType();  
        if ( Event.KeeperState.SyncConnected == keeperState) {  
            if ( Event.EventType.None == eventType ) {  
                LOG.info( LOG_PREFIX_OF_THREAD + "connected to zk successfully" );  
                connectedSemaphore.countDown();  
            }else if (event.getType() == Event.EventType.NodeDeleted && event.getPath().equals(waitPath)) {  
                LOG.info(LOG_PREFIX_OF_THREAD + "lock owners release lock, I have chance now");  
                try {  
                    if(checkMinPath()){  
                        getLockSuccess();  
                    }  
                } catch (KeeperException e) {  
                    e.printStackTrace();  
                } catch (InterruptedException e) {  
                    e.printStackTrace();  
                }  
            }  
        }else if ( Event.KeeperState.Disconnected == keeperState ) {  
            LOG.info( LOG_PREFIX_OF_THREAD + "connection is disrupted" );  
        } else if ( Event.KeeperState.AuthFailed == keeperState ) {  
            LOG.info( LOG_PREFIX_OF_THREAD + "authentication failed" );  
        } else if ( Event.KeeperState.Expired == keeperState ) {  
            LOG.info( LOG_PREFIX_OF_THREAD + "session expire" );  
        }  
    }  
}  


log配置文件:

# DEFAULT   

log4j.rootLogger=INFO,CONSOLE  
  
#  
# Log INFO level and above messages to the console  
#  
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender  
log4j.appender.CONSOLE.Threshold=INFO  
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout  
log4j.appender.CONSOLE.layout.ConversionPattern=%d{ISO8601} - %m%n  
  
  
log4j.appender.COMMONSTAT=org.apache.log4j.DailyRollingFileAppender  
log4j.appender.COMMONSTAT.Threshold=INFO  
log4j.appender.COMMONSTAT.File=/home/zookeeper/zookeeper-test-agent/logs/test.log  
log4j.appender.COMMONSTAT.DatePattern='.'yyyy-MM-dd  
  
log4j.appender.COMMONSTAT.layout=org.apache.log4j.PatternLayout  
log4j.appender.COMMONSTAT.layout.ConversionPattern=[%d{yyyy-MM-dd HH:mm:ss}] - %m%n  
  
log4j.logger.org.displaytag=WARN  
log4j.logger.org.apache.zookeeper=ERROR  
log4j.logger.org.springframework=WARN  
log4j.logger.org.I0Itec=WARN  
log4j.logger.commonStat=INFO,COMMONSTAT  

另外,说一下关于Zookeeper watch的事。watch事件是一次性触发器,当watch监视的数据发生变化时,通知设置了该watch的client,即watcher。

需要注意三点:
1.一次性触发器
client在一个节点上设置watch,随后节点内容改变,client将获取事件。当节点内容再次改变,client不会获取这个事件,
除非它又执行了一次读操作并设置watch。


2.发送至client,watch事件延迟
watch事件异步发送至观察者。比如说client执行一次写操作,节点数据内容发生变化,操作返回后,而watch事件可能还在发往client的路上。这种情况下,zookeeper提供有序保证:client不会得知数据变化,直到它获取watch事件。

网络延迟或其他因素可能导致不同client在不同时刻获取watch事件和操作返回值。

3.设置watch的数据内容
涉及到节点改变的不同方式。比方说zookeeper维护两个watch列表:节点的数据watch和子节点watch。

getData()和exists()设置了内容watch,getChildren()设置了子节点watch,操作返回的数据类型不同,前者是节点的内容,后者是节点的子节点列表。

  • setData()触发内容watch。
  • create()触发当前节点的"内容watch"和其父节点的"子节点watch"。
  • delete()同时触发"内容watch"和"子节点watch"(其子节点被全部删除),以及其父节点的"子节点watch"。

说白了,对当前节点的操作,要考虑到对其父节点与子节点的影响。


watch在客户端所连接的服务端本地维护。watch的设置、维护、分发操作都很轻量级。当客户端连接到新的服务端,watch将被任一会话事件触发。与服务端断开连接时,不能获取watch事件。客户端重连后,之前注册的watch将被重新注册并在需要时触发。通常这一切透明地发生,用户不会察觉到。有一种情况watch可能丢失:之前对一个尚未建立的节点的设置了exists watch,如果断开期间该节点被建立或删除,那么此watch将丢失。

对于watch,zookeeper提供以下保证:
1. watch对于其他事件、watch、异步响应是有序的。zookeeper client library保证有序分发
2. 客户端监视一个节点,总是先获取watch事件,再发现节点的数据变化。
3. watch事件的顺序对应于zookeeper服务所见的数据更新的顺序。

关于watch要记住的是:
1.watch是一次性触发的,如果获取一个watch事件并希望得到新变化的通知,需要重新设置watch。
2.watch是一次性触发的并且在获取watch事件和设置新watch事件之间有延迟,所以不能可靠的观察到节点的每一次变化。要认识到这一点。
3.watch object只触发一次,比如,一个watch object被注册到同一个节点的getData()和exists(),节点被删除,仅对应于exists()的watch ojbect被调用。
4.若与服务端断开连接,直到重连后才能获取watch事件。

更多关于ZooKeeper监听机制和watcher用法演示,

见这篇文章:https://www.cnblogs.com/programlearning/archive/2017/05/10/6834963.html

美团面试:分布式锁实现方案,你选哪种? Curator是一个zookeeper的开源客户端,也提供了分布式锁的实现。try {= null ) {// 获取当前所有节点排序后的集合// 获取当前节点的名称// 判断当前节点是否是最小的节点// 获取到锁} else {// 没获取到锁,对当前节点的上一个节点注册一个监听器if ( stat!throw e;} finally{ 阅读详情

相关推荐

SpringMVC+Redis实现分布式锁实现秒杀功能

1.实现分布式锁的几种方案 1.Redis实现 (推荐) 2.Zookeeper实现 3.数据库实现 Redis实现分布式锁 * * 在集群等多服务器中经常使用到同步处理一下业务,这是普通的事务是满足不了业务需求,需要分布式锁 * * 分布式锁的常用3种实现: * 0.数据库乐观锁实现 * 1....

fxbar的博客 4783

zookeeper实现分布式锁

介绍了Zookeeper如何实现分布式锁,并使用代码进行了演示

凉茶铺的博客 6971

代码详解——Transformer

对于一个序列,在 time_step 为 t 的时刻,我们的解码输出应该只能依赖于 t 时刻之前的输出,而不能依赖 t 之后的输出。当 Decoder 的输入矩阵和 Mask 矩阵输入矩阵包含 “ I have a cat” (0, 1, 2, 3, 4) 五个单词的表示向量,Mask 是一个 5×5 的矩阵。然后判断是否传入的mask, 如果有mask (mask参数值不为None),则把mask为0的位置,将对应位置的attn的值设为无穷小的负数。可以发现得到的输出和输入的K,Q,V的大小相同。

zyw2002的博客 7209

基于zookeeper实现分布式锁

如果创建的是永久的节点,那么这个锁永远不会释放,导致死锁;例如子节点列表 为/lock/lock-0000000000、/lock/lock-0000000001、/lock/lock-0000000002,序号为1的客户端监听 序号为0的子节点删除消息,序号为2的监听序号为1的子节点删除消息。客户端获取/lock下的子节点列表,判断自己创建的子节点是否为当前子节点列表中序号最小的子 节点,如果是则认为获得锁,否则监听刚好在自己之前一位的子节点删除消息,获得子节点变更通 知后重复此步骤直至获得锁;

一个菜鸡的博客 3336

SSD盘符漂移导致OSD down场景模拟与恢复

运维团队反馈一个问题,现象是:某个OSD对应的cache分区发生了变化,比如原来cache使用的分区是/dev/sde,后来还是这块盘,但分区信息不知何故,变成了/dev/sdf(产品OSD设备并不是根据分区名称来map,而是根据partlabel),最终的现象是这个OSD down了,没法启动.接到这个现象的反馈后,记录一下这个问题在lab的复现方法。

Gavin Blog 938

ABAP内表数据导出Excel:OLE、ALV与GUI_DOWNLOAD方案全解析

在企业级应用开发中,数据导出是连接后台系统与前端业务分析的关键桥梁。其核心原理是将结构化数据转换为通用文件格式,以实现跨平台的数据交换与可视化。从技术价值看,一个健壮的导出功能能显著提升数据处理效率,减少人工干预,是衡量系统实用性的重要指标。常见的应用场景包括报表生成、数据交接和临时数据提取。本文聚焦于SAP ABAP开发领域,深入探讨如何将内表数据高效、稳定地导出至Excel,涵盖了OLE自动化、ALV标准导出以及基于CL_GUI_FRONTEND_SERVICES与GUI_DOWNLOAD的通用方案,并

weixin_32715349的博客 321

基于Zookeeper实现分布式锁

在Zookeeper中的指定路径下创建创建节点,然后客户端根据当前路径下的节点状态来判断是否加锁成功,如下图一种情况为例,线程1创建节点成功后,线程2再去创建节点就会创建失败。(3)如果加锁次数等于0,则释放锁,删除掉创建的临时节点,下一个监听这个节点的客户端会感知到节点删除事件,从而重新去获取锁。3:判断自己的序号是否最小,如果最小的话,代表加锁成功,如果不是最小的话,就对前一个节点创建监听器。2:使用顺序节点的好处是,可以利用锁释放的事件监听机制,来实现。2:第二步客户端拿到加锁路径下所有创建的节点。

weixin_45125989的博客 2915

Maltab GUI课程设计——网络爬虫程序(基金连涨连跌提醒)

Maltab GUI课程设计——网络爬虫程序(基金连涨连跌提醒)

果果爱腰果的博客 849

常见的分布式锁--ZooKeeper如何实现分布式锁?

ZooKeeper是一个开源的分布式协调服务,提供了一种分布式锁的实现方式。在ZooKeeper中,可以使用临时节点和顺序节点的特性来实现分布式锁。本文将介绍ZooKeeper的分布式锁实现原理,并提供一个实战代码示例,通过分析关键技术来帮助理解。

IT_WEH_coder的博客 2325

Python爬虫实战:用最新技术高效下载摄影网站图片

本文将深入探讨如何利用Python最新技术栈构建一个功能完整的摄影网站图片爬虫。我们将使用异步编程、智能反爬策略和现代化工具,实现高效、可靠的图片下载系统。高性能异步架构:使用asyncio实现高并发下载智能反爬策略:支持多种反爬措施和浏览器模拟多网站适配:可解析多种摄影网站结构数据管理:完整的下载记录和统计功能扩展性强:支持代理、分布式等高级功能用户友好:提供进度显示和详细日志。

2201_76125261的博客 1644

基于 YOLOv8 的自动驾驶车辆障碍物检测与避障路径规划

本文探讨基于YOLOv8的自动驾驶车辆障碍物检测与避障路径规划系统。在感知层面,采用YOLOv8模型实现多类别障碍物识别,结合单目视觉距离估计和ByteTrack多目标跟踪算法,完成障碍物的稳定检测与运动状态估计。在路径规划层面,设计分层规划架构,融合全局路径规划与局部避障算法,重点实现Frenet坐标系下的采样优化算法和基于模型预测控制的实时避障轨迹生成。通过完整的代码实现与仿真实验,验证系统在复杂交通场景下的有效性与实时性,为自动驾驶开发者提供从理论到实践的完整技术参考。 关键词:YOLOv8;自动驾驶

huanghm88的专栏 248

Zookeeper 和 Redis 哪种更好? 为什么使用分布式锁? 1. 利用 Redis 提供的 第二种,基于 ZK 实现分布式锁的落地方案 对于 redis 的分布式锁而言,它有以下缺点:

如果要在两者之间做选择,就我个人而言的话,比较推崇 ZK 实现的锁,因为对于分布式锁而言,它应该符合 CP 模型,但是 Redis 是 AP 模型,所以在这个点上,Zookeeper 会更加合适。4、如果当前线程创建的节点不是所有节点序号最小的节点,则对节点序号的前一个节点添加一个事件监听,当前一个被监听的节点释放锁之后,触发回调通知, 从而再次去尝试抢占锁。2、线程创建节点后,获取/lock 节点下的所有子节点,判断当前线程创建的节点是否是所有的节点的序号最小的。锁的模型健壮、简单易用、适合做分布式锁。

weixin_44797327的博客 1238

RK3568平台开发系列:Android环境下CAN的使用

在RK3568平台上,我们可以利用Android环境中的API来实现CAN的使用。通过以上步骤,我们可以在Android应用中发送和接收CAN数据,并进行相应的处理。当接收到CAN数据时,将触发onMessageReceived回调方法,我们可以在这个方法中对接收到的数据进行处理。在上述代码中,我们指定了CAN的ID为0x123,数据为{0x01, 0x02, 0x03},并设置了标志位和周期。接收CAN数据需要注册一个监听器,并在监听器中处理接收到的数据。发送CAN数据需要指定CAN的ID和数据。

2301_79330513的博客 1912

Zookeeper实现分布式锁

一:背景在分布式锁之redis实现分布式锁一文中,已经说明了redis如何实现分布式锁。但是其实使用redis实现分布式锁还是比较的麻烦,我们可以利用zookeeper实现分布式锁。zookeeper的设计初衷就是为分布式事务服务的。二:实现方式本来想写一篇文章的,但是发现前辈已经写好了。所以朋友们可以参考以下的文章。如何用Zookeeper实现分布式锁?基于zookeeper实现分布式锁利用Zo...

li12412414的博客 493

1.2 博图TIA的轨迹(Trace)功能介绍

在TIA中“轨迹” ( Traces ) 能来记录设备变量并对记录进行评估,对有些故障排查很有帮助,本文进行介绍

qq_34047402的博客 1646

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

分布式锁用 Redis 还是 Zookeeper

什么是分布式锁 在分布式架构中,Java的锁无法管理多个实例,因此需要有一个类似于统一管理锁的架构模式,即分布式锁。 目前比较常见的分布式锁实现方案有以下几种: 基于数据库乐观锁,如MySQL(增加字段版本标识version控制实现) 基于缓存,如Redis 基于Zookeeper、etcd等(ZooKeeper机制规定:同一个目录下只能有一个唯一的文件名,借助ZooKeeper的临时节点实现) 例如两个订单服务,对要更新数据库的数据,如果能获取到相应的锁才能进行后续操作。 分布式锁的几种实现方式 基

一条小黑龙的博客 4155

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

深入解析Zookeeper实现分布式锁的原理与实践

本文详细介绍了使用Zookeeper实现分布式锁的多种方式,包括临时节点、临时顺序节点+Watcher等实现原理,并分析了Apache Curator、ZkClient等成熟SDK的实现方式。通过代码示例和对比分析,帮助开发者理解不同实现方案的优缺点及适用场景,为分布式系统开发提供实践参考。

lingding_cn的专栏 953

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

ZooKeeper实现分布式锁

ZooKeeper实现分布式锁

持续学习,坚持原创,分享技术笔记及经验。 1467

分布式锁用 Redis 还是 Zookeeper ?

分布式锁用 Redis 还是 Zookeeper ?为什么用分布式锁?基于Redis实现分布式锁另一种方式:Redisson小结:基于zookeeper实现分布式锁Curator介绍两种方案的优缺点比较小结建议 为什么用分布式锁? 在讨论这个问题之前,我们先来看一个业务场景: 系统A是一个电商系统,目前是一台机器部署,系统中有一个用户下订单的接口,但是用户下订单之前一定要去检查一下库存,确保库存足够了才会给用户下单。 由于系统有一定的并发,所以会预先将商品的库存保存在redis中,用户下单的时候会更新red

一个写湿的程序猿 445

什么是分布式锁?redis、zookeeper、etcd实现分布式锁有什么不同之处?

目录 分布式锁定义 目的 基于redis分布式锁 基于zookeeper实现的分布式锁 edis、zookeeper、etcd实现分布式锁的比较 分布式锁定义 分布式环境下,锁定全局唯一资源。 请求处理串行化、实际表现为互斥锁。 目的 交易订单锁定:防止重复下单、解决业务层幂等问题。 MQ消息消费幂等性:发送消息重复、消息消费端去重、比如手机提现。 在用户对商品下单后,订单状态为待支付,在某一时刻用户正在对该订单做支付操作,商家对该订单进行改价操作:状态的修改...

秃了也弱了 2813

ZK实现分布式锁的记录

实现分布式锁有很多种方式: 1:数据库方式: 谁先插入数据库值成功, 谁就获取锁。 2: 缓存方式 3: zookeeper 实现分布式锁, 推荐这种方式 zk实现分布式锁的原理及流程: 临时节点 + 事件通知 + 信号量, 临时节点的生命周期是连接断开则会删除。 zk有四种节点类型 1: 持久化节点 2:临时节点 3:持久化顺序节点 ...

tang_jian_dong的博客 829

Zookeeper 分布式锁 - 图解 - 秒懂

1.1. 分布式锁 简介 在我们进行单机应用开发,涉及并发同步的时候,我们往往采用synchronized或者Lock的方式来解决多线程间的代码同步问题。但当我们的应用是分布式集群工作的情况下,那么就需要一种更加高级的锁机制,来处理种跨机器的进程之间的数据同步问题。 这就是分布式锁。 1.1.1. 图解:公平锁和可重入锁 模型 分布式锁的概念和原理,比较抽象难懂。如果用一个简单的故事来类比,估计就简单多了。 很久以前,在一个村子有一口井,水质非常的好,村民们都抢着取井里的水。井就那么一口,村里的人

qq_34874784的博客 702

分布式锁的三种实现方式

文章目录分布式锁基于数据库实现分布式锁基于缓存实现分布式锁基于 ZooKeeper 实现分布式锁三种方案对比 分布式锁 与普通锁不同的是,分布式锁是指分布式环境下,系统部署在多个机器中,实现多进程分布式互斥的一种锁。为了保证多个进程能看到锁,锁被存在公共存储(比如 缓存、数据库等三方存储中),以实现多个进程并发访问同一个临界资源,同一时刻只有一个进程可访问共享资源,确保数据的一致性。 为了确保分布式锁的可用性,我们在设计时应考虑到以下几点: 互斥性,即在分布式系统环境下,对于某一共享资源,需要保证在同一

kk阿彬 319

Zookeeper:五、实现分布式锁

前言 Zookeeper实现分布式锁。 文章目录前言一、实现思路 一、实现思路 为什么有分布式锁? 1)分布式情况下多个客户端请求处理同一个资源,如果不加锁可能会产生数据一致性等其他严重问题,但是单机情况下的一些锁(比如ReentrantLock、Synchorized)只能控制对当前机器请求的数据一致性,不能处理多台机器,因此产生了分布式锁。 2)每个客户在处理资源前先要获取到分布式锁,只有获取到才能操作资源,否则等待。 Zookeeper怎么实现? 1)如图创建一个临时根节点/locks,每当有一

爱学习i的博客 281

实现分布式锁的解决方案中,你认为 Zookeeper 和 Redis哪种更好?

它获取锁的方式简单粗暴,如果获取不到锁,会不断尝试获取锁,比较消耗性能。Redis 是 AP 模型,在集群模式中由于数据的一致性会导致锁出现问题,即便使用Redlock 算法来实现,在某些复杂场景下,也无法保证其实现 100%的可靠性。不过在实际开发中使用 Redis 实现分布式锁还是比较常见,而且大部分场情况下不会遇到”极端复杂的场景“,更重要的是 Redis 性能很高,在高并发场景中比较合适。zookeeper 天生设计定位就是分布式协调,强一致性。锁的模型健壮、简单易用、适合做分布式锁。

qq_63431773的博客 114
上一篇: Java中CountDownLatch的用法
下一篇: jsp运行过程
大树叶
博客等级 码龄12年 1171粉丝 664原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值