Öncelikli Kuyruk düzeni

Azure Service Bus

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, isteklerin bir hizmet tarafından alınma sırası önemli değildir. Ancak, bazı durumlarda belirli isteklere öncelik tanımak gerekir. Bu istekler, daha önce uygulama tarafından gönderilen düşük öncelikli isteklerden daha önce işlenmelidir.

Çözüm

Kuyruk genellikle ilk gelen ilk çıkar (FIFO) yapısıdır ve tüketiciler genellikle iletileri kuyruğa gönderdikleri sırayla alır. Ancak, bazı ileti kuyrukları öncelikli mesajlaşmayı destekler. İleti gönderen uygulama bir öncelik atayabilir. Kuyruktaki iletiler otomatik olarak yeniden sıralanır, böylece daha yüksek önceliğe sahip olanlar daha düşük önceliğe sahip olanlardan önce alınır. Bu diyagramda şu işlem gösterilmektedir:

İleti önceliklendirmeyi destekleyen bir kuyruğa alma mekanizmasını gösteren diyagram.

Not

İleti kuyruğu uygulamalarının çoğu birden çok tüketiciyi destekler. (Bkz. Rakip Tüketiciler düzeni.) Tüketici işlemlerinin sayısı isteğe bağlı olarak artırılabilir ve 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 öncelikli kuyruklar, düşük öncelikli kuyruklardan daha hızlı donanım üzerinde çalışan daha büyük bir tüketici havuzuna sahip olabilir. Bu diyagramda her öncelik için ayrı ileti kuyrukları kullanımı gösterilmektedir:

Her öncelik için ayrı ileti kuyruklarının kullanımını gösteren diyagram.

Bu stratejinin bir çeşitlemesi, önce yüksek öncelikli kuyruklardaki iletileri denetleyan ve yalnızca daha düşük öncelikli kuyruklardan iletileri almaya başlayan tek bir tüketici havuzu uygulamaktır. Tek bir tüketici işlemleri havuzu kullanan bir çözüm (farklı önceliklere sahip iletileri destekleyen tek bir kuyruğa sahip veya her biri tek öncelikli iletileri işleyen birden çok kuyruğa sahip olan) ve her kuyruk için ayrı bir havuza sahip birden çok kuyruk kullanan bir çözüm arasında bazı anlamsal farklılıklar vardır.

Tek havuzlu yaklaşımda, daha yüksek öncelikli iletiler her zaman düşük öncelikli iletilerden önce alınır ve işlenir. Teoride düşük öncelikli iletilerin yerini sürekli alabilir ve hiçbir zaman işlenemez. Birden çok havuz yaklaşımında, düşük öncelikli iletiler her zaman işlenir, ancak daha yüksek öncelikli iletiler kadar hızlı işlenmez (havuzların göreli boyutuna ve bunlar için kullanılabilir kaynaklara bağlı olarak).

Öncelik kuyruğa alma mekanizmasının kullanılması aşağıdaki avantajları sağlayabilir:

  • Uygulamaların, farklı müşteri gruplarına farklı hizmet düzeyleri sunma gibi kullanılabilirlik veya performans önceliklerinin belirlenmesini gerektiren iş gereksinimlerini karşılamasına olanak tanır.

  • İşletim maliyetlerinin en aza indirilmesine yardımcı olabilir. Tek kuyruklu yaklaşımı kullanırsanız, gerekirse tüketici sayısını yeniden ölçeklendirin. Yüksek öncelikli iletiler yine önce işlenir (büyük olasılıkla daha yavaş olsa da) ve düşük öncelikli iletiler daha uzun süre geciktirilebilir. Her kuyruk için ayrı tüketici havuzlarıyla birden çok ileti kuyruğu yaklaşımını uygularsanız, düşük öncelikli kuyruklar için tüketici havuzunu azaltabilirsiniz. Hatta bu kuyruklardaki iletileri dinleyen tüm tüketicileri durdurarak çok düşük öncelikli kuyruklar için işlemeyi 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, kritik görevlerin önceliklerini, hemen çalışan alıcılar tarafından işlenmeleri ve daha az önemli arka plan görevlerinin daha az meşgul olan zamanlarda çalışacak şekilde zamanlanmış alıcılar tarafından işlenebilmesini sağlayabilirsiniz.

Dikkat edilmesi gerekenler

