Welcome to the Future of Cloud Native Java

このエントリは以下のエントリを基にしています。
This entry is based on the following written by Mike Milinkovich (Executive Director of the Eclipse Foundation).
https://eclipse-foundation.blog/2019/09/10/welcome-to-the-future-of-cloud-native-java/

今日、Jakarta EE 8がリリースされ、Javaのイノベーションの新しい時代に入りました。

Jakarta EE 8 Software
https://jakarta.ee/release/

ベンダーに依存しないオープンなプロセスのもと、世界有数のJavaの組織、数百人の専任開発者、Eclipse Foundationスタッフといった多様なコミュニティがJakarta EE 8 Full Platform、Web Profiles、関連するTCK、そしてJakarta EE 8互換の実装として認定されているEclipse GlassFish 5.1をリリースしました。

これは月並みに言ってもすごいことです。18個の異なるメンバー組織、160名を超える新しいコミッター、43個のプロジェクト、129個のGitリポジトリにある6100万行を超えるコードベースという、Eclipseコミュニティの標準からみても本当に大規模な取り組みでした。個々人の方々に感謝の意を述べるにはあまりにも多数の方がいらっしゃるので、この業界のマイルストーンを達成するのに役割を果たしたジャカルタEEコミュニティの皆さんにこの場を借りて感謝申し上げます。

Our members
https://jakarta.ee/membership/members/
EE4J
https://projects.eclipse.org/projects/ee4j

以下にこのリリースにこれほどまでにわくわくしているか述べていきます。

Java EEはエンタープライズアプリケーションの開発と実行のためのプラ​​ットフォームで、20年以上にわたって業界全体で選択されています。 IDCによると、Fortune 500企業の90%は、ミッションクリティカルなワークロードはJavaに依存しています。Jakarta EE 8は、ソフトウェアベンダー、1,000万人以上のJava開発者、および数多の企業に、Java EEアプリケーションとワークロードを標準ベースのベンダーに依存しないオープンソースのエンタープライズJavaスタックに移行するために必要な基盤を提供します。

Jakarta EE Working GroupのSpecification Committeeのたゆまぬ努力の結果、仕様開発はJakarta EE仕様プロセスとEclipse開発プロセスに従っています。これらは、Java EEのJava Community Process(JCP)に対するコミュニティ主導のオープンな後継者です。これにより、仕様を生成するための完全にオープンな共同アプローチが可能になり、コミュニティがすべての決定を共同で行います。オープンソースのTCKおよび自己申告のオープンプロセスと組み合わせることで、Jakarta EEは、独立した実装への参加と参加の障壁を大幅に低下させます。

Jakarta EE Specification Process
https://jakarta.ee/about/jesp/
Eclipse Development Process
https://www.eclipse.org/projects/dev_process/

Jakarta EE 8仕様はJava EE 8仕様と完全に互換性があり、開発者が長年使用してきた同じプログラミングモデルを使う、同じAPIとJavadocが含まれています。Jakarta EE 8 TCKは、Java EE 8 TCKに基づいており、完全に互換性があります。つまり、エンタープライズのお客様は、Java EE 8アプリケーションを変更せずにJakarta EE 8に移行できます。

GlassFish 5.1に加えて、IBMのOpen LibertyサーバーランタイムもJakarta EE 8互換の実装として認定されています。Jakarta EE Working Groupのすべてのベンダーは、各ベンダーのJava EE 8実装がJakarta EE 8と互換性があることを保証する予定です。

Eclipse GlassFish
https://projects.eclipse.org/projects/ee4j.glassfish/downloads
Open Liberty
https://openliberty.io/

これはすべて、JavaのステークホルダーがJakarta EEの前進に参加して、重要なビジネス上の課題を解決するクラウドベースのアプリケーションに対する最近のエンタープライズの要求を満たす前例のない機会を示しています。コミュニティには現在、オープンソースのベースラインを手にしており、これを使うことで、実績のあるJavaテクノロジーを、コンテナ、マイクロサービス、Kubernetes、サービスメッシュ、および過去数年にわたって企業に採用されているその他のクラウドネイティブテクノロジーの世界に移行できます。

行動の呼びかけの一環として、Jakarta EE Working Groupの新しいメンバーを積極的に募集しています。メンバーシップの便益と利点をよく調べていただければと思います。Javaがビジネスにとって重要であり、すべての人に利益をもたらす、よく管理された、ベンダーに中立なエコシステムの中でJakarta EEの革新、成長、および持続可能性を確保したい場合は、今すぐ参加しましょう。

Membership
https://jakarta.ee/membership/

また、クラウドネイティブJavaとは何か、多くの企業にとってクラウドネイティブJavaが重要である理由、およびJakarta EEテクノロジーがどこに向かっているのかについてのコミュニティの視点について詳しく知りたい場合は、Fulfilling the Vision for Open Source, Cloud Native Javaという新しい無料の電子ブックをダウンロードしてください。クラウドネイティブJava。 Adam Bien、Sebastian Daschner、Josh Juneau、Mark Little、Reza Rahmanが自身のインサイトと専門知識をこのeBookにつぎ込んでくれたことに感謝いたします。

Cloud Native Java eBook – Charting a Course for Cloud Native Java
https://jakarta-4753786.hs-sites.com/cloud-native-java-eBook

最後に、来週サンフランシスコのMoscone Centerで開催されるOracle Code Oneに参加されるのであれば、ブース#3228にお立ち寄りください。Eclipseコミュニティでは、Jakarta EE 8、GlassFish 5.1、Eclipse MicroProfile、Eclipse Che、その他クラウドネイティブJavaオープンソースプロジェクトのポートフォリオの多くをご紹介する予定です。

Oracle Code One 2019
https://www.oracle.com/code-one/
Eclipse MicroProfile
https://microprofile.io/
Eclipse Che
https://www.eclipse.org/che/

Azure Databricksの集計結果をCosmos DB(MongoDB API)に書き込む

このエントリは2019/09/02現在の情報に基づくもので、将来の機能追加や廃止に伴い、記載内容との乖離が発生する可能性があります。

Cosmos DBには種々のAPIがあり、例えばMongoDBやCassandraなどを使っているアプリケーションをCosmos DBに置き換える場合、接続文字列を置き換えるだけで移行できる、ということになっているが、果たしてそれがApache Sparkの場合にでも言えるのかを確認した。

結論から言うと、確かにMongoDB Connector for Apache Sparkを設定し直すことで対応できた。以下に記録を残す。

Databricksで実施する処理

Azure SQL DatabaseのAdventureworksデータベース内にあるSalesLT.CustomerAddress、SalesLT.Address、SalesLT.CustomerをJoinし、_idとして、CustomerIDとAddressIDを組み合わせた文字列を生成する。単なるJoinなので、本来ならDatabase内で完結すべきなのは承知の上で、テスト目的で実施した。

準備するもの

  • Cosmos DB
    • MongoDB APIを選択
  • Azure Databricks
    • 今回は5.5 LTS (Apache Spark 2.4.3 / Scala 2.11) を選択
  • MongoDB Connector for Apache Spark
    • Maven Repositoryからorg.mongodb.spark:mongo-spark-connector_2.11の2.4.1を選択し、ライブラリとして登録しておく
    • Scalaのバージョンと整合しておく必要がある
  • Azure Databricks Notebook
    • 今回は動作確認のため、Notebookを使用。
    • 今回、言語はScalaを利用
  • サンプルデータソース
    • ファイルでも何でもよいが、今回はAzure SQL Databaseのサンプルデータベース(Adventureworks)を使用

Databricksにデータを取り込み、DataSetを生成

JDBCドライバを使ってAzure DatabricksでSQL Databaseからデータを取り込む。DataSetを作成する場合はCase Classが必要なので、こちらも作成しておく。

val driverClass = "com.microsoft.sqlserver.jdbc.SQLServerDriver"
connectionProperties.setProperty("Driver", driverClass)
// Case Classes
case class Address(AddressID: Int, AddressLine1: String, AddressLine2: String, City: String, StateProvince: String, CountryRegion: String, PostalCode: String, rowguid: String, ModifiedDate: String)
case class Customer(CustomerID: Int, NameStyle: Boolean, Title: String, FirstName: String, MiddleName: String, LastName: String, Suffix: String, CompanyName: String, SalesPerson: String, EmailAddress: String, Phone: String, PasswordHash: String, PasswordSalt: String, rowguid: String, ModifiedDate: String)
case class CustomerAddress(CustomerID: Int, AddressID: Int, AddressType: String, rowguid: String, ModifiedDate: String)
// Create DataSets and load data to them
val customerAddress_DS = spark.read.jdbc(jdbcUrl, "SalesLT.CustomerAddress", connectionProperties).as[CustomerAddress]
val address_DS = spark.read.jdbc(jdbcUrl, "SalesLT.Address", connectionProperties).as[Address]
val customer_DS = spark.read.jdbc(jdbcUrl, "SalesLT.Customer", connectionProperties).as[Customer]

DataSet間でJoinしDataFrameを生成

各DataSetをJoinする。このとき、列名を===でつなぐJoinだと同じ名称の列ができてしまうので、列名だけを指定するようにしている。

val tempDS = customerAddress_DS.join(customer_DS, "CustomerID")
                          .join(address_DS, "AddressID")
                          .withColumn("_id", concat($"CustomerID", lit("-"), $"AddressID"))
                          .select("_id", "AddressID", "AddressLine1", "CustomerID", "CompanyName", "AddressType")

この結果、以下の列を持つDataFrameができあがる。

  • _id:string
  • AddressID:integer
  • AddressLine1:string
  • CustomerID:integer
  • CompanyName:string
  • AddressType:string

SQLで記述すると、以下のような処理を実行している。

select B.CustomerID || '-' || A.AddressID as _id,
          A.AddressID as AddressID,
          A.AddressLine1 as AddressLine1,
          B.CustomerID as CustomerID,
          B.CompanyName as CompanyName,
          C.AddressType as AddressType
  from Address A, Customer B, CustomerAddress C
where A.AddressID = C.AddressID and C.CustomerID = B.CustomerID

Cosmos DB (MongoDB API) に格納

Connectorを使うためのお作法に則って、構成を作成し、saveメソッドを呼び出す。

val writeConfigMap = Map(
    "database" -> "{database name}", 
    "collection" -> "{collection name}", 
    "uri" -> "mongodb://...", 
    "writeConcern.w" -> "majority")
val writeConfig: WriteConfig = WriteConfig(writeConfigMap, Some(WriteConfig(sc)))
MongoSpark.save(tempDF.write.mode(SaveMode.Overwrite), writeConfig)

注意すべきこと

Cosmos DB側のスループット設定が不足していると、最後の書き込みでエラーが発生することがある(HTTP 429)。これは書き込むデータ量に依存するので、単純な推奨値はない。そのため、適切なスループットの割り当てや、整合性の変更などを考慮する必要がある。もしどうしてもスループットが足りない場合は、何らかのスロットリング機構が必要である。

JVM Language Summit 2019 feedback

例年7月下旬にサンタクララで開催されるJVM Language Summitの報告会を東京(2019/08/09)、大阪(2019/08/23)、福岡(2019/08/30)の3か所で開催しました。

Tapestry of “Project Loom”

これは今年初の試みで、当初はちょっと違う内容を考えていました。ところがきしださんから、以下のようなコメントをもらい、開催した、という背景があります(そのくせ筆者のスライドは全て英語だったわけですが)。

ともかく、3会場で開催し、予想以上の多くの方に参加いただきましてありがとうございました。JVMLSに参加し、スピーカーをやってくださったさくらばさん (@skrb) 、きしださん (@kis) 、さかたさん (@jyukutyo) 、あじさかさん (@ajis_ka) 、そして会場を提供くださったLINE株式会社、LINE Fukuoka株式会社、Yahoo! Japan株式会社のご協力をもって開催できました。厚く御礼申し上げます(ロジ子のオフィスでやらなかった理由は、DevRelチームの手を借りることができなかったからです)。

この3回の報告会で使用したスライドは以下です。

JVMLSはいわゆるお祭り的なカンファレンスではありませんが、狭く深くJVMの一部分に興味をお持ちであれば、結構はまる可能性があります。ご興味ある方は是非来年参加してみてください。

WSL2からWindowsホストで動作しているアプリケーションにアクセスする

このエントリは2019/08/26現在の情報に基づくものであり、今後の機能追加・廃止に伴い、記載内容との乖離が発生する可能性があります。

先日、以下のエントリを記載し、アップデートした。

WindowsホストからWSL2のWebアプリケーションにアクセスする
https://logico-jp.io/2019/07/09/access-web-app-on-wsl2-from-windows-host/

今回はその逆、つまりWindowsホストで動作しているアプリに対してWSL2側からアクセスする。

動作確認のため、Windows 10でIISを稼働し、簡単なHTMLファイルを配置した。表示すると以下のような感じ。

これをWSL2から確認するためには、ドキュメントに記載の通り、WSL2側で/etc/resolve.confのnameserverに相当するIPアドレスを使う必要がある。

Linux からの Windows アプリケーションへのアクセス
https://docs.microsoft.com/ja-jp/windows/wsl/wsl2-ux-changes#accessing-windows-applications-from-linux
Accessing Windows applications from Linux
https://docs.microsoft.com/en-us/windows/wsl/wsl2-ux-changes#accessing-windows-applications-from-linux

当方の環境では以下のよう。

この内容は、コマンドプロンプトからも確認できる、WSL2環境にアクセスする場合のIPv4アドレスと同じ(当然であるが)。

ということで、http://172.29.240.1/a1.htmlにアクセスすると…

無事にアクセスできる。

Cosmos DB SDK v3で冗長化されたインスタンスのリージョンやURLを取得する

このエントリは2019/08/26現在の情報を基にしており、将来の機能追加や廃止に伴い、記載内容との乖離が発生する可能性があります。また、この内容はSDK v3をベースにしています。


以前、以下のエントリを記載したが、SDK v2ベースだったため、v3を基にした内容を別途記載しておく。

Cosmos DBの地理冗長化に関するあれこれ (v2)
https://logico-jp.io/2019/05/09/cosmos-db-distributed-across-multi-regions-v2/

各Regionに冗長化されたCosmos DBのURIを取得する

v2で利用しているAPIは以下の場所に移動した。Package名称からもわかるように、将来隠蔽される可能性があるので注意が必要。

Package com.azure.data.cosmos.internal
https://azure.github.io/azure-sdk-for-java/track1reports/com/azure/data/cosmos/internal/package-summary.html

基本的にはv2と同じメソッドを呼び出すことができるが、少々異なる箇所もあるので以下に記載しておく。

地理冗長化先のリージョンとURL

AsyncCosmosClientクラスのインスタンスを作成する。getDatabaseAccount()はFlux<DatabaseAccount>を返すので、今回はListで受け取るようにしている。もちろんStreamで受け取ることもできる。

AsyncDocumentClient tempClient = new AsyncDocumentClient.Builder()
        .withServiceEndpoint(ENDPOINT)
        .withMasterKeyOrResourceToken(KEY)
        .build();

List<DatabaseAccount> databaseAccountList = tempClient.getDatabaseAccount().buffer().blockLast();

あとは、取得したDatabaseAccountに設定されているリージョンとURLを調べればよい。

databaseAccountList.forEach(databaseAccount -> {
    Iterator<DatabaseAccountLocation> it = databaseAccount.getReadableLocations().iterator();
    while (it.hasNext()) {
        DatabaseAccountLocation loc = it.next();
        System.out.println(loc.getName() + "---" + loc.getEndpoint());
    }
});

GraalVM 19.2: New Tools

このエントリは以下のエントリをベースにしています。
This entry is based on the folllowing one written by
https://medium.com/graalvm/graalvm-19-2-new-tools-b78a70f54b06

本日GraalVM 19.2がリリースされました。

これは19.1に続くメジャーリリースで、変更点はリリースノートをご覧いただきたいのですが、トピックは以下の通りです。

  • 改善されたprofile-guided optimization
  • LLVM toolchain
  • Java Flight Recorderのサポートを備えたVisualVMの機能強化
  • Visual Studio Codeプラグイン(プレビュー)
  • ネイティブイメージのピークパフォーマンスの改善

GraalVM 19.1: Compiling Faster
https://medium.com/graalvm/graalvm-19-1-compiling-faster-a0041066dee4
https://logico-jp.io/2019/07/06/graalvm-19-1-compiling-faster/
リリースノート
https://www.graalvm.org/docs/release-notes/19_2/#1920

フィードバックや問題を報告くださったコミュニティのみなさま、このリリースにマージされたプルリクエストをお寄せいただいたみなさまに感謝いたします。

IssueとPull request
https://github.com/oracle/graal/issues
https://github.com/oracle/graal/pulls

以後はアップデートやバージョンのロードマップの詳細です。このまま読み続けてくださるもよし、いますぐダウンロードして試すもよし・・・。

GraalVM Downloads
https://www.graalvm.org/downloads/

Profile-Guided Optimizations

JVMで動作するGraalVM just-in-time (JIT) モードは起動時にランタイム情報を収集し、それを使用してマシンコードを最適化する機能があるため、高いピークパフォーマンスを求められる状況に適しています。GraalVM ahead-of-time (AOT)モードは、起動時とメモリ消費量の面で優れていますが、ランタイム情報がないため、ピーク時のパフォーマンスが低下します。このデメリットを低減するために、GraalVMチームはGraalVM Enterprise Editionにプロファイルガイド付き最適化(profile-guided optimizations、PGO)を実装しました。 PGOを使用すると、プロファイリングデータを事前に収集し、それをGraalVMの native-image ユーティリティに送り、この情報を使用してバイナリを生成します。これにより、(PGOなしのバイナリに比べて)パフォーマンスを最適化できます。

GraalVM 19.2までは、PGOを適用するためには、まずインストルメント済みのネイティブイメージバイナリをビルド、実行した上で、プロファイルを収集する必要がありました。この機能を使うことで、アプリケーションをJITモードで実行して収集したプロファイルを使用して高度に最適化されたネイティブバイナリを生成できます。

How to enable PGO

  1.  -Dgraal.PGOInstrument フラグをつけてJITモードでJavaプログラムを実行し、プロファイル情報を収集する。
    $ /graal-ee-19.2.0/bin/java -Dgraal.PGOInstrument=myclass.iprof MyClass
  2. 収集したデータを使ったネイティブイメージを生成する。
    $ /graal-ee-19.2.0/bin/native-image --pgo=myclass.iprof MyClass
  3. 高速起動、高スループットのバイナリイメージの準備完了。
    $ ./myclass

Java Flight Recorder

Java Flight Recorder (JFR) は実行中のJavaアプリケーションの診断データやプロファイルデータを収集するツールです。特定時点でのJVMやJavaアプリケーションで発生するイベントを収集します。

Java Flight Recorder in Graal VisualVM

GraalVMにバンドルされているVisualVMで、Java Flight Recorderファイル (.jfr) のデータを可視化する機能がプレビューで使えるようになりました。

JFRサポートを有効化するには、

  1. まず、 $GRAALVM_HOME/bin/jvisualvm を実行してVisualVMを起動する
  2. Tools > Plugins > Available Plugins を使って利用可能な全てのプラグインをリスト表示し、 VisualVM-JFR と VisualVM-JFR-Generic モジュールをインストールする

