使用Spring Integration和Hazelcast進行叢集領導者選舉
最近在檢查Spring Integration區域時,我注意到與Hazelcastdatagrid 的非常好的整合。在以下位置檢視:
https://github.com/spring-projects/spring-integration-extensions/tree/master/spring-integration-hazelcast
如果您使用Hazelcast,那麼您可以從Hazelcast支援的各種分散式資料結構中提供Spring Integration通道基礎架構,如:
- com.hazelcast.core.IMap,
- com.hazelcast.core.MultiMap,
- com.hazelcast.core.IList,
- com.hazelcast.core.ISet,
- com.hazelcast.core.IQueue,
- com.hazelcast.core.ITopic,
- com.hazelcast.core.ReplicatedMap
真正令我印象深刻的是Spring Integration團隊透過Hazelcast實施叢集領導者選舉。讓我們來看看並測試它。但首先要做的事情是:
演示任務:我們有兩個Spring Boot微服務,每10秒產生一個隨機值放入分散式IMap。現在只允許一個微服務在某一時刻消費使用IMap的資料。為了使它變得有點辣,微服務應該在訊息傳遞給其他節點之後放棄其領導。
透過Spring Integration Cluster Leadership解決方案:
首先,您需要將Spring Boot MicroService新增到領導遊戲中:
@Bean public Candidate nodeService1Candidate() { final NodeCandidate candidate = new NodeCandidate("service1", HazelcastConfiguration.ROLE_JOB_MAP); return candidate; } @Bean public LeaderInitiator initiator() { final LeaderInitiator leaderInitiator = new LeaderInitiator(hazelcastConfiguration.hazelcastInstance(), nodeService1Candidate()); return leaderInitiator; } |
但這不是全部。我們的目標是在領導權被授予後從IMap開始資料消費,另一方面在領導被撤銷後停止資料消費。
為此,我們需要監聽org.springframework.integration.leader.DefaultCandidate子類NodeCandidate中的onGranted和onRevoked事件。第一個建構函式引數是節點id,第二個是角色名稱。閱讀Spring Integration角色,但我不會使用它們。我將手動啟動IMap更改生成者。
為了瞭解資料更改,SI Hazelcast整合提供了HazelcastEventDrivenMessageProducer,它可以監聽分散式IMap更改並將適當的資料更改事件委派給Spring Integration通道基礎結構。
@Configuration public class HazelcastConfiguration { . . @Bean public IMap<String, String> getDistributedMapForJobInput() { return hazelcastInstance().getMap(INPUT_JOB_MAP); } @Bean public MessageChannel inputJobChannel() { return new DirectChannel(); } @Bean public HazelcastEventDrivenMessageProducer hazelcastEventDrivenMessageProducer() { final HazelcastEventDrivenMessageProducer producer = new HazelcastEventDrivenMessageProducer( getDistributedMapForJobInput() ); producer.setOutputChannel(inputJobChannel()); producer.setCacheEventTypes("ADDED,REMOVED,UPDATED,CLEAR_ALL"); producer.setCacheListeningPolicy(CacheListeningPolicyType.SINGLE); producer.setAutoStartup(false); return producer; } } |
setAutostartup(false)的注意事項。我們希望讓這位生產者在獲得領導時能夠開始啟動:
/** * Created by tomask79 on 24.08.17. */ public class NodeCandidate extends DefaultCandidate { @Autowired private HazelcastConfiguration hazelcastConfiguration; public NodeCandidate(String nodeId, String role) { super(nodeId, role); } @Override public void onGranted(Context ctx) { super.onGranted(ctx); System.out.println("Leader granted to: "+ctx.toString()); hazelcastConfiguration.hazelcastEventDrivenMessageProducer().start(); } @Override public void onRevoked(Context ctx) { super.onRevoked(ctx); System.out.println("Leader revoked to: "+ctx.toString()); hazelcastConfiguration.hazelcastEventDrivenMessageProducer().stop(); } } |
最後一項任務是消費來自分散式IMap的訊息並放棄領導,以便其他節點可以接受工作並享受一些樂趣。因此,讓我們宣告ServiceActivator監聽來自jobInputChannel DirectChannel 的資料:
@Bean @ServiceActivator(inputChannel =“inputJobChannel”) public MessageHandler logger(){ return new LogAndGiveInitiatorHandler(); } |
將訊息記錄到標準輸出:
/** * Created by tomask79 on 24.08.17. */ public class LogAndGiveInitiatorHandler implements MessageHandler{ @Autowired private JobServices jobServices; @Override public void handleMessage(Message<?> message) throws MessagingException { System.out.println(message.toString()); System.out.println("Waiting for another node to take the work...!"); jobServices.giveUp(); try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("........"); } } |
並命令微服務放棄其領導地位:
/** * Created by tomask79 on 10.08.17. */ @Service public class JobServices { @Autowired private LeaderInitiator initiator; . . public void giveUp() { if (initiator.getContext().isLeader()) { System.out.println("Giving up on leadership: "+initiator.getContext().toString()); initiator.getContext().yield(); } } } |
就是這樣!讓我們測試整個包。
- git clone https://bitbucket.org/tomask79/spring-leader-hazelcast.git
- mvn clean all (in the directory with top pom.xml to build all three projects)
輸出:
[INFO] Reactor Summary: <p class="indent">[INFO] <p class="indent">[INFO] spring-cloud-cluster-demo .......................... SUCCESS [ 0.412 s] <p class="indent">[INFO] spring-microservice-hazelcast ...................... SUCCESS [ 2.380 s] <p class="indent">[INFO] spring-microservice-service1 ....................... SUCCESS [ 3.685 s] <p class="indent">[INFO] spring-microservice-service2 ....................... SUCCESS [ 2.745 s] <p class="indent">[INFO] ------------------------------------------------------------------------ <p class="indent">[INFO] BUILD SUCCESS <p class="indent">[INFO] ------------------------------------------------------------------------ <p class="indent">[INFO] Total time: 10.047 s <p class="indent">[INFO] Finished at: 2017-08-28T19:57:53+02:00 <p class="indent">[INFO] Final Memory: 40M/532M <p class="indent">[INFO] ------------------------------------------------------------------------ |
現在開啟兩個終端並執行:
- java -jar spring-microservice-service1 / target / service1-0.0.1-SNAPSHOT.war(在第一個終端)
- java -jar spring-microservice-service2 / target / service2-0.0.1-SNAPSHOT.war(在第二個終端)
要驗證兩個微服務是否形成有效的Hazelcast叢集,您應該看到類似的內容:
Members [2] { Member [192.168.1.112]:5702 Member [192.168.1.112]:5701 this } |
在形成Hazelcast群集設定後,您應該看到以下輸出
第一終端(獲取領導權並放棄給服務2):
[st-leadership-0] com.example.hazelcast.NodeCandidate : DefaultCandidate{role=leader, id=service1} has been granted leadership; context: HazelcastContext{role=leader, id=service1, isLeader=true} Leader granted to: HazelcastContext{role=leader, id=service1, isLeader=true} <p class="indent">[st-leadership-0] .h.i.HazelcastEventDrivenMessageProducer : started hazelcastEventDrivenMessageProducer GenericMessage [payload=EntryEventMessagePayload [key=service18eff005d-6da8-4fb8-b747-f977ad8e1544, value=a61b5f9a-1b96-493d-b240-61ccb549ba17, oldValue=null], headers={hazelcast_cacheName=randomInputDataMap, hazelcast_member=/192.168.1.112:5702, id=f9c5455b-b42d-3ab7-ec49-9bd33db9ec5f, hazelcast_eventType=ADDED, timestamp=1503945864993}] Waiting for another node to take the work...! Giving up on leadership: HazelcastContext{role=leader, id=service1, isLeader=true} |
第二終端(獲取領導權並放棄給服務1)
Leader granted to: HazelcastContext{role=leader, id=service2, isLeader=true} 2017-08-28 20:47:08.001 INFO 1357 --- [st-leadership-0] .h.i.HazelcastEventDrivenMessageProducer : started hazelcastEventDrivenMessageProducer 2017-08-28 20:47:08.019 INFO 1357 --- [ main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat started on port(s): 8082 (http) 2017-08-28 20:47:08.029 INFO 1357 --- [ main] c.e.SpringMicroserviceServiceComponent : Started SpringMicroserviceServiceComponent in 12.807 seconds (JVM running for 13.507) ........ GenericMessage [payload=EntryEventMessagePayload [key=service249cde108-5045-4b77-84f7-cdc9f524df04, value=c4fe775f-e44d-4f10-ac43-0fe7157c0e67, oldValue=null], headers={hazelcast_cacheName=randomInputDataMap, hazelcast_member=/192.168.1.112:5701, id=df474178-1ff1-35e5-e1e1-d3f6f25d6d68, hazelcast_eventType=ADDED, timestamp=1503946037904}] Waiting for another node to take the work...! Giving up on leadership: HazelcastContext{role=leader, id=service2, isLeader=true} |
總結
只是一些想法。如果在生產過程中流經系統的訊息數量每天只有幾千(我們在Embedit的生產系統中的速率),那麼Hazelcast肯定是一種有過度殺傷力工作。建議始終使用JMS / AMPQ以迴圈方式將資料分發到您的節點。 但是當處理儲存在記憶體中的大資料時。你不應該錯過由Hazelcast支援的Spring Integration Election演算法。
相關文章
- 分散式系統中的領導選舉分散式
- Spring Boot整合Hazelcast實現叢集與分散式記憶體快取Spring BootAST分散式記憶體快取
- 使用Hazelcast排程Spring tasksASTSpring
- 致同女性領導者當選IWIRC香港董事會和全球領導團隊成員
- Hazelcast JET在Spring Boot上執行ASTSpring Boot
- 【譯】使用 ML.NET 進行機器學習 - 叢集完整指南機器學習
- 演算法領頭羊丨分散式系統如何選舉領導?演算法分散式
- redis叢集指導Redis
- ZooKeeper-3.4.6叢集選舉Bug踩坑與恢復記錄
- 使用HazelCast實現Spring Config Server配置ASTSpringServer
- Spark叢集和任務執行Spark
- 面試題:說說你對ZooKeeper叢集與Leader選舉的理解?面試題
- 實際使用Elasticdump工具對Elasticsearch叢集進行資料備份和資料還原Elasticsearch
- SpringBoot2 使用Spring Session叢集Spring BootSession
- Spring Boot 參考指南(Hazelcast)Spring BootAST
- 烏克蘭選舉委員會使用NEM區塊鏈進行投票審判區塊鏈
- 基於Spring Integration和Apache Camel的SEDASpringApache
- 使用微軟Detours庫進行模組列舉微軟
- 如何對 ElasticSearch 叢集進行壓力測試Elasticsearch
- 使用Spring Integration接收TCP與UDP請求SpringTCPUDP
- 面試官:Redis叢集有哪些方式,Leader選舉又是什麼原理呢?面試Redis
- 中國唯一入選 Forrester 領導者象限,阿里雲 Serverless 全球領先REST阿里Server
- Quartz在Spring中叢集quartzSpring
- spring boot redis做叢集Spring BootRedis
- mongodb副本叢集和分片叢集佈署MongoDB
- EJB叢集和Webservice叢集的討論Web
- 結合Hazelcast和Spring的分散式快取 - reflectoringASTSpring分散式快取
- 好程式設計師大資料技術分享:Zookeeper叢集管理與選舉程式設計師大資料
- 好程式設計師大資料技術分享Zookeeper叢集管理與選舉程式設計師大資料
- Nginx實現tomcat叢集進行負載均衡NginxTomcat負載
- 使用 Spring Boot 和 @SpringBootTest 進行測試Spring Boot
- Etcd叢集的介紹和選主應用
- zookeeper的原理和使用(二)-leader選舉
- 原始碼簡析Spring-Integration執行過程原始碼Spring
- 使用 flux2+kustomize+helm+github 進行多叢集 GitOps 雲原生漸進式交付UXGithub
- Spring quartz 叢集模式的坑Springquartz模式
- Redis 漸進叢集介紹Redis
- 使用夜鶯+categraf監控redis和redis叢集Redis