Kaninchen & Schlangen RabbitMQ & Python

Markus Zapke-Gründemann 11. DZUG-Tagung zu Zope, Plone und Python

Markus Zapke-Gründemann
• Softwareentwickler seit 2001 • Schwerpunkt: Web Application Development
mit Python und PHP

• Django, symfony & Zend Framework • Freier Softwareentwickler und Berater
seit 2008

• www.keimlink.de

Übersicht
• Warum Queues? • AMQP • RabbitMQ • Python Bibliotheken • Carrot • Celery

Warum Queues?
• Entkoppeln von Informationsproduzenten
und -konsumenten

• Asynchrone Verarbeitung • Load Balancing • Skalierbarkeit

AMQP
• Advanced Message Queuing Protocol • Offenes Protokoll • Plattformunabhängig • Port 5673/tcp • http://www.amqp.org/

AMQP
• Offener Standard für Messaging Middleware • Virtual Hosts • Exchange (durable oder auto-deleted) • Binding • Queue (durable oder auto-deleted)

Producer - Consumer

Quelle: http://www.redhat.com/docs/en-US/Red_Hat_Enterprise_MRG/1.0/html/Messaging_Tutorial/index.html

Fanout Exchange

Quelle: http://www.redhat.com/docs/en-US/Red_Hat_Enterprise_MRG/1.0/html/Messaging_Tutorial/index.html

Direct Exchange

Quelle: http://www.redhat.com/docs/en-US/Red_Hat_Enterprise_MRG/1.0/html/Messaging_Tutorial/index.html

Topic Exchange

Quelle: http://www.redhat.com/docs/en-US/Red_Hat_Enterprise_MRG/1.0/html/Messaging_Tutorial/index.html

RabbitMQ
• AMQP Message Broker • Erlang • Open Source • Mitglied in der AMQP Working Group • XMPP, SMTP, STOMP und HTTP (mit
Adaptern)

• http://www.rabbitmq.com/

Virtual Host Access Control mit RabbitMQ
$ rabbitmqctl add_user username secret $ rabbitmqctl add_vhost message-vhost $ rabbitmqctl set_permissions -p message-vhost username ".*" ".*" ".*"

Konfiguration Schreiben Lesen

Python Bibliotheken
• amqplib - Python AMQP Client • carrot - AMQP Messaging Framework • pika - Python AMQP Client • txAMQP - Python AMQP Library für Twisted

Carrot
• AMQP Messaging Framework • High-Level Interface • Benutzt amqplib • Serialisierung (Pickle, JSON,YAML) • Autor: Ask Solem • http://github.com/ask/carrot/

conf.py
exchange = 'messaging' queue = 'mbox' routing_key = 'message'

connection.py
from carrot.connection import BrokerConnection conn = BrokerConnection(hostname='localhost', userid='username', password='secret', virtual_host='message-vhost')

publisher.py
import datetime from carrot.messaging import Publisher from carrot.utils import gen_unique_id from conf import exchange, queue, routing_key from connection import conn publisher = Publisher(connection=conn, exchange=exchange, routing_key=routing_key, queue=queue, serializer='pickle') data = {'message_id': gen_unique_id(), 'timestamp': datetime.datetime.now(), 'message': 'Lorem ipsum dolor sit amet.'} publisher.send(data)

consumer.py
from carrot.messaging import Consumer from conf import exchange, queue, routing_key from connection import conn class MessageConsumer(Consumer): def receive(self, message_data, message): data = (message.delivery_tag, message_data['message'], message_data['message_id'], message_data['timestamp'].isoformat()) print 'Message %d "%s" with id %s sent at %s.' % data message.ack() if __name__ == '__main__': consumer = MessageConsumer(connection=conn, queue=queue, exchange=exchange, routing_key=routing_key) consumer.wait()

Celery Distributed Task Queue
• Backends: RabbitMQ, STOMP, Redis, Ghetto
Queue

• Clustering mit RabbitMQ • Webhooks • Django-Integration (optional) • Autor: Ask Solem • http://github.com/ask/celery/

Celery Distributed Task Queue
• Serialisierung (Pickle, JSON,YAML) • Parallele Ausführung • Zeitgesteuerte Ausführung • SQLAlchemy, carrot, anyjson

Python Task
# Task als Klasse from celery.task import Task from myproject.models import User class CreateUserTask(Task): def run(self, username, password): User.create(username, password) >>> from tasks import CreateUserTask >>> CreateUserTask().delay('john', 'secret') # Task als Funktion mit Decorator from celery.decorators import task from myproject.models import User @task() def create_user(username, password): User.create(username, password) >>> from tasks import create_user >>> create_user.delay('john', 'secret')

Python Task
@task() # Benutzt pickle, um das Objekt zu serialisieren. def check_means(user): return user.has_means() >>> from tasks import check_means >>> result = check_means.delay(user) >>> result.ready() # Gibt True zurück wenn der Task beendet ist. False >>> result.result # Task ist noch nicht beendet, kein Ergebnis verfügbar. None >>> result.get() # Warten bis der Task fertig ist und Ergebnis zurückgeben. 93.27 >>> result.result # Jetzt ist ein Ergebnis da. 93.27 >>> result.successful() # War der Task erfolgreich? True

Python Task Konfiguration
# celeryconfig.py BROKER_HOST = "localhost" BROKER_PORT = 5672 BROKER_USER = "myuser" BROKER_PASSWORD = "mypassword" BROKER_VHOST = "myvhost" CELERY_RESULT_BACKEND = "database" CELERY_RESULT_DBURI = "mysql://user:password@host/dbname" CELERY_IMPORTS = ("tasks", )

$ celeryd --loglevel=INFO

Zeitgesteuerter Task
# Periodic task from celery.decorators import periodic_task from datetime import timedelta @periodic_task(run_every=timedelta(seconds=30)) def every_30_seconds(): print("Running periodic task!") # crontab from celery.task.schedules import crontab from celery.decorators import periodic_task @periodic_task(run_every=crontab(hour=7, minute=30, day_of_week=1)) def every_monday_morning(): print("Execute every Monday at 7:30AM.")

$ celerybeat $ celeryd -B

Fotos der Titelfolie
• Kaninchen: Gidzy http://www.flickr.com/
photos/gidzy/3614942864/

• Grüne Python: Frank Wouters - http://

www.flickr.com/photos/frank-wouters/ 540417590/

Lizenz
Dieses Werk ist unter einem Creative Commons Namensnennung-Weitergabe unter gleichen Bedingungen 3.0 Unported Lizenzvertrag lizenziert. Um die Lizenz anzusehen, gehen Sie bitte zu http://creativecommons.org/licenses/by-sa/3.0/ oder schicken Sie einen Brief an Creative Commons, 171 Second Street, Suite 300, San Francisco, California 94105, USA.