分布式锁执行方法、装置及系统、应用服务器和存储介质与流程

文档序号:16067545发布日期:2018-11-24 12:49阅读:166来源:国知局

本申请涉及通信技术领域,尤其涉及分布式锁执行方法、装置及系统、应用服务器和存储介质。

背景技术

在分布式环境下存在不同进程互斥地访问共享资源的问题。进程包含一个或多个线程,如果多个进程中的线程均需对共享资源进行操作,那么不同进程中线程访问共享资源时往往需要互斥访问,以防止彼此干扰。此情况下通常需要使用分布式锁。

在分布式锁中典型代表为redis,在redis中可以为一进程中的线程分配分布式锁,并且,设定分布式锁的使用时间,在该使用时间内该线程可以访问共享资源。

但是,在redis存在一些等待访问共享资源的线程,在一个线程的分布式锁超时的情况下,可能会出现两个及以上线程获得分布式锁的异常情况。

例如,redis单库环境下,线程c1的分布式锁信息在redis里用expire指令设置了失效时间,如果时间到了redis里的分布式锁便被清除,那么线程c2可能抢到分布式锁,但此时c1还未执行完毕也拥有分布式锁。便会出现线程c1和c2均拥有分布式锁。

再如,redis主从环境下,线程c1在redis的master节点a拿到分布式锁。若在master节点a把线程c1的分布式锁信息同步到slave节点b之前宕机了,则此时slave节点b成了master节点,且里面没有线程c1的分布式锁信息。此时,线程c2来抢锁也能获取分布式锁。此时线程c1和线程c2均拥有分布式锁。



技术实现要素:

鉴于此,本申请提供一种分布式锁执行方法、装置及系统、应用服务器和存储介质,可以解决多个线程同时获得分布式锁引起的共享资源出现数据不统一的问题。

为了实现上述目的,本申请提供了下述技术特征:

一种分布式锁执行方法,应用于应用服务器的进程中需访问同一共享资源的多个线程,所述分布式锁执行方法包括:

线程利用从缓存服务器获取的当前时间生成唯一的时间标识,向所述缓存服务器发送包括分布式锁信息的加锁指令;其中,所述分布锁信息包括所述当前标识;

接收所述缓存服务器发送的与所述加锁指令对应的返回结果;

若所述返回结果表示该线程获得分布式锁,则该线程访问共享资源并执行与所述共享资源对应的任务操作;

该线程在与所述共享资源对应的执行任务操作结束后,仅在本地存储的分布式锁信息中时间戳与所述缓存服务器存储的分布式锁信息中时间标识一致的情况下,才释放所述分布式锁;

若所述返回结果表示该线程未获得分布式锁,则该线程执行抢锁操作。

可选的,所述线程利用从缓存服务器获取的当前时间生成唯一的时间标识,包括:

该线程发送时间戳获取指令至所述缓存服务器;

该线程获取所述缓存服务器反馈的返回值;其中,所述返回值包括所述缓存服务器的当前时间,以及,当前这一秒已经逝去的微秒数值;

该线程将所述当前时间与所述微秒数值组成当前时间戳,该当前时间戳即为所述时间标识。

可选的,在向所述缓存服务器发送包括分布式锁信息的加锁指令之前,还包括:

构建以分布式锁标识作为键,以所述时间标识作为值的键值对;

生成并存储包括所述键值对的分布式锁信息。

可选的,在向所述缓存服务器发送包括分布式锁信息的加锁指令之前,还包括:

设置与分布式锁对应的使用时间;

构建以分布式锁标识作为键,以所述时间标识和所述使用时间的时间戳和值作为值的键值对;或者,构建以分布式锁标识作为键,以所述时间标识的字符串和所述使用时间的字符串的合并字符串作为值的键值对;

生成并存储包括所述键值对的分布式锁信息。

可选的,所述该线程仅在本地存储的分布式锁信息中时间戳与所述缓存服务器存储的分布式锁信息中时间标识一致的情况下,才释放所述分布式锁,包括:

该线程在执行与所述共享资源对应的任务操作结束后,发送分布式锁信息获取指令至所述缓存服务器,并接收所述缓存服务器发送的当前分布式锁信息;

判断该线程本地存储的分布式锁信息中时间标识与所述当前分布式锁信息中时间标识是否一致;

若该线程本地存储的分布式锁信息中时间标识与所述当前分布式锁信息中时间标识一致,则发送释放分布式锁指令至所述缓存服务器,以供所述缓存服务器删除所述当前分布式锁信息。

可选的,还包括:

若该线程本地存储的分布式锁信息中时间标识与所述当前分布式锁信息中时间标识不一致,则该线程抛出异常提示消息,以触发回滚机制对该线程执行回滚操作使该线程回滚到获得分布式锁之前的最近状态。

可选的,所述该线程执行抢锁操作,包括:

判断当前占用分布式锁的线程是否超时;

若当前占用分布式锁的线程超时,则发送释放分布式锁指令至所述缓存服务器,以供缓存服务器删除超时线程对应的分布式锁信息;该线程进入所述线程利用从缓存服务器获取的当前时间生成唯一的时间标识,向所述缓存服务器发送包括分布式锁信息的加锁指令的步骤;

若当前占用分布式锁的线程未超时,则重新进入判断当前占用分布式锁的线程是否超时步骤。

可选的,所述分布式锁信息包括时间标识;则所述判断当前占用分布式锁的线程是否超时,包括:

发送分布式锁信息获取指令至所述缓存服务器,并接收所述缓存服务器发送的分布式锁信息、当前时间和分布式锁的使用时间;

计算所述当前时间与所述分布式锁信息中时间标识的差值;

若所述差值是否大于所述使用时间,则表示当前占用分布式锁的线程超时;

若所述差值不大于所述使用时间,则表示当前占用分布式锁的线程未超时。

可选的,分布式锁信息包括以分布式锁标识作为键,以所述时间标识和所述使用时间的时间戳和值作为值的键值对,则所述判断当前占用分布式锁的线程是否超时包括:

发送分布式锁信息获取指令至缓存服务器,并接收所述缓存服务器发送的分布式锁信息和当前时间;