Bu düzeni nasıl uygulayabileceğinize 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 öncelikli bir ileti 10 saniye içinde işlenmesi gereken bir ileti olarak tanımlanabilir. Yüksek öncelikli öğeleri işleme gereksinimlerini ve ölçütlerinizi karşılamak için ayrılması gereken kaynakları belirleyin.

  • Tüm yüksek öncelikli öğelerin düşük öncelikli öğelerden önce işlenip işlenmeyeceğine karar verin. İletiler tek bir tüketici havuzu tarafından işleniyorsa, kuyruğa daha yüksek öncelikli bir ileti girerse düşük öncelikli bir iletiyi işleyen bir görevi önceden ayarlayıp askıya alabilen bir mekanizma sağlamanız gerekir.

  • Birden çok kuyruk yaklaşımında, her kuyruk için ayrılmış bir tüketici havuzu yerine tüm kuyrukları dinleyen tek bir tüketici işlemleri havuzu kullandığınızda, tüketicinin her zaman daha düşük öncelikli kuyruklardan gelen iletilere daha yüksek öncelikli kuyruklardan gelen iletilere hizmet sunmasını sağlayan bir algoritma uygulaması gerekir.

  • Yüksek ve düşük öncelikli kuyruklardaki işleme hızını izleyerek bu kuyruklardaki iletilerin beklenen hızlarda işlenmesini sağlayın.

  • Düşük öncelikli iletilerin işlendiğini garanti etmeniz gerekiyorsa, birden çok tüketici havuzuyla birden çok ileti kuyruğu yaklaşımını uygulayın. Alternatif olarak, ileti önceliklendirmeyi destekleyen bir kuyrukta, kuyruğa alınan iletinin önceliğini yaşlandıkçe dinamik olarak artırabilirsiniz. Ancak, bu yaklaşım için ileti kuyruğunun bu özelliği sağlaması gereklidir.

  • birkaç iyi tanımlanmış önceliğe sahip sistemler için ileti önceliğine göre ayrı kuyruklar kullanma stratejisi önerilir.

  • Sistem, ileti önceliklerini mantıksal olarak belirleyebilir. Örneğin, açık yüksek ve düşük öncelikli iletilere sahip olmak yerine iletileri "ödeme yapan müşteri" veya "ödemesiz müşteri" olarak belirleyebilirsiniz. Sisteminiz daha sonra ödeme yapan müşterilerden gelen iletileri işlemek için daha fazla kaynak ayırabilir.

  • Bir kuyruğun ileti olup olmadığını denetlemeyle ilişkili bir finansal ve işleme maliyeti olabilir. Örneğin, bazı ticari mesajlaşma sistemleri her ileti gönderildiğinde veya alındığında ve iletiler için her kuyruk sorgulandığında küçük bir ücret alır. Birden çok kuyruğu denetlediğinizde bu maliyet artar.

  • Tüketici havuzunun boyutunu, havuzun hizmet sağladığı kuyruğun uzunluğuna göre dinamik olarak ayarlayabilirsiniz. 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ılara veya kiracılara farklı önceliklerle hizmet verilmelidir.

Örnek

Azure, sıralama yoluyla iletilerin otomatik olarak önceliklendirilmesini yerel olarak destekleyen bir kuyruğa alma mekanizması sağlamaz. Ancak Azure Service Bus konu başlıkları, ileti filtreleme sağlayan bir kuyruğa alma mekanizmasını destekleyen Service Bus abonelikleri ve Azure'ı çoğu öncelik sırası uygulaması için ideal hale getiren çeşitli esnek özellikler sağlar.

Azure çözümü, bir uygulamanın iletileri kuyruğa gönderebileceği gibi gönderebileceği bir Service Bus konusu uygulayabilir. İletiler, uygulama tanımlı özel özellikler biçiminde meta veriler içerebilir. Service Bus aboneliklerini konu başlığıyla ilişkilendirebilir ve abonelikler iletileri özelliklerine göre filtreleyebilir. Uygulama bir konuya ileti gönderdiğinde, ileti tüketicinin okuyabileceği uygun aboneliğe yönlendirilir. Tüketici işlemleri, bir abonelikten ileti kuyruğuyla birlikte kullanacakları semantiği kullanarak iletileri alabilir. (Abonelik mantıksal bir kuyrukdur.) Bu diyagramda Service Bus konu başlıklarını ve aboneliklerini kullanarak öncelik kuyruğu uygulama gösterilmektedir:

Service Bus konu başlıklarını ve aboneliklerini kullanarak öncelik kuyruğu uygulamayı gösteren diyagram.

Önceki diyagramda uygulama birkaç ileti oluşturur ve her iletide adlı Priority özel bir özellik atar. Priorityveya Lowdeğerine High sahiptir. Uygulama bu iletileri bir konuya gönderir. Konu başlığında, özelliğine göre Priority iletileri filtreleyen iki ilişkili abonelik vardır. Bir abonelik, özelliği olarak ayarlanmış Highiletileri Priority kabul eder. Diğeri, özelliği olarak Lowayarlanmış iletileri Priority kabul eder. Her iki abonelikten gelen iletileri bir tüketici havuzu okur. Yüksek öncelikli aboneliğin daha büyük bir havuzu vardır ve bu tüketiciler düşük öncelikli havuz için bilgisayarlardan daha fazla kullanılabilir kaynağa sahip daha güçlü bilgisayarlarda çalışıyor olabilir.

Bu örnekte yüksek ve düşük öncelikli iletilerin belirlenmesinde özel bir şey yoktur. Bunlar yalnızca her iletide özellik olarak belirtilen etiketlerdir. İletileri belirli bir aboneliğe yönlendirmek için kullanılır. Ek öncelikler gerekiyorsa, bu öncelikleri işlemek için daha fazla abonelik ve tüketici işlemi havuzu oluşturmak nispeten kolaydır.