JFR スナップショットを File > Load… もしくはJFRスナップショットノードをダブルクリックして開き、スナップショットを永続的にJFRリポジトリに追加します。JFRスナップショットの作成については、お使いのJavaバージョンのドキュメントをご覧ください。

JFRのサポートは現在プレビュー機能です。フィードバックは以下からどうぞ。

VisualVM Feedback
http://visualvm.github.io/feedback.html

バグ、機能リクエストはIssueを立ててください。

GraalVM GitHub Issues
https://github.com/oracle/visualvm/issues

Performance Improvements

すべての構成でパフォーマンスが若干向上しました。 大きなアップデートの一つとして、GraalVM Enterprise Editionのネイティブイメージでデフォルトのスループットが改善されたことがあげられます。GPOなしでMicronautのサンプルをGraalVMで実行したときの結果を測定しました。

Creating your first Micronaut Graal application
https://guides.micronaut.io/micronaut-creating-first-graal-app/guide/index.html

19.2では、100万のリクエストに対して、CPU時間が最大10%短縮し、単位時間あたりにおけるCPU1個あたりのリクエストのスループットが最大10%向上しています(訳注:原文はCPU secondという表現を使っています。CPUあたりという表現もおそらく1コアあたりと表現すべきでしょうが、詳細不明のため、CPUあたりとしています)。GraalVMのjust-in-time (JIT) 構成に比べるとスループットはまだ低いですが、AOT構成を同じレベルにするための進歩を続けています。

LLVM Toolchain

GraalVMには LLVM bitcodeエンジンを同梱しており、このエンジンを使ってLLVM bitcodeにコンパイル可能なC/C++やその他の言語を実行できます。Although compiling C/C++をbitcodeにコンパイルすること自体は、clangやllvm-linkといった標準的なLLVMツールで可能ですが、特にmakeのようなリンク・ビルドシステムが登場する場合は注意が必要です。GraalVM LLVMランタイムを対象とするネイティブプロジェクトを構築する際に、コンパイラを単純に置き換えてすぐ使える機能をtoolchainで提供することにより、このプロセスを簡素化することを目指しています。

How to get started

GraalVM 19.2をダウンロードし、LLVM toolchainを以下のコマンドを使って追加します(Community EditionとEnterprise Editionで違いはありません)。

gu install llvm-toolchain

toolchainを使って”Hello World!”のC++プログラムを実行します。

$ $GRAALVM_HOME/jre/languages/llvm/native/bin/clang++ hello-c++.cpp -o hello
$ $GRAALVM_HOME/bin/lli hello

LLVM toolchainの詳細を知りたい方は以下のドキュメントをご覧ください。

Running LLVM on GraalVM
https://www.graalvm.org/docs/reference-manual/languages/llvm/

toolchainは現時点ではまだ実験的 (experimental) であることにご注意ください。機能の追加、変更、削除の可能性があります。

GraalVM Extension for Visual Studio Code

実験的なVS Code extensionの第1版をリリースしました。このextensionはGraalVMで動作するプログラムの編集とデバッグの基本的なサポートを提供します。

GraalVM Support for VS Code
https://github.com/oracle/graal/tree/master/vscode/graalvm

以下のデバッグ設定を利用できます。

  • Node.jsアプリケーションの起動
  • JavaScriptの起動
    GraalVMを使うJavaScriptをデバッグモードで起動します。
  • アタッチ
    ローカルで実行中のGraalVMにデバッガをアタッチします。
  • リモートへのアタッチ
    リモートのGraalVMのデバッグポートにデバッガをアタッチします。

エディターで開かれたJavaScriptソースの場合、すべての Polyglot.eval(…) 呼び出しが検出され、それぞれの埋め込み言語がその場所に挿入されます。

引き続きこのプロジェクトに取り組んでおりますので、フィードバックやご提案を承っております。

