Öncelikli Kuyruk düzeni
Yüksek öncelikli isteklerin düşük öncelikli olanlardan daha önce alınması ve işlenmesini sağlamak için hizmete gönderilen isteklerin önceliklerini belirleyin. Bu düzen, ayrı ayrı istemcilere farklı hizmet düzeyi garantileri sunan uygulamalarda kullanışlıdır.
Bağlam ve sorun
Uygulamalar, arka plan işlemleri gerçekleştirme ya da diğer uygulama veya hizmetler ile tümleştirme gibi amaçlarla belirli görevler için diğer hizmetleri temsilci seçebilir. Bulutta arka planda işleme amacıyla göreve temsilci atamak için genelde bir ileti kuyruğu kullanılır. Çoğu durumda hizmetin istekleri alma sırası önemli değildir. Ancak, bazı durumlarda belirli isteklere öncelik tanımak gerekir. Bu istekler, uygulama tarafından daha önce gönderilen daha düşük öncelikli isteklerden daha önce işlenmelidir.
Çözüm
Kuyruklar, çoğunlukla ilk giren ilk çıkar (FIFO) yapısındadır ve tüketiciler genelde iletileri kuyruğa gönderildiği sırada alır. Ancak, bazı ileti kuyrukları öncelikli mesajlaşmayı destekler. İleti gönderen uygulama bu iletiye bir öncelik atayabilir. Bu durumda, kuyruktaki iletiler otomatik olarak yeniden sıralanır. Böylece yüksek öncelikli iletilerin daha düşük öncelikli olanlardan daha önce alınması sağlanır. Şekilde öncelikli mesajlaşma içeren bir kuyruk gösterilmektedir.

İleti kuyruğu uygulamalarının çoğu birden fazla tüketiciyi destekler (Rakip Tüketiciler düzenini izleyerek) ve tüketici işlemlerinin sayısında talebe bağlı olarak ölçek artırılıp azaltılabilir.
Öncelik tabanlı ileti kuyruklarını desteklemeyen sistemler için alternatif bir çözüm her bir öncelik için ayrı bir kuyruk sürdürmektir. Uygulama, iletilerin uygun kuyruğa gönderilmesinden sorumludur. Her bir kuyruğun ayrı bir tüketici havuzu olabilir. Yüksek öncelik kuyrukların, düşük öncelikli kuyruklara göre daha hızlı donanımlar üzerinde çalışan daha büyük bir tüketici havuzu olabilir. Aşağıdaki şekilde her bir öncelik için ayrı ileti kuyrukları kullanılması gösterilmektedir.

Bu stratejinin farklı bir versiyonu, tek bir tüketici havuzu kullanılıp önce yüksek öncelikli kuyruklarda ileti olup olmadığının denetlenmesi, ancak bundan sonra düşük öncelikli kuyruklardaki iletilerin getirilmesidir. Tek bir tüketici işlemleri havuzunu kullanan (farklı önceliklere sahip iletileri destekleyen tek bir kuyruk veya her biri tek bir önceliğe sahip iletileri işleyen birden fazla kuyruk aracılığıyla) bir çözüm ile her bir kuyruk için ayrı bir havuzun olduğu birden fazla kuyruk kullanan bir çözüm arasında anlamsal bazı farklar vardır.
Tek havuzlu yaklaşımda yüksek öncelikli iletiler her zaman düşük öncelikli iletilerden daha önce alınıp işlenir. Teorik olarak, çok düşük öncelikli iletiler sürekli geriye düşüp hiçbir zaman işlenmeyebilir. Birden fazla havuzlu yaklaşımda düşük öncelikli iletiler her zaman işlenir. Sadece bu işleme, yüksek öncelikli iletiler için olduğu kadar hızlı olmaz (havuzların birbirlerine göre boyutlarına ve kullanabilecekleri kaynaklara bağlı olarak).
Öncelikli bir kuyruğa alma mekanizmasının kullanılması aşağıdaki avantajları sağlayabilir:
Uygulamaların kullanılabilirlik veya performans için öncelik belirlenmesini gerektiren iş gereksinimlerini karşılamasına olanak sağlar. Örneğin, belirli müşteri gruplarına farklı düzeylerde hizmet sunulabilir.
İşletim maliyetlerinin en aza indirilmesine yardımcı olabilir. Tek kuyruklu yaklaşımda gerekirse tüketici sayısının ölçeğini küçültebilirsiniz. Yüksek öncelikli iletiler yine ilk olarak işlenir (ancak büyük olasılıkla daha yavaş bir şekilde) ve düşük öncelikli iletiler daha uzun bir süre için ertelenebilir. Her bir kuyruk için ayrı bir tüketici havuzu içeren birden fazla ileti kuyruğu yaklaşımını uyguladıysanız düşük öncelikli kuyruklar için tüketici havuzunu küçültebilir hatta çok düşük öncelik kuyruklarda ileti olup olmadığını dinleyen tüm tüketicileri durdurarak bu kuyrukların işlemlerini askıya alabilirsiniz.
Birden fazla ileti kuyruğu yaklaşımı, iletileri işleme gereksinimlerine bağlı olarak bölümleyerek uygulama performansı ve ölçeklenebilirliğinin en üst düzeye çıkarılmasına yardımcı olabilir. Örneğin, çok önemli görevler hemen çalıştırılan alıcılar tarafından işlenecek şekilde önceliklendirilebilir. Önemi daha düşük arka plan görevleri de daha az meşgul zamanlarda çalıştırılması zamanlanan alıcılar tarafından işlenebilir.
Sorunlar ve dikkat edilmesi gerekenler
Bu düzenin nasıl uygulanacağına karar verirken aşağıdaki noktaları göz önünde bulundurun:
Öncelikleri, çözümün bağlamında tanımlayın. Örneğin, yüksek öncelik iletilerin on saniye içinde işlenmesi gerektiği anlamına gelebilir. Yüksek öncelikli öğeleri işleme gereksinimlerini ve bu ölçütlere uymak için ayrılacak olan diğer kaynakları belirleyin.
Düşük öncelikli öğelere geçmeden önce tüm yüksek öncelikli öğelerin işlenmesinin gerekip gerekmediğine karar verin. İletiler tek bir tüketici havuzu tarafından işleniyorsa daha yüksek öncelikli bir ileti kullanılabilir hale geldiğinde düşük öncelikli bir iletiyi işlemekte olan bir görevi etkisiz hale getirip askıya alacak bir mekanizma sağlamanız gerekir.
Birden fazla kuyruklu yaklaşımda her kuyruk için adanmış bir tüketici havuzu yerine tüm kuyrukları dinleyen tek bir tüketici işlemleri havuzu kullanıyorsanız tüketici, düşük öncelikli kuyruklardaki iletilere geçmeden önce her zaman yüksek öncelikli kuyruklardaki iletilere hizmet sunmasını sağlayan bir algoritma uygulamalıdır.
Yüksek ve düşük öncelikli kuyruklardaki işleme hızını izleyerek bu kuyruklardaki iletilerin beklenen hızlarda işlendiğinden emin olun.
Düşük öncelikli iletilerin işleneceğini garantilemeye ihtiyacınız varsa birden fazla tüketici havuzu içeren birden fazla ileti kuyruğu yaklaşımını uygulamak gereklidir. Alternatif olarak, ileti önceliği belirlemeyi destekleyen bir kuyrukta kuyruğa alınmış bir ileti eskidikçe iletinin önceliğini dinamik olarak artırmak mümkündür. Ancak, bu yaklaşım için ileti kuyruğunun bu özelliği sağlaması gereklidir.
Her bir ileti önceliği için ayrı bir kuyruk kullanılması, en çok az sayıda iyi tanımlanmış önceliğe sahip sistemler için uygundur.
İleti öncelikleri sistem tarafından mantıksal olarak belirlenebilir. Örneğin, açık yüksek ve düşük öncelikli iletilere sahip olmak yerine"ücret ödeyen müşteri" veya "ücret ödemeyen müşteri" olarak belirlenebilirsiniz. İş modelinize bağlı olarak, sisteminiz ücret ödeyen müşterilerden gelen iletileri işlemeye ücret ödemeyen müşterilere göre daha fazla kaynak ayırabilirsiniz.
Bir kuyrukta ileti olup olmadığını denetlemeye ait bir finansal ve işleme maliyeti olabilir (bazı ticari mesajlaşma sistemleri her ileti gönderildiğinde veya alındığında ve bir kuyrukta ileti olup olmadığı her sorgulandığında küçük bir ücret alır). Birden fazla kuyruk denetlendiğinde bu maliyet artar.
Bir tüketici havuzunun boyutunu, hizmet verdiği kuyruğun uzunluğuna göre dinamik olarak ayarlamak mümkündür. Daha fazla bilgi için bkz. Otomatik Ölçeklendirme Kılavuzu.
Bu düzenin kullanılacağı durumlar
Bu düzen, aşağıdakilerin geçerli olduğu senaryolarda kullanışlıdır:
Sistem farklı önceliklere sahip birden çok görevi işlemelidir.
Farklı kullanıcı veya kiracılara farklı önceliklerle hizmet sunulması gereklidir.
Örnek
Microsoft Azure, sıralama aracılığıyla iletilerin önceliklerinin otomatik belirlenmesini yerel olarak destekleyen bir kuyruğa alma mekanizması sağlamaz. Ancak, bir kuyruğa alma mekanizmasını destekleyen Azure Service Bus konuları ve abonelikleri sağlar. Bu mekanizma, ileti filtrelemenin yanı sıra kendisini birçok öncelikli kuyruk uygulamasında kullanım için ideal kılan çok sayıda esnek özellik sunar.
Azure çözümleri, uygulamaların aynen bir kuyruğa gönderir gibi ileti gönderebilecekleri bir Service Bus konusu uygulayabilir. İletiler, uygulama tanımlı özel özellikler biçiminde meta veriler içerebilir. Service Bus abonelikleri konu ile ilişkilendirilebilir ve bu abonelikler iletileri özelliklerine göre filtreleyebilir. Bir uygulama bir konuya ileti gönderdiğinde ileti tüketiciler tarafından okunabileceği uygun aboneliğe yönlendirilir. Tüketici işlemleri, bir ileti kuyruğuyla aynı semantiği kullanarak bir abonelikten ileti alabilir (abonelik, mantıksal bir kuyruktur). Aşağıdaki şekilde, Azure Service Bus konuları ve abonelikleri aracılığıyla öncelikli bir kuyruk uygulanması gösterilmektedir.

