4

У меня есть приложение, использующее Service Broker - это SQL 2008. Примерно раз в день производительность базы данных начинает заметно снижаться, и я решил, что это из-за Сервисный брокер. Если я жесткий сброс всех соединений брокера, используя следующие команды:Сообщения сервисного брокера начинают зависать примерно через день

ALTER DATABASE [RegencyEnterprise] SET OFFLINE WITH ROLLBACK IMMEDIATE 
ALTER DATABASE [RegencyEnterprise] SET ONLINE 

Затем возвращается в нормальное состояние производительности примерно до следующего дня. Я также заметил, что, когда производительность невысока, выполнив следующий запрос возвращает большое количество (около 1000 в настоящее время) разговоров, которые застряли в состоянии STARTED_OUTBOUND:

SELECT * FROM sys.conversation_endpoints 

Кроме того, следующие запросы не возвращать в них:

SELECT * FROM sys.dm_qn_subscriptions 
SELECT * FROM sys.transmission_queue 

Производительность, похоже, в порядке, если есть много предметов, возвращаемых этим запросом. Единственный момент, когда возникают проблемы, - это когда есть STARTED_OUTBOUND, которые остаются в этом состоянии.

Единственная конфигурация, которую я сделал в Service Broker на моем SQL Server 2008 экземпляр был выполнить следующую команду:

ALTER DATABASE RegencyEnterprise SET ENABLE_BROKER 

копаться в журнал ошибок SQL, я нашел эту запись более 1000 раз, как хорошо:

07/11/2013 01:00:02,spid27s,Unknown,The query notification dialog on conversation handle '{6DFE46F5-25E9-E211-8DC8-00221994D6E9}.' closed due to the following error: '<?xml version="1.0"?><Error xmlns="http://schemas.microsoft.com/SQL/ServiceBroker/Error"><Code>-8490</Code><Description>Cannot find the remote service &apos;SqlQueryNotificationService-cb4e7a77-58f3-4f93-95c1-261954d3385a&apos; because it does not exist.</Description></Error>'. 

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

06/26/2013 14:25:01,spid116,Unknown,Service Broker needs to access the master key in the database '<Database name>'. Error code:26. The master key has to exist and the service master key encryption is required. 

Я думаю, что количество этих ошибок может быть связано с количеством цепочек, которые остаются в очереди. Здесь C# код, я использую, чтобы подписаться на уведомления запроса:

private void EstablishSqlConnection(
    String storedProcedureName, 
    IEnumerable<SqlParameter> parameters, 
    Action sqlQueryOperation, 
    String serviceCallName, 
    Int32 timeout, 
    params MultipleResult[] results) 
{ 
    SqlConnection storeConnection = (SqlConnection) ((EntityConnection) ObjectContext.Connection).StoreConnection; 
    try 
    { 
     using (SqlCommand command = storeConnection.CreateCommand()) 
     { 
      command.Connection = storeConnection; 
      storeConnection.Open(); 

      SqlParameter[] sqlParameters = parameters.ToArray(); 
      command.CommandText = storedProcedureName; 
      command.CommandType = CommandType.StoredProcedure; 
      command.Parameters.AddRange(sqlParameters); 

      if (sqlQueryOperation != null) 
      { 
       // Register a sql dependency with the SQL query. 
       SqlDependency sqlDependency = new SqlDependency(command, null, timeout); 
       sqlDependency.OnChange += OnSqlDependencyNotification; 
      } 

      using (DbDataReader reader = command.ExecuteReader()) 
      { 
       results.ForEach(result => result.MapResults(this, reader)); 
      } 
     } 
    } 
    finally 
    { 
     storeConnection.Close(); 
    } 
} 

Вот как я обрабатывать уведомления:

public static void OnSqlDependencyNotification(object sender, SqlNotificationEventArgs e) 
    { 
     if (e.Info == SqlNotificationInfo.Invalid) 
     { 
      // If we failed to register the SqlDependency, log an error 
      <Error is loged here...> 

      // If we get here, we are not in a valid state to requeue the sqldependency. However, 
      // we are on an async thread and should NOT throw an exception. Instead we just return 
      // here, as we have already logged the error to the database. 
      return; 
     } 

     // If we are able to find and remove the listener, invoke the query operation to re-run the query. 
     <Handle notification here...> 
    } 

Кто-нибудь знает, что может привести к связи брокера, чтобы получить в этом государство? Или какие инструменты я мог бы использовать, чтобы попытаться выяснить, что вызывает это? В настоящее время у меня есть только один веб-сервер, который регистрируется в своих уведомлениях, поэтому мой сценарий не слишком сложный.

UPDATE:

Итак, я решил от this post что ошибка «не удается найти службу удаленного ... потому что не существует» из-за SqlDependency не убирать за собой должным образом. Брокер по-прежнему пытается отправить уведомления в мое приложение после окончания службы. Так что теперь, похоже, мне просто нужно найти способ очистить все, что он не убирает должным образом, когда мое приложение запускается до вызова SqlDependency.Start(), но я не нашел способ сделать это иначе, чем мой оригинальный метод выше, который отключает базу данных и не подходит. Кто-нибудь знает знать, чтобы очистить это?

+0

Опишите конфигурацию вашего сервис-брокера. Какие у вас очереди, как вы их используете, где другие цели? и т. д. – RBarryYoung

+0

