0

私は特定のプロジェクト用の単純なアーキテクチャを持っています。これは次のようになります。

  1. ユーザーが ASP.NET MVC を使用してファイルを要求する
  2. 上記のファイルのローカル キャッシュがチェックされ、キャッシュに存在しない場合、ファイルは Azure Blob ストレージからプルされます。
  3. この時点で、ファイルは間違いなくサーバー上にあり、パスがわかります。
  4. サードパーティのライブラリを使用してファイルを開き、パスを指定すると、ユーザーのビューを作成するために使用するクラス構造が返されます。

これは、99% の確率で機能します。ファイルはキャッシュで見つかるかダウンロードされ、サードパーティのコードを使用して開かれた後、Nice ビューでユーザーに表示されます。

ただし、複製できる奇妙な状況があり、実稼働サーバーが完全にクラッシュします。

それらは次のとおりです。

  • ファイルがキャッシュにありません
  • ファイルは Azure からダウンロードされます
  • ファイルを開くときにサードパーティの (安全でない) ライブラリがクラッシュする
  • サーバーを持っていきます。

安全でないライブラリを使用してトラブルを起こしていることは理解していますが、最も奇妙なのは、Azure が最初に正しく使用され、Azure がヒットしなかったため、2 回目の試行でファイルがキャッシュされていることです。ファイルは正常に開きます。

サード パーティのライブラリは、基本的に Azure からダウンロードしたファイルが破損していると見なしますが、まったく同じコードが Azure の関与なしにまったく同じファイルを開こうとしても、問題なく開きます。

そのため、最初は Azure のせいにしました。ファイルを正しく閉じていなかったのかもしれません。私はチェックしましたが、ファイルを取得するために使用するファイルストリームは間違いなく閉じられています(usingステートメントでラップされています)。

コードは以下のとおりです (forceRefresh は、常にローカル キャッシュをスキップするように設定できるフラグです)。パスはサーバー上の場所に設定されています ~/tmp

if (!File.Exists(path) || forceRefresh)
{
   CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();
   CloudBlobContainer blobContainer = blobClient.GetContainerReference("mycontainer");

   ICloudBlob blob = blobContainer.GetBlockBlobReference("myblob");
   using (var filestream = new FileStream(path,FileMode.Create,FileAccess.ReadWrite,FileShare.Read))
   {
        blob.DownloadToStream(filestream);
   }

}

さらに奇妙なことに、テストを繰り返しました。今回は、クラッシュの後、キャッシュからファイルを削除して、Azure が再びヒットするようにしました。そうであり、クラッシュを引き起こすことなくファイルが開きます。

そのため、Azure からダウンロードしたファイルを初めて開いたときにのみ発生するようです。アプリケーション プールをリサイクルするだけで、必要に応じてエラーを発生させることができます。

これをデバッグする方法について何か提案はありますか? ローカルの開発マシンでレプリケートできません。

編集: Richard Turner からのフィードバックへの回答

ブロブ取得コードが例外の原因であるとは思いません。これは、Web アプリがクラッシュした場合、ファイルがダウンロードされた後であるためです。その後の再試行でファイルを開くことができるため、ファイルが破損していないことを確認することもできます。

「安全でない」に関してあなたが言ったことはまさに正しいです-私はPInvokeを実行するラッパーコードを持っています-しかし、IDisposableを実装していません。これはすぐに調べます。パフォーマンスに関しては、現時点では心配していません。

私のコードの再編成に関して、私が説明する「キャッシュ」は実際にはディスク上のファイルのセットであるため、本質的にはあなたが推奨する構造をすでに持っています。サードパーティのライブラリはファイルパスのみを入力として受け入れるため、そのルートに従う必要がありました。

最後の質問への回答:

  1. ブロブをストリームとして読み取ることは、それを読み取ることができる唯一の方法ですか? それを byte[] などとして取得するための API メソッドは見当たりません。

  2. FileStream は読み取り/書き込みである必要はありませんが、変更しても改善されませんでした。

4

2 に答える 2

0

たとえば、サードパーティ コンポーネントのインスタンスをインスタンス化/破棄する方法や、そのコンポーネントにデータを渡す方法を理解するのに十分なコードを投稿していないため、何が問題なのかを判断するのは困難です。

ただし、考慮すべき点がいくつかあります。

暗黙の了解: 未処理の例外をスローしているため、アプリがクラッシュしています。ストレージ サービスとやり取りする操作はすべて失敗すると想定します。まだ行っていない場合は、そうします。したがって、BLOB 取得コードをラップする例外ハンドラーを実装し、必要に応じて再試行セマンティクスを実装します。アプリ コード内のクラッシュとエラーをログに記録するために、 ELMAHログを追加することをお勧めします。

サードパーティのライブラリが「安全でない」という意味がよくわかりません。PInvoke する必要があるネイティブ ライブラリであるため、「安全でない」という意味ですか?

コードがサードパーティ コンポーネントをインスタンス化/破棄する方法によっては、コンポーネントが使用後にメモリに残り、破損/混乱する状態が維持される場合があります。このようなコンポーネントを使用する必要がある場合は、IDisposable もサポートする独自の PInvoke ラッパーを作成し、作業が完了したらコンポーネントを強制的にアンロードすることを検討してください。ただし、これによりパフォーマンスが低下する可能性があることに注意してください。

考慮すべきもう 1 つの点: サードパーティ コンポーネントがディスクからのみファイルをロードするように、コードを少し再編成する必要があるかもしれません。

  1. ファイルがディスク上にない場合は、Azure から読み込み (必要な例外ハンドラーで操作をラップ)、ディスクに保存します。
  2. ファイルの内容をディスクからロードし、サードパーティ コンポーネントに渡します

さらに、コード内で他にも確認すべき点がいくつかあります。

  1. blob を byte[] や文字列ではなくストリームとして読み取っている理由はありますか?
  2. 読み取り/書き込みファイルストリームを作成している理由はありますか? ストリームに書き込みを行っていない場合は、ストリームを読み取り専用モードで開くことを検討してください。

更新 2013-02-28 @ 16:47 PST - 上記の KingCronus の更新への返信:

CloudBlobContainer.GetBlockBlobReference(...) は CloudBlockBlob オブジェクトを返します。CloudBlockBlob オブジェクトには、DownloadByteArray()DownloadText()、そして重要なことにDownloadToFile( ) のメソッドがあります。この後者の API は、ファイル破損の問題を完全に軽減するのに役立つ可能性があります。

PInvoking しているネイティブ コンポーネントが、IIS の制御外で実行中のプロセスを破壊している可能性は十分にあります。

入力データ (つまり、ファイル) が破損しているためにクラッシュしている場合は、データを前処理してコンポーネントの要件に準拠できるようにすることを検討してください。

特に内部状態が壊れているためにコンポーネントが引き続きクラッシュする場合は、コンポーネントのインスタンスをホストする Windows サービスを作成するなどして、IIS からコンポーネントを分離することを検討してください。このようなサービスは、失敗した場合に自動的に再起動できます。WCF/NamedPipes/etc を介して、コンポーネントをホストしているサービスと通信できます。データをマーシャリングします。ただし、このような最後の手段を導入するよりも、可能であればコンポーネント全体を交換することを検討したいと思います。

于 2013-02-26T22:14:17.467 に答える
0

この種のものには例外処理を使用する必要があります。

      try
        {
            //connection here
        }
        catch (Exception ex)
        {
            MessageBox.Show(ex.Message, Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error);
            // will give you the error if no connection and you can get an idea why it crashes
        }
于 2013-02-26T16:35:20.340 に答える