从所述分布式锁信息中提取出时间戳和值;

判断所述当前时间是否大于所述时间戳和值;

若是,表示当前占用分布式锁的线程超时;

若否则表示当前占用分布式锁的线程未超时。

可选的,所述分布式锁信息包括以分布式锁标识作为键,以所述时间标识的字符串和所述使用时间的字符串的合并字符串,则所述判断当前占用分布式锁的线程是否超时包括:

发送分布式锁信息获取指令至缓存服务器,并接收所述缓存服务器发送的分布式锁信息和当前时间;

计算所述当前时间与分布式锁信息中时间标识的差值;

若所述差值大于所述使用时间,则确定当前占用分布式锁的线程超时;

若所述差值不大于所述使用时间,则确定当前占用分布式锁的线程未超时。

一种分布式锁执行装置,集成于应用服务器的进程中需访问同一共享资源的多个线程,所述分布式锁执行装置包括:

加锁单元,用于线程利用从缓存服务器获取的当前时间生成唯一的时间标识,向所述缓存服务器发送包括分布式锁信息的加锁指令;其中,所述分布锁信息包括所述当前标识;

接收单元,用于接收所述缓存服务器发送的与所述加锁指令对应的返回结果;

访问单元,用于若所述返回结果表示该线程获得分布式锁,则该线程访问共享资源并执行与所述共享资源对应的任务操作;

释放单元,用于该线程在与所述共享资源对应的执行任务操作结束后,仅在本地存储的分布式锁信息中时间戳与所述缓存服务器存储的分布式锁信息中时间标识一致的情况下,才释放所述分布式锁;

抢锁单元,用于若所述返回结果表示该线程未获得分布式锁,则该线程执行抢锁操作。

可选的,所述加锁单元中所述线程利用从缓存服务器获取的当前时间生成唯一的时间标识,具体包括:

时间戳获取指令发送单元,用于该线程发送时间戳获取指令至所述缓存服务器;

反馈单元,用于该线程获取所述缓存服务器反馈的返回值;其中,所述返回值包括所述缓存服务器的当前时间,以及,当前这一秒已经逝去的微秒数值;

组成单元,用于该线程将所述当前时间与所述微秒数值组成当前时间戳,该当前时间戳即为所述时间标识。

可选的,在向所述缓存服务器发送包括分布式锁信息的加锁指令之前,还包括生成分布式锁信息单元。

可选的,分布式锁信息单元,包括:第一构建键值对单元,用于构建以分布式锁标识作为键,以所述时间标识作为值的键值对;第一生成并存储单元,用于生成并存储包括所述键值对的分布式锁信息。

可选的,分布式锁信息单元,包括:

第二构建键值对单元,用于设置与分布式锁对应的使用时间;构建以分布式锁标识作为键,以所述时间标识和所述使用时间的时间戳和值作为值的键值对;或者,构建以分布式锁标识作为键,以所述时间标识的字符串和所述使用时间的字符串的合并字符串作为值的键值对;第二生成并存储单元,用于生成并存储包括所述键值对的分布式锁信息。

可选的,所述释放单元,具体包括:

分布式锁信息获取单元,用于该线程在执行与所述共享资源对应的任务操作结束后,发送分布式锁信息获取指令至所述缓存服务器,并接收所述缓存服务器发送的当前分布式锁信息;

判断单元,用于判断该线程本地存储的分布式锁信息中时间标识与所述当前分布式锁信息中时间标识是否一致;

释放分布式锁指令发送单元,用于若该线程本地存储的分布式锁信息中时间标识与所述当前分布式锁信息中时间标识一致,则发送释放分布式锁指令至所述缓存服务器,以供所述缓存服务器删除所述当前分布式锁信息。

可选的,还包括:

回滚单元,用于若该线程本地存储的分布式锁信息中时间标识与所述当前分布式锁信息中时间标识不一致,则该线程抛出异常提示消息,以触发回滚机制对该线程执行回滚操作使该线程回滚到获得分布式锁之前的最近状态。

可选的,所述抢锁单元用于所述该线程执行抢锁操作,具体包括:

判断超时单元,用于判断当前占用分布式锁的线程是否超时;

释放分布式锁单元,用于若当前占用分布式锁的线程超时,则发送释放分布式锁指令至所述缓存服务器,以供缓存服务器删除超时线程对应的分布式锁信息;该线程进入所述线程利用从缓存服务器获取的当前时间生成唯一的时间标识,向所述缓存服务器发送包括分布式锁信息的加锁指令的步骤;若当前占用分布式锁的线程未超时,则重新进入判断超时单元。

可选的,所述分布式锁信息包括时间标识;则判断超时单元用于所述判断当前占用分布式锁的线程是否超时,具体包括:

获取分布式锁信息单元,用于获取发送分布式锁信息获取指令至所述缓存服务器,并接收所述缓存服务器发送的分布式锁信息、当前时间和分布式锁的使用时间;

计算差值单元,用于计算所述当前时间与所述分布式锁信息中时间标识的差值;

确定单元,用于若所述差值是否大于所述使用时间,则表示当前占用分布式锁的线程超时;若所述差值不大于所述使用时间,则表示当前占用分布式锁的线程未超时。

可选的,分布式锁信息包括以分布式锁标识作为键,以所述时间标识和所述使用时间的时间戳和值作为值的键值对,则判断超时单元用于所述判断当前占用分布式锁的线程是否超时,具体包括:

分布式锁信息获取单元,用于发送分布式锁信息获取指令至缓存服务器,并接收所述缓存服务器发送的分布式锁信息和当前时间;

提取单元,用于从所述分布式锁信息中提取出时间戳和值;

判断单元,用于判断所述当前时间是否大于所述时间戳和值;

确定单元,用于若是,表示当前占用分布式锁的线程超时;若否则表示当前占用分布式锁的线程未超时。

可选的,所述分布式锁信息包括以分布式锁标识作为键,以所述时间标识的字符串和所述使用时间的字符串的合并字符串,则判断超时单元用于所述判断当前占用分布式锁的线程是否超时,具体包括:

分布式锁信息获取单元,用于发送分布式锁信息获取指令至缓存服务器,并接收所述缓存服务器发送的分布式锁信息和当前时间;

计算差值单元,用于计算所述当前时间与分布式锁信息中时间标识的差值;

确定单元,用于若所述差值大于所述使用时间,则确定当前占用分布式锁的线程超时;若所述差值不大于所述使用时间,则确定当前占用分布式锁的线程未超时。

一种分布式锁执行系统,包括缓存服务器,和,与所述缓存服务器相连的一个或多个应用服务器;应用服务器的进程包括需访问同一共享资源的多个线程;

所述应用服务器进程中的线程,用于线程利用从缓存服务器获取的当前时间生成唯一的时间标识,向所述缓存服务器发送包括分布式锁信息的加锁指令;其中,所述分布锁信息包括所述当前标识;接收所述缓存服务器发送的与所述加锁指令对应的返回结果;若所述返回结果表示该线程获得分布式锁,则该线程访问共享资源并执行与所述共享资源对应的任务操作;该线程在与所述共享资源对应的执行任务操作结束后,仅在本地存储的分布式锁信息中时间戳与所述缓存服务器存储的分布式锁信息中时间标识一致的情况下,才释放所述分布式锁;若所述返回结果表示该线程未获得分布式锁,则该线程执行抢锁操作。

一种应用服务器,包括:

处理器,用于线程利用从缓存服务器获取的当前时间生成唯一的时间标识,向所述缓存服务器发送包括分布式锁信息的加锁指令;其中,所述分布锁信息包括所述当前标识;接收所述缓存服务器发送的与所述加锁指令对应的返回结果;若所述返回结果表示该线程获得分布式锁,则该线程访问共享资源并执行与所述共享资源对应的任务操作;该线程在与所述共享资源对应的执行任务操作结束后,仅在本地存储的分布式锁信息中时间戳与所述缓存服务器存储的分布式锁信息中时间标识一致的情况下,才释放所述分布式锁;若所述返回结果表示该线程未获得分布式锁,则该线程执行抢锁操作;

存储器,用于存储所述分布式锁信息。

一种存储介质,其上存储有计算机程序,所述计算机程序被处理器执行,实现分布式锁执行方法的各步骤。

通过以上技术手段,可以实现以下有益效果:

本申请中线程在发送加锁指令至缓存服务器并且获得分布式锁时,缓存服务器会存储该线程对应的分布式锁信息。

在该线程访问共享资源并执行任务操作结束后,并不会直接释放分布式锁,而是会基于分布式锁信息来判断分布式锁是否仍然是本线程的;若该线程的分布锁所信息与当前分布式锁信息一致,则表示分布式锁仍然是本线程的;否则表示该线程的分布式锁被其它线程抢占。

为了保证共享资源的统一性,该线程在发现其它线程占用分布式锁后,会抛出异常以触发回滚机制,从而保证共享数据的一致性。

附图说明

为了更清楚地说明本申请实施例或现有技术中的技术方案,下面将对实施例或现有技术描述中所需要使用的附图作简单地介绍,显而易见地,下面描述中的附图仅仅是本申请的一些实施例,对于本领域普通技术人员来讲,在不付出创造性劳动的前提下,还可以根据这些附图获得其他的附图。

图1为本申请实施例公开的一种分布式锁执行系统的结构示意图;

图2为本申请实施例公开的一种分布式锁执行方法的流程图;

图3为本申请实施例公开的一种分布式锁执行方法的流程图;

图4为本申请实施例公开的一种分布式锁执行装置的结构示意图。

具体实施方式

下面将结合本申请实施例中的附图,对本申请实施例中的技术方案进行清楚、完整地描述,显然,所描述的实施例仅仅是本申请一部分实施例,而不是全部的实施例。基于本申请中的实施例,本领域普通技术人员在没有做出创造性劳动前提下所获得的所有其他实施例,都属于本申请保护的范围。

术语解释:

redis:一个开源的使用ansic语言编写、支持网络、可基于内存亦可持久化的日志型、key-value数据库,并提供多种语言的应用程序接口。

锁:核心是协调各个使用方对共享资源使用的一种机制。当存在多个使用方互斥地使用某一个公共资源时,为了避免并行使用导致的修改结果不可控,需要在某个地方记录一个标记。这个标记能够被所有使用方看到,当标记不存在时,可以设置标记并且获得公共资源的使用权,其余使用者发现标记已经存在时,只能等待标记拥有方释放后,再去尝试设置标记。这个标记即可以理解为锁。

分布式锁:是控制分布式系统之间多个使用方同步访问共享资源的一种方式。若多个使用方共享一个或一组资源,那么访问这些资源的时候,往往需要互斥访问共享资源,以防止彼此干扰从而保证共享资源的一致性,在这种情况下,便需要使用到分布式锁。

为了便于本领域技术人员了解,下面介绍分布式锁执行系统。参见图1,分布式锁执行系统包括:缓存服务器100,与缓存服务器100相连的一个或多个应用服务器200(图示中以三个应用服务器为例,分别采用应用服务器201、应用服务器202、应用服务器203表示),与缓存服务器100相连的数据库设备300。

缓存服务器100可以实现分布式锁,数据库设备300可以存储共享资源。其中,缓存服务器100可以采用redis技术来实现分布式锁,当然也可以采用memcached、tair等技术来实现分布式锁,在此不做限定。

一个或多个应用服务器200中的多个线程中可以向缓存服务器100申请分布式锁。获得分布式锁的线程可以访问数据库设备300存储的共享资源。

下面介绍分布式锁执行方法,应用于分布式锁执行系统,分布式锁执行系统的应用服务器的进程包括需访问同一共享资源的多个线程。由于一个或多个应用服务器200中多个线程的执行过程是一致的,在此以一个应用服务器中一个线程为例,对分布式锁执行方法进行描述。

根据本申请提供的一个实施例,提供一种分布式锁执行方法的实施例。参见图2,包括以下执行步骤:

线程利用从缓存服务器获取的当前时间生成唯一的时间标识,向所述缓存服务器发送包括分布式锁信息的加锁指令;其中,所述分布锁信息包括所述当前标识。本过程可以采用下述步骤s201~s206来实现。

其中,所述线程利用从缓存服务器获取的当前时间生成唯一的时间标识包括:该线程发送时间戳获取指令至所述缓存服务器;该线程获取所述缓存服务器反馈的返回值;其中,所述返回值包括所述缓存服务器的当前时间,以及,当前这一秒已经逝去的微秒数值;该线程将所述当前时间与所述微秒数值组成当前时间戳,该当前时间戳即为所述时间标识。本过程可以采用步骤s202~s204来实现。

步骤s201:应用服务器200中线程在确定需访问共享资源后,设置共享资源对应分布式锁的使用时间。

应用服务器200中线程在确定自身需要访问缓存服务器100的共享资源的情况下,可以根据自身访问共享资源的情况,设置共享资源对应的分布式锁的使用时间。使用时间的长短与具体进程对应的应用场景有关,在此不做限定。

步骤s202:应用服务器200中线程发送时间戳获取指令至缓存服务器100。

为了统一各个应用服务器的时间戳,本实施中应用服务器200中线程可以采用redis的lua脚本来获取缓存服务器100的时间戳,脚本内容可以为:locala=redis.call('time')。

步骤s203:缓存服务器100提取当前时间并发送返回值至应用服务器200中线程。

其中,返回值包含两个字符串,第一个字符串是当前时间(以unix时间戳格式表示),第二个字符串是当前这一秒钟已经逝去的微秒数值。

例如,返回值a[1]="1332395997",a[2]="952581";其中,"1332395997"为缓存服务器提取的当前时间,"952581"为当前这一秒钟已经逝去的微秒数值。

步骤s204:应用服务器200中线程基于返回值计算当前时间戳。

可以理解的是,将返回值中两个字符串进行叠加可以得到当前时间戳。

脚本内容如下:return(a[1]*1000000+a[2])。在上述举例下,当前时间戳为:a="1332395997952581"。

步骤s202~s204的有益效果在于:

本实施例中统一采用缓存服务器100的时间戳,而不是应用服务器200自身的时间戳,这样可以保证各个应用服务器200上的时间戳的一致性。

相对于现有技术中各个应用服务器采用同步操作来统一时间戳而言(同步操作一般只能精确到毫秒级别),本实施例可以避免同步操作,具有更好的操作性和实用性。并且,按照本方式获取到的时间戳可以精确到微秒级别,提高时间戳的准确性和一致性。

步骤s205:应用服务器200中线程构建一个键值对。

在向所述缓存服务器发送包括分布式锁信息的加锁指令之前,还包括构建一个键值对。本申请提供构建键值对的两种实现方式:

第一种实现方式:构建以分布式锁标识作为键,以所述时间标识作为值的键值对;也即,键(key)为分布式锁标识,值(value)为当前时间戳。

第二种实现方式:构建以分布式锁标识作为键,以所述时间标识和所述使用时间的时间戳和值作为值的键值对;也即,键(key)为分布式锁标识,值(value)为当前时间戳和使用时间组成时间戳和值。

或者,构建以分布式锁标识作为键,以所述时间标识的字符串和所述使用时间的字符串的合并字符串作为值的键值对;也即,键(key)为分布式锁标识,值(value)为当前时间戳字符串以及使用时间字符串的串联字符串。

按照第一种实现方式和第二种实现方式构建键值对后,生成并存储包括所述键值对的分布式锁信息。

步骤s206:应用服务器200中线程向缓存服务器100发送加锁指令。也即,应用服务器200中线程向缓存服务器100发送包含分布式锁信息的加锁指令。

应用服务器200中线程采用redissetkeyifnotexist指令实现加锁操作。加锁指令包括分布式锁信息的加锁指令,分布式锁信息为键值对。步骤s207:缓存服务器100接收加锁指令,并发送加锁指令的返回结果至应用服务器200中线程。

缓存服务器100在接收加锁指令后,判断是否有分布式锁标识对应的分布式锁,若有,则反馈表示未加锁成功的返回结果。若无则存储键值对,并反馈表示加锁成功的返回结果。

若所述返回结果表示该线程获得分布式锁,则该线程访问共享资源并执行与所述共享资源对应的任务操作。该步骤可以采用步骤s208~s209来实现。

步骤s208:应用服务器200中线程判断返回结果是否为加锁成功,若是则进入步骤s209;若否则进入步骤s215。

步骤s209:应用服务器200中线程确定返回结果为加锁成功,则通过缓存服务器100访问数据库设备300的共享资源,并利用获取到共享资源执行任务操作。

应用服务器200中线程确定返回结果为加锁成功,则表示该线程可以在使用时间内通过缓存服务器100访问数据库设备300的共享资源,并利用获取到的共享资源,来执行与所述共享资源对应的任务操作。

关于任务操作的具体实现,与具体应用场景有关,在此不做限定。

该线程在与所述共享资源对应的执行任务操作结束后,仅在本地存储的分布式锁信息中时间戳与所述缓存服务器存储的分布式锁信息中时间标识一致的情况下,才释放所述分布式锁。本过程具体包括下述详细过程:

该线程在执行与所述共享资源对应的任务操作结束后,发送分布式锁信息获取指令至所述缓存服务器,并接收所述缓存服务器发送的当前分布式锁信息;

判断该线程本地存储的分布式锁信息中时间标识与所述当前分布式锁信息中时间标识是否一致;

若该线程本地存储的分布式锁信息中时间标识与所述当前分布式锁信息中时间标识一致,则发送释放分布式锁指令至所述缓存服务器,以供所述缓存服务器删除所述当前分布式锁信息。

此外,若该线程本地存储的分布式锁信息中时间标识与所述当前分布式锁信息中时间标识不一致,则该线程抛出异常提示消息,以触发回滚机制对该线程执行回滚操作使该线程回滚到获得分布式锁之前的最近状态。上述过程可以采用步骤s210~s214来实现。

步骤s210:应用服务器200中线程在访问共享资源并执行任务操作结束后,发送分布式锁信息获取指令至缓存服务器100。

