7.1.2 同期プロセス
これまでのところで、統合データベース、Mobile Linkサーバ、リモートデータベースの役割を説明した。次に、どのように同期処理が行われるのか見ていくことにする。
同期プロセスは、アップロードとダウンロードの2つのプロセスからなる(図7.7)。同期プロセスの起点は同期クライアントだ(注6)。同期クライアントとは、リモートデータベースと同じデバイス上で動くdbmlsyncというプログラムで、Mobile Linkサーバに対するデータの送受信を担当する。起動された同期クライアントは、リモートデータベースのトランザクションログを調べて、前回同期成功時以降に変更のあった行のみを抽出し、Mobile Linkサーバに送信する(アップロードストリーム)(注7)。送信されるデータの形式はMobile Link独自のものである。
アップロードストリームを受け取ったMobile Linkサーバは、それをSQL文に翻訳して統合データベースにODBC経由で実行する。こうして、リモートデータベースのデータが統合データベースに反映される。翻訳の方法に関しては、あらかじめアップロード用の同期スクリプトとして作成し、統合データベースに保存しておく。Mobile Linkサーバは同期前に同期スクリプトを調べ、同期処理に利用する。
続いて、Mobile Linkサーバはダウンロード用の同期スクリプトに従って統合データベースからODBCでデータを取得し、そのデータをMobile Link固有のデータ形式にして元の同期クライアントに返信する(ダウンロードストリーム)。この同期スクリプトもSQL文としてあらかじめ用意しておく。
ダウンロードストリームを受け取った同期クライアントは、そのデータをリモートデータベースに反映させる。
以上がMobile Linkによる同期プロセスの概略だ。「アップロードとダウンロードの2つの過程で同期が処理され、処理の仕方は同期スクリプトとして作成しておく」ことが現段階ではわかればよいが、ここで重要なポイントは以下の2つだ。
- Mobile Linkサーバと同期クライアントがトランザクションを管理しているので、同期途中でエラーが起こったり通信回線が切断されてしまったりしても更新データはロールバックされて同期前の状態に戻り、統合データベースもリモートデータベースも不整合を起こさない。
- 統合データベースから見れば、Mobile LinkサーバはODBC経由でSQLをやり取りする通常のデータベースクライアントなので、同期スクリプトに記述可能なロジックは統合データベースが提供する環境そのものである。よって、同期処理に関する統合データベースの設定やチューニングも、通常のデータベースクライアントと同じように行えばよい。
SQL Anywhere Studio 8からの変更
SQL Anywhere Studio 8.0.2からは同期プロセスが改良されている。8.0.1までは、ダウンロードストリームのあとでリモートデータベースからMobile Linkサーバへの確認プロセスというものがさらに必要だった。SQL Anywhere Studio 8.0.2以降では、その確認プロセスは省略可能となり、上述したアップロードストリームとダウンロードストリームによる同期プロセスがデフォルトとなっている。確認プロセスがなくなったことで、同期パフォーマンスが向上した。
アップロード時にMobile Linkへ送られるトランザクション
同期クライアントがリモートデータベースのトランザクションログからアップロードストリームを作成するとき、1つの行(主キー)に対する複数のトランザクションは1つにまとめられ、転送の無駄が省かれる。たとえば、次のようなテーブルがリモートデータベースにあったとしよう。
CREATE TABLE Sample ( ID INT PRIMARY KEY, VALUE INT )
このテーブルに、3つのトランザクションを流す。
INSERT INTO Sample VALUES (1, 10); UPDATE Sample SET VALUE = 20 WHERE ID = 1; UPDATE Sample SET VALUE = 30 WHERE ID = 1;
ここで同期すると、3つのトランザクションではなく、1つのトランザクションとして送られる。アップロードストリームのイメージを仮にSQL文で表すとすれば、次のようになる。
INSERT INTO Sample VALUES (1, 30)
このように、1つの行に対してデータ操作を行うSQL文(INSERT、UPDATE、DELETE)を繰り返しても、アップロードストリームでは最終結果となる1つのトランザクションとして送られる(注8)。したがって、追加された行が同期されることなく削除されれば、次回同期時にはその行は送信されない。
以上がデフォルトの動作であるが、同期クライアントの -tuオプションで、この機能をオフにできる(transaction-level upload)。統合データベース側でトリガを利用してロジックを実装しているなど、トランザクションをまとめたくない場合に効果的だ。
アップロードストリームの「前回同期成功時」とは
アップロードストリーム生成の開始点となる「前回同期成功時」とは、技術的にはトランザクションログのオフセット番号として管理されている(注9)。オフセット番号とは、トランザクションのID番号のことで、コミットごとに採番されてトランザクションログに記録される。オフセット番号の大小はコミットされたトランザクションの時系列に一致し、オフセット番号が小さいほど過去のものとなる。「同期クライアントがアップロードストリームを生成するとき、リモートデータベースのトランザクションログを調べる」と書いたが、これは指定されたオフセット番号以降(から最新まで)のトランザクションについて調べることを意味する。
前回成功時のオフセット番号は、リモートデータベースのSYSSYNCテーブルと統合データベースのML_SUBSCRIPTIONテーブルが保持し、アップロードストリームの終了時に、新しいオフセット番号がそれぞれ記録される。このためダウンロードストリームの途中で回線が切断して同期が失敗し、再度同期したとしても、すでにオフセット番号は更新されているので(ダウンロードストリームが開始されたということは、アップロードが正常に行われたことを意味する)、先ほどアップロードされたデータが再送される無駄はない。
アップロードストリーム開始時に統合データベースとリモートデータベースそれぞれのオフセット番号を比較し、データベースの整合性を保とうとする。もし両者のオフセット番号が異なれば、デフォルトでは統合データベースのオフセット番号を使ってアップロードストリームをやり直す。統合データベースのオフセットが小さい場合(統合データベースがバックアップからリストアされた場合など)、アップロード済みのトランザクションが再送される。一方、リモートデータベースのオフセット値が小さい場合(リモートデータベースがバックアップからリストアされた場合など)、統合データベースのオフセット値以降のトランザクションがアップロードされた後データがダウンロードされる。いずれの場合も、障害が起きたほうのデータベースが障害時点のデータに近づくので、通常はこのデフォルト動作で問題ない。
デフォルト動作で都合が悪い場合は、dbmlsyncの-raや-rbオプションで制御できる。たとえば、バックアップされていたリモートデータベースをリストアした場合、統合データベースのオフセット番号はリストアされたリモートデータベースには存在しない可能性もあり、デフォルト動作では同期できないこともある。このような場合には、-rbオプションを使えばリモートデータベースのオフセット番号が強制的に使われるようになり、同期が成功する。ただし、この場合、同期が成功したとしても、データ抜けが起きえるので、データの一貫性が損なわれる可能性がある。
リモートデータベースのロック
同期処理の整合性を保つため、同期処理の間(アップロードストリームの作成からダウンロードストリームの適用まで)、同期クライアントはリモートデータベースの同期対象テーブルに共有ロックをかける(注10)。同期処理中に同期とは別のトランザクションが発生してしまうと、前回同期以降の変更をアップロードする際などで整合性が保てないからだ。よって、同期処理中のテーブルに対して、ほかのトランザクションは読み取りできるが書き込みできない。
Mobile Linkサーバのアイソレーションレベル
Mobile Linkサーバが統合データベースにODBC接続する際、そのアイソレーション(isolation:独立性)レベルはデフォルトでSQL_TXN_READ_COMMITTEDとなっている。競合解決時に反復可能読み取り(repeatable read)が必要となるからだ。
読み取り一貫性を有効にするには(デフォルトは無効)、
SET OPTION PUBLIC.allow_snapshot_isolation = 'On';
7.1.3 まとめ
Mobile Linkの同期プロセスはアップロードとダウンロードからなり、統合データベースに保存されているそれぞれの同期スクリプトに従って、Mobile Linkサーバが同期を行う。同期スクリプトの書き方を、次節以降で具体的に見ていく。