Я просто использую настройки по умолчанию - я еще не создал пользовательских очередей. Я подключаюсь с использованием объекта C# SqlDependency в своем веб-приложении. Есть ли конкретная информация о конфигурации, которая бы помогла? – lehn0058

+0

Можете ли вы показать нам код C#, пожалуйста? – Rikalous

ответ

4

Я нашел приемлемый подход к решению этой проблемы. Во-первых, я перенес код из SqlDependency, и теперь я использую SqlNotificationRequest. Это предотвращает создание/уничтожение Broker Queues and Services в неожиданные времена.

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

Эта настройка уменьшила количество подключений, которые у меня есть на ежедневной основе от более 1000, и их необходимо вручную убить, чтобы иметь максимум около 20 в любое время. I высоко рекомендуется использовать SqlNotificationRequest вместо SqlDependency.

0

Started Outbound означает, что SQL Server обработал BEGIN CONVERSATION для этого разговора, но сообщений еще не отправлено. ' (из книги в Интернете) Похоже, вы создаете разговоры, которые не используются, поэтому они никогда не закрываются.

Не совсем уверен, почему это приведет к ухудшению производительности.

+0

Это имеет смысл, почему они останутся в этом состоянии. Это странно, хотя из-за того, что мой веб-сервер регистрируется только для разговора, когда процесс запускается и закрывается, когда процесс завершается. Я полагаю, что если было отменено необработанное исключение, и IIS перезапустил процесс, тогда будет запущено более 1 разговора, а первое никогда не будет закрыто ... Я согласен с вами в том, что я не ожидаю, что у вас будут сообщения, которые не были доставлены влияют на производительность, как это. – lehn0058

2

Я нашел способ очистить разговоры, которые застряли. Я извлекаю все сгенерированные очереди SqlDependency, которые все еще существуют, и перебирают разговоры, которые не принадлежат ни одному из них, и заканчивают эти разговоры. Ниже приведен код:

SET NOCOUNT OFF; 
DECLARE @handle UniqueIdentifier 
DECLARE @count INT = 0 

-- Retrieve orphaned conversation handles that belong to auto-generated SqlDependency queues and iterate over each of them 
DECLARE handleCursor CURSOR 
FOR 
SELECT [conversation_handle] 
FROM sys.conversation_endpoints WITH(NOLOCK) 
WHERE 
    far_service COLLATE SQL_Latin1_General_CP1_CI_AS like 'SqlQueryNotificationService-%' COLLATE SQL_Latin1_General_CP1_CI_AS AND 
    far_service COLLATE SQL_Latin1_General_CP1_CI_AS NOT IN (SELECT name COLLATE SQL_Latin1_General_CP1_CI_AS FROM sys.service_queues) 

DECLARE @Rows INT 
SELECT @Rows = COUNT(*) FROM sys.conversation_endpoints WITH(NOLOCK) 
WHERE 
    far_service COLLATE SQL_Latin1_General_CP1_CI_AS like 'SqlQueryNotificationService-%' COLLATE SQL_Latin1_General_CP1_CI_AS AND 
    far_service COLLATE SQL_Latin1_General_CP1_CI_AS NOT IN (SELECT name COLLATE SQL_Latin1_General_CP1_CI_AS FROM sys.service_queues) 

WHILE @ROWS>0 
BEGIN 
    OPEN handleCursor 

    FETCH NEXT FROM handleCursor 
    INTO @handle 

    BEGIN TRANSACTION 

    WHILE @@FETCH_STATUS = 0 
    BEGIN 

     -- End the conversation and clean up any remaining references to it 
     END CONVERSATION @handle WITH CLEANUP 

     -- Move to the next item 
     FETCH NEXT FROM handleCursor INTO @handle 
     SET @count= @count+1 
    END 

    COMMIT TRANSACTION 
    print @count 

    CLOSE handleCursor; 

    IF @count > 100000 
    BEGIN 
     BREAK; 
    END 

    SELECT @Rows = COUNT(*) FROM sys.conversation_endpoints WITH(NOLOCK) 
    WHERE 
     far_service COLLATE SQL_Latin1_General_CP1_CI_AS like 'SqlQueryNotificationService-%' COLLATE SQL_Latin1_General_CP1_CI_AS AND 
     far_service COLLATE SQL_Latin1_General_CP1_CI_AS NOT IN (SELECT name COLLATE SQL_Latin1_General_CP1_CI_AS FROM sys.service_queues) 
END 
DEALLOCATE handleCursor; 
+1

В качестве побочного примечания: существует API C# нижнего уровня: ['SqlNotificaitonRequest'] (http://msdn.microsoft.com/en-us/library/system.data.sql.sqlnotificationrequest.aspx), который позволяет вам построить свою собственную «сантехнику» (целевой сервис и т. д.). Не является тривиальным, но вы можете избежать проблем, вызванных 'SqlDependency'. –

+0

Да, я нашел этот класс, и я рассматриваю его использование. Это позволило бы мне определить мои собственные объекты брокер-службы, а не автоматически генерировать их каждый раз, когда будет установлено новое соединение. – lehn0058

+0

ОК - это выглядит как боль, чтобы делать это регулярно. Несколько раз верните «стек мысли» - вы внедрили какой-либо код для деактивации уведомлений, когда ваш клиент закрывается? – Rikalous

 Смежные вопросы

  • Нет связанных вопросов^_^