SlideShare une entreprise Scribd logo
1  sur  49
Télécharger pour lire hors ligne
Intro
Lifestory:
Production monolith
migration to Swoole!
● What existing problems need to solve?
● Why choose Swoole?
● How solve it with Swoole?
● What unexpected troubles could happens?
● Show methods to avoid then (or not?)
● Talk about theory
● Examples in a context of a real project
Intro
Side Effects of
- PHP no dying (long-lived)
- Concurrency Async
- Shared Memory access
Intro
● ZF2 / Laminas / Mezzio / PSR-15 / ..
● PHP 5.6 -> … -> 7.4 --> 8.0 + swoole
● PostgreSQL / ElasticSearch Typesense / Redis / RabbitMQ / PubSub
● Docker / k8s / autoscale / Google Cloud
● Files: 2.5k, LOC: 200k, LLOC: 30k
Intro. About project
Intro. About project
Current AVG metrics:
- GA online users: ~3500
- API RPS: ~200
- DB transactions: ~3000/sec
- Products count: ~25kk
Consuming resources:
- PHP: 60 vCPU
- ElasticSearch: 40 vCPU
- PostgreSQL: 16 vCPU
- Others: 20 vCPU
● Not optimized resources usage.
● Hard tuning horizontal scale.
● Over-complicated infrastructure
● Not well performance (TTFB)
Why? Problems
Database
PHP PHP
PHP PHP
Elastic Elastic
Elastic
Other
4x times
● Not optimized resources usage.
● Hard tuning horizontal scale.
● Over-complicated infrastructure
● Not well performance (TTFB)
Why? Problems
PHP
4 vCPU
PHP
16 vCPU
VS
● Not optimized resources usage.
● Hard tuning horizontal scale.
● Over-complicated infrastructure
● Not well performance (TTFB)
Why? Problems
Docker, k8s, Terraform, Helm, GitHub
Actions, Envs: prod+stage+devs+local, Go,
Typescript
● Not optimized resources usage.
● Hard tuning horizontal scale.
● Over-complicated infrastructure
● Not well performance (TTFB)
Why? Problems
● ASYNC entire ecosystem
● Performance
● Easy to start
- Coroutine based concurrent asynchronous IO
- Event Loop
- Process management
- In-memory storage and management
- Async TCP/UDP/HTTP/WebSocket/HTTP2/FastCGI client
and servers
- Async Task API
- Channels, Locks, Timer, Scheduler
NO PECL: ext-pcntl, ext-pthreads, ext-event
Why Swoole?
Milestone 1: PHP no die
● Run HTTP Server
○ replace NGINX+FPM
○ simplify infrastructure (less DevOps, easy building & k8s configs)
○ change (unified) operations: CI / CD / local env
● Prepare bootstrap
● Implement best practices in shared memory usage to avoid side-effects
Plan
● Server Mode: SWOOLE_PROCESS / SWOOLE_BASE
● Dispatch Mode: 1-9 (Round-Robin, Fixed, Preemptive, etc)
● Worker Num: 1-1000 (CPU*2)
● Max Request: 0-XXX (0)
Other Options: Limits, Timeouts, Memory buffers...
php bin/http-server.php
Swoole HTTP Server
https://www.swoole.co.uk/docs/modules/swoole-server/configuration
MUST SEE:
<?php
$server = new SwooleHTTPServer("127.0.0.1", 9501);
$server->on('Request', function(Swoole/Server/Request $request, Swoole/Server/Response $response)
{
$response->end('<h1>Hello World!</h1>');
});
$server->start();
● Scan config files, env, run reflection, attributes, build DI, generate proxy, warm caches:
● NO NEED cache layer anymore
● NOW it before real start http server
(if no traffic: readiness probe=negative)
PSR-7 HTTP Messages
PSR-15 Middleware
PSR-11 Container
bootstrap in master
http request in worker process
Bootstrap app once
fork state
What are the problems?
- NO SUPER GLOBALS ($_SERVER, ...)
- No PHP Session (it is CLI SAPI)
- Stateful services that should mutate on each request
- DI containers - global state too.
Shared Memory
Any wrong example?
Shared Memory
https://github.com/chrisguitarguy/RequestIdBundle/blob/main/src/EventListener/RequestIdListener.php
public function onRequest(RequestEvent $event) : void
{
if (!$this->isMainRequest ($event)) {
return;
}
$req = $event->getRequest();
if ($this->trustRequest && ($id = $req->headers->get($this->requestHeader )))
{
$this->idStorage->setRequestId ($id);
return;
}
if ($id = $this->idStorage->getRequestId ()) {
$req->headers->set($this->requestHeader , $id);
return;
}
$id = $this->idGenerator ->generate();
$req->headers->set($this->requestHeader , $id);
$this->idStorage->setRequestId ($id);
}
Empty storage - no return
Generate NEW
Saving to storage
1
HTTP REQUEST:
Any wrong example?
Shared Memory
public function onRequest(RequestEvent $event) : void
{
if (!$this->isMainRequest ($event)) {
return;
}
$req = $event->getRequest();
if ($this->trustRequest && ($id = $req->headers->get($this->requestHeader )))
{
$this->idStorage->setRequestId ($id);
return;
}
if ($id = $this->idStorage->getRequestId ()) {
$req->headers->set($this->requestHeader , $id);
return;
}
$id = $this->idGenerator ->generate();
$req->headers->set($this->requestHeader , $id);
$this->idStorage->setRequestId ($id);
}
2
HTTP REQUEST:
Now has ID in storage
THE END
Dead code
https://github.com/chrisguitarguy/RequestIdBundle/blob/main/src/EventListener/RequestIdListener.php
Shared Memory
HTTP Server options:
Max Request: 100
What if...
Then…
In logs request ID is changed.
Best practices:
- Middlewares, Factories, Proxies, Delegators
Shared Memory
use PsrHttpMessageResponseInterface
;
use PsrHttpMessageServerRequestInterface
;
use PsrHttpServerRequestHandlerInterface
;
use PsrLogLoggerInterface
;
class SomeHandler implements RequestHandlerInterface
{
public function __construct(
private Closure $appServiceFactory
,
private LoggerInterface $logger
) {}
// Idempotent method!!!
public function handle(ServerRequestInterface $request) : ResponseInterface
{
$logger = clone $this->logger;
$logger->getProcessor(
'RequestID')->setRequestId(
$request->getAttribute(
'RequestID'));
$appService = ($this->appServiceFactory)(
$logger);
return new JsonResponse($appService->createBook())
;
}
}
Memory leaks
… in Doctrine ORM :(
Shared Memory
https://alejandrocelaya.blog/2019/11/04/how-to-properly-handle-a-doctrine-entity-manager-on-an-expressive-appli
cation-served-with-swoole/
use DoctrineORMDecoratorEntityManagerDecorator as
EMD;
class ReopeningEntityManager extends EMD
{
private $createEm;
public function __construct (callable $createEm)
{
parent::__construct($createEm());
$this->createEm = $createEm;
}
public function open(): void
{
if (! $this->wrapped->isOpen()) {
$this->wrapped = ($this->createEm)();
}
}
class CloseDbConnectionMiddleware implements
MiddlewareInterface
{
public function __construct(
private ReopeningEntityManager $em)
{}
public function process(
ServerRequestInterface $request,
RequestHandlerInterface $handler
) : ResponseInterface
{
$this->em->open() ;
try {
return $handler->handle($request);
} finally {
$this->em->getConnection()->close() ;
$this->em->clear() ;
}
}
}
Saved in DI
Shared Memory
Memory leaks
BUT WHERE???
abstract class EntityManagerDecorator extends
ObjectManagerDecorator
{
/** @var EntityManagerInterface */
protected $wrapped;
public function __construct (EntityManagerInterface $wrapped)
{
$this->wrapped = $wrapped;
}
public function getRepository ($className)
{
return $this->wrapped->getRepository ($className);
}
public function getRepository ($entityName )
{
return $this->repositoryFactory ->getRepository ($this,
$entityName );
}
Somewhere far far away
in EntityManager
PROBLEMS DUE TO: timeouts / lifecycles
Avoid: Stateful convert to stateless
Connections
$redis = $di->get(Redis::class); // FactoryRedis: $redis->connect(...);
$redis->get('KEY1');
$redisFactory = $di->get(RedisFactory::
class);
$redisFactory()->get(‘KEY1’); // + close connect in desctructor
Request Wrapper/Delegator:
new/refresh state on each request
OR
Milestone 2: ASYNC
● Async theory
● Using coroutines
● Non-blocked IO solutions
● Concurrency problems review
● Again memory leaks
● GET /some/action1/ SELECT sleep(1);
○ 1 worker = 1 req/sec
○ 2 worker = 2 req/sec
● GET /some/action2/ fibonacci(30);
○ 1 worker = 1 req/sec
○ 2 worker = depends on CPU cores
Why/What async?
Try benchmark this:
● GET /some/action1/ SELECT sleep(1);
○ 1 worker = 1 req/sec
○ 2 worker = 2 req/sec
● GET /some/action2/ fibonacci(30);
○ 1 worker = 1 req/sec
○ 2 worker = depends on CPU cores
MIX 50/50 = 1 req/sec
50% CPU
Why/What async?
Try benchmark this:
Now enable coroutines: http server options: .
'enable_coroutine' => true,
Why/What async?
● GET /some/action1/
○ 1 worker = 10000 req/sec
○ 2 worker = 10000 req/sec
● GET /some/action2/
○ 1 worker = 1 req/sec
○ 2 worker = depends on CPU cores
Now enable coroutines: http server options: .
'enable_coroutine' => true,
Why/What async?
● GET /some/action1/
○ 1 worker = 10000 req/sec
○ 2 worker = 10000 req/sec
● GET /some/action2/
○ 1 worker = 1 req/sec
○ 2 worker = depends on CPU cores
MIX 50/50 = 2 req/sec
100% CPU
go(function () { // FIRST CO
echo '1';
go(function () { // SECOND CO
echo '2';
co::sleep(3); // IO (in 2 CO), will return in 3 sec
echo '6';
go(function () { // THIRD CO
echo '7';
co::sleep(2); // IO
echo "9n";
}); // END THIRD
echo '8';
}); // END SECOND
echo '3';
co::sleep(1); // Again IO but in 1 CO
echo '5';
}); // END FIRST CO
echo '4';
Coroutines
1
2
3
4
5
Coroutines
https://www.swoole.co.uk/docs/modules/swoole-runtime-flags
Swoole Hooks
Coroutine Clients:
● TCP/UDP
● HTTP
● HTTP2
● Socket
● FastCGI
● Redis
● MySQL
● Postgresql
Runtime HOOKS:
● Coroutine support (any IO libraries based on php_stream):
○ Redis (phpredis) or (predis)
○ MySQL (mysqlnd) PDO and MySQLi
○ PHP SOAP
○ file_get_contents, fopen and many more file I/O operations
○ stream_socket_client functions
○ fsockopen
○ CURL with libcurl
● Libraries without coroutine support:
○ MySQL with libmysqlclient
○ MongoDB with mongo-c-client
○ pdo_pgsql, pdo_ori, pdo_odbc, pdo_firebird, php-amqp
VS
Non-blocked IO
$swooleServer->onRequest: go($this->requestHandler);
--------------------------------------------------------------------------
non-blocked: multiple requests in same time/code
Concurrency
function onRequest() {
$class = $di->get(stdClass:class);
if ($class->some === null) {
$class->some = 123;
}
sleep(2);
// && some logic
$class->some = null;
}
First request awaiting here
We expected clean in request end
http server options: .
'enable_coroutine' => true,
$swooleServer->onRequest: go($this->requestHandler);
--------------------------------------------------------------------------
non-blocked: multiple requests in same time/code
Concurrency
function onRequest() {
$class = $di->get(stdClass:class);
if ($class->some === null) {
$class->some = 123;
}
sleep(2);
// && some logic
$class->some = null;
}
First request awaiting here
We expected clean in request end
EPIC FAIL! in second request
http server options: .
'enable_coroutine' => true,
Request Wrapper/Delegator: new/refresh state on each request
Uncaught SwooleError: Socket# has already been
bound to another coroutine
Connections. Again?
$http = new SwooleHttpServer( '0.0.0.0', '80', SWOOLE_PROCESS) ;
$http->on('request', function (SwooleHttpRequest $request, SwooleHttpResponse $response)
{
if (empty($redis)) {
$redis = new Redis();
$redis->connect('127.0.0.1' , 6379);
$redis->select(1);
$redis->setOption(Redis::OPT_SERIALIZER , Redis::SERIALIZER_PHP) ;
}
try {
$redisJson = $redis->get('key');
} catch (Exception $e) {
// SWOOLE ERROR HERE !
}
$response->end('some response' );
});
https://www.swoole.co.uk/docs/modules/redis-connection-pool
Connections. Again?
POOL
Connections. Again?
use
DoctrineCommonCacheCacheProvider ;
use Redis;
use SwooleDatabaseRedisPool ;
class SwooleRedisCacheProvider extends
CacheProvider
{
public function __construct (
private RedisPool $pool,
) {
}
protected function doFetch($id, ?Redis $redis = null)
{
if (! $redis) {
return $this->run(fn (Redis $redis) : mixed =>
. $this->doFetch($id, $redis));
}
return $redis->get($id);
}
private function run(callable $procedure)
{
$redis = $this->pool->get();
$redis->setOption(Redis::SERIALIZER, $this->getSerializer ());
try {
$result = $procedure($redis);
} catch (Throwable $e) {
throw $e;
} finally {
$this->pool->put($redis);
}
return $result;
}
Memory Leaks. Again?
final class ReopeningEntityManager implements EntityManagerInterface
{
private Closure $entityManagerFactory ;
protected array $wrapped = [];
public function clear($object = null) : void
{
$this->getWrapped()->clear($object);
unset ($this->wrapped[Co::getCid()]); // does not help!
}
private function getWrapped() : EntityManagerInterface
{
if (! isset($this->wrapped[Co::getCid()])) {
$this->wrapped[Co::getCid()] =
($this->entityManagerFactory )();
}
return $this->wrapped[Co::getCid()];
}
public function getConnection ()
{
return $this->getWrapped()->getConnection ();
}
Memory Leaks. Again?
Using WeakMap &
defer in coroutines!
Restart workers?
You are coward!
Using PostgreSQL - no PDO hooks in Swoole
● Use Coroutine Postgresql Client:
extension=swoole_postgresql.so
● Write new Driver for Doctrine ORM
● Be ready to problems
Problem Again
Other miscellaneous:
Manage crons (by timers)
Manage message workers (process manager)
Manage Signals (soft termination)
Milestone 3: others
Cron jobs
- persist Deployment: run “crontab” process + list php CLI command
- CronJob (k8s) periodical run POD with “php bin/app cron:process”
- CronJob as Message (run as “bin/app messenger:consume transport.amqp”)
- + Swoole Timer async callback in PHP master process (instead linux crontab)
Prӕfectus
https://github.com/opsway/praefectus
Supervisor & Metrics server for Symfony Messenger
Prӕfectus
PraefectusListener
use SpiralGoridgeRelay
;
use SpiralGoridgeRPCRPC
;
use SpiralGoridgeRPCRPCInterface
;
/**
* @see SymfonyComponentMessengerWorker
*/
class PraefectusListener implements EventSubscriberInterface
{
private const IPC_SOCKET_PATH_TPL = '/tmp/praefectus_%d.sock'
;
// …
public function onMessageReceived (EventWorkerMessageReceivedEvent $event) : void
{
$this->getRpc()->call('PraefectusRPC.WorkerState' ,['pid'=>getmypid() ,'state'=>self::WORKER_BUSY]);
$this->getRpc()->call('PraefectusRPC.MessageState' , [
'id' => $messageIdStamp ->id(),
'name' => get_class( $event->getEnvelope ()->getMessage()),
'transport' => $event->getReceiverName (),
'bus' => $busName,
'state' => self::MESSAGE_STATE_PROCESSING,
]);
}
}
*not yet released on GitHub
● no compatibility in code:
○ run same code in FPM & build-in http server
○ work without swoole extension (PoC - write stubs?)
○ XDebug - goodbye (use PCOV for coverage)
○ Profiling - https://github.com/upscalesoftware
Results
● Doctrine + async = EVIL*
Results
* But is possible, if enough extra memory:
Each concurrency EntityManager = +100-150Mb
● Swoole Table for cache - must have!
Results
Doctrine (any) cache shared between workers.
Solved case: Deployment & migration process without
50x errors
● Benchmarks - good results!
Results
- empty handler (bootstrap) - TTFB before: 140 ms, after: 4 ms
SWOOLE
FPM
● Benchmarks - good results!
Results
- empty handler (bootstrap) - TTFB before: 140 ms, after: 4 ms
- AVG (all traffic) TTFB reduced on 40% - before: 250 ms, after: 150 ms
- 95 percentile - before: 1500 ms, after: 600 ms
P.S. Load by same API RPS: ~200
- Now: 20 (PHP) / 20 (Typesense) / 20 (other) / 16 (DB) vCPUs
- 6k$ --> 3.5k$ (per month)
Results
● Resources usage - (ETA) reduced!
Useful links:
- https://github.com/deminy/swoole-by-examples
- https://docs.mezzio.dev/mezzio/v3/why-mezzio/
- https://docs.mezzio.dev/mezzio-swoole/v3/considerations/
- https://www.swoole.co.uk/docs/modules/swoole-server/configuration
- https://github.com/swooletw/awesome-swoole
- https://github.com/k911/swoole-bundle
We looking: DevOps / Backend Developer / Frontend Developer / QA
manual+automation.
Any Questions?
BTW:

Contenu connexe

Tendances

Efficient Memory Mapped File I/O for In-Memory File Systems (HotStorage '17)
Efficient Memory Mapped File I/O for In-Memory File Systems (HotStorage '17)Efficient Memory Mapped File I/O for In-Memory File Systems (HotStorage '17)
Efficient Memory Mapped File I/O for In-Memory File Systems (HotStorage '17)Jungsik Choi
 
OWASP AppSecCali 2015 - Marshalling Pickles
OWASP AppSecCali 2015 - Marshalling PicklesOWASP AppSecCali 2015 - Marshalling Pickles
OWASP AppSecCali 2015 - Marshalling PicklesChristopher Frohoff
 
Surviving the Java Deserialization Apocalypse // OWASP AppSecEU 2016
Surviving the Java Deserialization Apocalypse // OWASP AppSecEU 2016Surviving the Java Deserialization Apocalypse // OWASP AppSecEU 2016
Surviving the Java Deserialization Apocalypse // OWASP AppSecEU 2016Christian Schneider
 
리눅스 커널 디버거 KGDB/KDB
리눅스 커널 디버거 KGDB/KDB리눅스 커널 디버거 KGDB/KDB
리눅스 커널 디버거 KGDB/KDBManjong Han
 
nginx 입문 공부자료
nginx 입문 공부자료nginx 입문 공부자료
nginx 입문 공부자료choi sungwook
 
Defending against Java Deserialization Vulnerabilities
 Defending against Java Deserialization Vulnerabilities Defending against Java Deserialization Vulnerabilities
Defending against Java Deserialization VulnerabilitiesLuca Carettoni
 
Petit potam slides-rtfm-ossir
Petit potam slides-rtfm-ossirPetit potam slides-rtfm-ossir
Petit potam slides-rtfm-ossirLionelTopotam
 
Polyglot payloads in practice by avlidienbrunn at HackPra
Polyglot payloads in practice by avlidienbrunn at HackPraPolyglot payloads in practice by avlidienbrunn at HackPra
Polyglot payloads in practice by avlidienbrunn at HackPraMathias Karlsson
 
훌륭한 개발자로 성장하기
훌륭한 개발자로 성장하기훌륭한 개발자로 성장하기
훌륭한 개발자로 성장하기Changyol BAEK
 
Time based CAPTCHA protected SQL injection through SOAP-webservice
Time based CAPTCHA protected SQL injection through SOAP-webserviceTime based CAPTCHA protected SQL injection through SOAP-webservice
Time based CAPTCHA protected SQL injection through SOAP-webserviceFrans Rosén
 
All You Need is One - A ClickOnce Love Story - Secure360 2015
All You Need is One -  A ClickOnce Love Story - Secure360 2015All You Need is One -  A ClickOnce Love Story - Secure360 2015
All You Need is One - A ClickOnce Love Story - Secure360 2015NetSPI
 
Graficar SAR Linux (System Activity Report)
Graficar SAR Linux (System Activity Report)Graficar SAR Linux (System Activity Report)
Graficar SAR Linux (System Activity Report)Moisés Elías Araya
 
Javascript Module Patterns
Javascript Module PatternsJavascript Module Patterns
Javascript Module PatternsNicholas Jansma
 
우아한 모노리스
우아한 모노리스우아한 모노리스
우아한 모노리스Arawn Park
 
[122]책에서는 맛볼 수 없는 HTML5 Canvas 이야기
[122]책에서는 맛볼 수 없는 HTML5 Canvas 이야기 [122]책에서는 맛볼 수 없는 HTML5 Canvas 이야기
[122]책에서는 맛볼 수 없는 HTML5 Canvas 이야기 NAVER D2
 
What should a hacker know about WebDav?
What should a hacker know about WebDav?What should a hacker know about WebDav?
What should a hacker know about WebDav?Mikhail Egorov
 
[오픈소스컨설팅]Day #2 MySQL Tuning, Replication, Cluster
[오픈소스컨설팅]Day #2 MySQL Tuning, Replication, Cluster[오픈소스컨설팅]Day #2 MySQL Tuning, Replication, Cluster
[오픈소스컨설팅]Day #2 MySQL Tuning, Replication, ClusterJi-Woong Choi
 
Pentesting GraphQL Applications
Pentesting GraphQL ApplicationsPentesting GraphQL Applications
Pentesting GraphQL ApplicationsNeelu Tripathy
 

Tendances (20)

Efficient Memory Mapped File I/O for In-Memory File Systems (HotStorage '17)
Efficient Memory Mapped File I/O for In-Memory File Systems (HotStorage '17)Efficient Memory Mapped File I/O for In-Memory File Systems (HotStorage '17)
Efficient Memory Mapped File I/O for In-Memory File Systems (HotStorage '17)
 
OWASP AppSecCali 2015 - Marshalling Pickles
OWASP AppSecCali 2015 - Marshalling PicklesOWASP AppSecCali 2015 - Marshalling Pickles
OWASP AppSecCali 2015 - Marshalling Pickles
 
Surviving the Java Deserialization Apocalypse // OWASP AppSecEU 2016
Surviving the Java Deserialization Apocalypse // OWASP AppSecEU 2016Surviving the Java Deserialization Apocalypse // OWASP AppSecEU 2016
Surviving the Java Deserialization Apocalypse // OWASP AppSecEU 2016
 
리눅스 커널 디버거 KGDB/KDB
리눅스 커널 디버거 KGDB/KDB리눅스 커널 디버거 KGDB/KDB
리눅스 커널 디버거 KGDB/KDB
 
nginx 입문 공부자료
nginx 입문 공부자료nginx 입문 공부자료
nginx 입문 공부자료
 
Defending against Java Deserialization Vulnerabilities
 Defending against Java Deserialization Vulnerabilities Defending against Java Deserialization Vulnerabilities
Defending against Java Deserialization Vulnerabilities
 
Petit potam slides-rtfm-ossir
Petit potam slides-rtfm-ossirPetit potam slides-rtfm-ossir
Petit potam slides-rtfm-ossir
 
Polyglot payloads in practice by avlidienbrunn at HackPra
Polyglot payloads in practice by avlidienbrunn at HackPraPolyglot payloads in practice by avlidienbrunn at HackPra
Polyglot payloads in practice by avlidienbrunn at HackPra
 
훌륭한 개발자로 성장하기
훌륭한 개발자로 성장하기훌륭한 개발자로 성장하기
훌륭한 개발자로 성장하기
 
Time based CAPTCHA protected SQL injection through SOAP-webservice
Time based CAPTCHA protected SQL injection through SOAP-webserviceTime based CAPTCHA protected SQL injection through SOAP-webservice
Time based CAPTCHA protected SQL injection through SOAP-webservice
 
All You Need is One - A ClickOnce Love Story - Secure360 2015
All You Need is One -  A ClickOnce Love Story - Secure360 2015All You Need is One -  A ClickOnce Love Story - Secure360 2015
All You Need is One - A ClickOnce Love Story - Secure360 2015
 
Graficar SAR Linux (System Activity Report)
Graficar SAR Linux (System Activity Report)Graficar SAR Linux (System Activity Report)
Graficar SAR Linux (System Activity Report)
 
Javascript Module Patterns
Javascript Module PatternsJavascript Module Patterns
Javascript Module Patterns
 
우아한 모노리스
우아한 모노리스우아한 모노리스
우아한 모노리스
 
[122]책에서는 맛볼 수 없는 HTML5 Canvas 이야기
[122]책에서는 맛볼 수 없는 HTML5 Canvas 이야기 [122]책에서는 맛볼 수 없는 HTML5 Canvas 이야기
[122]책에서는 맛볼 수 없는 HTML5 Canvas 이야기
 
Fetch API Talk
Fetch API TalkFetch API Talk
Fetch API Talk
 
What should a hacker know about WebDav?
What should a hacker know about WebDav?What should a hacker know about WebDav?
What should a hacker know about WebDav?
 
[오픈소스컨설팅]Day #2 MySQL Tuning, Replication, Cluster
[오픈소스컨설팅]Day #2 MySQL Tuning, Replication, Cluster[오픈소스컨설팅]Day #2 MySQL Tuning, Replication, Cluster
[오픈소스컨설팅]Day #2 MySQL Tuning, Replication, Cluster
 
Provider vs BLoC vs Redux
Provider vs BLoC vs ReduxProvider vs BLoC vs Redux
Provider vs BLoC vs Redux
 
Pentesting GraphQL Applications
Pentesting GraphQL ApplicationsPentesting GraphQL Applications
Pentesting GraphQL Applications
 

Similaire à "Swoole: double troubles in c", Alexandr Vronskiy

DSLing your System For Scalability Testing Using Gatling - Dublin Scala User ...
DSLing your System For Scalability Testing Using Gatling - Dublin Scala User ...DSLing your System For Scalability Testing Using Gatling - Dublin Scala User ...
DSLing your System For Scalability Testing Using Gatling - Dublin Scala User ...Aman Kohli
 
Original slides from Ryan Dahl's NodeJs intro talk
Original slides from Ryan Dahl's NodeJs intro talkOriginal slides from Ryan Dahl's NodeJs intro talk
Original slides from Ryan Dahl's NodeJs intro talkAarti Parikh
 
ApacheConNA 2015: What's new in Apache httpd 2.4
ApacheConNA 2015: What's new in Apache httpd 2.4ApacheConNA 2015: What's new in Apache httpd 2.4
ApacheConNA 2015: What's new in Apache httpd 2.4Jim Jagielski
 
php & performance
 php & performance php & performance
php & performancesimon8410
 
Building and Scaling Node.js Applications
Building and Scaling Node.js ApplicationsBuilding and Scaling Node.js Applications
Building and Scaling Node.js ApplicationsOhad Kravchick
 
PHP & Performance
PHP & PerformancePHP & Performance
PHP & Performance毅 吕
 
Scalable Socket Server by Aryo
Scalable Socket Server by AryoScalable Socket Server by Aryo
Scalable Socket Server by AryoAgate Studio
 
PHP Sessions and Non-Sessions
PHP Sessions and Non-SessionsPHP Sessions and Non-Sessions
PHP Sessions and Non-SessionsSven Rautenberg
 
Socket programming, and openresty
Socket programming, and openrestySocket programming, and openresty
Socket programming, and openrestyTavish Naruka
 
202107 - Orion introduction - COSCUP
202107 - Orion introduction - COSCUP202107 - Orion introduction - COSCUP
202107 - Orion introduction - COSCUPRonald Hsu
 
MySQL HA Orchestrator Proxysql Consul.pdf
MySQL HA Orchestrator Proxysql Consul.pdfMySQL HA Orchestrator Proxysql Consul.pdf
MySQL HA Orchestrator Proxysql Consul.pdfYunusShaikh49
 
Debugging: Rules & Tools
Debugging: Rules & ToolsDebugging: Rules & Tools
Debugging: Rules & ToolsIan Barber
 
Presentation of OrientDB v2.2 - Webinar
Presentation of OrientDB v2.2 - WebinarPresentation of OrientDB v2.2 - Webinar
Presentation of OrientDB v2.2 - WebinarOrient Technologies
 
Introduction to ZooKeeper - TriHUG May 22, 2012
Introduction to ZooKeeper - TriHUG May 22, 2012Introduction to ZooKeeper - TriHUG May 22, 2012
Introduction to ZooKeeper - TriHUG May 22, 2012mumrah
 
Rhebok, High Performance Rack Handler / Rubykaigi 2015
Rhebok, High Performance Rack Handler / Rubykaigi 2015Rhebok, High Performance Rack Handler / Rubykaigi 2015
Rhebok, High Performance Rack Handler / Rubykaigi 2015Masahiro Nagano
 

Similaire à "Swoole: double troubles in c", Alexandr Vronskiy (20)

DSLing your System For Scalability Testing Using Gatling - Dublin Scala User ...
DSLing your System For Scalability Testing Using Gatling - Dublin Scala User ...DSLing your System For Scalability Testing Using Gatling - Dublin Scala User ...
DSLing your System For Scalability Testing Using Gatling - Dublin Scala User ...
 
Original slides from Ryan Dahl's NodeJs intro talk
Original slides from Ryan Dahl's NodeJs intro talkOriginal slides from Ryan Dahl's NodeJs intro talk
Original slides from Ryan Dahl's NodeJs intro talk
 
ApacheConNA 2015: What's new in Apache httpd 2.4
ApacheConNA 2015: What's new in Apache httpd 2.4ApacheConNA 2015: What's new in Apache httpd 2.4
ApacheConNA 2015: What's new in Apache httpd 2.4
 
php & performance
 php & performance php & performance
php & performance
 
Building and Scaling Node.js Applications
Building and Scaling Node.js ApplicationsBuilding and Scaling Node.js Applications
Building and Scaling Node.js Applications
 
PHP & Performance
PHP & PerformancePHP & Performance
PHP & Performance
 
Haproxy - zastosowania
Haproxy - zastosowaniaHaproxy - zastosowania
Haproxy - zastosowania
 
Scalable Socket Server by Aryo
Scalable Socket Server by AryoScalable Socket Server by Aryo
Scalable Socket Server by Aryo
 
Symfony Performance
Symfony PerformanceSymfony Performance
Symfony Performance
 
PHP Sessions and Non-Sessions
PHP Sessions and Non-SessionsPHP Sessions and Non-Sessions
PHP Sessions and Non-Sessions
 
Socket programming, and openresty
Socket programming, and openrestySocket programming, and openresty
Socket programming, and openresty
 
Redis
RedisRedis
Redis
 
202107 - Orion introduction - COSCUP
202107 - Orion introduction - COSCUP202107 - Orion introduction - COSCUP
202107 - Orion introduction - COSCUP
 
MySQL HA Orchestrator Proxysql Consul.pdf
MySQL HA Orchestrator Proxysql Consul.pdfMySQL HA Orchestrator Proxysql Consul.pdf
MySQL HA Orchestrator Proxysql Consul.pdf
 
NodeJS
NodeJSNodeJS
NodeJS
 
Debugging: Rules & Tools
Debugging: Rules & ToolsDebugging: Rules & Tools
Debugging: Rules & Tools
 
Php
PhpPhp
Php
 
Presentation of OrientDB v2.2 - Webinar
Presentation of OrientDB v2.2 - WebinarPresentation of OrientDB v2.2 - Webinar
Presentation of OrientDB v2.2 - Webinar
 
Introduction to ZooKeeper - TriHUG May 22, 2012
Introduction to ZooKeeper - TriHUG May 22, 2012Introduction to ZooKeeper - TriHUG May 22, 2012
Introduction to ZooKeeper - TriHUG May 22, 2012
 
Rhebok, High Performance Rack Handler / Rubykaigi 2015
Rhebok, High Performance Rack Handler / Rubykaigi 2015Rhebok, High Performance Rack Handler / Rubykaigi 2015
Rhebok, High Performance Rack Handler / Rubykaigi 2015
 

Plus de Fwdays

"How Preply reduced ML model development time from 1 month to 1 day",Yevhen Y...
"How Preply reduced ML model development time from 1 month to 1 day",Yevhen Y..."How Preply reduced ML model development time from 1 month to 1 day",Yevhen Y...
"How Preply reduced ML model development time from 1 month to 1 day",Yevhen Y...Fwdays
 
"GenAI Apps: Our Journey from Ideas to Production Excellence",Danil Topchii
"GenAI Apps: Our Journey from Ideas to Production Excellence",Danil Topchii"GenAI Apps: Our Journey from Ideas to Production Excellence",Danil Topchii
"GenAI Apps: Our Journey from Ideas to Production Excellence",Danil TopchiiFwdays
 
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks..."LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...Fwdays
 
"Federated learning: out of reach no matter how close",Oleksandr Lapshyn
"Federated learning: out of reach no matter how close",Oleksandr Lapshyn"Federated learning: out of reach no matter how close",Oleksandr Lapshyn
"Federated learning: out of reach no matter how close",Oleksandr LapshynFwdays
 
"What is a RAG system and how to build it",Dmytro Spodarets
"What is a RAG system and how to build it",Dmytro Spodarets"What is a RAG system and how to build it",Dmytro Spodarets
"What is a RAG system and how to build it",Dmytro SpodaretsFwdays
 
"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii SoldatenkoFwdays
 
"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr Bagan"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr BaganFwdays
 
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek SchlawackFwdays
 
"Distributed graphs and microservices in Prom.ua", Maksym Kindritskyi
"Distributed graphs and microservices in Prom.ua",  Maksym Kindritskyi"Distributed graphs and microservices in Prom.ua",  Maksym Kindritskyi
"Distributed graphs and microservices in Prom.ua", Maksym KindritskyiFwdays
 
"Rethinking the existing data loading and processing process as an ETL exampl...
"Rethinking the existing data loading and processing process as an ETL exampl..."Rethinking the existing data loading and processing process as an ETL exampl...
"Rethinking the existing data loading and processing process as an ETL exampl...Fwdays
 
"How Ukrainian IT specialist can go on vacation abroad without crossing the T...
"How Ukrainian IT specialist can go on vacation abroad without crossing the T..."How Ukrainian IT specialist can go on vacation abroad without crossing the T...
"How Ukrainian IT specialist can go on vacation abroad without crossing the T...Fwdays
 
"The Strength of Being Vulnerable: the experience from CIA, Tesla and Uber", ...
"The Strength of Being Vulnerable: the experience from CIA, Tesla and Uber", ..."The Strength of Being Vulnerable: the experience from CIA, Tesla and Uber", ...
"The Strength of Being Vulnerable: the experience from CIA, Tesla and Uber", ...Fwdays
 
"[QUICK TALK] Radical candor: how to achieve results faster thanks to a cultu...
"[QUICK TALK] Radical candor: how to achieve results faster thanks to a cultu..."[QUICK TALK] Radical candor: how to achieve results faster thanks to a cultu...
"[QUICK TALK] Radical candor: how to achieve results faster thanks to a cultu...Fwdays
 
"[QUICK TALK] PDP Plan, the only one door to raise your salary and boost care...
"[QUICK TALK] PDP Plan, the only one door to raise your salary and boost care..."[QUICK TALK] PDP Plan, the only one door to raise your salary and boost care...
"[QUICK TALK] PDP Plan, the only one door to raise your salary and boost care...Fwdays
 
"4 horsemen of the apocalypse of working relationships (+ antidotes to them)"...
"4 horsemen of the apocalypse of working relationships (+ antidotes to them)"..."4 horsemen of the apocalypse of working relationships (+ antidotes to them)"...
"4 horsemen of the apocalypse of working relationships (+ antidotes to them)"...Fwdays
 
"Reconnecting with Purpose: Rediscovering Job Interest after Burnout", Anast...
"Reconnecting with Purpose: Rediscovering Job Interest after Burnout",  Anast..."Reconnecting with Purpose: Rediscovering Job Interest after Burnout",  Anast...
"Reconnecting with Purpose: Rediscovering Job Interest after Burnout", Anast...Fwdays
 
"Mentoring 101: How to effectively invest experience in the success of others...
"Mentoring 101: How to effectively invest experience in the success of others..."Mentoring 101: How to effectively invest experience in the success of others...
"Mentoring 101: How to effectively invest experience in the success of others...Fwdays
 
"Mission (im) possible: How to get an offer in 2024?", Oleksandra Myronova
"Mission (im) possible: How to get an offer in 2024?",  Oleksandra Myronova"Mission (im) possible: How to get an offer in 2024?",  Oleksandra Myronova
"Mission (im) possible: How to get an offer in 2024?", Oleksandra MyronovaFwdays
 
"Why have we learned how to package products, but not how to 'package ourselv...
"Why have we learned how to package products, but not how to 'package ourselv..."Why have we learned how to package products, but not how to 'package ourselv...
"Why have we learned how to package products, but not how to 'package ourselv...Fwdays
 
"How to tame the dragon, or leadership with imposter syndrome", Oleksandr Zin...
"How to tame the dragon, or leadership with imposter syndrome", Oleksandr Zin..."How to tame the dragon, or leadership with imposter syndrome", Oleksandr Zin...
"How to tame the dragon, or leadership with imposter syndrome", Oleksandr Zin...Fwdays
 

Plus de Fwdays (20)

"How Preply reduced ML model development time from 1 month to 1 day",Yevhen Y...
"How Preply reduced ML model development time from 1 month to 1 day",Yevhen Y..."How Preply reduced ML model development time from 1 month to 1 day",Yevhen Y...
"How Preply reduced ML model development time from 1 month to 1 day",Yevhen Y...
 
"GenAI Apps: Our Journey from Ideas to Production Excellence",Danil Topchii
"GenAI Apps: Our Journey from Ideas to Production Excellence",Danil Topchii"GenAI Apps: Our Journey from Ideas to Production Excellence",Danil Topchii
"GenAI Apps: Our Journey from Ideas to Production Excellence",Danil Topchii
 
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks..."LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
 
"Federated learning: out of reach no matter how close",Oleksandr Lapshyn
"Federated learning: out of reach no matter how close",Oleksandr Lapshyn"Federated learning: out of reach no matter how close",Oleksandr Lapshyn
"Federated learning: out of reach no matter how close",Oleksandr Lapshyn
 
"What is a RAG system and how to build it",Dmytro Spodarets
"What is a RAG system and how to build it",Dmytro Spodarets"What is a RAG system and how to build it",Dmytro Spodarets
"What is a RAG system and how to build it",Dmytro Spodarets
 
"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko
 
"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr Bagan"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr Bagan
 
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
 
"Distributed graphs and microservices in Prom.ua", Maksym Kindritskyi
"Distributed graphs and microservices in Prom.ua",  Maksym Kindritskyi"Distributed graphs and microservices in Prom.ua",  Maksym Kindritskyi
"Distributed graphs and microservices in Prom.ua", Maksym Kindritskyi
 
"Rethinking the existing data loading and processing process as an ETL exampl...
"Rethinking the existing data loading and processing process as an ETL exampl..."Rethinking the existing data loading and processing process as an ETL exampl...
"Rethinking the existing data loading and processing process as an ETL exampl...
 
"How Ukrainian IT specialist can go on vacation abroad without crossing the T...
"How Ukrainian IT specialist can go on vacation abroad without crossing the T..."How Ukrainian IT specialist can go on vacation abroad without crossing the T...
"How Ukrainian IT specialist can go on vacation abroad without crossing the T...
 
"The Strength of Being Vulnerable: the experience from CIA, Tesla and Uber", ...
"The Strength of Being Vulnerable: the experience from CIA, Tesla and Uber", ..."The Strength of Being Vulnerable: the experience from CIA, Tesla and Uber", ...
"The Strength of Being Vulnerable: the experience from CIA, Tesla and Uber", ...
 
"[QUICK TALK] Radical candor: how to achieve results faster thanks to a cultu...
"[QUICK TALK] Radical candor: how to achieve results faster thanks to a cultu..."[QUICK TALK] Radical candor: how to achieve results faster thanks to a cultu...
"[QUICK TALK] Radical candor: how to achieve results faster thanks to a cultu...
 
"[QUICK TALK] PDP Plan, the only one door to raise your salary and boost care...
"[QUICK TALK] PDP Plan, the only one door to raise your salary and boost care..."[QUICK TALK] PDP Plan, the only one door to raise your salary and boost care...
"[QUICK TALK] PDP Plan, the only one door to raise your salary and boost care...
 
"4 horsemen of the apocalypse of working relationships (+ antidotes to them)"...
"4 horsemen of the apocalypse of working relationships (+ antidotes to them)"..."4 horsemen of the apocalypse of working relationships (+ antidotes to them)"...
"4 horsemen of the apocalypse of working relationships (+ antidotes to them)"...
 
"Reconnecting with Purpose: Rediscovering Job Interest after Burnout", Anast...
"Reconnecting with Purpose: Rediscovering Job Interest after Burnout",  Anast..."Reconnecting with Purpose: Rediscovering Job Interest after Burnout",  Anast...
"Reconnecting with Purpose: Rediscovering Job Interest after Burnout", Anast...
 
"Mentoring 101: How to effectively invest experience in the success of others...
"Mentoring 101: How to effectively invest experience in the success of others..."Mentoring 101: How to effectively invest experience in the success of others...
"Mentoring 101: How to effectively invest experience in the success of others...
 
"Mission (im) possible: How to get an offer in 2024?", Oleksandra Myronova
"Mission (im) possible: How to get an offer in 2024?",  Oleksandra Myronova"Mission (im) possible: How to get an offer in 2024?",  Oleksandra Myronova
"Mission (im) possible: How to get an offer in 2024?", Oleksandra Myronova
 
"Why have we learned how to package products, but not how to 'package ourselv...
"Why have we learned how to package products, but not how to 'package ourselv..."Why have we learned how to package products, but not how to 'package ourselv...
"Why have we learned how to package products, but not how to 'package ourselv...
 
"How to tame the dragon, or leadership with imposter syndrome", Oleksandr Zin...
"How to tame the dragon, or leadership with imposter syndrome", Oleksandr Zin..."How to tame the dragon, or leadership with imposter syndrome", Oleksandr Zin...
"How to tame the dragon, or leadership with imposter syndrome", Oleksandr Zin...
 

Dernier

Handwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsHandwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsMaria Levchenko
 
A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?Igalia
 
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdfThe Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdfEnterprise Knowledge
 
[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdfhans926745
 
08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking MenDelhi Call girls
 
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptxHampshireHUG
 
Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...Enterprise Knowledge
 
Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonAnna Loughnan Colquhoun
 
CNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of ServiceCNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of Servicegiselly40
 
Slack Application Development 101 Slides
Slack Application Development 101 SlidesSlack Application Development 101 Slides
Slack Application Development 101 Slidespraypatel2
 
A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)Gabriella Davis
 
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024The Digital Insurer
 
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationFrom Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationSafe Software
 
IAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsIAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsEnterprise Knowledge
 
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptxEIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptxEarley Information Science
 
Artificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and MythsArtificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and MythsJoaquim Jorge
 
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...Neo4j
 
What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?Antenna Manufacturer Coco
 
A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024Results
 
Scaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationScaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationRadu Cotescu
 

Dernier (20)

Handwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsHandwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed texts
 
A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?
 
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdfThe Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
 
[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf
 
08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men
 
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
 
Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...
 
Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt Robison
 
CNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of ServiceCNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of Service
 
Slack Application Development 101 Slides
Slack Application Development 101 SlidesSlack Application Development 101 Slides
Slack Application Development 101 Slides
 
A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)
 
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
 
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationFrom Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
 
IAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsIAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI Solutions
 
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptxEIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
 
Artificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and MythsArtificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and Myths
 
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
 
What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?
 
A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024
 
Scaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationScaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organization
 

"Swoole: double troubles in c", Alexandr Vronskiy

  • 1.
  • 3. ● What existing problems need to solve? ● Why choose Swoole? ● How solve it with Swoole? ● What unexpected troubles could happens? ● Show methods to avoid then (or not?) ● Talk about theory ● Examples in a context of a real project Intro
  • 4. Side Effects of - PHP no dying (long-lived) - Concurrency Async - Shared Memory access Intro
  • 5. ● ZF2 / Laminas / Mezzio / PSR-15 / .. ● PHP 5.6 -> … -> 7.4 --> 8.0 + swoole ● PostgreSQL / ElasticSearch Typesense / Redis / RabbitMQ / PubSub ● Docker / k8s / autoscale / Google Cloud ● Files: 2.5k, LOC: 200k, LLOC: 30k Intro. About project
  • 6. Intro. About project Current AVG metrics: - GA online users: ~3500 - API RPS: ~200 - DB transactions: ~3000/sec - Products count: ~25kk Consuming resources: - PHP: 60 vCPU - ElasticSearch: 40 vCPU - PostgreSQL: 16 vCPU - Others: 20 vCPU
  • 7. ● Not optimized resources usage. ● Hard tuning horizontal scale. ● Over-complicated infrastructure ● Not well performance (TTFB) Why? Problems Database PHP PHP PHP PHP Elastic Elastic Elastic Other 4x times
  • 8. ● Not optimized resources usage. ● Hard tuning horizontal scale. ● Over-complicated infrastructure ● Not well performance (TTFB) Why? Problems PHP 4 vCPU PHP 16 vCPU VS
  • 9. ● Not optimized resources usage. ● Hard tuning horizontal scale. ● Over-complicated infrastructure ● Not well performance (TTFB) Why? Problems Docker, k8s, Terraform, Helm, GitHub Actions, Envs: prod+stage+devs+local, Go, Typescript
  • 10. ● Not optimized resources usage. ● Hard tuning horizontal scale. ● Over-complicated infrastructure ● Not well performance (TTFB) Why? Problems
  • 11. ● ASYNC entire ecosystem ● Performance ● Easy to start - Coroutine based concurrent asynchronous IO - Event Loop - Process management - In-memory storage and management - Async TCP/UDP/HTTP/WebSocket/HTTP2/FastCGI client and servers - Async Task API - Channels, Locks, Timer, Scheduler NO PECL: ext-pcntl, ext-pthreads, ext-event Why Swoole?
  • 12. Milestone 1: PHP no die ● Run HTTP Server ○ replace NGINX+FPM ○ simplify infrastructure (less DevOps, easy building & k8s configs) ○ change (unified) operations: CI / CD / local env ● Prepare bootstrap ● Implement best practices in shared memory usage to avoid side-effects Plan
  • 13. ● Server Mode: SWOOLE_PROCESS / SWOOLE_BASE ● Dispatch Mode: 1-9 (Round-Robin, Fixed, Preemptive, etc) ● Worker Num: 1-1000 (CPU*2) ● Max Request: 0-XXX (0) Other Options: Limits, Timeouts, Memory buffers... php bin/http-server.php Swoole HTTP Server https://www.swoole.co.uk/docs/modules/swoole-server/configuration MUST SEE: <?php $server = new SwooleHTTPServer("127.0.0.1", 9501); $server->on('Request', function(Swoole/Server/Request $request, Swoole/Server/Response $response) { $response->end('<h1>Hello World!</h1>'); }); $server->start();
  • 14. ● Scan config files, env, run reflection, attributes, build DI, generate proxy, warm caches: ● NO NEED cache layer anymore ● NOW it before real start http server (if no traffic: readiness probe=negative) PSR-7 HTTP Messages PSR-15 Middleware PSR-11 Container bootstrap in master http request in worker process Bootstrap app once fork state
  • 15. What are the problems? - NO SUPER GLOBALS ($_SERVER, ...) - No PHP Session (it is CLI SAPI) - Stateful services that should mutate on each request - DI containers - global state too. Shared Memory
  • 16. Any wrong example? Shared Memory https://github.com/chrisguitarguy/RequestIdBundle/blob/main/src/EventListener/RequestIdListener.php public function onRequest(RequestEvent $event) : void { if (!$this->isMainRequest ($event)) { return; } $req = $event->getRequest(); if ($this->trustRequest && ($id = $req->headers->get($this->requestHeader ))) { $this->idStorage->setRequestId ($id); return; } if ($id = $this->idStorage->getRequestId ()) { $req->headers->set($this->requestHeader , $id); return; } $id = $this->idGenerator ->generate(); $req->headers->set($this->requestHeader , $id); $this->idStorage->setRequestId ($id); } Empty storage - no return Generate NEW Saving to storage 1 HTTP REQUEST:
  • 17. Any wrong example? Shared Memory public function onRequest(RequestEvent $event) : void { if (!$this->isMainRequest ($event)) { return; } $req = $event->getRequest(); if ($this->trustRequest && ($id = $req->headers->get($this->requestHeader ))) { $this->idStorage->setRequestId ($id); return; } if ($id = $this->idStorage->getRequestId ()) { $req->headers->set($this->requestHeader , $id); return; } $id = $this->idGenerator ->generate(); $req->headers->set($this->requestHeader , $id); $this->idStorage->setRequestId ($id); } 2 HTTP REQUEST: Now has ID in storage THE END Dead code https://github.com/chrisguitarguy/RequestIdBundle/blob/main/src/EventListener/RequestIdListener.php
  • 18. Shared Memory HTTP Server options: Max Request: 100 What if... Then… In logs request ID is changed.
  • 19. Best practices: - Middlewares, Factories, Proxies, Delegators Shared Memory use PsrHttpMessageResponseInterface ; use PsrHttpMessageServerRequestInterface ; use PsrHttpServerRequestHandlerInterface ; use PsrLogLoggerInterface ; class SomeHandler implements RequestHandlerInterface { public function __construct( private Closure $appServiceFactory , private LoggerInterface $logger ) {} // Idempotent method!!! public function handle(ServerRequestInterface $request) : ResponseInterface { $logger = clone $this->logger; $logger->getProcessor( 'RequestID')->setRequestId( $request->getAttribute( 'RequestID')); $appService = ($this->appServiceFactory)( $logger); return new JsonResponse($appService->createBook()) ; } }
  • 20. Memory leaks … in Doctrine ORM :( Shared Memory https://alejandrocelaya.blog/2019/11/04/how-to-properly-handle-a-doctrine-entity-manager-on-an-expressive-appli cation-served-with-swoole/ use DoctrineORMDecoratorEntityManagerDecorator as EMD; class ReopeningEntityManager extends EMD { private $createEm; public function __construct (callable $createEm) { parent::__construct($createEm()); $this->createEm = $createEm; } public function open(): void { if (! $this->wrapped->isOpen()) { $this->wrapped = ($this->createEm)(); } } class CloseDbConnectionMiddleware implements MiddlewareInterface { public function __construct( private ReopeningEntityManager $em) {} public function process( ServerRequestInterface $request, RequestHandlerInterface $handler ) : ResponseInterface { $this->em->open() ; try { return $handler->handle($request); } finally { $this->em->getConnection()->close() ; $this->em->clear() ; } } } Saved in DI
  • 21. Shared Memory Memory leaks BUT WHERE??? abstract class EntityManagerDecorator extends ObjectManagerDecorator { /** @var EntityManagerInterface */ protected $wrapped; public function __construct (EntityManagerInterface $wrapped) { $this->wrapped = $wrapped; } public function getRepository ($className) { return $this->wrapped->getRepository ($className); } public function getRepository ($entityName ) { return $this->repositoryFactory ->getRepository ($this, $entityName ); } Somewhere far far away in EntityManager
  • 22. PROBLEMS DUE TO: timeouts / lifecycles Avoid: Stateful convert to stateless Connections $redis = $di->get(Redis::class); // FactoryRedis: $redis->connect(...); $redis->get('KEY1'); $redisFactory = $di->get(RedisFactory:: class); $redisFactory()->get(‘KEY1’); // + close connect in desctructor Request Wrapper/Delegator: new/refresh state on each request OR
  • 23. Milestone 2: ASYNC ● Async theory ● Using coroutines ● Non-blocked IO solutions ● Concurrency problems review ● Again memory leaks
  • 24. ● GET /some/action1/ SELECT sleep(1); ○ 1 worker = 1 req/sec ○ 2 worker = 2 req/sec ● GET /some/action2/ fibonacci(30); ○ 1 worker = 1 req/sec ○ 2 worker = depends on CPU cores Why/What async? Try benchmark this:
  • 25. ● GET /some/action1/ SELECT sleep(1); ○ 1 worker = 1 req/sec ○ 2 worker = 2 req/sec ● GET /some/action2/ fibonacci(30); ○ 1 worker = 1 req/sec ○ 2 worker = depends on CPU cores MIX 50/50 = 1 req/sec 50% CPU Why/What async? Try benchmark this:
  • 26. Now enable coroutines: http server options: . 'enable_coroutine' => true, Why/What async? ● GET /some/action1/ ○ 1 worker = 10000 req/sec ○ 2 worker = 10000 req/sec ● GET /some/action2/ ○ 1 worker = 1 req/sec ○ 2 worker = depends on CPU cores
  • 27. Now enable coroutines: http server options: . 'enable_coroutine' => true, Why/What async? ● GET /some/action1/ ○ 1 worker = 10000 req/sec ○ 2 worker = 10000 req/sec ● GET /some/action2/ ○ 1 worker = 1 req/sec ○ 2 worker = depends on CPU cores MIX 50/50 = 2 req/sec 100% CPU
  • 28. go(function () { // FIRST CO echo '1'; go(function () { // SECOND CO echo '2'; co::sleep(3); // IO (in 2 CO), will return in 3 sec echo '6'; go(function () { // THIRD CO echo '7'; co::sleep(2); // IO echo "9n"; }); // END THIRD echo '8'; }); // END SECOND echo '3'; co::sleep(1); // Again IO but in 1 CO echo '5'; }); // END FIRST CO echo '4'; Coroutines 1 2 3 4 5
  • 30. https://www.swoole.co.uk/docs/modules/swoole-runtime-flags Swoole Hooks Coroutine Clients: ● TCP/UDP ● HTTP ● HTTP2 ● Socket ● FastCGI ● Redis ● MySQL ● Postgresql Runtime HOOKS: ● Coroutine support (any IO libraries based on php_stream): ○ Redis (phpredis) or (predis) ○ MySQL (mysqlnd) PDO and MySQLi ○ PHP SOAP ○ file_get_contents, fopen and many more file I/O operations ○ stream_socket_client functions ○ fsockopen ○ CURL with libcurl ● Libraries without coroutine support: ○ MySQL with libmysqlclient ○ MongoDB with mongo-c-client ○ pdo_pgsql, pdo_ori, pdo_odbc, pdo_firebird, php-amqp VS Non-blocked IO
  • 31. $swooleServer->onRequest: go($this->requestHandler); -------------------------------------------------------------------------- non-blocked: multiple requests in same time/code Concurrency function onRequest() { $class = $di->get(stdClass:class); if ($class->some === null) { $class->some = 123; } sleep(2); // && some logic $class->some = null; } First request awaiting here We expected clean in request end http server options: . 'enable_coroutine' => true,
  • 32. $swooleServer->onRequest: go($this->requestHandler); -------------------------------------------------------------------------- non-blocked: multiple requests in same time/code Concurrency function onRequest() { $class = $di->get(stdClass:class); if ($class->some === null) { $class->some = 123; } sleep(2); // && some logic $class->some = null; } First request awaiting here We expected clean in request end EPIC FAIL! in second request http server options: . 'enable_coroutine' => true,
  • 33. Request Wrapper/Delegator: new/refresh state on each request Uncaught SwooleError: Socket# has already been bound to another coroutine Connections. Again? $http = new SwooleHttpServer( '0.0.0.0', '80', SWOOLE_PROCESS) ; $http->on('request', function (SwooleHttpRequest $request, SwooleHttpResponse $response) { if (empty($redis)) { $redis = new Redis(); $redis->connect('127.0.0.1' , 6379); $redis->select(1); $redis->setOption(Redis::OPT_SERIALIZER , Redis::SERIALIZER_PHP) ; } try { $redisJson = $redis->get('key'); } catch (Exception $e) { // SWOOLE ERROR HERE ! } $response->end('some response' ); });
  • 35. Connections. Again? use DoctrineCommonCacheCacheProvider ; use Redis; use SwooleDatabaseRedisPool ; class SwooleRedisCacheProvider extends CacheProvider { public function __construct ( private RedisPool $pool, ) { } protected function doFetch($id, ?Redis $redis = null) { if (! $redis) { return $this->run(fn (Redis $redis) : mixed => . $this->doFetch($id, $redis)); } return $redis->get($id); } private function run(callable $procedure) { $redis = $this->pool->get(); $redis->setOption(Redis::SERIALIZER, $this->getSerializer ()); try { $result = $procedure($redis); } catch (Throwable $e) { throw $e; } finally { $this->pool->put($redis); } return $result; }
  • 36. Memory Leaks. Again? final class ReopeningEntityManager implements EntityManagerInterface { private Closure $entityManagerFactory ; protected array $wrapped = []; public function clear($object = null) : void { $this->getWrapped()->clear($object); unset ($this->wrapped[Co::getCid()]); // does not help! } private function getWrapped() : EntityManagerInterface { if (! isset($this->wrapped[Co::getCid()])) { $this->wrapped[Co::getCid()] = ($this->entityManagerFactory )(); } return $this->wrapped[Co::getCid()]; } public function getConnection () { return $this->getWrapped()->getConnection (); }
  • 37. Memory Leaks. Again? Using WeakMap & defer in coroutines! Restart workers? You are coward!
  • 38. Using PostgreSQL - no PDO hooks in Swoole ● Use Coroutine Postgresql Client: extension=swoole_postgresql.so ● Write new Driver for Doctrine ORM ● Be ready to problems Problem Again
  • 39. Other miscellaneous: Manage crons (by timers) Manage message workers (process manager) Manage Signals (soft termination) Milestone 3: others
  • 40. Cron jobs - persist Deployment: run “crontab” process + list php CLI command - CronJob (k8s) periodical run POD with “php bin/app cron:process” - CronJob as Message (run as “bin/app messenger:consume transport.amqp”) - + Swoole Timer async callback in PHP master process (instead linux crontab)
  • 42. Prӕfectus PraefectusListener use SpiralGoridgeRelay ; use SpiralGoridgeRPCRPC ; use SpiralGoridgeRPCRPCInterface ; /** * @see SymfonyComponentMessengerWorker */ class PraefectusListener implements EventSubscriberInterface { private const IPC_SOCKET_PATH_TPL = '/tmp/praefectus_%d.sock' ; // … public function onMessageReceived (EventWorkerMessageReceivedEvent $event) : void { $this->getRpc()->call('PraefectusRPC.WorkerState' ,['pid'=>getmypid() ,'state'=>self::WORKER_BUSY]); $this->getRpc()->call('PraefectusRPC.MessageState' , [ 'id' => $messageIdStamp ->id(), 'name' => get_class( $event->getEnvelope ()->getMessage()), 'transport' => $event->getReceiverName (), 'bus' => $busName, 'state' => self::MESSAGE_STATE_PROCESSING, ]); } } *not yet released on GitHub
  • 43. ● no compatibility in code: ○ run same code in FPM & build-in http server ○ work without swoole extension (PoC - write stubs?) ○ XDebug - goodbye (use PCOV for coverage) ○ Profiling - https://github.com/upscalesoftware Results
  • 44. ● Doctrine + async = EVIL* Results * But is possible, if enough extra memory: Each concurrency EntityManager = +100-150Mb
  • 45. ● Swoole Table for cache - must have! Results Doctrine (any) cache shared between workers. Solved case: Deployment & migration process without 50x errors
  • 46. ● Benchmarks - good results! Results - empty handler (bootstrap) - TTFB before: 140 ms, after: 4 ms SWOOLE FPM
  • 47. ● Benchmarks - good results! Results - empty handler (bootstrap) - TTFB before: 140 ms, after: 4 ms - AVG (all traffic) TTFB reduced on 40% - before: 250 ms, after: 150 ms - 95 percentile - before: 1500 ms, after: 600 ms P.S. Load by same API RPS: ~200
  • 48. - Now: 20 (PHP) / 20 (Typesense) / 20 (other) / 16 (DB) vCPUs - 6k$ --> 3.5k$ (per month) Results ● Resources usage - (ETA) reduced!
  • 49. Useful links: - https://github.com/deminy/swoole-by-examples - https://docs.mezzio.dev/mezzio/v3/why-mezzio/ - https://docs.mezzio.dev/mezzio-swoole/v3/considerations/ - https://www.swoole.co.uk/docs/modules/swoole-server/configuration - https://github.com/swooletw/awesome-swoole - https://github.com/k911/swoole-bundle We looking: DevOps / Backend Developer / Frontend Developer / QA manual+automation. Any Questions? BTW: