LIVA Z2 Ubuntu設定 四 mongodbプログラム改修【サーバーリプレース その07】

はじめに

どうも、おはこんばんちは。お茶太郎です。

サーバーリプレース作業、少しずつ進めております。

Rubyで開発したプログラム(MongoDB部分)の改修も概ね終わり、現在最終テストをしている段階です。

改修で対応した内容を、自分用の備忘録および皆様に多少でもお役に立てればと思い、ブログに残しておきます。
あくまで素人の書くプログラムですので、非効率・手落ちなどありましても大目に見ていただければ幸いです。

なんとかやりたかったことは実現できておりますので。。。

 

プログラム改修の前に、ちょっと横道

良い子の読み聞かせ物語。。。

ちょっと変わったふたりの本屋さん

遠い遠いある街にちょっと変わったふたりの本屋さんが居ました。

ひとりはとても真面目で、きちんとした事が大好き。
ちょっとでもルールから外れることがだーーい嫌いな犬の本屋さん。

そして、もう一人はちょっと間抜けなおじさん本屋。
ちょっとだけ適当で、ルールとかこだわらないのんびり屋さん。


???
僕は、街の東の本屋さん。
きちんとしたことが大好きさ。
お店の本だって、きちんと整理整頓できてる。だから、とっても気持ちいいだろう!

犬の本屋さんのお店は、むかーーしからやっている小さなお店。

 

お茶太郎
俺は、街の西の本屋さん。
きちんとルールを決めるより、ちょっと自由なお店っていうのも発見があって楽しいものさ。
だからお店の本は自由に置いてあるんだぜ。

おじさんのお店は、ちょっと遠くの原っぱに最近できた大きなお店。


犬の本屋さんは、きちんとしたことが大好き。
だから、昔お店を出した時も一苦労。

???
僕のお店は小さなお店。
だから、お店の本棚はきれいに並んでいなきゃだめなんだ。
だって、小さなお店でもいっぱい本を置きたいから。
だから、無駄なくきれいに本棚を並べるぞ。
ここの列は緑の本棚、その隣は青色、そして赤い本棚もきれいに並べるぞ!
そして、きれいに並んだ本棚の中にも、きれいに本を並べなきゃ。

小さなお店にきちんと色分けされた本棚を並べて、そして綺麗に本を並べた犬の本屋さん。
緑の棚には植物の本、青い棚にはお天気の本、赤い棚には自動車の本。。。
きちんと本を並べられた犬の本屋さん。
でも、お店を出すまでに、ものすごく時間がかかっちゃったんだって。


一方、こちらは適当なおじさん本屋。
お店を出すときもちょっと適当。

お茶太郎
俺のお店は、とっても広い。
だから、本棚も自由に置くのさ。
こことあそこに青い本棚。そっちの空いているところは緑の本棚。
ここに赤い本棚を置けば、本棚迷路の出来上がりさ!!

おじさん本屋は、適当本屋。
でも、やっぱりおじさんも本屋さん。
適当でも、それなりに本は分けられていて、ちゃんと探しやすいお店の出来上がり!

ルールなんてあまり気にしないでどんどん本棚を置いていったから、犬の本屋さんのときよりも早くお店が完成したんだって。


二人の変わった本屋さん。

本当に変わっているのはお店の本。

???
僕のお店はきちんと本屋。だから、お店の本もきちんとしてるんだ。
本の中身の順番も、きちんと決まっているんだよ。

きちんと決まっているからさ、中身を見つけるのも簡単なんだ。

いっぱい並んだお天気の本。
最初のページは北の町。春の天気と夏の天気。
5ページ目からは南の町。やっぱり中身は、春と夏。
みんな中身は同じ順番。春の天気に、夏の天気。
10ページ目を開けば、秋の天気がすぐわかる!!

いっぱい並んだお料理の本。
最初のページは目玉焼き。2ページ目にはオムレツだ。
厚焼き玉子に、オムライス。
本の中身も順番も、きちんと決まった順番だ。
本が違えばレシピは違う。それでも中身の順番は、きちんと決まったルール通り。

朝顔のページは20ページ。
ひまわりの事が知りたけりゃ、どの本も50ページを見ればいい。

犬君のお店は、きちんと本屋。だから、本もきちんさん。


お茶太郎
俺のお店は、面白お店。

だから、本の中身も自由なもんさ。
なんでもかんでも書いてある。
順番なんて、意味ないさ。面白本屋は自由な本屋。

最初のページは目次かな?
そんなルールなんてないんだよ。

落書き、メモ書き、バラバラさ。
でも、中身がわからなきゃ本じゃない。
だから、本には見出し付き。見出しを見つりゃ、中身がわかる。

面白本屋は自由な本屋。
見出しでまとめて、中身を探す。


さてさて、ちょっと変わった二人の本屋さん。
ちょっと困った問題が。。。

???
家の本屋はきちんと本屋。
本棚に並べる本も綺麗に並べるんだ。

でも、たまに大きな本があって本棚にはいらないんだ。
その本は棚の上に置こうかな? でもそれじゃあ、きちんと本が並ばない。
しょうがないから、この本はお店にはおけないなぁ・・・

お茶太郎
俺のお店は、面白本屋。

置いてある本も自由なもんさ。
でも大きさの違う本を並べると、どうしても無駄なスペースができちゃうぞ。
でも、うちのお店は広いんだ。だから、自由に本も置いちゃうぞ!

横に寝かして並べても、本には変わりないからな。


ちょっと変わった二人の本屋さん。

犬君のお店は、綺麗に本棚に収まらない本はお店に置いてない。
おじさんのお店は、適当に並べた本が無駄に積み上がってきている。

さてさて。。。
更に困った問題が。。。

???
きちんと本を並べてきたけど、本棚がいっぱいだ。
植物の本を置く場所がないんだ。
青い本棚はお天気用の本棚。ここに植物の本はおけないなぁ・・・

本の中身もルール通りにならないやつもでてきちゃったぞ。
ハエ取り草なんて、他の本にはでていないよ。きちんとページも揃わない。

お茶太郎
面白おかしく本を揃えてきたけれど、無駄がいっぱいでてきたぞ。

この本の20ページは朝顔だ、50ページにはひまわりさ。
みんなページが決まっている。わざわざ見出しは不必要。


きれいに本が並ばなくなってきた犬の本屋さん。
そして、広かったお店にも無駄に本が積み上がって来たおじさん本屋さん。

ふたりのちょっと変わった本屋さん。
とっても困ったふたりの本屋さんになっちゃった。

そこで二人は相談しました。

???
町の東のおじさん本屋さん。
ちょっとお願いがあるんです。
お茶太郎
町の西の犬の本屋さん。
丁度よかった、俺もちょっと相談が。。。

ちょっと変わった二人の本屋さん。
犬の本屋さんで置けなくなった大きな本、中身の自由な本はおじさん本屋さんのお店で。
おじさん本屋さんで山積みになった、きちんとページが決まった本、こちらの本は犬の本屋さんで、売ってもらう事にしました。

ちょっと変わった二人の本屋さん。
これからは、協力しあって、町の人に楽しい本を届けていくことにしましたとさ。

おしまい


ということで、お話はここまで。

ここからは解説です。

データベースについて・・・

今回、物語風に描いた内容はデータベースの構造をイメージして書いています。
データ屋さんがデータベースをイメージしながら、子供向けの物語を書いてみました。

犬の本屋さんはSQL形式のデータベース、おじさん本屋さんはNOSQL形式のデータベース(Mongodb)です。

SQL型のデータベース

ルールをきちんと決めてお店を出した犬の本屋さん。

データベースをきちんと定義しないといけない(スキーマと言います)データベース、SQL型のデータベースに似ています。
SQL形式のデータベースは、エクセルの表のような形のテーブルというデータを保存する領域を用意します。
これは、犬の本屋さんの本棚に該当します。
緑の棚には植物の本を置いたように、特定のテーブルには特定のデータを記録します。

本当にエクセルの表のイメージに近いのですが、行としてレコードというデータのセットを持ち、それぞれの列には特定のデータが入ります。
これは物語で言うところの、本棚=テーブル、本=レコード、オムレツ=データです。

犬の本屋さんの変わった本。決まったページに決まった内容が書いてありました。
SQLのデータベースも、決まった列に決まったデータは入っています。
そして、そのデータは型というものが決まっています。
このデータは整数、このデータは文字列など列ごとにデータの形がきまっています。

データベースを新しく作るとき、このデータ定義(スキーマ)を設計するのにとても手間がかかります。
それは犬君がお店を出した時、手間がかかってしまったのと同じイメージです。

そして、整数型の項目に文字列のデータが入ってくると、エラーとなります。

NOSQL型データベース(mongodb)

こちらはおじさんの本屋さんです。

本棚や本の中身は自由です。
SQLのようにスキーマの定義は不要です。

表や列のようなイメージでデータを持っているわけではなく、ドキュメントの中身は基本的に自由記述のテキストのようになっています。
それぞれのデータに見出しのようなものが付いた、自由テキストというイメージでしょうか。
後ほど、改めて例示いたします。

Mongodbはデータの型を定義が不要のため、どんなデータでもどこのデータベースにも保存できます。

これは、自由にデータを作れるというメリットに対し、コレクションを間違たとしてもエラーで止まらずデータが保存されるというデメリットもあるということです。
プログラム作成時、エラーチェックロジックが存在しないのはとても危険なことだと言えますね。

データ構造比較

2つの形式のデータベース、シンプルなデータ構造の例をしてしてみてみることとします。

SQL形式のデータベース

料理名
(文字列)
材料
(文字列)
レシピ
(文字列)
調理時間
(整数)
備考
(文字列)
オムレツ
砂糖

牛乳
バター
まず、フライパンを火にかけ、熱します。
続いて・・・・
10
ゆで卵 まず、鍋に水をはり・・・ 15 卵はあらかじめ冷蔵庫から取り出し、室温に戻す

情報(データ項目)の重複がないため、メモリ・記憶領域の無駄遣いが少ない。
データ抽出時、料理名・材料など各項目に対し検索するため、検索時間が短くなる。

Mongodb

{”料理名”=>”オムレツ”,”材料”=>”卵、砂糖、塩・・・”,”レシピ”=>”moge-moge”,”調理時間”=>10,”備考”=>””}
{”材料”=>”卵”,”レシピ”=>”moge-moge”,”調理時間”=>15,”料理名”=>”ゆで卵”,”備考”=>”卵はあらかじめ室温に戻す”}
{”料理名”=>”生卵”,”備考”=>”調理手順ないため、レシピなし”}

上記データでは、1番目のドキュメントと2番目のドキュメントではデータの順番が違います。
また3番目のドキュメントは項目が2つしかありません。
この様に自由な構造のため、ドキュメントの中身もルールなく自由に作成することが可能です。
ただし、各データごとにデータ項目(見出し:正式名称わからず・・・)を持つため、情報の重複が発生し、データ容量が肥大化します。
十分なメモリと記憶領域が必要となります。
自由に記述されたドキュメント全体に検索をかけるため、抽出にも時間がかかるでしょう。

構造が自由なため、使い方も自由度が高くなっています。

データベースの新規作成は、書き込もうとした時点(呼び出したときかも。。。)で完了します。
SQL型のデータベースのように、事前にきちんと設計を決め、空のデータベース・テーブルを作るという(スキーマ)は不要です。

データ構造、データ内容など決まっていないような状態でも、気軽にテストプログラムを書くことができるということです。
開発中に、納得いかなければ、データベースごと削除し、プログラム修正して、再度データインサートすれば、新たにデータベースが出来上がります。
毎度毎度、設計自体をやり直さなくてはいけないSQL型のデータベースとは大違いです。

事前に仕様が確定しないアジャイル型の開発やDevOps型の開発と相性がとても良いと思います。
また、運用中にデータの中身が変わる可能性があるデータの保存にも向いています。
ということで、私は最近Mongodbを使って開発しています。
データベースが巨大化した時に、分散処理もできるのですがそこまでは活用しきれていません。

このように、SQL型データベースとNOSQL型データベースは基本構造が大きくことなります。
ただ、どちらが優れているというものではなく、利用目的・データの特性・環境など考慮し、適材適所で使い分けることが大切かと思います。

物語のラスト、犬の本屋さんとおじさん本屋さん、助け合って町のみんなに楽しい本を売ることにしたように。。。

補足
ちょっとシステムかじった素人データ屋さんのデータベースに関する考察ですので、間違いあればご指摘いただけると幸いです。

ということで、横道はここまで。。。

バージョン

今、移行作業中のバージョンアップは下記の通り

  • 現行サーバーのバージョン  mongodb:2.4.12  Ruby : ruby 1.9.3p484
  • 新サーバーのバージョン   mongodb:3.6.3   Ruby:ruby 1.9.3p484

MongoDBのバージョンが大きく上がる部分でトラブルが発生しています。
なんとなく、Linuxを使っているシステム屋さんではない私にはちょっとハードルが高く、手間取っております。

そして、試行錯誤して上手く行った対策を、備忘録としてブログに残しておきます。
記述に間違いがあった場合はご勘弁を。。。
ただし、注意事項やコマンドは実際に私が試して、困ったこと・上手く行ったことを記載していますので、再現性はあるはずです。

注意
2.4から3.6へのバージョンアップは、必ずステージング環境(テスト環境)を用意して行ってください。
コレクションのバージョンアップやコマンドの修正など発生し、移行に時間が掛かります。
本番環境を直接バージョンアップすると、(使用状況にもよりますが)数日間サーバーが止まる事になります。

改修/回避内容

MongoDBは、Rubyでコントロールしています。
Rubyのプログラム変更は、根本的な問題を解決する【改修】と解決方法が解からずその場しのぎの【回避】で対応しています。
システムスキルがないための苦肉の策の【回避】が多いかと思いますが、多少なりとも困っている方のお役に立てれば幸いです。

コレクションの宣言

データベースの呼び出しから仕様が変わったようで、いろいろうまく動きませんでした。

そこで、下記のように改修しています。

connection = Mongo::Connection.new
db = connection.db('moge-moge')
coll = db.collection('moge-coll')

↓↓↓↓↓↓

logger = Logger.new(STDOUT)
logger.level=4               #ログレベル設定 4 :fatal, 3 :error, 2 :warn, 1 :info, 0 :debu
db = Mongo::Client.new([ 'localhost:27017' ], :database => 'moge-moge', logger: logger)
coll = db[:'moge-coll']

必要以上にログを出力するため、それをコントロールする設定が最初の2行になります。

既存ドキュメントの確認

登録済みドキュメントかどうか判断して、未登録の内容であれば処理をする(ドキュメントを追加する)ときの処理です。

if coll.find_one('moge' => 'moge-moge').count == nil then
     hoge-hoge
end

↓↓↓↓↓↓

if coll.find('moge' => 'moge-moge').count == 0 then
     hoge-hoge
end

1件を出力することができなかったので、件数をカウントすることにしました。

ドキュメントの追加

ドキュメントを新規で追加するときの作法も変わったようです。

coll.insert(moge-moge)

↓↓↓↓↓↓

coll.insert_one(moge-moge)

細かなところにも変更があるものです。

ドキュメントの更新

ドキュメントを更新する時も、新規のように「_one」が必要です。

coll.update(moge-moge)

↓↓↓↓↓↓

coll.update_one(moge-moge)

ドキュメントの削除

ドキュメントを削除する時は、『remove』ではなく、『delete_many』

coll.remove()

↓↓↓↓↓↓

coll.delete_many()

処理をするドキュメントが1件なのか、それとも複数なのかを厳密に定義する仕様になったみたいです。

anemoneの一次データ保存領域をmongodbにしていた場合

これが対応できなく、SQLiteを一次保存の領域にすることとしました。

opts = {:storage => Anemone::Storage::MongoDB()}
Anemone.crawl("http://moge-moge.com", opts) do |anemone|
     hoge-hoge
end

↓↓↓↓↓↓

require 'sqlite3'

File.delete(Dir::getwd + "/anemone.db-journal") if File.exist?(Dir::getwd + "/anemone.db-journal")
File.delete(Dir::getwd + "/anemone.db") if File.exist?(Dir::getwd + "/anemone.db")
opts = {:storage => Anemone::Storage::SQLite3()}
Anemone.crawl("http://moge-moge.com", opts) do |anemone|
     hoge-hoge
end

SQLite一次保存領域とすると、「anemone.db-journal」「anemone.db」のデータファイルが形成されます。
このファイルが残っていると、エラー表示もなく、Rubyのプログラムが終了する挙動が見られました。
そこで、ファイルが存在する場合は、それらを削除する処理をしています。ファイルはオプション指定した時に生成されるので、その前段階で削除します。

最後に

ざっとではありますが、私が対応した改修内容メモしておきました。

これでプログラム改修は完了となりますので、週末にでも最後のテストを終わらせ、遂にサーバ入れ替えです。

ただ。。。
その前に、Liza Z2の経過レビューとWindows10の複製をしてみたいと思っています。
32GBのドライブから、増設したSSDへの換装です。
ただし、SSDに余りがないため、HDDへの換装とする予定です。

ご興味ある方はそちらもご一読いただければ幸いです。

それでは、本日はこれにて。。。ノシ〜〜〜〜

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です