Yukarıdaki şekilde, uygulama çeşitli iletiler oluşturur ve her iletiye High veya Low değerine sahip Priority adlı bir özel özellik atar. Uygulama bu iletileri bir konuya gönderir. Konuyla ilişkili iki abonelik de Priority özelliğini inceleyerek iletileri filtreler. Bir abonelik Priority özelliğinin High olarak ayarlanmış olduğu iletileri ve diğer abonelik de Priority özelliğinin Low olarak ayarlanmış olduğu iletileri kabul eder. Her iki abonelikten gelen iletileri bir tüketici havuzu okur. Yüksek öncelikli aboneliğin havuzu daha büyüktür ve bu tüketiciler düşük öncelikli havuzdaki tüketicilere göre daha fazla kaynağa sahip, daha güçlü bilgisayarlarda çalıştırılıyor olabilir.
Bu örnekte yüksek ve düşük öncelikli iletilerin atanması hakkında özel bir şey olmadığına dikkat edin. Bunlar, yalnızca her iletide özellik olarak belirtilen etiketlerdir ve iletileri belirli bir aboneliğe yönlendirmek için kullanılmaktadır. Ek öncelikler gerekirse bu öncelikleri işlemek için kolayca başka abonelikler ve tüketici işlemi havuzları oluşturulabilir.
GitHub’dan edinilebilecek PriorityQueue çözümü bu yaklaşımın bir uygulamasını içerir. Bu çözüm, PriorityQueue.High ve PriorityQueue.Low adlı iki çalışan rolü projesi içerir. Bu çalışan rolleri, OnStart yöntemindeki belirtilen bir aboneliğe bağlanma işlevini içeren PriorityWorkerRole sınıfından devralır.
PriorityQueue.High ve PriorityQueue.Low çalışan rolleri, yapılandırma ayarları tarafından tanımlanan farklı aboneliklere bağlanır. Bir yönetici, her rolün çalıştırılacağı farklı bir sayı yapılandırabilir. Genellikle PriorityQueue.High çalışan rolünün PriorityQueue.Low çalışan rolüne göre daha fazla örneği olacaktır.
PriorityWorkerRole sınıfındaki Run yöntemi, kuyrukta alınan her ileti için sanal ProcessMessage yönteminin (yine PriorityWorkerRole sınıfında tanımlanan) çalıştırılmasını düzenler. Aşağıdaki kod, Run ve ProcessMessage yöntemlerini göstermektedir. PriorityQueue.Shared projesinde tanımlanan QueueManager sınıfı, Azure Service Bus kuyruklarını kullanmaya yönelik yardımcı yöntemler sağlar.
public class PriorityWorkerRole : RoleEntryPoint
{
private QueueManager queueManager;
...
public override void Run()
{
// Start listening for messages on the subscription.
var subscriptionName = CloudConfigurationManager.GetSetting("SubscriptionName");
this.queueManager.ReceiveMessages(subscriptionName, this.ProcessMessage);
...;
}
...
protected virtual async Task ProcessMessage(BrokeredMessage message)
{
// Simulating processing.
await Task.Delay(TimeSpan.FromSeconds(2));
}
}
PriorityQueue.High ve PriorityQueue.Low çalışan rollerinin her ikisi de ProcessMessage yönteminin varsayılan işlevlerini geçersiz kılar. Aşağıdaki kod, PriorityQueue.High çalışan rolüne ilişkin ProcessMessage yöntemini göstermektedir.
protected override async Task ProcessMessage(BrokeredMessage message)
{
// Simulate message processing for High priority messages.
await base.ProcessMessage(message);
Trace.TraceInformation("High priority message processed by " +
RoleEnvironment.CurrentRoleInstance.Id + " MessageId: " + message.MessageId);
}
Bir uygulama, PriorityQueue.High ve PriorityQueue.Low çalışan rolleri tarafından kullanılan abonelikler ile ilişkili konuya ileti gönderirken aşağıdaki kod örneğinde gösterildiği gibi Priority özel özelliğini kullanarak önceliği belirtir. Bu kod (PriorityQueue.Sender projesindeki WorkerRole sınıfında uygulanır) bir konuya toplu olarak ileti göndermek için QueueManager sınıfının SendBatchAsync yardımcı yöntemini kullanır.
// Send a low priority batch.
var lowMessages = new List<BrokeredMessage>();
for (int i = 0; i < 10; i++)
{
var message = new BrokeredMessage() { MessageId = Guid.NewGuid().ToString() };
message.Properties["Priority"] = Priority.Low;
lowMessages.Add(message);
}
this.queueManager.SendBatchAsync(lowMessages).Wait();
...
// Send a high priority batch.
var highMessages = new List<BrokeredMessage>();
for (int i = 0; i < 10; i++)
{
var message = new BrokeredMessage() { MessageId = Guid.NewGuid().ToString() };
message.Properties["Priority"] = Priority.High;
highMessages.Add(message);
}
this.queueManager.SendBatchAsync(highMessages).Wait();
Sonraki adımlar
Bu düzeni uygularken aşağıdaki yönergeler de yararlı olabilir:
Bu düzeni gösteren bir örnek GitHub’dan edinilebilir.
Zaman Uyumsuz Mesajlaşma Temel Bilgileri. Bir isteği işleyen bir tüketici hizmetinin isteği gönderen uygulama örneğine bir yanıt göndermesi gerekebilir. İstek/yanıt iletilerini uygulamak için kullanabileceğiniz stratejiler hakkında bilgiler sunulmaktadır.
Otomatik Ölçeklendirme Kılavuzu. Bir kuyruğu işleyen tüketici işlemleri havuzunun boyutunu kuyruğun uzunluğuna bağlı olarak ölçeklendirmek mümkün olabilir. Bu strateji, özellikle yüksek öncelikli iletileri işleyen havuzların performansını artırmak için yardımcı olabilir.
İlgili düzenler ve kılavuzlar
Bu düzeni uygularken aşağıdaki desenler de ilgili olabilir:
Rekabet tüketicilere yönelik desenler. Kuyrukların aktarım hızını artırmak için, aynı kuyruğu dinleyen birden çok tüketiciye sahip olmak ve görevleri paralel olarak işlemek mümkündür. Bu tüketiciler iletiler için rekabete girer, ancak her bir iletiyi yalnızca tek bir tüketici işleyebilmelidir. Bu yaklaşımı uygulamanın avantajları ve dezavantajları hakkında daha fazla bilgi sağlanmaktadır.
Daraltma kriteri. Kuyrukları kullanarak azaltma uygulayabilirsiniz. Öncelikli mesajlaşma kullanılarak kritik uygulamalardan veya yüksek değerli müşteriler tarafından çalıştırılan uygulamalardan gelen isteklere daha az önemli uygulamalardan gelen isteklere göre öncelik verilmesi sağlanabilir.
abhishek lal 'nin bloguna Service Bus sahip desenler Kurumsal Tümleştirme .