Microsoft Sync Framework 2.1 で Azure SQL を同期する

Azure DataSync(プレビュー) が Silverlight インターフェースを終了した後、大きなスキーマを持つデータベースに対するスキーマ同期に失敗するようになったらしい。( http://social.msdn.microsoft.com/Forums/windowsazure/en-US/9c679a74-9a7c-48e7-b4c9-95f6f7cfafd9/sql-azure-data-sync-refresh-schema-not-working?forum=ssdsgetstarted によると 800KB以上)
自分のところではテーブル数が200未満であるが、テーブル名・フィールド名に日本語を使っており内部的な表現でバイト数が膨れる可能性が高かった。

Azure DataSync の中身は Sync Framework がベースになっている。ということで自力で Microsoft Sync Framework 2.1 での実装することになった。

行数が小さなテーブルを同期するだけであれば、 http://msdn.microsoft.com/en-us/library/ff928700.aspx “Synchronizing SQL Server and SQL Express” で動作する。

行数が大きなテーブルになると問題が発生する。この問題に対処するヒントが http://msdn.microsoft.com/en-us/library/hh882017.aspx “Differences between Synchronization Classes for SQL Azure and SQL Server”

このうち CommandTimeout は、環境に依存するものではなく単純にデータ量に対応してタイムアウトの秒数を増やす必要があるというだけのもの。

Azure 特有の問題は ApplicationTransactionSize の値。Azure には throttling 機構がある。これは、Azure SQL が共有で使う構成のため、1ユーザーのアクセスが他のユーザーに重大な影響を及ぼさないような制約が入っている。そのうちの一つが1回のバッチに対する容量制限だ。
http://blogs.msdn.com/b/sync/archive/2010/09/24/how-to-sync-large-sql-server-databases-to-sql-azure.aspx “How to Sync Large SQL Server Databases to SQL Azure” によると、 50000 から始めよ、とのこと。しかし自分の環境では 50000 では失敗。

ApplicationTransactionSize = 16384 で成功した。

そしてこの値は、同期が一方向 (Download) の場合であっても、両側に適用しなければならない。当初データ供給側には不要かもしれないと ApplicationTransactionScope の設定をしなかったらエラーが発生した。

Bulk command BulkInsertCommand failed with the following exception. Rows will be retried during single apply. System.Data.SqlClient.SqlException (0x80131904): サーバーから結果を受信しているときに、トランスポート レベルのエラーが発生しました。 (provider: TCP Provider, error: 0 – 既存の接続はリモート ホストに強制的に切断されました。) —> System.ComponentModel.Win32Exception (0x80004005): 既存の接続はリモート ホストに強制的に切断されました。
   場所 System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
   場所 System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose)
   場所 System.Data.SqlClient.TdsParserStateObject.ReadSniError(TdsParserStateObject stateObj, UInt32 error)
   場所 System.Data.SqlClient.TdsParserStateObject.ReadSniSyncOverAsync()
   場所 System.Data.SqlClient.TdsParserStateObject.TryReadNetworkPacket()
   場所 System.Data.SqlClient.TdsParserStateObject.TryPrepareBuffer()
   場所 System.Data.SqlClient.TdsParserStateObject.TryReadByte(Byte& value)
   場所 System.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady)
   場所 System.Data.SqlClient.SqlDataReader.TryConsumeMetaData()
   場所 System.Data.SqlClient.SqlDataReader.get_MetaData()

データベース側の master.sys.event_log を見ると、 event_type = throttling_long_transaction , description は以下のようなエラーになっていた。

The session has been terminated because it has acquired too many locks. Try reading or modifying fewer rows in a single transaction.

データ同期の速度は、おおざっぱには 100万レコード/30分 ぐらい。

広告

コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト / 変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト / 変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト / 変更 )

Google+ フォト

Google+ アカウントを使ってコメントしています。 ログアウト / 変更 )

%s と連携中

%d人のブロガーが「いいね」をつけました。