SQL SERVER Broker Priority


           Случалось ли вам работать с механизмом Service Broker или, то бишь с очередями. Механизм очень интересный, первый пришёл, почти первый ушёл. Почему "почти": если в процедуре активации указать receive top n и сообщения будут с одним идентификатором диалога, то из очереди выходят сообщения раньше своей очереди. Но идея статьи не в этом.
           Между двумя промышленными системами идёт обмен с помощью интеграционного решения и механизма очередей на базах данных всех трёх систем. При пиковых нагрузках выходит, что сообщение, наиболее важное по нашему мнению, застревает в очереди из несколько тысяч наименее важных. Соответственно неприятные ожидания и недовольства от бизнеса. Так подошли к решению об использовании приоритетов.
          Расскажу только об одной части этой замечательной схемы, об  приоритетах в очередях MS SQL Server, по шагам. Приоритеты у нас будут 1, 4 и 8.
         Шаг 1. Создаем XML-схему нашего сообщения.

                   CREATE XML SCHEMA COLLECTION PR_DATA_SCHEMA AS
                   N'<?xml version="1.0"  encoding="UTF-16"?>
<xsd:schema elementFormDefault="qualified" xmlns:xsd="http://www.w3.org/2001/XMLSchema" >
<xsd:element name="payload" >
<xsd:complexType >
<xsd:sequence maxOccurs = "1" minOccurs = "1" >
<!--transport elemets-->
<xsd:element name="id" type="xsd:string" />
<xsd:element name="key" type="xsd:string" />
<xsd:element name="value" type="xsd:string" />
</xsd:sequence >
</xsd:complexType>
</xsd:element>
                     </xsd:schema>'

         Шаг 2. Создаем очередь, тип сообщения.

              CREATE QUEUE PR_QUEUE
                  WITH STATUS = ON,
                  POISON_MESSAGE_HANDLING (STATUS = OFF);
              GO

              CREATE MESSAGE TYPE [PR_MESS_TYPE] VALIDATION = VALID_XML 
                  WITH SCHEMA COLLECTION PR_DATA_SCHEMA;
              GO

          Шаг 3. Создаем контракты, сервисы отправителя и получателя на каждый приоритет.

               --Сервисы для сообщений с приоритетом 1
               CREATE CONTRACT [PR_CONTRACT_FIRST] ([PR_MESS_TYPE]
                                                                                                    SENT BY INITIATOR);
               GO
               CREATE SERVICE [PR_SENDER_FIRST]  AUTHORIZATION [dbo]
                       ON QUEUE [dbo].[PR_QUEUE] ([PR_CONTRACT_FIRST])
               GO
               CREATE SERVICE [PR_RECEIVER_FIRST]  AUTHORIZATION [dbo]
                       ON QUEUE [dbo].[PR_QUEUE] ([PR_CONTRACT_FIRST])
               GO

              --Сервисы для сообщений с приоритетом 2
               CREATE CONTRACT [PR_CONTRACT_FOURTH] ([PR_MESS_TYPE]
                                                                                                         SENT BY INITIATOR);
               GO
               CREATE SERVICE [PR_SENDER_FOURTH]  AUTHORIZATION [dbo]
                       ON QUEUE [dbo].[PR_QUEUE] ([PR_CONTRACT_FOURTH])
               GO
               CREATE SERVICE [PR_RECEIVER_FOURTH]  AUTHORIZATION [dbo]
                       ON QUEUE [dbo].[PR_QUEUE] ([PR_CONTRACT_FOURTH])
               GO

               -- Сервисы для сообщений с приоритетом 2
               CREATE CONTRACT [PR_CONTRACT_EIGHT] ([PR_MESS_TYPE]
                                                                                                     SENT BY INITIATOR);
               GO
               CREATE SERVICE [PR_SENDER_EIGHT]  AUTHORIZATION [dbo]
                       ON QUEUE [dbo].[PR_QUEUE] ([PR_CONTRACT_EIGHT])
               GO
               CREATE SERVICE [PR_RECEIVER_EIGHT]  AUTHORIZATION [dbo]
                       ON QUEUE [dbo].[PR_QUEUE] ([PR_CONTRACT_EIGHT])
               GO

         Шаг 4. Оповещаем Broker о необходимых приоритетах. На самом деле, для создания приоритетов не обязательно создавать по 3 различный объекта. Достаточно одного различия, для остальных компонентов в конструкции "CREATE BROKER PRIORITY" указать значение параметра ANY.

              GO
              CREATE BROKER PRIORITY [PRIORITY_FIRST]
              FOR CONVERSATION  SET (
                CONTRACT_NAME = [PR_CONTRACT_FIRST] ,
                LOCAL_SERVICE_NAME = [PR_SENDER_FIRST] ,
                REMOTE_SERVICE_NAME = N'PR_RECEIVER_FIRST' ,
                PRIORITY_LEVEL = 1 )
              GO
              CREATE BROKER PRIORITY [PRIORITY_FOURTH]
              FOR CONVERSATION  SET (
                CONTRACT_NAME = [PR_CONTRACT_FOURTH] ,
                LOCAL_SERVICE_NAME = [PR_SENDER_FOURTH] ,
                REMOTE_SERVICE_NAME = N'PR_RECEIVER_FOURTH' ,
                PRIORITY_LEVEL = 4 )
              GO
              CREATE BROKER PRIORITY [PRIORITY_EIGHT]
              FOR CONVERSATION  SET (
               CONTRACT_NAME = [PR_CONTRACT_EIGHT] ,
               LOCAL_SERVICE_NAME = [PR_SENDER_EIGHT] ,
               REMOTE_SERVICE_NAME = N'PR_RECEIVER_EIGHT' ,
               PRIORITY_LEVEL = 8 )
             GO

         Шаг 5. Заполняем очередь сообщениями с разными приоритетами.

              DECLARE @DIALOG_HANDLE UNIQUEIDENTIFIER
                                , @MESS XML, @i INT
                                , @NAME_SENDER VARCHAR(20)
                                , @NAME_RECEIVER VARCHAR(20)
                                , @NAME_CONTRACT VARCHAR(20);
              SET @i = 1
              WHILE (@i<16)
                  BEGIN

                  IF (@i < 6)
