Блог программиста Еремина Вячеслава Викторовича
(ASP.NET) ASP NET (2010 год)

Тестирование производительности Web-приложений

web performance У меня на сайте размещено много информации, посвященной наблюдению за web-приложениями, однако в той заметке я создавал нагрузку на Web-приложение с помощью какой-то адской микрософтовской системы, которая входит в самую дорогую комплектацию Visual Studio (более чем за 10 тысяч долларов). Это конечно полный бред - заплатить десять тысяч долларов ОПГ Билла Гейтса за сотню строчек бейсика.

Поэтому я решил опубликовать для web-прогрммистов приложение для создания нагрузки на сайты, для отслеживания поведения своего сайта под нагрузкой и проверки - какое технологическое решение более производительно. Думаю, мои колебания вы понимаете - любой предмет можно использовать не по назначению, например травматический пистолет предназначен для защиты от нападения хулиганов, однако как вы знаете, некоторые мусора додумались засовывать его в задний проход попавшим в вытрезвитель и убивать там народ именно так.

Как вы понимаете, программы создающие нагрузки на сайты тоже можно использовать через Ж - например чтобы положить любой сайт вообще. Собственно, как скоро сайт начнет ложиться при том или ином программном решении - это и позволяет определиться какое именно решение у программиста было верное. Поэтому прогу этого топика я полностью публикую в исходном виде, но в бинарном виде выкладываю только под Linux и без умножителя нагрузки.

Первая утилита WebRequest создает собственно нагрузку на сайт. Для примера я проверил ею правильность технологических решений трех сайтов - сайт нашего фюрера (сайт его оффшорчика, куда он сгоняет выручку от выкачанной из России нефти), сайт Доку Умарова (которому так нравится взрывать нас) и сайт Билла Гейтса (которому так нравится подкупать наших идиотов в минобразовании, чтобы они вставляли именно его гнусные проги для обязательного изучения в школе начиная с третьей четверти третьего класса).

Взгляните подробнее на рисунок в титуле этой страницы. Как вы видите - сайт оффшорчика нашего фюрера держит нагрузку лучше всех - значит програмистские решения в нем были приняты самые верные. Чеченский сайт держит нагрузку гораздо хуже. Ну а идиоты-микрософтовцы как всегда сумели отличиться - отклик их сайта не только самый большой в абсолютных значениях, но и нарастает самыми быстрыми темпами.


   1:  Module Module1
   2:   
   3:      <MTAThreadAttribute()> _
   4:          Sub Main()
   5:          Dim URL As String
   6:          Dim RepeatCount As Integer
   7:          Dim PRM() As String = Environment.GetCommandLineArgs
   8:          Try
   9:              If PRM.Count < 3 Then
  10:                  GoTo usage
  11:              Else
  12:                  URL = PRM(1)
  13:                  RepeatCount = PRM(2)
  14:              End If
  15:              Console.WriteLine(AppDomain.GetCurrentThreadId.ToString & " : start at " & Now & " " & URL)
  16:              For i As Integer = 0 To RepeatCount - 1
  17:                  Dim MyState1 As New MyState(i, Now, AppDomain.GetCurrentThreadId)
  18:                  Dim X As New AsyncWebRequest(AddressOf EndAsyncWebRequest, URL, MyState1)
  19:                  X.WebRequest()
  20:              Next
  21:              Console.ReadLine()   'остановим основной поток
  22:              Exit Sub
  23:          Catch ex As Exception
  24:              Console.WriteLine("Error: " & ex.Message)
  25:          End Try
  26:   
  27:  usage:  Console.WriteLine("Usage:       WebPerfomance.exe URL RepeatCount" & vbCrLf & _
  28:                            "URL:         Запрашиваемый URL," & vbCrLf & _
  29:                            "RepeatCount: Количество запросов URL")
  30:      End Sub
  31:   
  32:      'хандлер асинхронного завершения потока чтения
  33:      Public Sub EndAsyncWebRequest(ByVal result As System.IAsyncResult)
  34:          Dim HTML As String = CType(result, AsyncWebRequest).HTML
  35:          Dim MyState1 As MyState = CType(result, AsyncWebRequest).AsyncState
  36:          Console.WriteLine(MyState1.StartThreadID.ToString & " : " & (MyState1.I + 1).ToString("000000") & " : " & Len(HTML).ToString("000000") & " : " & Now.Subtract(MyState1.StartTime).ToString)
  37:      End Sub
  38:   
  39:   
  40:      Public Class AsyncWebRequest
  41:          Implements IAsyncResult
  42:   
  43:          Dim _IsCompleted As Boolean = False
  44:          Dim _Callback As AsyncCallback
  45:          Dim _URL As String
  46:          Dim _HTML As String
  47:          Dim _MyState As MyState
  48:   
  49:          Public ReadOnly Property AsyncState() As Object Implements System.IAsyncResult.AsyncState
  50:              Get
  51:                  Return _MyState
  52:              End Get
  53:          End Property
  54:   
  55:          Public ReadOnly Property AsyncWaitHandle() As System.Threading.WaitHandle Implements System.IAsyncResult.AsyncWaitHandle
  56:              Get
  57:                  Return Nothing
  58:              End Get
  59:          End Property
  60:   
  61:          Public ReadOnly Property CompletedSynchronously() As Boolean Implements System.IAsyncResult.CompletedSynchronously
  62:              Get
  63:                  Return False
  64:              End Get
  65:          End Property
  66:   
  67:          Public ReadOnly Property IsCompleted() As Boolean Implements System.IAsyncResult.IsCompleted
  68:              Get
  69:                  Return _IsCompleted
  70:              End Get
  71:          End Property
  72:   
  73:          Public ReadOnly Property HTML()
  74:              Get
  75:                  Return _HTML
  76:              End Get
  77:          End Property
  78:   
  79:          Public Sub New(ByVal callback As AsyncCallback, ByVal URL As String, ByVal MyState As MyState)
  80:              _URL = URL
  81:              _Callback = callback
  82:              _MyState = MyState
  83:          End Sub
  84:   
  85:          Public Sub WebRequest()
  86:              Threading.ThreadPool.QueueUserWorkItem(New Threading.WaitCallback(AddressOf AsyncRequest), Nothing)
  87:          End Sub
  88:   
  89:          'запрос по HTTP в отдельном потоке пула потоков
  90:          Public Sub AsyncRequest()
  91:              Dim Request As Net.HttpWebRequest = CType(System.Net.WebRequest.Create(_URL), Net.HttpWebRequest)
  92:              Request.AllowAutoRedirect = True
  93:              Dim Response As Net.WebResponse = Request.GetResponse()
  94:              Dim Reader As New System.IO.StreamReader(Response.GetResponseStream(), System.Text.Encoding.Default)
  95:              _HTML = Reader.ReadToEnd
  96:              Reader.Close()
  97:              _IsCompleted = True
  98:              _Callback(Me)
  99:          End Sub
 100:   
 101:      End Class
 102:   
 103:      'состояние потока для печати
 104:      Public Class MyState
 105:   
 106:          Dim _I As Integer
 107:          Dim _StartTime As DateTime
 108:          Dim _StartThreadID As Integer
 109:   
 110:          Public ReadOnly Property I() As Integer
 111:              Get
 112:                  Return _I
 113:              End Get
 114:          End Property
 115:   
 116:          Public ReadOnly Property StartTime() As DateTime
 117:              Get
 118:                  Return _StartTime
 119:              End Get
 120:          End Property
 121:   
 122:          Public ReadOnly Property StartThreadID() As Integer
 123:              Get
 124:                  Return _StartThreadID
 125:              End Get
 126:          End Property
 127:   
 128:          Public Sub New(ByVal I As Integer, ByVal StartTime As DateTime, ByVal StartThreadID As Integer)
 129:              _I = I
 130:              _StartTime = StartTime
 131:              _StartThreadID = StartThreadID
 132:          End Sub
 133:   
 134:      End Class
 135:   
 136:  End Module


