一种基于Jedis的将多线程并发请求合并批量提交并分发结果的实现方法与流程

文档序号:14504875阅读:278来源:国知局

本发明属于数据库技术领域,尤其涉及一种基于Jedis的将多线程并发请求合并批量提交并分发结果的实现方法。



背景技术:

Redis是一种目前较流行的NoSQL数据库。Jedis是Redis官方推荐的Java客户端开发包。在单进程多线程应用中,在通过Jedis访问Redis服务器时:如果使用普通的方式访问,每个线程各自都会持有一个单独的连接,并通过各自持有的连接单独发起请求,等待响应结果。而Redis的特点是服务器端采用了单线程处理模式,即服务端只能顺序处理收到的请求。这就造成了多个客户端请求之间的相互等待,进而影响了应用的整体性能。

也可以采用另外一种方式,通过管道方式Pipeline,Pipeline适用于批处理,当有大量的操作需要一次性执行的时候,可以用Pipeline。Jedis自身已有提供Pipeline方式,该方式在客户端发送请求时是异步,下发请求后可以不等待返回接着再发送后续请求,在将请求全部发送后,再执行提交操作,然后一次性获取到之前全部请求的结果。这种方式可以通过异步提高客户端的吞吐量,但是由于多个客户端提交请求的并发操作,每个客户端都会执行自己的提交请求,而且由于服务器端只能同时处理一个客户端的请求,这样也会造成不同客户端之间执行提交请求时的相互等待,同样会影响应用整体的性能。



技术实现要素:

本发明就是为了解决类似于如上描述的这种问题,来提高应用的整体性能。本发明的总体思路是,将Jedis进程内多线程并发请求收集起来,同时通过原有底层单一连接Pipeline执行异步请求,将请求统一提交,然后再一次性获取请求的结果,最后把请求的结果分发给各个调用线程。

本发明的目的是通过以下技术方案实现的。

本发明提出了一种基于Jedis的将多线程并发请求合并批量提交并分发结果的实现方法,所述Jedis的封装包括以下模块:基本操作模块、监听器模块、唤醒器模块;其中,PipelineWrapper是基本操作模块的主类,TimerMonitor是监听器模块的主类,Notifier是唤醒器模块的主类;

所述方法包括:

客户端线程向PipelineWrapper发起请求,所述请求包括同步请求op()、异步请求opAsync()或批量提交sync()中的一种;

所述请求首先向PipelineWrapper请求全局排它锁;

获得锁之后,向底层的Pipeline发起op()、opAsync()请求或者sync()请求的其中一种;

所述op()、opAsync()请求对PipelineWrapper的操作计数属性opCount执行+1操作,一旦opCount>maxOpCount,触发批量提交sync()的执行;

释放全局排它锁;

获取结果并返回。

对于同步请求op(),每次执行都会向同步操作上报队列(respQueue)中增加一个代表该请求结果是否已经可以读取的信号量(Semaphore),该Semaphore会在批量提交sync()执行时由Notifier唤醒。所述TimerMonitor会按照设定的间隔时间,周期性地执行PipelineWrapper的批量提交方法sync(),触发底层批量提交的执行。

当所述请求是同步请求op()时,所述基于Jedis的将多线程并发请求合并批量提交并分发结果的实现方法具体包括:

客户端线程向PipelineWrapper发起同步请求op()调用;

获得PipelineWrapper对象属性lock的排它锁;

向底层的pipeline发起相应的请求,所述请求以异步方式执行,;

对操作计数器opCount执行+1操作;

执行PipelineWrapper的reportOp()操作,将通过“new Semaphore(0)”创建一个信号量Semaphore推送到同步操作等待队列respQueue,最后将信号量返回;

如果此时opCount>maxOpCount,即操作计数已经超过设置的最大操作数,则触发批量提交sync()的执行;

释放PipelineWrapper对象属性lock的排它锁,继续执行其他请求;

在创建的信号量Semaphore上执行等待操作acquire(),直到被Notifier唤醒;

在底层pipeline返回的Response钩子对象上调用get方法获取结果并返回。

当所述请求是异步请求opAsync()时,所述基于Jedis的将多线程并发请求合并批量提交并分发结果的实现方法具体包括:

客户端线程向PipelineWrapper发起异步请求opAsync()调用;

获得PipelineWrapper对象属性lock的排它锁;

向底层的pipeline发起相应的请求,所述请求以异步方式执行;

对操作计数器opCount执行+1操作;

如果此时PipelineWrapper的属性trigerCommitInAsync==true并且opCount>maxOpCount,并且操作计数已经超过设置的最大操作数,则触发批量提交sync()的执行;

释放PipelineWrapper对象属性lock的排它锁;继续执行其他请求

直接返回对Response包装后的Resp。

当所述请求是批量提交sync()时,所述基于Jedis的将多线程并发请求合并批量提交并分发结果的实现方法具体包括:

客户端线程向PipelineWrapper发起批量提交sync()调用;

获得PipelineWrapper对象属性lock的排它锁;

判断opCount>0是否成立,成立继续;否则直接返回;

向底层的pipeline发起批量提交请求,等待底层执行返回;

在对象属性latch上执行countDown()打开异步请求闩,以便异步请求线程获取结果,并创建一个新的未打开的异步请求闩赋值给对象属性latch,供后续异步请求使用;

如果同步请求队列respQueue非空,则将其封装到新的Notifier中,提交至线程池ExecutorService进行唤醒任务的执行;

将opCount置位为0;

释放PipelineWrapper对象属性lock的排它锁,继续执行其他请求;

调用返回。

本发明的有益效果:

1.将进程内多线程的并发请求合并起来统一批量提交,可以减少连接资源的消耗,也减少了各线程独立提交请求时的请求提交次数,最大限度地提高了网络的吞吐量,还可以消除不同请求之间的相互等待。

2.提供了同步、异步方法、主动提交方法,可以根据应用业务自由决定使用何种请求方式。

3.可以根据设置的最大请求数和最大提交周期自动执行提交,保证了操作的及时完成,保证了客户端等待的线程数目不会过多。

附图说明

通过阅读下文优选实施方式的详细描述,各种其他的优点和益处对于本领域普通技术人员将变得清楚明了。附图仅用于示出优选实施方式的目的,而并不认为是对本发明的限制。而且在整个附图中,用相同的参考符号表示相同的部件。在附图中:

图1是根据本发明实施方式的Jedis的封装模块类图;

图2是根据本发明实施方式的Jedis的封装模块交互示意图;

图3是根据本发明实施方式的同步请求时序图;

图4是根据本发明实施方式的同步请求流程图;

图5是根据本发明实施方式的异步请求时序图;

图6是根据本发明实施方式的异步请求流程图;

图7是根据本发明实施方式的异步请求中从Resp上获取结果的流程图;

图8是根据本发明实施方式的批量提交时序图;

图9是根据本发明实施方式的批量提交流程图。

具体实施方式

下面将参照附图更详细地描述本公开的示例性实施方式。虽然附图中显示了本公开的示例性实施方式,然而应当理解,可以以各种形式实现本公开而不应被这里阐述的实施方式所限制。相反,提供这些实施方式是为了能够更透彻地理解本公开,并且能够将本公开的范围完整的传达给本领域的技术人员。

在本发明的方案中,通过制作一个基于Jedis的封装,来实现将多线程并发请求合并批量提交并分发结果,包括以下模块:基本操作模块、监听器模块、唤醒器模块,下面具体介绍各模块的具体实现方式,各模块涉及的类图及相互关系如图1所示。

PipelineWrapper:是基本操作模块的主类,对外提供了各种同步和异步方法,另外还有批量提交方法。它内部封装了Jedis的异步请求类Pipeline。由于同步异步方法较多,在本发明的描述中使用op()代表同步类型的方法,opAsync()代表异步类型的方法。由于内部封装的Jedis的Pipeline不支持并发执行,所以所有请求都需要先加锁,执行完之后再释放锁,本发明通过属性lock来实现锁机制。

PipelineWrapper(Pipeline pipeline,intmaxOpCount,long periodTime)方法为构造方法,参数包括:Jedis原始的Pipeline,最大请求数maxOpCount和最大提交周期periodTime,构造方法用这三个参数分别赋值给自己内部相应的属性。同时,使用参数pipeline和periodTime创建并启动一个常驻线程运行TimerMoniotr,TimerMoniotr可参见下文描述。

原始Jedis的Pipeline中有很多种操作方法,都为异步请求方法,只有批量提交方法是同步请求方法,本发明技术方案向客户端提供了很多同步请求方法、异步请求方法和批量提交方法,这里将本发明所有的同步请求方法用op()来描述表示,将所有的异步请求方用opAsync()来描述表示,将批量提交方法用sync()来描述表示。

