在我工作的公司,我们使用 Quartz 进行作业调度。大部分时间Quartz都在为我们提供所需的一切:
无论如何,有时在超高峰期间,Quartz表会遇到数据库锁定问题。所以我在想什么是Quartz替代品。以下项目前景看好:
但是,让我们尝试一些轻松简单的方法,如何使用 Spring Scheduling 实现任务启动,以及使用 Hazelcast 数据网格实现集群编排?
Spring Scheduling和Hazelcast一起运行
任务目标:假设我想在两个微服务上每2秒启动一次特定任务,我想确保群集中始终只有一个任务在运行!
这是Hazelcast派上用场的时刻。我们将为它测试两种Hazelcast解决方案:
在ILock和ISemaphore这两个分布式对象之间的重要区别在于ILock需要由请求锁定的同一线程释放。另一方面,ISemaphore可以通过完全另一个线程释放。
演示
让我们有两个微服务在工作后每两秒启动一次:
<b>private</b> <b>void</b> doJob(<b>final</b> String microServiceName)抛出InterruptedException { System.out.println(microServiceName +“in critical section ...”); <b>for</b>(<b>int</b> i = 0; i <4; i ++){ Thread.sleep(1000); System.out.println(“在做什么”+ microServiceName); } }
用ILock演示
如上所述,我们希望确保只有线程处于关键部分:(ILock解决方案)
<b>public</b> <b>void</b> performJobWithLock(<b>final</b> String microServiceName) { <b>final</b> ILock lock = hazelcastConfiguration.getJobLock(); <b>if</b> (lock.tryLock()) { <b>try</b> { doJob(microServiceName); } <b>catch</b> (InterruptedException e) { e.printStackTrace(); } <b>finally</b> { lock.unlock(); } } } @Scheduled(fixedRate = 2000) <b>public</b> <b>void</b> performJob() { jobServices.performJobWithLock(<font>"service1"</font><font>); } </font>
请注意,在try / finally块之前获取锁定(tryLock方法)。我使用的tryLock方法在获取锁定方面更安全,因为跳过了try / finally块。但是当使用ILock.lock()方法时,您需要知道未授予锁定的可能性,然后ILock.unlock()方法引发IllegalStateException。
测试
第一个终端:
service1 in critical section... Doing something in service1 Doing something in service1 Doing something in service1 Doing something in service1
第二个终端:
service2 in critical section... Doing something in service2 Doing something in service2 Doing something in service2 Doing something in service2
使用ISemaphore进行演示
与ILock相同,但这次ISemaphore是从另一个线程异步释放的:
<b>public</b> <b>void</b> performJobWithSemaphore(<b>final</b> String microServiceName) { <b>final</b> ISemaphore semaphore = hazelcastConfiguration.getJobSemaphore(); <b>try</b> { semaphore.acquire(); Thread thread = <b>new</b> Thread() { <b>public</b> <b>void</b> run() { <b>try</b> { <b>try</b> { doJob(microServiceName); } <b>catch</b> (InterruptedException e) { e.printStackTrace(); } } <b>finally</b> { semaphore.release(); System.out.println(<font>"Thread released semaphore..."</font><font>+microServiceName); } } }; thread.start(); } <b>catch</b> (InterruptedException e) { e.printStackTrace(); } } </font>
不要忘记将ISemaphore permits 的数量设置为1.我们希望ISemaphore表现为ILock,但我们需要能够从另一个线程中释放临界区。
@Bean <b>public</b> ISemaphore getJobSemaphore() { ISemaphore semaphore = hazelcastInstance().getSemaphore(<font>"criticalJobSemaphore"</font><font>); semaphore.init(1); <b>return</b> semaphore; } </font>
测试
以与ILock相同的方式启动两个微服务。以下输出将在两个终端窗口中显示,但同样,永远不会同时出现!
第一个终端
Doing something in service1 Doing something in service1 Doing something in service1 Doing something in service1 Thread released semaphore...service1
第二终端
Doing something in service2 Doing something in service2 Doing something in service2 Doing something in service2 Thread released semaphore...service2