MastodonでIDCFクラウドのオブジェクトストレージを利用する

はじめに

最近Mastodonが流行っていますね。 そこで@reki_frequent 氏と一緒にshimaidon.netというインスタンスをたちあげました。

AWSを使う手もありましたが料金の魅力からIDCFクラウドを選択しました。 IDCFクラウドでとりあえずたててみたという記事は他にも多数ありますので、 建て方については他の記事に譲るとして本記事ではオブジェクトストレージを使用して料金を節約する方法を紹介します。

Mastodonとは

Mastodonとは分散型ミニブログの規格であるOStatusのOSS実装の一つです。 そのため誰でもインスタンスをたてることが可能です。 またインスタンス間の協調も定義されています。 したがって特定の組織に依存しないSNSのネットワークを構成することが可能です。

Mastodonを個人で運営していく上での問題点

Mastodonを運営していく上での問題の一つに画像等で大量のディスク容量が必要とされることが挙げられます。 他のサーバリソースは登録者の制限等で一定水準に保つことが可能ですがディスク使用量は少人数しかいないインスタンスでもどんどん消費されていきます。 そのため安価にディスク容量を確保することは個人でMastodonを運営していく上で重要となります。 IDCFクラウドは通常のストレージよりオブジェクトストレージを使用したほうが安価(しかも50GBまで無料で使える)です。 IDCFクラウドのオブジェクトストレージはAWSのS3との高い互換性を謳っています。 また、MastodonではS3をストレージとして利用することが可能です。 したがって、IDCFクラウドのオブジェクトストレージをストレージとして利用することが可能です。

実装

本例の環境はCentOS7.3.1611でmastodonのバージョンは1.3.2を利用しています。

実装方針としては.env.productionに設定を追加することでMastodon側でオブジェクトストレージを利用する設定にします。 IDCFクラウドのオブジェクトストレージの課金の特徴としてIDCFクラウド内の通信は無料です。 そこでVMのnginxを必ず経由させるようにしてさらに利用料を抑えます。

shimaidonの場合.env.productionに追加した設定は下記です。

S3_ENABLED=true
S3_BUCKET=shimaidon
AWS_ACCESS_KEY_ID=<API Key>
AWS_SECRET_ACCESS_KEY=<Scret Key>
S3_REGION=ds.jp-east
S3_ENDPOINT=https://ds.jp-east.idcfcloud.com
S3_PROTOCOL=https
S3_SIGNATURE_VERSION=s3
S3_HOSTNAME=shimaidon.net/s3_contents

S3_ENABLEDでS3を有効にするかどうかの設定をします。 S3_BUCKETは使用するバケットを指定します。 このバケットは予め作成しておきます。例ではshimaidonというバケットにしました。 「AWS_ACCESS_KEY_ID」、「AWS_SECRET_ACCESS_KEY」はそれぞれ適切に設定してください。 S3_ENDPOINTはエンドポイント、S3_REGIONはエンドポイントから「idcfcloud.com」を取り除いたものとなります。 S3_PROTOCOLはhttpsです。 S3_SIGNATURE_VERSIONはIDCFクラウドはv4に対応していないのでs3としてください。 S3_HOSTNAMEですがnginxでオブジェクトストレージにproxyさせるため「<自ドメイン>/<サブディレクトリ>」としてください。 今回の例ではshimaidon.net/s3_contentsとしてあります。サブディレクトリ名は当然ですがmastodonのものと被らないように気をつけてください。

次にnginxの設定です。 雑に下記のようにしてあります。

        location /s3_contents/ {
            proxy_set_header host $host;
            proxy_pass https://ds.jp-east.idcfcloud.com/;
        }

/s3_contents/に来たアクセスをs3_contentsを取り除いたファイル名をhttps://ds.jp-east.idcfcloud.com/ に転送しています。

コメント

今回は料金を下げるという点に注目しました。 最後のnginxでリバースプロキシさせるというのは料金とトラフィックやサーバの負荷のトレードオフとなっています。 お金にものを言わせて大規模インスタンスを運営する際はnginxを経由させないようにS3_HOSTNAMEをds.jp-east.idcfcloud.comにするほうがよいです。 お金があるならAWSでPaaSを駆使したほうがよさげではありますが。

まとめ

本記事では各種クラウドの中でも比較的安価なIDCFクラウドを用いてさらにそのオブジェクトストレージを用いることで料金を下げる方法を紹介しました。 具体的にはS3とIDCFのオブジェクトストレージが互換性があること、IDCFクラウド内での通信は無料であるという特性を利用しました。 このような形態の運用はお金のない個人インスタンスを運営する上で有用です。

2016年サークルのサーバの障害まとめ

新年あけましておめでとうございます. 新年早々,障害の記事なんてって感じですが年越し前に書くつもりがこんな時期になっていました… 障害があったことは年超えても忘れずに今後にいかしていきましょうということで…

さて,本日の話題は去年にサークルで発生した大きめの障害(単純な再起動等では復旧しなかったもの)のまとめです. 2つとも人為障害でした…

事例1:パーミッションの設定忘れによる一部ファイル閲覧不可

下記が対応ログより抜粋

   nginxログ確認
    →下記出力を確認
> 2016/10/20 21:48:08 [crit] 35340#0: *6 open() "/var/lib/nginx/tmp/proxy/2/00/0000000002" failed (13: Permission denied) while reading upstream, client: 133.82.251.196, server: _, request: "GET /only/static/file_management_rule.pdf HTTP/1.1", upstream: "http://127.0.0.1:8082/only/static/file_management_rule.pdf", host: "densanken.com", referrer: "http://densanken.com/only/"
    
   /var/lib/nginx/配下の権限確認
    →nginxユーザが所有者であることを確認
> [root@main01 /]# ll /var/lib/nginx/
> 合計 0
> drwx------ 7 nginx nginx 73 10月 16 19:37 tmp

   /var/lib/nginx配下の所有者変更実施
    →正常に変更できたことを確認

nginxの実行ユーザをwebadminにしたのですが,"/var/lib/nginx/“の権限を変え忘れて死んでたという感じです. 対応ログではさくっとnginxのエラーログ見て対応してみたいに書いていますが, 最初はアプリケーション側の障害を疑ってました. 「推測するな.計測せよ.」,通信経路順におっていけっていう教訓です.

事例2: SSL化にともなってhttpとURLが記載されていた場所が死ぬ.

Webアプリケーションにhttpと書かれていた部分によって引き起こされました. 下手にhttp→httpsにリダイレクトしていたため,なぜか更新ができないという 一見,SSL証明書と関係ないバグのような感じで手間取りました.

最終更新日を確認するとSSL化した日付以降更新がないのでもしやと思ったらビンゴでした.

まとめ

今回の障害はサーバの設定を行う時に確認すべき項目が整備されてなかったことによるものでした. 面倒ですが,

  1. 設定変更したときに意図しない動作をするようにしていないか確認手順を設ける
  2. 機械的にテストできるものはテストする

ようにしましょう(といいつつしてないので今度メインで管理している後輩たちに投げたい)

Ansible+Dockerでシンプルにサークルのサーバを管理しはじめた話

どうも千葉大電子計算機研究会(以下CCS)、老害㌠いかろちゃんです。 CCS Advent Calendar 2016 の6日目の記事として 老害なので現役生を差し置いてサーバ管理をしちゃってる話を今日は書こうと思います。

サークルでサーバ管理をする上での問題点

大学サークルの特徴(少なくともCCSは)として下記があります。

  1. 人間の流動が激しい(役職は一年交代)
  2. 様々なWebアプリケーションがデプロイされる可能性がある
  3. 予算がその年のサークルの人数によって決まる
  4. 仕事でしているわけではないのでかけられる時間が限られる

したがって

  1. サーバを構築した人が連絡がつかず誰も構成を把握・対応できなくなる
  2. 環境がコンフリクトしてしまい最悪各種サービスが提供できなくなる
  3. いつIDCの変更を余儀なくされるかわからない
  4. 時間的制約で後回しにされがち

といった問題があります。

これらの問題を解決するために構成をシンプルにしてAnsible+Dockerでコード化をすすめてみたよというのが今日のお話。 今後CCSのWeb管になる人、他のサークル等で同様の悩みを抱えている人の参考になれば幸いです。

技術選択

クラウド

会室にサーバ機を置くのはネット回線を引く手間、盗難・火事等が怖いのでまず最初に却下としました。 クラウドとかVPSの候補としてはAWSGCP,IDCFクラウド、さくらVPS、ServersMan@VPSが候補に。 料金・拡張性を考えてIDCFクラウドとしました。 IDCFクラウドなら最低ワンコイン(オブジェクトストレージつかうともっとさげられますが…)からはじめられます。 (ServersMan@VPSは安いけど前使った感じあんまり印象が良くなくてお遊び以上には使えないなーっていう感じがあったので却下)

お金があるんだったらAWSとかGCPのPaaSをがんがんつかっていくというのがよい選択な気がします。

OS

現在はCentOS7を使っています。 これは最近のものがまぁまぁ動いてかつ枯れていて、サポート期間も長いため選択しました。 過去にCoreOSやFeodraつかってみましたが、CoreOSは小規模環境ではただただつらい、 Fedoraはサーバ機でする選択ではなかったですね…

構成管理

構成管理ツールのひとつであるAnsibleで構成管理を行っています。 Ansibleを使い構成をコード化することで(Ansibleがわかる人なら)誰でもサーバの構成を把握しやすくなりました。 また、将来のクラウド移転を行うことになった際もだいぶ楽なはずです。

Ansible特徴としてはエージェントレスであることYAMLで記述するため比較的設定がシンプルであることが挙げられます。 Chef-soloなんかでもいい気も一瞬しましたが、シンプルにできることはシンプルに済ませるというのが引き継ぎや作業のコスパを考えるといい気がしたのでAnsibleを選択しました。

Webアプリケーション

ここでコンテナ型仮想化技術のDockerです。 これでAnsibleを導入したのと同様の環境のコード化を手に入れ、 また環境がホスト・他のDockerコンテナと分離されるのでコンフリクトを気にする必要がなくなります。

Webサーバ

軽量・高速なWebサーバであるNginxを採用しました。 nginxで静的サイトの配信及びWebアプリケーションへの振り分けを行っています。 各種環境に依存するサービス、特にWebアプリケーション(というか今はWebアプリケーションしかコンテナ化してない…)をコンテナ化しました。

監視

外形監視にはUptimeRobotを利用しています。 また,内部のリソース管理にはNagiosを利用しています。 Nagiosを利用しているのはわたしが慣れているからという理由だけなのでZabbixでもMackerelでもなんでもいいと思います。

コードの管理

Ansibleのplaybook, DockerのDockerfile, そしてコンテンツ系ソースコードの管理はGitHubで行っています。 gitによるバージョン管理を行うことで構築でミスって障害を引き起こしても最悪直前の状態までもどせるという安心をえることができます。 学生ならアカデミックライセンスがつかえますのでプライベートリポジトリもつかえていい感じです。

実装

仮想マシンの立ち上げ・基本設定

IDCFはCloudStack APIに対応していますのでAnsibleのCloudStackモジュールを利用することで上位のファイアウォールの設定はもちろん、VMインスタンスを自動的にたてて基本的な設定をするといったことまで可能です。 これは下記を参考に実装しました。

AnsibleでCloudStackを操作する(基礎編:仮想マシン作成とプロビジョニング) - Qiita

ユーザはセオリー通りsudo権限を持つ管理者ユーザ、webコンテンツの管理者ユーザ(sudoは不可)を用意しました。 webコンテンツの管理者ユーザはDockerの各種コマンドが実行できるようにdockerグループに入れてあります。

SSL証明書の取得

世の中の常時SSL化の流れにしたがってCCSでもすべてのページを原則https化しています。

SSL証明書の取得にはLet’s Encryptを利用しました。 Let’s Encryptを使うと無料でSSL証明書を取得できます。 また,コマンドラインで取得,更新が可能ですので非常に自動化向きです。 certbotをyumでいれて定期的に更新するようなcronを仕込めば完了です。 Ansible化するための注意点としてSSL証明書の取得のコマンドをそのまま叩いてしまうと冪等性が保証されないので –keep-until-expiringオプションを付ける必要がありました。

Nginx

これもAnsibleで管理です。 特に細かいチューニング等はしていません。 また,一時期動的にdockerコンテナにproxyする実装にしようかと思いましたが, 実装コストを考えて手動で設定ファイルを書き換えて各種コンテナにproxyさせるようにしています。 必要になったら実装すればよいでしょう。

監視

例のごとく監視設定,監視エージェント(NRPE)もAnsibleで管理しています。 監視項目で特にかわっている点としてはサーバにSWAPがないのでメモリ使用量監視にしているということでしょうか。 これには下記のプラグインを利用しています。

GitHub - koemu/nagios_plugin_check_memfreetotal: Checking overall memory free space (RAM + Swap) plugin for Nagios.

また,コンテナの起動監視もしたいと思っていて,現在こちらのプラグインを作成中です。

監視サーバは暫定的にわたしの個人契約しているのを利用しているのでそのうち移行したいと考えています。

コンテンツ系

先程説明したとおり,WebアプリケーションはDockerで管理しています。 基本的に揮発しても良いものはDockerfileにかいて、 データはVolumeでマウントするようにしています。 gitで管理はしているものの,基本的に手動でデプロイです。 ポート番号とかも手動管理… これはいけてないのでそのうち直したい…

実際に運用してみて

メリットとしては作った本人も構築当時の設定等をわすれてしまうもので, 何かあったときとりあえずGitHubをみて設定を確認できるってのは便利だなって思ってます。 今までは構築担当者が死んだらサーバの構成は闇の中でしたがそういったこともなくなりました。 また,教える時に余計コストが増えるかと思いきやAnsibleやDockerの概念さえ教えてしまえば、 細かいところに気をとられることなくざっくりと教えられる、ダブルチェックの手間が減る等 で時間的コストを大幅に減らすことに成功しました。 具体的には昔は構築は教えながらだと2,3日fullでしても終わらないとかでしたが 今は最短数秒,教えながらしても合計12時間程度の時間になりました。

今回サーバ構成で意識したこととしては、要求を満たしかつ凝りすぎないということです。 再利用性や柔軟性をかんがえたり、もっとストイックに全部Dockerで管理したり… ともっとやろうと思えば色々できたと思います。 ただそういうことをしてしまうとメリットをデメリットが上回ってしまいます。 また、シンプルなシステムのほうが壊れにくいし何かあっても対処しやすい。 そういったことを考えて妥協点を探るというのが特にサークルのサーバような 必要経費ではあるものの全力でそれに時間をかけているものではないといった場合に 必要なのではないかと思います(もちろんお金があるんだったら専門の会社とかにアウトソーシングとかもありなんでしょうけど…) 実は明らかな技術的負債も作り込んでしまっていますが、これはきっと後輩たちが解決してくれるでしょう(他人任せ

ただ,緊急で対応したいとかテストしたいとかのときになかなか面倒だなーっていうところはあるので そういったのに対応しやすいPlaybookとかかきたい(テスト環境をいい感じに整備することもふくめ)なあといった感じです。

まとめ

サークルのような低予算かつ人の流動が激しい環境ではAnsible+Docker等で出来る限り環境のコード化する, 構成をシンプルに保つことで幸せになれるかもというお話でした。

次は @littlebird514 君の予定です。よろしくおねがいいたします

Fedora22で突然dnfが使えなくなって解決した話

dnf updateするかーとおもっていつものように

sudo dnf update

とすると

Traceback (most recent call last):
  File "/bin/dnf", line 36, in <module>
    main.user_main(sys.argv[1:], exit_code=True)
  File "/usr/lib/python2.7/site-packages/dnf/cli/main.py", line 198, in user_main
    errcode = main(args)
  File "/usr/lib/python2.7/site-packages/dnf/cli/main.py", line 84, in main
    return _main(base, args)
  File "/usr/lib/python2.7/site-packages/dnf/cli/main.py", line 117, in _main
    cli.configure(map(ucd, args))
  File "/usr/lib/python2.7/site-packages/dnf/cli/cli.py", line 1006, in configure
    self.base.plugins.run_init(self.base, self)
  File "/usr/lib/python2.7/site-packages/dnf/plugin.py", line 104, in run_init
    plugin = p_cls(base, cli)
  File "/usr/lib/python2.7/site-packages/dnf-plugins/system_upgrade.py", line 359, in __init__
    super(SystemUpgradePlugin, self).__init__(base, cli)
TypeError: must be type, not None

とエラー。

調べてみると https://github.com/rpm-software-management/dnf-plugin-system-upgrade/commit/4bbbf1ec0c3f387249d30dd103ff4d002c17f574 に行き着いた。 Python2のユニコード周りのバグらしい...

Unfortunately, Fedora 21 and Fedora 22 don't have that

ほんとに不運だ...

ちゃんと修正されたソースコードはあるのでそれをDLして現状のものを置き換える(念の為バックアップもとっておく)

# cd /usr/lib/python2.7/site-packages/dnf-plugins/
# cp system_upgrade.py{,.bak}
# wget https://raw.githubusercontent.com/rpm-software-management/dnf-plugin-system-upgrade/4bbbf1ec0c3f387249d30dd103ff4d002c17f574/system_upgrade.py

これで解決した。

PyCon2015に参加してきました #PyConJP

1日目

Pragmatic Logging and Metrics

Pythonっぽい話かなと思ったら、わりとインフラよりのお話。 「fast/once/context」を実現するためにどうするか? まずはSentryの紹介。 アプリケーションの例外をSentryに送って、そこからSlack等へ配布。 fluentdに近いイメージ?

次にGrafanaとかいろいろ。 メトリクスを収集して表示的な感じ(いろいろあって把握しきれてなかった...)

そして、各種のログ出力をいい感じに整形して渡してくれるstructlogというのを書いたよという話。

Python と型ヒント (Type Hints)

Python3.5で導入された型ヒントについて。 大雑把にいうとイケメンではあるけれども、 それと同時に弊害・理想と現実という問題もあるというのも現実というような感じの内容。

プログラム全体が対応していないとあんまり意味がないっていうのはC++constみたいな感じだなって思った。

今後漸次的型付け(Gradual Typing)ってのは色々なところでいわれはじめそうな気がするので、 はやめに把握しておきたい。

組合せ最適化を体系的に知ってPythonで実行してみよう

タイトル通り。 組み合わせ最適化の紹介と実用例。 基本的にには解きたい問題をパターンに落とし込んでソルバに入れてあげれば答え出るねという感じ。

組み合わせ最適化問題は 標準問題と数理問題という二面から捉えることができる。 一般的に標準問題のほうが、早くとけることが多い。

わりと数学的なようで実用面結構ありそうだなという感触だった。 解くということに関しては、もうライブラリが充実しているので各アルゴリズムの特性とかを理解するのが良いのかなという感触。

なぜWeb画面自動テストはうまく行かないのか

Seleniumでいけそうだけど、現実問題(マルチブラウザ、パラメータ変更コスト、環境容易コスト)からうまくいかないのでラッパー作りましたという話。

環境に依存しないCoreと、あって状態(パラメータ)を記述するファイルというのはServerspecとかも そういうような感じになっていてWeb画面自動テストに限らずテストのフレームワーク作る際の定石なのかなという印象。

MinecraftPythonで遊ぶ

登壇者が若くて驚いた。 mcpiをつかってPythonからMinecraftをいじると楽しいよという話。

Minecraftで遊んだことないけど、こういう遊び方もあるのかと3000円払いたくなってきた。 発表の中でいわていた学習というコンテキストで語られる機会の多いmcpiだけど、そうじゃなくて楽しいからやってみる っていうのとても大事だなって思う。

いま求められるコミュニティの多様性と未来

コミュニティについてのパネルディスカッション。 色々と考えさせられた。

この中で入りやすいコミュニティ大事という話があったけど、 C++のコミュニティとかここらへん真逆なあれだよなっていう感じがした。

懇親会

ビールばっかり飲んでたw 前から会いたいなーっておもってたこくたんと話せてよかった。 Twitterと同じように面白い人だった。

2日目

PythonとPyCoRAMでお手軽にFPGAシステムを開発してみよう

物理デバイスをつくるプログラムが書くの大変なので、 Pythonラッパーを作ってみましたというお話。

FPGAはあまり興味わかなかったけど、 Python構文木をいじれるってのは面白いなって思った。

uWSGI/Dockerを利用したWebサービス運用事例

わたしはgunironユーザだったけど、 パフォーマンスも良さそうだし、機能豊富だしuWSGI使ってみようと思った。 uWSGIのReuse-Portがダウンタイムを最小にしていい感じにできるらしい。

Dockerはよく言われる壊れることを前提にする的な話だった。

セカイノカオ by チーム・カオ

発想がぶっ飛んでた。 こういうアートとITの融合みたいなのおもしろいなーって思う。

Rise of the Static Site Generator

WordPressみたいなCMSな動的サイトは確かに便利なんだけど、 重かったり、攻撃の対象になったりとか色々と問題が多い。 そこでStatic Site Generator(有名ドコロだとMT?)で解決しましょうという話。 Python製のPelicanが紹介されていた。

唯一聞き取れた英語セッションだったのでうれしかった。(もっと英語力高めたい....)

※あとでまた追記するかも

YAPC::Asia Tokyo 2015に行ってきました!#yapcasia

投稿おそくなりました。ブログを書くまでがYAPCです!

最初はYAPCの存在すらよく知らなかったのですがかるぱねぎらさん(@karupanerura)にチケットを譲っていただき行ってきました。

めっちゃPerl, Perlしているのかなーと思いきやそんなことはなく、IT系の人たちが集まるお祭りって感じでした。 以下気になったセッションの感想を書いていきます。

Managing Containers at Scale with CoreOS and Kubernetes

Kubernetesとは何者なのか? デモとともに紹介していくというセッション。 個人的に最近Dockerに興味を持っていてそろそろ複数のコンテナを扱いたいなーって思っていたので、 ちょうどタイミングのいいセッションでした。

ポイントとしてはKubernetesはスケジューラでありレプリケーションコントローラでPod(同一ホストで起動しなくてはならないDocker群)の数を一定に保つようにするということですかね。 死活監視をしているので、ホストサーバが死んだ場合自動的に最適な別ホストにDockerを立ち上げてくれます。 また、スケールアウトや逐次アップデート、いくつかだけアップデートなどもコマンドをひとつ叩くだけでよしなにやってくれます。 ただ、逆に突然別ホストに移動する可能性があり、死んだDockerは削除されてしまうのでKubernetesで管理するものは基本的にステートレスなDockerクラスタに適応する感じで、永続化したいものはnfsマウントするなりAWSだったらS3に預けるなりしないとダメとのこと。

うっかりをなくす技術

インフラエンジニアとしてお仕事をさせていただいてもらっているので、ミスを出来る限り減らしたいという理由からとてもためになるセッションでした。

人間だからミスをしてしまう。そのミスをいかに減らし、またミスっても大事に至らないようにするかというお話。 まず、意識レベルを高めるということ。指差し確認などが有効なよう。 また、ミスは勘違いから生まれるので、勘違いしないような設計が大事で、そのためにはどうするかというと人の視点にたって手順を作ったりコードを書くとよい。読みやすいコードについてはリーダブルコード読みましょう!というお話でした。また、どうしてもトリッキーな実装になってしまう時はコメントに残す、コメントと実装の乖離をなくすにはみんなでコードレビューが有効。

また、ハインリッヒの法則からnear missを減らせば重大なミスは減らせるが、そもそもnear missは気づきにくいのでどうやって見つけるかが重要。具体的にはGitHubのIssueにヒヤリハットの要因を集めてまとめておくと良いとのこと。

最後にコーディングする上で言語による制約をうまく使いましょうという話。副作用を閉じ込める関数型言語はつよい。

ISUCONの勝ち方

ISUCONで勝つために聞いてきました!

まず、そもそもなぜ早くしなくてはいけないのか? ユーザ的な面だと遅いとUXが下がり、また検索順位に影響するとのこと。 そして、お金的な面で当然速いほどサーバ台数を減らせるのではやいとコスト削減になる。

方針として紹介されていた最初の1時間は問題把握・方針の決定、最後の30分は再起動テストにあてるってのは、去年やっていたのであとはのこりの6:30でいかにチューニングするかですね... また、参考になったのは「決まったことはメモとして書き出す」というの。 計測した情報とかは書き出すようにしてましたが、することに関しては今からします宣言して作業程度だったので、これは実践しようと思いました。 また、レギュレーションを読めというのこれ大事ですね...しなくていいチューニングをしないように。  技術的な面だとまずMySQLでは「コストの高いクエリより実行回数がおおいクエリが効いてくることもある」というの。とりあえずスロークエリにすべて吐き出す設定でベンチまわすのもありかもですね。long_query_time=0でそれが実現できるらしいです。あとは「いつもB+木を」。secondery indexのリーフにはprimary keyがいて、そこからprimary keyの探索が走るというの知らなかったので意識していきたいです。あとはそもそもoffsetがなくなるようにKVSとかとの連携も重要ですね。 Frontだとh2oはやいというはなし聞いたのでちょっと試してみます。

MB-SystemのMBIOの構造

お久しぶりです。

研究関連でMB-Systemのソースコードをよんで修正する機会がありましたので、その時にキーワードとなったMBIOのしくみについてまとめます。

はじめに

MB-Systemとは「MB-System is an open source software package for the processing and display of bathymetry and backscatter imagery data derived from multibeam, interferometry, and sidescan sonars. This software is distributed freely (and for free) in the form of source code for Unix platforms. 」で要するに海底地形データの処理に使用するソフトウェアです。ということでかなりマニアックな領域、情報系とはおよそ関係ない領域のことなので書いてもあんまりじゅようないかなーと思いつつ、私自身どこかにまとめとかないと忘れそうなのでまとめておきます。

MBIOとは

一口に測深データといってもベンダ・機関・機器・versionによって使用しているフォーマットが大きくことなります。 そこでMB-Systemでは測深データを読み込んだ後MB-System独自のデータ形式に変換し統一的に扱えるようにしています。 そのデータ形式(構造体)と操作(関数)を提供するのがMBIOです。ライブラリ化されているので外部からも使えます。 MBIOを使うことで元のデータ形式に依存しない操作ができるようになるわけです。 もちろん各フォーマットへのエクスポートもサポートしています。

MBIOに新フォーマットを対応させる際の作法

今回わたしがやったのは修正ですので、新フォーマットに対応させるということはしていませんが、 調べる途中でだいたい見えてきたのでかいておきます。もしかしたら抜けがあるかもしれません。

src/mbio/配下にmbr.cというファイルを作り(は任意。フォーマット名にするといいかもしれません)、 対応させたいフォーマットからMBIOに変換するための関数を実装します。慣習的に下記のようにmbr_register*という名前になっているようです。

int mbr_register_*(int verbose, void *mbio_ptr,
                int *error);

ここでverboseは出力のレベル、mbio_ptrはMBIOの構造体へのディスクリプタerrorはエラーが起こった時の書き込み先のポインタが渡されます。 基本的にmbio_ptrに、がしがしデータとそれらを扱う関数をセットしていけばおkです。 他のフォーマットの実装を参考にしつつ実装すると楽かと思います。 また、実装しない関数はNULLを入れておくのが作法なようです(ある関数が使えるかどうかの判定が多くの場合NULLかどうかでされている)

つぎにmb_format.hを編集してフォーマットIDを割り当てます。 1000番台の値を割り当てとけばまず、衝突することはないでしょう。 mb_format.hに追記します。

#define MBF_* ID

これと先ほど作成したbr_register_*を紐付ける処理を書きます。 mb_format.cのmb_format_register関数の中に下記のようなelse ifの羅列があるので、そこに追記しましょう。

        else if (*format == MBF_*)
                {
                status = mbr_register_*(verbose, mbio_ptr, error);
                }

また同じくmb_format.cにmb_get_format関数というフォーマットを取得し返す関数があります。 これに新しく追加したフォーマットの判別処理を書きましょう。 例えば独自フォーマットの拡張子が.fooとすると下記のようになります。

        if (found == MB_NO)
            {
            if (strlen(filename) >= 5)
                i = strlen(filename) - 4;
            else
                i = 0;
            if ((suffix = strstr(&filename[i],".foo")) != NULL)
                suffix_len = 4;
            else if ((suffix = strstr(&filename[i],".FOO")) != NULL)
                suffix_len = 4;
            else
                suffix_len = 0;
            if (suffix_len == 4)
                {
                if (fileroot != NULL)
                    {
                    strncpy(fileroot, filename, strlen(filename)-suffix_len);
                    fileroot[strlen(filename)-suffix_len] = '\0';
                    }
                *format = MBF_*;
                found = MB_YES;
                }
            }

基本的に

            if ((suffix = strstr(&filename[i],".foo")) != NULL)

            else if ((suffix = strstr(&filename[i],".FOO")) != NULL)

                *format = MBF_*;

の部分を書き換えればよさ気な雰囲気です(基本的に拡張子しかみてないんですね...

以上をするとフォーマットを自動判別して適切な変換関数を呼び出しあとはよしなに扱ってくれます。