swoft-cloud / swoft

🚀 PHP Microservice Full Coroutine Framework
https://swoft.org
Apache License 2.0
5.58k stars 787 forks source link

并发下RPC响应可能互窜 #1472

Open stevennight opened 2 years ago

stevennight commented 2 years ago
Q A
Bug report? yes
Feature request? no
Swoft version 2.0.11
Swoole version 4.8.5
PHP version 7.4.27
Runtime environment Ubuntu

Describe the bug 并发下RPC客户端请求和接受的结果不匹配。 如传入ID 1可能接收到的结果是ID 2。详细代码如下Detail。

并发模拟: ab -n 100000 -c 10 "http://192.168.138.130:18306/?id=1" ab -n 100000 -c 10 "http://192.168.138.130:18306/?id=2"

b0phm6.png

Expected behavior 不会出现响应和请求不匹配

Screenshots b0phm6.png

Details

RPC服务:

<?php declare(strict_types=1);
/**
 * This file is part of Swoft.
 *
 * @link     https://swoft.org
 * @document https://swoft.org/docs
 * @contact  group@swoft.org
 * @license  https://github.com/swoft-cloud/swoft/blob/master/LICENSE
 */

namespace App\Rpc\Service;

use App\Rpc\Lib\UserInterface;
use Exception;
use RuntimeException;
use Swoft\Co;
use Swoft\Rpc\Server\Annotation\Mapping\Service;

/**
 * Class UserService
 *
 * @since 2.0
 *
 * @Service()
 */
class UserService implements UserInterface
{
    /**
     * @param int $id
     * @param mixed $type
     * @param int $count
     *
     * @return array
     */
    public function getList(int $id, $type, int $count = 10): array
    {
        vdump(1);
        // 模拟耗时操作
        Co::sleep(random_int(0,500) / 1000);
        vdump(2);
        return [
            'id' => $id,
        ];

        return ['name' => ['list']];
    }
}

RPC客户端:

<?php declare(strict_types=1);
/**
 * This file is part of Swoft.
 *
 * @link     https://swoft.org
 * @document https://swoft.org/docs
 * @contact  group@swoft.org
 * @license  https://github.com/swoft-cloud/swoft/blob/master/LICENSE
 */

namespace App\Http\Controller;

use App\Model\Data\GoodsData;
use App\Rpc\Lib\UserInterface;
use Swoft;
use Swoft\Http\Message\ContentType;
use Swoft\Http\Message\Response;
use Swoft\Http\Server\Annotation\Mapping\Controller;
use Swoft\Http\Server\Annotation\Mapping\RequestMapping;
use Swoft\Log\Helper\CLog;
use Swoft\Rpc\Client\Annotation\Mapping\Reference;
use Swoft\View\Renderer;
use Throwable;
use function bean;
use function context;

/**
 * Class HomeController
 * @Controller()
 */
class HomeController
{
    /**
     * @Reference(pool="testrpc.pool")
     * @var UserInterface
     */
    public $user;

    /**
     * @RequestMapping("/")
     * @throws Throwable
     */
    public function index(Swoft\Http\Message\Request $request): Response
    {
        $id = (int) $request->query('id');
        $array = $this->user->getList($id, 'test');
        var_dump($id);
        if ($id !== $array['id']) {
            var_dump($id . ':' .  $array['id'] . '不匹配');
            CLog::error($id . ':' .  $array['id'] . '不匹配');
        }

        return context()->getResponse();

        /** @var Renderer $renderer */
        $renderer = Swoft::getBean('view');
        $content  = $renderer->render('home/index');

        return context()->getResponse()->withContentType(ContentType::HTML)->withContent($content);
    }
}