2026/04/10

webアプリケーションのクラウドでの性能優先設計

宣伝です。

noteでマガジン「webアプリケーションのクラウドでの性能優先設計」を公開しました。↓こちらの写真が目印です。クラウドの記事なので雲が主役(?)の写真を見出しに使ってます。


2026/03/01から公開していましたが、noteのフォーロー中のトップから外れるとページビューが激減したので、ここでも宣伝してみることに。


内容はタイトルどおりですが、クラウドでwebアプリケーションを実装するにあたって網羅的に必要な知識・技術から書いています。特に運用コスト削減に関する内容が多くなっています。処理性能については良くするというより、必要な性能を確保するという内容になっています。

このブログでは散発的な記事しか書いていませんが、このブログに書いていない内容の方が多くなっています。

以下のような問題に遭遇した方は、ぜひ読んでいただきたいと思っています。解決策が見つかるはずです。

  • 費用
    • クラウドを使っているけど運用費用が想定より高い。
    • クラウドに乗り替えたらオンプレミス/レンタルサーバより運用費用が増えた。
  • 性能
    • スケーリングができない。
    • リクエストの処理に時間がかかる。
    • スケールアウトのたびにリクエストのレイテンシが増加してレスポンスが悪い。

    • その他
      • そもそもクラウドをどのように使えばいいのかわからない。
      • 非同期処理/バッチ処理の効率的な実装方法がわからない。
      • 非同期処理が意図せず中断する。


    またクラウドで使われる以下の技術についても、詳細や使いどころを説明しています。

    • スケーリング
    • サーバレスアーキテクチャ
    • マイクロサービスアーキテクチャ


    A4サイズでデザインしたところ全部で100ページ近い分量になりました。読みごたえがあります。noteでは 1記事=1ページ なので、長い記事は読みにくくなります。それを回避するため複数の記事に分割し、まとめてマガジンとしています。

    分量や、経験からしか得られないノウハウも掲載していますので、有料としています。今は試しにマガジンのみ半額にしています。いつまで半額かは未定で気分次第ですので、興味のある方はお早めに。


    2026/04/07

    Cloud Runのインスタンスベース料金

    Cloud Runの料金体系についての疑問

    Cloud Runサービスには2種類の料金体系があります。

    • リクエストベース(デフォルト)
    • インスタンスベース


    デフォルトのリクエストベースの料金体系はおなじみです。webサーバを構成するCloud Runサービスの機能とも一致していて、わかりやすいのですね。

    一方でインスタンスベースの料金体系はどういう状況で使うべきなのかずっと理解できませんでした。


    インスタンスベースの料金体系

    この疑問については偶然ですが、ブログ記事「新しい CPU 割り当てコントロールにより Cloud Run 上でさらに多様なワークロードを実行」を見つけて理解できました。

    2021/09/28とちょっと古い記事なので、時期的にはCloud Runにはまだサービスしかありません。Jobsはまだリリースされていません。Cloud Functionsはまだ第1世代のみで、Cloud Runとは独立したプロダクトという位置づけでした。


    結論ですが、ユースケースとしてはCloud Runサービスでサブスレッドを使って非同期処理を実行する場合を考慮したものでした。Cloud Runサービスではメインスレッドでリクエストを受信後、そのメインスレッドでレスポンスを返すと処理が終了したものと判断されます。そしてリクエストを処理していないインスタンスは、その後一定時間新たなリクエストが割り当てられないと、スケールインしてスピンダウンする対象となります。

    ここでリクエスト開始~レスポンスを返すまでの間にサブスレッドを生成し、そのサブスレッドでメインスレッドよりも時間のかかる処理を行う実装を行っているとします。メインスレッドがレスポンスを返してしまった時点で、プラットフォーム(Cloud Runサービス)からは 処理中のリクエスト数=0 と見えてしまい、インスタンスのスピンダウンが起きます。この時点でまだサブスレッドは実行中だと、完了前に強制終了させられることになります。




    これを避けるために上記の記事にあるように、CPUの常時割り当ての機能が追加されたということです。最小インスタンス数の設定と組み合わせることで、インスタンスの強制終了によるサブスレッドの停止を回避できます。そしてそれに対応する料金体系がインスタンスベースということでした。


    歴史は繰り返す?

    App Engineでも同じ問題は起きていましたね。App Engineだけ使う場合はサブスレッドを諦めて、タスクキューで解決していました。

    Cloud RunでもCloud Tasksと組み合わせれば同様の方法で回避可能です。


    より新しいソリューション

    現在では非同期処理を実装するためには、BatchやCloud Run Jobsが用意されています。これらはスレッドだけでなくタスクでも並列処理を実装できます。タスクの方がCPU・メモリリソースを分け合わないので、実装やパフォーマンスチューニングは簡単です。起動に時間がかかりますが。


    2026/02/09

    生成AIに対する既視感

    Oh, deja vu!

     現在AIが絶賛大人気、話題の中心となっています。会話が出来て、プロンプトさえ書けば絵が描けて動画も作ってくれて。もう何でもやってくれそう... という意見さえ、あったような、なかったような。

    しかし話題になり始めたころから、過剰に期待しすぎているようにしか感じない、この盛り上がりに既視感を感じていました。1980年前後のSF映画には「コンピュータ様がなんとかしてくださる」みたいなシーンが登場することがあります。それに似ているような感覚があります。


    でも進化? も

    以前との違いは、これまでの現実感がなくて絵空事で終わっていたAIと違って、今の生成AIはやる気になれば自分で使うことができますし、そうでなくてもチャットによるサポート(しかし期待する答えが返ってきたことは1度もない)などの形で一般の生活の中でも目にするようになっています。

    私がかかわっているIT業界では、もっともAIが身近ではないかと思います。調べ物に使ったり、ドキュメントを書かせる人もいたり(私は自分で書くのでやってませんが)、コーディングでのコード補完やレビューと、私でもそれなりに使っています。


    今の生成AIはバブル疑惑

    しかし調べれば調べるほど、今話題の生成AIも、バブルで終わりそうな気配しか感じません。根拠は私が読んだものの一部のみ紹介、過去読んだものは探し出せなくなったものも数多くあります。

    その他にも「経験の浅い技術者がAIでクソコードを量産してレビューが地獄」等など「使えない」事例や、将来性に疑問があることの根拠は、きりがないくらい出てきます。


    半端なAIなら いらなくない?

    巷の反応を見ていると、現在の生成AIと、まだ実現されていない汎用AI(AGI)を混同している人も少なくない気がします。現在の生成AIは、目的特化で実現されたものであって、汎用ではありません。向かないことをさせれば、ボロを出します。

    現在の生成AIは、出来ることが限られていることや、ハルシネーションの影響、期待する結果に近づけるためにはユーザの努力が要求されるなど、期待させている割に性能的には中途半端と判断しています。正直、この程度ならなくてもそんなに困りません。

    現在の生成AIに限ってですが、最も上手く使いこなした例はこちらのような動画ではないでしょうか(でも詩を作ったのはAIじゃなさそう)。おもちゃにするにはいいのですが、実用品として例えるならその実力は、手間・実用性などからT型フォードあたりがふさわしい気がします。


    今後はおそらく、有効な使い方が判明するにつれて特定の分野・使い方で限定的に残っていくものと思われます。その結論が出始めると、バブルも終わるでしょう。


    2026/01/17

    RDB脳に注意

    RDB脳 って何

     俗に「RDB脳」と呼ばれる現象の発生が、ソフトウェア開発者の中で知られています。

    これは、リレーショナルDBを利用してきた技術者が、非リレーショナルなDBを使おうとした際に、以下の現象がみられるものです。

    • 非リレーショナルなDBの仕様の理解に苦しむ。
    • 非リレーショナルなDBを使いこなせず、十分な性能が出ない。


    非リレーショナルなDBの登場について

    歴史的にはリレーショナルDBの欠点を解決するために登場したのが、非リレーショナルなDBと考えていいと思います。リレーショナルDBの欠点は、具体的には以下ではないかと思います。

    • プライマリキー
      レコードを唯一に識別する仕組みとして使用されているがプライマリキーです。単純にユニークな値を持つ単独のIDとかで十分なのに、わざわざ複数のデータを使うのは不自然です。
      リレーショナルDBが普及し始めた当時は、今と違ってまだストレージが高価だった時代ですので、ストレージの節約は重要でした。少しでもストレージを節約するために、データの一部をIDとして利用することで、記録に必要な容量を減らす仕組みがプライマリキーであると考えられます。IDだとユニークにするためには短くないはずですので、それさえも削減したいということでしょう。
      (CassandraやDynamoDBのように非リレーショナルでありながらプライマリキーの概念があるDBも存在します)
    • Write on Schema
      レコードを記録する前に、レコードのデータ構造であるスキーマを決定しておく必要があります。当然スキーマと異なるデータ構造は記録できませんので、データ構造の変更は容易にはできません。
      またレコード間でスキーマを揃えなくてはならないので、実際にデータが保存されているのは一部のフィールドのみという無駄が発生する状況になることもあります。
    • スケーリングへの対応能力
      クラウドで処理能力を拡大/縮小する仕組みであるスケーリングへの対応が難しいようです。そのためクラウドベンダーの用意したクラウドネイティブなリレーショナルDBでない場合は、スケーリングへの対応はレプリカの設定程度に限定されます。


    非リレーショナルなDBのプロダクト

    Google Cloudだと以下が非リレーショナルなDBです。

    • ドキュメント指向DB
      • Firestore
    • キー・バリュー型DB
      • Bigtable
      • Memorystore(Redis/Valkey/memcached どれもキー・バリュー型)
      • Datastore(Firestoreの前身のいにしえのDBであり、すでに提供終了)


    RDB脳を生み出す原因

    RDB脳を生み出す原因となっているのは、リレーショナルDBと非リレーショナルDBの仕様や使い方の違いと思われます。具体的には以下が該当しそうです。

    • SQL   vs.   NoSQL
      リレーショナルDBは一般的にはSQLで利用されます。
      それに対して非リレーショナルDBは、「Not only SQL」を略して「NoSQL」と表現されるように、SQLを使用しません。SQLライクな言語が用意されることもありますが(例:CassandraのCQL)、そもそも言語で操作が不可能なDBもあります。
    • Write on Schema   vs.  Read on Schema
      非リレーショナルDBがNoSQLである理由の1つです。
      「Write on Schema」は、データの書き込み前にスキーマを決定しておく必要があることを表しています。リレーショナルDBで採用されています。
      「Read on Schema」は、データの書き込み時にはスキーマを固定しておく必要はありません。かと言ってスキーマが存在しないのではなく、データを読み出すとスキーマが判明します。そのためデータごとにスキーマが異なる可能性があります。
    • プライマリキー   vs.   ID/キー
      リレーショナルDBで一般的に使われるSQLでは、レコードを一意に識別するために、レコード内の複数のデータを組み合わせてプライマリキーとして利用します。
      非リレーショナルDBで用いられるIDまたはキーは、それだけでデータの記録場所を特定できます。
    • 正規化   vs.   非正規化
      リレーショナルDBの場合は通常、1つのデータは1つだけ保存されるようにデータ構造を最適化する正規化を行います。これによりデータの一貫性を保証します。
      非リレーショナルDBでは、読み出し時のレスポンスを確保するためにあえて非正規化する場合があります。
    • CURDの概念
      非リレーショナルDBでは一般的に、CreateとUpdateの違いがありません。どちらも書き込みであり、新規追加か既存更新かは意識しません。
    • 取得の概念
      リレーショナルDBで一般的に使われるSQLには、検索と取得の区別がありません。データを取得するためには、検索します。レコードの識別がID/キーではなく、プライマリキーという複数のデータであることに起因しています。
      非リレーショナルDBでの取得は、ID/キーを使用して一発で取得できます。そのため検索は別の機能です。またキー・バリュー型DBの場合は、検索が用意されていないこともあります。
    • インデックスの扱い
      リレーショナルDBでは検索の高速化のために任意で使用しますが、非リレーショナルDBでは単に検索するために予めインデックスを作っておく必要があることもあります。


    事例

    実際RDB脳でやらかしてしまったと思われる事例は、ネットでも見つかります。


    Firestore → Cloud SpannerでDBコスト93%削減!無停止でやり切った 1 年間の全記録

    どのような処理を行っているのか説明されていないので推測ですが、状況からRDB脳案件の可能性があります。DBマイグレーションしてますが、移行先がRDBのSpannerなので、RDB脳なら問題なく使えるのは当たり前です。
    FirestoreはサーバレスなのでI/O数によって課金される仕様です。そのため無駄にI/Oを行う実装になっていると、この記事のような運用コストの問題が発生します。まずは無駄なI/Oを削減する必要があります。ロジックを見直すのが本来の解決方法ですが、MemorystoreやFirestore Data Bundlesでキャッシュするのも有効な解決手段となります。
    あるいは本来Firestoreが向かない用途に使ってしまったケースかもしれません。

    Spanner は本当に高い?思ったよりも低い Firestore との損益分岐点
    上記の記事と同じ状況と思われます。無駄にI/O行う実装になっていないか疑問があり、結論の信憑性に大きな疑問があります。

    DynamoDB設計で痛い目にあった話 – RDB脳から抜け出すための実践ガイド
    非リレーショナルDB初心者にありがちな失敗談が語られていて、共感できます。
    プライマリキーやインデックスがテーブル作成時にしか指定できないのは不便そうです。


    以下は参考になりそうな記事。

    非リレーショナルDBでテーブルを実装するケースで参考になりそうです。正規化/非正規化という点に着目している点がおもしろいと感じました。
    しかし非リレーショナルDBではテーブルにする必要がない点で、非リレーショナルDBでの実装が必ずこのようになるというわけではありません。結果整合性についての記述もそれを採用したDBではそのとおりですが、強整合性のDBではあてはまらないことに注意が必要です。

    ある夏のFirestoreのこわい話
    うっかりやらかしていたことに気付いて改善した例です。この例はSQLでも同じ問題が起きます。やらかしていることに気づきにくく、思わず同情してしまいました。


    「DB = リレーショナルDB」は過去の話

    現在では非リレーショナルなDBも当たり前に使われるようになっていますが、いまだに非リレーショナルなDBの存在を知らない人に出会ったことがあります。リレーショナルDBと非リレーショナルなDBは、使い分けが重要です。


    RDB脳を回避する方法

    リレーショナルDBに慣れた方が、新たに非リレーショナルDBを学ぼうとする場合、RDB脳に陥る可能性があります。まず非リレーショナルDBを学ぶ前に、リレーショナルDBの知識・経験をきれいに忘れてください。

    ...と言っても、現実はそんな都合よく忘れられるわけがないのが困ったところです。


    私の場合はドキュメント指向DBから入ったという経緯もあり、私だけかもしれませんが、後から学んだリレーショナルDBが「ヘンテコな仕様」に見えました。具体的には以下が理解しがたかったと記憶しています。

    • SQL → なんで言語にする? やるならGUIだろ。
    • プライマリキー → なんでIDじゃないの?
    • 取得がない → なんで検索(query)しかないの?
    • Write on Schema → 実装は難しかしそうなので、仕方ないか。
    • JOIN/MERGE → 意味不明。


    RDB脳を回避するには、まずは非リレーショナルなDBについてそれが生まれた背景や、目指すところの違いを意識するのが早いのではないかと思います。そうすれば自ずと特徴や使いどころも理解できるのではないでしょうか。


    2025/12/12

    残念な AppRun

    ガバメントクラウドに暫定認定の「さくらのクラウド」で、 2025/12/09にAppRunがリリースされました。

    さくらインターネット、アプリケーション実行基盤「AppRun」の正式サービス提供を開始 〜専有型と共用型の2プランを同時リリース、用途に応じた柔軟な実行環境を実現〜


    おめでとー と喜びたいところですが...


    「占有型と共用型」... なにそれ。上記のリリースニュースを読めばわかりますが、共用型はこれまでプレビューリリースだったもの、占有型は新たに追加されたものとあります。


    そして占有型は「CPU使用率ベースでのスケーリング」であると...

    コレいらない。


    一般的には市場に提供されるサービスはwebアプリであることが多いと思いますが、webサーバのスケーリングはリクエスト数ベースでないと適切にスケーリングできません。CPU使用率ベースでは手遅れになってからスケールが始まります。

    まあ、占有型を無視して共用型を使えばいいことですが。


    さらに言えば、フロントエンドであるwebサーバはオートスケールが必要ですが、バックエンドではオートスケールは邪魔になるケースのほうが多くなります。バックエンドに必要なのは実行開始時にスケールを指定できるマニュアルスケールです。

    バックエンド向けのプロダクトはこれから出てくるのでしょうか。


    料金体系も異なりますので、おそらくこの料金体系を反映させるための仕様でしょうか。

    期待していたのに残念です。


    2025/12/07

    「なんとか as a Service」って、何種類あんねん

    この記事のタイトルが どこかで聞いたことのあるような... いや聞いたことないことにしてください。


    XaaS

    面白い記事を見つけてたので紹介します。

    AaaS、BaaS、CaaS、DaaS、、、 どこまであるの?調べてみた!

    最後のオチが...


    実際には上記の記事で紹介されている以外にもXの部分は、AIaaSとかSECaaSのように2文字・3文字に増えているものや、iDaaSのように2文字かつ小文字混じりのものもあります。

    もう本当に増えすぎていて、まとめてXaaSと呼ばれるようになっていますね。


    CaaS

    CaaSの読みとして「カース」と紹介している記事を見受けますが、これだけXaaSがあると、この読み方には違和感を感じています。

    • KaaSも「カース」で区別がつかない。
    • MaaSは「マース」?  SaaSは「サーズ」? これらの読みは一般的にはMERS・SARSの方が有名なので、印象が悪い。
    • IaaSのように発音が難しいうえに頻出するものがある。
    • DaaSは某企業様から訴えられそう。と思ったらDARSだった。

    KaaS

    もう一つの違和感。
    KaaSは「kubernetes as a Service」の略と紹介されることが多いですね。Knativeを忘れていませんか。実際に有用なのはkubernetesではなくてKnativeの方であることが多いので、KaaSには「Knative as a Service」の解釈も追加すべきだと思います。

    2025/10/13

    LotteryServアップデート

        LotteryServを更新しました。今回の更新は1つだけです。


    応募画面を独自デザインに対応

     応募画面を募集ごとに、独自のデザイン/UIに対応可能にしました。


     これまで応募ページはデフォルトのデザインのみで、主催者様の好みに合わせた内容・デザインを使えませんでした。

     今回のアップデートで、主催者様で応募ページのコンテンツ(HTML/CSS/JavaScript)を作成し、それをアップロードしていただくことで、独自デザインの応募ページを表示することが可能になりました。応募ページ内に画像や動画を表示することも可能です。いくつか約束事はありますが、それさえ守っていただければ、応募ページは自由なデザインをご利用いただけます。

     応募ページに独自コンテンツをアップロードするには、募集詳細画面から「コンテンツ編集」ボタン押下で遷移する「コンテンツ編集」画面で操作します。


     応募ページのコンテンツには以下の制限があります。

    • 最低1つのHTMLをアップロードする必要があります。
    • HTMLは複数アップロード可能ですが、応募者に最初に表示されるメインページを設定する必要があります。
    • ディレクトリなどの階層構造は利用できません。
    • 応募や抽選結果の確認のためにJavaScriptを用意してあります。それを読み込み、適切に使用する必要があります。


     独自コンテンツのアップロードがない場合、従来どおりのデフォルトのデザインのページとなります。アップロードしたコンテンツの削除も可能です。アップロードしたすべてのコンテンツを削除した場合は、デフォルトのデザインで応募ページを表示します。

     より詳しくは各画面のヘルプをご覧ください。


    2025/08/25

    Docker+Kubernetesでいいの?

    動機

     前スレの『さくらのクラウドとサーバレスアーキテクチャ』で書いた以下について説明不足と感じたので、ここで詳しく書いておこうと思います。

    「クラウドに移行したもののランニングコストが予測よりずっと高く、期待したように下がらない」という話を時々聞きます。

    自治体システム標準化、ガバクラ移行で運用コスト2~4倍に悲鳴「議会に通らない」(有料記事ですが1ページ目のみ無料で閲覧可能)

     ガバメントクラウド移行で自治体の年間コストが5.7倍に…計画の重要性

     ガバメントクラウド移行で自治体の運用コストは本当に下がるのか?

    上記の引用はガバメントクラウドに関するものですが、過去に私が関わった民間企業のwebアプリケーションでも同様の現象が起きていました。この企業で使っていたのもKubernetes(GKE)ですが、「思うようにスケーリングできない」ので無駄にリソースを割り当ててアプリケーションを実行しているという状況でした。


    問題点

    クラウド上に実装されたアプリケーションで「Dockerコンテナに突っ込んでKubernetesでオーケストレーション」という作りをよく見ますが、webアプリケーションでこれが有効なケースは、実際にはごく一部に限られます。

    実際にはこの構成でwebアプリケーションを実装すると、以下の問題が発生します。

    • オートスケールを設定しているのに、リクエストの急増でサーバビジーが発生する。
    • (上記のように)運用コストが高いケースがある。


    原因

    クラウドがオンプレミス/レンタルサーバに比べて有利になる要因は、スケーリングの恩恵によるところが大きくなっています。

    従来(オンプレミス/レンタルサーバ)では、あらかじめ契約により用意したリソースの中で、それを有効活用できるようにユーザがやりくりしていました。確保されるリソースは契約で変更するのが前提なので、迅速な変更はできず、これがリソースの無駄の原因となっていました。

    対するクラウドでは、複数のプロジェクト(これには他人のプロジェクトも含みます)にまたがってデータセンター全体の中で、リアルタイムでリソースの割り当てを変更することで、リソースの無駄を削減します。アプリケーションは必要なものを、必要な時に、必要なだけ確保します。ここが従来と最も異なる点です。リソースの無駄がなくなることによって運用コストが下げられます。


    ここまでならKubernetesによるオートスケールでも実現できそうに感じるのですが、実際には一般的なwebアプリケーションでは、そう思いどおりにならないケースが多いようです。


    一般的なwebアプリケーションではエンドユーザの操作に従ってクライアントからリクエストが送信され、サーバがそれに答えます。この間はエンドユーザが待っているので短い方が好ましく、一般的には1秒以下、瞬間的に遅くなっても3秒程度が限度とされます。

    Kubernetesによるオートスケールは一定時間間隔でCPU負荷を監視して、Pod/ノードをスケーリングします。そのため負荷の変化が起きてからでないとスケーリングは始まりません。負荷を急増させるリクエストがあっても、そのリクエストはすでに処理を開始した後なので、スケーリングの恩恵を受けられません。

    またwebアプリケーションのリクエストの一般的な処理時間に比べて、Kubernetesによる負荷監視の間隔はあまりに長いことが多く、適切な監視およびスケーリングを行いきれません。監視間隔を短くすれば改善できるでしょうが、CPU負荷の測定そのものがコンテナに負荷をかけるので、短いのも悪影響があります。

    さらにPodの水平スケールは秒単位で終わりますが、ノードのスケールは分単位で時間がかかります。これだけ長いとエンドユーザは待ってくれません。


    つまりKubernetesでのオートスケールが有効なのは、負荷の変化が比較的ゆっくり(分単位かそれ以上)の場合です。急激に変化する場合は追従しきれず、サーバビジーを発生する原因となります。


    解決策

    解決策の構成の1つが以下です。

    webサーバのオートスケールのコントロールをKubernetesではなく、Knativeで行うことで改善が期待できます。KnativeはKubernetesに替えてサーバレスアーキテクチャに基づいてスケーリングを行います。
    webサーバの場合はリクエストはイベントとして処理され、リクエスト数がスケーリング指標となるので、CPU負荷に頼らずスケーリングが可能です。リクエストがプラットフォームに届いた時点でスケールアウトの必要性が判断され実行されるので、スケールアウトの要因となったリクエストもスケーリングの恩恵を受けられます。そのためサーバビジーは発生しにくくなります。
    またCPU負荷監視の間隔がスケーリングに与える影響が少なくなり、負荷の変化に対して迅速なスケーリングが可能となります。これによってリソースの無駄がなくなり、運用コストを削減できます。

    Knativeを利用したApp EngineやCloud Runサービスを長年使ってますが、ノードのスケールアウトに相当するケースに遭遇したことがありません。ノードについてはプラットフォーム側である程度プールしているものと推測されます。ノードのスケールインは観測できないので、いつ起きているのか不明です。

    またKnativeには、複雑なKubernetesの設定を簡略化してくれるという側面もあります。

    設計

    ユーザが自分でKnativeを組み込むことはまずなく、一般的にはすでにKnativeが組み込まれたPaaSを利用します。Google Cloudでは以下が該当します。
    以下はKnativeだけどPaaS以外。

    Knativeによるサーバレスアーキテクチャでの実装については、アプリケーション(=コンテナへの分割の仕方、コンテナの中身)の設計・実装も従来とは変える必要があります。これはモノシリック構成に替えてマイクロサービス化する程度では対応できません。スケーリングがいつ起きてどこに影響するのかを考慮する必要があります。
    具体的にどうすればいいのかは、長くなるのでまた別の記事で。(書くかもしれませんが書かないかもしれません)

    例外

    論理的に、アクティブユーザ(=同時接続していて操作しているユーザ)が十分多い大規模アプリケーションの場合、各ユーザの操作が平均化されて極端な負荷の変化が起きにくくなる可能性があります。このような場合はKubernetesによる緩慢なスケーリングでも十分となる可能性があります。
    しかしこれに該当するには相当な規模のアクティブユーザ数が必要なようです。具体的にどの程度の規模が必要かを知るには、私自身もこの業界もまだ経験が足りないようです。toBの規模ではないと想像しています。toCでは「何時から開始」のようなサービスを提供するケースで、緩慢なスケーリングでは一時的に対応できなくなる可能性が高くなります。
    またどのようなサービスでも最初は小規模から始まるものなので、ある程度の規模がないと効果がないKubernetesよりKnativeのほうが、損失を抑えながらサービスを立ち上げることができるという利点もあります。

    またイベントドリブンではなく、要件やアプリケーションの仕様(操作方法)の工夫によってスケーリングの要求を緩慢なものにできるアプリケーションでは、Kubernetesで十分な性能を発揮できることがあると思われます。

    まとめ

    以下はwebアプリケーション、正確に言えばその中でも、エンドユーザからのリクエストを処理するフロントエンドを構成するwebサーバに限った話です。

    コンテナの中身については、クラウド以前の古い設計・実装のままでも機能的には動くかもしれませんが、それではKubernetesにせよKnativeにせよ、性能面でクラウドが能力を発揮することはまずないでしょう。
    オーケストレーションについては、ここで最適なのはKubernetesではなく、Knativeです。クラウドと同時に登場したサーバレスアーキテクチャこそが、イベントドリブンの場合の本来の使い方だと言えます。

    最後に

    「従来の設計・実装のままDockerコンテナに突っ込んでKubernetesでオーケストレーション」という例が未だになくならないのは、クラウドの使い方を理解している人が少ないだけでなく、仕事を受注してお金を稼げればいいだけの意識の低い受託開発業者が多く、発注側もこのような技術面での認識が出来ていないということだと思います。
    もう少し踏み込んでモノシリックな構成から脱却しマイクロサービスアーキテクチャを取り入れているケースや、DDD(ドメイン駆動設計)を取り入れているケースもあります。これらはコンテナの使い方を意識したものと思われますが、スケーリングを考慮しないならクラウドでの効果は限定的です。またコンテナの分割の仕方によっては逆効果となる可能性もあります。

    営利目的のサービスの場合は、多少運用コストが高くても売り上げを増やせば利益を確保できます。しかし行政のような直接売り上げを生み出さないアプリケーションの場合、運用コストの増大は危機的な悪影響となります。まして行政の場合は潜在ユーザは多いもののアクティブユーザは僅かと考えられますので、事実上有望な選択肢はサーバレスアーキテクチャの一択となります。

    2025/07/18

    さくらのクラウドとサーバレスアーキテクチャ

    さくらのクラウドの注目記事

     私が現在利用しているクラウドはGoogle Cloudのみですが、その他には国産クラウドである「さくらのクラウド」にも興味を持っています。現在ガバメントクラウド認定を目指して整備が進められているさくらのクラウドですが、そのアプリケーション実行基盤である「AppRun」はサーバレスであることが発表されています。

    さくらインターネット、アプリケーション実行基盤「AppRun β版」にて製品版のトライアルを開始

    さくらのクラウド、コンテナをサーバレスで実行する「AppRun」製品版トライアルを開始。トライアル中は全機能が無料に


    サーバレスアーキテクチャとは

    2008年のApp Engineリリースから使えるようになったものなので、まだご存じない技術者も見かけます。理解が簡単ではないので、普及はこれからといった印象です。またFaaS(Function as a Service)と混同しやすいので注意が必要です。


    サーバレスアーキテクチャは、このブログの記事「サーバレスアーキテクチャ」でも説明しています。コンピューティングにおいては、アプリケーションの実行インスタンスは常に起動しているわけではなく、必要な時に必要な分だけのリソースを割り当ててアプリケーションの実行を行うアーキテクチャです。リソースの管理はプラットフォームがやってくれるので、ユーザは意識する必要がありません。

    サーバレス アーキテクチャとは

    サーバーレス・コンピューティングとは

    クラウド以前の従来のサーバは想定された利用状況に応じてあらかじめリソースを割り当てておきます。リソースの管理は、夜間など利用の少ない時間帯にバッチ処理を走らせるなど、計画的で柔軟性はありません。

    クラウドでも非サーバレス場合は、最低1つ以上の実行インスタンスが常に割り当てられます。夜間バッチの実装など従来と変わらない設計が主流です。

    それに対してサーバレスアーキテクチャでは、リアルタイムで必要なだけリソースを割り当て/開放します。これによりランニングコストの低減や、サーバビジーによる一時的なサービス提供不能の発生低減が期待できます。これはユーザにとって大きなメリットとなります。


    しかしクラウドベンダー目線で考えると、上記とは違う特徴を実現することが目的ではないかと考えられます。

    リアルタイムにリソース割り当てを変更できることから、データセンター全体でリソースを有効利用できるようになります。またリソースの割り当ては基本的に永続的ではなくなるので、ハードウェアのメンテナンスをしやすくなる(ユーザにとってもメンテナンスの影響を受けにくくなる)利点も考えられます。


    「みんなのクラウド」と表現されることがありますが、データセンターのリソースをユーザみんなで共有し、その割り当てをより柔軟にして(非サーバレス以上の)最大限の効果を狙うのがサーバレスアーキテクチャであると言えると思います。


    サーバレスアーキテクチャの現状

    現在の日本のwebアプリケーションは、まだサーバレスアーキテクチャを採用したものは少ないように見えます。キーワードとしてKubernetesが出てくるアプリケーションは、サーバレスアーキテクチャではありません。それどころかクラウドに最適化されていなくて従来の延長線上でしかないものもあるようです。

    現在クラウドの利用方法の主流は、Docker+Kubernetesの構成と思われます。この構成が流行った要因は以下のようなものと考えられます。

    • どのクラウドベンダーでも同じように実装でき、ベンダーロックインが発生しない。これは特に受託開発やSESにとって好都合。
    • クラウド以前の従来の技術・知識・プロダクト(ライブラリ、フレームワーク)を使いまわせる。新たに覚えるべきことはDockerとKubernetesのみ。
    • Kubernetesによって一応スケーリングも可能なので、スケーリングの恩恵も得られる。
    主に開発者の都合が中心です。ひどい場合はDockerコンテナにクラウド以前のレガシーな構成をそのまま詰め込んだだけのケースもありそうです。Kubernetesでスケーリングさせているつもりが、その効果さえ確認していないケースもあるようです。クラウドに最適化しないのであれば、クラウドによる恩恵も最低限しか受けられません。


    サーバレスアーキテクチャではコンテナオーケストレーションにはKubernetesではなく、Knative(あるいは相当のもの)を用います。


    ランニングコストについて

    「クラウドに移行したもののランニングコストが予測よりずっと高く、期待したように下がらない」という話を時々聞きます。

    自治体システム標準化、ガバクラ移行で運用コスト2~4倍に悲鳴「議会に通らない」(有料記事ですが1ページ目のみ無料で閲覧可能)

     ガバメントクラウド移行で自治体の年間コストが5.7倍に…計画の重要性

     ガバメントクラウド移行で自治体の運用コストは本当に下がるのか?


    上記の引用はガバメントクラウドに関するものですが、過去に私が関わった民間企業のwebアプリケーションでも同様の現象が起きていました。この企業で使っていたのもKubernetes(GKE)ですが、「思うようにスケーリングできない」ので無駄にリソースを割り当ててアプリケーションを実行しているという状況でした。

    他の原因の1つは、クラウド以前の従来のアーキテクチャを引きずったまま移行していることにあるのではないかと考えられます。クラウドに最適化しないのであれば、クラウドに乗り換える効果も限定的でしかないのは想像に難しくありません。


    その他にも、従来の手作業・紙ベースの手順をそのままにしておくことを優先したため、コンピュータ処理に適さない手順を無理やり実装したことによる弊害もあると考えられます。これは今に始まったことではなく、クラウドやアーキテクチャによるものでもない別次元の話なので、本記事ではこれ以上取り上げません。


    サーバレスアーキテクチャでの実装

    実際にサーバレスアーキテクチャで実装するには、対応するPaaSのプロダクトを利用することになります。しかしそれだけでは実装後に以下のような性能上の問題が発生することがあります。

    • レスポンスが悪い、または悪くなることがある。
    • バッチ処理などバックエンドの処理に時間がかかる。
    • ランニングコストが下がらない。
      (使い方を間違うと効果は得られない)
    • コストの予測が困難。
      (スケーリングする限り非サーバレスでも同じだが、より変化が大きい)


    サーバレスアーキテクチャを有効に使いこなすためには、それに対応した設計が必要となります。ここでのノウハウにはサーバレスアーキテクチャを実装した経験からしか得られないものもあります。具体的にここで書ききれる量ではないので別の機会に。

    しかしサーバレスアーキテクチャを使いこなせば、スケーリングを最大限に活用できて以下の効果を得られる可能性があります。

    • ランニングコストの削減。
    • サーバビジーによる一時的なサービス不可の減少。


    技術的課題

    従来のサーバは「起動しておいて必要とされるのを待つ」思想で実装されています。しかしサーバレスアーキテクチャでは「必要とされたから起動する」という思想に変わります。そのためwebサーバのような「ユーザが待っている」ケースでは、起動の遅い実装はユーザを待たせる悪いユーザエクスペリエンスにつながります。バックエンドのような起動の遅延が影響しないケースでは無視できます。

    これにより従来のプロダクト(サーバレスアーキテクチャを考量していないライブラリやフレームワーク)が使い物にならなくなっているケースがあります。フレームワークの場合はそれを理解せず使用してしまうと、ほぼすべて再実装でしか改善できないほどの影響も考えられます。たとえ人気で過去に実績もあるプロダクトといえど、サーバレスアーキテクチャを考量してなくて悪影響となるものは、早めに清く捨て去る必要があります。

    この思想の違いは開発者にとっては、パラダイムシフトとも言えるほどの影響です。これはサーバレスアーキテクチャの理解や使いこなしを難しくしています。


    またクラウドベンダーにより対応の方法がバラバラです。簡単にサーバレスアーキテクチャへの対応をまとめると、以下のようになります。

    • Google Cloud
      • App Engine(Standard Environment):独自コンテナ+Knative、webサーバ。
      • Cloud Run:Docker+Knative。
        • Service:webサーバ。
        • Function:FaaSとしての利用形態で実態はServiceと同じ。
      • GKE + Knative serving:もうCloud Runでよくない?
    • AWS:Serverless Application Modelに基づいてLambdaで実装。
    • Azure:Azure Functionsを利用。
    • さくらのクラウド
      • AppRun:Docker+Knative

    そのほかにIBM、Oracleも対応しているようです。

    AWS, AzureはFaaS(Function as a Service)の流用にとどまっており、あまりサーバレスアーキテクチャの採用に関して積極的に見えません。

    Google CloudはFaaSだけでなくPaaSも用意されており、対応が最も進んでいます。またwebサーバでなくバッチ処理でも同じように使えるプロダクト(Batch, Cloud Run Job)が用意されいます。これらは本来サーバでないのでサーバレスアーキテクチャと呼びませんが、「必要な時に必要な分だけ」リソースを使うことができる点においては同じです。


    さくらのクラウドに対する期待

    さくらのクラウドでは今後はサーバレスアーキテクチャが普及していくものと予測しているそうです。これは私も同意見で、世の中の技術者たちがサーバレスアーキテクチャの理解を進め、普及していくように活動しています。


    2025/06/20

    LotteryServアップデート

       LotteryServを更新しました。今回の更新は細かい仕様変更や不具合修正です。


    多要素認証の設定はEメールアドレスのみ必須に

     2025/05/06の更新で多要素認証に対応しましたが、同時に主催者の支払い方法を設定するにはユーザアカウントに多要素認証の設定を必須としました。しかしGoogleアカウントを利用している場合、Googleアカウントにパスキーや多要素認証が設定されているか否かを判断できないため、Googleアカウントの多要素認証とLotteryServの多要素認証で2回の第2認証が行われる可能性が発生しました。これは意味がないので、以下の仕様に変更しました。

    • Googleアカウントの場合は、LotteryServでの多要素認証設定は任意とします。ただしGoogleアカウントにパスキーを利用するか、多要素認証の設定を推奨します。
    • Eメールアドレスの場合は、LotteryServでの多要素認証設定は必須のままです。

    応募・抽選結果のCSVをZipアーカイブに

     応募・抽選結果はCSVファイルでダウンロード可能ですが、応募数が多い(100,000以上)場合は複数のCSVファイルに分割しています。これは少々古いバージョンのExcelでも扱えるようにするための仕様です。

     従来はCSVファイルを1つずつダウンロードする必要がありましたので、応募数が多い場合は面倒でした。今回の更新では、すべてのCSVファイルを1つのZipアーカイブにまとめる仕様に変更しました。ダウンロード後に解凍は必要ですが、ダウンロードの手間は軽減されています。


    ツールチップが表示されない不具合を修正


     操作可能なアイコンをマウスポインタでポイントすると、アイコンのそばにそのアイコンの説明を表示するのがツールチップです。上の図は主催者ログイン画面の告知リスト左下のリロードアイコンのものです。

     これを実装していたのですが、どこかの更新で表示されなくなっていました。おそらく2025/05/06の更新からだと思われます。気づくのに遅れましたが、今回修正しました。

     ただし全画面でツールチップに対応しているわけではありません。一部の画面では以前からツールチップには非対応です。なんとなくアイコンの見た目で機能は判断できると思いますので、今後もツールチップ非対応画面ではそのままの予定です。


    Angularの*ng~ディレクティブについて

    従来

     Angularでは状況に応じてHTMLの内容を変更する際に以下のディレクティブを使用します。

    • *ngIf
    • *ngSwitch, *ngSwitchCase, *ngSwitchDefault
    • *ngFor

     これらのディレクティブは以下のタグと組み合わせて使用することもあります。

    • ng-container
    • ng-content
    • ng-template

     使い方を説明した記事はネット上に既にたくさんあるので詳細は説明しませんが、以下のような感じになります。

    <div *nfIf="isProcessing; then processingMess; else doneMess"></div>
    
    <ng-template #processingMess>
        <span>処理中...</span>
    </ng-template>
    
    <ng-template #doneMess>
        <span>完了!</span>
    </ng-template>
    <div [ngSwitch]="processState">
        <span *ngSwitchCase="PREPARING">準備中.</span>
        <span *ngSwitchCase="PROCESSING">処理中...</span>
        <span *ngSwitchCase="DONE">完了!</span>
        <span *ngSwitchDefault> (?o?) </span>
    </div>
    <table>
        <tr *ngFor="let item of itemList">
            <td>{{item}}</td>
        </tr>
    </table>

     ngSwitchやngForの例はまだ何とかわかりますが、ngIfのようにng-templateなどとの組み合わせになると直感的でなくて、わかりにくいと大変不評です。


    Angular17以降

     Angular17で、以下の新しい構文が追加されました。
    • @if, @else, @else if
    • @switch, @case, @default
    • @for, @empty

     これらは直感的に書けるように改善されています。

    <span>
        @if (isProcessing) {
            処理中...
        } @else {
            完了!
        }
    </span>
    <span>
        @switch (processState) {
            @case ("PREPARING") {準備中.}
            @case ("PROCESSING") {処理中...}
            @case ("DONE") {完了!}
            @default { (?o?) }
        }
    </span>
    <table>
        @for (item of itemList; track item) {
            <tr>
                <td>{{item}}</td>
            </tr>
        }
        @empty {
            <tr>
                <td>空っぽです</td>
            </tr>
        }
    </table>

     @emptyに対応する*ng~ディレクティブはなさそうです。探してみたのですが見つかりません。


     一度使ってしまうと、もう*ng~ディレクティブには戻れません。


    2025/06/08

    LotteryServアップデート

      LotteryServを更新しました。前回2025/05/06の更新に続いて、今回の更新もセキュリティの強化が中心です。


    ワンタイムパスワード認証に対応

     多要素認証の第2要素として、ワンタイムパスワード認証を追加しました。

     多要素認証はログインできなくなった場合への備えとして複数の第2認証を登録することを勧めていますが、前回のアップデートで対応したSMS認証のみでは、複数のスマートフォン/携帯電話が必要になり、現実的とは言い難い状況でした。今回ワンタイムパスワード認証を追加したことで、スマートフォン/携帯電話は1台でも2つの第2認証に対応できるようになります。

     ワンタイムパスワードアプリは、以下の2つで動作することを確認しています。

    • Google Authenticator
    • Microsoft Authenticator


     ただし機種変更時の移行には、あらかじめワンタイムパスワード認証の設定をアカウントに保存するなど準備をしておくか、新旧2台を並べて操作するかが必要なようです。ご注意ください。


    第2認証の完全な削除を可能に

     前回のアップデートでは、第2認証を複数登録した場合は1つずつ削除が可能でしたが、最後の1つの第2認証は削除不可能という制限がありました。今回のアップデートでその制限はなくなりました。

     すべての第2認証を削除すると、ログイン・再認証は第2認証なしとなります。もちろんこの場合は多要素認証の設定がないので、アカウントは脆弱な状態となります。

     多要素認証の設定がないユーザでは募集の開始ができない制限は、前回2025/05/06の更新からのものです。この制限はクレジットカード決済の悪用による被害を防ぐためのものです。


    UIのモダナイズ

     前記ワンタイムパスワード認証の追加に伴い、主催者ログイン画面など一部の画面をモダンなデザイン・実装に変更しました。

     また他の画面でもごく一部に画面遷移やデザインを変更した個所がありますが、使い方には変化はありません。


    メールでログインでもアイコンを利用可能に

     Eメールアドレス/パスワードでログインするアカウントの場合、従来はアイコンが固定でした。

     インタネット上に公開されているアイコンがある場合、そのアイコンのURIを指定していただくことで、LotteryServ上でもそのアイコンを表示するようになりました。

     ただ、現在このアイコンを表示するのは、ユーザメニューの最初の項目のみです。


    その他軽微な不具合の修正

     詳細の説明は割愛いたしますが、軽微な不具合を複数修正しています。

    2025/06/06

    Firebaseコンソールの不具合

     Firebase Authenticationで多要素認証を実装しようとしていて発見した、Firebaseコンソールの不具合です。


    準備

    まずはテスト用の電話番号を登録します。SMSを受信できるスマホや携帯電話が2台以上あれば、テスト用の電話番号は不要かもしれません。

    テスト用電話番号の登録手順は以下のとおり。この手順を説明した記事は少なそうだったので、念のため記載します。

    1. FirebaseコンソールでAuthenticationを選択。
    2. 画面上部のタブで「ログイン方法」を選択。

    3. 「SMS多要素認証」の「変更」を押下。

    4. ダイアログの「有効にする」をチェックして
    5. 「テスト用の電話番号」を押下するとダイアログが伸びてテスト用の電話番号の設定が現れます。
    6. 適当な電話番号(日本なので"+81aabbbbcccc")と確認コード(10進数6桁)を入力して、
    7. 「保存」を押下。


    発生手順

    手順の際現にはSMS認証による多要素認証をFirebase Authenticationで実装したアプリが必要です。ない場合はFirebaseのquickstart-jsでも再現できます。

    以下にquickstart-jsによる再現手順を示します。

    1. SMS multi-factor authenticationを選択。

    2. 登録してある任意のアカウントのEメールアドレスとパスワードを入力して「SIGN IN」を押してログイン。
    3. 「ENROLL」を押下して第2認証のSMS認証の登録を開始。
    4. SMS認証に追加する電話番号を入力。準備で設定したテスト用の番号で十分です。

    5. reCAPTCHAをチェックしたら「SEND CODE」を押下。ここで"Firebase: Error (auth/requires-recent-login)."が発生したらいったんSIGN OUTし、手順2からログインしなおし。
    6. 届いたSMSに記載されている認証コードと、任意の表示名を入力して「VERIFY CODE」を押下。ここでは表示名は"test SMS 1"としています。
    7. SMS認証の追加が完了し、結果が表示されます。
    8. FirebaseコンソールのAuthenticationで「ユーザー」タブを選択し、SMS認証を追加したユーザの3点リーダを押下してオプションメニューを表示。
    9. オプションメニューから「多要素認証を構成」を選択。
    10. ダイアログの「保存」押下。特に編集しなくても現象は発生します。

    11. アプリquickstart-jsに戻ります。手順10でユーザアカウントを編集しているので、ログアウトしているはずです。ログアウトしていなかったら「SIGN OUT」を押下してログアウトします。
    12. もう一度ログインします。今度は手順3~7で追加した第2認証が必要になっていますので、これも認証します。

    現象

    アプリquickstart-jsでログインしてみると、第2認証のSMS認証の表示名が「N/A」に変わっています。


    複数の電話番号を使えば1人のユーザに対して複数のSMS認証を追加できますが、すべてのSMS認証の表示名が「N/A」に変わってしまいます。

    第2認証にワンタイムパスワードを使用している場合、ワンタイムパスワードだけ影響をうけません。SMS認証のみで発生します。


    最後に

    Firebaseのライブラリでいうと、MultiFactorInfo.displayNameがnullになっているようです。表示名を設定する手段はMultiFactorUser.enroll()しか見つからなかってので、消えてしまった表示名を復活させるには、SMS認証をいったん消して再登録するしかないようです。


    一応Firebaseのサポートには報告し、「再現できたから開発チームに報告しておく」と回答をいただきました。そのうち修正されるでしょうが影響を受けるのは開発者のみなので、優先順位は低く対応が遅い可能性があります。Firebase Authenticationで多要素認証を実装・デバッグしていると混乱しかねない現象ですので、ご注意ください。

    ちなみにFirebaseのサポートとのやり取りには3週間以上かかっています。


    2025/06/03

    Container RegistryからArtifact Registryへの変更の影響

    動機

     少し古い話ですが、Container Registryは2025/3くらいから徐々に停止しています。プロダクトによって具体的な停止のタイミングはいくらか異なるようです。これに伴いContainer Registry→Artifact Registryへの移行が必須となるのですが、この移行により思わぬ影響があったので、ここに記しておきます。


    手順

    移行は「Container Registry から Artifact Registry に自動的に移行する」による自動移行ではなく、「標準リポジトリへの移行」に従って手作業で移行しています。具体的に変わるのは、Cloud Buildによるコンテナのレジストリへの保存や、レジストリから取り出してCloud Runにデプロイする部分のみだと認識していました。

    実際のコマンドだと以下のようになります。

    Container Registry

    gcloud builds submit --tag gcr.io/プロジェクト名/イメージ名

    gcloud run deploy apply --image gcr.io/プロジェクト名/イメージ名 --region=リージョン名

     

    Artifact Registry

    gcloud builds submit . --pack image=リージョン名-docker.pkg.dev/プロジェクト名/リポジトリ名/イメージ名

    gcloud run deploy apply --image リージョン名-docker.pkg.dev/プロジェクト名/リポジトリ名/イメージ名 --region=リージョン名


    その他のソースなどは変更不要の認識です。


    現象

    ところがCloud Runでデプロイしたイメージを実行してみると、動作が違います。ソースとログから解析して、環境変数がなくなっていると判断しました。
    Container Registryを使っていたころの該当環境変数は、以下のような感じでDockerfileで指定していました。

    ENV 環境変数名 値の文字列


    Artifact RegistryだとDockerfileの環境変数は反映されない様子です。


    対処

    DockerfileをあきらめてgcloudコマンドでCloud Runにデプロイする際に環境変数を指定することにしました。これはContainer Registryでも実績がある方法です。
    実際の指定は以下のような感じ。
    gcloud run deploy apply --image リージョン名-docker.pkg.dev/プロジェクト名/リポジトリ名/イメージ名 --set-env-vars="環境変数名=値の文字列" --region=リージョン名


    これで解決しました。 

    ちなみに、複数の環境変数を定義したい場合、"--set-env-vars"の値をコンマで区切って並べます。こんな感じ。

    --set-env-vars="環境変数名1=値の文字列1","環境変数名2=値の文字列2"

     

    2025/05/06

    LotteryServアップデート

     LotteryServを更新しました。今回の更新はセキュリティの強化のみです。そのために利用方法が若干変わった点があり、また新たな制限を追加しています。


    3Dセキュア対応

     LotteryServのご利用料金はクレジットカード払いです。クレジットカードの不正利用のリスクを下げるため、EMV 3Dセキュアに対応しました。これは経済産業省の「クレジットカード‧セキュリティガイドライン」に準じるものです。

     以下に説明します今回の更新のその他の変更は、これに伴うものとなっています。


    募集の開始・再開ができるユーザを制限

     募集の開始および、休止中の募集の再開ができるユーザを、主催者の支払い方法を登録しているユーザのみに制限しました。

     募集の開始・再開時にご利用料金の上限を決め、クレジットカードに対して支払いの予約を行うため、この制限が必要になりました。

     練習モードではこの制限はありません。


    多要素認証に対応

     ログインの際に多要素認証を利用できるようにしました。今回の更新では第2要素に利用できるのは、SMS認証のみです。

     主催者の支払い方法を登録するユーザは、多要素認証の追加を必須としています。


    2025/04/21

    SMS認証登録のログ「Failed to initialize reCAPTCHA Enterprise config. Triggering the reCAPTCHA v2 verification.」

    (2025/04/23)
    タイトルに「エラー」と表記していましたが、「ログ」に修正しました。

     現象

    Identity Platform/Firebase Authenticationを使用して多要素認証にSMS認証の登録を実装する場合、PhoneAuthProvider.verifyPhoneNumber()で表題のログがブラウザのコンソールに出て失敗することがあります。

    Failed to initialize reCAPTCHA Enterprise config. Triggering the reCAPTCHA v2 verification.

    実装はGoogleのスニペットどおりですが、web8とweb9で実行結果に違いが出たりします。

    対象結果
    web8 (namespaced)期待どおり成功
    web9 (modular)失敗


    調査

    Googleのドキュメントにはこのような現象についての記述は見当たりません。

    ネットで検索してみると、redditの記事「Firebase Phone Auth reCAPTCHA Error」が見つかりました。他の記事はこの記事の別言語版と、リンク切れのみでしたので、実質たった1つです。

    この記事ではReact Nativeで発生しているようですが、私が発生を確認したのはweb9 + Angularの組み合わせです。またこの記事は多要素認証ではなく電話認証のようです。しかし発生している現象はほぼ同じの様子です。この記事でも解決はしていません。


    解決

    手がかりが全くないので、思い当たるところを勘で変更して動作を確認するという地味な作業を繰り返し、解決方法にたどり着けました。

    失敗していた実装は以下のような感じです。MultiFactorUserインスタンスをあらかじめ取得しておき、それを使いまわしていました。

    
    class MfaComponent {
        multiFactorUser: MultiFactorUser;
        ...
        constructor(...) {
            ...
            this.multiFactorUser = multiFactor(ログインユーザのUser);
            ...
        }
    
        sendSms() {
            this.multiFactorUser.getSesstion()		←ここが原因
            .then((multifactorsession) => {
                const options = {
                    phoneNumber: 電話番号,
                    session: multifactorsesstion,
                };
                const provider = new PhoneAuthProvider(auth);
                provider.verifyPhoneNumber(options, recaptcha).then((verificationid) => {
                    ...
                });
    


    MultiFactorUserインスタンスを必要な時に取得するように変更することで、成功するようになりました。

    
    class MfaComponent {
        ...
        constructor(...) {
            ...
        }
    
        sendSms() {
            multiFactor(ログインユーザのUser).getSesstion()		←修正
            .then((multifactorsession) => {
                const options = {
                    phoneNumber: 電話番号,
                    session: multifactorsesstion,
                };
                const provider = new PhoneAuthProvider(auth);
                provider.verifyPhoneNumber(options, recaptcha).then((verificationid) => {
                    ...
                });
    


    最後に

    無事SMSは送信できるようになったものの、表題のログは出続けています。このログがPhoneAuthProvider.verifyPhoneNumber()が期待動作しなかったことと関係あるのかは不明です。動作には影響してなさそうですが、ちょっと不安です。


    2024/10/18

    LotteryServアップデート

     LotteryServを更新しました。


    抽選の仕組みを更新

     抽選の仕組みを変更しました。

     抽選はユーザの方々からは見えないところで動作しているので、それを変更しても変化はまったく感じていただけません。UIの見た目や使い方にも影響や変化はありません。


    価格の変更

     上記の抽選の仕組みの変更により、運用コストを下げることが可能になりましたので、それを価格に反映しました。Google Cloudの利用料金は米ドルで計算されるので、現在も続いている円安により運用コストが高めになっているのは頭が痛いことですが。


    ユーザ認証の変更

     ログインや再認証のなどユーザ認証の実装を若干変更しました。Googleアカウントでの認証では、ポップアップウィンドウが出るように変更しています。

     まれにポップアップウィンドウが自動的に閉じられず、認証後も残ったままになることがあるようです。残っていても無害ですが、認証が成功していたらクローズボタンで閉じてください。


    2024/10/01

    Batch実行時のエラー「java.lang.NullPointerException: Cannot invoke "String.lastIndexOf(int)" because "endpoint" is null」の対処

    事象

    GAE/JでBatchジョブを起動しようとBatchServiceClient.create()をコールすると、以下のエラーが発生しました。

    java.lang.NullPointerException: Cannot invoke "String.lastIndexOf(int)" because "endpoint" is null

    ソースコードはGoogleのスニペットどおりで、ヌルポなど発生するわけがないはずです。しかし何度実行しても、ビルドしなおしても状況に変化はありません。


    調査

    BatchServiceClient.create()ではどのようにしてBatchServiceClientが生成されているのかわかりませんが、BatchServiceClient.create(BatchServiceSettings settings)メソッドを使用して自分でBatchServiceSettingsを生成して渡せば、生成されるBatchServiceClientの内容をある程度推測できそうです。
    とりあえず以下のようなスニペットでBatchServiceSettings.newBuilder()でデフォルト設定のBatchServiceSettingsを生成し、別のBatchジョブの起動に成功しているプロジェクトとBatchServiceSettingsの内容を比較してみました。

    	BatchServiceSettings settings = BatchServiceSettings.newBuilder().create();

    生成されたBatchServiceSettingsの内容で、有意な差異は以下のとおりでした。

    成功しているプロジェクト :
    	endpoint=batch.googleapis.com:443,
    失敗するプロジェクト :
    	 endpoint=null,

    エラーメッセージどおりですが、endpointがnullです。


    endpointは文字列ですし、BatchServiceSettings.Builder.setEntpoint(String endpoint)で設定できます。そこで強制的にendpointに成功しているプロジェクトと同じ値をセットしてBatchServiceSettingsを生成し、それを渡してBatchServiceClientを生成してみると、発生するエラーが以下に変わりました。

    com.google.api.gax.rpc.PermissionDeniedException: io.grpc.StatusRuntimeException: PERMISSION_DENIED: Batch API has not been used in project プロジェクト名 before or it is disabled.

    Batchが有効になっていない...


    解決方法

    その1

    BatchのAPIを有効にします。GCPコンソールからなら以下の手順になります。

    1. GCPコンソールの「APIとサービス」-「ライブラリ」を表示。
    2. 「APIとサービス」にBatchと入力してBatchを探す。
    3. 検索結果のリストから「Batch API」をクリック。
    4. Batch APIのページの「有効にする」をクリック。



    Batchは手動で有効化する必要があったのを忘れていただけでした。そして最初に目にするエラーメッセージはそれを連想しにくいものなので、気づけないというワナもあったということでした。


    その2

    Batchを有効化し、BatchServiceClient.create()のコールをGoogleのスニペットどおりに戻してみたのですが、相変わらずこの記事の最初と同じヌルポが発生したままです。
    とりあえず上記調査と同様にendpointを強制的に設定することで、Batchジョブの実行はできるようになりました。

    しかしなぜプロジェクトによって挙動が違うのかは不明のままです。

    2024/08/26

    Firestore/Datastoreで複数の範囲フィルタを使ってクエリが可能に

    Firestoreが登場する前の昔のDatastoreから、Firestore/Datastoreのクエリには「不等式はクエリ内で1つだけ」という制限があったのですが、2024/7/29にやっと解除されました。

    上記リンクはFirestoreですが、Datastoreも同様のページがあります。Datastoreの日本語ページにはプレビューマークがついていますが、リリースノートにはGAと説明されています。

    この制限のためにこれまで「DBに範囲を記録しておいて、指定の値がその範囲内にあるデータを検索」ができませんでした。具体的には以下のようなケースです。
    • 開始・終了日時を保存しておき、指定の日時に対応するデータを検索。
    • 上限・下限の金額を保存しておき、指定の金額に対応するデータを検索。
    • etc.

    ただし無制限になったわけではなく、少ないながらも制限事項もあるようです。検索時間などパフォーマンス面も未検証なので、遅くないのかなど気になります。

    これまではこの制限を回避するためだけにSearch APIを利用したりElasticsearchをインストールしたりといった対応が必要だったのですが、だいぶFirestore/Datastoreのみで検索ができるようになりそうです。

    2024/07/17

    vsReversiアップデート

     vsReversiをアップデートしました。


    仕様変更

    • 以下のアカウントによるログイン/新規登録を廃止。
      • FaceBook
      • twitter

    不具合修正

    • ブラウザでクロスオリジン・リダイレクト・ログインがサポート停止された影響でログインできないケースがあったので、ログインをポップアップウィンドウに変更。

    FaceBookアカウントによるログインは維持するのが難しくなったので、廃止しました。
    FaceBookは定期的にアカウントなどを利用する機能に対する審査を行っており、機能の提供を受けるためにはその審査を通過する必要があります。審査の内容や、通過しなかった場合の対応の仕方は毎年変わります。昨年まではサポートやり取りしながらなんとかなりましたが、とうとう維持する手間が見合わないところまで来ました。
    最近はあまり使われていないようですし、メールアドレスでも利用可能なのでサポート外とすることにしました。
    twitterは今のところそのようなことはないのですが、Xに変わってから収益化のために一部サービスの有料化を進める可能性があるようです。今後有料になる可能性もあると考えられますが、vsReversiの本来の目的はデモンストレーションなので、手間暇や運用費用をかけられません。そのため同時にサポートを廃止することにしました。幸いtwitterアカウントによるユーザは登録されていません。