Azureの小ネタ (改)

~Azureネタを中心に、色々とその他の技術的なことなどを~

Azure storage SDK for java V10 (その1)

Azure Storage SDK for Java に新しいバージョン(V10)が登場したので、少し調べてみた記録です。

https://github.com/Azure/azure-storage-java

しばらく気づかなかったのですが、以前からアナウンスされていたようです。

https://azure.microsoft.com/ja-jp/blog/build-richer-applications-with-the-new-asynchronous-azure-storage-sdk-for-java/

ざっくり説明すると、

  • ソフトウェアスタックの変更(Netty Httpとか)
  • RxJavaの非同期プログラミングモデル
  • Storage REST API と整合性がある低レベルAPI
  • 便利な高レベルAPI
  • スレッドセーフ
  • すべてのStorage SDKの一環したバージョン管理(各言語間なのか?

だそうです。

New SDK for BLOB 利用準備

Maven Repositoryにありますんで適当にプロジェクトを作って、以下を参照するようにしましょう。BLOB用は、現時点では、10.3.0となっておりPreviewは取れております。Queue用はまだPreviewみたいです(執筆時点)

https://mvnrepository.com/artifact/com.microsoft.azure/azure-storage-blob

<dependency>
    <groupId>com.microsoft.azure</groupId>
    <artifactId>azure-storage-blob</artifactId>
    <version>10.3.0</version>
</dependency>

新旧の比較

とりあえず能書きはいいのでコードを実行してみます。Java 11を利用してコード書いてます(ので var を使ってます)

コンテナの作成

以下は、コンテナを作成する旧コードです。接続文字列をパースして、CloudStorageAccountを作成して、そこからコンテナリファレンスを取得して、createIfNotExists()を呼び出す。旧SDKは基本同期メソッドしかないので、.NETのようにはいきませんが、慣れし親しんだコードです。

    var account = CloudStorageAccount.parse(connectionString);
    var client = account.createCloudBlobClient();
    var container = client.getContainerReference("v8container");
    container.createIfNotExists();

新SDKの場合は、以下です。サンプルをサクッともってきて実行してみました。github サンプルのコードは微妙にメソッドシグネチャが違っていたので動きませんでしたので、適当に修正してみます。おいおいちょっと待てよという長さになってしまいました。

    var creds = new SharedKeyCredentials(accountName, accountKey);
    var serviceURL = new ServiceURL(new URL("https://" + accountName + ".blob.core.windows.net"),
             StorageURL.createPipeline(creds, new PipelineOptions()));
    ContainerURL containerURL = serviceURL.createContainerURL("v10container");
    try {
        var response = containerURL.create().blockingGet();
        System.out.println("Container Create Response was " + response.statusCode());
    } catch (RestException e) {
        if (e instanceof RestException && ((RestException) e).response().statusCode() != 409) {
             throw e;
         } else {
             System.out.println("container already exists");
         }
     }

接続文字列をパースするクラスはなくなったみたいです。SharedKeyCredensitalsでアカウントとキーを設定します。SASとかOAuth トークンが使えるぽいです。ICredentials から3つのクラスが実装されてます。

ICredentials
  + AnonymouseCredentials
  + SharedKeyCredentials
  + TokenCredentils 

ServiceURLクラスが基点となる感じぽいのですが、URLとかハードコードしなくてはならないのか、どこかに設定されているのか、ユーティリティクラスがあるのか現時点では不明(ざっとソースみたけどそういうのは無いみたい)。

次に、ContainerURLを作成し、次にcreateメソッドでコンテナを作成しつつ、RxJavaのblockingGetで同期待ちです。409 が返ってきたらコンテナは存在するっぽい。

ファイルアップロード

ファイルのアップロードですが、例えばBlock BLOBならば、コンテナからBlock BLOBリファレンスを取得して、upload* メソッドを呼び出せば、ファイルからだったり、文字列、Streamなどからのアップロード可能です。非同期メソッドはありませんけど。

    var blob = container.getBlockBlobReference("test.txt");
    blob.uploadFromFile("c:/temp/test.txt");

新SDKでは以下の通り。ContainerURLから、BlockBlobURL を作成し、TransferManager経由でファイルをアップロードしてます。TransferManagerは、前述した便利な高レベルAPIクラスにあたるようです。

    BlockBlobURL blob = containerURL.createBlockBlobURL("test.txt");
    var fileChannel = AsynchronousFileChannel.open((new File("c:/temp/test.txt")).toPath());
    var res = TransferManager.uploadFileToBlockBlob(fileChannel, blob, 8 * 1024 * 1024, null).blockingGet();
    System.out.println(res.statusCode());

まとめ

使いやすいかというと、まだよくわからない感じです。旧SDKはNETと類似したクラス構造をもっていたしそんなに不便でもありませんでしたが、非同期メソッドがなかったのが致命的な感じだったのでしょうか。そこをRxJavaを使ってRewriteしたと。

でも、NETのクラス構造と乖離していくのはどうなんでしょうね?と思います。生粋のJavaerにはこっちのほうが学習コストが低いのでしょうか。NET側も追随するんでしょうか? Azure Management APIは、Javaのfluentが先行してNETも対応したように見えたので。

というわけで、今後、もう少し掘り下げたい感じです。