DOBON.NET DOBON.NETプログラミング掲示板過去ログ

XML WEBサービスでのレスポンス改善方法

環境/言語:[Visual Studio 2008(Framework3.5)、Sql Server 2008]
分類:[ASP.NET]

XML WEBサービスを使用してで業務アプリの開発を検討していますがデータ件数が増えてくると
レスポンスが落ちると聞いております。テストデータを作成し、試してみましたが
やはりレスポンスが低下するようです。いくつか試してみましたが劇的に
レスポンスが改善するものはありませんでした。
あまり大量のデータを取得しないよう設計するしかないのでしょうか?
別途方法等ありましたらご教授お願いします。

【開発環境】
Visual Studio 2008
Sql Server 2008

【以下試した内容】
・データを圧縮・解凍して送受信。
・データをバイナリにして送受信。
・可能な限りデータセットをしないでデータリーダーを使用するように変更
・初回起動時、レスポンスが遅いため、ログイン時非同期でデータベースアクセス。


【例】データセットを使用してデータグリッドに表示
22万件のデータにアクセスし、データグリッドに表示した場合
XML WEBサービス使用した場合 →18秒
XML WEBサービス使用しない場合 →3秒


以上、お手数ですがよろしくお願いいたします。
■No25389に返信(pootさんの記事)
> 【例】データセットを使用してデータグリッドに表示
> 22万件のデータにアクセスし、データグリッドに表示した場合
> XML WEBサービス使用した場合 →18秒
> XML WEBサービス使用しない場合 →3秒

  ボトルネックが本当にXML WEBサービスにあるのかどうか・・・
  調べる必要はあります。

  SQL Serverからデータを取得した際、その22万件からSELECTに
  掛る時間は、双方変わらないはずです。
  ただその取得した件数自体が多い場合・・・
  現在のXMLサービスでは、ネットワーク上をXMLデータが非圧縮で
  流れてしまうはずですので、ネットワーク通信に時間を要してい
  るのか、クライアント側IEで取得したデータを表示するのに時間
  がかかっているのか・・・

  それらを再度調べてみてお考えになれば・・・と思います。

以上。参考まで・・・
■No25389に返信(pootさんの記事)
> 劇的にレスポンスが改善するものはありませんでした。
処理階層が増えるわけですから、処理手順等を充分に検討して
 DB サーバ上でやらせるべきことと、
 Web サーバー側でやるべきことと、
 クライアント側でやるべきことと、
 (時には、キャッシュ用ローカルDB上でやらせるべきこと)
そのそれぞれを、適切に分離する事がより重要となります。


> 別途方法等ありましたらご教授お願いします。
・サーバー側とクライアント側の双方で、HTTP 圧縮を有効にする。

・データ更新のために編集後の DataSet を返却する必要がある場合には、
 DataSet 全体を送り返すのではなく、GetChanges で変更差分のみを取り出す。

・更新頻度が低い割に、参照回数の多いデータについては、可能であれば
 ローカルキャッシュなどに蓄える事を検討する。

・SOAP 通信による XML 化のために、元データに対して付加情報が
 発生するため、小規模のデータを細かく送る事は避けて、
 ある程度まとめて一度に送る事ができないかも検討する。

・巨大なバイナリデータの交換が必要な場合、BASE64 処理される事を避けるため、
 生のバイナリその物を HTTP Request/Response Body 等で交換する事も検討する。
 (添付データ付き SOAP が使える処理系ばかりでは無いので…)


> XML WEBサービス使用した場合 →18秒
Fiddler2 などを用いて、どのような HTTP データがやり取りされているのかを
キャプチャしてみてください。その結果、データ量の増加以上に処理時間が
かかってしまっているようであれば、何か別の問題があるのかも知れません。
お世話になります。ご返信ありがとうございます。
一部環境の説明に不備がありましたので補足します。
XML WEBサービスを利用してClickOnceでアプリケーションの配布を考えています。

ご教授いただいた内容を元にボトルネックとなる部分の切り分けをしました。
データグリッド表示を無効にして処理を行ったところ、処理速度は
ほとんど変わりませんでした。
更新に関しては画面からは大量に更新することは無いと考えていますが、大量更新
する際はご教授いただいた内容を参考にさせていただきます。ありがとうございます。

色々調査した結果プログラム内で実装している圧縮・解凍処理で時間が
かかっているようです。
圧縮・解凍処理をはずしたところ、処理速度が18秒→9秒に短縮されました。
圧縮・解凍処理はある程度時間がかかってしまうのかそれともソースに問題が
あるのかわかりません。
圧縮・解凍処理についてはある本を参考に実装しました。
web.config、app.configに一部追加しwebサービスを使用する箇所すべてに
実装されるようになっております。
以下実際のソースになります。不備等ありましたらご指摘お願いいたします。

【ソース】
Imports System.Data
Imports System.IO
Imports System.Runtime.Serialization.Formatters.Binary
Imports System.Web
Imports System.Web.Services
Imports System.Web.Services.Protocols
Imports System.IO.Compression

Public Class CompressExtension
Inherits SoapExtension

Private Const BufferSize As Integer = 32768
Private mOldStream As Stream = Nothing
Private mNewStream As Stream = Nothing

Public Overloads Overrides Function ChainStream(ByVal stream As Stream) As Stream
mOldStream = stream
mNewStream = New MemoryStream
Return mNewStream
End Function

Public Overrides Sub ProcessMessage(ByVal message As SoapMessage)
' SOAP Message Stagesのチェック
Select Case message.Stage
Case SoapMessageStage.BeforeSerialize
message.ContentEncoding = "gzip"
Case SoapMessageStage.AfterSerialize
' 圧縮処理
Compress()
Case SoapMessageStage.BeforeDeserialize
If (message.ContentEncoding = "gzip") Then
'解凍処理
DeCompress()
Else
Me.Copy(mOldStream, mNewStream)
mNewStream.Position = 0
End If
Case SoapMessageStage.AfterDeserialize
' nop;
End Select
End Sub

' シリアライズ後の圧縮処理
Private Sub Compress()
Using zipStream As New GZipStream(mOldStream, CompressionMode.Compress, True)
mNewStream.Position = 0
Copy(mNewStream, zipStream)
End Using
End Sub

' デシリアライズ前の圧縮解除処理
Private Sub DeCompress()
Using unzipStream As New GZipStream(mOldStream, CompressionMode.Decompress, True)
Copy(unzipStream, mNewStream)
mNewStream.Position = 0
End Using
End Sub

' デシリアライズ前のコピー処理
Private Sub Copy(ByVal sourceStream As Stream, ByVal destinationStream As Stream)
Dim buf(BufferSize - 1) As Byte
Dim bytesRead As Integer = sourceStream.Read(buf, 0, buf.Length)
While bytesRead > 0
destinationStream.Write(buf, 0, bytesRead)
bytesRead = sourceStream.Read(buf, 0, buf.Length)
End While
End Sub

Public Overloads Overrides Function GetInitializer(ByVal serviceType As System.Type) As Object
Return Nothing
End Function

Public Overloads Overrides Function GetInitializer(ByVal methodInfo As System.Web.Services.Protocols.LogicalMethodInfo, ByVal attribute As System.Web.Services.Protocols.SoapExtensionAttribute) As Object
Return Nothing
End Function

Public Overrides Sub Initialize(ByVal initializer As Object)
End Sub
End Class

色々試していますので随時報告します。
以上、よろしくお願いします。
■No25401に返信(pootさんの記事)
> 圧縮・解凍処理をはずしたところ、処理速度が18秒→9秒に短縮されました。
> 圧縮・解凍処理はある程度時間がかかってしまうのかそれともソースに問題が
> あるのかわかりません。
通信にかかる時間と、圧縮・展開にかかる時間のトレードオフだと思います。

データ量が少ない時に使うと、パフォーマンスを悪くすると思いますし、逆に
データ量が多すぎる場合には、圧縮にかかるサーバー側負荷が高くなりすぎて
しまうことがあるため、無差別に圧縮しない方が良いかと思います。
(当方のあるプロジェクトでは、4MB〜40MB のみを圧縮対象にしていました)

圧縮に適した範囲は、そのWeb サービスが インターネット接続なのか、
LAN 接続なのかなど、幾つかの要件によって異なるかと思いますので、
実環境で閾値を変化させながら測定してみては如何でしょう。


> 圧縮・解凍処理についてはある本を参考に実装しました。
特に理由が無ければ、書名は伏せずに公開していただけると有り難いです。


> 以下実際のソースになります。不備等ありましたらご指摘お願いいたします。
私自身は SoapExtension を組み込んだ事が無いので、問題点の有無を指摘
することはできないのですが、身の回りのサンプルを幾つか見たところ、
これを IDisposable にして、ChainStream で差し替えたストリームを
破棄している実装を少数見かけました。ただ、それが適切な実装であるかどうかは
私には判断が付きませんが…。
お世話になります。
> 通信にかかる時間と、圧縮・展開にかかる時間のトレードオフだと思います。
→現時点ではインターネット回線を使用し、通常時はBフレッツ、バックアップ回線時にはISDNを使用すること想定しており、バックアップ回線に対応するためにも圧縮・解凍処理の実装は必須と考えております。処理が集中した際のサーバ負荷の不安はありますが…

> 特に理由が無ければ、書名は伏せずに公開していただけると有り難いです。
→Visual Basic 2008 逆引きレシピ[Windows アプリケーション編] と言う本です。

> 私自身は SoapExtension を組み込んだ事が無いので、問題点の有無を指摘
> することはできないのですが、身の回りのサンプルを幾つか見たところ、
> これを IDisposable にして、ChainStream で差し替えたストリームを
> 破棄している実装を少数見かけました。ただ、それが適切な実装であるかどうかは私には判断が付きませんが…。
→時間があるときに試して報告したいと思います。

DOBON.NET | プログラミング道 | プログラミング掲示板