Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / Microsoft SQL Server Новый топик    Ответить
 проблема при работе сервис брокера  [new]
Fly1
Member

Откуда:
Сообщений: 6
Здравствуйте, коллеги.

Не так часто приходится обращаться с вопросами, т.к. поиск обычно выручает, но сейчас возникла проблема, с которой не смог разобраться.

В SQL Server 2008 Standard существует обработчик очереди service broker, который производит некоторые расчеты и записывает их в базу. Примерно в одном из 5 000 – 25 000 вызовов запись не происходит.

Я понимаю, что это противоречит официальной позиции касательно сервис брокера, которая гласит что при возникновении ошибок механизм сам делает повторный запуск процедуры, но у меня повторного запуска не происходит.

Чтобы разобраться с проблемой я завел систему логирования:

ALTER PROC [dlfe].[PortfolioProcessJournalEntry]
AS

DECLARE @Handle	uniqueidentifier
	,@Msg	varchar(MAX)
	,@MsgType	varchar(256)
	,@EntryId	int
	,@RC		int

;WAITFOR(RECEIVE TOP (1) @Handle = conversation_handle,@Msg = message_body,@MsgType = message_type_name	FROM PortfolioTargetQueue)
IF(@MsgType = 'JournalEntry')
BEGIN
	
	SET XACT_ABORT ON
	SET DEADLOCK_PRIORITY	-5

	SET @EntryId = CAST(@Msg AS int)
	INSERT INTO dbo.ServiceBrockerLog(
		EntryId
		, CompleteCode
		, InsertStamp
		)  
		VALUES (
			@EntryId
			, NULL
			, GETDATE()
			)
	
	BEGIN TRY
		EXEC @RC = dlfe.PortfolioMakeEntryChanges @EntryId
	END TRY
	BEGIN CATCH
		ROLLBACK TRANSACTION
		RAISERROR('все плохо, жрать нечего',16,1)
		RETURN -1
	END CATCH

	UPDATE dbo.ServiceBrockerLog
		SET CompleteCode	= @RC
			,EditStamp		= GETDATE()
		WHERE EntryId = @EntryId

END
END CONVERSATION @Handle


Запись в очередь:
ALTER PROC [gaap].[SendJournalEntryToPortal]	
	@EntryId	int
	,@DoServiceBrockerRealTime	bit = 0
AS

IF(@DoServiceBrockerRealTime = 0)
BEGIN
	DECLARE @conversationHandle uniqueidentifier

	BEGIN TRANSACTION
	EXECUTE AS USER = 'portfolio';
		-- Start dialog.
		BEGIN DIALOG  @conversationHandle
			FROM SERVICE    PortfolioInitiatorService
			TO SERVICE      'PortfolioTargetService'
			ON CONTRACT     JournalEntryContract
			WITH ENCRYPTION = OFF, LIFETIME = 86400;

		-- Send message.
		SEND ON CONVERSATION @conversationHandle 
			MESSAGE TYPE JournalEntry (CAST(@EntryId AS varchar(20)))
	REVERT;
	COMMIT
END
ELSE
BEGIN

	EXEC dlfe.PortfolioMakeEntryChanges @EntryId = @EntryId

END


Создание очереди:
CREATE MESSAGE TYPE JournalEntry
CREATE CONTRACT JournalEntryContract(JournalEntry SENT BY INITIATOR)

--GAAP
CREATE QUEUE PortfolioInitiatorQueue	WITH STATUS = ON	,ACTIVATION (PROCEDURE_NAME = gaap.PortfolioProcessJournalEntry,MAX_QUEUE_READERS = 1,EXECUTE AS 'portfolio')
CREATE SERVICE PortfolioInitiatorService ON QUEUE PortfolioInitiatorQueue(JournalEntryContract)

GRANT RECEIVE ON PortfolioInitiatorQueue TO portfolio
GRANT SEND ON SERVICE::PortfolioInitiatorService TO portfolio

--Portal
CREATE QUEUE PortfolioTargetQueue	WITH STATUS = ON,	ACTIVATION (PROCEDURE_NAME = dlfe.PortfolioProcessJournalEntry,MAX_QUEUE_READERS = 1,EXECUTE AS 'portfolio')
CREATE SERVICE PortfolioTargetService ON QUEUE PortfolioTargetQueue(JournalEntryContract)

GRANT RECEIVE ON PortfolioTargetQueue TO portfolio
GRANT SEND ON SERVICE::PortfolioTargetService TO portfolio



В результате при очередном сбое я получил результаты, которые у меня совсем в голове не укладываются, вот 9 проводок подряд которые не записались в базу:

Номер проводки началась обработка зафиксирована обработка
8985594 17:46:18 17:46:18
8985595 17:46:18 17:46:19
8985596 17:46:19 17:46:19
8985597 17:46:19 нулл
8985598 17:46:21 нулл
8985599 17:46:26 нулл
8985600 17:46:28 нулл
8985601 17:46:29 17:46:29
8985602 17:46:30 17:46:30


Таким образом, получается что при выполнении процедуры записи произошла ошибка (вполне возможный дэдлок) но это не помешало системе логирования записать для 5 проводок из 9 что процедура выполнена успешно.

Сервис брокером я пользуюсь уже более двух лет, настраивал и для разных машин и внутри одного инстанса. Последние пол года пытаюсь избавиться от этой проблемы, но не получается. Происходит один-два раза в месяц.

