Nransfer backend PHP menyang bus streams Redis lan milih perpustakaan framework-independen

Nransfer backend PHP menyang bus streams Redis lan milih perpustakaan framework-independen

Pambuka

Situs webku, sing dadi hobi, dirancang kanggo dadi tuan rumah kaca ngarep lan situs pribadi sing menarik. Topik iki wiwit narik minat aku ing wiwitan perjalanan programku; ing wektu iku aku kepincut nemokake profesional sing apik sing nulis babagan awake dhewe, hobi lan proyeke. Kebiasaan nemokake dhewe nganti saiki: ing meh kabeh situs komersial lan ora komersial, aku terus nggoleki ing footer kanggo nggoleki pranala menyang penulis.

Implementasi gagasan

Versi pisanan mung kaca html ing situs web pribadi, ing ngendi aku sijine pranala karo teken menyang dhaftar ul. Sawise ngetik 20 kaca sajrone sawetara wektu, aku wiwit mikir yen iki ora efektif banget lan mutusake kanggo nyoba ngotomatisasi proses kasebut. Ing stackoverflow, aku ngerteni manawa akeh wong sing nuduhake situs ing profil, mula aku nulis parser ing php, sing mung ngliwati profil, diwiwiti kanthi sing pertama (alamat ing SO nganti saiki kaya iki: `/users/1` ), ngekstrak pranala saka tag sing dikarepake lan ditambahake ing SQLite.

Iki bisa diarani versi kapindho: koleksi puluhan ewu URL ing tabel SQLite, sing ngganti dhaptar statis ing html. Aku nggoleki prasaja ing dhaptar iki. Amarga mung ana URL, banjur telusuran mung adhedhasar.

Ing tataran iki aku nilar project lan bali menyang sawise dangu. Ing tahap iki, pengalaman kerjaku wis luwih saka telung taun lan aku rumangsa bisa nindakake perkara sing luwih serius. Kajaba iku, ana kepinginan gedhe kanggo nguwasani teknologi sing relatif anyar.

Versi modern

Proyek kasebut disebarake ing Docker, database ditransfer menyang mongoDb, lan luwih anyar, lobak ditambahake, sing pisanan mung kanggo caching. Salah sawijining microframework PHP digunakake minangka basis.

masalah

Situs anyar ditambahake dening printah console sing sinkron nindakake ing ngisor iki:

  • Ngundhuh konten kanthi URL
  • Nyetel gendera sing nuduhake manawa HTTPS kasedhiya
  • Ngreksa inti saka website
  • HTML lan header sumber disimpen ing riwayat "indeksasi".
  • Parses isi, extract Judhul lan Deskripsi
  • Nyimpen data menyang koleksi kapisah

Iki cukup kanggo nyimpen situs lan nampilake ing dhaptar:

Nransfer backend PHP menyang bus streams Redis lan milih perpustakaan framework-independen

Nanging gagasan ngindeks, nggolongake lan peringkat kabeh kanthi otomatis, supaya kabeh tetep anyar, ora cocog karo paradigma iki. Malah mung nambah cara web kanggo nambah kaca sing dibutuhake duplikasi kode lan pamblokiran kanggo ngindhari DDoS potensial.

UmumΓ©, mesthi, kabeh bisa ditindakake kanthi sinkron, lan ing metode web sampeyan mung bisa nyimpen URL supaya daemon monstrous nindakake kabeh tugas kanggo URL saka dhaptar. Nanging isih, malah ing kene tembung "antrean" nyaranake dhewe. Lan yen antrian dileksanakake, kabeh tugas bisa dipΓ©rang lan dileksanakake paling ora sinkron.

kaputusan

Ngleksanakake antrian lan nggawe sistem acara-mimpin kanggo proses kabeh tugas. Lan aku wis pengin nyoba Redis Streams kanggo dangu.

Nggunakake aliran Redis ing PHP

Amarga Amarga kerangkaku dudu salah siji saka telung raksasa Symfony, Laravel, Yii, aku pengin golek perpustakaan mandiri. Nanging, minangka ternyata (ing ujian pisanan), iku mokal kanggo nemokake perpustakaan serius individu. Kabeh sing ana gandhengane karo antrian yaiku proyek saka 3 sing ditindakake limang taun kepungkur, utawa diikat karo kerangka kasebut.

Aku wis krungu akeh babagan Symfony minangka supplier komponen migunani individu, lan aku wis nggunakake sawetara. Lan uga sawetara perkara saka Laravel uga bisa digunakake, umpamane ORM, tanpa anane kerangka kasebut.

symfony / utusan

