第8回 Chaos Engieering 読書会@リモートのログ

learning.oreilly.com

javaee-study.connpass.com

引き続き Discord によるオンライン開催。

こちらのリストで次の本を検討してます。

次回は 17. Let’s Get Cyber-Physical の Chaos Engineering as a Step Beyond FMEA から。

javaee-study.connpass.com

トピック

  • iPhone 12 Pro は以外と大きいみたいなので買うかどうかで悩ましい
  • Apple Silicon な新 mac は Docker が動かないのは悩ましい
  • Cyberphysics は IPA情報処理技術者関係の試験にも出てくる概念だった
  • WFH を改善するため引っ越すことにした
  • Raspberry Pi で自宅 Kubernetes クラスタを組んでみたり

ディスカッション

15. Chaos Maturity Model

15.1 Adoption 採用

  • 組織として重大インシデントの経験があるかどうかも重要だと思う
    • もう少し条件がありそう
  • 障害やインシデントに対する事業価値を計測できるようなると同時に導入するのが理想的じゃないかなぁ

15.2 Sophistication 啓蒙

  • ゲームデイは必要
  • いきなり汎用的なソリューションを開発しようとするのはよくない
  • 意味がわからないんだけど「一定期間内に消費できるKPIの猶予として「カオスバジェット」を設計する」

    • 実験によりビジネスの望まない損失が発生しないことを保証できるようになる
    • 実験の仮説を立てるときに織り込み済みなんだと思ってたので、ここで改めて登場する話なのかなとも思った
  • 納得した「実験が進化すると対象はインフラストラクチャ、アプリケーション、ビジネスロジックの順に進んでいくことになる」

    • ビジネスロジック」について、一定の割合である商品の購入に失敗する、みたいな実験のほうがよっぽど簡単そう
      • ビジネスとしては VM 落とすとか手段はどうでもいい
    • つまり「ビジネスロジック」から実験していくほうが簡単そう

15.3 Putting It All Together

16. Continuous Verification

17. Let’s Get Cyber-Physical

https://www.linkedin.com/in/nathanaschbacher/

参考情報

JPA のエンティティクラスに必要なデフォルトコンストラクタは直接記述する

JPA のエンティティクラスにデフォルトコンストラクタとして Lombok@NoArgsConstructorを利用すると開発の邪魔になる問題が発生するので使わないほうがいい。

@Entity
@Table(name = "staff")
@Data
@AllArgsConstructor
@NoArgsConstructor(onConstructor = @__(@PersistenceConstructor))
@With
public class StaffEntity implements Serializable {

    private static final long serialVersionUID = 1374L;

IntelliJ IDEA ではこういう見た目になる。 (ちょっとわかりにくいけど L19 の @__コンパイルエラーになっているため赤字になっている)

あらゆる場所でエラーの存在が喧伝される状態になるため、本当に問題がある場所が分からなくなってしまう。 なので、デフォルトコンストラクタだけは直接記述したほうがいい。

f:id:yujiorama:20201018141701p:plain

詳細

JPA のエンティティクラスには引数無しコンストラクタが必要。

ただ、Spring Data を使ってる場合は @PersistenceConstructor で指定したコンストラクタを利用することもできる。 面倒なので一致させておくけど。

Lombok@NoArgsConstructor を利用すると簡単にデフォルトコンストラクタを生成できる。 生成したコンストラクタに @PersistenceConstructor を指定するには onX 機能を利用する。

@__ は、括弧の中身をコンパイラに解釈させず注釈プロセッサで処理することを指示するための特別な記法。 要するに @__(@xxx) と記述したら Lombok の生成したコードに @xxx を指定することになる。 しかし IDEA の構文チェッカ―は @__ を解釈できないので見た目上はコンパイルエラーになってしまう。

@__ の代替記述として属性名を onConstructor_ とする方法もあるけど、やはり IDE の構文チェッカ―には解釈できないためコンパイルエラーになる。

こちらの方法は左辺値が確定しないため、右辺値を入力するときにコード補完が効かなくなる。つまり @__ を使う場合より都合が悪い。 したがって、こちらの方法を採用するわけにいかないので、結局直接記述するのが一番だという結論になる。

リンク

Lombok : onX

PersistenceConstructor (Spring Data Core 2.3.4.RELEASE API)

Jakarta Persistence

HashiCorp Waypoint のドキュメントを読んだ

リンク

Waypoint is 何

アプリケーションコードをビルドして任意のプラットフォームへ配置、公開するための環境を提供するソリューションでした。

機能的には AWS Code Pipeline とか Azure DevOps とか Google Cloud Build と同じレイヤーになると思うんだけど、開発効率を向上するほうに注目してる感じです。

アプリケーションコードをビルド

  • Maven や Gradle や sbt などのビルドツールより上位の概念としてのビルドを担当します
  • KubernetesNomad 経由で Cloud Native Buildpacks を使う場合が多そうです
  • シンプルな docker build も使えます

任意のプラットフォームへ配置、公開

第7回 Chaos Engieering 読書会@リモートのログ

learning.oreilly.com

javaee-study.connpass.com

引き続き Discord によるオンライン開催。

次回は 11/15(日曜日)で、Part IV Business Factors の 15 Chaos Maturity Model から。

javaee-study.connpass.com

対象範囲

  • Part III Human Factors(第三部 ヒューマンファクター)
  • 12 Experiment Selection Problem (and a Solution)
  • Part IV Business Factors
  • 13 ROI of Chaos Engineering
  • 14 Open Minds, Open Science, and Open Chaos

トピック

  • iPhone 12 が公開
    • AppStore アプリから予約するのが簡単らしい
  • 仕事部屋を絶賛改造中
  • Sourcegraph をお試し中
  • テニスを通じていろんな人と交流してる
  • 自宅のモバイルネットワーク品質が悪いことに気付いてがっかりしてる

ディスカッション

12 Experiment Selection Problem (and a Solution)

  • カオス実験で設定する問題事象は、それぞれの事象の発生頻度は極めて低いのに、無数の組み合わせから慎重に選択するモチベーションが理解できない
    • 大規模になればどれだけ低確率の事象でも普段から発生することになるから、やっぱり考慮しないといけない
    • とはいえほとんど生じない要素を取り上げるという考え方はおかしいだろう
  • 無数の実験から選択する方法は実質 1 つ - 専門家に委ねる
    • ただ、嘘をついてしまう場合があるので注意が必要
    • 問題として認識してるけど対応するのがすごい大変、とか
  • 収集したコールグラフにモデル式を適用することで優先して実験したほうがいい部分を導出する、みたいな研究すごい

Part IV Business Factors

13 ROI of Chaos Engineering

  • カオス実験により発見した欠陥を解消できたことで、より高い可用性を求められると困ってしまう問題
  • カークパトリックモデル
    • 投資対効果を評価する古典的なモデル
    • 1 反応 - 肯定的か
    • 2 学習 - 何を学んだか
    • 3 転移(振る舞い) - 学んだことから行動は変化するか
    • 4 結果 - 費用コストに見合う結果は得られたか
    • (この指標、仕事に使えるのでは・・・)
  • 費用コストに直結しない KPI でも合意さえあれば指標として実験の価値を示すことができる
    • カークパトリックモデルは指標ではなくあくまでも評価モデルでしかない (誤解してた)

14 Open Minds, Open Science, and Open Chaos

shop.oreilly.com

openchaos.io

Open Science now: A systematic literature review for an integrated definition - ScienceDirect

GitHub - open-chaos/experiment-catalog: A public and open source chaos engineering experiment catalog.

参考情報

「○○にしましょう」と呼びかけるより淡々とやっていく

いろんな活動や目標が当てはまるので汎用性が高い。仕事でも個人の活動でもだいぶ前からそういう思想で行動するようになった。

自分の望む状態があるなら、人に頼るより自分のできることを積み上げていくほうが可能性があるんじゃないか、という。

期待してないわけじゃなくて、助けてくれるなら嬉しいのは間違いない。

助けをあてにすると裏切られた気持ちになりがちで、それが相手に対する負の印象へ置き換わってしまうことを避けたい。

Oracle Developers Live Java 視聴ログ

developer.oracle.com

Java 15 のリリースに合わせて開催されたオンラインイベントのセッション動画が公開されたので面白かったところのメモ。



Java Language Futures—Mid 2020 Edition (35:32)

JDK 15 で導入されたフィーチャーの紹介。

