2013-03-15

[.tested] Joruri CMS 1.3.1 [AX3]

Joruri CMSは、Ruby(on Rails)とMySQL上で動作するオープンソースのCMS(コンテンツマネジメントシステム)です。
日本で開発された、Ruby言語を使った、RESTの考えに従った、統合的なCMSであり、名前の由来はJapan Originated Ruby-based RESTful and Integratedの頭文字からつけられています。
本CMSは徳島県と株式会社アイ・ディ・エスにより共同開発されたものですが、オープンソースソフトウェアとして一般公開されており、現在も、多くの自治体で汎用的に利用できるCMSとして機能や操作性の拡張が行われています。
最新の情報は以下のサイトを参照してください。

Joruri公式サイト

最新のリリースである、joruri CMS 1.3.1をインストールするための想定環境は以下の通りです。

[システム]
OS         : CentOS 6.3
Webサーバ  : Apache 2.2
DBシステム : MySQL 5
Ruby       : 1.9.1
Rails      : 2.3.16

今回は、joruri CMS 1.3.1をARMアーキテクチャであるOpenBlocks AX3上のdebian 6.0上にインストールします。
また、debian 6.0の環境は、LXC上のゲストOSとして構築します。

OBDN技術ブログによる動作検証は、該当するソフトウェアの動作を保証およびサポートを行うものではありません。
内容に関するご指摘などありましたら、ブログ記事の担当までご連絡下さい。

<検証環境>
OpenBlocks AX3/4 Debian 6.0 kernel: 3.0.6
LXC 0.7.5 / ゲストOS: Debian 6.0

1.LXCの導入


今回、評価環境を、LXCのゲストOS(Debian squeeze)上で構築しました。
仮想化を行わない場合は、この作業は必要ありません。

LXC環境の構築について

 以下のページの手順に従って作業してください。

 OpenBlocks AX3でLXCによる仮想化を試してみる

初期設定について

先に、タイムゾーンの設定、ロケールデータの作成を行います。
ただし、lxc-createしてすぐの状態では、vimなどのツールがないため、
apt-getにより必要なものを追加する必要があります。
また、aptitudeパッケージも最初は含まれていませんので、先にaptitudeパッケージをapt-getにより導入します。

# apt-get install aptitude
# aptitude update
# aptitude install vim

 タイムゾーンの設定:
# dpkg-reconfigure tzdata

 ロケールデータの作成:
# vi /etc/locale.gen
   ja_JP.UTF-8 等の必要なロケールをアンコメント(行頭の#を消す)する

# locale-gen

また、今回は、CMSサーバとして使用しますので、/etc/network/interfacesのeth0は、dhcpによるIPアドレス設定ではなく、固定のIPアドレスを指定します。
IPアドレスは、それぞれの環境で割り当てられたものを使用してください。
以下の例では、割り当てられたIPアドレスを、192.168.253.248、gatewayが192.168.253.1と想定しています。

auto eth0
iface eth0 inet static
    address 192.168.253.248
    network 192.168.253.0
    netmask 255.255.255.0
    broadcast 192.168.253.255
    gateway 192.168.253.1

開発環境の導入について

まず、よく利用するツールをインストールします。

# aptitude install tasksel
# tasksel install standard

開発用のツール類をインストールします。

# aptitude install build-essential

上記の作業により、LXCのゲストOS上での開発環境が構築されます。

また、LXC仮想環境の複製を行いたい場合ですが、上記の記事で導入した場合、

# ln -s /usr/local/var/lib/lxc /var/lib/lxc

とした後、元の、/var/lib/lxc/<元のコンテナ名>/config を、複製した/var/lib/lxc/<複製したコンテナ名>/configに上書きして、config内の<コンテナ名>の部分を書き換えることにより代替環境として動作させることが出来ます。
(lxc-0.7.5では、インストール時に、/usr/local/var/lib/lxcが指定されていますが、この部分が一部のツールと整合性が取れていないようです。)

また、上記の記事にある通り、そのままではudevのインストールによりエラーが出ます。
これは記事にあるように、configファイルを変更することにより、インストールエラーそのものは出なくなります。
ただし、この場合、立ち上げたコンソールが使用出来なくなりますので、別途sshでlxcコントロール用のターミナルを確保して下さい。

2.apacheの導入


パッケージのインストール

# aptitude install apache2

 インストールのみで起動します。

mod_rewriteを有効にする

# a2enmod rewrite


3.mysqlの導入


パッケージのインストール

# aptitude install mysql-server

 インストール時にMySQLを管理するrootユーザのパスワードを聞かれるため、
 予め決めておく必要があります。

動作確認

# mysql -u root -p

mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
+--------------------+
2 rows in set (0.00 sec)

mysql>



4.joruri CMSパッケージのインストールのための事前準備


以下のマニュアルを参考に作業を進めます。ただし、想定環境がCentOS 6.3であるため、debian 6.0では導入するパッケージや、設定方法が異なります。

Joruri CMS 1.3.1 インストールマニュアル

まずは、root権限で作業を行います。

必要なパッケージの導入

apache(httpd)、mysqlに関してはすでに上記で導入作業を行っているため、必要ありません。
aptitudeコマンドにより、以下のパッケージを導入してください。

# aptitude install <パッケージ名>
libxslt-dev
libjpeg-dev
libpng-dev
librsvg2-dev
ghostscript
imagemagick
libmagickcore-dev
libmagickwand-dev
libcurl4-openssl-dev
nkf
apache2-dev

必要なソースコードファイルのダウンロード

 インストールマニュアルの通り、wgetコマンドによりダウンロードを行います。

  # cd /usr/local/src/
  # wget http://joruri.org/download/joruri-1.3.1.tar.gz \
      http://core.ring.gr.jp/archives/lang/ruby/1.9/ruby-1.9.1-p378.tar.gz \
      http://rubyforge.org/frs/download.php/60718/rubygems-1.3.5.tgz \
      http://chasen.org/~taku/software/darts/src/darts-0.32.tar.gz \
      "http://sourceforge.jp/frs/redir.php?m=jaist&f=%2Fchasen-legacy%2F32224%2Fchasen-2.4.4.tar.gz" \
      "http://sourceforge.jp/frs/redir.php?m=iij&f=%2Fipadic%2F24435%2Fipadic-2.7.0.tar.gz" \
      http://downloads.sourceforge.net/lame/lame-398-2.tar.gz

Joruriユーザの作成

  # useradd joruri
  # passwd joruri

Joruriソースコードの設置

  # mkdir /var/share
  # tar xvzf joruri-1.3.1.tar.gz -C /var/share
  # chown -R joruri:joruri /var/share/joruri

Apache の設定

 設定ファイルを編集します。アドレスは固定アドレスとして設定したものを使用してください。

  # vi /etc/apache2/httpd.conf
 
  ServerName 192.168.253.248

 設定ファイルにエラーがないことを確認し、Apacheを再起動します。

  # apachctl restart

MySQL の設定と、joruriユーザの作成

 文字エンコーディングの標準を UTF-8 に設定します。

  # vi /etc/mysql/my.cnf
   :
  [mysqld]
  character-set-server=utf8 #追加
   :

 MySQLを再起動します。MySQLはインストール時にすでに自動起動設定され起動しています。

  # /etc/init.d/mysqld restart

 rootユーザのパスワードは、aptitudeコマンドによりインストール時に設定しています。

 MySQL monitorを起動し、joruriユーザを作成します。

# mysql -u root -p
Enter password: ←インストール時に設定した(mysqlの)rootユーザパスワードを入力
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 39
Server version: 5.1.49-3 (Debian)

Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
This software comes with ABSOLUTELY NO WARRANTY. This is free software,
and you are welcome to modify and redistribute it under the GPL v2 license

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql>

 joruriユーザを作成します。

mysql> grant all on *.* to joruri@localhost IDENTIFIED BY 'pass';

 確認は以下のコマンドにより行います。

mysql> SELECT host,user FROM mysql.user;
+-----------+------------------+
| host      | user             |
+-----------+------------------+
| 127.0.0.1 | root             |
| deb-2     | root             |
| localhost | debian-sys-maint |
| localhost | joruri           |
| localhost | root             |
+-----------+------------------+
5 rows in set (0.00 sec)

mysql>

※パスワードは適切な値を設定してください。
本マニュアルでは pass と設定しています。

Rubyのインストール

  # cd /usr/local/src
  # tar xvzf ruby-1.9.1-p378.tar.gz
  # cd ruby-1.9.1-p378

 パッチをダウンロードします。
 
  # wget http://bugs.ruby-lang.org/attachments/download/837/openssl-build-fix-v2.patch

 以下の操作でうまくパッチが当らない場合は、
 openssl-build-fix-v2.patchを開いて手で修正してください。

  # patch -p0 < openssl-build-fix-v2.patch
    > File to patch:
      # 以下のパスを順に入力
      /usr/local/src/ruby-1.9.1-p378/ext/openssl/ossl.c
      /usr/local/src/ruby-1.9.1-p378/ext/openssl/ossl.h
      /usr/local/src/ruby-1.9.1-p378/ext/openssl/ossl_pkcs7.c
      /usr/local/src/ruby-1.9.1-p378/ext/openssl/ossl_ssl.c
      /usr/local/src/ruby-1.9.1-p378/ext/openssl/ossl_x509attr.c
      /usr/local/src/ruby-1.9.1-p378/ext/openssl/ossl_x509crl.c

 ビルド、インストールします。

  # ./configure
  # make && make install

RubyGemsのインストール

  # cd /usr/local/src
  # tar xvzf rubygems-1.3.5.tgz
  # cd rubygems-1.3.5
  # ruby setup.rb

gemライブラリ のインストール

 gemライブラリをインストールします。

  # ruby /var/share/joruri/doc/install/gems.rb
 
 以下のgemがインストールされます。

  # gem install rake --no-ri --no-rdoc -v 0.8.7
  # gem install rails --no-ri --no-rdoc --include-dependencies -v 2.3.16
  # gem install ruby-ldap --no-ri --no-rdoc -v 0.9.10
  # gem install rmagick --no-ri --no-rdoc -v 2.12.2
  # gem install zipruby --no-ri --no-rdoc -v 0.3.6
  # gem install mime-types --no-ri --no-rdoc -v 1.16
  # gem install will_paginate --no-ri --no-rdoc -v 2.3.16
  # gem install passiverecord --no-ri --no-rdoc -v 0.2
  # gem install tamtam --no-ri --no-rdoc -v 0.0.3
  # gem install mysql --no-ri --no-rdoc -v 2.8.1

Phusion Passenger のインストール

 Phusion Passengerをインストールします。

  # gem install passenger --no-ri --no-rdoc -v 3.0.19
  # passenger-install-apache2-module
    ( 画面の内容を確認して Enterキーを押してください。 )

 Apacheに設定を追加し、再起動します。

  # cp /var/share/joruri/config/samples/passenger.conf \
      /etc/apache2/conf.d/passenger.conf

  # apachectl restart

5.joruri CMS 1.3.1のインストール


Joruriユーザに変更します。

  # su - joruri
  $ cd /var/share/joruri

設定ファイルの編集

 環境に応じて設定ファイルを編集します。

Joruri基本設定

  $ vi config/core.yml
  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  title  : Joruri
  uri    : http://192.168.253.248/
  proxy  : ※プロキシ
  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

  uriは設定したIPアドレスにより異なります。 
   ※プロキシ
  プロキシサーバが導入されている場合は
   http://example:8080/ の様に記述してください。
 
DB接続情報

 必要に応じて変更してください。(今回は変更なし)

  $ vi config/database.yml

VirtualHost設定

 必要に応じて変更してください。(今回は変更なし)

  $ vi config/virtual-hosts/joruri.conf

データベースの作成

 データベースを作成します。

  $ /usr/bin/mysql -u root -p -e "create database joruri"

 テーブルを作成します。

  $ rake db:schema:load RAILS_ENV=production

 初期データを登録します。

  $ rake db:seed RAILS_ENV=production

 サンプルデータを登録します。

  $ rake db:seed:demo RAILS_ENV=production

VirtualHost の反映

 Apacheに設定を追加します。

  $ su -
  # ln -s /var/share/joruri/config/virtual-hosts/joruri.conf \
      /etc/apache2/conf.d/

 joruri.confの以下の部分を変更してください。

<VirtualHost 192.168.253.248:80>  ←設定したIPアドレス
    ServerName 192.168.253.248
    DocumentRoot /var/share/joruri/public_00000001
    Alias /_common/ "/var/share/joruri/public/_common/"
    setenv LANG ja_JP.UTF-8
    RailsEnv production
    Include /var/share/joruri/config/rewrite/base.conf
    Include /var/share/joruri/config/rewrite/00000001.conf
</VirtualHost>

 Apacheを再起動します。

  # apachectl restart

 ここまでの手順で Joruri にアクセスすることができます。

  公開画面 : http://192.168.253.248/  ←設定したIPアドレス

  管理画面 : http://192.168.253.248/_admin

 次のユーザが登録されています。

    管理者(システム管理者)
      ユーザID   : admin
      パスワード : admin

    一般ユーザ(徳島 太郎)
      ユーザID   : user1
      パスワード : user1

    一般ユーザ(阿波 花子)
      ユーザID   : user2
      パスワード : user2

    一般ユーザ(吉野 三郎)
      ユーザID   : user3
      パスワード : user3

6.ふりがな・読み上げ機能のインストール


 LAMEをインストールします。

  # cd /usr/local/src
  # tar xvzf lame-398-2.tar.gz
  # cd lame-398-2
  # ./configure --prefix=/usr
  # make && make install

 Dartsをインストールします。

  # cd /usr/local/src
  # tar xvzf darts-0.32.tar.gz
  # cd darts-0.32
  # ./configure --prefix=/usr
  # make && make install

 ChaSenをインストールします。

  # cd /usr/local/src
  # tar xvzf chasen-2.4.4.tar.gz
  # cd chasen-2.4.4
  # ./configure --prefix=/usr
  # make && make install

 IPAdicをインストールします。
 先に/usr/etcディレクトリを作成してください。

  # mkdir /usr/etc

  # cd /usr/local/src
  # tar xvzf ipadic-2.7.0.tar.gz
  # cd ipadic-2.7.0
  # ./configure --prefix=/usr

 辞書をUTF8に変換します。
 
  # vi to_utf8.sh  #(新規作成)
  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  #!/bin/sh
  for file in *.dic *.cha chasenrc
  do
  if [ -f $file ]; then
      nkf --utf8 $file > tmpfile
      mv tmpfile $file
  fi
  done
  exit
  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

  # chmod 744 to_utf8.sh
  # ./to_utf8.sh
  # `chasen-config --mkchadic`/makemat -i w
  # `chasen-config --mkchadic`/makeda -i w chadic *.dic
  # make install

 ChaOneをインストールします。

  # cd /var/share/joruri/ext/morph/chaone
  # chmod 775 configure
  # ./configure
  # make && make install

 GalateaTalkをインストールします。

  # cd /var/share/joruri/ext/gtalk
  # sed -i "s/ getline/ my_getline/" main.c
  # sed -i "s/ getline/ my_getline/" getline.c
  # chmod 775 configure
  # ./configure
  # make
  # chmod 747 /var/share/joruri/ext/gtalk_filter.rb

7.定期実行設定


 先にcronをインストールします。

# aptitude install cron

 記事の公開/非公開処理を設定します。
 以下の例は、毎時15分毎に記事の公開/非公開処理を行い、
 公開ディレクトリに記事を静的ファイルとして書き出します。

  # su - joruri
  $ crontab -e
  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  10,25,40,55 * * * * /usr/local/bin/ruby /var/share/joruri/script/runner \
    -e production "Script.run('sys/script/tasks/exec')"
  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

  ※公開ディレクトリ : /var/share/joruri/public_00000001

 トップページや中間ページを静的ファイルとして書き出します。

  $ crontab -e
  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  */15 * * * * /usr/local/bin/ruby /var/share/joruri/script/runner \
    -e production "Script.run('cms/script/nodes/publish')"
  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

 音声ファイルを静的ファイルとして書き出します。

  $ crontab -e
  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  */15 * * * * /usr/local/bin/ruby /var/share/joruri/script/runner \
    -e production "Script.run('cms/script/talk_tasks/exec')"
  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

 新着記事ポータルで設定したAtomフィードを取り込みます。

  $ crontab -e
  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  0 * * * * /usr/local/bin/ruby /var/share/joruri/script/runner \
    -e production "Script.run('cms/script/feeds/read')"
  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

8.動作確認


 joruriは初期状態で以下のサンプル画面が表示されます。
 一部を管理画面で書き換えました。

<トップページ>
<ふりがなをつけた状態 >
<読み上げ画面>

9.さいごに


今回、joruri CMS の最新バージョンである、1.3.1が、ARMアーキテクチャのOpenBlocks上で動作することを確認しました。
joruriは、CMSの他にjoruri GW(グループウェア)などもオープンソースとして公開されていますので、そちらのインストール、評価に関してもまた報告できればと思います。


2013-02-22

OSC 2013 Tokyo/Spring 出展中です

今週末は、OSC 2013 Tokyo/Springにブース出展しています。




開催概要は以下の通りです。

日程:2013年2月22日(金)10:00-18:00 (展示は11:00-17:30)
        23日(土)10:00-17:30 (展示は10:00-16:00)

会場明星大学 日野キャンパス 28号館 2F
   (多摩モノレール 「中央大学・明星大学駅」から大学まで直結。会場まで徒歩6分)
   [アクセスマップ] [キャンパスマップ] [OpenStreetMap]
   (ご来場の際は公共交通機関をご利用下さい)

費用:無料

内容:オープンソースに関する最新情報の提供
   ・展示 - オープンソースコミュニティ、企業・団体による展示
   ・セミナー - オープンソースの最新情報を提供

主催:オープンソースカンファレンス実行委員会

協賛明星大学
   明星大学 情報学部

企画運営:株式会社びぎねっと

 
OpenBlocks A Familyの展示のほか、OBDNマガジンに掲載された事例などを配布します。
また、金曜17:15分より、

 クラウド時代におけるLinuxマイクロサーバのポジショニングとその事例

と題してセミナー発表もさせていただきます。
(*intelの提唱するマイクロサーバとは別ものですのでご注意下さい)

 是非お立ち寄り下さい。

2013-02-13

USBシリアルコンバータを使用したコンソール接続について

ノートPCをOpenBlocksのコンソールにする場合、よほど古いものを使わない限り、RS-232Cの口がないため、USBシリアルインタフェースを使う必要があります。

自分の場合も、通常はRATOCのREX-USB60F(FTDI chip)を使用しているのですが、先日出張先のどこかで置いてきてしまい、同じものを買うのも悔しいので、秋葉原でノーブランドのUSBシリアルコンバータ(PL2303)を買ってきました。



PCはWindows7で、Prolificのドライバは自動で導入されます。また、Prolificのサイトからドライバ一式をダウンロードしてドキュメントを読むと、Windows7の場合は、ネットワーク越しのupdateで最新版が適用されるようです。

ご存知の方も多いとは思いますが、このchipsetを使ったUSBシリアルコンバータは、115200bpsで使用するとデータを落としやすいという話が多く、今回使用したモジュールでも、Teratermの使用では度々障害が出ました。
ただ、puttyで使用する限りは問題なく使えていますので、このモジュールを使用する場合はputtyを使用してください。

PuTTY: A Free Telnet/SSH Client

--
*2/27 puttyなら問題なく使えるという指摘がありましたので、puttyで検証し、訂正しました。

2013-02-08

今週末は、OSC 2013 Hamamatsu に出展します。

今週末の、「OSC 2013 Hamamatsu」 にてOpenBlocksの展示を行います。
開催概要概要は以下の通りです。

--

日程:2013年2月9日(土) 10:00~18:00

会場:浜松市市民協働センター 2F ギャラリー
   (JR浜松駅 徒歩8分、または 遠州鉄道西鹿島線 遠州病院駅 徒歩2分) [アクセスマップ]

費用:無料

内容:オープンソースに関する最新情報の提供
   ・展示 - オープンソースコミュニティ、企業・団体による展示
   ・セミナー - オープンソースの最新情報を提供

主催:オープンソースカンファレンス実行委員会

後援湖西市市民活動支援事務局
   浜松市市民協働センター

企画運営:株式会社びぎねっと

--

OpenBlocks A Familyの展示のほか、OBDNマガジンに掲載された事例などを配布します。
是非お立ち寄り下さい。


2013-01-29

OpenBlocksの動作モードについて

こんにちは。OpenBlocksファミリの開発・技術担当の木村です。

私は開発・技術担当ではありますが、お客様との直接お会いして製品の紹介をする機会も多くあり、よく説明を求められる内容として、RAMディスクモードとストレージ併用モードというOpenBlocks独自の仕組みがあります。今回はこの内容について、解説を行わせていただきたいと思います。

OpenBlocksでは、Debian GNU/Linuxを標準搭載するOpenBlocks 600D(販売終了済み)、A6、AX3において、RAMディスクモードとストレージ併用モードの二つの動作モードを用意しており、用途や要件に応じて使い分けが可能です。補足説明が必要と思われる用語については、本稿末尾に用意した用語解説や、以下サイトにて公開しているユーザーズガイドも併せてご参照下さい。

http://openblocks.plathome.co.jp/support/guide/


◆ RAMディスクモード

実行プログラムや設定が少量で済むインフラ系のサービスや静的なHTTPサービスを稼働させる場合に最適です。もとより高堅牢なハードウェアとなっているOpenBlocksですが、SSDのようなストレージを使用しないことでさらに故障要因を減らすことが出来ます。なお後述するとおりRAMディスクモードでで構築済みの環境を保存するには、容量の制限を考慮する必要がありますので、大容量の領域を必要とする用途にはストレージ併用モードがお勧めです。

RAMディスクモードでは、名称の通り起動後のユーザーランドをRAMディスクに構築して動作します。電源ONしFlashROMからロードしたファームウェアが実行されると、ファームウェアに含まれるinitrdのイメージのために128MB、稼働中の追加ソフトウェアやデータの置き場として384MBのtmpfs領域(/.rw)を確保してDebian GNU/Linuxの動作が始まります。





RAMディスクは高速なアクセスが可能であるため、書き換えが頻繁なテンポラリ領域として利用される事が多くありますが、不揮発性のメインメモリを利用しているという都合により、一度電源OFFしてしまうとデータが全て消えてしまうという特性があります。

通常ここに各種ソフトウェアを追加して、サービス提供するシステムを構築しようと考える方はあまりいらっしゃらないのでは無いかと思いますが、壊れにくさの追求を掲げているOpenBlocksでは、このRAMディスクを利用してシステムを構築可能にすることで、SSD等のストレージデバイスを利用しない、より高堅牢なシステムを実現できると考え、標準の機能として盛り込んでいます。

RAMディスクモードでは、initrd、tmpfsとこれらをunionfsで統合した3つのファイルシステムが大きな役割を果たしています。以下図を見ると一見複雑に見えると思いますが、unionfsによって複雑さは隠されており、利用する上では特に気になることは無いかと思います。



initrdには動作に必要な最小限のプログラムやライブラリなどの一式(debootstrapで構築した内容+α程度)が納められており、起動の度に同じ内容が展開されます。この環境には、たとえばless等の一般的なツールであっても、起動に不要なものはファームウェアサイズ削減のために含まれておりません。initrdの内容だけではサーバとして利用するためのソフトウェアが不足しておりますので、用途に合わせたソフトウェアの追加が必要となります。このための領域としてtmpfsが確保されており、利用者にはunionfsによって統合された姿が見えています。

利用者がDebian GNU/Linuxの一般的な操作で、ソフトウェアの追加や設定変更を行っていくと、tmpfsの領域にinitrdが提供するファイルシステムに対する変更差分(追加、変更、削除)が蓄積されていきます。

環境の保存

unionfsの存在によって、内部の仕組みは意識すること無く利用する事が出来ますが、変更差分が蓄積されたまま何も対処をせずに電源OFFすれば、せっかくセットアップした内容も次回起動時には消えてしまいます。

次回起動時にも変更差分を残しておくために、tmpfsの内容をFlashROMに保存するためのコマンド(/usr/sbin/flashcfg)を用意してあります。これを実行することで、tmpfsの内容(/.rw以下)を tar + gz で圧縮保存したデータをFlashROMの専用のエリアに保存します。OpenBlocks AX3は、約48MBの領域がありますが、圧縮の効果を考慮するとおよそ2~3倍程度のデータ量を保存することが出来ます。(AX3での構築例: lighttpd + php5によるWEBサーバやDNS/DHCP等の各種インフラ系サーバ)

なお構築した環境がFlashROMに収まるかどうかは、実際にtar+gzで圧縮保存してみないと分かりません。保存に失敗した場合は、保存対象のデータが削減出来ないかを精査して、再度保存を実行してみて下さい。

保存の内容を独自に調整したい場合は、/usr/sbin/flashcfg コマンドをカスタマイズして自分専用の保存コマンドを作成することも出来ます。bashスクリプトになっておりますので、カスタマイズは比較的手軽かと思います。(カスタマイズする場合でも、フォーマットはtar+gzにしておく必要があります)

環境の復元

flashcfgコマンドで保存したデータは、起動の度に自動的にtmpfs領域に展開されるため、利用する上で特に気にかける必要はありません。実際の処理は/etc/init.d/openblocks-setupが行っておりますので、興味がある方は一度ご覧下さい。

/.rwに変更差分が集約されることのメリット

バックアップと環境の復元が容易に行えます。ファームウェアによって、ベースとなるユーザランド(initrd)が提供され、それに対する変更差分は/.rwに集約されていますので、ファームウェアバージョンをそろえ、/.rwの内容をバックアップ・リストアすることで手軽に構築済み環境のコピーを作ることができます。

前述のflashcfgコマンドには、FlashROMへの保存の他にバックアップを実行する機能を備えており、USBメモリなどのストレージを用意して次のようなコマンドを実行するだけでバックアップが可能です。
    # mkfs -t ext3 -L DEB_CONFIG /dev/sdb1
    # flashcfg -B
ここで重要なのは、ボリュームラベルに「DEB_CONFIG」と設定することです。これによってバックアップ用のメディアを探し出して、変更差分を保存します。

RAMディスクモードでのリストアを想定している場合、次のように実行します。
    # mkfs -t ext3 -L DEB_CONFIG /dev/sdb1
    # flashcfg -B
    # mount LABEL=DEB_CONFIG /mnt
    # touch /mnt/FORCE
    # umount /mnt
リストア先として用意したOpenBlocksに、バックアップメディアを接続し、電源ONすればOKです。「touch /mnt/FORCE」の操作によって、FlashROMからの展開処理はスキップされ、バックアップメディアに保存されている変更差分を展開し環境を復元します。起動後はflashcfgコマンドによって、バックアップメディアから展開された変更差分をFlashROMに保存することで、構築済み環境をコピーしたことになります。バックアップの展開の他、init.shやpost-init.shというshスクリプトを用意すると、展開の前後で実行されますので、ファームウェアの書き換えなどの処理を追加することも出来ます。

RAMディスク領域を増やしたい

OpenBlocksファミリの中でもAX3の4ポート版はSO-DIMMソケットがあるため、大容量のメインメモリを活かすために、tmpfsの領域を増やしたいと問い合わせを時々受けます。あまりスマートな方法ではありませんが、次のよな操作で設定することが出来ます。
    # vi /etc/rc.local
    ~ コメント部 省略 ~
   
    mount -oremount,size=512m /.rw
   
    exit 0
   
    # sh /etc/rc.local
    (動作確認のため)
ただtmpfs領域が増えても、FlashROMのサイズは固定ですので、flashcfgで保存できる容量が増えるわけではありません。テンポラリ領域を増やすことが目的であれば/tmpだけをtmpfsにする方法も有用ですので、その場合は/etc/fstabにあるサンプル設定を基にお試し下さい。RAMディスク上で動作させたいプログラムを増やしたい場合には、FlashROMで収まらないものをSSDやその他ストレージから起動時に一度だけ読み出して展開する等のカスタマイズも考えられます。


 
◆ ストレージ併用モード

基本的な仕組みはRAMディスクモードと全く同じですが、tmpfsの代わりにラベルにDEBIANを設定したext4/ext3のストレージを利用して動作します。この条件のストレージを搭載して電源ONすることで、自動的にストレージ併用モードとして動き始めます。

RAMディスクモードとは違って、専用のコマンド(flashcfg)による保存操作が不要ですので、旧来のサーバになれている方にとっては、こちらの動作モードで触り始めていただくと戸惑いも無く触っていただけるかと思います。この動作モードでは、特別な操作をしなくてもデータは再起動後も残っていますので、ログの蓄積やDBサーバのように多量のデータをため込むような用途が向いています。

RAMディスクモードとの違いを以下にまとめます。

  • ソフトウェア追加の際に容量を気にする必要がありません
    特に小容量のSSDを搭載した場合を除き、通常の利用であれば容量を気にする必要は殆ど無くなるかと思います
     
  • メモリの空き領域を全てアプリケーション実行に利用する事が出来ます
    ただしinitrdが提供する128MBのRAMディスク領域は、ストレージ併用モードでも利用済みです
     
     
  • flashcfgコマンドによるFlashROMへの保存が不要です
    RAMディスクモードで唯一必要だった特別な操作が無くなり、IAサーバと変わらぬ操作で利用する事が出来ます 保存操作が不要になりますので、起動時に復元をすることも無くなります。RAMディスクモードでは、データベースのようにデータを蓄積するタイプの用途は不向きでしたが、ストレージ併用モードではこういった用途でも問題なく対応出来ます。


◆ まとめ

今回はRAMディスクモードを中心に、動作の仕組みを解説させていただきました。本記事が皆様のご理解の助けになれば幸いと思っています。今後もOBDNマガジンやマニュアルへの加筆等で情報公開を実施していきたいと思っておりますので、ご不明な点やさらに解説を希望される内容等、ご希望がございましたら是非OBDNマガジンへのコメント等でご連絡いただければ幸いです。




◆ 用語解説

  • ファームウェア
    Linuxカーネルとinitrdを結合したものです。出荷時からFlashROMに格納されており、更新バージョンがリリースされた場合は、apt-get upgradeによってファームウェアを含むDebianパッケージがダウンロードされ、FlashROMへの反映が行われます。
  • initrd
    Initial Ramdiskの略称です。従来は各種Linuxディスリビューションのインストーラで利用されており、カーネルを書き込んだFDとinitrdを書き込んだFDとして利用されたり、起動時にSCSI等のストレージデバイスのモジュールをロードする仕組みなどで利用されたいました。現在はinitramfsという別の手法が利用されており、initrdはあまり使われていないようです。
  • tmpfs
    Linuxで利用可能なファイルシステムの一種です。initrdはブロックデバイスとして扱われるため使うまでに初期化(mkfs)して使いたいファイルシステムの作成が必要ですが、tmpfsはオプションでメモリサイズを指定するだけで即座にファイルシステムとしてマウントできます。また指定したメモリサイズは、即座に割り当てがかかるわけではなく、実際に消費された分した割り当てされないため無駄なく利用出来ます。
  • unionfs
    複数のファイルシステムを透過的に重ねて、統合した結果を1つのファイルシステムとして見せることが出来ます。NFSにルートファイルシステムを構築して、ホームディレクトリのみをローカルストレージに保存する場合や、Live DVD等でユーザーデータをUSBメモリに保存する場合など、テンプレート化されリードオンリーで提供される共通のユーザーランドを、リードオンリーであることを意識させずに利用させるといった用途で利用されています。

2013-01-07

[.tested] BGAN EXPLORER500 インマルサット衛星電話 [AX3][A6]

[.tested] BGAN EXPLORER500 インマルサット衛星電話 [AX3][A6]

インマルサットBGANサービス(Inmarsat BGAN : Broadband Global Area Network)は、BGAN衛星電話端末から、宇宙にある人工衛星へ 向けて、無線電波を発信することで、音声通話サービス、FAX通信、データ通信サービスを利用できる通信回線サービスです。
今回テストに使用したEXPLORER500は、最大492kbpsのパケットデータ通信と音声電話サービスをサポートする通信衛星モデムユニットであり、パケットデータ通信により、IP通信サービスによる衛星モデムベースのルータユニットとしても機能します。



仕様については、以下のページを参照してください。

BGANインマルサット衛星電話 ビーギャンエクスプローラー500


1. 外観/接続端子
本モデルは、完全な防水仕様ではないため、屋外に放置して使用することは出来ません。
(災害時には、ビニールの袋等で防水処理をして使用されているようです)

本体横には、PC等を接続するLANポート、およびUSBポート、ACアダプタ端子があります。
バッテリ駆動可能なモデルです。


上部にはLCD操作パネルおよび、方位計があり、本体のみで設置の設定が行えます。



2. 設置/設定
衛星モデムは、通信衛星の向きにユニットを固定する必要があります。
本体にはコンパスが内蔵されていますので、これにより方位を設定し、併せて仰角を設定します。
微調整は、発信音によりナビゲートされ、一連の設置操作は早ければ1~2分で終了します。
基本的に、南側が開けた場所へ設置しますが、窓ガラス内の場合、コーティングなどでGPSの電波の受信が出来ず通信が行えない場合があります。



このユニットは、設置設定が終わったあとは、一般的なWANルータと同じく、LAN内に接続したPCからIP網へのアクセスが可能になります。
ただし、衛星通信であることから、一般的には従量課金を選択していますので、PCからソフトウェア本体やデータのアップデートを行ってしまうと大量のデータパケットが流れてしまい、すぐに契約上限を超えてしまいます。
そのため、PCを接続する場合は、ソフトウェアのデータ更新や、メールのトラフィック等に注意し、安易なWebアクセスなどを行わないように十分に注意する必要があります。

USB端子にAX3およびA6を接続した場合は、USBシリアルデバイスとして認識されます。

usb 1-1: new full-speed USB device number 2 using ehci_marvell usb 1-1: New USB device found, idVendor=10fe, idProduct=0004 usb 1-1: New USB device strings: Mfr=1, Product=2, SerialNumber=3 usb 1-1: Product: EXPLORER 500 usb 1-1: Manufacturer: Thrane & Thrane usb 1-1: SerialNumber: none cdc_acm 1-1:1.0: ttyACM0: USB ACM device cdc_acm 1-1:1.2: ttyACM1: USB ACM device usbcore: registered new interface driver cdc_acm cdc_acm: USB Abstract Control Model driver for USB modems and ISDN adapters

モデムデバイス名は以下の通りです。
crw-rw---- 1 root dialout 166,  0 Dec 21 16:03 ttyACM0 crw-rw---- 1 root dialout 166,  1 Dec 21 16:03 ttyACM1

minicomで atコマンドで コントロールすることが可能です。
(今回、相手先のプロバイダ情報がないため、pppdでの通信テストなどは行っていません)

root@obsax3:~# cat .minirc.dfl # Machine-generated file - use setup menu in minicom to change parameters. pu port /dev/ttyACM0 AT S7=45 S0=0 L1 V1 X4 &c1 E1 Q0 OK
3. IP通信について

今回、試験的にレンタルした端末の契約は、

100KB/80円

上り下りの帯域 128kbpsの 遅延 1400msの 回線を使用し、併せて、通信料の上限を設定しました。

IPアドレスはUK内のプロバイダからのものです。
衛星経由の遅延に関しては、1050 ms の遅延が発生していると考えられます。

MTUサイズは 1470 byets
スピードテストでは 上り下り共に約 128Kbps
となります。

社内からのtraceroute

# traceroute 161.30.22.220 traceroute to 161.30.22.220 (161.30.22.220), 64 hops max, 40 byte packets 1 192.168.10.1 (192.168.10.1) 2.106 ms 1.370 ms 0.852 ms 2 118.23.8.84 (118.23.8.84) 34.581 ms 25.215 ms 14.009 ms 3 118.23.7.161 (118.23.7.161) 14.532 ms 15.100 ms 12.847 ms 4 118.23.96.121 (118.23.96.121) 18.085 ms 18.293 ms 16.144 ms 5 60.37.55.85 (60.37.55.85) 13.862 ms 10.896 ms 9.821 ms 6 60.37.27.91 (60.37.27.91) 10.031 ms 60.37.27.155 (60.37.27.155) 14.856 ms 118.23.168.27 (118.23.168.27) 10.331 ms 7 ae-11.r21.tokyjp01.jp.bb.gin.ntt.net (129.250.12.201) 10.826 ms 16.582 ms 12.414 ms 8 ae-1.r25.tokyjp01.jp.bb.gin.ntt.net (129.250.2.73) 10.590 ms 15.223 ms 18.754 ms 9 as-2.r22.amstnl02.nl.bb.gin.ntt.net (129.250.3.78) 280.397 ms 278.798 ms 271.423 ms 10 peer76-01.ams2.ip.telecity.net (195.69.144.113) 279.727 ms * 277.857 ms 11 border76-01-ams2-te34.telecity.com (80.252.81.154) 278.301 ms 276.132 ms 278.984 ms 12 82.199.70.202 (82.199.70.202) 266.864 ms 275.349 ms 272.905 ms 13 * * * 14 161.30.16.34 (161.30.16.34) 337.590 ms 340.956 ms 345.253 ms
テスト機からの traceroute

# pathping 202.32.197.41 Tracing route to www.plathome.co.jp [202.32.197.41] over a maximum of 30 hops: 0 WindowsXP [192.168.0.4] 1 172.27.9.2 2 172.27.9.17 3 161.30.16.33 4 65.219.15.157 5 500.Serial2-10.GW1.HNL2.ALTER.NET [157.130.205.73] 6 0.so-7-0-0.XL1.HNL2.ALTER.NET [152.63.50.254] 7 0.so-5-0-2.XL3.SJC7.ALTER.NET [152.63.48.6] 8 POS6-0.GW2.SJC7.ALTER.NET [152.63.51.45] 9 iij-america-sjc-gw.customer.alter.net [152.179.48.2] 10 sjc002bf02.IIJ.Net [206.132.169.249] 11 tky001bf01.IIJ.Net [206.132.169.161] 12 tky009bb10.IIJ.Net [58.138.80.174] 13 tky009ipgw11.IIJ.Net [58.138.112.150] 14 tky009ip72.IIJ.Net [58.138.112.122] 15 202.232.12.102 16 dmzgw-global.plathome.co.jp [202.32.197.3] 17 www.plathome.co.jp [202.32.197.41] Computing statistics for 425 seconds... Source to Here This Node/Link Hop RTT Lost/Sent = Pct Lost/Sent = Pct Address 0 WindowsXP [192.168.0.4] 0/ 100 = 0% | 1 1300ms 0/ 100 = 0% 0/ 100 = 0% 172.27.9.2 0/ 100 = 0% | 2 1305ms 0/ 100 = 0% 0/ 100 = 0% 172.27.9.17 0/ 100 = 0% | 3 1306ms 0/ 100 = 0% 0/ 100 = 0% 161.30.16.33 0/ 100 = 0% | 4 1333ms 0/ 100 = 0% 0/ 100 = 0% 65.219.15.157 0/ 100 = 0% | 5 1299ms 0/ 100 = 0% 0/ 100 = 0% 500.Serial2-10.GW1.HNL2.ALTER.NET [157.130.205.73] 0/ 100 = 0% | 6 1333ms 0/ 100 = 0% 0/ 100 = 0% 0.so-7-0-0.XL1.HNL2.ALTER.NET [152.63.50.254] 0/ 100 = 0% | 7 1425ms 0/ 100 = 0% 0/ 100 = 0% 0.so-5-0-2.XL3.SJC7.ALTER.NET [152.63.48.6] 0/ 100 = 0% | 8 1361ms 0/ 100 = 0% 0/ 100 = 0% POS6-0.GW2.SJC7.ALTER.NET [152.63.51.45] 0/ 100 = 0% | 9 1405ms 0/ 100 = 0% 0/ 100 = 0% iij-america-sjc-gw.customer.alter.net [152.179.48.2] 0/ 100 = 0% | 10 1380ms 0/ 100 = 0% 0/ 100 = 0% sjc002bf02.IIJ.Net [206.132.169.249] 0/ 100 = 0% | 11 1479ms 0/ 100 = 0% 0/ 100 = 0% tky001bf01.IIJ.Net [206.132.169.161] 0/ 100 = 0% | 12 1504ms 0/ 100 = 0% 0/ 100 = 0% tky009bb10.IIJ.Net [58.138.80.174] 0/ 100 = 0% | 13 1472ms 0/ 100 = 0% 0/ 100 = 0% tky009ipgw11.IIJ.Net [58.138.112.150] 0/ 100 = 0% | 14 1455ms 0/ 100 = 0% 0/ 100 = 0% tky009ip72.IIJ.Net [58.138.112.122] 0/ 100 = 0% | 15 1469ms 0/ 100 = 0% 0/ 100 = 0% 202.232.12.102 0/ 100 = 0% | 16 --- 100/ 100 =100% 100/ 100 =100% dmzgw-global.plathome.co.jp [202.32.197.3] 0/ 100 = 0% | 17 1443ms 0/ 100 = 0% 0/ 100 = 0% www.plathome.co.jp [202.32.197.41] Trace complete.

MTUサイズ  1470bytesと 確認

# ping -f -l 1472 -n 1 202.32.197.41 Pinging 202.32.197.41 with 1472 bytes of data: Request timed out. Ping statistics for 202.32.197.41: Packets: Sent = 1, Received = 0, Lost = 1 (100% loss), # ping -f -l 1470 -n 1 202.32.197.41 Pinging 202.32.197.41 with 1470 bytes of data: Reply from 202.32.197.41: bytes=1470 time=2642ms TTL=48 Ping statistics for 202.32.197.41: Packets: Sent = 1, Received = 1, Lost = 0 (0% loss), Approximate round trip times in milli-seconds: Minimum = 2642ms, Maximum = 2642ms, Average = 2642ms

スピードテストは、
通信速度測定システム

 Radish Network Speed Testing 東京

を使用しました。結果は以下の通りです。

下り回線      速度  131.8kbps (16.47kByte/sec)      測定品質  77.5 
上り回線      速度  154.1kbps (19.26kByte/sec)      測定品質  74.4 

4. まとめ
今回は、BGAN EXPLORER500によるデータ通信について、その取り回しや遅延などについての検証を行いました。
衛星通信に限らず、3G/2G回線においてもM2Mに於いては通信量の把握は重要な事項であり、OpenBlocksの様なgatewayサーバによりデータの処理やコントロールを行いたいという問い合わせも増えています。

2012-12-26

JubatusをOpenBlocksで動作させてみる

前回のエントリである「JubatusをOpenBlocks AX3へインストールしてみる」の続きとなります。
今回は、以下の3点を目標とします。

  • 1. OpenBlocks AX3 上のJubatusを、ZooKeeperのCライブラリとリンクして動作させる
  • 2. Jubatusの分類器jubaclassifierをOpenBlocks上で動作させて試す
  • 3. Jubatusの分類器jubaclassifierを分散動作させて試す。このとき、jubaclassifierをOpenBlocksとx86系サーバというヘテロジニアスな環境で組み合わせる

この3点を選んだ理由は、ZooKeeperのCライブラリの利用がOpenBlocksで実行可能であること、Jubatusのサンプ ルを利用して実際にJubatusの分類器を触ってみること、応用として異なるCPUアーキテクチャ間の環境でもJubatusが利用できることを確認 することができるからです。
その代わり、ZooKeeperのセットアップ・設定方法については解説しません。ZooKeeper本体を動作させなくても、1,2番目の内容でOpenBlocks上で動かすJubatusの分類器を触ることはできると思います。

1. 環境構築:ZooKeeper CクライアントライブラリのインストールとJubatusのインストール

JubatusをOpenBlocks AX3へインストールしてみる」 からの差分として、ZooKeeperのCクライアントライブラリをインストールします。また、Jubatusはconfigureオプションから ZooKeeperの利用を有効にしてからインストールします(既にJubatusをインストールしていても、再インストールする形となっても構いませ ん。ただし、Linuxの共有ライブラリのキャッシュが有効になっている場合は再インストール後の再構築を忘れないでください)。
ApacheのZooKeeperプロジェクトから ZooKeeper 3.4.5(stable)リリースのtarボールをダウンロードし、そこからCライブラリをインストールします。ZooKeeperのCライブラリはイ ンラインアセンブラを利用しており、そのままではARMプロセッサを用いているOpenBlocksで動作しないため $ patch -p0 < patch.diff のようなコマンドで以下のパッチをあてることでインストールできます。
diff src/mt_adaptor.c.orig src/mt_adaptor.c -u --- src/mt_adaptor.c.orig 2012-12-14 20:14:37.060018322 +0900 +++ src/mt_adaptor.c 2012-12-14 20:18:20.000018333 +0900 @@ -482,6 +482,8 @@ int32_t fetch_and_add(volatile int32_t* operand, int incr) { + return __sync_fetch_and_add(operand, incr); +#if 0 #ifndef WIN32 int32_t result; asm __volatile__( @@ -503,6 +505,7 @@ } return result; #endif +#endif } // make sure the static xid is initialized before any threads started
$ wget http://ftp.yz.yamagata-u.ac.jp/pub/network/apache/zookeeper/zookeeper-3.4.5/zookeeper-3.4.5.tar.gz $ tar -xvf zookeeper-3.4.5.tar.gz $ cd zookeeper-3.4.5/src/c/ $ ./configure $ make $ sudo make install
2012年11月リリースのJubatus 0.3.4利用します。--enable-zookeeperと--enable-debugオプションも加えてconfigureします。
$ git clone https://github.com/jubatus/jubatus.git $ cd jubatus $ git checkout jubatus-0.3.4 -b jubatus-0.3.4 $ ./waf configure --disable-re2 --enable-debug --enable-zookeeper Setting top to : /home/kashihara/repos/jubatus Setting out to : /home/kashihara/repos/jubatus/build Checking for 'g++' (c++ compiler) : ok Unpacking gtest : yes Checking for library pthread : yes Checking for library msgpack : yes Checking for library dl : yes Checking for program pkg-config : /usr/bin/pkg-config Checking for 'libglog' : yes Checking for 'libevent' : not found Checking for library event : yes Checking for 'pficommon' : yes Checking for header pficommon/network/mprpc.h : yes Checking for header unistd.h : yes Checking for header sys/types.h : yes Checking for header sys/wait.h : yes Checking for header sys/stat.h : yes Checking for header cxxabi.h : yes Checking for header sys/socket.h net/if.h : yes Checking for header sys/ioctl.h : yes Checking for header fcntl.h : yes Checking for header netinet/in.h : yes Checking for header arpa/inet.h : yes Checking for header dlfcn.h : yes Checking for header c-client-src/zookeeper.h : not found Checking for header zookeeper/zookeeper.h : yes Checking for library zookeeper_mt : yes Checking for header sys/socket.h net/if.h sys/ioctl.h : yes Checking for header netinet/in.h arpa/inet.h : yes Checking for compiler atomic builtins : no 'configure' finished successfully (12.197s)
$ ./waf $ sudo ./waf install

ZooKeeperでの動作確認


ZooKeeperのセットアップについては解説しないため、導入にあたっては以下の記事や本家ドキュメントをお勧めします。

管理が困難―分散処理の常識はZooKeeperで変わる (1/3) - @IT
http://www.atmarkit.co.jp/fjava/rensai4/bigdata_java08/01.html
Apache ZooKeeper へようこそ!
http://oss.infoscience.co.jp/hadoop/zookeeper/
Apache ZooKeeper - Home
http://zookeeper.apache.org

ZooKeeperを有効にしたJubatusの分類器jubaclassifierが動作するか確認しましょう。ZooKeeperのホスト、 ポート番号を-zオプションで指定し、-nオプションでJubatus内でのグループ名を指定します。ここではtestとしておきます。以下のように ZOO_INFOといったノードの作成のログが表示されていれば成功です。
$ jubaclassifier -z 192.168.0.102:2181 -n test I1225 01:51:17.177259 14603 server_util.cpp:137] starting jubaclassifier 0.3.4 RPC server at 192.168.0.101:9199 pid : 14603 user : kashihara mode : multinode mode timeout : 10 thread : 2 tmpdir : /tmp logdir : zookeeper : 192.168.0.102:2181 name : test join : false interval sec : 16 interval count : 512 2012-12-25 01:51:17,177:14603(0x2b44a6620d00):ZOO_INFO@log_env@712: Client environment:zookeeper.version=zookeeper C client 3.4.5 2012-12-25 01:51:17,177:14603(0x2b44a6620d00):ZOO_INFO@log_env@716: Client environment:host.name=pfisky 2012-12-25 01:51:17,177:14603(0x2b44a6620d00):ZOO_INFO@log_env@723: Client environment:os.name=Linux 2012-12-25 01:51:17,177:14603(0x2b44a6620d00):ZOO_INFO@log_env@724: Client environment:os.arch=2.6.32-71.29.1.el6.x86_64 2012-12-25 01:51:17,177:14603(0x2b44a6620d00):ZOO_INFO@log_env@725: Client environment:os.version=#1 SMP Tue May 10 17:35:18 CDT 2011 2012-12-25 01:51:17,178:14603(0x2b44a6620d00):ZOO_INFO@log_env@733: Client environment:user.name=kashihara 2012-12-25 01:51:17,178:14603(0x2b44a6620d00):ZOO_INFO@log_env@741: Client environment:user.home=/home/kashihara 2012-12-25 01:51:17,178:14603(0x2b44a6620d00):ZOO_INFO@log_env@753: Client environment:user.dir=/home/kashihara/repos/jubatus 2012-12-25 01:51:17,178:14603(0x2b44a6620d00):ZOO_INFO@zookeeper_init@786: Initiating client connection, host=192.168.0.102:2181 sessionTimeout=10000 watcher=(nil) sessionId=0 sessionPasswd=<null> context=(nil) flags=0 2012-12-25 01:51:17,178:14603(0x2b44a6a32700):ZOO_INFO@check_events@1703: initiated connection to server [192.168.0.102:2181] 2012-12-25 01:51:17,181:14603(0x2b44a6a32700):ZOO_INFO@check_events@1750: session establishment complete on server [192.168.0.102:2181], sessionId=0x13ad037d2ce00fd, negotiated timeout=10000 I1225 01:51:17.202198 14603 zk.cpp:109] create /jubatus I1225 01:51:17.235656 14603 zk.cpp:109] create /jubatus/supervisors I1225 01:51:17.237215 14603 zk.cpp:109] create /jubatus/jubakeepers I1225 01:51:17.238535 14603 zk.cpp:109] create /jubatus/actors I1225 01:51:17.239946 14603 zk.cpp:109] create /jubatus/actors/classifier I1225 01:51:17.241165 14603 zk.cpp:109] create /jubatus/actors/classifier/test I1225 01:51:17.242658 14603 zk.cpp:109] create /jubatus/actors/classifier/test I1225 01:51:17.243892 14603 zk.cpp:109] create /jubatus/actors/classifier/test/master_lock I1225 01:51:17.245112 14603 zk.cpp:109] create /jubatus/actors/classifier/test/nodes I1225 01:51:17.246489 14603 zk.cpp:109] create /jubatus/actors/classifier/test/nodes/192.168.0.101_9199 I1225 01:51:17.246520 14603 membership.cpp:79] actor created: /jubatus/actors/classifier/test/nodes/192.168.0.101_9199
例えば、ZooKeeperとうまく接続できなかったときは次のようにノード作成失敗のログを出力し、最終的にエラーが発生して起動に失敗します。
$ jubaclassifier -z 127.0.0.1:1234 -n test I1225 01:41:41.027243 11741 server_util.cpp:136] starting jubaclassifier 0.3.4 RPC server at 192.168.0.100:9199 pid : 11741 user : kashihara mode : multinode mode timeout : 10 thread : 2 tmpdir : /tmp logdir : zookeeper : 127.0.0.1:1234 name : test join : false interval sec : 16 interval count : 512 2012-12-25 01:41:41,028:11741(0x401ba430):ZOO_INFO@log_env@712: Client environment:zookeeper.version=zookeeper C client 3.4.5 2012-12-25 01:41:41,028:11741(0x401ba430):ZOO_INFO@log_env@716: Client environment:host.name=obsax3 2012-12-25 01:41:41,029:11741(0x401ba430):ZOO_INFO@log_env@723: Client environment:os.name=Linux 2012-12-25 01:41:41,029:11741(0x401ba430):ZOO_INFO@log_env@724: Client environment:os.arch=3.0.6 2012-12-25 01:41:41,029:11741(0x401ba430):ZOO_INFO@log_env@725: Client environment:os.version=#1 SMP Fri Nov 16 11:53:45 JST 2012 2012-12-25 01:41:41,030:11741(0x401ba430):ZOO_INFO@log_env@733: Client environment:user.name=kashihara 2012-12-25 01:41:41,032:11741(0x401ba430):ZOO_INFO@log_env@741: Client environment:user.home=/home/kashihara 2012-12-25 01:41:41,032:11741(0x401ba430):ZOO_INFO@log_env@753: Client environment:user.dir=/home/kashihara 2012-12-25 01:41:41,032:11741(0x401ba430):ZOO_INFO@zookeeper_init@786: Initiating client connection, host=127.0.0.1:1234 sessionTimeout=10000 watcher=(nil) sessionId=0 sessionPasswd=<null> context=(nil) flags=0 2012-12-25 01:41:41,033:11741(0x40ed6460):ZOO_ERROR@handle_socket_error_msg@1697: Socket [127.0.0.1:1234] zk retcode=-4, errno=111(Connection refused): server refused to accept the client E1225 01:41:41.033897 11741 zk.cpp:104] /jubatus failed in creation -4 connection loss 2012-12-25 01:41:41,034:11741(0x40ed6460):ZOO_ERROR@handle_socket_error_msg@1697: Socket [127.0.0.1:1234] zk retcode=-4, errno=111(Connection refused): server refused to accept the client E1225 01:41:41.034329 11741 zk.cpp:104] /jubatus/supervisors failed in creation -4 connection loss 2012-12-25 01:41:41,034:11741(0x40ed6460):ZOO_ERROR@handle_socket_error_msg@1697: Socket [127.0.0.1:1234] zk retcode=-4, errno=111(Connection refused): server refused to accept the client E1225 01:41:41.034677 11741 zk.cpp:104] /jubatus/jubakeepers failed in creation -4 connection loss 2012-12-25 01:41:41,034:11741(0x40ed6460):ZOO_ERROR@handle_socket_error_msg@1697: Socket [127.0.0.1:1234] zk retcode=-4, errno=111(Connection refused): server refused to accept the client E1225 01:41:41.035019 11741 zk.cpp:104] /jubatus/actors failed in creation -4 connection loss 2012-12-25 01:41:41,035:11741(0x40ed6460):ZOO_ERROR@handle_socket_error_msg@1697: Socket [127.0.0.1:1234] zk retcode=-4, errno=111(Connection refused): server refused to accept the client E1225 01:41:41.035387 11741 zk.cpp:104] /jubatus/actors/classifier failed in creation -4 connection loss 2012-12-25 01:41:41,035:11741(0x40ed6460):ZOO_ERROR@handle_socket_error_msg@1697: Socket [127.0.0.1:1234] zk retcode=-4, errno=111(Connection refused): server refused to accept the client E1225 01:41:41.035745 11741 zk.cpp:104] /jubatus/actors/classifier/test failed in creation -4 connection loss F1225 01:41:41.036495 11741 server_util.hpp:124] Dynamic exception type: jubatus::exception::runtime_error::what: Failed to prepare lock_service #0 [jubatus::exception::error_api_func_*] = lock_service::create #0 [jubatus::exception::error_at_file_*] = ../src/common/membership.cpp #0 [jubatus::exception::error_at_line_*] = 161 #0 [jubatus::exception::error_at_func_*] = void jubatus::common::prepare_jubatus(jubatus::common::lock_service&, const std::string&, const std::string&) *** Check failure stack trace: *** @ 0x402fa974 google::LogMessage::Fail() @ 0x402fe764 google::LogMessage::SendToLog() @ 0x402fdd18 google::LogMessage::Flush() @ 0x402fec54 google::LogMessageFatal::~LogMessageFatal() @ 0x1e174 jubatus::framework::run_server<>() @ 0x13934 main @ 0x40526538 (unknown) アボートしました

2. Jubatusの分類器jubaclassifierを試す

jubatus-exampleの将軍分類サンプルを見てみましょう。
https://github.com/jubatus/jubatus-example

jubaclassiferの起動

OpenBlocks側では引数なしで起動してみましょう
$ jubaclassifier I1225 01:49:25.317184 11751 server_util.cpp:136] starting jubaclassifier 0.3.4 RPC server at 192.168.0.100:9199 pid : 11751 user : kashihara mode : standalone mode timeout : 10 thread : 2 tmpdir : /tmp logdir : zookeeper : name : join : false interval sec : 16 interval count : 512

jubatus-example 将軍分類の実行

shogunは、徳川家、足利家、北条家の将軍の姓名をあらかじめ学習させ、分類時に名前を入力すると三家の名字を返すサンプルプログラムとなっています。
サンプルプログラムをx86系のLinuxかMac等で実行します。Rubyのサンプルを使うためjubatus ruby gemsをインストールします。
$ git clone https://github.com/jubatus/jubatus-example $ cd jubatus-example $ git checkout -b obs-example $ gem install jubatus $ cd shogun
OpenBlocks AX3に割り当てているIPアドレスを192.168.0.100とします。 shogun.rbのグローバル変数 $hostを書き換えてから、shogun.rbを実行します。以下のように結果が表示されたら成功です。
$ ruby shogun.rb 徳川慶喜 足利義昭 北条守時
shogun.rbのコードを見てみましょう。config, train, predictという3つのメソッドが定義されています。それぞれ、Jubatusの分類器の設定、学習、名前から名字を分類(予測)することに対応しています。
trainメソッドでは徳川・足利・北条の各家の代表的な将軍が記述され、これがJubatusの分類器で学習されます。predictメソッドで は、慶喜・義昭・守時を名前の入力としてJubatusに問いあわせ、Jubatusが返した結果からスコアの高いラベル(学習時の名字である徳川・足 利・北条に対応)を分類結果として表示しています。
入力した文字列(名前)をどのように機械学習で扱っているかについてはData Conversion — Jubatusを参照してください。configメソッドを見るとuni-gramを用いていることがわかります。
以上で、Jubatusの分類器をOpenBlocksで試すことが確認できました。shogun.rbファイルで学習・分類していましたが、実行 してみたい分類に応じてファイルを分割して分類、学習をJubatusで実行してみると面白いと思います。 注意事項として、学習前にset_configを使って必ず設定を与える必要があります。学習後はset_configを実行しないでください。なぜな ら、学習後にset_configを呼び出すと、学習済みのモデルがクリアされてしまうからです(2013年の次のリリースでは、set_configの RPCによる設定指定は廃止し、別の手段で設定を指定できるようにする予定です)。 また、Jubatusはサーバとして実装されており、現在提供しているインタフェースはMessagePack-RPC(TCP/IPv4)経由となって います。ネットワークが接続できない環境だと外部のマシンからRPCを実行することもできませんし、あまりにも重たい(量の多い)処理を実行させると通信 時にサーバもしくはクライアント側でタイムアウトが発生する可能性があります。

3. jubaclassifierを分散動作させて試してみる

jubaclassifierをOpenBlocksとx86系サーバというヘテロジニアスなアーキテクチャ間でJubatusの分散動作を試して みましょう。OpenBlocksと同様に、x86系LinuxでZooKeeperありでJubatusをインストールした環境を用意します。 x86_64でのREHL系Linux向けのRPMパッケージと、Debianパッケージは公式サイトでも提供しており、Quick Start — Jubatusの解説に従ってインストールが可能です。 shogun.rbでは、サーバとするホスト名、ポート番号は単体で動作させた時と同じ値のままにしておきます。

プロセス、ホスト構成

Tutorial in Distributed Mode — Jubatusを参考にして、以下のような構成でプロセスを起動します。
  • 192.168.0.101 Scientific Linux 6 or Debian Linux
    • Jubatusクライアント(Ruby: shogun.rb)
    • jubaclassifier_keeper
    • jubaclassifier
  • 192.168.0.100 OpenBlocks AX3
    • jubaclassifier
  • 192.168.0.102 Linux
    • ZooKeeper

プロセスの起動

OpenBlocksとScientific Linuxのコンソールで以下のプロセスをそれぞれ起動します。
jubaclassifier -z 192.168.0.102:2181 -n test -p 9198 -i 1
jubaclassifier_keeper -z 192.168.0.102:2181
jubaclassifier -z 192.168.0.102:2181 -n test -i 1
それぞれプロセスが起動した状態で、jubactlコマンドを実行するとZooKeeperと接続しているプロセスのホスト(IPアドレス)がZooKeeperに登録されていることを確認できます。
$ jubactl -z 192.168.0.102:2181 -s jubaclassifier -t classifier -n test -c status active jubakeeper members: 192.168.0.100_9199 active jubavisor members: active test members: 192.168.0.100_9190 192.168.0.101_9199

分散時の学習とMIXの確認

shogun.rbのメソッド呼び出し部分を以下のように分類を実行しないよ書き換えて、設定と学習のみをまず実行します。
# run example config(client) train(client) #predict(client)
分散してJubatusを稼働させていると、Jubatusは学習結果のモデル共有のためにMIX処理というものを行います(*1)。今回は Jubatusのconfigure時に--enable-debugを有効にしていると、jubaclassifierのログに以下のようなMIX処理 のログ出力を確認することができます。現在は、学習の回数もしくは一定期間ごとにMIX処理が自動的に発生します。以下のログは学習結果のデータを共有し ていることがMIX処理の転送データサイズから確認できますが、モデルを共有(同期)させる必要がないときは8バイト程度の転送になります。
I1225 13:33:30.516629 3240 linear_mixer.cpp:172] starting mix: I1225 13:33:30.517878 3240 linear_mixer.cpp:79] get diff from 192.168.0.100:9198 I1225 13:33:30.517902 3240 linear_mixer.cpp:79] get diff from 192.168.0.101:9199 I1225 13:33:30.520889 3240 linear_mixer.cpp:90] pull diff to 192.168.0.100:9198 I1225 13:33:30.520915 3240 linear_mixer.cpp:90] pull diff to 192.168.0.101:9199 I1225 13:33:30.523612 3240 linear_mixer.cpp:230] mixed with 2 servers in 0.006961 secs, 4144 bytes (serialized data) has been put. I1225 13:33:30.523646 3240 linear_mixer.cpp:184] .... 2th mix done.
*1: Overview — Jubatus http://jubat.us/ja/overview.html

分類の確認

shogun.rbを以下のように分類のみ実行するよう書き換え、jubaclassifier単体で実行したときと同じ実行結果である「徳川慶喜」「足利義昭」「北条守時」を得られることを確認します。
# run example #config(client) #train(client) predict(client)
繰り返しshogun.rbを実行しても同じ結果が返ることを確認したり、jubaclassifier_keeperのログを確認してどちらの jubaclassifierに対してRPCを実行しているか確認してみても良いでしょう。MIX処理で学習したモデルが共有されていることが実際に確認 できます。
I1225 13:51:53.796672 12127 keeper.hpp:134] random_proxy1 classify test I1225 13:51:53.796926 12127 keeper.hpp:139] request to 192.168.0.101:9199 I1225 13:51:53.799523 12127 keeper.hpp:134] random_proxy1 classify test I1225 13:51:53.799747 12127 keeper.hpp:139] request to 192.168.0.101:9199 I1225 13:51:53.802237 12127 keeper.hpp:134] random_proxy1 classify test I1225 13:51:53.802461 12127 keeper.hpp:139] request to 192.168.0.100:9198
このときは、jubaclassifier_keeperというプロセスをプロキシとして経由してclassify(分類のための)RPCを呼び出しています。trainやclassifyといったset_config以外のRPCは直接jubaclassifierを指定して実行しても構いませ ん。

jubaclassifier_keeperのclasifyは同じグループ名で起動しているjubaclassifierからランダムに1つ選んでRPCを呼びます。keeperを通したときにRPCをどう呼び出すかはclassifier.idlなどのIDLに定義されています。例えば、set_configは@broadcastというものが指定されており、これはclassifyと異なり参加しているすべてのプロセスに対して同じ内容のRPCを実行します。

まとめ

今回の内容で、以下のことが確認できました。
  • Jubatusの分類器jubaclassifierをOpenBlocksで動作させることができた
  • ZooKeeperのCクライアントライブラリをOpenBlocks上でJubatusと組み合わせ動作させることができた
  • 異なるアーキテクチャ間であるIntel 64(x86_64)のLinuxとOpenBlocks AX(ARM)でJubatusを動作させることができた
今回はJubatusのMIX処理についても説明しましたが、ここで覚えてもらいたい点があります。Jubatusは学習したモデルが分 散したサーバ間で共有(同期)されていきますが、常に同じモデルを一貫して保持することを保証していません。複数台の Jubatus(jubaclassifierなど)があったとき、いくつかでは学習済みのサーバがあっても、まだその結果が共有されていないサーバが存 在する可能性もあります。
機械学習や分散したときの特性も考えながら、OpenBlocksと他アーキテクチャCPUと組み合わせてJubatusを触っていってもらえるとありがたいです。