Konuya girmeden önce; artık blog post’larım django.org.tr gezegeninde yayınlanmakta. Bu yüzden bana tumblr’ın getirtiği baştan salma yazı yazma alışkanlığımı sonlandırmak istiyorum. Başlıksız ya da içeriksiz post atmak her ne kadar güzel olsa da post’lar sadece tumblr üzerinden okunmuyor. Artık özen göstererek yazmak gerekecek :)
Distributed Computing
RabbitMQ, zaten dağıtık hesaplama (distributed computing) konusunda ünlü olan Erlang dili ile geliştirilmiş AMQP(Advanced Message Queuing Protocol) protokolü üzerinde çalışan open-source bir message broker (mesaj kuyruğu diyebiliriz) yazılımıdır. Bu ve bunun gibi message broker yazılımları sayesinde kullandığımız dilden bağımsız bir şekilde yapılması uzun süren işlemleri (hesaplamalar, email vb.) çeşitli makinalara ya da aynı makina üzerindeki birden fazla worker’a dağıtabiliriz.
Gerçek hayattan bir örnek verecek olursak; scale edilmesi gereken bir django uygulamasında request ve response arasında uzun süren işlemler ya da web ile alakası olmayan ayrı bir katmanda yapılan bir iş olmaması gerekmektedir. Misal kullanıcılara bir ya da birden fazla email göndermek, uzun süren hesaplamalar yapmak, kullanıcıya yeni bir demo site açmak gibi …
Requirements;
- Erlang platformu (Linux üzerindeyken RabbitMQ kendisi yüklemekte. Eğer windows üzerinde iseniz şuradan indirip kurabilirsiniz.)
- RabbitMQ Server (Windows’ta iseniz şuradan indirebilirsiniz)
- Kullanacağımız programlama dili için RabbitMQ client kütüphanesi. Örneklerde python için pika kullanacağız. Diğer diller için kütüphaneler şurada.
Paket manager’ımız ile rabbitmq-server’ı yükleyelim.
apt-get install rabbitmq-server
Kurulum bittiğinde server otomatik olarak başlatılacaktır. Şimdi de python kütüphanemizi yükleyelim.
pip install pika
Bu işlem de bittikten sonra yükleyeceğimiz başka bir şey kalmıyor. Örneklere geçebiliriz.
Bir mesaj kuyruğu uygulamasında üç temel yapı vardır; Consumer, Queue ve Publisher.
Consumer
Publisher’dan gelecek olan mesajlar için sürekli dinlemede olan bir nevi sunucudur. Aynı anda birden fazla consumer çalıştırabilirsiniz. RabbitMQ tüm consumer’lara eşit miktarda iş yükü dağıtmaya çalışacaktır.
Queue
Task yani görevlerin saklandığı kuyruktur. Eğer tek consumer var ise bu yapı FIFO (First in First out) yani -ilk giren ilk çıkar- şeklindedir. Zira birden fazla consumer olduğunda RabbitMQ işleri dağıtmaktadır.
Publisher
Consumer’a işleri gönderen uygulamadır. Bu bir django application’ı olabilir.
Şimdi örneğimize geçelim; peş peşe email gönderen bir uygulama simüle edelim. İlk olarak receiver yani consumer uygulamamızı yazalım.
consumer.py içeriği;
import pika, time
def callback(ch, method, properties, body):
print "email gonderiliyor; ", body
time.sleep(1) # gercekci olsun diye 1 saniye bekletiyoruz :)
print "email gonderildi."
def main():
connection = pika.BlockingConnection(pika.ConnectionParameters(host='localhost'))
channel = connection.channel()
channel.queue_declare(queue='mailing')
channel.basic_consume(callback, queue='mailing', no_ack=True)
channel.start_consuming()
if __name__ == "__main__":
main()
Örnekte mailing adında bir kuyruk oluşturduk ve o kuyruk üzerinde consuming işlemini başlattık. Örneği çalıştırdığınızda program dinlemeye geçecektir. Bir mesaj geldiğinde ise oluşturduğumuz callback fonksiyonu mesaj parametresi ile birlikte işlemeye başlayacaktır. Consumer uygulamamızı aşağıdaki gibi başlatalım;
python consumer.py
Şimdi ise publisher’ımızı yazalım.
publisher.py içeriği;
import sys
import pika
def main():
connection = pika.BlockingConnection(pika.ConnectionParameters(host='localhost'))
channel = connection.channel()
channel.queue_declare(queue='mailing')
channel.basic_publish(exchange='', routing_key='mailing',body=sys.argv[1])
connection.close()
if __name__ == "__main__":
main()
Consumer uygulamamızdaki gibi aynı kuyruğa bağlandık ve bu sefer kuyruğa mesaj göndermesini istedik. Publisher uygulamamızı aşağıdaki gibi çalıştırdığımızda dinlemede olan consumer’ımız üzerine görevi yapacaktır.
python publisher.py fatiherikli@gmail.com
Burada önemli olan kısım publisher’dan ziyade consumer uygulamamızın yapılandırmasıdır. Örnekte biz tek bir consumer uygulaması çalıştırdık. Peş peşe publisher.py üzerinden komut göndermeye çalıştığınızda Consumer’ınız sırasıyla gönderdiğiniz komutları çalıştıracaktır.
Şimdi ise consumer.py ‘nizi farklı terminallerde aynı anda çalıştırın. Örnek olarak 3 tane consumer’ınız dinlemede olsun. Publisher’ınız üzerinden peş peşe mesaj göndermeye çalıştığınızda her consumer’da aynı görev sayısı olacak şekilde işlemlerin dağıtıldığını göreceksiniz.
Ayrıca Django ve RabbitMQ etkileşimini daha da kolaylaştıran celery projesini incelemenizi tavsiye ederim;
http://celeryproject.org/