Netflix Hollow 簡介
1. 概述
在本教程中,我們將學習 Netflix Hollow,這是一個用於將資料從來源分發到多個目標的低延遲框架。該庫適用於頻繁接收中低容量結構化資料的場景,在這些場景中,處理時間至關重要。
Java 應用程式在分發資料時極易出現堆空間問題。 Netflix Hollow 的設計透過將大型資料集卸載到外部儲存系統(例如檔案系統、物件儲存或網路解決方案)來高效管理內存,從而解決了這個問題。
2. 主要組成部分及其特點
Netflix-Hollow 遵循關注點分離設計模式:
通常,該庫使用生產者-消費者模型來處理訊息。生產者透過呼叫來源系統的 API 從中取得資料。同時,消費者負責讀取這些數據並將其分發給下游系統。
生產者可以建立和修改外部資料快照,例如檔案系統和物件儲存。 Netflix-Hollow 庫提供了內建的發布者實現,用於將資料寫入本機檔案系統。相比之下,消費者只能從這些快照中讀取已發布的資料。
在生產者組件中,我們概述了從外部系統檢索資料的步驟。通常,我們使用發布者和通知者元件來發布資料並通知消費者。此外,狀態引擎有助於寫入資料並維護快照版本。
接下來,在消費者端,我們使用公告監聽器和檢索器元件來取得資料。與生產者一樣,消費者也依賴狀態引擎從快照中讀取正確的資料版本。
此外,要讀取和處理快照中的數據,消費者必須先反序列化快照。因此,Netflix Hollow 函式庫提供了一個HollowAPIGenerator類,用於產生存取快照資料的 API。消費者透過與這些產生的 API 互動來檢索生產者發布的資料。 API 生成器類別依賴反映資料結構的實體類別。因此,在使用生成器建立 API 之前,我們必須先定義實體類別。
3. 先決條件
現在我們已經了解了 Netflix Hollow 架構的基本原理,接下來讓我們建立一個範例生產者應用程式和一個消費者應用程式。假設這是一個關鍵應用程序,它必須定期輪詢基礎設施監控工具以獲取最新事件。最後,它必須將這些事件持久化到資料庫中以供進一步處理。
我們將首先在pom.xml檔案中匯入 Netflix Hollow 最基本的Maven 依賴項:
<dependency>
<groupId>com.netflix.hollow</groupId>
<artifactId>hollow</artifactId>
<version>7.14.23</version>
</dependency>
4. 生產者實現
接下來,我們來定義監控事件的實體類別:
@HollowPrimaryKey(fields = "eventId")
public class MonitoringEvent {
private int eventId;
private String eventName;
private String creationDate;
private String eventType;
private String status;
private String deviceId;
//..Standard getters and setters
}
註解@HollowPrimaryKey有助於聲明快照資料模型的主鍵。
接下來,我們來定義從監控工具取得最新事件的生產者:
public static void main(String[] args) {
initialize(getSnapshotFilePath());
pollEvents();
}
本質上,我們使用 ` main()方法來實作程式的入口點。它首先呼叫 ` nitialize()方法,然後呼叫 ` pollEvents()方法。此外, getSnapshotFilePath()方法會取得快照資料的位置,生產者會將從監控工具取得的資料寫入該位置。
首先, initialize()方法實例化HollowProducer.Publisher和HollowProducer.Announcer介面的實作類別:
private static void initialize(final Path snapshotPath) {
publisher = new HollowFilesystemPublisher(snapshotPath);
announcer = new HollowFilesystemAnnouncer(snapshotPath);
producer = HollowProducer.withPublisher(publisher)
.withAnnouncer(announcer)
.build();
dataService = new MonitoringDataService();
mapper = new HollowObjectMapper(producer.getWriteEngine());
}
HollowFilesystemPublisher和HollowFilesystemAnnouncer是 Hollow 庫中開箱即用的類,提供了HollowProducer.Publisher和HollowProducer.Announcer介面的實作。
with方法呼叫鏈,會傳回一個HollowProducer.Builder類別的實例。流暢式 API 會將publisher和announcer實例註冊到HollowProducer實例中。然後,我們會實例化一個特定於應用程式的MonitoringDataService類別,用於擷取監控事件。
接下來,在pollEvents()方法中,我們使用MonitoringDataServic定期擷取最新事件:
private static void pollEvents() {
while(true) {
List<MonitoringEvent> events = dataService.retrieveEvents();
events.forEach(mapper::add);
producer.runCycle(task -> {
events.forEach(task::add);
});
producer.getWriteEngine().prepareForNextCycle();
sleep(POLL_INTERVAL_MILLISECONDS);
}
}
通常,輪詢函數會透過在while循環中呼叫資料服務類別來定期檢索資料。在兩次呼叫之間,它會使用Thread#sleep()方法暫停指定的時間。然而,我們也可以使用像 Quartz 這樣的調度庫,它能藉助 cron 表達式來定義更高階的調度方案。
5. 產生消費者 API
消費者必須讀取生產者發布的快照資料。因此,Netflix Hollow 會根據已發佈的資料模型和快照儲存目標自動產生消費者 API。消費者 API 是消費者程式和持久層之間的適配器,生產者在持久層中持久化快照資料。
讓我們來看看自訂ConsumerApiGenerator類別中的消費者生成器程式:
public static void main(String[] args) {
String sourceDir = args[0];
Path outputPath = getGeneratedSourceDirectory(sourceDir);
HollowWriteStateEngine writeEngine = new HollowWriteStateEngine();
HollowObjectMapper mapper = new HollowObjectMapper(writeEngine);
mapper.initializeTypeState(MonitoringEvent.class);
HollowAPIGenerator generator = new HollowAPIGenerator.Builder()
.withDestination(outputPath)
.withAPIClassname("MonitoringEventAPI")
.withPackageName("com.baeldung.hollow.consumer.api")
.withDataModel(writeEngine)
.build();
try {
generator.generateSourceFiles();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
首先,我們檢索或建立消費者 API 類別的輸出來源目錄。接下來,我們實例化HollowWriteStateEngine和HollowObjectMapper類別。映射器有助於在序列化和反序列化過程中將MonitoringEvent資料實體物件轉換為 Netflix Hollow 物件格式,反之亦然。
此外,Gradle 建置工具支援Hollow 消費者 API 生成器插件。遺憾的是,Netflix Hollow 的 Maven 外掛程式與最新版本的 Netflix Hollow 不相容。在我們的範例中,我們使用了 Maven exec 外掛程式來運行生成器類別並建立消費者 API 原始檔。
6. 消費者實施
基於我們對可擴展性和高可用性的需求,我們可以將生產者和消費者程式部署在同一個或不同的 JVM 中。在本例中,我們選擇將消費者作為單獨的應用程式。這有助於保持其模組化和鬆散耦合性。
讓我們看看MonitoringEventConsumer類別是如何處理生產者發布的資料的:
public static void main(String[] args) {
initialize(getSnapshotFilePath());
while (true) {
Collection<MonitoringEvent> events = monitoringEventAPI.getAllMonitoringEvent();
processEvents(events);
sleep(POLL_INTERVAL_MILLISECONDS);
}
}
首先,程式呼叫initialize()方法來設定公告監視器和快照檢索器元件.此外,它還會實例化MonitoringEventAPI類別。
initialize()方法準備類別層級的HollowFilesystemAnnouncementWatcher和HollowFilesystemBlobRetriever物件:
private static void initialize(final Path snapshotPath) {
announcementWatcher = new HollowFilesystemAnnouncementWatcher(snapshotPath);
blobRetriever = new HollowFilesystemBlobRetriever(snapshotPath);
consumer = new HollowConsumer.Builder<>()
.withAnnouncementWatcher(announcementWatcher)
.withBlobRetriever(blobRetriever)
.withGeneratedAPIClass(MonitoringEventAPI.class)
.build();
consumer.triggerRefresh();
monitoringEventAPI = consumer.getAPI(MonitoringEventAPI.class);
}
在這個方法中, HollowConsumer.Builder類別使用公告監視器和檢索器物件建構HollowConsumer物件。接下來, HollowConsumer#triggerRefresh()方法將消費者更新到公告監視器發布的最新版本。最後,它會呼叫HollowConsumer#getAPI()來檢索MonitoringEventAPI,該 API 稍後將用於取得監控事件。
初始化完成後,消費者程式會像生產者程式一樣,在一個無限while中定期輪詢本機檔案系統中的快照資料。在循環中,程式呼叫MonitoringEventAPI#getAllMonitoringEvent()方法,從檔案系統中取得MonitoringEvent物件集合。最後, processEvents()方法會進一步處理所取得的事件。
7. 結論
本文中,我們使用 Netflix Hollow 庫創建了一個監控事件生產者應用程式和一個消費者應用程式。 Hollow API 是一個簡單易懂、易於實現的框架。
該庫處理生產者端的所有複雜任務,包括更新快照和發布這些更新。同樣,它也管理消費者端的特定任務,例如監控和讀取更新。
此外,開發人員建立了實體結構,並專注於編寫管理資料的程式。
與往常一樣,本文中使用的程式碼可在 GitHub 上找到。