使用Hazelcast排程Spring tasks

banq發表於2019-01-10

在我工作的公司,我們使用Quartz進行作業排程。大部分時間Quartz都在為我們提供所需的一切:
  • 透過cron表示式進行排程。
  • 監控和啟動已啟動的工作......

無論如何,有時在超高峰期間,Quartz表會遇到資料庫鎖定問題。所以我在想什麼是Quartz替代品。以下專案前景看好:
  • Cron4J
  • Apache Ignite(哦,是的!)

但是,讓我們嘗試一些輕鬆簡單的方法,如何使用Spring Scheduling實現任務啟動,以及使用Hazelcast資料網格實現叢集編排?

Spring Scheduling和Hazelcast一起執行
任務目標:假設我想在兩個微服務上每2秒啟動一次特定任務,我想確保群集中始終只有一個任務在執行!
這是Hazelcast派上用場的時刻。我們將為它測試兩種Hazelcast解決方案:

  • ILock - Hazelcast分散式鎖,用於訪問關鍵部分。只允許一個執行緒位於關鍵部分。
  • ISemaphore - 用於關鍵部分編排的叢集範圍計數訊號量。允許多個執行緒位於關鍵部分。取決於設定。

在ILock和ISemaphore這兩個分散式物件之間的重要區別在於ILock需要由請求鎖定的同一執行緒釋放。另一方面,ISemaphore可以透過完全另一個執行緒釋放。
  • ISemaphore - 如果你想非同步解鎖關鍵部分,那麼ISemaphore就是你的方式。
  • ILock - 訪問需要同步應答的一些共享資源是ILock的一種方式。


演示
讓我們有兩個微服務在工作後每兩秒啟動一次:

private void doJob(final String microServiceName)丟擲InterruptedException { 
        System.out.println(microServiceName +“in critical section ...”); 
        forint i = 0; i <4; i ++){ 
            Thread.sleep(1000); 
            System.out.println(“在做什麼”+ microServiceName); 
        } 
    }



用ILock演示
如上所述,我們希望確保只有執行緒處於關鍵部分:(ILock解決方案)

public void performJobWithLock(final String microServiceName) {
        final ILock lock = hazelcastConfiguration.getJobLock();
        if (lock.tryLock()) {
            try {
                doJob(microServiceName);
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        }
    }

@Scheduled(fixedRate = 2000)
    public void performJob() {
        jobServices.performJobWithLock("service1");
    }   


請注意,在try / finally塊之前獲取鎖定(tryLock方法)。我使用的tryLock方法在獲取鎖定方面更安全,因為跳過了try / finally塊。但是當使用ILock.lock()方法時,您需要知道未授予鎖定的可能性,然後ILock.unlock()方法引發IllegalStateException。

測試
  • 開啟兩個終端視窗。
  • git clone https://bitbucket.org/tomask79/spring-integration-hazelcast.git
  • 在pom.xml的頂級目錄中執行“mvn clean install”
  • 第一個終端中的java -jar spring-microservice-service1 / target / service1-0.0.1-SNAPSHOT.war。
  • java -jar spring-microservice-service2 / target / service2-0.0.1-SNAPSHOT.war在第二個終端。
  • 在你啟動兩個微服務之後,輸出將出現在兩個視窗中,但絕不會同時出現!

第一個終端:

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是從另一個執行緒非同步釋放的:

public void performJobWithSemaphore(final String microServiceName) {
        final ISemaphore semaphore = hazelcastConfiguration.getJobSemaphore();
        try {
            semaphore.acquire();
            Thread thread = new Thread() {
                public void run() {
                    try {
                        try {
                            doJob(microServiceName);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    } finally {
                        semaphore.release();
                        System.out.println("Thread released semaphore..."+microServiceName);
                    }
                }
            };
            thread.start();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }


不要忘記將ISemaphore permits 的數量設定為1.我們希望ISemaphore表現為ILock,但我們需要能夠從另一個執行緒中釋放臨界區。

@Bean
    public ISemaphore getJobSemaphore() {
        ISemaphore semaphore = hazelcastInstance().getSemaphore("criticalJobSemaphore");
        semaphore.init(1);
        return semaphore;
    }


測試
以與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


 

相關文章