Ozz'un daha önce de belirttiği gibi ortak yaklaşım bir mesaj kuyruğu . Tasarım açısından bakıldığında, bir mesaj kuyruğu esasen bir FIFO kuyruğudur ve oldukça temel bir veri türüdür:
Bir ileti kuyruğunu özel kılan, uygulamanızın kuyruktan sorumlu olmakla birlikte, kuyruktan çıkarmadan farklı bir işlemin sorumlu olacağıdır. Kuyruğa alma dilinde, uygulamanız mesajların göndericisidir ve kuyruktan çıkarma işlemi alıcıdır. Bariz avantaj, tüm sürecin asenkron olması, alıcı, işlenecek mesajlar olduğu sürece gönderenden bağımsız olarak çalışmasıdır. Bariz dezavantaj, her şeyin çalışması için ekstra bir bileşene, gönderene ihtiyacınız olmasıdır.
Mimariniz artık mesaj alışverişi yapan iki bileşene dayandığından, bunun için süslü terim süreçler arası iletişimi kullanabilirsiniz .
Kuyruk eklemek uygulamanızın tasarımını nasıl etkiler?
Uygulamanızdaki belirli işlemler e-posta oluşturur. Bir mesaj kuyruğunun tanıtılması, bu eylemlerin artık mesajları bunun yerine kuyruğa göndermesi gerektiği anlamına gelir (ve daha fazlası değil). Bu mesajlar, alıcınız bunları işlediğinde e-postaları oluşturmak için gerekli olan minimum bilgi miktarını taşımalıdır.
Mesajların biçimi ve içeriği
İletilerinizin biçimi ve içeriği tamamen size bağlıdır, ancak ne kadar küçük olursa o kadar iyi olduğunu unutmayın. Sıranız üzerine yazmak ve işlemek için olabildiğince hızlı olmalı, büyük miktarda veri atmak muhtemelen bir darboğaz yaratacaktır.
Ayrıca, birkaç bulut tabanlı kuyruk hizmetinin ileti boyutları üzerinde kısıtlamaları vardır ve daha büyük iletileri bölebilirler. Fark etmeyeceksiniz, bölünmüş mesajlar sizden istendiğinde bir olarak sunulacak, ancak birden fazla mesaj için ücretlendirileceksiniz (elbette ücret gerektiren bir hizmet kullandığınız varsayılarak).
Alıcının tasarımı
Bir web uygulaması hakkında konuştuğumuzdan, alıcınız için ortak bir yaklaşım basit bir cron betiği olacaktır. Her aday olacağını x
dakika (veya saniye) ve it would:
n
Kuyruktaki mesajların pop miktarı,
- Mesajları işleyin (yani e-postaları gönderin).
Get veya getir yerine pop demeye dikkat ediyorum, bunun nedeni alıcınızın yalnızca kuyruktan öğe almaması değil, aynı zamanda bunları da temizlemesidir (yani onları kuyruktan kaldırmak veya işlenmiş olarak işaretlemek). Bunun tam olarak nasıl olacağı, mesaj kuyruğunuzu uygulamanıza ve uygulamanızın özel ihtiyaçlarına bağlıdır.
Tabii ki tanımladığım şey aslında bir toplu işlem , bir kuyruğu işlemenin en basit yolu. İhtiyaçlarınıza bağlı olarak mesajları daha karmaşık bir şekilde işlemek isteyebilirsiniz (bu da daha karmaşık bir sıra gerektirir).
Trafik
Alıcınız trafiği dikkate alabilir ve işlem yaptığı mesaj sayısını çalıştığı sırada trafiğe göre ayarlayabilir. Basit bir yaklaşım, geçmiş trafik verilerine dayalı olarak yüksek trafik saatlerinizi tahmin etmek ve her x
dakika çalışan bir cron komut dosyası ile gittiğinizi varsayarsak, şöyle bir şey yapabilirsiniz:
if(
now() > 2pm && now() < 7pm
) {
process(10);
} else {
process(100);
}
function process(count) {
for(i=0; i<=count; i++) {
message = dequeue();
mail(message)
}
}
Çok saf ve kirli bir yaklaşım, ama işe yarıyor. Değilse, diğer yaklaşım, sunucunuzun her bir yinelemedeki mevcut trafiğini bulmak ve işlem öğelerinin sayısını buna göre ayarlamak olacaktır. Yine de kesinlikle gerekli değilse, mikro optimizasyon yapmayın, zamanınızı boşa harcıyorsunuz.
Kuyruk depolama
Uygulamanız zaten bir veritabanı kullanıyorsa, o zaman tek bir tablo en basit çözüm olacaktır:
CREATE TABLE message_queue (
id int(11) NOT NULL AUTO_INCREMENT,
timestamp timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
processed enum('0','1') NOT NULL DEFAULT '0',
message varchar(255) NOT NULL,
PRIMARY KEY (id),
KEY timestamp (timestamp),
KEY processed (processed)
)
Gerçekten bundan daha karmaşık değil. Elbette ihtiyacınız olduğu kadar karmaşık hale getirebilirsiniz, örneğin, bir öncelik alanı ekleyebilirsiniz (bu, bunun artık bir FIFO kuyruğu olmadığı anlamına gelir, ancak gerçekten ihtiyacınız varsa, kimin umurunda?). Ayrıca, işlenen alanı atlayarak da daha basit hale getirebilirsiniz (ancak satırları işledikten sonra silmeniz gerekir).
Bir veritabanı tablosu günde 2000 mesaj için ideal olurdu, ancak muhtemelen günde milyonlarca mesaj için iyi ölçeklenmeyecektir. Dikkate alınması gereken bir milyon faktör vardır, altyapınızdaki her şey uygulamanızın genel ölçeklenebilirliğinde rol oynar.
Her durumda, veritabanı tabanlı kuyruğu bir darboğaz olarak tanımladığınızı varsayarsak, bir sonraki adım bulut tabanlı bir hizmete bakmak olacaktır. Amazon SQS kullandığım tek hizmetti ve vaat ettiklerini yaptı. Eminim orada birkaç benzer hizmet var.
Bellek tabanlı kuyruklar da, özellikle kısa ömürlü kuyruklar için dikkate alınması gereken bir şeydir. memcached , mesaj kuyruğu depolaması olarak mükemmeldir.
Sıranızı oluşturmaya karar verdiğiniz depolama alanı ne olursa olsun, akıllı olun ve soyutlayın. Ne gönderen ne de alıcınız belirli bir depolama birimine bağlı olmamalıdır, aksi takdirde daha sonra farklı bir depolama birimine geçmek tam bir PITA olacaktır.
Gerçek hayat yaklaşımı
Yaptığınız şeye çok benzeyen e-postalar için bir mesaj kuyruğu oluşturdum. Bir PHP projesindeydim ve Zend Framework'ün farklı depolar için çeşitli adaptörler sunan bir bileşeni olan Zend Queue etrafında oluşturdum . Depolarım nerede:
- Birim testi için PHP dizileri,
- Üretimde Amazon SQS,
- Geliştirme ve test ortamlarında MySQL.
Mesajlarım olabildiğince basitti, uygulamam gerekli bilgileri içeren küçük diziler oluşturdu ( [user_id, reason]
). Mesaj deposu bu dizinin serileştirilmiş bir versiyonuydu (ilk önce PHP'nin dahili serileştirme formatı, sonra JSON, neden geçiş yaptığımı hatırlamıyorum). Bu reason
bir sabit ve tabii ki reason
daha dolgun açıklamalar eşler bir yerde büyük bir tablo var (bir reason
kez daha dolu mesaj yerine şifreli müşterilere yaklaşık 500 e-posta göndermek için başardı ).
daha fazla okuma
Standartlar:
Araçlar:
İlginç okumalar: