PHP پس منظر کي ريڊيس اسٽريم بس ڏانهن منتقل ڪرڻ ۽ فريم ورڪ-آزاد لائبريري چونڊڻ

PHP پس منظر کي ريڊيس اسٽريم بس ڏانهن منتقل ڪرڻ ۽ فريم ورڪ-آزاد لائبريري چونڊڻ

اڳوڻي

منهنجي ويب سائيٽ، جنهن کي مان هڪ شوق جي طور تي هلائيان ٿو، دلچسپ گهر صفحن ۽ ذاتي سائيٽن کي ميزباني ڪرڻ لاءِ ٺهيل آهي. اهو موضوع منهنجي پروگرامنگ جي سفر جي شروعات ۾ ئي مون کي دلچسپي ڏيڻ لڳو؛ ان وقت مون کي عظيم پروفيشنل ڳولڻ جو شوق هو، جيڪي پنهنجي باري ۾ لکن ٿا، انهن جي شوق ۽ منصوبن بابت. انهن کي پنهنجي لاءِ دريافت ڪرڻ جي عادت اڄ ڏينهن تائين رهي ٿي: تقريبن هر تجارتي ۽ نه تمام تجارتي سائيٽ تي، مان ليکڪن جي لنڪ جي ڳولا ۾ فوٽر ۾ ڏسندو رهيس.

نظريي تي عمل ڪرڻ

پهريون نسخو منهنجي ذاتي ويب سائيٽ تي صرف هڪ html صفحو هو، جتي مون دستخطن سان لنڪ يو ايل لسٽ ۾ رکيا. 20 صفحن تي ٽائپ ڪرڻ کان پوء، مون سوچڻ شروع ڪيو ته اهو تمام گهڻو اثرائتو نه هو ۽ عمل کي خودڪار ڪرڻ جي ڪوشش ڪرڻ جو فيصلو ڪيو. اسٽيڪ اوور فلو تي، مون ڏٺو ته گھڻا ماڻھو پنھنجي پروفائيل ۾ سائيٽن جي نشاندهي ڪن ٿا، تنھنڪري مون php ۾ ھڪڙو parser لکيو، جيڪو صرف پروفائلز جي ذريعي ويو، پھرين سان شروع ٿئي ٿو (SO تي اڄ تائين ايڊريس ھن طرح آھن: `/users/1` )، مطلوب ٽيگ مان لنڪ ڪڍيا ۽ ان کي SQLite ۾ شامل ڪيو.

اهو ٻيو نسخو سڏيو وڃي ٿو: هڪ SQLite ٽيبل ۾ هزارين URLs جو هڪ مجموعو، جيڪو html ۾ جامد فهرست کي تبديل ڪيو. مون هن لسٽ تي هڪ سادي ڳولا ڪئي. ڇاڪاڻ ته صرف URLs هئا، پوء ڳولا صرف انهن تي ٻڌل هئي.

هن مرحلي تي مون منصوبي کي ڇڏي ڏنو ۽ هڪ ڊگهي وقت کان پوء ان ڏانهن موٽيو. هن مرحلي تي، منهنجو ڪم تجربو اڳ ۾ ئي ٽن سالن کان وڌيڪ هو ۽ مون محسوس ڪيو ته مان ڪجهه وڌيڪ سنجيده ڪري سگهان ٿو. ان کان سواء، اتي هڪ وڏي خواهش هئي ته نسبتا نئين ٽيڪنالاجي ماسٽر ڪرڻ لاء.

جديد نسخو

پروجيڪٽ ڊاڪر ۾ مقرر ڪيل، ڊيٽابيس کي mongoDb ڏانهن منتقل ڪيو ويو، ۽ وڌيڪ تازو، ريڊش شامل ڪيو ويو، جيڪو پهريان صرف ڪيشنگ لاء هو. PHP microframeworks مان هڪ هڪ بنياد طور استعمال ڪيو ويندو آهي.

مسئلو

نيون سائيٽون هڪ ڪنسول ڪمانڊ طرفان شامل ڪيون ويون آهن جيڪي هم وقت سازي سان هيٺيون ڪم ڪن ٿيون:

  • URL ذريعي مواد ڊائون لوڊ ڪريو
  • ھڪ جھنڊو سيٽ ڪري ٿو جيڪو اشارو ڪري ٿو ته ڇا HTTPS موجود ھو
  • ويب سائيٽ جي جوهر کي محفوظ ڪري ٿو
  • ماخذ HTML ۽ هيڊر محفوظ ڪيا ويا آهن "انڊيڪسنگ" جي تاريخ ۾
  • مواد کي پارس ڪري ٿو، عنوان ۽ وضاحت ڪڍي ٿو
  • ڊيٽا کي الڳ جمع ڪرڻ ۾ محفوظ ڪري ٿو

اهو صرف سائيٽن کي ذخيرو ڪرڻ ۽ انهن کي فهرست ۾ ڊسپلي ڪرڻ لاء ڪافي هو.

PHP پس منظر کي ريڊيس اسٽريم بس ڏانهن منتقل ڪرڻ ۽ فريم ورڪ-آزاد لائبريري چونڊڻ

پر هر شيءِ کي پاڻمرادو ترتيب ڏيڻ، درجه بندي ڪرڻ ۽ درجه بندي ڪرڻ جو خيال، هر شيءِ کي تازه ترين رکڻ، هن تمثيل ۾ چڱيءَ طرح نه ٺهيو. جيتوڻيڪ صرف صفحا شامل ڪرڻ لاءِ ويب طريقو شامل ڪرڻ گھربل ڪوڊ نقل ۽ بلاڪ ڪرڻ ممڪن DDoS کان بچڻ لاءِ.

عام طور تي، يقينا، هر شي کي هم وقت سازي سان ٿي سگهي ٿو، ۽ ويب طريقي سان توهان صرف URL کي محفوظ ڪري سگهو ٿا ته جيئن شيطاني ڊيمون فهرست مان URLs لاء سڀني ڪمن کي انجام ڏئي. پر اڃا تائين، هتي لفظ "قطار" پاڻ کي ظاهر ڪري ٿو. ۽ جيڪڏهن هڪ قطار لاڳو ٿئي ٿي، پوء سڀني ڪمن کي ورهائي سگهجي ٿو ۽ گهٽ ۾ گهٽ asynchronously انجام ڏئي سگهجي ٿو.

فيصلو

قطار لاڳو ڪريو ۽ سڀني ڪمن جي پروسيسنگ لاءِ واقعن تي مبني نظام ٺاهيو. ۽ مان ڪوشش ڪرڻ چاهيان ٿو ريڊس اسٽريمز کي گهڻي وقت کان.

PHP ۾ ريڊس اسٽريمز استعمال ڪرڻ

ڇاڪاڻ ته جيئن ته منهنجو فريم ورڪ ٽن ديوين Symfony، Laravel، Yii مان نه آهي، مان هڪ آزاد لائبريري ڳولڻ چاهيان ٿو. پر، جيئن اهو نڪتو (پهرين امتحان تي)، اهو ناممڪن آهي ته انفرادي سنجيده لائبريرين کي ڳولڻ لاء. قطارن سان لاڳاپيل هر شيء يا ته هڪ منصوبو آهي 3 ڪمن کان پنج سال اڳ، يا فريم ورڪ سان ڳنڍيل آهي.

مون سمفوني جي باري ۾ گهڻو ٻڌو آهي انفرادي مفيد اجزاء جي سپلائر جي طور تي، ۽ مان پهريان ئي انهن مان ڪجهه استعمال ڪريان ٿو. ۽ پڻ Laravel کان ڪجھ شيون پڻ استعمال ڪري سگھجن ٿيون، مثال طور انھن جي ORM، فريم ورڪ جي موجودگي کان سواء.

سمفوني/ميسينجر

پهريون اميدوار فوري طور تي مثالي محسوس ٿيو ۽ بغير ڪنهن شڪ جي مون ان کي نصب ڪيو. پر اهو وڌيڪ ڏکيو ٿي ويو گوگل مثالن جي استعمال جي Symfony کان ٻاهر. ڪلاسن جي هڪ گروپ مان پيغام موڪلڻ لاءِ بس ڪيئن گڏ ڪجي آفاقي، بي معنيٰ نالن سان، ۽ ريڊس تي به؟

PHP پس منظر کي ريڊيس اسٽريم بس ڏانهن منتقل ڪرڻ ۽ فريم ورڪ-آزاد لائبريري چونڊڻ

سرڪاري سائيٽ تي دستاويز ڪافي تفصيلي هئي، پر شروعات صرف سمفوني لاء بيان ڪئي وئي هئي انهن جي پسنديده YML ۽ ٻين جادو طريقن کي استعمال ڪندي غير سمفونسٽ لاء. مون کي انسٽاليشن جي عمل ۾ ڪا به دلچسپي نه هئي، خاص طور تي نئين سال جي موڪلن دوران. پر مون کي اهو هڪ غير متوقع طور تي ڊگهي وقت تائين ڪرڻو پيو.

اهو معلوم ڪرڻ جي ڪوشش ڪري ته سمفوني ذريعن کي استعمال ڪندي هڪ سسٽم کي ڪيئن شروع ڪيو وڃي سخت آخري وقت لاءِ تمام معمولي ڪم نه آهي:

PHP پس منظر کي ريڊيس اسٽريم بس ڏانهن منتقل ڪرڻ ۽ فريم ورڪ-آزاد لائبريري چونڊڻ

انهن سڀني ڳالهين تي غور ڪرڻ ۽ پنهنجن هٿن سان ڪجهه ڪرڻ جي ڪوشش ڪرڻ کان پوءِ، مان انهيءَ نتيجي تي پهتو آهيان ته مان ڪنهن قسم جي بيچيني ڪري رهيو آهيان ۽ ٻيو ڪجهه ڪرڻ جو فيصلو ڪيو اٿم.

روشني / قطار

اهو ظاهر ٿيو ته هي لائبريري مضبوط طور تي Laravel انفراسٽرڪچر ۽ ٻين انحصار جي هڪ گروپ سان ڳنڍيل هئي، تنهنڪري مون ان تي گهڻو وقت نه گذاريو: مون ان کي نصب ڪيو، ان کي ڏٺو، انحصار ڏٺو ۽ ان کي ختم ڪيو.

yiisoft/yii2-قطار

خير، هتي اهو فوري طور تي نالو مان ورتو ويو، ٻيهر، Yii2 سان سخت ڪنيڪشن. مون کي هن لائبريري کي استعمال ڪرڻو پيو ۽ اهو خراب نه هو، پر مون ان حقيقت جي باري ۾ نه سوچيو ته اهو مڪمل طور تي Yii2 تي منحصر آهي.

آرام

ٻيو سڀ ڪجهه جيڪو مون GitHub تي مليو اهي ناقابل اعتبار، پراڻي ۽ ختم ٿيل منصوبا هئا بغير ستارن، ڪانٽن ۽ وڏي تعداد ۾ ڪميٽ.

symfony/messenger ڏانھن واپس وڃو، ٽيڪنيڪل تفصيل

مون کي هن لائبريريءَ جو پتو لڳائڻو هو ۽، ڪجهه وڌيڪ وقت گذارڻ کان پوءِ، مان ان قابل ٿيس. اهو ظاهر ٿيو ته هر شيء بلڪل جامع ۽ سادي هئي. بس شروع ڪرڻ لاءِ، مون هڪ ننڍڙو ڪارخانو ٺاهيو، ڇاڪاڻ ته... مون کي ڪيترن ئي ٽائر ۽ مختلف هينڊلر سان گڏ هجڻ گهرجي.

PHP پس منظر کي ريڊيس اسٽريم بس ڏانهن منتقل ڪرڻ ۽ فريم ورڪ-آزاد لائبريري چونڊڻ

صرف چند قدم:

  • اسان ميسيج هينڊلر ٺاهيندا آهيون جيڪي صرف ڪالبل هجڻ گهرجن
  • اسان انهن کي HandlerDescriptor ۾ لپيندا آهيون (لائبريري مان ڪلاس)
  • اسان انهن ”تفصيل ڪندڙن“ کي HandlersLocator مثال ۾ لپيندا آهيون
  • شامل ڪرڻ HandlersLocator کي MessageBus مثال ۾
  • اسان 'SenderInterface' جو هڪ سيٽ SendersLocator ڏانهن منتقل ڪريون ٿا، منهنجي صورت ۾ 'RedisTransport' ڪلاس جا مثال، جيڪي واضح طريقي سان ترتيب ڏنل آهن.
  • MessageBus مثال ۾ SendersLocator شامل ڪرڻ

