トップ «前の日記(2004-10-23) 最新 次の日記(2004-10-25)» 編集

日々の破片

著作一覧

2004-10-24

_ プロクシとの通信料金

一度必ずキャッシュを送ってくれるんだが、この通信分も課金対象なのかな?

結局再読み込みする事になるんだが。

_ ステートレスコンポーネント

注)なんとなく書き始めてみたが精査できてないから結構怪しいとこがあるけど、仕上げる気力がないからこのままだったり。

あるコンポーネント(分離度が高く、他のプログラムから呼び出されることを前提としたプログラム)がステートレスであるとはどういう文脈で使われるかによってもちろん異なるのだが、暗黙の了解としては主となる公開メソッドの後続の呼び出しが以前の呼び出しに依存しないということだ。

当然、主とならない、たとえば依存性解消のためのセッタ呼び出しであるとかライフサイクルを通じて一度実行されるinitializeとかコンストラクタとかに、主となるメソッドの呼び出しは依存してもそれは構わない(それは不変条件あるいはクライアント側が実行する準備処理という意味においては事前条件である。っていうか、こういう場合の不変条件と事前条件の区別って良くわからないんだけど)。また、主となるメソッドの内部で状態遷移があるのも当然(JDBCでいけばConnectionからPreparedStatementを取得した状態、executeQueryを投げた状態、ResultSetをcloseした状態、の種々の状態がある)だ。

もともと(といっても僕に取っては1997年頃からの知識になるわけでそれ以前から別の文脈で使われているかも知れないのだが)、あるコンポーネントがステートレスかステートフルか、というのはスケーラビリティに関する議論であった。ステートフルであれば、あるコンポーネントのインスタンスは1つのクライアントに密結合されることになる(なぜなら、状態を保持したまま複数の呼び出しで処理が完結するから)。1000クライアントが存在すれば1000のインスタンスが必要となる。いっぽうステートレスであれば、コンポーネントのインスタンスプール(フライウェイトですね)が使えるし(最大で必要となるのは同時に実行されるスレッド数)、ましてスレッドに従属しなければ(通常のServletを想像すればよい)1インスタンスで同時に複数のクライアントにサービスを提供することができる。

ちなみに2年位前には、最後のServlet型が最高だと考えていたが、実際にいろいろ動かしてみたらコンポーネントのインスタンスの生成/廃棄のオーバーヘッドはもっと細かな(文字列みたいな)オブジェクトの生成/廃棄の影に隠れて誤差みたいなもんだとわかってきた。したがってインスタンス変数は使っても良いな、と考えが変わって来た(スレッドあたり1インスタンス)。でも、初期化処理のオーバーヘッドまで考えた場合、およびインスタンス管理の複雑度を考えると、ステートフルなのはちょいと考えものである(というか、インスタンス管理を考えるくらいならEJBコンテナを使えばよろしいと思う)。また、ステートフルな実装はある意味、設計が複雑になりやすい(ここは興味深い。「ある意味」以外の場合があるからだ)。

で、ステートフルにするメリットとステートレスにするメリットの差は一体なんでしょう? と考えると、それはメソッド呼び出しのコンテキストの量に依存するということだ。

たとえば、ある状態を持った処理――誤解を招く可能性はあるが、マスターレコード読んで表示用データを返送、変更内容を受け取って更新の2つの状態を持つWebページを考えてみる――では、機能的にはステートは最初に読み込んだマスターレコードのキー(楽観ロックが必要であればさらに更新バージョンを示す情報も必要)である。非機能的にはログイン情報、クライアントのアドレス、セッション状態などなどがあるのだが、それをWebサーバーが提供すると前提できるのであれば、そのWebページにとってはレコードのキーだけが(楽観ロックの場合は……省略)呼び出すメソッド間で保持すべきステートとなる。

この情報をWebページが呼び出すコンポーネントが保持すれば2度目の呼び出しすなわち更新メソッドの呼び出し時にクライアントはキーをWebページへ送信する必要はない。しかし、そのために1つのインスタンスをクライアントに従属させるメリットってある? というのがステートレスなコンポーネントの考え方である。しかし保持すべきコンテキスト情報が500Kバイトあれば、クライアントとサーバーで転送を繰り返すよりはサーバー側で保持したほうが良さそうに感じてくるはずだ。しかし、それが1000クライアントとなるとサーバー側は500Mバイトのステートフルコンポーネントのインスタンス群を同時に抱えることになる(大したことないな、こう書いてしまうと。でも処理は1種類のはずはないから合計すると非現実的なサイズになるわけだ。そこに、EJBがステートフルとステートレスの2種類のセッションビーンを規定し、かつステートフルの場合状態を保持したまま非アクティブ化したりする処理をEJBコンテナが提供するメリットが生じる)。

ちなみにスマートクライアントではセッションコンテキストをクライアント側が保持することが原則となる。

では、呼び出しの間に保持すべきステートが少ないかあるいはほとんど存在しない場合にはコンポーネントはどうあるべきか? そのように設計できるのであればステートフルにする必要性はあるのだろうか? ――無い。

J2EEプログラミング講座(るいも, 宇野)

って言うか、ステートレス/ステートフルの考え方についてEJB仕様は、実務に耐え得るか/実装に必要かはおいておいても非常にうまくまとまっているんだから読んでおいて損はない。って言うか、J2EEプログラミング講座もよろしく。

ASP(VB5)時代の文献――「ステートレスな (状態を持たない) コンポーネントを設計します」(しかし、最終更新日2003年とかってその通りなんだろうがミスリードしやすい表示だな)。

ちなみにひがさんのくーすでのステートレスの意味は上の分類ではServletタイプのようだ。想定している処理の粒度が違うのかも。

以下は個人的な感触。

もしステートを持たずpublicメソッドのみを提供するのであれば、そのクラスの実装は本当に構造化プログラミングだけで済むかどうかといえば処理の粒度に依存するということとなる。個人的には比較的粗粒度とし1つのコンポーネントが3〜4くらいのクラスによって実装されるくらいがバランスが良さそうに感じるのだが、処理内容に依存するから実際にはケースバイケースではないかと思う。また、徹底的に詳細まで仕様を落としていけば単一のプログラムになるからそれはそれでありかなとも思わないでもない。


2003|06|07|08|09|10|11|12|
2004|01|02|03|04|05|06|07|08|09|10|11|12|
2005|01|02|03|04|05|06|07|08|09|10|11|12|
2006|01|02|03|04|05|06|07|08|09|10|11|12|
2007|01|02|03|04|05|06|07|08|09|10|11|12|
2008|01|02|03|04|05|06|07|08|09|10|11|12|
2009|01|02|03|04|05|06|07|08|09|10|11|12|
2010|01|02|03|04|05|06|07|08|09|10|11|12|
2011|01|02|03|04|05|06|07|08|09|10|11|12|
2012|01|02|03|04|05|06|07|08|09|10|11|12|
2013|01|02|03|04|05|06|07|08|09|10|11|12|
2014|01|02|03|04|05|06|07|08|09|10|11|12|
2015|01|02|03|04|05|06|07|08|09|10|11|12|
2016|01|02|03|04|05|06|07|08|09|10|11|12|
2017|01|02|03|04|05|06|07|08|09|10|11|12|
2018|01|02|03|04|05|06|07|08|09|10|11|12|
2019|01|02|03|04|05|06|07|08|09|10|11|12|
2020|01|02|03|04|05|06|07|08|09|10|11|12|
2021|01|02|03|04|05|06|07|08|09|10|11|12|
2022|01|02|03|04|05|06|07|08|09|10|11|12|
2023|01|02|03|04|05|06|07|08|09|10|11|12|
2024|01|02|03|

ジェズイットを見習え