Postmanを使ってChatworkにメッセージを投稿する

以前 Postman を使って API のテストをしていましたが、いつの間にか Flows という機能が登場していて、それを使うと API Gateway や Lambda を用意しなくても簡単な Web サービスの連携に使えることを知りました。

これを知ったきっかけのイベントは 【大阪開催】もめんと Meet-up #8 Momento × フレンドライクなベンダー祭り! です。

早速、Chatwork にメッセージが送れるか試してみることにします。

API の定義

まずは、メッセージを送る Chatwork API を定義しておきます。

リクエストメソッドは POST で、URL は "https://api.chatwork.com/v2/rooms/:ROOM_ID/messages" にします。

Params の Path Variables に Key が "ROOM_ID" の項目が表示されるので、送信するルームIDを変数から設定できるように "{{ROOM_ID}}" と入力します。

Headers には、"x-chatworktoken" を追加して、シークレットな環境変数から値を設定できるように "{{CHATWORK_TOKEN}}" と入力します。

Body は Key (self_unread と body) を追加設定します。

環境変数 (CHATWORK_TOKEN) をシークレットとして設定し、変数 ROOM_ID を設定します。

Flows

Flows は図のようなイメージで作成しました。

この作成した Flows の Webhook URL に message を含む JSON 例えば '{ "message": "旧年中はいろいろとお世話になりありがとうございました。本年もどうぞよろしくお願い申し上げます。" }' を送ると、Chatwork にメッセージが投稿されます。

Chatwork API のテストをするときや Webhook のちょっとした機能が欲しいときに、AWS Lambda 等を作らなくていいのでとても便利だと思いました。

WSL2のUbuntuにamazon-ssm-agentをインストールした作業ログ

ドキュメントに書かれていた snap コマンドではエラーになったので、次のコマンドでインストール。

mkdir /tmp/ssm
cd /tmp/ssm

wget https://s3.amazonaws.com/ec2-downloads-windows/SSMAgent/latest/debian_amd64/amazon-ssm-agent.deb
sudo dpkg -i amazon-ssm-agent.deb

sudo systemctl stop amazon-ssm-agent

sudo amazon-ssm-agent --register -code 'Activation Code' -id 'Activation ID' -region 'AWS Region'

sudo systemctl start amazon-ssm-agent

AWS-RunShellScript を使って ls コマンド等を実行して疎通を確認する。

ネイティブ呼び出しが気になった件

これは Java Advent Calendar 202320日目の記事です。

Testcontainers でDockerにアクセスできることからUNIXドメインソケットの利用にネイティブ呼び出しが使われているのでは?と気になって調べてみました。

UNIXドメインソケットとは何かですが、Unixのプロセス間通信にはpipeやfifoの他にUNIXドメインソケットがあります。pipeやfifoは一方通行ですが、UNIXドメインソケットは双方向で通信できます。現在ではUNIXドメインソケットはUnixライクなLinuxだけでなくWindowsでも利用できるようになっています。

Dockerは通常UNIXドメインソケットを使ってdockerコマンド等のクライアントとバックエンドが通信します。Testcontainersの場合はdockerコマンドを介さず直接UNIXドメインソケットを使ってDockerのバックエンドと通信を行います。JavaUNIXドメインソケットを使う場合ネイティブ呼び出しが使用されるJava Native Library等を利用してきました。

Java 16以降は JEP 380: Unix-Domain Socket Channels が取り入れられたことでUNIXドメインソケットへのアクセスにネイティブ呼び出しを利用する必要はなくなっています。実際調べてみるとTestcontainersが利用しているdocker-javaで、JEP 380 を使う UnixSocket.java が追加されていました。Java 16以降を使っていればネイティブ呼び出しにはならないと確認できました。

ネイティブ呼び出しの問題

ではネイティブ呼び出しは何が問題なのか。ネイティブ呼び出しのあるライブラリを利用するコードはそのネイティブコードが対応していないプラットフォームであってもコンパイルはエラーになりません。そして実行時にエラーになります。これはマルチプラットフォームで動作するアプリケーションを開発できるというJavaの利点を損なってしまうことにつながります。

またネイティブコードはライブラリのjar内にパッケージングされていることが多くネイティブ呼び出しの有無はわかりにくいです。さらに、どのOS等をサポートしているかもわかりにくいです。ネイティブコードはサポートする複数のOS用に個別にコンパイルされています。例えば次のリストはTestcontainersの依存ライブラリ Java Native Library のjarに同梱されたネイティブライブラリです。

com/sun/jna/win32-x86/jnidispatch.dll
com/sun/jna/aix-ppc/libjnidispatch.a
com/sun/jna/aix-ppc64/libjnidispatch.a
com/sun/jna/darwin-x86-64/libjnidispatch.jnilib
com/sun/jna/darwin-aarch64/libjnidispatch.jnilib
com/sun/jna/linux-x86/libjnidispatch.so
com/sun/jna/linux-x86-64/libjnidispatch.so
com/sun/jna/linux-arm/libjnidispatch.so
com/sun/jna/linux-armel/libjnidispatch.so
com/sun/jna/linux-aarch64/libjnidispatch.so
com/sun/jna/linux-ppc/libjnidispatch.so
com/sun/jna/linux-ppc64le/libjnidispatch.so
com/sun/jna/linux-mips64el/libjnidispatch.so
com/sun/jna/linux-loongarch64/libjnidispatch.so
com/sun/jna/linux-s390x/libjnidispatch.so
com/sun/jna/linux-riscv64/libjnidispatch.so
com/sun/jna/sunos-x86/libjnidispatch.so
com/sun/jna/sunos-x86-64/libjnidispatch.so
com/sun/jna/sunos-sparc/libjnidispatch.so
com/sun/jna/sunos-sparcv9/libjnidispatch.so
com/sun/jna/freebsd-x86/libjnidispatch.so
com/sun/jna/freebsd-x86-64/libjnidispatch.so
com/sun/jna/openbsd-x86/libjnidispatch.so
com/sun/jna/openbsd-x86-64/libjnidispatch.so
com/sun/jna/win32-x86-64/jnidispatch.dll
com/sun/jna/win32-aarch64/jnidispatch.dll

おそらく上記のようなリストからどのプラットフォームをサポートしているかを判断する必要がありそうです。

おわりに

普段何気なく利用しているライブラリの中にもネイティブ呼び出しを含んだものが時々あります。今回気になったTestcontainersの場合は、Java 16以降を使っていれば心配ありませんでした。あまり神経質にならない程度に、たまに依存関係にネイティブ呼び出しがないか注意を払い、進化を続けるJavaを楽しんでいきたいと考えています。

Momento Topics を調べた

Momento Advent Calendar 2023の18日目の記事です。

さて、皆さんは pub/sub って聞いたことがありますか。pub/sub とは Enterprise Integration Patterns の Messaging Patterns の1つとして挙げられていて、Publish-Subscribe Channel というのが正式な名前のようです。

複数のパブリッシャー (Publisher) が Topic を指定してメッセージやイベントを書き込みます。複数のサブスクライバー (Subscriber) は関心のある Topic を購読していて、書き込まれたメッセージやイベントを読み取り処理します。pub/sub ではパブリッシュする側とサブスクライブする側のどちらも複数にすることが可能です。この点が1対1を前提とする Point-to-Point Channel 等との大きな違いになります。

pub/sub に使用できる OSSやサービスはいくつかありますが、それぞれ異なる特徴もあります。この記事では Momento 社以外の OSS やサービスの具体名は使わずに説明します。

メッセージ配信の信頼性

メッセージ配信は通常リモート間をインターネット等のネットワークを使って配信します。これには有名な「二将軍の問題 (Two Generals'Problem)」があります。

At-most-once

At-most-once (最大1回) はパブリッシャーが書き込んだメッセージがサブスクライバーで最大1回読み取れることを保証します。ネットワークに問題がありサブスクライバーで読み取れない可能性もあります。つまり、配信は0回または1回を意味し「配信を保証しない」ということもできるかもしれません1

At-least-once

At-least-once (最低1回) はサブスクライバーは最低でも1回は読み取れることを保証します。ただし場合によっては同じメッセージが複数回配信される可能性もあります。多くのメッセージ配信メカニズムでこの at-least-once が保証されているため、同じメッセージを受信しても問題が発生しないように冪等に設計しましょうと言われるのはこういったところにあります。

Exactly-once

Exactly-once (確実に1回) はサーブスクライバーは確実に1回読み取れることを保証します。

メッセージの永続性

パブリッシャーが書き込んだメッセージやイベントを一定期間保持する OSS やサービスがあります。これらを使用すると、任意の時点でサブスクライブを開始しても、過去の保存されている時点からのメッセージやイベントから読み取ることが可能です。保存される部分をイベントストアと呼ぶ場合もあります。最後の1つのメッセージやイベントのみを保存するものもあります。さらに、パブリッシュされると即座にサブスクライバーに送るだけの「fire-and-forget messaging model」を採用しているものもあります。

Momento Topics はどう機能するか

Momento 社の pub/sub である Momento Topics には次のように書かれています。

Momento Topics operates on a fire-and-forget messaging model, which means that once an item is published, it is immediately sent to all current subscribers of the topic and then discarded. There is no built-in item persistence or delivery guarantees. Consequently, Momento Topics is most suitable for applications where low latency is crucial and occasional item loss can be tolerated.

つまり、Momento Topics 自体ではメッセージの永続化は行わず、配信保証も組み込まれていないため、もしそれが必要であれば、パブリッシャーやサブスクライバーで永続化や配信保証メカニズムを実装する必要があるということになります。これはネガティブな意味ではなく、別途実装が可能な要素を除いて最大限のパフォーマンスを提供していることを意味しています。

紹介したドキュメントには、Momento Cache を使った解決案が記述されていて、必要な永続化、配信保証を性能要件とをみながら実装が可能です。

個人的には IoT デバイスでは MQTT を使って pub/sub を実現することが多いですが、次はぜひ Momento Topics を使って試したいと思います。


  1. 例えば Akka のドキュメント「Message Delivery Reliability」に "at-most-once delivery, i.e. no guaranteed delivery" と書かれている。

Javaの帰還 (Return of the Java)

この記事は AWS Lambda と Serverless Advent Calendar 2023 14 日目の記事です。

昨年2022年re:Invent 2022のAWS Lambda SnapStartの発表でJava Runtimeが再び注目されました。

AWS Lambdaの登場からの歴史

2014年11月にAWS Lambdaが発表されました。この発表でランタイムはNode.jsのみでファンクションの最大実行時間も60秒となっていました。

2015年6月にJava Supportが発表されます。この発表の記事を読むとすでにコールドスタートにかかる時間が問題となっていたことがわかります。

We’re continuing to invest in speeding up the initialization time to make the cold / infrequent use case even better.

その後しばらくは目立ったコールドスタートへの対応はなかったのですが、2019年12月にようやくProvisioned Concurrencyの発表がありました。同時実行 (Concurrency) をプロビジョンすることでコールドスタート時間を短縮することができます。

そして、2022年12月についにSnapStart発表の時が訪れます。

SnapStartの仕組み

AWS Lambdaはサーバーレスと呼ばれることもありますが、実際にはLinux OSの上で実行されます。使用するLinux OSについてもAmazon Linux 2023へのアップグレードが進んでいるようです。

LinuxCRIUというユーザースペースでCheckpointとRestoreを実装しようというプロジェクトがあります。これは実行中のコンテナやアプリケーションの状態をディスクに保存でき、保存から復元して同じ状態から実行できるようにします。

SnapStartはJavaCRaCプロジェクトの成果を利用します。CRaC自体はCRIUのような特定の実装に依存しないよう設計されていますが、現在のところCRIUを利用して実現されているためLinux OSのCRIUサポートを必要としています。SnapStartを有効にするとLambdaの実行中のメモリイメージが保存されます。Lambda実行時に保存されたイメージを復元して開始します。これによって、Java Runtime環境のロードや初期化時間等のコールドスタート時間を短縮できます。

なぜ今この記事を書いているのか

昨年の発表後、Java Runtimeを採用するAWS Lambdaが増えると予想していました。しかし私の知る限りあまりそうした変化を感じることができずにいます。Java言語を使う多くのプロジェクトでは、Springのようなフレームワークを利用して実装されます。こうしたフレームワークがCRaCに対応していなかったことも一因ではと考えています。

2023年5月16日にAzulから「Reduce Java Application Startup and Warmup Times with CRaC」の記事で商用サポートが発表され、11月16日のSpring Framework 6.1でCRaCのサポートが発表され、Spring Boot 3.2以降で使用できるようになりました。

Springを使ったかなり多くの資産があると考えていて、こうした資産の再利用が可能になったことでJava Runtimeを使ったAWS Lambdaが増えることを期待しています。

参考リンク

AWS Community Builders program に参加できてよかったこと

この記事はAWS Community Builders Advent Calendar 2023の12日目の記事です。

私は COVID-19 パンデミックの前 Java Community の JJUG や 関ジャバ、あるいはScala関西で数回登壇したことがありました。その後パンデミックになりオンライン登壇も何度かしましたがイベントの開催自体が減少傾向となり少し遠のいていました。

昨年2022年からは再び対面やハイブリッド開催が復活しはじめイベントに参加したりLT登壇する機会を得られるようになってきました。対面イベントの参加者も回を重ねてかなり回復してきたようです。

AWSの国内イベントでは2023年4月20日と21日にAWS Summit Tokyo幕張メッセで開催され、また10月7日にJAWS FESTA 2023が九州福岡の福岡工業大学で開催されました。

COVID-19 パンデミック以前からある JAWS-UG のイベントに参加し登壇される方の自己紹介を聞いていると、AWS認定資格の他に AWS Community Builders、AWS HeroesAWS Ambassador、Japan AWS Top Engineers、Japan AWS All Certifications Engineers、Japan AWS Jr. Champions などさまざまなタイトルがあることがわかります。

幾つかのタイトルは AWS Partner Network (APN) に加わっている企業に所属していないと獲得できないものがあります。私の所属会社は APN に加わっていることもあって2023年度の Japan AWS Top Engineers に選出していただきました。来年2024年度の Japan AWS All Certifications Engineers をいただく条件も満たせています。この勢いでさらに AWS Ambassador を目指せればと思っています。

もう一方で、先にも書いた通り、私の関心事としてコミュニティ活動があります。そこで AWS Community Builders に応募しました。最初に AWS コミュニティビルダー のページにアクセスしてウェイティングリストに名前を追加しました。

7月3日に「AWS Community Builders になるためのフォームに入力してください」という旨のメールが届き、これに入力しました。フォームへは英語で入力する必要があります。あと活動内容としてブログ等のURLを入力しますが、英語のブログを書いていた方が有利というのはあるそうですが、私の場合は日本語のブログのURLを入力しました。

それからしばらく経った8月15日に「あなたは AWS Community Builders になった」というメールが届きました。このグローバルなプログラムに参加でき、とても嬉しくなり、いろいろな SNS (LinkedInX 等) で報告していました。

Community Builders になってどうだったか

Community Builders は幾つかの特典があってそれぞれとても嬉しいものです。プロモーションクレジットを使ってAWSのいろいろなサービスを試してみることができますし、各領域の専門家 (つまり中の人) が解説するウェビナーもあります。前の記事にもありますが、これらの利点を最大限享受しようとすると英語力が必要になってきます。私の英語力はかなり低いので直近の課題でありなんとかしないとと考えています。

コミュニティ活動に対して、より活発に取り組みたいという思いが強くなりました。以前からボランティアスタッフとして参加している JJUG CCC だけでなく、関ジャバもめんと会の運営にも積極的に参加していこうと考えています。

最後に、AWS Community Builders のディレクトリがあり、公開を選択したコミュニティビルダーを検索することができます。例えば、検索フィールドに「Shigeki Shoji」と入力すると、私を見つけられます。

ぜひ、皆さんと一緒にコミュニティを盛り上げていきましょう。

サービスメッシュの利点

複数のサービスで構成されたシステムにサービスメッシュを採用するモチベーションについて説明します。

サービスメッシュ必読ガイド - 第2版: 次世代のマイクロサービス開発」によると、サービスメッシュが解決しようとする課題は次のとおりです。

  • サービスディスカバリー、ルーティング、およびアプリケーションレベル (レイヤー 7) の非機能通信要件を処理するために、言語固有の通信ライブラリを個々のサービスにコンパイルする必要がなくなります。
  • 外部サービスのネットワークロケーション、セキュリティクレデンシャル、サービス品質ターゲットなど、サービス通信構成の外部化。
  • 他のサービスのパッシブおよびアクティブな監視を提供します。
  • 分散システム全体にポリシーの適用を分散化する。
  • 可観測性にデフォルトを提供し、関連データの収集を標準化します。
    • リクエストロギングの有効化
    • 分散トレーシングの構成
    • メトリクスの収集

非機能通信要件の処理

3つのサービス (Service A、Service B、Service C) で構成されたシステムを例にします。

図はサービスメッシュを利用しない構成です。

最初に Service A の実装を考えてみましょう。

Service A が Service B の API (/list) を呼び出す場合、URL は http://service-b/list となります。Service C の API (/items) を呼び出す場合の URL は http://service-c/items となります。

Service A と同様に Service B、Service C もそれぞれ依存するサービスの URL を生成します。

次にサービスメッシュ (Service Mesh) を利用する場合のトポロジーは次の図のとおりです。

proxy の代表例は Envoy Proxy です。

各サービスと proxy は同一の Pod に同梱して運用します。

ここで、先の例 Service A の実装を考えてみます。

Service A が Service B の API (/list) を呼び出す場合の URL は http://localhost/service-b/list となります。Service C の API (/items) を呼び出す場合の URL は http://localhost/service-c/items となります。

ここで、proxy はサービスディスカバリーにより、Service B、Service C のアドレスを理解してルーティングします (ルーティングの設定は、サービスメッシュにより自動的に反映されます)。

Service A と同様に Service B、Service C もそれぞれ依存するサービスへのルーティングを proxy が実行します。

これだけだと、URL のホスト名を localhost にかえて、サービス名をパスのプレフィックスにしただけで、メリットよりも proxy があることによる性能面での劣化の方が気になるでしょう。

さて、ここで Service C の APIREST API から gRPC を使う HTTP/2 に切り替えてパフォーマンスを向上したくなったと仮定してみてください。

サービスメッシュを利用していない最初の例の場合、Service C に依存する他のサービスは、Service C の API を呼び出すための改修が必要になります。そして、Service C の新バージョンのデプロイに合わせて、依存するすべてのサービスのデプロイも実施する必要があります。

サービスメッシュを利用している場合はどうなるでしょうか。

サービスメッシュの proxy の代表例 Envoy Proxy について「Istio in Action」の中で次のように書かれています。

Envoy can accept HTTP/1.1 connections and proxy to HTTP/2—or vice versa—or proxy incoming HTTP/2 to upstream HTTP/2 clusters. gRPC is an RPC protocol using Google Protocol Buffers (Protobuf) that lives on top of HTTP/2 and is also natively supported by Envoy.

Envoy は、HTTP/1.1 を HTTP/2 に (またはその逆にも) プロキシします、また受信した HTTP/2 を上流の HTTP/2 クラスタにプロキシすることができます。gRPC は、Google の Protocol Buffers (Protobuf) を使用する RPC プロトコルで HTTP/2 を使用しますが Envoy によってネイティブにサポートされています。

サービスメッシュの proxy を使用すると図のようになります。

他のサービスのパッシブおよびアクティブな監視

再び Service A について考えてみます。

Service A が、Service B の API を呼び出す必要があった時に Service B が停止していた場合、タイムアウトするまで処理がブロックされたくはないでしょう。

このためには、他のサービスの状態を監視し、停止しているサービスへのルーティングを行わないようにするサーキットブレーカーと呼ばれる機能によって、ブロックを防ぐことが一般的です。

サービスメッシュを利用しない場合は、各サービスでこのような機能を実装する必要がありますが、proxy はサービスの死活監視などパッシブとアクティブな監視により、このような機能が実現されます。

分散システム全体にポリシーの適用を分散化

サービスメッシュの proxy はポリシーを適用する機能が組み込まれています。

これを適用することで、ゼロトラストネットワークに必要な、認証 (JWT認証、mTLS 等)、認可 (OPA等) によるネットワークセキュリティの実行が可能です。

例えば、NIST (米国国立標準技術研究所) の「Zero Trust Architecture (NIST SP 800-207)」を参考にあてはめると次のようになります。

ZTA

可観測性と関連データの収集の標準化

可観測性とは、「マイクロサービスアーキテクチャ 第2版」によれば、

システムの可観測性とは、外部出力からシステムの内部状態をどの程度把握できるかです。

サービスメッシュの proxy はアクセスログ、サービスのログ、メトリクス、分散トレーシングデータ等を収集し配信できます。

各サービスへのプロダクト固有のエージェントの組み込み等を回避できます。

最後に

サービスをコンテナ化する大きな利点は、サイズの小さいイメージを作成することで、起動が俊敏となり、ミリ秒単位でスケールイン/アウトできることにあると考えています。

このためには、コンテナで実装するサービスは、可能な限り少ない責務のドメインに特化したコードのみとし、外部化が可能な実装はサービスメッシュでも実現されているように、サイドカーやコントロールプレーンとデータプレーンの分離等のコンセプトを取り入れることが必要でしょう。

さらに、サービスメッシュは、Feature Flags (Feature Toggles) や Blue/Green デプロイ、カナリアリリース等を実現できる機能もあります。

参考