GitHub'da PriorityQueue çözümü bu yaklaşımı temel alır. Bu çözüm ve PriorityQueueConsumerLowadlı PriorityQueueConsumerHigh Azure İşlevi projelerini içerir. Bu Azure İşlevi projeleri, tetikleyiciler ve bağlamalar aracılığıyla Service Bus ile tümleştirilir. bunlar içinde ServiceBusTrigger tanımlanan farklı aboneliklere bağlanır ve gelen iletilere tepki gösterir.

public static class PriorityQueueConsumerHighFn
{
    [FunctionName("HighPriorityQueueConsumerFunction")]
    public static void Run(
      [ServiceBusTrigger("messages", "highPriority", Connection = "ServiceBusConnection")]string highPriorityMessage,
      ILogger log)
    {
        log.LogInformation($"C# ServiceBus topic trigger function processed message: {highPriorityMessage}");
    }
}

Yönetici olarak, Azure App Service üzerindeki işlevlerin ölçeğini genişletebileceği örnek sayısını yapılandırabilirsiniz. Bunu yapmak için Azure portal Ölçeği Genişletme Sınırını Zorla seçeneğini yapılandırabilir ve her işlev için bir ölçek genişletme sınırı üst sınırı ayarlayabilirsiniz. Normalde işlevin işlevinden daha fazla örneğine PriorityQueueConsumerHighPriorityQueueConsumerLow sahip olmanız gerekir. Bu yapılandırma, yüksek öncelikli iletilerin kuyruktan düşük öncelikli iletilere göre daha hızlı okunmasını sağlar.

Başka bir proje olan PriorityQueueSender, her 30 saniyede bir çalışacak şekilde yapılandırılmış zaman ile tetiklenen bir Azure işlevi içerir. Bu işlev, bir çıkış bağlaması aracılığıyla Service Bus ile tümleşir ve bir IAsyncCollector nesneye düşük ve yüksek öncelikli iletilerden oluşan toplu işler gönderir. İşlev, ve PriorityQueueConsumerLow işlevleri tarafından PriorityQueueConsumerHigh kullanılan aboneliklerle ilişkili konuya ileti gönderirken, burada gösterildiği gibi özel özelliğini kullanarak Priority önceliği belirtir:

public static class PriorityQueueSenderFn
{
    [FunctionName("PriorityQueueSenderFunction")]
    public static async Task Run(
        [TimerTrigger("0,30 * * * * *")] TimerInfo myTimer,
        [ServiceBus("messages", Connection = "ServiceBusConnection")] IAsyncCollector<ServiceBusMessage> collector)
    {
        for (int i = 0; i < 10; i++)
        {
            var messageId = Guid.NewGuid().ToString();
            var lpMessage = new ServiceBusMessage() { MessageId = messageId };
            lpMessage.ApplicationProperties["Priority"] = Priority.Low;
            lpMessage.Body = BinaryData.FromString($"Low priority message with Id: {messageId}");
            await collector.AddAsync(lpMessage);

            messageId = Guid.NewGuid().ToString();
            var hpMessage = new ServiceBusMessage() { MessageId = messageId };
            hpMessage.ApplicationProperties["Priority"] = Priority.High;
            hpMessage.Body = BinaryData.FromString($"High priority message with Id: {messageId}");
            await collector.AddAsync(hpMessage);
        }
    }
}

Sonraki adımlar

Bu düzeni uygularken aşağıdaki kaynaklar size yardımcı olabilir:

  • GitHub'da bu düzeni gösteren bir örnek.

  • 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. Bu makalede, istek/yanıt mesajlaşması uygulamak için kullanabileceğiniz stratejiler hakkında bilgi sağlanır.

  • Otomatik ölçeklendirme kılavuzu. Bazen kuyruğu işleyen tüketici işlemleri havuzunun boyutunu kuyruğun uzunluğuna göre ölçeklendikleyebilirsiniz. Bu strateji, özellikle yüksek öncelikli iletileri işleyen havuzlar için performansı artırmanıza yardımcı olabilir.

Bu deseni uygularken aşağıdaki desenler size yardımcı olabilir:

  • Rakip Tüketiciler düzeni. Kuyrukların aktarım hızını artırmak için aynı kuyrukta dinleyen ve görevleri paralel olarak işleyen birden çok tüketici uygulayabilirsiniz. Bu tüketiciler iletiler için rekabet eder, ancak her iletiyi yalnızca bir kişinin işleyebilmesi gerekir. Bu makalede, bu yaklaşımı uygulamanın avantajları ve dezavantajları hakkında daha fazla bilgi sağlanmaktadır.

  • Azaltma düzeni. Kuyrukları kullanarak azaltma uygulayabilirsiniz. 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 verildiğinden emin olmak için öncelikli mesajlaşmayı kullanabilirsiniz.