BEGIN
SET @NAME_SENDER = 'PR_SENDER_FIRST'
SET @NAME_RECEIVER = 'PR_RECEIVER_FIRST'
SET @NAME_CONTRACT = 'PR_CONTRACT_FIRST'
END
                  IF (@i >= 6) AND (@i < 11)
BEGIN
SET @NAME_SENDER = 'PR_SENDER_FOURTH'
SET @NAME_RECEIVER = 'PR_RECEIVER_FOURTH'
SET @NAME_CONTRACT = 'PR_CONTRACT_FOURTH'
END
                  IF (@i >= 11) AND (@i < 16)
BEGIN
SET @NAME_SENDER = 'PR_SENDER_EIGHT'
SET @NAME_RECEIVER = 'PR_RECEIVER_EIGHT'
SET @NAME_CONTRACT = 'PR_CONTRACT_EIGHT'
END
   
BEGIN DIALOG CONVERSATION @DIALOG_HANDLE
FROM SERVICE @NAME_RECEIVER TO SERVICE @NAME_SENDER
ON CONTRACT  @NAME_CONTRACT WITH ENCRYPTION = OFF
                  SELECT @MESS = N'<payload><id>' + CAST(@i AS VARCHAR) + '</id><key>' +                                                          CAST(@i + 1000 AS VARCHAR) + '</key><value>AF' +                                                                    CAST(@i AS VARCHAR) + '</value></payload>';
                  SEND ON CONVERSATION @DIALOG_HANDLE MESSAGE TYPE                                                                                [PR_MESS_TYPE] (@MESS)

                  SET @i+=1
                  END;

              SELECT TOP 1000 *, casted_message_body = 
              CASE message_type_name WHEN 'X' 
                   THEN CAST(message_body AS NVARCHAR(MAX)) 
                   ELSE message_body 
              END 
              FROM [DB_PRIOR_QUEUE].[dbo].[PR_QUEUE] WITH(NOLOCK)


         Шаг 6. Выбираем сообщения из очереди. Проверяем правильность выборки, согласно приоритетам.

               WAITFOR (RECEIVE TOP (1)
                                   [PRIORITY],
                                   [CONVERSATION_HANDLE],
                                   [MESSAGE_TYPE_NAME],
                                   [MESSAGE_BODY],
                               [QUEUING_ORDER]
                  FROM [DB_PRIOR_QUEUE].[dbo].[PR_QUEUE]), TIMEOUT 1000;



         Возможность расстановки приоритетов в очередях Service Broker является удобством, особенно в системах с большой загрузкой. Диапазон приоритетов от одного (низкий) до десяти (высокий).

Комментарии

Популярные сообщения из этого блога

SQL SERVER. Автономные транзакции. Autonomous transaction.

ORA-04043: object SYS_PLSQL_XXXXXXXX_XXX_X does not exist