Теперь расмотрим утилиту CommandStarter - умножитель нагрузки, который позволяет создать несколько Win-задач, каждая из которых запустит псевдопотоки .NET с web-реквестами. Как и предыдущее приложение - это простое консольное приложение. Как оно работает - ясно из скрина слева.


web performance
   1:  Module Module1
   2:   
   3:      Sub Main()
   4:          Dim PRM() As String = Environment.GetCommandLineArgs
   5:          Dim RepeatCount As Integer
   6:          Dim StartedCommand As String
   7:          Dim CommandArguments As String = ""
   8:          Try
   9:              If PRM.Count < 3 Then
  10:                  GoTo usage
  11:              Else
  12:                  RepeatCount = PRM(1)
  13:                  StartedCommand = PRM(2)
  14:                  For i As Integer = 3 To PRM.Count - 1
  15:                      CommandArguments &= " " & PRM(i)
  16:                  Next
  17:              End If
  18:              '
  19:              For i As Integer = 1 To RepeatCount
  20:                  Dim NewWindows As New OneStart(StartedCommand, CommandArguments)
  21:                  Dim NewThread As New System.Threading.Thread(AddressOf NewWindows.Start)
  22:                  NewThread.Start()
  23:              Next
  24:              Exit Sub
  25:          Catch ex As Exception
  26:              Console.WriteLine("Error: " & ex.Message)
  27:          End Try
  28:  usage:  Console.WriteLine("Usage: CommandStarter RepeaterCount StartedCommand CommandParameters" & vbCrLf & _
  29:                            "RepeaterCount    : количество одновременно запускаемых клонов комманды," & vbCrLf & _
  30:                            "StartedCommand   : стартуемая команда," & vbCrLf & _
  31:                            "CommandArguments : параметры команды")
  32:      End Sub
  33:   
  34:      Public Class OneStart
  35:   
  36:          Dim _StartedCommand As String
  37:          Dim _CommandArguments As String
  38:   
  39:          Public Sub New(ByVal StartedCommand As String, ByVal CommandArguments As String)
  40:              _StartedCommand = StartedCommand
  41:              _CommandArguments = CommandArguments
  42:          End Sub
  43:   
  44:          Public Sub Start()
  45:              Dim Proc1 As New System.Diagnostics.Process
  46:              Proc1.StartInfo.UseShellExecute = True
  47:              Proc1.StartInfo.CreateNoWindow = False
  48:              Proc1.StartInfo.FileName = _StartedCommand
  49:              Proc1.StartInfo.Arguments = _CommandArguments
  50:              Proc1.Start()
  51:              Proc1.Close()
  52:          End Sub
  53:   
  54:      End Class
  55:   
  56:  End Module

Этот топик будет продолжен утилитой для замера производительности SQL-операций сайта. В бинарном виде первую утилиту вы можете сгрузить отсюда.



Комментарии к этой страничке ( )
ссылка на эту страничку: http://www.vb-net.ru/WebPerfomance/index.htm
<На главную>  <В раздел ASP>  <В раздел NET>  <В раздел SQL>  <В раздел Разное>  <Написать автору>  < Поблагодарить>