本日は、データベースの複製に関する話題です。
ずいぶん前にも社内のデータを外部のサーバに持っていく仕組みを作ったことがありますが、なぜに皆さんわたしにこういう作業を振ってくるんでしょうね?(笑
XML使ってみよう!
さて、今回の要望ですが、あまりシビアに複製が作れる必要はなく、ネットワーク的に遠いところにあるデータベースを手元において高速にアクセスできるようになれば良いというものです。
素直に処理するなら、サーバ側でダンプを作って、それをネットワーク越しに持ってきて社内のデータベースに復元すれば良いと言うことになります。
しかし、実際に作業に入ってから、びっくり。
なんと、ウェブサーバ上で稼動しているデータベースシステムと社内でデータを持ってきて欲しいといわれているデータベースサーバがまったく違うものだったのです。
なるへそ、だから、わざわざこんな簡単な(失礼!)案件でわが社のような外部に依頼が来たのかと納得です。
今回依頼のあった客先とはまったく別で、以前も同じようにまったくデータベースシステムの違うものについて同期を行なわせたことがあるのですが、その時には独自のプロトコルを準備してネットワーク越しに同期を行なわせました。
しかし、今回の場合はそこまで大規模な仕組みを構築するほどのものではないと判断し、お手軽、お気軽プログラミングを行なって対処することに決めました。
ウェブサーバ側で、データベースの必要な部分を編集し XML 形式でデータを流させます。それを取り込んで社内のデータベースを更新しようと言うわけです。
サーバ側
サーバ側の処理は、PHP にて実行することにしました。
特定のURLにアクセスしに行くと、テーブルの内容をまんまXMLに変換して返してくると言う、ただそれだけです。
テーブルに SELECT でアクセスしに行って全レコードをループしながら XML のデータを吐き出すと言うただそれだけ。
お気軽です。
ただ、変なところではまるのが嫌だったので、データベースの DDL から PHP のコードを吐き出す perl のスクリプトを作って対処しました。ま、一度走らせるだけの、かなり手抜きのスクリプトなのでここで紹介する気はありません。(笑
クライアント側
クライアント側と言うのが、社内のシステム。
ここでは、サーバにアクセスしに行って、返ってきた XML を処理して、今度はそれを社内データベースへ反映させる処理を書くことになります。
そこで登場するのが、relaxer。
XML を処理するプログラムを書くとなると、DOM やら SAX やらが登場することになりますが、今回はお気軽にやってしまうつもりだったので、この relaxer に XML 処理を行なう Java クラスを生成してもらい、それを使ってデータベースを更新させることにしました。
まずは、この relaxer が処理する RELAX NG に準拠した rng ファイルを作成します。このファイル自体も簡単な XML ファイルです。
雰囲気だけでもつかんでいただくために、サンプルを以下に示しておきます。
<?xml version="1.0" encoding="UTF-8" ?>
<grammar
xmlns="http://relaxng.org/ns/structure/1.0"
xmlns:a="http://relaxng.org/ns/compatibility/annotations/1.0"
xmlns:relaxer="http://www.relaxer.org/xmlns/relaxer"
xmlns:java="http://www.relaxer.org/xmlns/relaxer/java"
xmlns:sql="http://www.relaxer.org/xmlns/relaxer/sql"
datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes"
ns="">
<start>
<ref name="userProperties"/>
</start>
<define name="userProperties">
<element name="userProperties">
<ref name="result"/>
<oneOrMore>
<ref name="record"/>
</oneOrMore>
</element>
</define>
<define name="result">
<element name="result">
<element name="code">
<data type="integer"/>
</element>
<element name="timezone">
<data type="string"/>
</element>
<element name="message">
<text/>
</element>
</element>
</define>
<define name="record">
<element name="record">
<element name="id">
<data type="string"/>
</element>
<element name="passwd">
<data type="string"/>
</element>
<element name="name">
<data type="string"/>
</element>
<element name="kana">
<data type="string"/>
</element>
<element name="mailAddress">
<data type="string"/>
</element>
<element name="span">
<data type="integer"/>
</element>
<element name="temporary">
<data type="integer"/>
</element>
<element name="ts">
<data type="dateTime"/>
</element>
<element name="modifyTs">
<data type="dateTime"/>
</element>
<optional>
<element name="kAddress">
<data type="string"/>
</element>
</optional>
</element>
</define>
</grammar>
びっくりするほど難しいものでもありません。
これを relaxer で処理すると、Java のクラスが一式作成されて、プログラム中からは、普通に Java オブジェクトとして、getHogehoge() みたいな形で XML ファイルの中身にアクセスが出来るようになります。
つまり、XML ファイルを準備して、あとはこの XML 文書の構造を示す rng ファイルを準備してあげれば文書解析のプログラムを書く必要はほとんどゼロと言うわけです。
今回の場合は、http による接続を行なうためのコードと、そこからストリームを取り出して、relaxer が吐き出してくれたクラスに放り込むだけで、データを取り出すことができるようになりました。
あとは、JDBC 経由で社内のデータベースを更新するだけ。
お気楽、お気軽プログラミングのおしまいというわけです。
とか言いつつはまった部分
などとえらく簡単に出来てしまったように書いていますが、実際には、わたし自身が思い込みをしてた部分があって、それを解決するのにちょっと時間がかかってしまった部分があります。
それは、サーバ側で吐き出した XML 文書と、.rng ファイルで指定していた文書の構造が一致していないという問題です。
人間、一度思い込んでしまうと、「ここは大丈夫」と思って、原因がもっと別のところにあるものと考えてしまい、なかなか解決に至らないことがあります。
見るべき場所が違っていては発見できるものも発見できないと言う、あたりまえの話です。
人間が見つけられないものは機械に見つけてもらおうと言うことで、最初の最初にやっておくべき Jing による XML ファイルのチェックを敢行。
3秒で悪いところがわかって、「ほへー、わたしが悪うございましたー」となってちょん。(大汗
その他
まぁ、ここに書くためにかなり話を単純にしてしまいましたが、実際には稼動中のサービスを止めないための工夫とかネットワークの帯域を使いすぎないようにこの処理に関しての流量を制限する仕組みがあったりしました。
そのあたりの話も機会があれば書いてみたいと思います。
