簡體   English   中英

如何使用多個WCF服務實例強制實施消息隊列序列

[英]How to enforce message queue sequence with multiple WCF service instances

我想創建一個使用MSMQ綁定的WCF服務,因為我有大量的服務要處理的通知。 重要的是客戶端不會受到服務的阻礙,並且通知按照引發的順序進行處理,從而實現隊列實現。

另一個考慮因素是彈性。 我知道我可以集群MSMQ本身使隊列更加健壯,但我希望能夠在不同的服務器上運行我的服務實例,所以如果服務器崩潰通知不會在隊列中積累但是另一台服務器繼續進行處理。

我已經嘗試了MSMQ綁定,並發現您可以讓多個服務實例在同一個隊列上進行偵聽,並留給自己最終做了一種循環,負載分布在可用的服務上。 這很好,但我最終失去了隊列的排序,因為不同的實例需要不同的時間來處理請求。

我一直在使用一個簡單的控制台應用程序進行實驗,這是下面的史詩代碼轉儲。 當它運行時,我得到這樣的輸出:

host1 open
host2 open
S1: 01
S1: 03
S1: 05
S2: 02
S1: 06
S1: 08
S1: 09
S2: 04
S1: 10
host1 closed
S2: 07
host2 closed

我想要發生的是:

host1 open
host2 open
S1: 01
<pause while S2 completes>
S2: 02
S1: 03
<pause while S2 completes>
S2: 04
S1: 05
S1: 06
etc.

我原以為,由於S2還沒有完成,它可能仍會失敗,並將正在處理的消息返回給隊列。 因此,不應允許S1從隊列中拉出另一條消息。 我的隊列是事務性的,我已經嘗試在服務上設置TransactionScopeRequired = true但無濟於事。

這甚至可能嗎? 我是以錯誤的方式去做的嗎? 是否有其他方法可以在沒有某種中央同步機制的情況下構建故障轉移服務?

class WcfMsmqProgram
{
    private const string QueueName = "testq1";

    static void Main()
    {
        // Create a transactional queue
        string qPath = ".\\private$\\" + QueueName;
        if (!MessageQueue.Exists(qPath))
            MessageQueue.Create(qPath, true);
        else
            new MessageQueue(qPath).Purge();

        // S1 processes as fast as it can
        IService s1 = new ServiceImpl("S1");
        // S2 is slow
        IService s2 = new ServiceImpl("S2", 2000);

        // MSMQ binding
        NetMsmqBinding binding = new NetMsmqBinding(NetMsmqSecurityMode.None);

        // Host S1
        ServiceHost host1 = new ServiceHost(s1, new Uri("net.msmq://localhost/private"));
        ConfigureService(host1, binding);
        host1.Open();
        Console.WriteLine("host1 open");

        // Host S2
        ServiceHost host2 = new ServiceHost(s2, new Uri("net.msmq://localhost/private"));
        ConfigureService(host2, binding);
        host2.Open();
        Console.WriteLine("host2 open");

        // Create a client 
        ChannelFactory<IService> factory = new ChannelFactory<IService>(binding, new EndpointAddress("net.msmq://localhost/private/" + QueueName));
        IService client = factory.CreateChannel();

        // Periodically call the service with a new number
        int counter = 1;
        using (Timer t = new Timer(o => client.EchoNumber(counter++), null, 0, 500))
        {
            // Enter to stop
            Console.ReadLine();
        }

        host1.Close();
        Console.WriteLine("host1 closed");
        host2.Close();
        Console.WriteLine("host2 closed");

        // Wait for exit
        Console.ReadLine();
    }

    static void ConfigureService(ServiceHost host, NetMsmqBinding binding)
    {
        var endpoint = host.AddServiceEndpoint(typeof(IService), binding, QueueName);
    }

    [ServiceContract]
    interface IService
    {
        [OperationContract(IsOneWay = true)]
        void EchoNumber(int number);
    }

    [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
    class ServiceImpl : IService
    {
        public ServiceImpl(string name, int sleep = 0)
        {
            this.name = name;
            this.sleep = sleep;
        }

        private string name;
        private int sleep;

        public void EchoNumber(int number)
        {
            Thread.Sleep(this.sleep);
            Console.WriteLine("{0}: {1:00}", this.name, number);
        }
    }
}

batwad,

您正在嘗試手動創建服務總線。 你為什么不嘗試使用現有的?

NServiceBus,MassTransit,ServiceStack

其中至少有2個與MSMQ合作。

此外,如果您絕對需要訂購,它實際上可能是出於另一個原因 - 您希望能夠發送消息,並且您不希望在第一條消息之前處理相關消息。 您正在尋找Saga Pattern。 NServiceBus和MassTransit都允許您輕松管理Sagas,它們都允許您簡單地觸發初始消息,然后根據條件觸發剩余消息。 它將允許您快速實現分布式應用程序的豐滿。

然后,您甚至可以擴展到數千個客戶端,隊列服務器和消息處理器,而無需編寫任何代碼,也不會出現任何問題。

我們試圖在這里通過msmq實現我們自己的服務總線,我們放棄了,因為另一個問題不斷蔓延。 我們選擇了NServiceBus,但MassTransit也是一款出色的產品(它是100%的開源,NServiceBus不是)。 ServiceStack在制作API和使用消息隊列方面非常出色 - 我相信你可以用它來制作幾分鍾內充當隊列前端的服務。

哦,我是否提到過,在NSB和MT的情況下,只需要10行代碼就可以完全實現隊列,發送者和處理程序?

- - - 添加 - - -

Udi Dahan(NServiceBus的主要貢獻者之一)談到了這一點: Udi Dahan的 按順序傳遞一個神話” “消息排序:它是否具有成本效益?” 與烏迪達漢

Chris Patterson(公共交通的主要貢獻者之一) “使用Sagas確保正確的順序消息順序”問題

StackOverflow問題/答案: “在WCF應用程序中使用MSMQ消息時保留消息順序”

- - - 題 - - -

我必須說,我很困惑為什么你需要保證消息順序 - 如果你使用HTTP / SOAP協議,你會處於相同的位置嗎? 我的猜測是否定的,那為什么它在MSMQ中是一個問題?

祝你好運,希望這會有幫助,

確保按順序傳遞消息是高容量消息傳遞的事實上的棘手問題之一。

在理想的世界中,您的消息目標應該能夠處理無序消息傳遞。 這可以通過確保您的消息源包含某種排序信息來實現。 理想情況下,它采用某種x-of-n批量標記的形式(消息1的10,2的10,等等)。 然后,您的消息目標需要在交付后將數據按順序組合。

但是,在現實世界中,通常沒有改變下游系統來處理無序到達的消息的空間。 在這種情況下,您有兩個選擇:

  1. 完全單線程 - 實際上你通常可以找到某種'grouping id',這意味着你可以在for-each-group意義上使用單線程,這意味着你仍然可以在不同的消息組中實現並發。
  2. 在您希望接收按順序消息的每個消費者系統周圍實施重新定序器包裝器。

這兩種解決方案都不是很好,但這是我認為你可以擁有並發和有序消息傳遞的唯一方法。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM