まだプログラマーですが何か?

プログラマーネタとアスリートネタ中心。たまに作成したウェブサービス関連の話も http://twitter.com/dotnsf

CouchBase は大規模データ処理を得意とする No-SQL なデータベースです。ベースとなった CouchDB と memcached の機能を合わせ持っていることで高速トランザクションに耐え、またウェブアプリケーションサーバーを内蔵していることで管理機能だけでなく、ウェブアプリケーションの開発もすぐに開始できる、という特徴があります。加えて REST ベースのデータ読み書き API が標準で用意されている(というか、データの読み書きには REST を使う)ので、特定言語やプラットフォームに依存しない多くの環境から利用することができる、という特徴もあります。


この CouchBase を CentOS 環境にインストールします。なお CentOS は 64bit 版の 6.5 を、CouchBase のバージョンはこのエントリ執筆現在の最新版 2.5.1 を使う前提で以下を紹介します。今回は Enterprise Edition を利用しますが、この Enterprise Edition は無償でダウンロードでき、非商用利用であればノード数無制限に、商用利用でも2ノードまでは無償で利用できます。


まずは導入用のモジュールを入手します。公式サイトから環境にあったモジュールを選択してダウンロードします。今回のケースでは 64bit Red Hat 6 の Enterprise Edition を選択します。
2014060601


処理を進めていくと、最終的にダウンロードURLの書かれたメールを受け取ることになります。記載された URL からインストールモジュールをダウンロード&インストールします:
# cd /tmp
# wget http://packages.couchbase.com/releases/2.5.1/couchbase-server-enterprise_2.5.1_x86_64.rpm
# rpm -ivh couchbase-server-enterprise_2.5.1_x86_64.rpm

これだけでインストールは完了です。ついでに CouchBase サーバーの起動も完了しています。秒殺。


では Web ベースの管理コンソールにアクセスして、初期設定まで行ってしまいましょう。ブラウザで
 http://(サーバーのIPアドレス):8091/
にアクセスします(クラウドなどでファイアウォールの設定が必要な場合は 8091 番ポートを開放しておきます)。

以下の様なセットアップ用の初期画面が表示されます。"SETUP" ボタンをクリックしてセットアップを開始します:
2014060602

最初の画面ではデータの保存ディレクトリとクラスタリングの設定を行います。保存ディレクトリは特に希望がなければデフォルトのままでも大丈夫です。次にこのサーバーのホスト目(またはIPアドレス)を入力します。クラスタ設定ではまずは1台目のサーバーになるので "Start a new cluster" を選択します。この画面の最後にこのクラスタで使用するメモリ量の指定を行いますが、とりあえずは変更せずにそのまま進めても構いません。
2014060603


次の画面ではサンプルバケットを利用するかどうかの設定を行います。CouchBase では実際のデータの入れ先のことを(データ)バケットと呼びます。そのバケットのサンプルを一緒に導入するかどうかの設定です。これがあるとすぐに動くものを確認できるようになりますが、実運用上では不要なものです。必要であればチェックを付けて次の画面に向かいます:
2014060604


次にデフォルトバケットの設定を行います。まず Backet Settings ではバケットの種類を選択します。ここではディスク永続性はないものの RAM メモリ上だけで高速に動作する memcached を選択することも可能です。一方 CouchBase は memcached の特徴に加えて、非同期/同期にディスクへの永続化を行うことも可能なデータベースになっています。 ここでは CouchBase を選ぶことにします。
Memory Size は前の画面で設定した割り当てメモリのうちの、このデフォルトバケットに割り振るメモリ量を指定します。バケットが1つだけであれば全てのメモリを割り振って構いませんし、よく分からなければ初期状態を変更せずにそのまま進めても構いません。
最後の Replication はデータの冗長性を指定する項目です。1 は「冗長数が1」、つまり2台のサーバーでデータを保持することを意味します。1台のサーバーが障害で止まっても、フェールオーバーによってデータは保たれることになります。この数が多いほど信頼性も上がりますが、それだけ多くのサーバーやリソースが必要になります。ここでは 1 を指定することにして次の項目に進みます:
2014060605


次は製品のアップデートと登録の画面です。Update Notifications にチェックを入れておくと製品がアップデートされた時に通知を受け取ることができます。また Register をしておくと最新情報が届くことに加え、緑の少ない地域に苗木を一本寄付することになるようです(お金を支払うわけではありません)。是非 Register しましょう:
2014060606


設定の最終画面です。管理者の ID(初期状態は Administrator)とパスワードを入力します。これで初期設定は完了です:
2014060607


このような管理画面が出てくれば初期設定も完了です。初期設定まで含めて考えると、CouchBase の導入手順はものすごく簡単な印象です:
2014060608



最後に、この稼働中の CouchBase サーバーに API からアクセスしてみます。今回は curl コマンドを使って、こんな感じでサーバープール情報を取得します(実際には改行なしのデータが返ってきます):
# curl 'http://(CouchBase サーバーのIPアドレス):8091/pools'
{ "pools":[ {"name":"default","uri":"/pools/default?uuid=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx","streamingUri":"/poolsStreaming/default?uuid="} ], "isAdminCreds":false, "isROAdminCreds":false, "isEnterprise":true, "settings":{ "maxParallelIndexers":"/settings/maxParallelIndexers?uuid=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", "viewUpdateDaemon":"/settings/viewUpdateDaemon?uuid=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" }, "uuid":"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", "implementationVersion":"2.5.1-1083-rel-enterprise", "componentsVersion":{ "public_key":"0.13", "asn1":"1.6.18", "lhttpc":"1.3.0", "ale":"8ca6d2a", "os_mon":"2.2.7", "couch_set_view":"1.2.0a-a425d97-git", "compiler":"4.7.5", "inets":"5.7.1", "couch":"1.2.0a-a425d97-git", "mapreduce":"1.0.0", "couch_index_merger":"1.2.0a-a425d97-git", "kernel":"2.14.5", "crypto":"2.0.4", "ssl":"4.1.6", "sasl":"2.1.10", "couch_view_parser":"1.0.0", "ns_server":"2.5.1-1083-rel-enterprise", "mochiweb":"2.4.2", "syntax_tools":"1.6.7.1", "xmerl":"1.2.10", "oauth":"7d85d3ef", "stdlib":"1.17.5" } }

これも簡単ですよね。

なお、couchBase 2.5.x の REST API 詳細についてはドキュメントを参照してください。



IBM Bluemix チャレンジでは、用意された多くのミドルウェアサービスを使ってアプリケーションを構築・開発することになると思いますが、入賞を狙おうとするとやはりなるべく IBM 製品を使ってアピールすべきではないか(苦笑)、とも思うわけです。

そんなわけで今回のエントリでは IBM DB2 が持つ特徴的な機能を紹介します。こういうことをやろうとすると DB2 の特徴を活かしてプログラミングや構築ができる、というサンプルになれば。


最近の話ではないのですが、DB2 に V9 から搭載された XML ストア機能というものがあります。

リレーショナルデータベースである DB2 に XML という型の列を定義することができます。そしてこの列には XML データをそのまま格納することができます。テーブル作成時にはこんな感じで定義します:
create table test(id int not null, data xml, updated timestamp)


他のリレーショナルデータベースでもちょっと無理をすればテキスト型の列を定義して、そこに XML を(文字列として)格納する、ということもできます、格納するだけであれば。

でも決定的な違いもあります。それは XML データを(文字列ではなく) ネイティブな XML データとして格納している、という点です。これによって以下のようなことができるようになります。

例えば上記の内容で定義した test テーブルに以下のようなレコードが格納されていると仮定します(最後のupdated列は無視します):
IDDATA
1<Response><Say language="ja" gender="woman">いい天気ですね</Say></Response>
2<Response><Say language="en" gender="man">Hello. What are you going do today?</Say></Response>
3<Response><Say language="ja" gender="man">encode と decode</Say></Response>

この状態のテーブルの DATA 列から色々な条件でレコードを検索したい時、普通の text 型データだと一般的には like 節を使った SQL の全文検索を実行することになると思います。例えば「天気」という文字を含むレコードを検索するにはこんな感じで:
> select * from test where data like '%天気%'

上記例であれば ID = 1 のレコードが検索されるはずです。text 型のデータでもこのくらいはできます。

では「<Say>要素の language 属性が "en" のものだけを検索したい」場合はどうでしょう?ケースとしては「英語で格納されているデータだけを取り出したい」ような場合です。先程の応用で SQL はこんな感じでしょうか?
> select * from test where data like '%en%'

でもこれだと ID = 2 だけでなく、(本文の中に "en" が含まれる)ID = 3 のレコードも検索されてしまいます。求めたかった結果とは違ってしまいますね。とはいえ text 型のデータに対する SQL はこの辺りはシンプルにはいかないのです。

一方、XML 型で格納した場合はどうでしょう? DB2 の XML 列に対しては XPath を使ったクエリーを実行できます。今回の例であれば、こんな具合で SQL(?) を実行します:
> select * from test where xmlexists( '$t/Response/Say[@language="en"]' passing test.data as "t" )

XPath を使って test テーブルの data 列の中身で <Reponse> 要素の下の <Say> 要素の language 属性が "en" のものを指定して検索しています。つまり単なる全文検索ではなく、XML のデータの属性値を対象に絞り込みを行っています。XML データとして扱うことができるので、もちろん「テキスト値だけを対象とした検索」や「他の属性値による絞り込み」を行うことも可能です。

この方法によって、非構造的なデータを XML の形式で保存するだけでなく、XML データとしてのテキスト検索や属性検索、といった非構造データの特性に合わせたクエリーの実行もできるようになるのでした。


