ウェブアプリケーション全盛の時代だが、その外見は大きく二つに分けることができる。従来型の複数のページを遷移していくマルチページアプリケーション(MPA)と、ひとつのページの中の情報が置き換わるシングルページアプリケーション(SPA)*1だ。
組み合わせることもできる*2ので分類ではなくて比重の問題だが、ショッピングサイトやコンテンツ管理システム(CMS)、画面遷移がある方がユーザーが混乱しない場合はMPAであることが多く、𝕏/Twitterのようなマイクロブログ型SNSやチャットはSPAになっていることが多い。
1. サーバーとJavaScriptの間の通信手順はWeb API
技術的には、ブラウザーにJavaScriptで書かれたアプリケーションを送り込み、現在では総称でWeb APIと呼ばれるプロトコルで通信を行う。Web APIはもともとは、ウェブアプリケーションのための技術と言うよりは、ウェブアプリケーションが外部サービスと連携するために作られた節があるのだが、SPAでも有用。Web APIは、スマートホンやタブレット端末のアプリへの横展開に使うことができる。
2. サーバー負荷の軽く、ユーザー体験がよい技術
SPAは、最初にフレームワークを含めた大量のJavaScriptコードをダウンロード*3した後は、ブラウザーで動くJavaScriptがサーバーからデータだけをダウンロードしてきて、画面の一部だけを書き換えていく。サーバー側でhtmlを使ったページを生成する頻度が原則としてなくなり、その分は、通信量が減る。サーバーの負荷が軽くなり、レスポンスが良くなるので、ユーザー体験が改善する*4。
3. デジタル庁クラウドチームのWeb API観
さて、本題。山本教仁COOの「Web APIアーキテクチャ」の説明では、上述の特徴以上に、スケーラビリティをSPAの利点として見出している。
URLで表現される対象への処理に単純化され、処理が軽量化されるためコンテナ化もしやすく、水平に多数コンテナを並べることで、ベースとなるインフラコストを抑えつつ、大量アクセスが来たときもスケールアウトしてコンテナ数を素早く増やすことでスケーラビリティを確保しやすくもなります。
代表的なWeb APIのRESTを念頭に置いているわけだが、操作対象(e.g.テーブル)ごとにURLを与え、検索/挿入/修正/削除を行うような設計がとられる。またWeb APIの後に、次のWeb APIにアクセスするような縛りはつけず、独立性を高くするのが原則だ。Web APIひとつひとつが独立したアプリケーションのように振舞う。
コンテナーはアプリケーションの隔離技術で、独立したアプリケーションであれば、それぞれ別のコンテナーに入れることができる。クラウドサービス事業者は、コンテナーを実行するマネージドサービスを提供しており、トラフィックに応じてコンテナーをコピーして増やすことで、処理能力をスケールさせてくれる。
4. ステートレス縛りによるスケーラビリティ向上
デジタル庁クラウドチームの話で興味深いところは、ステートレスを強調しているところだ。
ステートレスは、連続したアクセスにおいてサーバーがクライアントの情報を保持しない方法を指す。あるユーザーが使っているブラウザーやスマートフォンがログインに成功したと言う情報を、サーバー側は保持しない(クライアント側は保持してよい)。Web APIの代表RESTfulの場合、厳密にはステートレスを要求している。
反対のやり方になるステートフルは、サーバーにセッションと呼ばれるクライアントの情報を保持する仕組みを使うことを指す。これまでの一般的なウェブアプリケーションは当然のように用いており、ステートフルな反則Web APIもある*5。MPAとSPAを組み合わせた場合、どちらにしろセッション情報はあるので使ってしまう。
MPAからするとセッションは、確認画面を使ったり、画面を戻して再編集するのに大変便利なのだが、サーバーの台数を増やしてスケーリングさせるには、大抵はセッション情報を管理するkey-valueデータベースを用意する必要があるし、それがスケーリングのボトルネックになる事もある。
5. ユーザー認証とログイン情報
ステートレス縛りがあるので、MPAにどっぷり漬かってきたプログラマーは、ユーザー認証方法を再考することになる。
ステートフルなユーザー認証は次のようになる。ブラウザーがログインに成功したら、サーバーはログイン情報をサーバーにある領域に保存し、ブラウザーにはセッションIDと呼ばれる整理番号を渡す。その後のリクエストにおいて、ブラウザーはセッションIDをリクエストに含めるので、いちいちユーザー認証する必要がない*6。
ステートレス縛りになるので、この従来方法を捨てないといけない。リクエストごとにユーザー認証をするのが単純な方法だが、RDBの負荷が高くなるので、ステートレス縛りの意味がなくなる。セッション管理に用いるmemcachedの方がRDBより高速だ。クラウド利用料削減にならないし、スケーラビリティも上がらない。
この問題はトークンを使って解決される*7。概念的には*8次のような仕組みになる。ログイン時に、ログイン情報(i.e. ID,ロール, 有効期限,IPアドレス*9)を秘密鍵で暗号化するか署名し、それをトークンとしてクライアントに渡す。クライアントはリクエスト時にトークン(とログイン情報)を送信し、アプリケーションサーバーはトークンが偽造ではないことを確認する。
認証サーバーをあわせて使うこともできる。クライアントは認証サーバーからトークン(と言うかassertion)をもらって来て、アプリケーションサーバーは認証サーバーの公開鍵でそれを検証する*10。マネージド認証サーバーになるIDaaSのクラウドサービスを使うこともでき*11、IDaaSは一般的なアプリより慎重に運用されているのでより安全になる。Active Directoryによるユーザー管理とIDaaSを連携させて、SSOを徹底した自治体向けソリューションもある*12。
なお、山本教仁COOの話に認証回りの話が無かった。IDaaSについて言及も無い。MPAを書いてきたプログラマがSPAを書こうと思ったら、まず悩むところなのだが。
6. NoSQLによるボトルネックの解消
ステートレスなWeb APIをクラウドに設置し、究極のスケーリングを目指せそうな気がしてきたと思う。
だが、ちょっと待って欲しい。官庁や地方自治体のアプリケーションは、RDBに頻繁にアクセスする。RDBの速度がボトルネックになって、スケーリングの効果に限度が出る。memcachedの方がRDBより高速だ。だから、セッション管理をしてもスケーリングの限度が低くなるかは自明ではないと言うか、おそらく大差ない。
トークンを使ったステートレス認証はモバイルアプリの会社では常識らしいのだが、オンラインゲームが主体。RDBではなくNoSQLを主につかってパフォーマンスを出していたりする。
もちろん、こんなことは山本教仁COOも分かっていて、
単純なAPIに対する情報の読み書きに対するためであれば、データベースもスケーラビリティに強いNoSQLなども使えます。
と言及している。NoSQLも使えると言うか、RDBではなくNoSQLを使えと言う話と理解した。住民基本台帳などはRDBに入っているし、RDBとNoSQLの連携が要りそうだが。
7. 官庁や地方自治体の関心はスケーラビリティなのか?
デジタル庁クラウドチームの主張は「適所があれば、クラウド向きだし使え」と理解できるので、大筋で異論はない。むしろ賛成だ。新型コロナウイルス感染症のワクチン接種の予約システムがこの方法で作られていたら、素晴らしく機能したと思う。
ただし、アクセス数のサージを捌くためのスケーラビリティに意識が集中しているギーク感は否めない。役所の人々、スケーラビリティに悩んでいるのであろうか。SPA/Web APIを推すのであれば、ユーザーエクスペリエンスの良さや、スマートフォンやタブレット端末への横展開と言う観点、民間サービスとの協業などの方をもっと強調しても良かった。立場上、なるべくクラウドと関係ある話をしないといけないのだと思うが。
*1Vue.jsやReactを使えばSPAになるわけではない。十中八九はSPAになっていると思うが。
*2アプリケーション全体で見ると画面遷移はあるが、編集画面だけシングルアプリケーションで、更新ボタンの処理では画面遷移しないなど。
*3クラウド利用の場合、料金に響きそうではあるが、静的ページなのでコンテンツ配信ネットワーク(CDN)を使うことができる。
*4前世紀はブラウザーで動くJavaScriptのコードはユーザー体験の悪化要因と思われていた。クリスマスだからって、無駄に降雪アニメをつけるな。互換性とデータ保存方法の欠如から大したことには使えなかったが、1997年のAjax(と言うかXMLHttpRequest)の登場から、フロントエンドのJavaScriptで真面目にアプリケーションを書こうと言う潮流ができ、2003年にrich web applicationsと名前のついたコンセプトになり、そこからGoogle DocsやGMailなどの重量級アプリケーションが登場し、さらにブラウザーのJavaScript実行速度の大幅な向上と、JavaScript(と言うかECMAScript)の言語仕様の発展を経て、2010年ぐらいからSPA向けのフレームワークが幾つも公開され、気づくとユーザー体験を改善する技術として広く受容されるようになった。なお、現在でもJavaScriptによるページの動的生成を徹底すると描画が重くなるので、フロントエンドエンジニアはバランスに気を使っている。
*5SPA+REST APIにおけるセッションを使った認証の実践例 | Fintan
*6セッション攻撃が気になるかも知れないが、対策はされている。不正にセッションIDを騙るセッションハイジャックは、IPアドレスと紐付けることで防止される。ブラウザーに表示したフォームを記録したりと防止策が取られている。ユーザーにトロイの木馬を送りつけて、不正操作を行うセッションフィクセーションは、二重投稿防止機能でほぼ防止できる。
*7標準化された型式JWTがある。
*8秘密鍵を定期的に更新する仕組みもいるし、有効期限を延長したトークンを発行し続けないといけない。トークンの保存先も問題になる。ブラウザーを閉じたらログアウト運用にするか、Local Storageに保存するかの二択になるようだが。
*9モバイルだとIPアドレスが移動で変化するときがあるので、入れるべきかは要件による。
*10SAMLの主流の使われ方の場合。OpenID Connet(OIDC)を使うと、クライアントが持ってきた認可コードを使って、アプリケーションがバックチャネルで認証サーバーに問い合わせることになる。
*11無料でサービスされているOAuthやOpenIDではロールの情報がないので、RDBの負荷が重くなってスケールしなくなりそうではあるが、IDaaSはロールの管理もしてくれるそうだ。
*12名前が定まらないActive Directory Federation Services → Azure Active Directory → Microsoft Entra IDがある(クラウド・サービスと社内ADとのSSOを実現する(前)(1/4) - @IT)。
0 コメント:
コメントを投稿