大数据分布式常见问题zookeeper、redis和数据库的分布式锁的思想

在大数据的组织架构中,分布式的数据一致性是重中之重,当然在hadoop的生态中,保证数据一致性的常见解决方案一般是使用zookeeper进行协调锁和同步

试想一个需要购票业务场景中,在单一机器的多进程环境下下,如果进行最后一张票的购票,会非常容易出现票数为负数的情况,这个时候可以使用锁进行临界资源的锁定,以阻止其他进程的访问,通常我们在java对于同一jvm而言,jdk的lock和同步就足以保证资源的有序访问。

在单进程的系统中,当存在多个线程可以同时改变某个变量(可变共享变量)时,就需要对变量或代码块做同步,使其在修改这种变量时能够线性执行消除并发修改变量。

而同步的本质是通过锁来实现的。为了实现多个线程在一个时刻同一个代码块只能有一个线程可执行,那么需要在某个地方做个标记,这个标记必须每个线程都能看到,当标记不存在时可以设置该标记,其余后续线程发现已经有标记了则等待拥有标记的线程结束同步代码块取消标记后再去尝试设置标记。这个标记可以理解为锁。

在linux中是使用互斥量或信号量等进行标记的,关于这部分可以去查阅linux相关书籍,此处不做赘述

而在分布式集群中,此方案显然是无法达到我们的业务需求的,因为分布式集群中可能涉及众多集群的并发读取和存储,使用java的jdk锁无法达到对整个集群临界资源的有序访问分布式锁

相对于单机应用设定的单机锁,为分布式应用各节点对共享资源的排他式访问而设定的锁就是分布式锁。在分布式场景下,有很多种情况都需要实现多节点的最终一致性。比如全局发号器,分布式事务等等。

传统实现分布式锁的方案一般是利用持久化数据库(如利用InnoDB行锁,或事务,或version乐观锁),当然大部分时候可以满足大部分人的需求。而如今互联网应用的量级已经几何级别的爆发,利用诸如zookeeper,redis等更高效的分布式组件来实现分布式锁,可以提供高可用的更强壮的锁特性,在这里我们对zookeeper,redis的分布式锁进行简单的分析分布式锁的几种实现方式

1.使用redis的setnx()和expire()

2.使用redis的getset()

3.使用zookeeper的创建节点node

4.使用zookeeper的创建临时序列节点zookeeper分布式锁

ZooKeeper核心是一个精简的文件系统,它提供了一些简单的文件操作以及附加的功能 ,它的数据结构原型是一棵znode树(类似Linux的文件系统),并且它们是一些已经被构建好的块,可以用来构建大型的协作数据结构和协议 。

每个锁都需要一个路径来指定(如:/geffzhang/lock)

1.根据指定的路径, 查找zookeeper集群下的这个节点是否存在.(说明已经有锁了)

2. 如果存在, 根据查询者的一些特征数据(如ip地址/hostname), 当前的锁是不是查询者的

3. 如果不是查询者的锁, 则返回null, 说明创建锁失败

4. 如果是查询者的锁, 则把这个锁返回给查询者

5. 如果这个节点不存在, 说明当前没有锁, 那么创建一个临时节点, 并将查询者的特征信息写入这个节点的数据中, 然后返回这个锁.

根据以上五个步骤, 一个zookeeper分布式的锁就可以创建了.

创建的锁有三种状态:

1. 创建失败(null), 说明该锁被其他查询者使用了.’

2. 创建成功, 但当前没有锁住(unlocked), 可以使用

3. 创建成功, 但当前已经锁住(locked)了, 不能继续加锁.redis分布式锁

原理:

主要是使用这几个redis命令来实现:

1.setnx : 不能设置重复key

2.getset : 获取旧的值,设置新的值

3.expire : 设置key的有效期

4.del : 删除key

设置锁:

首先使用setnx命令保存一个key,value setnx(lockkey,currentTime+timeout)1

lockkey: 就是key的名称

currentTime : 时间戳(System.currentTimeMillis())

timeout : 这个锁被动释放的时间,定义在配置文件中,方便修改

如果设置成功,也就是返回1,给这个key设置有效期

expire(lockkey,timeout)1接着执行业务,如调用关单的sql

放锁

del(lockkey)1

如果设置失败,也就是返回0,代表当前有tomcat正在使用锁,还没有释放

那就获取当前锁

get(lockkey) 得到valueA1

如果

valueA!=null && currentTime (当前时间毫秒数)>valueA1

代表这个key已经超时了,

这个时候获取到这个锁的tomcat有权重新设置超时时间,也就是重新设置value

getset(lockkey,currentTime+timeout) 得到valueB1

执行完后 返回valueB,如果

valueB ==null || valueA(之前get得到的值) == valueB1

那么便是成功的获取到锁,执行获取到锁的流程

否则便结束这次定时任务总结:

Redis分布式锁,必须使用者自己间隔时间轮询去尝试加锁,当锁被释放后,存在多线程去争抢锁,并且可能每次间隔时间去尝试锁的时候,都不成功,对性能浪费很大。

Zookeeper分布锁,首先创建加锁标志文件,如果需要等待其他锁,则添加监听后等待通知或者超时,当有锁释放,无须争抢,按照节点顺序,依次通知使用者。

发表评论
留言与评论(共有 0 条评论)
   
验证码:

相关文章

推荐文章

'); })();