写点什么

第七周作业

用户头像
刘卓
关注
发布于: 2020 年 07 月 23 日
  • 性能压测的时候,随着并发压力的增加,系统响应时间和吞吐量如何变化,为什么?

压测时由于已经经过了性能测试和负载测试的阶段,系统在资源占用且无法合理释放的情况下,处理并发请求的能力会迅速下降,对于单个请求的响应时间会迅速增加,吞吐量也会迅速下降。

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

class TestController extends Controller
{
const user_agent = 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36';
function actionRun($url, $method, $data, $async_count, $times)
{
$request = [
'method' => $method,
'url' => $url,
'referer' => '',
'data' => $data
];
$elapseds = [];
echo '---- url: ' . $url . ' ---- async count: ' . $async_count . ' ---- times: ' . $times . "\r\n";
for ($i = 0; $i < $times; $i++) {
echo '---- time: ' . $i;
$start = microtime(true);
$this->multi_curl($request, $async_count);
$elapsed = microtime(true) - $start;
$elapseds[] = $elapsed;
echo ' ---- elapsed: ' . $elapsed . "\r\n";
}
sort($elapseds, SORT_NUMERIC);
$percent_index = intval($times * 0.95);
$percent_elapsed = $elapseds[$percent_index - 1];
$avg_elapsed = array_sum($elapseds) / count($elapseds);
echo '---- 95%: ' . $percent_elapsed . '---- index: ' . $percent_index . '---- avg: ' . $avg_elapsed . "\r\n";
}
function multi_curl($request, $async_count)
{
$mh = curl_multi_init();
for ($i = 0; $i < $async_count; $i++) {
$default = [
'method' => 'GET',
'user-agent' => self::user_agent,
'url' => null,
'referer' => 'https://www.google.co.uk',
'headers' => null,
'data' => [],
'proxy' => false,
'timeout' => 15
];
$request = array_merge($default, $request);
$method = mb_strtolower($request['method']);
$method_allow = ['get', 'post'];
if (null === $request['url'] || !in_array($method, $method_allow, true)) {
continue;
}
$options = [
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_USERAGENT => $request['user-agent'],
CURLOPT_REFERER => $request['referer'],
CURLOPT_TIMEOUT => $request['timeout'],
CURLOPT_CONNECTTIMEOUT => 5,
CURLOPT_RETURNTRANSFER => 1,
];
if ($method == 'get') {
$options[CURLOPT_HTTPGET] = true;
$options[CURLOPT_URL] = self::buildUrl($request['url'], $request['data']);
} elseif ($method == 'post') {
$options[CURLOPT_URL] = $request['url'];
$options[CURLOPT_POST] = true;
$content_type = isset($request['headers']) && isset($request['headers']['Content-Type']) ? $request['headers']['Content-Type'] : null;
$options[CURLOPT_POSTFIELDS] = self::buildPostData($request['data'], $content_type);
}
// headers
if (isset($request['headers'])) {
$http_headers = [];
foreach ($request['headers'] as $k => $v) {
$http_headers[] = $k . ':' . $v;
}
$options[CURLOPT_HTTPHEADER] = $http_headers;
}
$nor_curl = curl_init();
curl_setopt_array($nor_curl, $options);
curl_multi_add_handle($mh, $nor_curl); //2 增加句柄
}
$active = null;
do {
while (($mrc = curl_multi_exec($mh, $active)) == CURLM_CALL_MULTI_PERFORM) ;
if ($mrc != CURLM_OK) {
break;
}
// a request was just completed -- find out which one
while ($done = curl_multi_info_read($mh)) {
// get the info and content returned on the request
$info = curl_getinfo($done['handle']);
$error = curl_error($done['handle']);
if (!isset($error) || empty($error)) {
$content = curl_multi_getcontent($done['handle']);
} else {
echo 'url: ' . $info['url'] . ' error: ' . $error;
}
// remove the curl handle that just completed
curl_multi_remove_handle($mh, $done['handle']);
curl_close($done['handle']);
}
// Block for data in / output; error handling is done by curl_multi_exec
if ($active > 0) {
curl_multi_select($mh);
}
} while ($active);
return;
}
private static function buildUrl($url, $mixed_data = '')
{
$query_string = '';
if (!empty($mixed_data)) {
$query_mark = strpos($url, '?') > 0 ? '&' : '?';
if (is_string($mixed_data)) {
$query_string .= $query_mark . $mixed_data;
} elseif (is_array($mixed_data)) {
$query_string .= $query_mark . http_build_query($mixed_data, '', '&');
}
}
return $url . $query_string;
}
public static function buildPostData($data, $content_type)
{
$jsonPattern = '/^(?:application|text)\/(?:[a-z]+(?:[\.-][0-9a-z]+){0,}[\+\.]|x-)?json(?:-[a-z]+)?/i';
$binary_data = false;
// Return JSON-encoded string when the request's content-type is JSON and the data is serializable.
if (isset($content_type) &&
preg_match($jsonPattern, $content_type) &&
(
is_array($data) ||
(
is_object($data) &&
interface_exists('JsonSerializable', false) &&
$data instanceof JsonSerializable
)
)) {
$data = \Curl\Encoder::encodeJson($data);
} elseif (is_array($data)) {
// Manually build a single-dimensional array from a multi-dimensional array as using curl_setopt($ch,
// CURLOPT_POSTFIELDS, $data) doesn't correctly handle multi-dimensional arrays when files are
// referenced.
if (ArrayUtil::is_array_multidim($data)) {
$data = ArrayUtil::array_flatten_multidim($data);
}
// Modify array values to ensure any referenced files are properly handled depending on the support of
// the @filename API or CURLFile usage. This also fixes the warning "curl_setopt(): The usage of the
// @filename API for file uploading is deprecated. Please use the CURLFile class instead". Ignore
// non-file values prefixed with the @ character.
foreach ($data as $key => $value) {
if (is_string($value) && strpos($value, '@') === 0 && is_file(substr($value, 1))) {
$binary_data = true;
if (class_exists('CURLFile')) {
$data[$key] = new CURLFile(substr($value, 1));
}
} elseif ($value instanceof CURLFile) {
$binary_data = true;
}
}
}
if (!$binary_data &&
(is_array($data) || is_object($data)) &&
(
!isset($content_type) ||
!preg_match('/^multipart\/form-data/', $content_type)
)) {
$data = http_build_query($data, '', '&');
}
return $data;
}
}



测试结果:



用户头像

刘卓

关注

还未添加个人签名 2018.04.26 加入

还未添加个人简介

评论

发布
暂无评论
第七周作业