Что я делаю не так?
2 апр 12, 03:48    [12348678]     Ответить | Цитировать Сообщить модератору
 Re: проблема при работе сервис брокера  [new]
mike909
Member

Откуда:
Сообщений: 662
Fly1
Здравствуйте, коллеги.

Не так часто приходится обращаться с вопросами, т.к. поиск обычно выручает, но сейчас возникла проблема, с которой не смог разобраться.

В SQL Server 2008 Standard существует обработчик очереди service broker, который производит некоторые расчеты и записывает их в базу. Примерно в одном из 5 000 – 25 000 вызовов запись не происходит.

Я понимаю, что это противоречит официальной позиции касательно сервис брокера, которая гласит что при возникновении ошибок механизм сам делает повторный запуск процедуры, но у меня повторного запуска не происходит.

Оффициальная позиция (BOL) говорит
Инструкция RECEIVE удаляет полученные сообщения из очереди, если только очередь не указывает сохранение сообщений. 
Если параметр RETENTION для очереди установлен в ON, инструкция RECEIVE устанавливает столбец status в 0 и оставляет сообщение в очереди.
При откате транзакции, содержащей инструкцию RECEIVE, производится также откат всех изменений в очереди в пределах транзакции;
сообщения при этом возвращаются в очередь.
Иными словами, если у Вас повторного запуска не происходит, следовательно Вы читаете сообщения из очереди в одной транзвкции, а обработку проводите в другой транзакции. Как следствие - потеря сбойного сообщения.
Ваш код по обработке "логирования" как раз такой. Впрочем, для системы логирования он вполне приемлем.
Чудеса с логированием могут быть еще связаны и с тем, что Ваша SP_шка [gaap].[SendJournalEntryToPortal] может быть успешно вызвана в контексте транзакции обработки до возникновения ошибки, которая и откатит отсылку сообщения. Например:
begin try
  begin tran
  exec [gaap].[SendJournalEntryToPortal] --- bla,bla,bla
  select 1/0
end try
begin catch
  rollback tran
end catch
commit tran

Сообщение не уйдет.
Пара советов:
1) Проверьте код обработки на предмет работы в одной транзакции. Или примите меры в секции catch по сохранению сбойного сообщения.
2) Замените систему логирования например на такую
2 апр 12, 11:11    [12349485]     Ответить | Цитировать Сообщить модератору
 Re: проблема при работе сервис брокера  [new]
Fly1
Member

Откуда:
Сообщений: 6
mike909,

Спасибо,

Заменил финальную часть логирования на:

	UPDATE dbo.ServiceBrockerLog
		SET CompleteCode	= @@TRANCOUNT--@RC
			,EditStamp	= GETDATE()
		WHERE EntryId = @EntryId

Получил значение 2, т.е. транзакция однозначно открыта в рамках всей процедуры, т.к. сам я ее не открывал.

Предположив что блок TRY/CATCH отрабатывает не так, как я того ожидаю из-за чего ошибка не эскалирется механизму сервис брокера, из-за чего не происходит повторного исполнения процедуры, заменил его на использование XACT_STATE().

Получилось:
ALTER PROC [dlfe].[PortfolioProcessJournalEntry]
AS

DECLARE @Handle    uniqueidentifier
    ,@Msg    varchar(MAX)
    ,@MsgType    varchar(256)
    ,@EntryId    int
    ,@RC        int

SET DEADLOCK_PRIORITY    -5
BEGIN TRANSACTION

;WAITFOR(RECEIVE TOP (1) @Handle = conversation_handle,@Msg = message_body,@MsgType = message_type_name    FROM PortfolioTargetQueue)
IF(@MsgType = 'JournalEntry')
BEGIN
    

    SET @EntryId = CAST(@Msg AS int)
    INSERT INTO dbo.ServiceBrockerLog(
        EntryId
        , CompleteCode
        , InsertStamp
        )  
        VALUES (
            @EntryId
            , NULL
            , GETDATE()
            )

    EXEC @RC = dlfe.PortfolioMakeEntryChanges @EntryId
    
    IF (XACT_STATE() = 1)
        COMMIT TRANSACTION
    ELSE IF (XACT_STATE() != 0)
    BEGIN
        ROLLBACK TRANSACTION
        RAISERROR('все плохо, жрать нечего',16,1)
        RETURN -1
    END

    UPDATE dbo.ServiceBrockerLog
        SET CompleteCode    = @@TRANCOUNT--@RC
            ,EditStamp        = GETDATE()
        WHERE EntryId = @EntryId
    
    IF(@RC <> 0)
        RAISERROR('все плохо, жрать нечего',16,1)

END

END CONVERSATION @Handle


Возможно я что-то понял не так из совета, если тут ошибка – поправьте, пожалуйста.

Если за две недели не повторится сбой, отпишусь.
4 апр 12, 04:01    [12361456]     Ответить | Цитировать Сообщить модератору
 Re: проблема при работе сервис брокера  [new]
Fly1
Member

Откуда:
Сообщений: 6
Видимо до этого я не правильно понимал как обаботать ошибку при выполнении транзакции.

Ошибок в данных пока не появилось новых, полет нормальный.
14 апр 12, 04:11    [12416230]     Ответить | Цитировать Сообщить модератору
Все форумы / Microsoft SQL Server Ответить