Rumah  >  Artikel  >  rangka kerja php  >  Perkongsian contoh konkurensi tinggi: Swoole melaksanakan perniagaan dengan cekap melalui pengagregatan permintaan

Perkongsian contoh konkurensi tinggi: Swoole melaksanakan perniagaan dengan cekap melalui pengagregatan permintaan

青灯夜游
青灯夜游asal
2022-05-17 10:00:513556semak imbas

Artikel ini akan berkongsi dengan anda contoh permintaan pengagregatan serentak tinggi Swoole dan memperkenalkan cara menggunakan sepenuhnya pemprosesan kumpulan pangkalan data untuk melaksanakan fungsi perniagaan dengan lebih cekap melalui pengagregatan permintaan dalam senario serentak tinggi. Contoh ini hanya digunakan sebagai titik permulaan, dengan harapan dapat merangsang pemikiran yang lebih mendalam.

Perkongsian contoh konkurensi tinggi: Swoole melaksanakan perniagaan dengan cekap melalui pengagregatan permintaan

Kursus video yang disyorkan: " Puluhan juta penyelesaian konkurensi data (teori dan praktikal) "

Kongsi beberapa soalan temuduga konkurensi tinggi: 15 soalan temu duga PHP tentang konkurensi tinggi (ringkasan)

Latar belakang yang dipilih untuk contoh ini ialah perniagaan pesanan serentak. Dalam keadaan biasa, membuat pesanan pada bahagian belakang ialah operasi insert sekeping demi sekeping. Apabila konkurensi rendah, operasi insert pangkalan data sememangnya dapat mengekalkan kecekapan yang baik Namun, apabila bilangan permintaan meningkat, pangkalan data kerap melakukan satu insert, yang akan menjejaskan kecekapan keseluruhan. perniagaan pesanan. Menjadi lebih rendah (artikel ini hanya menganggap bahawa 1 pesanan = 1 insert) .

Melalui penerangan di atas, sebenarnya mudah untuk memikirkan bidang yang memerlukan pengoptimuman. Analogi dengan adegan menaiki lif dalam kehidupan sebenar: lif diisi dan kemudian naik , yang boleh mengurangkan tekanan orang dengan paling cepat.

Mari kita laksanakan idea kita dengan kod:

<?php

Swoole\Runtime::enableCoroutine($flags = SWOOLE_HOOK_ALL);

// 最大等待次数
const MAX_TIMES = 10;
// 按批处理时, 每一批的最大请求暂留数量
const MAX_REQUEST = 3;
// 服务端最大超时时间, 避免客户端一直等待
const MAX_TIMEOUT = 5;

Co\run(function () {
    // 请求传输的channel, 原因是不要在swoole的协程环境中, 使用多个协程修改同一个全局变量
    // 如果是golang, 当然是可以不定义这里的$rqChannel
    // 只需要简单的将下面的$rqQueue和$times定义为全局变量即可达到一样的效果
    // 但是最好的方式任然是是通过channel共享内存
    $rqChannel = new Swoole\Coroutine\Channel(MAX_REQUEST);

    // 模拟创建订单
    $createOrder = function () use ($rqChannel) {
        // 使用数组模拟请求暂留队列
        $rqQueue = [];
        // 使用等待次数模拟tick效果
        $times = MAX_TIMES;
        while (true) {
            $times--;
            // 必须带上timeout参数, 否则channel是阻塞的
            $rq = $rqChannel->pop(1);
            // 保存1个正常的请求数据
            if (!empty($rq)) {
                $rqQueue[] = $rq;
            }
            // 请求数量未达上限或者还有等待次数时, 提前进入下一次循环
            if ($times > 0 && count($rqQueue) < MAX_REQUEST) {
                continue;
            }
            // 重置等待次数
            $times = MAX_TIMES;
            // 初始化SQL
            $sql = "INSERT INTO orders VALUES ";
            $inserts = [];
            // 模拟数据验证
            $validator = function ($input): bool {
                // 为了缩减代码, 没有真的做数据验证的处理
                array_filter($input);
                return true;
            };
            // $rqQueue在协程上下文是并发安全的, 所以遍历时不用担心
            foreach ($rqQueue as $index => $rq) {
                list($data, $chan) = $rq;
                // 这里可以考虑后置执行, 原因是后面可以有一些补救逻辑
                unset($rqQueue[$index]);
                // 判断$chan是否关闭å
                if ($chan->errCode === SWOOLE_CHANNEL_CLOSED) {
                    $data = null;
                    continue;
                }
                $bool = $validator($data);
                if ($bool) {
                    $inserts[] = "({$data[&#39;user_name&#39;]}, {$data[&#39;amount&#39;]}, {$data[&#39;mobile&#39;]})";
                    $chan->push([&#39;state&#39; => 1]);
                } else {
                    $chan->push([&#39;state&#39; => 0]);
                }
                // unset($rqQueue[$index]);
            }
            $sql .= (implode(&#39;,&#39;, $inserts) . &#39;;&#39;);
            // 模拟创建订单落库的逻辑
            echo $sql;
        }
    };

    // 新手要注意这一句代码的位置, 原因是 $server->start() 之后的代码不会执行
    go($createOrder);

    // 路由处理器
    $orderHandler = function ($rq, $res) use ($rqChannel) {
        $chan = new Swoole\Coroutine\Channel(1);
        // 使用timeout参数模拟超时
        $bool = $rqChannel->push([$rq->post, $chan], MAX_TIMEOUT);
        if (!$bool) {
            // 关闭$chan
            $chan->close();
            $res->end(&#39;timeout&#39;);
        }
        if (!empty($data = $chan->pop())) {
            // 关闭$chan
            $chan->close();
            // 区分成功或失败状态再输出响应
            if ($data[&#39;state&#39;] === 1) {
                $res->end(microtime());
            } else {
                $res->end(&#39;error&#39;);
            }
        }
    };

    $server = new Co\Http\Server("0.0.0.0", 9502, false);

    $server->handle(&#39;/order/create&#39;, $orderHandler);
    // 当前协程容器的终点
    $server->start();
});

Kod secara keseluruhannya masih sangat mudah difahami Pembolehubah$rqQueue adalah serupa dengan permintaan lif dan tahan. Bilangan kali menunggu untuk tempoh masa tertentu $times adalah sama dengan keperluan untuk lif untuk menunggu aliran orang masuk mengikut urutan . Sudah tentu, perkara paling penting yang saya harap pembaca akan ambil perhatian ialah: Dalam persekitaran coroutine, jangan gunakan memori yang dikongsi untuk komunikasi Anda harus menggunakan komunikasi untuk berkongsi memori.

Pembelajaran yang disyorkan: tutorial swole

Atas ialah kandungan terperinci Perkongsian contoh konkurensi tinggi: Swoole melaksanakan perniagaan dengan cekap melalui pengagregatan permintaan. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Kenyataan:
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn