Тестирование производительности Web-приложений
Поэтому я решил опубликовать для 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-реквестами. Как и предыдущее приложение - это простое консольное приложение. Как оно работает - ясно из скрина слева.
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-операций сайта. В бинарном виде первую утилиту вы можете сгрузить отсюда.
|