working with asynchronous events

32
Working with Asynchronous Events Jan Gregor Emge-Triebel (@jan0707) Dennis Oehme (@dennisoehme)

Upload: garden-of-concepts-gmbh

Post on 13-Apr-2017

184 views

Category:

Software


0 download

TRANSCRIPT

Page 1: Working with Asynchronous Events

Working withAsynchronous Events

Jan Gregor Emge-Triebel (@jan0707)Dennis Oehme (@dennisoehme)

Page 2: Working with Asynchronous Events

Garden of Concepts GmbH● Hanau / Munich

● In house CMS “.stone”

● In house CRM “Elvis”

● Various individual customer projects

● Symfony based development, supported by:

○ MongoDB, ElasticSearch, MySQL, RabbitMQ,

Redis, AngularJS, Twig, Jade, Gitlab, Docker,

Vagrant, Ansible

● Say hi @goc_mediastudio

Page 3: Working with Asynchronous Events

Requests == Event

“Symfony is a request based framework.”

Fabien Potencier, Symfony Live 2014

@fabpot

Page 4: Working with Asynchronous Events

Requests

Request Controller Logic 1 Logic 2 Response

Request Controller

Logic 1

Logic 2

Response

Synchronous

Asynchronous

Page 5: Working with Asynchronous Events

Why do we need asynchronous event processing ?● Move long running logic

● Cut down reaction times

● Transfer load

● Microservices

● Exchange data/messages with other (sub-)systems

● Parallelization

● Scaling

Page 6: Working with Asynchronous Events

Our journey● Gearman

● (PHP) Resque

○ Demo

● RabbitMQ

Page 7: Working with Asynchronous Events

Gearman● Gearman Job Server (written in C)

● Runs as a Linux daemon

● Requires PECL extension for worker API

● Worker APIs exists for other Languages (C, Perl,...)

Page 8: Working with Asynchronous Events

Gearman

http://gearman.org/examples/send-emails/

Page 9: Working with Asynchronous Events

Gearman● Latest PECL-Extension version is 1.1.2 (August 2013)

● Latest Server-Release (spring 2014)

● No more process is being made

● Gearman daemon and extension are often incompatible

Page 10: Working with Asynchronous Events

(PHP) Resque ● Is a Resque port to php:

○ Resque is a Redis-backed Ruby library for creating background jobs, placing them on multiple

queues, and processing them later.

● Needs Redis(-Cluster)

● Redis is capable of atomic transactions (FIFO)

Page 11: Working with Asynchronous Events

Demo

https://github.com/Jan0707/async-symfony

Page 12: Working with Asynchronous Events

(PHP) Resque ● Hardly any commits since 2012

● Last commit to Master on 2015-05-12

● chrisboulton/php-resque & michelsalib/BCCResqueBundle must be presumed

dead ?

Page 13: Working with Asynchronous Events

RabbitMQ

Or why this talk should be named:“Working with Asynchronous Events in RabbitMQ”

Page 14: Working with Asynchronous Events

RabbitMQ● Message Broker written in Erlang

● AMQP (Advanced Message Queuing Protocol)

● Open, but binary network protocoll

● Routing, message distribution

● Transactions

● Plus, more nice features○ TTL

○ DLX (Dead Letter eXchange)

○ PreFetching

Page 15: Working with Asynchronous Events

Of publishers and consumers ...

Publisher Publish ConsumerEx-change QueueRoutes Consumes

Page 16: Working with Asynchronous Events

There is a Bundle for it● https://github.com/php-amqplib/RabbitMqBundle

● Consumer and Producer as Symfony services

● Every queue Consumer runs as a Symfony command

● Configuration via app/config.yml○ Better: Create app/config/rabbitmq.yml and import in app/config/config.yml

Page 17: Working with Asynchronous Events

app/config/rabbitmq.yml

Page 18: Working with Asynchronous Events

Symfony Producer

Page 19: Working with Asynchronous Events

Symfony Consumer

Page 20: Working with Asynchronous Events

Lessons Learned: Consumer● PHP threads are not meant to be long running

○ New problems: memory leaks, ...

● Use supervisor to check and restart Consumers

● Open database connections, timeouts○ Better quit when inactive

● Cap maximum runtime per thread○ Automatically shutdown after processign x messages

● Memory limit: RabbitMQ-Bundle utilizes “soft-quota”

● Booting consumers takes rather long

● Prefetching (Warning: Order!)

Page 21: Working with Asynchronous Events

Lessons Learned: Message● Compact/short messages

● Queues eat up a lot of storage / RAM

● Common format such as JSON or XML○ Do not serialize PHP objects or arrays

○ Ensure interoperability with other systems and languages

Page 22: Working with Asynchronous Events

Lessons Learned: Message Transformation● Use JMS/Serializer to convert objects to JSON

○ Deserialize JSON to PHP objects in consumer

○ Objects can and should be validated (with symfony forms and asserts)

○ Reload entities / documents to keep them up to date (doctrine/unit of work)

● Alternative approach: PHPs JsonSerializable Interface

Page 23: Working with Asynchronous Events

Lessons Learned: Message Header● Use message “Header” for content-type and version

○ Message formats can change

○ consumers must remain compatible

● Unqiue IDs make logging / debugging / live easier

● Other meta data:○ timestamp

○ user / session

○ App id

○ ...

Page 24: Working with Asynchronous Events

Tip: Custom Consumer-/Producer-Classes● Message transformation

● Events

● Logging

Page 25: Working with Asynchronous Events

Transactions● Messages must be brokered to exactly one Consumer

● Consumer must explicitly answer a message with “acknowledge”

● If not, the message will be marked “rejected” and be requeued○ Beware of requeuing:

■ Can lead to toxic messages

■ Can change the order of messages

○ Beware of final rejection:

■ Can lead to loss of data

Page 26: Working with Asynchronous Events

Toxic Messages● If a message is not explicitly being answered, it will be requeued.

● If that happens multiple times :

● Congratulations on your infinite loop

● Congratulations on your infinite loop

● Congratulations on your infinite loop

● Congratulations on your infinite loop

● Congratulations on your infinite loop

● Congratulations on your infinite loop

● Congratulations on your infinite loop

● Congratulations on your infinite loop

● Congratulations on your infinite loop

Page 27: Working with Asynchronous Events

Dead Letter Exchange● RabbitMQ comes with a Dead Letter Exchange (DLX)

● Every queue determines its own or shared DLX

● DLX is a separate queue, storing all rejected messages

○ (Reject, TTL, Prefetch)

Page 28: Working with Asynchronous Events

app/config/rabbitmq.yml

Page 29: Working with Asynchronous Events

Signal Handling● Graceful Shutdown

● pcntl_signal / _dispatch

● SIGTERM

● FATAL ERROR abfangen

● Logging

● Toxic Message-Handling

Shutdown

Page 30: Working with Asynchronous Events

Deployment● Consumers need an up to date code base

● Consumers need a graceful shutdown

● Consumers must only be shutdown when idling○ Otherwise : Loss of message / data

Page 31: Working with Asynchronous Events

Other challenges● Significant change of infrastructure

○ Choose your libraries and dependencies carefully!

● Moving load is not removing load

● Rethinking necessary○ Display of status / intermediate result

○ Websockets or Push instead of Polling

● Interdependencies of messages○ Especially when running parallel consumers!

● Performance (Doctrine ORM / ODM)

Page 32: Working with Asynchronous Events

Questions ?Thank you :)

Find this and other talks at: https://www.gardenofconcepts.com/talks/

Feedback is always welcome

& please rate our talk !