op()方法:同步请求方法,该类型方法对外提供同步方式的调用,客户端在调用本类型方法时,会同步返回结果,其特点是客户端需要等待。op()每执行一次,便会向同步操作上报队列(respQueue队列)中增加一个java的信号量对象(new Semaphore(0)),并且方法会在该信号量上执行请求,等待批量提交之后被唤醒。该方法的详细实现逻辑及流程可参见附图3的同步请求时序图。

opAsync()方法:异步请求方法,该类型方法对外提供异步方式的调用,客户端在调用本类型方法时,直接返回一个钩子类对象Resp,不必等真正的结果。可以在需要读取结果是在Resp对象上调用get()方法来获取。该方法的详细实现逻辑及流程可参见附图5的同步请求时序图。

sync()方法:批量提交方法,该类型方法执行批量提交请求,并负责把执行结果分发给各个客户端请求线程。该方法的详细实现逻辑及流程可参见附图8的批量提交时序图。

Resp:该类为异步请求opAsync()返回的结果钩子类,客户端线程可以随时基于它获取正真的结果。但是如果批量提交方法sync()尚未执行,底层结果尚未返回,从Resp上获取结果时客户端线程会被挂起,直到底层结果返回。

该类包含三个重载的构造方法,分别用于不同的场景:

Resp(CountDownLatch wrapper,Response<?>redisResp)方法:构造方法,在PipelineWrapper执行异步方法中通过该构造方法创建结果钩子对象作为返回值。

Resp()方法:构造方法,该方法一般用在不需要返回值,或者只需要返回null的场景中

Resp(T value)方法:构造方法,该方法一般用在只需要返回value的场景,比如:不需要知道具体返回值,只需要知道程序是否顺利执行完成,如果执行完成返回为真(true),否则返回否(false)。

get()方法:该方法用来从Resp中获取执行结果,如果Resp对象属性hasGet为false(即第1次执行),则会在对象属性latch上执行await()方法,等待批量提交结果返回时被唤醒,如果已经被唤醒过,await()方法不会挂起,会直接跳过,继续执行后续逻辑,在属性redisResp上执行get()方法获得真正结果,并将hasGet设置为true,最后将结果赋值给value属性;如果执行时hasGet属性为true(即已经执行过),则直接返回value。

TimerMonitor:是监听器模块的主类,它实现了Java的Runnable接口,主要用来按照设定的间隔时间,周期性地监听PipelineWrapper,每个周期结束,都会执行PipelineWrapper的批量提交方法sync(),保证批量提交操作的周期性执行。

TimerMonitor(PipelineWrapperpip,long periodTime)方法:该方法为构造方法,将传入的参数赋值给本身对应的属性。

run()方法:该方法内部使用了while(true)无限循环,先根据属性periodTime做相应时间的休眠,然后再执行属性pip的批量提交方法sync()触发请求批量提交。

Notifier:是唤醒器模块的主类,它实现了Java的Runnable接口,以便在线程池中作为任务执行,它用来在底层的连接执行完批量提交并返回结果后,将同步等待的客户端线程唤醒,进而返回各自的结果。

Notifier(Queue<Semaphore>q)方法:该方法为构造方法,将传入的参数q赋值给相应的属性。参数队列中的元素为java中的Semaphore,它们来自PipelineWrapper的同步类型方法op(),每个Semaphore即代表一个同步请求,并且在其上有一个客户端请求线程在挂起等待。

run()方法:该方法从队列respQueue中逐个获取Semaphore元素,并在该Semaphore元素上执行release()方法,即唤醒方法,一旦该方法执行,挂在Semaphore上的客户端请求线程即被唤醒,进而获取相应的结果,同步调用即可完成返回。当respQueue中没有元素时,respQueue即被销毁,相应的Notifier对象也可以被垃圾回收了。

ExecutorService:该类为Java中的线程池,用来执行Notifier任务。

根据本发明的实施方式,提出一种基于Jedis的将多线程并发请求合并批量提交并分发结果的实现方法,如前所述,所述Jedis的封装包括:基本操作模块(PipelineWrapper模块)、监听器模块(TimerMonitor)以及唤醒器模块(Notifier),各模块之间的交互如附图2所示,所述方法包括:

首先由客户端线程向PipelineWrapper发起请求,每个线程同一时刻可以发起三种类型的请求的任意一种,op()、opAsync()或sync(),不论哪种操作,都需要先向PipelineWrapper请求锁,获得锁之后,向底层的Pipeline发起请求,然后再释放锁。

不论op()还是opAsync(),每个请求都会对PipelineWrapper的操作计数属性opCount执行+1操作,一旦opCount>maxOpCount,便会触发批量提交方法sync()的执行(对于opAsync()还需要判断trigerCommitInAsync是否为true)。同时有可能触发Notifier唤醒任务的执行。

对于op()方法,每次执行都会向respQueue中增加一个代表该请求结果是否已经可以读取的信号量(Semaphore),该Semaphore会在批量提交方法sync()执行时由Notifier唤醒。

TimerMonitor会周期性地执行PipelineWrapper的批量提交方法sync(),周期为periodTime毫秒。但是不一定每次sync()都会真正有效,因为如果opCount为0时,表示没有请求,这种情况下底层也就不会真正执行提交。

下面结合附图3-附图9详细描述前述同步请求op()、异步请求opAsync()或批量提交sync()的实现过程(即具体实施方式)。

实施方式一:

同步请求时序如附图3所示,同步请求流程如附图4所示,本发明的所述同步请求具体包括:

客户端线程向PipelineWrapper发起同步方法op()调用;

获得PipelineWrapper对象属性lock的排它锁;

向底层的pipeline发起相应的请求,由于pipeline的方法都是异步方法,所以该底层的请求是以异步方式执行的,而其返回的结果是Jedis本身的钩子类Response;

对操作计数器opCount执行+1操作。

执行reportOp()方法上报操作到等待队列,该方法会通过newSemaphore(0)创建一个信号量Semaphore,并将该信号量推送到同步操作等待队列respQueue,最后将信号量返回;

如果此时opCount>maxOpCount,即操作计数已经超过设置的最大操作数,则触发批量提交方法sync()的执行;

释放PipelineWrapper对象属性lock上的锁,方便其他请求继续执行;

在上面步骤创建的信号量Semaphore上执行等待操作acquire(),直到被Notifier唤醒;

在上面步骤返回的Response对象上调用get方法获取结果并返回。

实施方式二:

异步请求时序如附图5所示,异步请求流程如附图6-7所示,本发明的所述异步请求具体包括:

客户端线程向PipelineWrapper发起异步方法opAsync()调用;

获得PipelineWrapper对象属性lock的排它锁;

向底层的pipeline发起相应的请求,由于pipeline的方法都是异步方法,所以该底层的请求是以异步方式执行的,而其返回的结果是Jedis本身的钩子类Response;

对操作计数器opCount执行+1操作。

如果此时trigerCommitInAsync==true并且opCount>maxOpCount,即设置了异步操作可以触发批量提交,并且操作计数已经超过设置的最大操作数,则触发批量提交方法sync()的执行;

释放PipelineWrapper对象属性lock上的锁,方便其他请求继续执行;

直接返回对Response包装后的Resp。

在Resp中包含“异步请求”时传入的“异步请求闩”和Pipeline异步结果钩子对象Response,这两个属性在Resp获取最终结果时会用到,从Resp上获取结果流程,如图7所示。

实施方式三:

批量提交时序如附图8所示,批量提交流程如附图9所示,本发明的所述批量提交具体包括:

客户端线程向PipelineWrapper发起批量提交方法sync()调用;

获得PipelineWrapper对象属性lock的排它锁;

判断opCount>0是否成立,成立继续;否则直接返回;

向底层的pipeline发起批量提交请求,等待底层执行返回;

在对象属性latch上执行countDown()打开异步请求闩,方便异步请求线程获取结果,并创建一个新的未打开的异步请求闩赋值给对象属性latch,供后续异步请求使用;

如果同步请求队列respQueue非空,则将其封装到新的Notifier中,提交至线程池ExecutorService进行唤醒任务的执行;

将opCount置位为0;

释放PipelineWrapper对象属性lock上的锁,方便其他请求继续执行;

调用返回。

本发明将同一进程内多个Redis请求合并到同一个Pipeline中批量提交,再将返回结果分发给原来的各个请求。提供了同步请求和异步请求两种不同的请求模式,可以根据多种配置实现不同的提交策略,可以配置批量提交的最大数目限制,批量提交的最大周期,只要有一个条件满足,就会自动提交请求,但前提是必须最少要有1个请求。另外,本发明还提供了客户端主动提交接口,每个请求可根据业务需要实时触发批量提交。最终经过测试,通过以上技术方案实现,可以大大提高客户端并发请求的响应性能。

以上所述,仅为本发明较佳的具体实施方式,但本发明的保护范围并不局限于此,任何熟悉本技术领域的技术人员在本发明揭露的技术范围内,可轻易想到的变化或替换,都应涵盖在本发明的保护范围之内。因此,本发明的保护范围应以所述权利要求的保护范围为准。

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