Hazelcast JET在Spring Boot上執行
Hazelcast JET目前是分散式計算框架領域的新成員。根據Hazelcast團隊的說法,他們甚至比Apache Spark和Apache Flink更快。檢視基準。讓我們看看如何使用Hazelcast JET和Spring Boot,當然我會像往常一樣構建一個簡單的演示。
Hazelcast JET和Spring Boot依賴項設定:
<dependency> <groupId>com.hazelcast.jet</groupId> <artifactId>hazelcast-jet</artifactId> <version>0.3.2-SNAPSHOT</version> </dependency> |
並且讓我們嘗試建立一個Hazelcast JET例項並最終將其關閉,以便驗證我們是否能夠正確啟動Hazelcast JET:
try { JetInstance instance = Jet.newJetInstance(); } finally { Jet.shutdownAll(); } |
不幸的是,Spring Boot應用程式內部的Hazelcast JET例項建立將崩潰:
java.lang.NoSuchFieldError: JET at com.hazelcast.jet.impl.config.XmlJetConfigBuilder.getXmlType(XmlJetConfigBuilder.java:128) ~[hazelcast-jet-0.3.2-SNAPSHOT.jar!/:0.3.2-SNAPSHOT] at com.hazelcast.config.AbstractXmlConfigHelper.getNamespaceType(AbstractXmlConfigHelper.java:136) ~[hazelcast-3.7.6.jar!/:3.7.6] at com.hazelcast.config.AbstractXmlConfigHelper.<init>(AbstractXmlConfigHelper.java:72) ~[hazelcast-3.7.6.jar!/:3.7.6] at com.hazelcast.config.AbstractConfigBuilder.<init>(AbstractConfigBuilder.java:59) ~[hazelcast-3.7.6.jar!/:3.7.6] at com.hazelcast.jet.impl.config.XmlJetConfigBuilder.<init>(XmlJetConfigBuilder.java:67) ~[hazelcast-jet-0.3.2-SNAPSHOT.jar!/:0.3.2-SNAPSHOT] at com.hazelcast.jet.impl.config.XmlJetConfigBuilder.getConfig(XmlJetConfigBuilder.java:80) ~[hazelcast-jet-0.3.2-SNAPSHOT.jar!/:0.3.2-SNAPSHOT] |
好吧,不要責怪Hazelcast JET團隊,只是Spring Boot已經內建了Hazelcast IMDG(Spring Boot 1.5.3版本為3.7.6),其中這個版本包含了hazelcast ConfigType列舉,但沒有包含JET欄位。就這樣。解決此問題的方法是在您的pom中升級Hazelcast IMDG。對我有用的是將hazelcast.version屬性設定為:
<properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.8</java.version> <hazelcast.version>3.8</hazelcast.version> </properties> |
在這個解決方法之後,一切都應該工作正常,你應該能夠看到他們漂亮的ascii藝術:-)
Hazelcast JET架構
在進入JET演示之前,讓我們描述一下它的架構。Hazelcast JET基於將計算工作組合到DAG圖中。這不是革命性的東西,因為Apache Spark也基於DAG工作。但是讓我們更深入地瞭解Hazelcast JET DAG術語::
- Vertex 是JET作業的一個工作單元。把它作為計算工作的一步。一個Vertex 包含一個或多個您實現的處理器(類AbstractProcessor)來執行您想要的邏輯。每個Vertex 可以有更多的處理器。Number基於本地和全域性並行設定。你可以有SINK Vertex (只有輸入,不發射任何東西),INTERNAL Vertex (有輸入並向其序數發射輸出)和SOURCE Vertex (僅發射)。
- DAG是Vertex 的邊緣聯結器。每次建立JET作業時,都必須將處理器實現與Edges連線。
為了向您展示一個示例,我們可以構建一個簡單的JET Job,它將RabbitMQ代理中的資料注入到分散式Hazelcast Map中。我們的工作將包含兩個Vertex ,第一個Vertex 將發出來自RabbitMQ的專案,第二個Vertex 將是簡單的Sink進入Map。
private static Job createJetJob(JetInstance instance) { DAG dag = new DAG(); Properties props = props( "server", "localhost", "user", "guest", "password", "guest"); Vertex source = dag.newVertex("source", readRabbitMQ(props, "jetInputQueue")); Vertex sink = dag.newVertex("sink", writeMap("sink")); dag.edge(between(source, sink)); return instance.newJob(dag); } |
詳細程式碼
方法readRabbitMQ返回一個JET Processor實現,用於從RabbitMQ讀取訊息。該實現的靈感來自官方的ReadKafkaP處理器。我剛剛以輪詢方式重寫了聯結器以與RabbitMQ代理進行通訊。讀取部分的訊息在AbstractProcessor.complete方法中。要了解這種方法,您需要了解兩件事:
- 重複呼叫方法,直到返回true。由於我的作業中的第一個Vertex 是Source,因此我的ReadRabbitMQP.complete方法始終返回false。
- 來自RabbitMQ代理的輪詢訊息需要透過Traverser介面返回。另請參閱Traversers util類以獲得方便的方法。
輪詢RabbitMQ訊息的完整方法:
@Override public boolean complete() { System.out.println("....Invoking RabbitMQ vertex processor complete..."); if (emitCooperatively(traverser)) { final Message message = this.rabbitTemplate.receive(this.queueNames[0]); if (message != null) { System.out.println("Message payload: " + new String(message.getBody())); final List<Message> list = new ArrayList<>(); list.add(message); Random rn = new Random(); traverser = traverseStream(list.stream()).map(r -> entry(String.valueOf(rn.nextInt()), new String(r.getBody())) ); } } return false; } |
Hazelcast JET和工作分配到叢集
將來自RabbitMQ代理的流式傳輸寫入Hazelcast JET時,接收器Vertex 中的每個處理器都將成為消費者,從而完成相同的工作。
來自AMPQ佇列的有效負載將在JET處理器之間進行負載平衡。無論如何,為特定Vertex 建立處理器的方式是ProcessorMetaSupplier和ProcessorSupplier實現的工作。
簡而言之,JET使用ProcessorMetaSupplier實現為DAG圖中的每個Vertex 獲取ProcessorSupplier。然後將ProcessorSupplier傳送到Vertex ,根據並行度設定建立處理器。我強烈建議您閱讀JET文件中的NumberGenerator示例,這有助於瞭解JET如何建立處理器。
在RabbitMQ流媒體的情況下,我再說一遍,每個處理器都將做同樣的工作,因此:
private static final class MetaSupplier<K, V> implements ProcessorMetaSupplier { static final long serialVersionUID = 1L; private final String[] queueNames; private Properties properties; private MetaSupplier(String[] queueNames, Properties properties) { this.queueNames = queueNames; this.properties = properties; } @Override public Function<Address, ProcessorSupplier> get(List<Address> addresses) { return address -> new Supplier<>(queueNames, properties); } } private static class Supplier<K, V> implements ProcessorSupplier { static final long serialVersionUID = 1L; private final String[] queueNames; private final Properties properties; private transient List<Processor> processors; Supplier(String[] topicIds, Properties properties) { this.properties = properties; this.queueNames = topicIds; } @Override public List<Processor> get(int count) { return processors = range(0, count) .mapToObj(i -> new ReadRabbitMQP<>(queueNames, properties)) .collect(toList()); } @Override public void complete(Throwable error) { processors.stream() .filter(p -> p instanceof ReadRabbitMQP) .map(p -> (ReadRabbitMQP) p) .forEach(p -> Util.uncheckRun(p::close)); } } |
測試此演示
- git clone https://bitbucket.org/tomask79/spring-hazelcast-jet-streaming.git
- mvn clean install
- 在RabbitMQ中建立一個名為“jetInputQueue”的佇列
- java -jar target / demo-0.0.1-SNAPSHOT.jar
現在將一些訊息傳送到“jetInputQueue”輸入4條以後輸出:
Received 4 entries in 78080 milliseconds. ....Invoking RabbitMQ vertex processor complete... ....Invoking RabbitMQ vertex processor complete... Received 4 entries in 78182 milliseconds. ....Invoking RabbitMQ vertex processor complete... ....Invoking RabbitMQ vertex processor complete... Received 4 entries in 78283 milliseconds. ....Invoking RabbitMQ vertex processor complete... ....Invoking RabbitMQ vertex processor complete... Received 4 entries in 78385 milliseconds. ....Invoking RabbitMQ vertex processor complete... ....Invoking RabbitMQ vertex processor complete... Received 4 entries in 78486 milliseconds. ....Invoking RabbitMQ vertex processor complete.. |
我對Hazelcast JET的看法
優點:
- 令人難以置信的效能。與Apache Spark相比,甚至更好一點。
- 非常編碼友好的DAG API。僅僅兩天後,我就能夠編寫JET DAG作業。
缺點:
- 更好的容錯能力。目前,如果我的RabbitMQ JET消費者死亡,那麼整個工作將因資料丟失而中止.. :(
- 我想看看Apache Hive對Hazelcast JET的支援。就像編寫SQL樣式語句一樣,Hive會為我生成JET DAG,就像它與Apache Spark一樣。
無論如何JET引起了我的注意,我期待著下一個版本。
點選標題看原文
相關文章
- 在Kubernetes上使用Spring Boot實現Hazelcast分散式快取 – PiotrSpring BootAST分散式快取
- Spring Boot 參考指南(Hazelcast)Spring BootAST
- 在GraalVM中部署執行Spring Boot應用 - Indrek OtsLVMSpring Boot
- Spring Boot執行緒安全指南Spring Boot執行緒
- 如何執行Spring Boot專案Spring Boot
- spring boot 執行sql檔案Spring BootSQL
- 在 Kubernetes 上使用Spring Boot+ActiveMQSpring BootMQ
- Spring Boot @Async 非同步任務執行Spring Boot非同步
- Spring Boot虛擬執行緒與Webflux在JWT驗證和MySQL查詢上的效能比較Spring Boot執行緒WebUXJWTMySql
- 利用神器BTrace 追蹤線上 Spring Boot應用執行時資訊Spring Boot
- 使用Hazelcast排程Spring tasksASTSpring
- Spring Boot整合Hazelcast實現叢集與分散式記憶體快取Spring BootAST分散式記憶體快取
- 在NuoDB上執行AsteriskAST
- 在 Spring Boot 上過載 REST 控制器端點Spring BootREST
- Spring Boot使用執行緒池處理事務任務Spring Boot執行緒
- Linux系統CentOS 7配置Spring Boot執行環境LinuxCentOSSpring Boot
- 轉:在Linux上執行WinFormLinuxORM
- 使用HazelCast實現Spring Config Server配置ASTSpringServer
- 使用Spring Integration和Hazelcast進行叢集領導者選舉SpringAST
- wine-在mac上執行exe執行檔案Mac
- spring boot 圖片上傳Spring Boot
- 在 Spring Boot 中使用 RedisSpring BootRedis
- 在spring boot專案(maven)中引入其他 spring boot專案Spring BootMaven
- 使用Spring Boot和GraalVM在Knative上構建微服務 - piotrSpring BootLVM微服務
- Spring Boot 到底是怎麼執行的,你知道嗎?Spring Boot
- Spring Boot到底是怎麼執行的,你知道嗎?Spring Boot
- 如何讓spring boot 啟動後就執行某個方法Spring Boot
- 在Spring Boot應用啟動時如何執行程式碼? -DukesletterSpring Boot行程
- 怎樣在 Kubernetes 上執行 PostgreSQLSQL
- 在VSCode上執行Python程式(Mac)VSCodePythonMac
- 在kubernetes上執行WASM負載ASM負載
- Jet Set
- 使用谷歌Skaffold在Kubernetes上進行Spring Boot應用程式的CI / CD工作流程 - foojay谷歌Spring Boot
- Spring Boot的檔案上傳Spring Boot
- Spring Boot 分片上傳檔案Spring Boot
- 在Spring Boot框架中使用AOPSpring Boot框架
- spring-boot-admin對spring-boot專案進行監控Springboot
- Hummingbird: 在Web上執行Flutter應用WebFlutter