次の方法で共有



April 2009

Volume 24 Number 04

同期 - Microsoft Sync Framework でデータを効率的に管理する

James Yip | April 2009

この記事では、次の内容について説明します。

  • Microsoft Sync Framework
  • 同期サービス
  • メタデータ保存領域
  • スキーマの同期
この記事では、次のテクノロジを使用しています。
ADO.NET、Microsoft Sync Framework、SQL Server

目次

使用シナリオ
Microsoft Sync Framework のしくみ
同期プロバイダ
Sync Framework のメタデータ保存領域サービス
Sync Services の動作
データおよびスキーマを同期する
カスタム同期を実装する
まとめ

異なるデータ ストア間の同期をとることは容易ではありません。固有のロジックを作成して同期を実行するには手間とコストがかかります。そこで、Microsoft Sync Framework とその API を使用すると、同期ロジックの作成が大幅に簡素化されます。Microsoft Sync Framework では、ネットワーク上の任意のプロトコルを使用してデータ ストアからアプリケーション データを統合できます。 

Microsoft Sync Framework と共にリリースされた Microsoft Synchronization Services for ADO.NET、Synchronization Services for File Systems、および Synchronization Services for FeedSync は、いずれも Microsoft Sync Framework とは異なり、特定の環境で同期を行う機能です。これらのツールはアプリケーションの同期ロジックを作成する場合に使用します。

これらの Sync Services は、2 つのデータベース ソース間のデータの同期、2 台のコンピュータ間のファイルの同期、アプリケーションと RSS フィードまたは ATOM フィードとの同期を行うためのツール セットを提供します。これらのサービスを利用することで、データの同期にかかる手間が軽減され、アプリケーション ロジックに労力を集中できるようになります。

使用シナリオ

Microsoft Sync Framework はさまざまな場面で役立ちます。次にその一般的な例を示します。

ダウンロードのみの同期: クライアント コンピュータには保存するデータ内容や保存されたデータの追跡方法を決める権限がない場合です。例として RSS 同期が挙げられます。RSS 同期では、RSS プロバイダが情報の提供方法と更新頻度を決定し、クライアントはコンテンツの内容と提供時期を決定します。

オフラインのデータ アクセスが多い場合: 一部の Windows アプリケーションでは、ユーザーがネットワークに接続していない状態でもアプリケーションの実行が適切に続けられるようにするためのオフライン データ アクセス機能が必要です。例として在庫管理アプリケーションが挙げられます。販売担当者がラップトップでリモートから販売データを入力し、後からデータベースと同期できる機能があったら便利です。

ピアツーピア コラボレーションを行うことがある場合: クライアントのパフォーマンスを向上させるためにデータベースのローカル コピーを発行します。複数のローカル コピーが散在している場合、バックエンドのデータ リポジトリを適切に更新し、すべての変更が処理されるようにする必要があります。一般的な例として、POS (販売時点情報管理) アプリケーションが挙げられます。販売が発生すると、各店舗の POS アプリケーションが販売取引を記録し、店舗の在庫を更新します。これらの更新を集中管理用のデータ ストアと他の店舗が使用しているデータベースのすべてのローカル コピーに反映し、各店舗の販売担当者が手持ちの在庫状況を把握できるようにする必要があります。

これらのデータ アクセス シナリオは Microsoft Sync Framework の最も一般的な利用方法です。次に、Microsoft Sync Framework を使用してこれらのオフライン データ アクセスの問題を解決する方法を説明します。

Microsoft Sync Framework のしくみ

Microsoft Sync Framework はセッションを使用してデータを同期します。セッション内に、変更元となるデータ ソースと変更の複製先となる同期先を定義します。クライアントで同期がトリガされると、次の処理が行われます。

  1. 同期セッションが作成されます。
  2. ローカル コピーをダウンロードした後に他の同期元からコミットされた変更が同期先データに存在するかどうかを Sync Framework が確認します。
  3. 見つかった変更が同期元に送信されて適用されます。
  4. 同期先は、同期先ストアに変更を送信することを同期元に要求します。
  5. 同期元が変更を送信し、その変更が同期先データ ストアに適用されます。

