- PR -

WebアプリにおけるDLLの更新方法について

1
投稿者投稿内容
あさべー
会議室デビュー日: 2005/06/03
投稿数: 11
投稿日時: 2005-07-11 14:02
いつも参考にさせていただいております。

早速質問なのですが
.NET(C#)でWebサービスの開発をしております。
要件として以下の3つがあります。

1.WEBサービス内で大量(数百〜)のDLLを使用する。

2.使用するDLLはあらかじめ参照設定しておくのではなく
Assembly assembly = Assembly.LoadFrom(strDLLPath);
Type[] type = assembly.GetTypes();
MyClass obj = (MyClass)assembly.CreateInstance(type[0].ToString());
string strReturn = obj.execute();
のように、実行時にSystem.Reflection.Assemblyクラスを使用してロードして実行する。

3.WEBサービスで使用するDLLはサービスを止めることなく更新する必要がある。


始め、WEBサービスのbinフォルダにDLLを配置していました。
これによりDLLを上書きした場合に、アプリケーションドメインの再起動が発生し
常に最新のDLLをコールすることができていました。

ところがDLLの数が増えるに従い、
アプリケーションドメインの再起動時間(DLL更新後初回実行時にかかる時間)が極めて膨大になってしまったため、
DLL配置先をWEBサービスのbinフォルダから別のフォルダ「例:c:¥test¥bin」に変更し
Assembly assembly = Assembly.LoadFrom(@"c:¥test¥bin¥sample.dll");
のように別フォルダからロードするように変更したのですが
今度はメモリにロードされているDLLの上書きが出来なくなってしまいました
(当然といえば当然ですが)。

実現したい動作としましては
・DLLの上書きを常に行うことができる
・上書きされたものがWEBサービスの動作に反映される
・WEBサービスアプリの初回実行時間が遅くならない(アプリケーションドメインの再起動が発生しないのが一番です)。

というものなのですが、解決策があれば教えて頂けませんでしょうか。
宜しくお願いします。
ryuuji
ベテラン
会議室デビュー日: 2003/07/10
投稿数: 53
お住まい・勤務地: 東京都
投稿日時: 2005-07-12 15:55
引用:

アプリケーションドメインの再起動時間(DLL更新後初回実行時にかかる時間)が極めて膨大になってしまったため、
DLL配置先をWEBサービスのbinフォルダから別のフォルダ「例:c:¥test¥bin」に変更し



配置先を変更することで再起動時間を解決できると考えたのは何故なのでしょうか?
あさべー
会議室デビュー日: 2005/06/03
投稿数: 11
投稿日時: 2005-07-12 16:04
ryuujiさん、返信有難うございます。

引用:
配置先を変更することで再起動時間を解決できると考えたのは何故なのでしょうか?



初回起動時の起動時間が極めて遅かったので、原因究明をした結果、
Webサービスのbinフォルダ内にあるファイル(DLL)の数(サイズにも)の増加に
伴うことが判明しました。

そこで、DLLの配置先を変更した次第です。
これにより、確かに初回起動時間は極端に短くなりました(数分→数秒)が、
上記のような問題が発生してしまったのです。


ryuuji
ベテラン
会議室デビュー日: 2003/07/10
投稿数: 53
お住まい・勤務地: 東京都
投稿日時: 2005-07-12 16:41
引用:

初回起動時の起動時間が極めて遅かったので、原因究明をした結果、
Webサービスのbinフォルダ内にあるファイル(DLL)の数(サイズにも)の増加に
伴うことが判明しました。



不思議ですね。アセンブリのサイズは初回呼出し時のコンパイル時間に影響するにしてもファイル数は何に影響しているのでしょう。AppDomainが起動する際にASP.NETが監視対象であるPrivatePath内のアセンブリを読み込んでいるのかも知れません。

となると↓はあまり意味がない気がしますが、
http://weblogs.asp.net/bhouse/archive/2005/05/01/405230.aspx
PrivatePathの設定方法の話題です。詳細はMSDNにも記載されています。

適宜アセンブリをロード/アンロードできれば良いのかも知れませんが、メモリはGCまかせなので難しい気がしてきました。。。運用時にアセンブリを入れ替える際、AppDomainを再起動できるツール/手段を用意するとかぐらいしか思い付きません。すいません。
どっとねっとふぁん
ぬし
会議室デビュー日: 2005/02/23
投稿数: 935
投稿日時: 2005-07-12 18:50
引用:

ryuujiさんの書き込み (2005-07-12 16:41) より:
引用:

初回起動時の起動時間が極めて遅かったので、原因究明をした結果、
Webサービスのbinフォルダ内にあるファイル(DLL)の数(サイズにも)の増加に
伴うことが判明しました。



不思議ですね。アセンブリのサイズは初回呼出し時のコンパイル時間に影響するにしてもファイル数は何に影響しているのでしょう。AppDomainが起動する際にASP.NETが監視対象であるPrivatePath内のアセンブリを読み込んでいるのかも知れません。


ASP.NETではbinフォルダに存在するアセンブリはすべてシャドーコピーした後でコンパイルされ利用されるはず。ということでそのあたりで問題がでているのかもしれませんね。
ただ、そのシャドーコピーのおかげでサービスを止めずにアセンブリの更新ができるので。。。
ちょっとうまい方法は考え付きませんねぇ。
Jitta
ぬし
会議室デビュー日: 2002/07/05
投稿数: 6267
お住まい・勤務地: 兵庫県・海手
投稿日時: 2005-07-12 20:47
 私がそんなに大規模な開発をしたことがないから、なのでしょうが、数百になる時点でアプリケーションを分けます。。。だって、保守し切れないじゃないですか。


 あと、保守の運用として、いつでも更新、なんて運用はしません。だって、怖いじゃないですか。入れ替え作業中に誰かがデータベースを触っていたら、なんて考えると。そんな運用のテスト、どうやったら「大丈夫」と言えるか、思いつきません。


 ということで、私も人間系で何とかする、ことしか思いつきません。すみません。
あさべー
会議室デビュー日: 2005/06/03
投稿数: 11
投稿日時: 2005-07-15 19:36
ryuujiさん、どっとねっとふぁんさん、Jittaさん、返信ありがとうございます。
お返事が遅くなって申し訳ございません。

まず、
引用:
不思議ですね。アセンブリのサイズは初回呼出し時のコンパイル時間に影響するにしてもファイル数は何に影響しているのでしょう。AppDomainが起動する際にASP.NETが監視対象であるPrivatePath内のアセンブリを読み込んでいるのかも知れません。


に関してですが
おっしゃるとおりAppDomainの起動時にアセンブリを読み込んでいると思われる挙動をしています。

例えばトータルで1MBのDLLを
1.10KB×100個
2.1MB×1個
にした場合、
原則はサイズとファイル数のどちらにも比例(トータルサイズに比例)することから
(どちらかと言えば2の方が起動が早いですが)、
AppDomainの起動時にアセンブリを読み込んでいると判断しました。
実際のDLL利用時にロードしてくれればいいんですけどね。。

次にWEBサービスのbinフォルダ以外にPrivatePathの設定を行い、動作を確認してみましたが、このフォルダも結局はシャドウコピーをするわけではないらしく、
起動は早いものの、メモリにロードされているDLLの上書きは出来ませんでした。


引用:
私がそんなに大規模な開発をしたことがないから、なのでしょうが、数百になる時点でアプリケーションを分けます。。。だって、保守し切れないじゃないですか。


どうしても解決方法が見つからなかったら最終的にはJittaさんのおっしゃるとおり
アプリケーションを分けようとは思っています。
ただ、保守しきれないことはないと思いますし、
アプリケーションを分けたところで保守のしやすさがそこまで変わるとは思わないので、
できれば1アプリケーションで実現したいところです。

引用:
あと、保守の運用として、いつでも更新、なんて運用はしません。だって、怖いじゃないですか。入れ替え作業中に誰かがデータベースを触っていたら、なんて考えると。そんな運用のテスト、どうやったら「大丈夫」と言えるか、思いつきません。


いつでも更新するというわけではないですが
DLL入れ替え作業中に誰かがデータベースを触っている可能性は当然ありますよね。
この場合、DLL内のメソッドが実行されている最中などにも
メモリ上のDLLは更新される可能性があるのでしょうか。
(例えば、上書きしたときに実行中のプロセスが終了するまでまって、次のタイミングでメモリを更新といったことはやってくれないのでしょうか)
Jitta
ぬし
会議室デビュー日: 2002/07/05
投稿数: 6267
お住まい・勤務地: 兵庫県・海手
投稿日時: 2005-07-16 05:20
引用:

ただ、保守しきれないことはないと思いますし、
アプリケーションを分けたところで保守のしやすさがそこまで変わるとは思わないので、
できれば1アプリケーションで実現したいところです。


 あれ?これ、どういう意味で書いたんだろう?
 確かに、そうですよね。Web アプリケーションだと、分けたところでセッションが切れるから、余計に難しいのに。すみません、忘れてくださいm(..)m


引用:

この場合、DLL内のメソッドが実行されている最中などにも
メモリ上のDLLは更新される可能性があるのでしょうか。


 bin ディレクトリが書き換えられると、ワーカープロセスがリセットする…と書いてあったと思います。
引用:

MSDN 『セッション状態』より:
インプロセス セッション状態モードを使用している場合、aspnet_wp.exe またはアプリケーション ドメインを再起動するとセッション状態データは失われます。この再起動は、一般的に次のような場合に発生します。

  • アプリケーションの Web.config ファイルの <processModel> 要素で、条件が満たされたときに新しいプロセスを起動する memoryLimit などの属性を設定している場合。
  • Global.asax ファイルまたは Web.config ファイルを変更した場合。
  • Web アプリケーションの ¥Bin ディレクトリに変更を加えた場合。
  • ウィルス対策ソフトウェアが Global.asax ファイル、Web.config ファイル、または Web アプリケーションの ¥Bin ディレクトリ内のファイルをスキャンして変更した場合。



これから判断すると、書き換わった時点でワーカープロセスが再起動することで DLL もメモリから捨てられる、と思います。
 これの動作は変更できるかどうか、知りません。変更できるとすると、デバッグがしづらいですよね(^-^; 変更して、三角ボタンをクリックして実行!!でも、実行されるのは変更される前のアセンブリ...とか。
 このほか、「終了」というのは、ちょっと難しいですね。ワーカープロセスは、いつまでアプリケーションドメインを保持していればよい、ユーザからのリクエストが来ない、というのを判断できませんから。デフォルトでは、20分くらい要求がなければ、終了すると思います。

_________________
1

スキルアップ/キャリアアップ(JOB@IT)