写点什么

架構師訓練營第 1 期 - 第 07 周作業

用户头像
Panda
关注
发布于: 2020 年 11 月 06 日

1. 性能压测的时候,随着并发压力的增加,系统响应时间和吞吐量如何变化,为什么?

性能壓測依據併發的壓力可以分為三個階段

1. 性能測試階段

  • 此階段在系統設計規劃的併發壓力範圍之內

  • 當併發壓力持續增加

  • 系統的吞吐量會有近似線性的增加

  • 系統的響應時間只會微幅的變慢

  • 原因

  • 併發壓力在設計之內

  • 系統的資源也很充足

  • 所以併發壓力不會影響系統處理用戶請求

2. 負載測試階段

  • 此階段已超過系統設計規劃,但尚在服務器最高可容許的範圍之內

  • 當併發壓力持續增加

  • 系統吞吐量的增加比例會減緩

  • 系統的響應時間會有較大幅度的變慢

  • 原因

  • 因為此時服務器的資源開始不足

  • 雖然開始不足,但還是能處理比性能測試階段更多的請求

  • 所以吞吐量還是會增加,只是比例沒有那麼大

  • 較多的線程會等待 CPU 的調度、等待鎖、等待網路 I/O等

  • 在等待時就會影響響應的時間

3. 壓力測試階段

  • 此時已經超過服務器可以負荷的最高容許範圍

  • 當併發壓力持續增加

  • 系統的吞吐量會開始下降

  • 系統的響應時間會有更大幅度的變慢,直到最後系統崩潰不響應

  • 原因

  • 因為服務器的資源開始大量的不足

  • 大部分的線程都在等待服務器的資源

  • 內存大量的不足,處理能力都消耗在硬盤及內存的置換上

  • 處理用戶的請求能力下降,導致吞吐量降低

  • 因為服務器的處理請求能力持續下降

  • 導致請求的處理時間持續變長,響應時間也極速的變慢

  • 最後導致系統崩潰不響應

2. 用你熟悉的编程语言写一个 Web 性能压测工具,输入参数:URL,请求总次数,并发数。输出参数:平均响应时间,95% 响应时间。用这个测试工具以 10 并发、100 次请求压测 www.baidu.com

import threading
import requests
import time
import pandas as pd

class TimeIt(object):
def __init__(self, func):
self._func = func
self._result = []

def __call__(self, *args, **kwargs):
start_time = time.time_ns()
res = self._func(*args, **kwargs)
end_time = time.time_ns()
self._result.append((end_time - start_time) // 1000000)
return res

def get_result(self):
return self._result

class Delay(object):
def __init__(self, func):
self._func = func

def __call__(self, *args, **kwargs):
res = self._func(*args, **kwargs)
time.sleep(100 // 1000)
return res

class TestThread(threading.Thread):
def __init__(self, request_times, **kwargs):
threading.Thread.__init__(self, **kwargs)
self._request_times = request_times
self._time_it = TimeIt(self._target)
self._real_func = Delay(self._time_it)
self._target = self._execute

def _execute(self, *args, **kwargs):
for _ in range(self._request_times):
self._real_func(*args, **kwargs)

def get_time_result(self):
if self._time_it:
return self._time_it.get_result()
return None

def test_request(url):
requests.get(url)

def stress_test(url, concurrent_number, request_times):

testThs = []
result = []
for ith in range(concurrent_number):
testThs.append(TestThread(request_times, target = test_request, args = (url,)))

for ith in range(concurrent_number):
testThs[ith].start()

for ith in range(concurrent_number):
testThs[ith].join()

for ith in range(concurrent_number):
result.extend(testThs[ith].get_time_result())

data = pd.Series(result)

return data.count(), data.mean(), data.quantile(0.95)

if __name__ == '__main__':

url = 'https://www.baidu.com'
concurrent_number = 10
request_times = 100

count, mean, percentile95 = stress_test(url, concurrent_number, request_times)

print('Stress Test')
print(f'Test URL: {url}')
print(f'Concurrent: {concurrent_number}')
print(f'Test Times for Each: {request_times}')
print(f'Total Times: {count}')
print(f'Mean Response Time: {mean} ms')
print(f'95 Percentile Response Time: {percentile95} ms')



Output
------------------
Stress Test
Test URL: https://www.baidu.com
Concurrent: 10
Test Times for Each: 100
Total Times: 1000
Mean Response Time: 276.13 ms
95 Percentile Response Time: 343.04999999999995 ms



說明:

  • TestThread 繼承 thread.Thread

  • 使用 _execute(...) 置換代入的 target function

  • 在 _execute(...) 中執行所設定的測試次數

  • 記錄每一次測試所需的時間

  • 每一次測試到下次測試間需隔一段時間

  • 目前是 100 ms

  • 如果不間隔,則百度網會在中間測試時拒絕,無法達到所需測試的次數

  • 根據併發數的設定,產生相對應個數的 TestThread

  • 將所有測試的結果(每一次響應時間)集合在一個 list 中

  • 利用 pandas 算出所需的響應平均值及 95%響應時間

发布于: 2020 年 11 月 06 日阅读数: 27
用户头像

Panda

关注

还未添加个人签名 2015.06.29 加入

还未添加个人简介

评论

发布
暂无评论
架構師訓練營第 1 期 - 第 07 周作業