  • Records (JEP384)
    • ボイラープレートコードを省略すること自体は目的じゃない
    • 他の言語でいうタプルのような存在
  • Pattern matching for instanceof (JEP375)
    • instanceof でガードしていたキャストは撲滅できる
      • 論理積演算子 && でつなげるから真偽値を返す?
      • 式なのか文なのか…
  • Sealed Classes (JEP360)
    • 特筆することがない…
  • Text Blocks (JEP379)
    • 紹介されなかった

Java 15新機能まとめ - Qiitaを読めばいいことがわかった。

ZGC: The Next Generation Low-Latency Garbage Collector (39:26)

発音:ズィージーシー

今利用できる GC アルゴリズムと特徴

  • ZGC はレイテンシ(GCによる停止時間)の削減を目指してる
  • スループット(GCによる処理数)を大きくするアルゴリズムはヒープメモリの使用効率を向上しようとしてる
GC Optimized for
Serial Memory Footprint
Parallel Throughput
G1 Throughput/Latency Balance
ZGC Low Latency

ZGC の特徴

  • リージョンベースで並行処理
  • NUMA対応でトレーシング可能
  • ロードバリアによるコンパクション
  • 単一世代で色ポインタを利用する
    • ヤング・オールドみたいな世代はない
  • 停止時間はヒープサイズやライブセットサイズに依存しない(ルートセットサイズに依存する)
  • クラスアンロードもできる

ZGC の振る舞い

  • マークスタートフェーズ
    • 10ms 以下
    • 対象オブジェクトにマークする
    • マッピングを修正する
  • マークエンドフェーズ
    • 10ms 以下
    • マークしたオブジェクトをリアロケートするための準備
  • リアロケートフェーズ
    • 10ms 以下
    • 準備したオブジェクトをリアロケートする

色ポインタ

  • オブジェクトポインタの構造
    • 未使用ビットとオブジェクトアドレスの間の 4 bit をメタデータとして利用する
    • マーク済み、とか、リアロケート対象、とか
p = 未使用 (16 bit) +
    色ポインタ (4 bit) +
    オブジェクトアドレス(44 bit, 16 TB に相当する)

ロードバリア

  • ヒープのオブジェクトを参照するときに JIT がコード片を挿入する
  • ロードしたタイミングで色ポインタをチェックする
  • チェックして問題があれば修復する

ZGC の性能

ZGC の未来

  • GC停止時間のさらなる削減 - 1 ms 以下にしたい
  • GC停止時間がルートセットサイズに依存しないようにしたい
    • 今のところスレッドスタック処理に未対応なため (JEP 376 で議論してる)
  • 世代別 GC

Keeping Your Java Applications Secure: Cryptographic Improvements and Best Practices (37:09)

Cryptographic Improvements

  • 安全なアルゴリズムの提供
    • JDK のリリースごとにより優れたアルゴリズムが追加されている
    • バックポートされているから昔のバージョンでもアップデートしていく必要がある
  • 安全でないアルゴリズムの使用を制限
  • 関連する警告やイベントを出力するようになっている
    • keytooljarsigner の出力に気を付けよう
    • JFR で観測できるイベントが増えている
      • jdk.SecurityPropertyModification
      • jdk.TLSHandshake
      • jdk.X509Validation
      • jdk.X509Certificate

Secure Programming Best Practices

Secure Coding Guidelines for Java SE の紹介。

コーディングガイドは10章構成。

  • 1-3章は基礎
    • DoS
    • 機密情報の保護
    • 注入攻撃
  • 4-10章はコードと権限に関連する

Java に限定した話じゃないので注意が必要。

要するに、プロセスの外部から入力されるデータは信用できないので、言語機能を公開するべきではない、みたいな感じ。

自分でコーディングする場合以外に、フレームワークやソリューションを選定するときも注意したほうがいいと思う。

This Ain’t Your Parent’s Java (40:45)

個人的に心の中で Java 芸人と呼んでいるベンカット・サブラマニアンのマシンガントーク (貴重な Emacsen でもある)。

Project Loom: Modern Scalable Concurrency for the Java Platform (38:34)

並列性の目的はスループット

  • スループットはリトルの法則 L=λW に支配されている
    • λ - 並列度 (制御できる)
    • W - 平均レイテンシ (外部サービスへのアクセスなど、制御できない部分が混在する)
    • L - 並列性の度合

現在の Java スレッド

  • OS スレッドのラッパー
    • タスクスイッチにカーネルモードへの切り替えが伴う
    • OS のスケジューリングに依存
    • キャッシュの局所性が悪い
  • スレッドごとの消費リソースが大きい
  • スレッドプールを使えば再利用できるけど別の問題が生じる
    • トランザクションが完了したら戻すモデル (request thread 的な話)
      • スレッドローカルがリークする
      • キャンセル処理が複雑化する
    • 待ち状態になったら戻すモデル (nio 的な話)
      • API に互換性がない
      • コンテキストを維持できない
  • 結局のところ同期処理と非同期処理のトレードオフになる
    • 人間にやさしい vs マシンにやさしい
    • 簡単 vs 複雑
  • いいとこどりしたい
    • 前方互換性を保ちつつ( 既存の資産を守りつつ ) 新しい機能を導入したい

そこで Java スレッドの再設計

  • Thread.currentThead() はあちこちで使われてるので注意が必要
  • Java 5 以降は Executor/Future を利用するようになってるから直接的に Thread API を使う場面は減っている
  • Thread API を大掃除すればかなりフットプリントを削減できる

新しい Java スレッド = Virtual Threads

  • スタックのサイズを可変にする
    • メタデータに 2kB 使っていたのを 200-300B にする
    • スタックに 1MB 使っていたのを可変にする
  • ユーザーモードコンテキストスイッチできるようにする
    • 長くて 10μs から 200ns 以内に短縮する
  • スケジューラーを交換可能にする

利用者にとってのメリット

構造化並列性という概念の導入

  • 構造化とは ?
    • ランタイムの振る舞いをコードに反映すること
    • libdill(C)や Trio(Python) で採用されている

Executor API の改善

  • 1 ThreadExecutor は Auto-Closeable になり、すべてのタスクが完了するまで待機する
    • スレッドプールにタスクを submit する API は変わらない
  • 2 指定した期間を経過したらタスクを実行してるスレッドを interrupt する
  • 3 join や wait や cancel を簡単に扱えるようになるはず

コード例。

// 1
ThreadFactory factory = Thread.builder().virtual().factory();
try (var executor = Executors.newThreadFactory(factory)) {
    executor.submit(task1);
    executor.submit(task2);
}

// 2
ThreadFactory factory = Thread.builder().virtual().factory();
try (var executor = Executors.newThreadFactory(factory)
                             .withDeadline(Instant.now().plusSeconds(30))) {
    executor.submit(task1);
    executor.submit(task2);
}

// 3
try (var executor = Executors.newVirtualThreadExecutor()) {
    String first = executor.invokeAny(List.of(
        () -> "a",
        () -> { throw new IOException("too lazy for work"); },
        () -> "b"
    ));
    System.out.println("one result: " + first);
} catch (ExecutionException e) {
    e.printStackTrace();
}

Collections Refueled (30:16)

JDK 9 以降の Collections Framework の改善について淡々と紹介。

簡潔なファクトリメソッド

  • 不変コレクションを生成するための of
    • Collections.unmodifiableList(Arrays.asList(xxx))List.of(xxx) で代替できるようになった
    • Collections.unmodifiableSet(new HashSet<>(xxx))Sets.of(xxx) で代替できるようになった
    • Collections.unmodifiableMap(xxx) にも代替案がある
      • Map.of(k1,v1,k2,v2) みたいな感じ
      • Map.ofEntries(Map.entry(k1, v1), Map.entry(k2, v2)) というのもある
  • 冪等な複製を得るための copyOf
    • 不変コレクションは copyOf しても新しいオブジェクトを生成しない (知らなかった!)
  • Stream から不変コレクションを生成するための Collectors.toUnmodifiableXXX

イテレーション順序のランダム化

  • Set および Map キーの順序の話
    • HashSet と HashMap (のキー) の順序は未定義
    • 新しく JDK がリリースされても順序の一貫性は保たれていた
    • もし順序が変わると既存のコードが壊れる可能性がある
  • 新しいファクトリメソッドが生成する不変コレクションは 順序をランダムにした
    • 潜在的な順序依存性を解消するため
    • 既存の HashSet や HashMap はそのまま
    • 順序を保ちたければ LinkedHashSet LinkedHashMap を使うようにして欲しい

重複する要素の扱い

  • Set.of(a,a) Map.of(k1,v1,k1,v2) Map.ofEntries(...)IllegalArgumentException をスローする
  • リテラルで記述するためのメソッドなのでコーディング誤りの可能性が高いから

空間効率について

ファクトリメソッドはサイズに応じた実装のコレクションオブジェクトを生成する(複製する?)。

素数 実装
0 シングルトン
少数(10以下?) フィールドベースの実装
多数 配列ベースの実装

testcontainers のための Docker への接続情報を環境変数で指定する

前提

  • Java (Kotlin) プロジェクト
  • ビルドツールは Gradle
  • テストコードで testcontainers-java を使ってる

課題

解決方法

ファイルレイアウトはこういう感じになります。

./build.gradle
./settings.gradle
./src/main/java/xxxx
./src/test/java/xxxx
./.env

.env ファイルの内容は次のような感じです。

DOCKER_CERT_PATH=C:/Users/path/to/docker/certs
DOCKER_TLS_VERIFY=1
DOCKER_HOST=tcp://dockerhost:2376

最終的な build.gradle は次のような感じになります。

plugins {
    id 'java'
    id 'co.uzzu.dotenv.gradle' version '1.1.0' // プラグインの追加
}
group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = JavaVersion.VERSION_11

repositories {
    mavenCentral()
}

dependencies {
    testImplementation('org.junit.jupiter:junit-jupiter-api:5.3.1')
    testRuntimeOnly('org.junit.jupiter:junit-jupiter-engine:5.3.1')
    testImplementation('org.testcontainers:junit-jupiter:1.14.3')
    testImplementation('org.testcontainers:postgresql:1.14.3')
}

test {
    useJUnitPlatform()
    // environment で指定した環境変数だけになるので、System.getenv() も指定しないとおかしなことになる
    environment = System.getenv() + [
        'DOCKER_HOST'      : env.fetch('DOCKER_HOST', 'unix:///var/run/docker.sock'),
        'DOCKER_TLS_VERIFY': env.fetch('DOCKER_TLS_VERIFY', ''),
        'DOCKER_CERT_PATH' : env.fetch('DOCKER_CERT_PATH', ''),
    ]
}