SQL.RU
 client/server technologies
 Главная | Документация | Статьи | Книги | Форум | Блоги | Опросы | Гостевая | Рассылка | Работа | Поиск | FAQ |

How to: Репликация транзакций

ПУБЛИКАЦИИ  

По материалам статьи Paul Ibison: How to: Transactional Replication
Перевод Ирины Наумовой

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

СОДЕРЖАНИЕ

Репликация транзакций

Как использовать DBCC OPENTRAN?

Вот мой метод использования DBCC OPENTRAN: Если log reader agent успевает обработать то, что находится в журнале транзакций, тогда LSN самой старой транзакции, которая еще не передана подписчику, будет такой: (0:0:0).

Oldest distributed LSN : (10:384:4) Oldest non-distributed LSN : (0:0:0)

Если же он не успевает обработать все новые тиражируемые транзакции или он не запущен, то результат будет похож на следующий:

Oldest distributed LSN : (10:388:4) Oldest non-distributed LSN : (10:390:1)

Если имеются открытые транзакции, в начале получаемого отчёта будет следующая информация:

Oldest active transaction: SPID (server process ID) : 55 UID (user ID) : 1 Name : mytran LSN : (10:391:1) Start time : May 16 2005 10:10:28:920AM Replicated Transaction Information: Oldest distributed LSN : (10:388:4) Oldest non-distributed LSN : (10:390:1)

Для того чтобы определить, какая выполняется команда T-SQL, нужно воспользоваться командой dbcc inputbuffer (55), а затем уже принимать решение нужно ли прерывать данный процесс.
Числа в скобках - (10:388:4) - это порядковые номера журнала транзакций (LSN). Вы можете выполнить запрос:

select * :: fn_dblog (null, null)

Результатом исполнения этого запроса будет список LSN, а для получения более детальной информации, можно воспользоваться программой LogExplorer.

[В начало]

Как определить какие команды ожидают загрузки?

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

select transaction_timestamp from subscriberdatabasename..MSreplication_subscriptions

Что бы увидеть последнюю команду, нужно выполнить в контексте базы данных Distribution представленный ниже скрипт. В качестве параметра процедуры используйте значение, полученное из запроса выше:

sp_browsereplcmds @xact_seqno_start = '0x000000AF00000043000B00000001'

[В начало]

Как понять когда лучше использовать комбинацию sp_dropsubscription и sp_addsubscription вместо комбинации sp_dropsubscription и sp_droparticle, с последующим исполнением sp_addarticle и sp_addsubscription?

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

Как избавиться от ошибки "Violation of Primary Key constraint 'PK__@snapshot_seqnos__{UniqueNumber}'. Cannot insert duplicate key in object '#{UniqueNumber}'

Необходимо установить последний сервисный пакет. Имеются отзывы, что и этого не достаточно, потому что тип параметра subscription_seqno - varbinary (16), а не varchar (16). Нужно заменить тип данных столбца на varbinary (16), и тогда все будет работать правильно.

[В начало]

Как определить какой подписчик еще не получил данные?

Подписчики, на которых количество ожидающих передачу команд велико:

select agent_id from msdistribution_status group by agent_id having sum(undelivCmdsInDistDB) >1000 order by sum(undelivCmdsInDistDB) desc

Для того чтобы получить список таких подписчиков, нужно полученный результат объединить с запросом к таблице msdistribution_agents (поле Id).
Далее, следует запрос, который позволяет определить статьи, в которых производится самое большое количество изменений:

select article_id, max(undelivcmdsindistdb) from Msdistribution_status group by article_id

[В начало]

Как правильно сделать резервную копию реплицируемой БД?

Прочитайте в BOL статьи "Strategies for Backing Up and Restoring Transactional Replication" и "Backing Up and Restoring Replication Databases". Имеется возможность для стандартной репликации транзакций использовать опцию 'sync with backup'. При использовании этой опции, транзакции не попадают в базу дистрибуции пока они не будут включены в резервную копию реплицируемой БД (то есть не будет таких транзакций в msrepl_commands, которые не были бы уже помещены в резервную копию на издателе). Однако это ведет к снижению производительности (даже при использовании Log Shipping выполнение резервной копии может выполняться не чаще чем раз в минуту). Если Вы не используете эту опцию, после восстановления из резервной копии нужно будет игнорировать некоторые транзакции и ошибки, делая это вручную (используя параметр -SKIPERRORS). Что же касается восстановления резервных копий подписчика, это обычно не является настолько критичным. Они должны быть восстановлены на момент времени, предшествующий восстановлению дистрибутора, и затем уже команды будут тиражироваться агентом дистрибуции - подробности можно прочитать в BOL, а также в статье Резервное копирование в репликации SQL Server. Или в качестве альтернативы, Вы могли бы просто реинициализировать подписчиков.

[В начало]

Как ежедневно добавлять таблицы в БД и реплицировать их, без запуска агента создания снимка?

Да, это возможно, если предполагается что данные уже существует на подписчике. Для этого нужно использовать процедуру sp_addsubscription с параметром @sync_type = 'none' при добавлении подписки, и нужно вручную добавить на подписчике пользовательские хранимые процедуры (используя sp_scriptpublicationcustomprocs). Тогда не понадобится генерировать новый снимок.

EXEC sp_addarticle @publication = N'NorthwindOIncludeDRINonCLustered', @article = N'CategoriesArticle', @source_object = N'Categories', @destination_table = N'Categories' GO EXEC sp_addsubscription @publication = N'NorthwindOIncludeDRINonCLustered', @article = N'CategoriesArticle', @subscriber = N'HOME-WIN2K', @destination_db = N'Pubs', @sync_type = N'none' GO

