Rhagair
Mae fy ngwefan, yr wyf yn ei rhedeg fel hobi, wedi'i chynllunio i gynnal tudalennau cartref diddorol a gwefannau personol. Dechreuodd y pwnc hwn fy niddori ar ddechrau fy siwrnai raglennu; ar y foment honno cefais fy swyno gan ddod o hyd i weithwyr proffesiynol gwych sy'n ysgrifennu amdanynt eu hunain, eu hobïau a'u prosiectau. Erys yr arferiad o’u darganfod i mi fy hun hyd heddiw: ar bron bob safle masnachol ac nid masnachol iawn, rwy’n parhau i edrych yn y troedyn i chwilio am ddolenni i’r awduron.
Gweithredu'r syniad
Dim ond tudalen html oedd y fersiwn gyntaf ar fy ngwefan bersonol, lle rhoddais ddolenni gyda llofnodion i mewn i restr ul. Wedi teipio 20 tudalen dros gyfnod o amser, dechreuais feddwl nad oedd hyn yn effeithiol iawn a phenderfynais geisio awtomeiddio’r broses. Ar stackoverflow, sylwais fod llawer o bobl yn nodi gwefannau yn eu proffiliau, felly ysgrifennais ddosraniad yn php, a aeth trwy'r proffiliau yn syml, gan ddechrau gyda'r cyntaf (mae'r cyfeiriadau ar SO hyd heddiw fel hyn: `/users/1` ), wedi tynnu dolenni o'r tag a ddymunir a'i ychwanegu yn SQLite.
Gellir galw hwn yn ail fersiwn: casgliad o ddegau o filoedd o URLau mewn tabl SQLite, a ddisodlodd y rhestr statig yn html. Fe wnes i chwiliad syml ar y rhestr hon. Achos dim ond URLs oedd, yna roedd y chwiliad yn syml yn seiliedig arnynt.
Ar y cam hwn, gadewais y prosiect a dychwelyd ato ar ôl amser hir. Ar y cam hwn, roedd fy mhrofiad gwaith eisoes yn fwy na thair blynedd ac roeddwn yn teimlo y gallwn wneud rhywbeth mwy difrifol. Yn ogystal, roedd awydd mawr i feistroli technolegau cymharol newydd.
Fersiwn modern
problem
Mae gwefannau newydd yn cael eu hychwanegu gan orchymyn consol sy'n gwneud y canlynol yn gydamserol:
- Yn lawrlwytho cynnwys yn ôl URL
- Yn gosod baner yn nodi a oedd HTTPS ar gael
- Yn cadw hanfod y wefan
- Mae'r ffynhonnell HTML a'r penawdau yn cael eu cadw yn yr hanes “mynegeio”.
- Dosrannu cynnwys, detholiadau Teitl a Disgrifiad
- Yn cadw data i gasgliad ar wahân
Roedd hyn yn ddigon i storio gwefannau a'u harddangos mewn rhestr:
Ond nid oedd y syniad o fynegeio, categoreiddio a graddio popeth yn awtomatig, gan gadw popeth yn gyfredol, yn cyd-fynd yn dda â'r patrwm hwn. Roedd hyd yn oed ychwanegu dull gwe i ychwanegu tudalennau yn gofyn am ddyblygu cod a blocio er mwyn osgoi DDoS posibl.
Yn gyffredinol, wrth gwrs, gellir gwneud popeth yn gydamserol, ac yn y dull gwe gallwch arbed yr URL fel bod yr ellyll gwrthun yn cyflawni'r holl dasgau ar gyfer yr URLau o'r rhestr. Ond o hyd, hyd yn oed yma mae'r gair “ciw” yn awgrymu ei hun. Ac os gweithredir ciw, yna gellir rhannu'r holl dasgau a'u perfformio yn anghydamserol o leiaf.
penderfyniad
Gweithredu ciwiau a gwneud system a yrrir gan ddigwyddiadau ar gyfer prosesu pob tasg. Ac rydw i wedi bod eisiau rhoi cynnig ar Redis Streams ers amser maith.
Defnyddio ffrydiau Redis yn PHP
Achos Gan nad yw fy fframwaith yn un o'r tri cawr Symfony, Laravel, Yii, hoffwn ddod o hyd i lyfrgell annibynnol. Ond, fel y digwyddodd (ar yr archwiliad cyntaf), mae'n amhosibl dod o hyd i lyfrgelloedd difrifol unigol. Mae popeth sy'n ymwneud â chiwiau naill ai'n brosiect o 3 ymrwymiad bum mlynedd yn ôl, neu'n gysylltiedig â'r fframwaith.
Rwyf wedi clywed llawer am Symfony fel cyflenwr cydrannau defnyddiol unigol, ac rwyf eisoes yn defnyddio rhai ohonynt. A hefyd gellir defnyddio rhai pethau o Laravel hefyd, er enghraifft eu ORM, heb bresenoldeb y fframwaith ei hun.
symffoni/negesydd
Roedd yr ymgeisydd cyntaf yn ymddangos yn ddelfrydol ar unwaith a heb unrhyw amheuaeth fe wnes i ei osod. Ond daeth yn anoddach google enghreifftiau o ddefnydd y tu allan i Symfony. Sut i ymgynnull bws ar gyfer trosglwyddo negeseuon o griw o ddosbarthiadau gydag enwau cyffredinol, diystyr, a hyd yn oed ar Redis?
Roedd y ddogfennaeth ar y safle swyddogol yn eithaf manwl, ond dim ond ar gyfer Symfony y disgrifiwyd y cychwyniad gan ddefnyddio eu hoff YML a dulliau hud eraill ar gyfer y rhai nad ydynt yn symffonydd. Nid oedd gennyf unrhyw ddiddordeb yn y broses osod ei hun, yn enwedig yn ystod gwyliau'r Flwyddyn Newydd. Ond bu'n rhaid i mi wneud hyn am gyfnod annisgwyl o hir.
Nid yw ceisio darganfod sut i gychwyn system gan ddefnyddio ffynonellau Symfony ychwaith y dasg fwyaf dibwys ar gyfer terfyn amser tynn:
Ar ôl ymchwilio i hyn i gyd a cheisio gwneud rhywbeth gyda fy nwylo, deuthum i'r casgliad fy mod yn gwneud rhyw fath o faglau a phenderfynais roi cynnig ar rywbeth arall.
goleuedig/ciw
Daeth i'r amlwg bod y llyfrgell hon wedi'i chlymu'n dynn â seilwaith Laravel a llawer o ddibyniaethau eraill, felly ni threuliais lawer o amser arno: fe'i gosodais, edrychais arno, gwelais y dibyniaethau a'i ddileu.
yiisoft/yii2-ciw
Wel, yma y tybiwyd ar unwaith oddiwrth yr enw, eto, gysylltiad caeth ag Yii2. Roedd yn rhaid i mi ddefnyddio'r llyfrgell hon ac nid oedd yn ddrwg, ond ni feddyliais am y ffaith ei fod yn dibynnu'n llwyr ar Yii2.
Y gweddill
Roedd popeth arall a ddarganfyddais ar GitHub yn brosiectau annibynadwy, hen ffasiwn ac wedi'u gadael heb sêr, ffyrc a nifer fawr o ymrwymiadau.
Dychwelyd i symffoni/negesydd, manylion technegol
Roedd yn rhaid i mi ddarganfod y llyfrgell hon ac, ar ôl treulio mwy o amser, roeddwn i'n gallu. Mae'n troi allan bod popeth yn eithaf cryno a syml. I gychwyn y bws, fe wnes i ffatri fach, oherwydd ... Roeddwn i fod i gael sawl teiars a gyda thrinwyr gwahanol.
Dim ond ychydig o gamau:
- Rydym yn creu trinwyr negeseuon y dylid eu galw'n syml
- Rydyn ni'n eu lapio mewn HandlerDescriptor (dosbarth o'r llyfrgell)
- Rydym yn lapio'r “Disgrifyddion” hyn mewn enghraifft HandlersLocator
- Ychwanegu HandlersLocator at yr enghraifft MessageBus
- Rydyn ni'n trosglwyddo set o `SenderInterface` i SendersLocator, yn fy achos i, achosion o ddosbarthiadau `RedisTransport`, sydd wedi'u ffurfweddu mewn ffordd amlwg
- Ychwanegu SendersLocator at yr enghraifft MessageBus
Mae gan MessageBus ddull `->dispatch()` sy'n edrych i fyny'r trinwyr priodol yn y HandlersLocator ac yn trosglwyddo'r neges iddynt, gan ddefnyddio'r `SenderInterface` cyfatebol i'w hanfon ar y bws (nentydd Redis).
Yn y cyfluniad cynhwysydd (php-di yn yr achos hwn), gellir ffurfweddu'r bwndel cyfan hwn fel hyn:
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);
},
Yma gallwch weld ein bod yn SendersLocator wedi neilltuo “cludiant” gwahanol ar gyfer dwy neges wahanol, ac mae gan bob un ohonynt ei gysylltiad ei hun â'r ffrydiau cyfatebol.
Gwneuthum brosiect demo ar wahân yn arddangos cymhwysiad o dri daemon yn cyfathrebu â'i gilydd gan ddefnyddio'r bws canlynol:
Ond byddaf yn dangos i chi sut y gellir strwythuro defnyddiwr:
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();
Defnyddio'r seilwaith hwn mewn cais
Ar ôl gweithredu'r bws yn fy nghefn, gwahanais gamau unigol o'r hen orchymyn cydamserol a gwneud trinwyr ar wahân, pob un ohonynt yn gwneud eu peth eu hunain.
Roedd yr arfaeth ar gyfer ychwanegu safle newydd at y gronfa ddata yn edrych fel hyn:
Ac yn syth ar ôl hynny, daeth yn llawer haws i mi ychwanegu ymarferoldeb newydd, er enghraifft, echdynnu a dosrannu Rss. Achos mae'r broses hon hefyd yn gofyn am y cynnwys gwreiddiol, yna mae'r triniwr echdynnu cyswllt RSS, fel WebsiteIndexHistoryPersistor, yn tanysgrifio i'r neges “Cynnwys / HtmlContent”, yn ei phrosesu ac yn trosglwyddo'r neges a ddymunir ar hyd ei biblinell ymhellach.
Yn y diwedd, daeth sawl daemon gennym i ben, ac mae pob un ohonynt yn cynnal cysylltiadau â'r adnoddau angenrheidiol yn unig. Er enghraifft cythraul crawlers yn cynnwys yr holl drinwyr sydd angen mynd i'r Rhyngrwyd ar gyfer cynnwys, a'r ellyll dyfal yn dal cysylltiad â'r gronfa ddata.
Nawr, yn lle dewis o'r gronfa ddata, mae'r ids gofynnol ar ôl eu mewnosod gan y persister yn cael eu trosglwyddo'n syml ar y bws i'r holl drinwyr sydd â diddordeb.
Ffynhonnell: hab.com