Calon pisanan langsung katon becik lan tanpa mangu aku nginstal. Nanging dadi luwih angel kanggo google conto panggunaan ing njaba Symfony. Kepiye carane ngumpul saka pirang-pirang kelas kanthi jeneng universal sing ora ana gunane, bis kanggo ngirim pesen, lan uga ing Redis?

Nransfer backend PHP menyang bus streams Redis lan milih perpustakaan framework-independen

Dokumentasi ing situs resmi cukup rinci, nanging initialization mung diterangake kanggo Symfony nggunakake YML favorit lan cara sihir liyane kanggo non-symphonist. Aku ora kapentingan ing proses instalasi dhewe, utamanΓ© sak preian Taun Anyar. Nanging aku kudu nindakake iki kanggo wektu sing ora dinyana-nyana.

Nyoba kanggo mangerteni carane instantiate sistem nggunakake sumber Symfony uga dudu tugas sing paling sepele kanggo tenggat wektu sing ketat:

Nransfer backend PHP menyang bus streams Redis lan milih perpustakaan framework-independen

Sawise delving menyang kabeh iki lan nyoba kanggo nindakake soko karo tangan, Aku teka menyang kesimpulan sing aku mengkono sawetara jenis crutches lan mutusakΓ© kanggo nyoba mergo.

padhang / antrian

Ternyata perpustakaan iki diikat banget karo infrastruktur Laravel lan akeh dependensi liyane, mula aku ora ngentekake wektu akeh: Aku nginstal, ndeleng, ndeleng dependensi lan mbusak.

yiisoft / yii2-antrean

Inggih, kene langsung dianggep saka jeneng, maneh, sambungan ketat kanggo Yii2. Aku kudu nggunakake perpustakaan iki lan iku ora ala, nanging aku ora mikir bab kasunyatan sing rampung gumantung ing Yii2.

Liyane

Kabeh liyane sing ditemokake ing GitHub minangka proyek sing ora bisa dipercaya, ketinggalan jaman lan ditinggal tanpa lintang, garpu lan akeh komitmen.

Bali menyang symfony / messenger, rincian teknis

Aku kudu ngerteni perpustakaan iki lan, sawise mbuwang sawetara wektu, aku bisa. Pranyata kabeh iku cukup ringkes lan prasaja. Kanggo nggawe bis, aku nggawe pabrik cilik, amarga ... Aku mestine duwe sawetara ban lan karo pawang beda.

Nransfer backend PHP menyang bus streams Redis lan milih perpustakaan framework-independen

Mung sawetara langkah:

  • Kita nggawe pawang pesen sing mung bisa ditelpon
  • Kita mbungkus ing HandlerDescriptor (kelas saka perpustakaan)
  • Kita mbungkus "Deskriptor" iki ing conto HandlersLocator
  • Nambahake HandlersLocator menyang conto MessageBus
  • Kita ngirim set `SenderInterface` menyang SendersLocator, ing kasusku, kelas `RedisTransport`, sing dikonfigurasi kanthi jelas.
  • Nambahake SendersLocator menyang conto MessageBus

MessageBus duwe `-> dispatch ()` cara sing katon munggah handler cocok ing HandlersLocator lan ngirim pesen kanggo wong-wong mau, nggunakake cocog `SenderInterface` kanggo ngirim liwat bis (Redis stream).

Ing konfigurasi wadhah (ing kasus iki php-di), kabeh bundel iki bisa dikonfigurasi kaya iki:

        CONTAINER_REDIS_TRANSPORT_SECRET => function (ContainerInterface $c) {
            return new RedisTransport(
                $c->get(CONTAINER_REDIS_STREAM_CONNECTION_SECRET),
                $c->get(CONTAINER_SERIALIZER))
            ;
        },
        CONTAINER_REDIS_TRANSPORT_LOG => function (ContainerInterface $c) {
            return new RedisTransport(
                $c->get(CONTAINER_REDIS_STREAM_CONNECTION_LOG),
                $c->get(CONTAINER_SERIALIZER))
            ;
        },
        CONTAINER_REDIS_STREAM_RECEIVER_SECRET => function (ContainerInterface $c) {
            return new RedisReceiver(
                $c->get(CONTAINER_REDIS_STREAM_CONNECTION_SECRET),
                $c->get(CONTAINER_SERIALIZER)
            );
        },
        CONTAINER_REDIS_STREAM_RECEIVER_LOG => function (ContainerInterface $c) {
            return new RedisReceiver(
                $c->get(CONTAINER_REDIS_STREAM_CONNECTION_LOG),
                $c->get(CONTAINER_SERIALIZER)
            );
        },
        CONTAINER_REDIS_STREAM_BUS => function (ContainerInterface $c) {
            $sendersLocator = new SendersLocator([
                AppMessagesSecretJsonMessages::class => [CONTAINER_REDIS_TRANSPORT_SECRET],
                AppMessagesDaemonLogMessage::class => [CONTAINER_REDIS_TRANSPORT_LOG],
            ], $c);
            $middleware[] = new SendMessageMiddleware($sendersLocator);

            return new MessageBus($middleware);
        },
        CONTAINER_REDIS_STREAM_CONNECTION_SECRET => function (ContainerInterface $c) {
            $host = 'bu-02-redis';
            $port = 6379;
            $dsn = "redis://$host:$port";
            $options = [
                'stream' => 'secret',
                'group' => 'default',
                'consumer' => 'default',
            ];

            return Connection::fromDsn($dsn, $options);
        },
        CONTAINER_REDIS_STREAM_CONNECTION_LOG => function (ContainerInterface $c) {
            $host = 'bu-02-redis';
            $port = 6379;
            $dsn = "redis://$host:$port";
            $options = [
                'stream' => 'log',
                'group' => 'default',
                'consumer' => 'default',
            ];

            return Connection::fromDsn($dsn, $options);
        },

Ing kene sampeyan bisa ndeleng manawa ing SendersLocator wis menehi "transportasi" sing beda kanggo rong pesen sing beda-beda, sing saben duwe sambungan dhewe menyang aliran sing cocog.

Aku nggawe proyek demo kapisah sing nuduhake aplikasi telung daemon sing sesambungan karo bus ing ngisor iki: https://github.com/backend-university/products/tree/master/products/02-redis-streams-bus.

Nanging aku bakal nuduhake sampeyan carane konsumen bisa disusun:

use AppMessagesDaemonLogMessage;
use SymfonyComponentMessengerHandlerHandlerDescriptor;
use SymfonyComponentMessengerHandlerHandlersLocator;
use SymfonyComponentMessengerMessageBus;
use SymfonyComponentMessengerMiddlewareHandleMessageMiddleware;
use SymfonyComponentMessengerMiddlewareSendMessageMiddleware;
use SymfonyComponentMessengerTransportSenderSendersLocator;

require_once __DIR__ . '/../vendor/autoload.php';
/** @var PsrContainerContainerInterface $container */
$container = require_once('config/container.php');

$handlers = [
    DaemonLogMessage::class => [
        new HandlerDescriptor(
            function (DaemonLogMessage $m) {
                error_log('DaemonLogHandler: message handled: / ' . $m->getMessage());
            },
            ['from_transport' => CONTAINER_REDIS_TRANSPORT_LOG]
        )
    ],
];
$middleware = [];
$middleware[] = new HandleMessageMiddleware(new HandlersLocator($handlers));
$sendersLocator = new SendersLocator(['*' => [CONTAINER_REDIS_TRANSPORT_LOG]], $container);
$middleware[] = new SendMessageMiddleware($sendersLocator);

$bus = new MessageBus($middleware);
$receivers = [
    CONTAINER_REDIS_TRANSPORT_LOG => $container->get(CONTAINER_REDIS_STREAM_RECEIVER_LOG),
];
$w = new SymfonyComponentMessengerWorker($receivers, $bus, $container->get(CONTAINER_EVENT_DISPATCHER));
$w->run();

Nggunakake infrastruktur iki ing aplikasi

Sawise ngetrapake bis ing mburiku, aku misahake tahapan individu saka perintah sinkron sing lawas lan nggawe pawang sing kapisah, sing saben-saben nindakake dhewe-dhewe.

Pipa kanggo nambah situs anyar menyang database katon kaya iki:

Nransfer backend PHP menyang bus streams Redis lan milih perpustakaan framework-independen

Lan sanalika sawise iku, aku dadi luwih gampang kanggo nambah fungsi anyar, contone, extracting lan parsing Rss. Amarga proses iki uga mbutuhake isi asli, banjur RSS link extractor handler, kaya WebsiteIndexHistoryPersistor, langganan pesen "Konten / HtmlContent", proses lan ngirim pesen sing dipengini bebarengan pipeline luwih.

Nransfer backend PHP menyang bus streams Redis lan milih perpustakaan framework-independen

Pungkasane, kita rampung karo sawetara daemon, sing saben-saben njaga sambungan mung menyang sumber daya sing dibutuhake. Contone setan CRAWLERS ngemot kabeh pawang sing mbutuhake menyang Internet kanggo isi, lan daemon tetep ngemu sambungan menyang database.

Saiki, tinimbang milih saka database, id sing dibutuhake sawise dilebokake dening persister mung dikirim liwat bis menyang kabeh pawang sing kasengsem.

Source: www.habr.com

Add a comment