・・・と、こんな具合に XML フォーマットのデータや、XML フォーマットに変換できる非構造データに関しては DB2 の XML ストア機能を使って保存することで、単なる全文検索だけでなく、そのデータの特性に合わせた検索も可能になるのでした。



 

NoSQL データベースの1つで、非構造データを JSON 形式で保持できる mongoDB を「レプリカセット」と呼ばれる方法でクラスタリングします。

今回は3台の CentOS マシンによるクラスタ構成を行います。1台がプライマリ、1台がスレーブ、そして1台がアービターと呼ばれるフェイルオーバー時のマスター選択専用ノード(データは保持しない)で構成します。


プライマリ/スレーブ/アービターそれぞれのマシンの IP アドレスは P.P.P.P / S.S.S.S / A.A.A.A であると仮定して以下を記載します。


まず、3台のマシンそれぞれに MongoDB をインストールします。MongoDB の導入手順にそのものについては以下を参照してください:
mongoDB を CentOS 上にインストールする

上記手順最後のコマンド "chkconfig mongod on" までが実行されていれば、3台のマシン上それぞれで MongoDB が(独立して)稼働している状態になっています。


ここからがレプリカセット環境構築のための設定になります。まずそれぞれのマシン上で /etc/mongod.conf を編集します。編集内容は2点で (1) bind_ip 行をコメントアウト、 (2) replSet 行を追加 します:
# vi /etc/mongod.conf
  :
  :
# bind_ip=127.0.0.1 (コメントアウト)
  :
  :
replSet=testRS (この1行を追加)
  :
  :
なお、replSet=XXX で追加する行の XXX 部分は同じ文字列(上記例では testRS )を指定します。これによって3台の mongoDB サーガーが同一のレプリカセット環境上にあることを指定します。

bind_ip 行は接続を受け付ける元のアドレス範囲を指定する行です。127.0.0.1 が指定されていると localhost のみが指定されたことになり、他のマシンからの接続を受け付けなくなってしまうのでコメントアウトします。

ここまで出来た所で、3台のマシンそれぞれで mongoDB を再起動します:
# /etc/init.d/mongod restart


次にプライマリサーバー(P.P.P.P) 上で、各マシンの役割を指定します。プライマリサーバー上でコンソールにログインします:
# mongo

> 

コンソール画面内で以下を実行します:
> config = { _id:"testRS", 
  members:[
    { _id:0, host:"A.A.A.A:27017", arbiterOnly:true }, 
    { _id:1, host:"P.P.P.P:27017" },
    { _id:2, host:"S.S.S.S:27017" }
  ]
}
 :
:
> rs.initiate( config ) :
:
>

上記コマンドで testRS(replSet に指定した文字列値)に属する3台のマシンの IP アドレスとポート番号を指定し、A.A.A.A のマシンについてはアービターのノードであることも指示しています。 そしてその内容を rs.initiate コマンドで実行して初期化しています。

これが成功するとレプリカセットの完成です。rs.status() コマンドでレプリカセットの設定状況を確認することもできます:
> rs.status()
{
  "set": "testRS",
  "date": ISODate("2014-06-02T12:34:56Z"),
  "myState": 1,
  "members": [
    {
      "_id": 0,
      "name": "A.A.A.A:27017",
      "health": 1,
      "state": 7,
      "stateStr": "ARBITER",
      "uptime": 30,
      "lastHeartbeat": ISODate("2014-06-02T12:34:56Z"),
      "pingMs": 1
    },
    {
      "_id": 1,
      "name": "P.P.P.P:27017",
      "health": 1,
      "state": 1,
      "stateStr": "PRIMARY",
      "uptime": 80,
      "optime": Timestamp(1357209986000, 1),
      "optimeDate" : ISODate("2014-06-02T12:34:56Z"),
      "self": true
    },
    {
      "_id": 2,
      "name": "S.S.S.S:27017",
      "health": 1,
      "state": 2,
      "stateStr": "SECONDARY",
      "uptime": 30,
      "optime": Timestamp(1357209986000, 1),
      "optimeDate" : ISODate("2014-06-02T12:34:56Z"),
      "lastHeartbeat": ISODate("2014-06-02T12:34:56Z"),
      "pingMs": 1
    }
  ],
  "ok": 1 
}

> 

_id = 0 のマシンがアービター、1 のマシンがプライマリ、2 のマシンがスレーブになっていることを確認します。


一応これでレプリカセット環境としては動くようになりました。が、このままだとスレーブサーバーはプライマリサーバー以外のマシンからの接続を許可しないため色々不便です。というわけで、最後にスレーブサーバーにプライバリサーバー以外からも接続できるよう設定します。

スレーブサーバー上でコンソールにログインし、db.getMongo().setSlaveOk() コマンドを実行します:
# mongo

> db.getMongo().setSlaveOk()

>

これでスレーブサーバーに他のマシンから接続して状況を確認することもできるようになりました。




このページのトップヘ