MessageBus وٽ هڪ `->dispatch()` طريقو آهي جيڪو HandlersLocator ۾ مناسب هينڊلر ڳولي ٿو ۽ انهن ڏانهن پيغام موڪلي ٿو، لاڳاپيل `SenderInterface` استعمال ڪندي بس ذريعي موڪلڻ لاءِ (ريڊيس اسٽريمز).

ڪنٽينر جي ترتيب ۾ (هن صورت ۾ php-di)، هي سڄو بنڊل هن طرح ترتيب ڏئي سگهجي ٿو:

        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);
        },

هتي توهان ڏسي سگهو ٿا ته SendersLocator ۾ اسان ٻن مختلف پيغامن لاءِ مختلف ”ٽرانسپورٽ“ تفويض ڪيا آهن، جن مان هر هڪ جو تعلق لاڳاپيل سلسلو سان آهي.

مون هڪ الڳ ڊيمو پروجيڪٽ ٺاهيو جيڪو ٽن ڊيمن جي ايپليڪيشن کي ڏيکاري ٿو جيڪو هيٺ ڏنل بس استعمال ڪندي هڪ ٻئي سان رابطو ڪري ٿو: https://github.com/backend-university/products/tree/master/products/02-redis-streams-bus.

پر مان توهان کي ڏيکاريندس ته هڪ صارف ڪيئن ترتيب ڏئي سگهجي ٿو:

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();

ايپليڪيشن ۾ هن انفراسٽرڪچر کي استعمال ڪندي

منهنجي پس منظر ۾ بس کي لاڳو ڪرڻ سان، مون انفرادي مرحلن کي پراڻي هم وقت سازي ڪمانڊ کان الڳ ڪيو ۽ الڳ هينڊلر ٺاهيا، جن مان هر هڪ پنهنجو ڪم ڪندو آهي.

ڊيٽابيس ۾ نئين سائيٽ شامل ڪرڻ لاءِ پائپ لائن هن طرح نظر آئي:

PHP پس منظر کي ريڊيس اسٽريم بس ڏانهن منتقل ڪرڻ ۽ فريم ورڪ-آزاد لائبريري چونڊڻ

۽ ان کان پوءِ فوري طور تي، منهنجي لاءِ نئين ڪارڪردگي شامل ڪرڻ تمام آسان ٿي ويو، مثال طور، Rss کي ڪڍڻ ۽ پارس ڪرڻ. ڇاڪاڻ ته هن عمل کي اصل مواد جي به ضرورت آهي، پوءِ آر ايس ايس لنڪ ڪڍڻ وارو هينڊلر، جهڙوڪ WebsiteIndexHistoryPersistor، "Content/HtmlContent" پيغام جي رڪنيت حاصل ڪري ٿو، ان کي پروسيس ڪري ٿو ۽ گهربل پيغام کي ان جي پائپ لائن سان اڳتي منتقل ڪري ٿو.

PHP پس منظر کي ريڊيس اسٽريم بس ڏانهن منتقل ڪرڻ ۽ فريم ورڪ-آزاد لائبريري چونڊڻ

آخر ۾، اسان ڪيترن ئي ڊيمن سان ختم ڪيو، جن مان هر هڪ صرف ضروري وسيلن سان ڪنيڪشن برقرار رکي ٿو. مثال طور هڪ شيطان ڪرلر سڀني ھينڊلرن تي مشتمل آھي جن کي مواد لاءِ انٽرنيٽ ڏانھن وڃڻ جي ضرورت آھي، ۽ ڊيمون قائم رهڻ ڊيٽابيس سان ڪنيڪشن رکي ٿو.

ھاڻي، ڊيٽابيس مان چونڊڻ جي بدران، پرزيسٽر پاران داخل ٿيڻ کان پوءِ گهربل آئي ڊيز بس ذريعي سڀني دلچسپي رکندڙ ھينڊلر ڏانھن منتقل ڪيون وينديون آھن.

جو ذريعو: www.habr.com

تبصرو شامل ڪريو