[В начало]

Как динамически секционировать данные?

Используйте подписку с трансформацией. В таких подписках используются DTS пакеты для преобразования данных, и для каждого из подписчиков может быть создан свой пакет. При создании публикации убедитесь, что выбраны опции 'Show Advanced Options' и 'Yes, Transform the Data'.
После создания публикации, создайте для нее DTS пакет. Особенностью Enterprise Manager является то, что эта опция доступна в папке publication опубликованной базы данных, но не в папке Publishers в Replication Monitor. Таким образом, щелкните правой кнопкой мыши на публикации, и выберите Define Transformation of Published Data. В этом мастере создается задача Data Driven Query. Убедитесь в том, что используется VBScript, и измените сценарий для фильтрации строк следующим образом:

if DTSSource("RegionID") = 1 then Main = DTSTransformStat_OK else Main = DTSTransformStat_SkipRow end if

[В начало]

Что происходит, когда при выполнении транзакции на издателе происходит ошибка, применяется ли она на подписчике?

Результат выполнения транзакции на издателе можно отслеживать с помощью функции @@error, а затем при необходимости делать откат транзакции, но транзакция все равно применится на подписчике. Данная ситуация отлавливается, если установить уровень изоляции транзакций serializable.
Это важно предусмотреть заранее, потому что, даже если Вы получите ту же самую ошибку в транзакции на подписчике и откатите транзакцию там, ошибка все равно будет зарегистрирована, и distribution agent завершит работу с ошибкой. Чтобы обойти эту проблему, можно использовать параметр SkipErrors, но в идеале транзакция, выполнение которой привело к ошибке, не должна быть послана от издателя подписчику.

[В начало]

Как в репликации транзакций прочитать транзакции не в двоичном формате?

Транзакции записываются в таблицу MSrepl_commands, чтобы их посмотреть, нужно запустить процедуру sp_browsereplcmds. В случае использования очереди, применяйте sp_replqueuemonitor для того чтобы прочитать данные из таблицы MSreplication_queue, и sp_browsereplcmds для того чтобы посмотреть команды в транзакции при разрешении конфликтов.

[В начало]

Как реплицировать изменения командой Update? Когда я выполняю команду update, она разбивается на delete и insert на подписчике. Почему?

Это случается при изменении поля, которое является частью уникального индекса. Используйте флаг 8207, чтобы команда update применялась как update на подписчике, но это действительно только для случаев, когда update - одна команда в транзакции. Прочитайте статью 302341.

[В начало]

Как реплицировать пользователей?

Пользователи и другие административные объекты не могут быть реплицированы, поскольку нельзя реплицировать системные таблицы. Если это необходимо, Вы можете:

  1. Создать DTS пакет

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

[В начало]

Как предотвратить удаления, приходящие от подписчика?

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

[В начало]

Сообщения об ошибках

При создании подписчиков с немедленным обновлением, выдается ошибка "Login failed for 'sa' Почему?

При подключении к издателю, подписчики с немедленным обновлением используют удаленный вызов процедур (RPC). По умолчанию учетная запись для подключения таким образом - sa с пустым паролем, что часто становится причиной ошибок. Используйте процедуру sp_link_publication с параметром @security_mode = 2. Другие параметры этой процедуры описаны в BOL или по этой ссылке: MS article.

[В начало]

С чем связана эта ошибка: Could not find stored procedure 'sp_MSupd_Region'?

Если в процедуре sp_addsubscription Вы используете параметр @sync_type = None (или выбираете аналогичную опцию в мастере создания публикации), а в окне инициализации подписчиков выбираете 'no, the subscriber already has the schema and data' - Вы можете получить эту ошибку. Системные таблицы репликации будут созданы на подписчике в любом случае, но Вам придётся вручную создать хранимые процедуры на подписчике, если Вы использовали эту опцию. Иными словами, Вы можете получить эту ошибку при изменении записей на издателе. Используйте sp_scriptpublicationcustomprocs (предполагается, что у Вас установлен sp1) для создания скриптов этих процедур, и выполните эти скрипты на подписчике.

[В начало]

Общие проблемы

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

Если при инициализации у Вас используется опция nosync, может получиться, что поле имеет атрибут Identity - Yes (not for replication), но значение identity не увеличивается в процессе репликации и DBCC CHECKIDENT не всегда работает для таких полей. Это может стать для Вас одной из причин, чтобы рассмотреть возможность использования обновляемых подписчиков с использованием очередей.

[В начало]

Какие изменения в схеме допустимы на издателе?

  1. Изменение размера поля - не допустимо, реинициализация или использование комбинации процедур sp_repladdcolumn и sp_repldropcolumn.

  2. Удаление ограничения на таблицу, участвующую в репликации - допустимо, ограничение будет удалено на таблицу на издателе, но эти изменения не реплицируются на подписчиков.

  3. Создать новое ограничение на таблицу - допустимо, но оно не будет реплицировано.

  4. Удаление индекса опубликованной таблицы будет ли это реплицировано на подписчика - допустимо, но не реплицируется.

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

Для тех действий, которые допустимы на издателе, но не реплицируются на подписчиков, можно использовать механизм On-Demand Script Execution (или посредством linked servers и т.д.).

[В начало]

Перевод: Ирины Наумовой  2005г.

Rambler's Top100 Рейтинг@Mail.ru  Administrator: Обратная связь 
Copyright: SQL.Ru 2000-2013