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. Выбираем сообщения из очереди. Проверяем правильность выборки, согласно приоритетам.
[PRIORITY],
[CONVERSATION_HANDLE],
[MESSAGE_TYPE_NAME],
[MESSAGE_BODY],
[QUEUING_ORDER]
FROM [DB_PRIOR_QUEUE].[dbo].[PR_QUEUE]), TIMEOUT 1000;
Возможность расстановки приоритетов в очередях Service Broker является удобством, особенно в системах с большой загрузкой. Диапазон приоритетов от одного (низкий) до десяти (высокий).
Комментарии
Отправить комментарий