У меня есть основная база данных (server_A), зеркальная база данных (server_B) и база данных свидетелей (server_C). Базы данных настроены на автоматическое переключение при сбое, то есть когда server_A выходит из строя или переключается при сбое, server_B принимает на себя роль новой основной базы данных. Насколько мне известно, кворум базы данных настроен правильно.
Я написал приложение на c ++ для подключения к базе данных и получения значения для обеспечения истинного соединения. Приложение обнаруживает, когда происходит сбой при вызове GetValue, и пытается повторно подключиться при возникновении ошибки.
Проблема заключается в следующем:
Когда у меня есть НЕСКОЛЬКО подключений к базе данных (после двух подключенных потоков, однажды подключенных, он получит значение в цикле), когда происходит аварийное переключение (остановка сервера sql на сервере A, чтобы сервер B стал основным), я обнаруживаю сбой соединения и уничтожить мое соединение и попытаться восстановить соединение, используя ту же строку соединения:
«Драйвер = {Собственный клиент SQL}; Сервер = tcp: Сервер_A; Failover_Partner = tcp: Сервер_B; База данных = SomeDatabase; Uid = SomeUser; Pwd = SomePassword;»
** НОТА **
Я проверил, что отказоустойчивость произошла путем мониторинга баз данных.
Несмотря на то, что соединение с базой данных было должным образом удалено, я не могу повторно подключиться к базе данных, пока не перезапущу приложение, ИЛИ если я переведу server_A обратно в оперативный режим (теперь он действует как зеркальная база данных), а затем восстановлю отказоустойчивый сервер server_B (завершив работу сервера sql ) снова сделав сервер А основной базой данных, приложение может переподключиться без необходимости полного закрытия.
Хотя я мог бы манипулировать строкой соединения, чтобы сделать server_B новым принципалом и server_A новым Failover_Partner, это не идеальное решение, так как будет использоваться гораздо больше соединений.
Имейте в виду, это происходит ТОЛЬКО с несколькими подключениями к базе данных. Если я запускаю приложение только с одним соединением, все в порядке, и я могу просто переподключиться, когда происходит аварийное переключение.
РЕДАКТИРОВАТЬ: Если я подключаюсь в начале с несколькими потоками, все в порядке. Когда я завершаю работу SQL Server и, следовательно, происходит аварийное переключение, я могу восстановить соединение только тогда, когда прохожу, удаляю ВСЕ объекты и заново создаю экземпляры новых объектов. Также я использую SQL Native Client 11.0 (ODBC). Мысли?
Многое из того, что вы описываете, согласуется с проблемой, описанной в KB 2605597 «Ошибка времени ожидания при создании зеркального подключения к базе данных провайдером данных .NET Framework для SQLClient».
В КБ описываются проблемы, когда для тайм-аута соединения установлено значение 15 секунд. Я неоднократно слышал о подобных проблемах, когда для тайм-аута соединения установлено значение 0 (что не является хорошей идеей по другим причинам, упомянув на всякий случай).
Это исправление применяется к серверам приложений. Если вы хотите исключить это как возможную причину, вы можете проверить увеличение тайм-аута (как сказано в разделах об обходе поста), чтобы убедиться, что это не проблема.
Позже я подумал: еще одна вещь, которую я заметил, необычная, это то, что вы указываете протокол TCP в строке соединения и имя партнера по обеспечению отработки отказа. Из документации мне не ясно, поддерживается ли она в имени партнера по отработке отказа. Возможно, вы захотите попробовать удалить это и указать вместо этого сетевой атрибут. (Рекомендуется здесь.)
Я понимаю, что вы считаете, что проблема не в этих вещах из-за проблемы с одним / несколькими подключениями, которую вы протестировали.
Тем не менее, я думаю, что вам лучше упростить строку подключения, чтобы она максимально соответствовала опубликованным примерам, и следите за тем, чтобы люди не сталкивались с этим первым. (Проблема повторных попыток возникает при наличии задержки, которая может сделать ее несколько спорадической.)
Хорошо, я нашел ответ.
Мне пришлось изменить файл hosts, потому что мое приложение не находилось в том же домене, что и базы данных. Поэтому при попытке перехода на другой ресурс я не смог получить доступ к базе данных с именем экземпляра (что и было использовано в качестве кэширующего партнера). Я изменил файл hosts, чтобы преобразовать имя экземпляра в IP-адрес машины, и теперь все работает.