この処理を行うには、同期元と同期先がなんらかのメタデータを保持し、発生した変更を同期間で識別できるようにする必要があります。そのための方法はいくつもありますが、同期するデータの種類によって方法は異なります。

実装するアプリケーションや同期の種類によっては、変更を追跡する手段がデータにないために、カスタム変更追跡を実装する必要がない場合があります。しかし、ファイル システムに保存されたファイルなどのデータの場合は、既に作成および更新されたメタデータを保持しています。Microsoft Sync Framework は一方向の同期と双方向の同期をサポートしています。双方向の同期は、同期元と同期先間の 2 つの一方向同期として実装されます。

Microsoft Sync Framework は、SyncOrchestrator クラスを使用して 2 つのデータ ソース間のデータ フローを管理します。同期セッション中にカスタム アプリケーション ロジックを追加する場合以外、このクラスを拡張する必要はありません。

同期の方向は SyncOrchestrator クラスの Direction プロパティで制御します。特定の SyncOrchestrator インスタンスでアップロード、ダウンロード、またはその両方のいずれの同期を行うかを選択できます。

プロバイダを同期元および同期先のデータ ストアとの通信に使用します。同期をトリガする前に、使用するプロバイダを SyncOrchestrator に通知する必要があります。同期をトリガすると、SyncOrchestrator はプロバイダのメソッドを呼び出して変更を取得し、その変更を保存して競合を解決します。図 1 に、同期のしくみを示します。

fig01.gif

図 1 SyncOrchestrator オブジェクト

同期プロバイダ

Microsoft Sync Framework は同期元および同期先の通信にプロバイダを使用します。プロバイダは、データ ソースと通信し、関連付けられたデータ ストアと互換性のある方法でアプリケーション データを保存します。また、同期セッションの相手側から提供された情報に基づいて変更を検出し、受け取った変更を適用して、データ ソースから変更を取得します。

プロバイダの開発には相当の手間がかかります。同期プロバイダを実装するには、KnowledgeSyncProvider 抽象クラス、IChangeDataRetriever インターフェイス、および INotifyingChangeApplierTarget インターフェイスを実装する必要があります。これらのクラスおよびインターフェイス内では、変更を検出し、その変更を適用するロジックを実装するためのさまざまなイベントが用意されています。

クライアント アプリケーションと集中管理用のデータ ストアとの直接接続が存在しない場合は、プロキシ プロバイダを実装できます。プロキシ プロバイダはコマンドを受け取り、受け取ったコマンドを同期セッション内の他のプロバイダに中継します。

プロキシ プロバイダは、クライアント アプリケーションがインターネットで集中管理用のデータ ストアと通信する場合などに便利です。この場合、クライアントは HTTPS でプロキシに接続し、そのプロキシを SQL Server に接続します。この構成により、内部サーバーがインターネットに公開されるリスクが軽減されますが、外部ユーザーは Sync Framework を使用してデータを同期することができます。

プロキシ プロバイダの実装方法は他のプロバイダと同じです。唯一の相違点は、プロキシ プロバイダはクライアント アプリケーションから直接トリガされるのではなく、他のプロバイダによってトリガされることです。

Sync Framework のメタデータ保存領域サービス

データ ソースによっては、追加情報の保存や変更追跡の実装ができない場合があります。Windows ファイル システムがその例です。このような場合の解決方法として、Microsoft Sync Framework には、開発者がメタデータ リポジトリを作成する必要のない、メタデータ保存領域サービスと呼ばれる簡易データ ストアが用意されています。

メタデータ保存領域サービス内に作成したストアには、2 種類のデータ (レプリカ レベルのデータと項目レベルのデータ) を格納できます。これらのストアは特定の同期先 (レプリカ) および項目に関する情報の保存に使用します。各同期先にはその同期先を一意に識別するレプリカ ID が必要です。

ReplicaMetadata、ItemMetadata、および MetadataStore は、それぞれレプリカのメタデータ、項目のメタデータ、およびメタデータ ストアを表す抽象クラスです。これらのクラスを使用してメタデータを操作できます。

SqlMetadataStore は、Microsoft Sync Framework のメタデータ保存領域サービスの具象実装です。このクラスでは、メタデータをレプリカ レベルで管理できます。Microsoft Sync Framework は項目レベルのメタデータの実装をサポートしていません。項目レベルのメタデータを保存するには、ItemMetadata クラスの固有の実装を作成し、MetadataStore オブジェクトを作成する必要があります。SqlMetadataStore は、SQL Server を使用して、ユーザーが定義したファイルにメタデータを保存します。

SqlMetadataStore を使用するには、保存されたストアを OpenStore メソッドで開くか、CreateStore メソッドを使用して新しいストアを作成します。通常は、アプリケーションごとに 1 つのストアがあれば十分ですが、必要に応じて複数のストアを保持することもできます。メタデータをストアから取得するには、GetReplicaMetadata メソッドを使用します。

SqlMetadataStore から項目を取得する方法を次に示します。

SyncIdFormatGroup idFormat=new SyncIdFormatGroup();
SyncId syncId=new SyncId(1);
SqlMetadataStore metadataStore=SqlMetadataStore.OpenStore(filePath);
ReplicaMetadata item= metadataStore.GetReplicaMetadata(idFormat,syncId);

SqlMetadataStore を使用する場合、保存するデータのスキーマを指定する必要があります。そのためには、SqlMetadataStore の InitializeReplicaMetadata メソッドを呼び出します。このメソッドは、基になる SQL データベースに情報を保持するために、テーブルを作成して設定します。たとえば、フィールドが 1 つあるメタデータ ストアの設定方法を次に示します。

SyncIdFormatGroup idFormat=new SyncIdFormatGroup();
SyncId syncId=new SyncId(1);
FieldSchema[] fields=new FieldSchema[1];
IndexSchema[] indexes=new IndexSchema[1];
fields[0]=new FieldSchema("LastSync",typeof(string));
indexes[0]=new IndexSchema("LastSync",false);
SqlMetadataStore metadataStore=SqlMetadataStore.CreateStore(filePath);
ReplicaMetadata item= metadataStore.InitializeReplicaMetadata(  idFormat,syncId, fields,indexes );

Sync Services の動作

次に、Sync Services for ADO.NET を使用してアプリケーションに同期のサポートを追加する方法を説明します。SQL Server Compact Edition 3.5 を使用して、ローカル ファイル システムに簡易データ ストアを作成できます。SQL Server Compact Edition の利点は、動作は SQL Server と同様でありながら、ファイルをリポジトリとして使用するため、ローカル データ ストアと連携するようにアプリケーションを変更する必要がないということです。

Synchronization Services for ADO.NET は、SQL Server Compact Edition データベースなどの SQL Server データベース間のデータおよびスキーマの同期をサポートします。ここでは、集中管理用の SQL Server データベースを使用するアプリケーションで、SQL Server Compact Edition データベース内に保持されているレプリカを経由したオフライン アクセスを可能にする方法を示します。

Synchronization Services for ADO.NET を実装する場合は、データ変更を追跡する方法を最初に決定します。Synchronization Services for ADO.NET では、SQL Server 2008 の統合変更追跡の機能を利用できます。またはアプリケーション データベースで変更追跡を手動で管理することにより、カスタム追跡を使用することもできます。

SQL Server 2008 では、統合変更追跡に対応したテーブルに、変更追跡ログ テーブルのすべてのデータ変更が記録されます。このログが Sync Services で参照され、最後の同期以後に行われたすべての変更が識別されます。このため、開発者は既存のアプリケーションのデータベース スキーマを変更する必要がありません。