在应用服务器200利用获取到的共享资源执行任务操作结束后,便可以释放分布式锁,在释放分布式锁之前先获取当前分布式锁信息,以基于当前分布式锁信息判断本线程是否仍然占有分布式锁。

步骤s211:缓存服务器100获取当前分布式锁信息,并发送当前分布式锁信息至应用服务器200中线程。

在应用服务器200中线程执行访问共享资源并执行任务操作过程中,可能会出现异常情况,此时可能会出现该线程超时使用分布式锁的问题;在该线程超时后,分布式锁可能被其它线程抢占,此时缓存服务器会存储其它线程的分布式信息(分布式锁标识均是一致的,不同的是时间戳)。

通过前面描述可知,分布式锁信息包括分布式锁的键值对。

步骤s212:应用服务器200中线程将用于加锁指令中的时间戳与分布式锁信息中的时间戳进行对比;若一致,则进入步骤s213;若不一致则进入步骤s214。

可以理解的是,在分布式锁未被其它线程所抢占的情况下,缓存服务器100中分布式锁信息仍然是该线程的,其标志性特征便是时间戳应该仍然为该线程的时间戳。

分布式锁在释放时要求解铃还须系铃人,即,在正常释放分布式锁情况下,该线程仅能释放本线程添加的分布式锁。因此,在释放分布式锁之前,先判断分布式锁是否仍然是本线程的。即,将该线程用于加锁指令中的时间戳与当前分布式锁信息中的时间戳进行对比。

若时间戳一致,则表示分布式锁仍然是本线程的,未被其它线程抢占。若不一致,则该线程可以发现分布式锁已经不是本线程的,已被其它线程抢占。

步骤s213:若一致,则向缓存服务器100发送释放分布式锁指令。

若一致则表示分布式锁还属于本线程,可以向缓存服务器100发送释放分布式锁指令,以便释放分布式锁,以供其它线程抢占分布式锁。

缓存服务器100接收分布式锁指令后,会删除分布式锁标识对应的分布式锁信息。也即,删除本条时间戳对应的分布式锁信息。

步骤s214:若不一致,则抛出系统异常,以触发回滚机制。

若不一致则表示该分布式锁不是该线程的,此时本线程不能释放其它线程添加的分布式锁。即,在该线程结束任务操作之前,该线程发生一些异常情况,导致该线程占用分布式锁超出使用时间,所以分布式锁锁已经被其它线程所抢占。

由于其它线程持续在判断分布式锁是否超时,所以在该线程占用分布式锁超时情况下,便会被其它线程释放分布式锁(此时释放分布式锁时属于异常情况,所以其它线程可以直接释放该线程的分布式锁,无需步骤s212中验证时间戳是否一致)。

由于该线程超时使用了分布式锁,为了保证共享资源的一致性操作,此时该线程抛出系统异常,将共享资源恢复到该线程占用分布式锁之前的状态。

步骤s210~s214可以实现的有益效果:

如果某个线程获取分布式锁后执行超时的话:如果没有其他线程过来抢锁,则能正常执行并释放锁,因为redis里的分布式锁信息没被删除;如果有其他线程已经抢锁则能够弹出异常(现有技术无法发现异常)。此时,该线程无法正常释放锁,而是抛出异常以触发回滚操作,从而保证共享资源的一致性。

此外,步骤s210~s214还可以巧妙的解决redis主从或集群下分布式锁的容错性问题;以背景技术slave节点里存储的分布式锁信息是线程c1的情况为例,在线程c0释放分布式锁时,会发现线程c0持有的分布式锁信息和slave节点里的不符,所以线程c0被当做超时情况进行回滚处理。因此,本申请支持通过redis主从或者集群来实现分布式锁。

若服务器发送的与所述加锁指令对应的返回结果,表示该线程未获得分布式锁,则该线程执行抢锁操作。

关于该线程执行抢锁操作具体包括:判断当前占用分布式锁的线程是否超时;若当前占用分布式锁的线程超时,则发送释放分布式锁指令至所述缓存服务器,以供缓存服务器删除超时线程对应的分布式锁信息;该线程进入所述线程利用从缓存服务器获取的当前时间生成唯一的时间标识,向所述缓存服务器发送包括分布式锁信息的加锁指令的步骤;若当前占用分布式锁的线程未超时,则重新进入判断当前占用分布式锁的线程是否超时步骤。

上述过程可以采用步骤s215~s218来实现。

接步骤s208进入步骤s215:应用服务器200中线程确定返回结果未加锁成功,则发送分布式锁信息获取指令至缓存服务器100。

步骤s216:缓存服务器100获取当前分布式锁信息,并发送当前分布式锁信息至应用服务器200中线程。

持有分布式锁的线程在加锁成功后添加分布式锁信息至缓存服务器100。

相对于步骤s206而言,分布式锁信息也具有三种实现方式:

第一种实现方式:分布式锁所信息包括键值对。

加锁指令包括键值对,键(key)为分布式锁标识,值(value)为当前时间戳。使用时间默认采用预先之前设定使用时间。

第二种实现方式:分布式锁所信息包括键值对。

相比于第一种实现方式而言,加锁指令的键值对中融合了使用时间。可以理解的是,不同线程的使用时间可以根据实际场景而定,所以适应度比较高。

值(value)为当前时间戳+使用时间组成的时间戳,或者,当前时间戳和使用时间组成的字符串。

步骤s217:应用服务器200中线程基于当前分布式锁信息判断当前持有分布式锁的线程是否超期。若是则进入步骤s218,若否则进入步骤s202。

对于第一种实现方式而言,发送分布式锁信息获取指令至所述缓存服务器,并接收所述缓存服务器发送的分布式锁信息、当前时间和分布式锁的使用时间;计算所述当前时间与所述分布式锁信息中时间标识的差值;若所述差值是否大于所述使用时间,则表示当前占用分布式锁的线程超时;若所述差值不大于所述使用时间,则表示当前占用分布式锁的线程未超时。

也即,应用服务器200中线程计算当前时间戳与分布式锁信息中时间戳的差值,并判断差值是否大于使用时间。若是,则表示当前持有分布式锁的线程已经超期;若否则表示当前持有分布式锁的线程未超期。

对于第二种实现方式而言,还可以细分两类。

第一类:分布式锁信息包括以分布式锁标识作为键,以所述时间标识和所述使用时间的时间戳和值作为值的键值对,则判断当前占用分布式锁的线程是否超时的步骤包括:

发送分布式锁信息获取指令至缓存服务器,并接收所述缓存服务器发送的分布式锁信息和当前时间;从所述分布式锁信息中提取出时间戳和值;判断所述当前时间是否大于所述时间戳和值;若是,表示当前占用分布式锁的线程超时;若否则表示当前占用分布式锁的线程未超时。

第二类:分布式锁信息包括以分布式锁标识作为键,以所述时间标识的字符串和所述使用时间的字符串的合并字符串,则判断当前占用分布式锁的线程是否超时的步骤包括:

发送分布式锁信息获取指令至缓存服务器,并接收所述缓存服务器发送的分布式锁信息和当前时间;计算所述当前时间与分布式锁信息中时间标识的差值;若所述差值大于所述使用时间,则确定当前占用分布式锁的线程超时;若所述差值不大于所述使用时间,则确定当前占用分布式锁的线程未超时。

也即,应用服务器200中线程直接判断当前时间戳是否大于分布式锁信息中时间戳(分布式锁信息中键值对的值即为时间戳,也即为该线程的超期时间),若大于,则表示当前持有分布式锁的线程已经超期;若否则表示当前持有分布式锁的线程未超期。

步骤s218:应用服务器200中线程发送释放分布式锁指令至缓存服务器100,进入步骤s202。

若当前持有分布式锁的线程已经超期则表示此时死锁发生,所以,应用服务器200中线程发送删除指令至缓存服务器100。缓存服务器100直接删除该分布式锁。应用服务器200中线程会重新确定当前时间戳并执行加锁操作。

本实施例中,缓存服务器自身不再清除超时的线程,而是由线程来发现超时线程,从而向缓存服务器发送释放指令,以便缓存服务器接收清除指令后删除自身存储的已超时线程对应的分布式锁信息。

通过上述描述,可以发现本实施例具有以下有益效果:

第一,持有分布式锁的线程超时的情况下,抛出系统异常,以触发回滚机制,从而保证共享资源的一致性。

第二,本实施例中统一采用缓存服务器的时间戳,而不是各个应用服务器使用自身的时间戳,可以保证各个应用服务器上的时间戳的一致性。并且,也可以避免各个应用服务器的时间戳同步操作,具有更好的操作性和实用性。并且,按照本方式获取到的时间戳可以精确到微秒级别,提高时间戳的准确性和一致性,为后续分布式锁的执行提供统一时间戳。

第三,本申请可以巧妙的解决redis主从或集群下分布式锁的容错性;对于背景技术中线程c0和线程c1均抢到分布式锁,但是最终在slave节点里存储的分布式锁信息是线程c1的情况,在线程c0释放分布式锁时,会发现线程c0持有的分布式锁信息和slave节点里的不符,所以线程c0会被当做超时情况进行回滚处理。因此,本申请支持通过redis主从或者集群来实现分布式锁。

第四,不论是在主从的分布式环境中还是在集群的分布式环境中多个线程可能获得分布式锁情况下,本实施例在缓存服务器中添加分布式信息后,便能始终保证缓存服务器中同一时刻仅存在一条分布式锁信息,且,该分布式锁信息中的时间戳决定该分布式锁信息仅对应一个线程。

第五,在持有分布式锁的线程正常情况下,其余线程无法获得分布式锁。在持有分布式锁的线程超时的情况下,下一个来抢锁的线程在抢锁失败后,会释放该超时的锁。然后加入抢锁大军和其他线程继续公平的竞争锁。

参见图3,下面介绍本申请的一个应用实例,以redis实现分布式锁为例:

1)初始化一个分布式锁,并设置锁超时时间timeout。

2)加锁时,先通过lua脚本获取redis服务器当前的时间戳,再创建一个key为lockname的项目,value为之前获取到的时间戳。

3)开始抢锁流程,先执行redis指令setnxkey时间戳,如果返回1则表示抢到锁,然后执行业务代码;若返回0则表示未抢到锁继续等待锁作。

3)等待锁时,先判断当前存在的分布式锁是否超时。如果超时,则释放锁,然后进行抢锁操作;如果未超时,则直接继续去抢锁。

5)当本任务运行完成之后,进行释放锁操作。

释放锁操作是删除redis中key为lockname的项目,只有当value等于当前锁对象里保存的时间戳才进行删除操作,否则说明锁超时已被释放,需抛出异常做回滚操作。

如果某个进程获取分布式锁后执行超时的话:如果这时没有其他进程过来抢锁,则能正常执行并释放锁,因为redis里的锁记录没被清除;如果有其他进程过来抢锁,则无法正常释放锁,此时无法释放锁,会按超时进行回滚处理。

本实施例中线程执行的软件方法可以理解成是一个中间件,以第三方引入包的形式向外提供。所谓中间件就是非业务的技术类组件。以java语言为例,java应用程序可以引入第三方的jar包直接使用而不用关心其内部的细节。线程执行的软件方法可以单独制作成一个jar包,以供任何java应用程序调用。

当然,也可以将线程执行的软件方法组成一个在线中间件。以web服务的形式发布出来,其他应用程序以http的形式来调用;或者以socket的形式发布出来,其他应用以tcp的形式来调用。本申请不限定线程执行的软件方法的实现形式。

根据本申请提供的一个实施例,提供一种分布式锁执行装置。参见图4,分布式锁执行装置包括:

加锁单元41,用于线程利用从缓存服务器获取的当前时间生成唯一的时间标识,向所述缓存服务器发送包括分布式锁信息的加锁指令;其中,所述分布锁信息包括所述当前标识。

其中,加锁单元41包括:

时间戳获取指令发送单元411,用于该线程发送时间戳获取指令至所述缓存服务器;

反馈单元412,用于该线程获取所述缓存服务器反馈的返回值;其中,所述返回值包括所述缓存服务器的当前时间,以及,当前这一秒已经逝去的微秒数值;

组成单元413,用于该线程将所述当前时间与所述微秒数值组成当前时间戳,该当前时间戳即为所述时间标识。

在向所述缓存服务器发送包括分布式锁信息的加锁指令之前,还包括生成分布式锁信息两种实现方式:

第一种实现方式:第一构建键值对单元,用于构建以分布式锁标识作为键以所述时间标识作为值的键值对。第一生成并存储单元,用于生成并存储包括所述键值对的分布式锁信息。

第二种实现方式:第二构建键值对单元,用于设置与分布式锁对应的使用时间;构建以分布式锁标识作为键,以所述时间标识和所述使用时间的时间戳和值作为值的键值对;或者,构建以分布式锁标识作为键,以所述时间标识的字符串和所述使用时间的字符串的合并字符串作为值的键值对;第二生成并存储单元,生成并存储包括所述键值对的分布式锁信息。

接收单元42,用于接收所述缓存服务器发送的与所述加锁指令对应的返回结果。

访问单元43,用于若所述返回结果表示该线程获得分布式锁,则该线程访问共享资源并执行与所述共享资源对应的任务操作。

释放单元44,用于该线程在与所述共享资源对应的执行任务操作结束后,仅在本地存储的分布式锁信息中时间戳与所述缓存服务器存储的分布式锁信息中时间标识一致的情况下,才释放所述分布式锁。

其中释放单元44,具体包括:

分布式锁信息获取单元441,用于该线程在执行与所述共享资源对应的任务操作结束后,发送分布式锁信息获取指令至所述缓存服务器,并接收所述缓存服务器发送的当前分布式锁信息。

判断单元442,用于判断该线程本地存储的分布式锁信息中时间标识与所述当前分布式锁信息中时间标识是否一致。

释放分布式锁指令发送单元443,用于若该线程本地存储的分布式锁信息中时间标识与所述当前分布式锁信息中时间标识一致,则发送释放分布式锁指令至所述缓存服务器,以供所述缓存服务器删除所述当前分布式锁信息。

回滚单元45,用于若该线程本地存储的分布式锁信息中时间标识与所述当前分布式锁信息中时间标识不一致,则该线程抛出异常提示消息,以触发回滚机制对该线程执行回滚操作使该线程回滚到获得分布式锁之前的最近状态。

抢锁单元46,用于若所述返回结果表示该线程未获得分布式锁,则该线程执行抢锁操作。其中,抢锁单元46具体包括:

判断超时单元461,用于判断当前占用分布式锁的线程是否超时;若当前占用分布式锁的线程未超时,则重新进入判断当前占用分布式锁的线程是否超时步骤。

释放分布式锁单元462,用于若当前占用分布式锁的线程超时,则发送释放分布式锁指令至所述缓存服务器,以供缓存服务器删除超时线程对应的分布式锁信息;该线程进入加锁单元41执行线程利用从缓存服务器获取的当前时间生成唯一的时间标识,向所述缓存服务器发送包括分布式锁信息的加锁指令的步骤。

在所述分布式锁信息包括时间标识情况下;则所述判断当前占用分布式锁的线程是否超时,包括:

发送分布式锁信息获取指令至所述缓存服务器,并接收所述缓存服务器发送的分布式锁信息、当前时间和分布式锁的使用时间;计算所述当前时间与所述分布式锁信息中时间标识的差值;若所述差值是否大于所述使用时间,则表示当前占用分布式锁的线程超时;若所述差值不大于所述使用时间,则表示当前占用分布式锁的线程未超时。

在分布式锁信息包括以分布式锁标识作为键,以所述时间标识和所述使用时间的时间戳和值作为值的键值对情况下,则所述判断当前占用分布式锁的线程是否超时包括:

发送分布式锁信息获取指令至缓存服务器,并接收所述缓存服务器发送的分布式锁信息和当前时间;从所述分布式锁信息中提取出时间戳和值;判断所述当前时间是否大于所述时间戳和值;若是,表示当前占用分布式锁的线程超时;若否则表示当前占用分布式锁的线程未超时。

在所述分布式锁信息包括以分布式锁标识作为键,以所述时间标识的字符串和所述使用时间的字符串的合并字符串情况下,则所述判断当前占用分布式锁的线程是否超时包括:

发送分布式锁信息获取指令至缓存服务器,并接收所述缓存服务器发送的分布式锁信息和当前时间;计算所述当前时间与分布式锁信息中时间标识的差值;若所述差值大于所述使用时间,则确定当前占用分布式锁的线程超时;若所述差值不大于所述使用时间,则确定当前占用分布式锁的线程未超时。

关于分布式锁执行装置的具体方案,可以参见图2所示的实施例,在此不再赘述。

本申请还提供一种应用服务器,包括:

处理器,用于线程利用从缓存服务器获取的当前时间生成唯一的时间标识,向所述缓存服务器发送包括分布式锁信息的加锁指令;其中,所述分布锁信息包括所述当前标识;接收所述缓存服务器发送的与所述加锁指令对应的返回结果;若所述返回结果表示该线程获得分布式锁,则该线程访问共享资源并执行与所述共享资源对应的任务操作;该线程在与所述共享资源对应的执行任务操作结束后,仅在本地存储的分布式锁信息中时间戳与所述缓存服务器存储的分布式锁信息中时间标识一致的情况下,才释放所述分布式锁;若所述返回结果表示该线程未获得分布式锁,则该线程执行抢锁操作;

存储器,用于存储所述分布式锁信息。

处理器执行所述线程利用从缓存服务器获取的当前时间生成唯一的时间标识步骤,具体包括:该线程发送时间戳获取指令至所述缓存服务器;该线程获取所述缓存服务器反馈的返回值;其中,所述返回值包括所述缓存服务器的当前时间,以及,当前这一秒已经逝去的微秒数值;该线程将所述当前时间与所述微秒数值组成当前时间戳,该当前时间戳即为所述时间标识。