Version Roadmap

予測可能なリリース日とアップデートリリースに関する情報を含むバージョンロードマップの説明を作成しました。以下のURLにあるリリースツリーの図の下にあります。

Version Roadmap
https://www.graalvm.org/docs/release-notes/version-roadmap/

将来的には、次のメジャーリリースで計画されている機能を追跡できるプロセスを導入する予定にしています。


GraalVM 19.2をダウンロードして新機能をお試しください。

GraalVM Downloads
https://www.graalvm.org/downloads/

フィードバックをお待ちしています。GraalVMのGitHubリポジトリにIssueを立ててもらってもいいですし、何らかの方法でメッセージをお寄せいただいても結構です。

GraalVM GitHubリポジトリ
https://github.com/oracle/graal
GraalVM Community
https://www.graalvm.org/community/

Cosmos DB Java SDK v3でマルチマスタを構成する

これは2019/08/21現在の情報を基にしたものです。将来の機能追加や廃止に伴って記載内容との乖離が発生する可能性があります。


Cosmos DBのSDKを使ってマルチマスタを構成する方法は以下のドキュメントに記載がある。

Azure Cosmos DB を使用するアプリケーションでマルチマスターを構成する
https://docs.microsoft.com/ja-jp/azure/cosmos-db/how-to-multi-master
Configure multi-master in your applications that use Azure Cosmos DB
https://docs.microsoft.com/en-us/azure/cosmos-db/how-to-multi-master

ただ、2019/08/21時点において、Java SDKを使った例は、v2のAsync Java SDK(CompletableFutureを使った実装)についてのみ紹介されており、SDK v3のReactorを使った実装を基にした記述にはなっていない。そのため、V3の場合の例を以下にまとめておく(当然、将来ドキュメントの記載が変更されるはず)。

v2の場合

v2の場合、以下のようにConnectionPolicyのプロパティを設定することで、マルチマスタ構成を設定していた。

ConnectionPolicy policy = new ConnectionPolicy();
policy.setUsingMultipleWriteLocations(true);
policy.setPreferredLocations(Collections.singletonList(region));
AsyncDocumentClient client =
    new AsyncDocumentClient.Builder()
        .withMasterKeyOrResourceToken(this.accountKey)
        .withServiceEndpoint(this.accountEndpoint)
        .withConsistencyLevel(ConsistencyLevel.Eventual)
        .withConnectionPolicy(policy).build();

v3の場合

v3でも同様のプロパティは存在する。設定方法はほぼ同じだが、メソッドが異なるので注意。

// String[] REGION = {"Japan East", "Japan West"};
ConnectionPolicy policy = new ConnectionPolicy()
        .usingMultipleWriteLocations(true)
        .preferredLocations(Arrays.asList(REGION));
CosmosClient client = CosmosClient.builder()
        .endpoint(ENDPOINT)
        .key(KEY)
        .consistencyLevel(ConsistencyLevel.EVENTUAL)
        .connectionPolicy(policy)
        .build();

ConnectionPolicy#usingMultipleWriteLocations(true) でマルチマスタの利用を宣言し、ConnectionPolicy#preferredLocations() を呼び出して、アクセス先のリージョン(Cosmos DBがレプリケートされている、書き込み可能なリージョン)を指定する。preferredLocationsへ渡す引数はListであることに注意(配列ではない)。ここで、1個だけリージョンを指定すると、当該リージョンが障害でアクセスできない場合は例外が発生するが、アプリケーションのデプロイ先リージョンを指定することで、プライマリリージョンに書き込みが集中しないように構成できる。

また、preferredLocationsに複数個のリージョンを指定すると、明示的にフォールバック時のアクセス順序を指定できる。ConnectionPolicyクラスのjavadocは以下。

com.azure.data.cosmos.ConnectionPolicy
https://azure.github.io/azure-cosmosdb-java/3.0.0/com/azure/data/cosmos/ConnectionPolicy.html