1. 概要

このチュートリアルでは、永続的なキューのJava実装であるビッグキューについて簡単に説明します。

そのアーキテクチャについて少しお話しした後、簡単で実用的な例を通してその使用方法を学びます。

2. 使用法

bigqueue依存関係をプロジェクトに追加する必要があります。

<dependency>
    <groupId>com.leansoft</groupId>
    <artifactId>bigqueue</artifactId>
    <version>0.7.0</version>
</dependency>

また、リポジトリを追加する必要があります。

<repository>
    <id>github.release.repo</id>
    <url>https://raw.github.com/bulldog2011/bulldog-repo/master/repo/releases/</url>
</repository>

基本的なキューの操作に慣れている場合は、APIが非常に似ているため、BigQueueに簡単に適応できます。

2.1. 初期化

コンストラクターを呼び出すだけで、キューを初期化できます。

@Before
public void setup() {
    String queueDir = System.getProperty("user.home");
    String queueName = "baeldung-queue";
    bigQueue = new BigQueueImpl(queueDir, queueName);
}

最初の引数は、キューのホームディレクトリです。

2番目の引数は、キューの名前を表します。 キューのホームディレクトリ内に、データを永続化できるフォルダが作成されます。

メモリリークを防ぐために、完了したらキューを閉じることを忘れないでください。

bigQueue.close();

2.2. 挿入

enqueue メソッドを呼び出すだけで、テールに要素を追加できます。

@Test
public void whenAddingRecords_ThenTheSizeIsCorrect() {
    for (int i = 1; i <= 100; i++) {
        bigQueue.enqueue(String.valueOf(i).getBytes());
    }
 
    assertEquals(100, bigQueue.size());
}

BigQueueはbyte[] データ型のみをサポートするため、挿入時にレコードをシリアル化する責任があることに注意してください。

2.3. 読む

予想どおり、dequeueメソッドを使用するとデータの読み取りも同じくらい簡単です。

@Test
public void whenAddingRecords_ThenTheyCanBeRetrieved() {
    bigQueue.enqueue(String.valueOf("new_record").getBytes());

    String record = new String(bigQueue.dequeue());
 
    assertEquals("new_record", record);
}

また、読み取るときにデータを適切に逆シリアル化するように注意する必要があります。

空のキューから読み取ると、NullPointerExceptionがスローされます。

isEmpty メソッドを使用して、キューに値があることを確認する必要があります。

if(!bigQueue.isEmpty()){
    // read
}

各レコードを調べずにキューを空にするには、removeAllメソッドを使用できます。

bigQueue.removeAll();

2.4. 覗く

覗くときは、レコードを消費せずに読み取るだけです。

@Test
public void whenPeekingRecords_ThenSizeDoesntChange() {
    for (int i = 1; i <= 100; i++) {
        bigQueue.enqueue(String.valueOf(i).getBytes());
    }
 
    String firstRecord = new String(bigQueue.peek());

    assertEquals("1", firstRecord);
    assertEquals(100, bigQueue.size());
}

2.5. 消費されたレコードの削除

dequeue メソッドを呼び出すと、レコードはキューから削除されますが、ディスクに保持されたままになります。

これにより、ディスクが不要なデータでいっぱいになる可能性があります。

幸い、 gc メソッドを使用して、消費されたレコードを削除できます。

bigQueue.gc();

Java ガベージコレクタがヒープから参照されていないオブジェクトをクリーンアップするのと同じように、gcはディスクから消費されたレコードをクリーンアップします。

3. アーキテクチャと機能

Big Queueの興味深い点は、コードベースが非常に小さいことです。約20KBのディスク領域を占めるソースファイルはわずか12個です。

大まかに言えば、大量のデータの処理に優れているのは永続的なキューにすぎません。

3.1. 大量のデータの処理

キューのサイズは、使用可能なディスクの合計容量によってのみ制限されます。クラッシュに耐えるために、キュー内のすべてのレコードはディスクに保持されます。

ボトルネックはディスクI/Oです。つまり、SSDはHDDよりも平均スループットを大幅に向上させます。

3.2. 非常に高速なデータへのアクセス

ソースコードを見ると、キューがメモリマップトファイルによってバックアップされていることがわかります。 キューのアクセス可能な部分(ヘッド)はRAMに保持されるため、レコードへのアクセスは非常に高速になります。

キューが非常に大きくなり、テラバイトのディスクスペースを占有する場合でも、O(1)時間計算量でデータを読み取ることができます。

大量のメッセージを読み取る必要があり、速度が重要な懸念事項である場合は、データをディスクからメモリに移動する方がはるかに高速であるため、HDD上でSSDを使用することを検討する必要があります。

3.3. 利点

大きな利点は、サイズが非常に大きくなる能力です。 ストレージを追加するだけで理論上の無限大に拡張できるため、その名前は「Big」です。

コンカレント環境では、BigQueueはコモディティマシンで約166MBpsのデータを生成および消費できます。

平均メッセージサイズが1KBの場合、1秒あたり166kのメッセージを処理できます。

シングルスレッド環境では、1秒あたり最大333kのメッセージを送信できます。これは非常に印象的です。

3.4. 短所

メッセージは、消費した後もディスクに保持されるため、不要になったときにガベージコレクションデータを処理する必要があります。

また、メッセージのシリアル化と逆シリアル化も担当しています。

4. 結論

このクイックチュートリアルでは、Big Queueと、それをスケーラブルで永続的なキューとして使用する方法について学習しました。

いつものように、コードはGithubから入手できます。