アリババクラウドのLOG Java Producerの使い方

この記事では、**Alibaba Cloud**の**LOG Java Producer**という、**Log Service**にデータを送信するのに役立つ、使いやすく設定性の高い**Java**ライブラリの使い方を紹介しています。

*本ブログは英語版からの翻訳です。オリジナルは[こちら](https://www.alibabacloud.com/blog/how-to-use-alibaba-cloud-log-java-producer_594954)からご確認いただけます。一部機械翻訳を使用しております。翻訳の間違いがありましたら、ご指摘いただけると幸いです。*

#背景
[Alibaba Cloud LOG Java Producer](https://github.com/aliyun/aliyun-log-java-producer?spm=a2c65.11461447.0.0.3ab4677338bUtr)は、ビッグデータや高同時実行シナリオで動作するJavaアプリケーション向けに設計された高性能な書き込みLogHubライブラリです。APIやSDKを使用する場合と比較して、Alibaba Cloud LOG Java Producer（プロデューサー）を使用することで、高性能、コンピューティングとI/Oロジックの分離、制御可能なリソース使用量など、多くのメリットがあります。Producerの機能や仕組みを理解するには、記事「Alibaba Cloud LOG Java Producer - ログをクラウドに移行するための強力なツール」を参照してください。本記事では、Producerの使い方を中心に解説します。

#利用方法の手順
以下の図のように、Producerを使用するためには、3つのステップを実行することができます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/647921/3c288cf2-5f52-3743-bf06-cc1ba06febda.png)

#Producerの作成
Producerを作成する際には、以下のオブジェクトが関与します。

###プロジェクトのコンフィグ
ProjectConfig オブジェクトには、対象プロジェクトのサービス・エンドポイント情報と、呼び出し元の身元を示すアクセス・クレデンシャルが格納されます。

###サービス エンドポイント
最終的なアクセスアドレスは、プロジェクト名とサービスエンドポイントで構成されます。プロジェクトのエンドポイントの決定方法の詳細は、「[サービスエンドポイント](https://www.alibabacloud.com/help/ja/doc-detail/29008.htm)」を参照してください。

###アクセス・クレデンシャル
Producerの AccessKey または Security Token Service (STS) トークンを設定することができます。STS トークンを使用する場合は、定期的に新しい ProjectConfig オブジェクトを作成して ProjectConfig に入れる必要があります。

###ProjectConfigs
異なるプロジェクトにデータを書き込む必要がある場合は、複数の ProjectConfig オブジェクトを作成して ProjectConfigs に置くことができます。ProjectConfigsは、マップを介して異なるプロジェクトの構成を維持します。マップのキーはプロジェクト名、値はプロジェクトのクライアントです。

###ProducerConfig
ProducerConfig は、送信ポリシーを設定するために使用します。異なるビジネスシナリオに応じて異なる値を指定することができます。これらのパラメータの説明を次の表に示します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/647921/e35a0493-4213-9b1b-e39d-37aec85fda93.png)

詳しくは[TimeoutException](https://github.com/aliyun/aliyun-log-java-producer/blob/master/src/main/java/com/aliyun/openservices/aliyun/log/producer/errors/TimeoutException.java?spm=a2c65.11461447.0.0.3ab4677338bUtr&file=TimeoutException.java)と[Attempts](https://github.com/aliyun/aliyun-log-java-producer/blob/master/src/main/java/com/aliyun/openservices/aliyun/log/producer/Attempt.java?spm=a2c65.11461447.0.0.3ab4677338bUtr&file=Attempt.java)を参照してください。

###LogProducer
LogProducerはProducerの実装クラスであり、producerConfigパラメータのみを受け付けるようになっています。producerConfigを用意したら、以下のようにProducerのインスタンスを作成します。

```
Producer producer = new LogProducer(producerConfig);
```

Producerのインスタンスを作成すると、一連のスレッドが作成されます。これはかなりの量のリソースを消費します。1 つのアプリケーションに対して 1 つの Producer インスタンスのみを使用することをお勧めします。Producerインスタンスのスレッドは以下のようにリストアップされています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/647921/34d82a73-5dc3-dcdb-3a1e-dd40621b06b1.png)

さらに、LogProducer が提供するメソッドはすべてスレッドセーフです。これらのメソッドはマルチスレッド環境で安全に実行できます。

#データの送信
Producerのインスタンスを作成した後、それが提供するメソッドを使用してデータを送信することができます。

###パラメータの説明
Producerは、複数のデータ送信方法を提供します。これらの方法のパラメータは以下の通りです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/647921/e7c03992-7bc9-e4d9-6dc3-5b30efaa4e8f.png)

異なるデータをビッグバッチにマージするには、データが同じプロジェクト、ログストア、トピック、ソース、および shardHash プロパティを持つ必要があります。データ マージ機能を正しく動作させ、メモリ リソースを節約するために、これら 5 つのプロパティの値の範囲を制御することをお勧めします。トピックなどのフィールドの値があまりにも多くの異なる値を持つ場合は、トピックを直接使用するのではなく、これらの値を logItem に追加することをお勧めします。