处理器在向所述缓存服务器发送包括分布式锁信息的加锁指令之前,还包括生成分布式锁信息,可以包括下述两种实现方式:

第一种实现方式:构建以分布式锁标识作为键,以所述时间标识作为值的键值对;生成并存储包括所述键值对的分布式锁信息。

第二种实现方式:设置与分布式锁对应的使用时间;构建以分布式锁标识作为键,以所述时间标识和所述使用时间的时间戳和值作为值的键值对;或者,构建以分布式锁标识作为键,以所述时间标识的字符串和所述使用时间的字符串的合并字符串作为值的键值对;生成并存储包括所述键值对的分布式锁信息。

处理器执行该线程仅在本地存储的分布式锁信息中时间戳与所述缓存服务器存储的分布式锁信息中时间标识一致的情况下,才释放所述分布式锁,具体包括:

该线程在执行与所述共享资源对应的任务操作结束后,发送分布式锁信息获取指令至所述缓存服务器,并接收所述缓存服务器发送的当前分布式锁信息;判断该线程本地存储的分布式锁信息中时间标识与所述当前分布式锁信息中时间标识是否一致;若该线程本地存储的分布式锁信息中时间标识与所述当前分布式锁信息中时间标识一致,则发送释放分布式锁指令至所述缓存服务器,以供所述缓存服务器删除所述当前分布式锁信息。

处理器,还用于若该线程本地存储的分布式锁信息中时间标识与所述当前分布式锁信息中时间标识不一致,则该线程抛出异常提示消息,以触发回滚机制对该线程执行回滚操作使该线程回滚到获得分布式锁之前的最近状态。

处理器执行该线程执行抢锁操作,具体包括:判断当前占用分布式锁的线程是否超时;若当前占用分布式锁的线程超时,则发送释放分布式锁指令至所述缓存服务器,以供缓存服务器删除超时线程对应的分布式锁信息;该线程进入所述线程利用从缓存服务器获取的当前时间生成唯一的时间标识,向所述缓存服务器发送包括分布式锁信息的加锁指令的步骤;若当前占用分布式锁的线程未超时,则重新进入判断当前占用分布式锁的线程是否超时步骤。

在所述分布式锁信息包括时间标识情况下;处理器执行所述判断当前占用分布式锁的线程是否超时过程,具体包括:

发送分布式锁信息获取指令至所述缓存服务器,并接收所述缓存服务器发送的分布式锁信息、当前时间和分布式锁的使用时间;计算所述当前时间与所述分布式锁信息中时间标识的差值;若所述差值是否大于所述使用时间,则表示当前占用分布式锁的线程超时;若所述差值不大于所述使用时间,则表示当前占用分布式锁的线程未超时。

在分布式锁信息包括以分布式锁标识作为键,以所述时间标识和所述使用时间的时间戳和值作为值的键值对情况下,处理器判断当前占用分布式锁的线程是否超时具体包括:

发送分布式锁信息获取指令至缓存服务器,并接收所述缓存服务器发送的分布式锁信息和当前时间;从所述分布式锁信息中提取出时间戳和值;判断所述当前时间是否大于所述时间戳和值;若是,表示当前占用分布式锁的线程超时;若否则表示当前占用分布式锁的线程未超时。

在所述分布式锁信息包括以分布式锁标识作为键,以所述时间标识的字符串和所述使用时间的字符串的合并字符串情况下,则所述判断当前占用分布式锁的线程是否超时包括:

发送分布式锁信息获取指令至缓存服务器,并接收所述缓存服务器发送的分布式锁信息和当前时间;计算所述当前时间与分布式锁信息中时间标识的差值;若所述差值大于所述使用时间,则确定当前占用分布式锁的线程超时;若所述差值不大于所述使用时间,则确定当前占用分布式锁的线程未超时。

本申请还提供了一种存储介质,其上存储有计算机程序,所述计算机程序被处理器执行,实现所述的分布式锁执行方法的各步骤:线程利用从缓存服务器获取的当前时间生成唯一的时间标识,向所述缓存服务器发送包括分布式锁信息的加锁指令;其中,所述分布锁信息包括所述当前标识;接收所述缓存服务器发送的与所述加锁指令对应的返回结果;若所述返回结果表示该线程获得分布式锁,则该线程访问共享资源并执行与所述共享资源对应的任务操作;该线程在与所述共享资源对应的执行任务操作结束后,仅在本地存储的分布式锁信息中时间戳与所述缓存服务器存储的分布式锁信息中时间标识一致的情况下,才释放所述分布式锁;若所述返回结果表示该线程未获得分布式锁,则该线程执行抢锁操作。

关于各个步骤的具体实现可以参见图2所示的实施例在此不再赘述。

本实施例方法所述的功能如果以软件功能单元的形式实现并作为独立的产品销售或使用时,可以存储在一个计算设备可读取存储介质中。基于这样的理解,本申请实施例对现有技术做出贡献的部分或者该技术方案的部分可以以软件产品的形式体现出来,该软件产品存储在一个存储介质中,包括若干指令用以使得一台计算设备(可以是个人计算机,服务器,移动计算设备或者网络设备等)执行本申请各个实施例所述方法的全部或部分步骤。而前述的存储介质包括:u盘、移动硬盘、只读存储器(rom,read-onlymemory)、随机存取存储器(ram,randomaccessmemory)、磁碟或者光盘等各种可以存储程序代码的介质。

本说明书中各个实施例采用递进的方式描述,每个实施例重点说明的都是与其它实施例的不同之处,各个实施例之间相同或相似部分互相参见即可。

对所公开的实施例的上述说明,使本领域专业技术人员能够实现或使用本申请。对这些实施例的多种修改对本领域的专业技术人员来说将是显而易见的,本文中所定义的一般原理可以在不脱离本申请的精神或范围的情况下,在其它实施例中实现。因此,本申请将不会被限制于本文所示的这些实施例,而是要符合与本文所公开的原理和新颖特点相一致的最宽的范围。

当前第1页1 2 
网友询问留言 已有0条留言
  • 还没有人留言评论。精彩留言会获得点赞!
1