ただし、SQL Server 2005 を使用するアプリケーションのように、場合によっては統合変更追跡の機能を利用できないことがあります。そのような場合は、カスタム変更追跡の使用を検討してください。カスタム変更追跡では、テーブルのレコードの挿入および更新を識別する場合には列を参照し、削除を識別する場合には廃棄テーブルを参照します。Sync Services を使用して、最後の更新以後に更新または挿入された行を識別するには、追跡する各テーブルに 4 つの列 (Update Originator、Update Time、Create Originator、Update Time) を追加する必要があります。また、廃棄テーブルを作成して、削除されたすべての行のログを保持する必要があります。テーブルには少なくとも 2 つの情報 (削除時刻と行の元の主キー) が必要です。

削除データは同期元からは既に削除されているため、Sync Services は、廃棄テーブルを参照して、同期先ストアから削除する必要があるエントリを検出します。この情報が、最後の同期以後に行われた変更の特定に役立ちます。

データおよびスキーマを同期する

データベース間の同期を実装する場合、多くのアプリケーションで、スキーマの整合性の維持が問題になります。そのため、Sync Services for ADO.NET ではデータベース スキーマの同期もサポートしています。ただし、サポートには制限があります。同期するたびにテーブルを再作成するように開発者が構成しない限り、クライアント データベースにテーブルが作成されるのは同期を最初に実行したときのみです。

プロバイダに Sync Services for ADO.NET の使用を構成するには、テーブルに同期を設定し、実行する同期の方向を指定するコードをプロバイダに実装する必要があります。同期元から同期先にデータを同期するか、同期先から同期元に同期するか、双方向に同期するかを選択できます。また、同期を構成するコードをプロバイダ クラスのコンストラクタに追加できます。テーブルをグループに分割して個々のテーブルの同期をより詳細に制御することもできます。

適切なスキーマを作成してデータを読み込む処理を Sync Services for ADO.NET が自動的に行うため、通常は同期先にプロバイダを明示的に構成する必要はありません。必要な作業は、同期先データベースの場所を指定することだけです。Sync Services for ADO.NET には 2 つのプロバイダがあります。1 つは SQL Server を使用するプロバイダ、もう 1 つは SQL Server Compact Edition を使用するプロバイダです。両者の唯一の相違点は、データベース エンジンとの通信に使用する、基になるライブラリの違いです。SQL Server プロバイダは System.Data.SqlClient を使用し、SQL Server Compact Edition のプロバイダは System.Data.SqlCeClient を使用します。

SQL Server と通信するプロバイダは DbServerSyncProvider、SQL Server Compact Edition と通信するプロバイダは SqlCeClientSyncProvider です。プロバイダを初期化する場合には、プロバイダが基になる SQL Server と通信する方法や、変更追跡の詳細 (変更の発生元の列や、カスタム SQL 変更追跡を使用するかどうかなど) に関する情報を保持する SyncAdapter オブジェクトが必要です。SyncAdapter に定義されるもう 1 つの重要な情報は同期の方向です。Sync Services for ADO.NET では、テーブル単位で同期の方向を定義できます。Sync Services for ADO.NET には、テーブル名、更新元列名、作成元列名などの情報を指定することによって必要な SyncAdapter オブジェクトおよび SQL ステートメントを作成することができる SyncAdapterBuilder が付属しています。このアダプタ ビルダを使用して SyncAdapter を作成する方法を図 2 に示します。

図 2 SyncAdapterBuilder

sqlSABuilder = new Microsoft.Synchronization.Data.Server.SqlSyncAdapterBuilder(sqlconn);
sqlSABuilder.TableName = "User";
sqlSABuilder.FilterClause = "username='" +   System.Threading.Thread.CurrentPrincipal.Identity.Name + "' ";
sqlSABuilder.TombstoneTableName = "Deleted_"+ sqlSABuilder.TableName;
sqlSABuilder.SyncDirection =   Microsoft.Synchronization.Data.SyncDirection.Bidirectional;
sqlSABuilder.CreationTrackingColumn = "ct";
sqlSABuilder.UpdateTrackingColumn = "ut";
sqlSABuilder.DeletionTrackingColumn = "dt";
sqlSA = sqlSABuilder.ToSyncAdapter(true, true, true, true);
sqlSA.TableName = "User";
destinationProvider.SyncAdapters.Add(sqlSA);

