网站出现恶意并发攻击,解决问题第一步,自己先模拟并发,进行测试
注意:
session 登录状态,我们需要设置 cookie
api 登录状态,我们一般需要设置 Bearer token
1.并发工具:
postman - 网上各种说 postman 并发测试,那是迭代请求,并非并发,错误
AB(Apache Bench) - 这个是经常听说的一款,很简单
参考:
ab(Apache Bench)命令详解以及压力测试模拟
https://blog.csdn.net/jiajiren11/article/details/79486967
JMeter - Apache JMeter是Apache组织开发的基于Java的压力测试工具
参考:
使用 JMeter 进行压力测试
https://www.cnblogs.com/stulzq/p/8971531.html
其他工具,没看,参考:
10大主流压力测试工具
https://blog.csdn.net/langzitianya/article/details/81479422
九款Web服务器性能压力测试工具
https://blog.csdn.net/qq_33440246/article/details/80591070
2.自己使用 PHP 来模拟并发
1>使用 guzzlehttp 的并发请求
use GuzzleHttp\Client;
use GuzzleHttp\Promise;
use Psr\Http\Message\ResponseInterface;
use GuzzleHttp\Exception\RequestException;
use GuzzleHttp\Exception\ServerException;
/**
* 模拟发红包 - 异步并发
*/
public function mockSendRedPacketConcurrent($token)
{
$client = new Client([
'base_uri' => 'http://xxx/api/',
]);
$promises = [];
for($i = 0; $i < 20; $i++){
$promise = $client->postAsync('red/sent', [
'headers' => [
'Accept' => 'application/json',
// 登录 token
'Authorization' => 'Bearer ' . $token,
// 模拟不同的虚拟IP
'X-Forwarded-For' => '168.1.1.' . $i,
],
'query' => [
'red_money' => 100,
'red_type' => 1,
'red_group' => 184,
'red_num' => 1,
'red_title' => '恭喜发财',
],
]);
$promises[] = $promise;
}
$results = Promise\unwrap($promises);
foreach($results as $result){
$body = $result->getBody();
$content = $body->getContents();
dump($content);
}
}
2>使用 curl 并发请求
https://www.cnblogs.com/52fhy/p/8908315.html
https://www.oschina.net/question/54100_58279
/**
* 模拟发红包 - Rolling cURL并发
*/
public function mockSendRedPacketCurl()
{
$token = '';
$urls = [];
for($i = 0; $i < 600; $i++){
$urls[] = 'http://xxx/api/red/sent';
}
$responses = $this->rolling_curl($urls, $token, 30);
dd($responses);
}
/**
* Rolling cURL并发
*/
private function rolling_curl($urls, $token, $delay) {
$queue = curl_multi_init();
$map = array();
foreach ($urls as $i => $url) {
$ch = curl_init();
$headers = [
'Accept' => 'application/json',
// 登录 token
'Authorization' => 'Bearer ' . $token,
// 模拟不同的虚拟IP
'X-Forwarded-For' => '168.1.1.' . $i,
];
$params = [
'red_money' => 1,
'red_type' => 2,
'red_group' => '201910270025455db473899d72f',
'red_num' => 1,
'red_title' => '并发测试',
];
// $params = [
// 'red_money' => 100,
// 'red_type' => 1,
// 'red_group' => 184,
// 'red_num' => 1,
// 'red_title' => '恭喜发财',
// ];
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $params);
curl_setopt($ch, CURLOPT_TIMEOUT, 100);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_NOSIGNAL, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_multi_add_handle($queue, $ch);
$map[(string) $ch] = $url;
}
$responses = array();
do {
while (($code = curl_multi_exec($queue, $active)) == CURLM_CALL_MULTI_PERFORM) ;
if ($code != CURLM_OK) { break; }
// a request was just completed -- find out which one
while ($done = curl_multi_info_read($queue)) {
// get the info and content returned on the request
$info = curl_getinfo($done['handle']);
$error = curl_error($done['handle']);
$content = curl_multi_getcontent($done['handle']);
// $results = callback(curl_multi_getcontent($done['handle']), $delay);
// $responses[$map[(string) $done['handle']]] = compact('info', 'error', 'results');
$responses[] = [
'info' => $info,
'error' => $error,
'content' => $content,
];
// remove the curl handle that just completed
curl_multi_remove_handle($queue, $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($queue, 0.5);
}
} while ($active);
curl_multi_close($queue);
return $responses;
}
参考文章:
模拟 ip 是可以的
https://blog.csdn.net/intel80586/article/details/8906779
不过 laravel 的 ip() 好像检测比较准确
使用 guzzlehttp 来实现并发请求:
https://segmentfault.com/q/1010000007683839
使用guzzle发送异步请求返回的promise 调用 then 方法不会立即执行, 还必须要调用wait去等待所有的请求结束,才会执行
curl 并发:
https://www.cnblogs.com/52fhy/p/8908315.html
https://www.oschina.net/question/54100_58279