###データ送信結果の取得
Producerは非同期にデータを送信します。データ送信結果は、Producerが返すフューチャーオブジェクトやコールバックから取得する必要があります。

###Future
sendメソッドは[ListenableFuture](https://github.com/google/guava/wiki/ListenableFutureExplained?spm=a2c65.11461447.0.0.3ab4677338bUtr)を返します。ListenableFutureでは、I/Oスレッドをブロックしてget()メソッドを呼び出してデータ送信結果を取得するだけでなく、コールバックを登録することができます。コールバックはFutureの設定が完了した後に呼び出されます。以下のスニペットはListenableFutureの使い方を示しています。この未来のためにFutureCallbackを登録し、実行のためにアプリケーションが提供するEXECUTOR_SERVICEスレッドプールにコールバックを送る必要があります。完全なサンプルコードについては、[SampleProducerWithFuture.java](https://github.com/aliyun/aliyun-log-producer-sample/blob/master/src/main/java/com/aliyun/openservices/aliyun/log/producer/sample/SampleProducerWithFuture.java?spm=a2c65.11461447.0.0.3ab4677338bUtr&file=SampleProducerWithFuture.java)を参照してください。

```
ListenableFuture<Result> f = producer.send("project", "logStore", logItem);
Futures.addCallback(f,
                    new FutureCallback<Result>() {
                        @Override
                        public void onSuccess(@Nullable Result result) {
                        }

                        @Override
                        public void onFailure(Throwable t) { 
                        }
                    },
                    EXECUTOR_SERVICE);
```

###コールバック
将来的には、sendメソッドを呼び出した際にコールバックを登録して、データ送信結果を取得することもできます。コードスニペットは以下の通りです。完全なサンプルコードは、[SampleProducerWithCallback.java](https://github.com/aliyun/aliyun-log-producer-sample/blob/master/src/main/java/com/aliyun/openservices/aliyun/log/producer/sample/SampleProducerWithCallback.java?spm=a2c65.11461447.0.0.3ab4677338bUtr&file=SampleProducerWithCallback.java)を参照してください。

```
producer.send(
        "project",
        "logStore",
        logItem,
        new Callback() {
            @Override
            public void onCompletion(Result result) {
            }
        });
```

コールバックはProducerの内部スレッドによって実装されます。バッチで占有されているスペースは、対応するコールバックが実行された後にのみ解放されます。Producerをブロックして全体のスループットを低下させないようにするために、コールバックで時間を消費する操作を実行しないようにしてください。プロデューサバッチの送信を再試行するためにsendメソッドを呼び出すことも推奨されません。retries パラメータの値を増やすか、ListenableFuture オブジェクトのコールバックでバッチの送信をリトライすることができます。

###Futureとコールバックの比較
データ送信結果を取得するには、Futureとコールバックのどちらを選択すればいいのでしょうか？結果を取得した後の処理ロジックが比較的単純で、ProducerのI/Oスレッドをブロックしない場合は、直接コールバックを使用します。それ以外の場合は、ListenableFutureを使用して、その後の処理ロジックを別のスレッド（プール）で実行することをお勧めします。

#Producerをシャットダウン
送信するデータが少なくなった場合や、現在の処理を終了する場合は、Producerをシャットダウンする必要があります。そうすることで、Producerのキャッシュされたデータを完全に処理することができます。

###安全なシャットダウン
ほとんどの場合、安全にシャットダウンすることをお勧めします。close()メソッドを呼び出すことで、Producerを安全にシャットダウンすることができます。このメソッドは、Producerのキャッシュされたデータがすべて処理され、すべてのスレッドが終了し、登録されたコールバックが実行され、すべての先物が設定されたときにのみ返されます。

全てのデータが処理されるまで待たなければならないが、Producerをシャットダウンした後は、キャッシュされたバッチはすぐに処理され、失敗してもリトライされることはありません。そのため、コールバックがブロックされていない限り、通常はcloseメソッドですぐに戻ることができます。

###限定的なシャットダウン
コールバックが実行されたときにブロックされる可能性が高く、closeメソッドを短く返したい場合は、制限付きシャットダウンモードを使用します。`close(long timeoutMs) `メソッドを使って制限付きシャットダウンを実装することができます。指定した timeoutMs が経過しても完全にシャットダウンされない場合、IllegalStateException 例外が発生します。この場合、キャッシュされたデータが処理されたか、登録されたコールバックが実行されたかに関わらず、Producerはシャットダウンされます。

#サンプルアプリケーション
Producerの学習をより簡単にするために、[Alibaba Cloud LOG Java Producerサンプルアプリケーション](https://github.com/aliyun/aliyun-log-producer-sample?spm=a2c65.11461447.0.0.3ab4677338bUtr)を用意しました。サンプルでは、Producerの作成からシャットダウンまでを網羅しています。

*アリババクラウドは日本に２つのデータセンターを有し、世界で60を超えるアベラビリティーゾーンを有するアジア太平洋地域No.1(2019ガートナー)のクラウドインフラ事業者です。
アリババクラウドの詳細は、こちらからご覧ください。
[アリババクラウドジャパン公式ページ](https://www.alibabacloud.com/ja)*