そうは言っても、ほとんどの場合、必要な作業は同期元プロバイダに SyncAdapters を表示するロジックを追加することだけです。双方向の同期を実行する場合は両方を処理する必要があります。

データベースの同期を設定するには、SyncAgent オブジェクトのインスタンスを作成します (SyncAgent オブジェクトは前に述べた SyncOrchestrator オブジェクトに似ていますが、Sync Services for ADO.NET の同期を実行します)。その後、プロバイダを SyncAgent オブジェクトの RemoteProvider プロパティと LocalProvider プロパティに割り当てます。次に、SyncAgent の Synchronize メソッドを呼び出します。このメソッドは同期処理をトリガし、プロバイダが実装している各イベントおよびメソッドを呼び出します。SyncAgent の構成方法と同期の開始方法を次に示します。

SyncAgent syncAgent=new SyncAgent();
syncAgent.LocalProvider = new SqlCeClientSyncProvider ();
syncAgent.RemoteProvider = new DbServerSyncProvider();
syncAgent.Synchronize();

Sync Services for ADO.NET について 1 つ重要なこととして、ADO.NET がサポートするほぼすべてのデータ ソースで使用できるため、同期元データベースまたは同期先データベースは SQL Server に限定されません。

Sync Services for ADO.NET は、SyncTable オブジェクトを使用して、同期に関連するテーブルについての情報を保存します。次のコードは、SyncTable オブジェクトの設定方法と、SyncAgent に SyncTable オブジェクトを構成する方法を示しています。SyncGroup クラスを使用して、SyncTables を ADO.NET が一括して処理する同期グループ単位に集約し、グループ内のすべてのテーブルの整合性を確保することができます。

SyncGroup lookupSyncGroup=new SyncGroup("LookupTables");
SyncTable syncTable = new SyncTable("Customer");
syncTable.CreationOption = syncTable.DropExistingOrCreateNewTable;
syncTable.SyncDirection = syncTable.Bidirectional;
syncTable.SyncGroup = lookupSyncGroup;
syncAgent.Configuration.SyncTables.Add(syncTable);

カスタム同期を実装する

固有のロジックを使用して同期を実装する場合や、Microsoft Sync Framework でサポートされないデータ ストアの同期を実装する場合は、固有のプロバイダを作成して、基になるデータ ストアからデータを取得するロジックを実装する必要があります。

それには、抽象クラス KnowledgeSyncProvider から派生クラスを作成し、GetChangeBatch メソッドをオーバーライドして変更を取得します。同期プロセスを開始すると、このメソッドが SyncOrchestrator オブジェクトによってトリガされます。検出されたすべての変更が ChangeBatch オブジェクトに保存され、同期先プロバイダの ProcessChangeBatch メソッドに渡されます。同期先プロバイダは ChangeBatch オブジェクトを処理し、固有のロジックを使用して同期先データ ストアに変更を適用します。

FilterInfo オブジェクトを使用して、同期元プロバイダと同期先プロバイダとのフィルタリング情報の受け渡しを行います。同期元プロバイダはこのオブジェクトを設定し、ChangeBatch オブジェクトにアタッチします。同期先プロバイダは、この ChangeBatch オブジェクトを使用して、データの適切なサブセットのみに変更を適用します。実装したカスタム プロバイダは SyncOrchestrator で使用できます。ただし、同期プロバイダはスレッドセーフではないので、複数の同期を異なるスレッドで実行する場合は、新しいスレッド内で複製したプロバイダを使用する必要があります。そのためには、新しいプロバイダ オブジェクトを作成し、Union メソッドを使用して既存のプロバイダ オブジェクトと結合します。次に、元のプロバイダではなく、新しく作成したプロバイダを使用するように SyncOrchestrator を構成します。このように構成しないと、そのプロバイダに関連付けられた実行中の同期セッションが複数存在する場合、同期が失敗します。

アプリケーションに同期ロジックを実装する場合、競合の解決が常に問題になります。Microsoft Sync Framework は、次のロジックに従って項目に競合が存在するかどうかを確認します。

  1. 1. 項目の同期先レプリカのバージョン情報が同期元レプリカのナレッジに含まれているかどうかを同期先プロバイダが確認します。
  2. 2. 同期先レプリカのバージョンが同期元レプリカのナレッジに含まれていない場合、オブジェクトに競合が生じていると判断されます。

同期先のバージョン情報が項目に含まれていない場合、Sync Framework は各項目の INotifyingChangeApplierTarget インターフェイスを実装しているクラスの TryGetDestinationVersion イベントをトリガします。このイベントにロジックを追加して、Sync Framework にバージョン管理情報を指定し、競合の解決に役立てることができます。

public bool TryGetDestinationVersion(ItemChange sourceChange, out   ItemChange destinationVersion)
 {
    ...
 }

Microsoft Sync Framework は既定で単純な競合の解決をサポートしています。プロバイダの競合解決ポリシーを構成すると、Sync Framework が自動的にその競合解決を実行します。Sync Framework は既定で次の 5 種類の競合解決ポリシーをサポートします。

  • 同期元優先: 競合が存在する場合、常に同期元レプリカが優先されます。
  • 同期先優先: 競合が存在する場合、常に同期先レプリカが優先されます。
  • マージ: 同期元および同期先からの変更をマージして項目の新しいバージョンを作成し、その新しいバージョンを同期先に送信して適用します。
  • ログ: 競合を無視し、競合している項目の情報を INotifyingChangeApplierTarget を実装しているクラスの SaveConflict イベントに送信します。
  • 保留: 競合を完全に無視し、競合に関する情報を同期先ストアに送信しません。

これらの競合解決ポリシーはすべて項目レベルで適用できますが、セッションには同期元優先および同期先優先のみが適用されます。プロバイダに同期ポリシーを指定するには、ConflictResolutionPolicy プロパティを設定します。

destinationProvider.Configuration.ConflictResolutionPolicy =   ConflictResolutionPolicy.DestinationWins;

既定の構成を使用するのではなく、同期の進行状況を通知するようにプロバイダを構成することもできます。既定では、プロバイダが進行状況を通知する場合には関連付けられた SyncCallback オブジェクトの ProgressChanged イベントを呼び出します。この動作を変更して固有の進行状況通知機能を実装することができます。そのためには、ItemChange クラスの WorkEstimate イベントを使用してイベントを項目レベルで実装するか、ChangeBatch クラスの BatchWorkEstimate イベントを使用してイベントをバッチ レベルで実装する必要があります。これにより、必要なときにいつでもプロバイダ コード内でプロバイダの OnProgressChanged メソッドを呼び出して変更を通知できます。

まとめ

Microsoft Sync Framework はアプリケーションに同期を組み込むためのアプリケーション プログラミング フレームワークです。このフレームワークは、異なるデータ ソース間の同期処理を簡素化するさまざまな機能やライブラリを備えていますが、実際に同期を実行するわけではありません。変更を検出して適用するロジックと競合を解決するロジックは開発者に委ねられます。

Sync Services は、SQL Server、ファイル システム、RSS などの一般的なデータ ストア間の同期処理に役立つ一連のライブラリです。Sync Services を使用すると、同期ロジックの開発は簡単です。ライブラリをアプリケーションに応じて適用するだけで、短時間で簡単に同期できます。Microsoft Sync Framework を適用して、固有のアプリケーションにオフライン データ アクセスとコラボレーションの機能を簡単にサポートできます。

James Yip は、MCT、MCITP、MCPD、PMP の資格を持ち、香港に本社を置くテクノロジ コンサルティング会社、Eventus Limited の管理コンサルタントでもあります。James は設計およびプロジェクト担当マネージャとしての職務に従事しています。また、Windows サーバー システム管理および .NET 開発の MOC クラスの講師を務め、MOC コースと作成者コースウェアの SME および TR の職務にも携わっています。