ちょっと硬派なコンピュータフリークのBlogです。

カスタム検索

2009-12-28

MySQL Cheat Sheet 1.0

先日、DB2 Cheat SheetなるものがDB2な人のページにアップされたので、負けじと早速MySQL Cheat Sheetを作ってみた。

A4サイズで印刷して手元に置いたりデータセンターに持っていったり額に入れて壁に貼ったりポスグレ派の人の鞄にこっそり忍ばせたり自分の枕の下に敷いたり(イイ夢見るよ!)出来るようにしてあるので是非ダウンロードしていただきたい。なお、ツッコミがあればいつでも本投稿へのコメントおよびTwitter(@nippondanji)やメール(みきやどっとおくのあっとぢぃ〜めいるどっとこむ)などで受け付けているのでお気軽にどうぞ!!

2009-12-22

MySQLバックアップ頂上決戦!! LVMスナップショット vs InnoDB Hot Backup

先日のMyNAのイベントにて、「InnoDB Hot Backup(もしくはXtra Backup)のようなツールとLVM等でスナップショットを取るのはどちらが最強のバックアップたり得るか?」という感じの内容の議論がなされていたのだが、確かにこれは答えるのが難しい永遠のテーマである。永遠のテーマだからこそ漢のロマンがある!!というわけで、今日はそれぞれのバックアップ方法について仕組みを説明しつつ私の見解を述べたいと思う。(見解≠結論ではない点には注意して頂きたい。結論を出すのは貴方なのだから!!)

2009-12-18

MySQLに纏わる10の都市伝説

誰の口から飛び出したのかは定かではないが、巷ではMySQLにまつわる様々な「都市伝説」がまことしやかに囁かれているようだ。恐らくMySQLに対する理解が低い人や、MySQLがあまり好きではない面々によってFUDっぽく言われているのだと思うが、世の中にはそのような「都市伝説」を真に受けてしまう人が居るのもまた事実であである。MySQLにおける昨今の開発スピードには目覚ましいものがあり、MySQLは性能・安定性・使い易さ共に進化し続けている。(特に先日リリースされたMySQL 5.5は性能・安定性・使い易さを両立している優れたバージョンだ!!)しかし「都市伝説」で語られることは総じて「MySQLはダメな子ちゃん」であるという烙印を押すものばかりであり、MySQLerとしてはそのような言われ無き汚名を全身全霊をもって晴らさなければならない使命を背負っている。そこで、今日はMySQLについて語られている「都市伝説」を10個紹介しよう。MySQLをよく知っている人にとっては「んなアホな!?」と思われるほど突拍子もない事ばかりなので、くれぐれもそのような根も葉も幹も細胞もないうわさを信じないで頂きたい。

2009-12-16

MySQL 5.5 厳選リンク集

現時点で出てきているMySQL 5.5関連の(MySQL 5.5の新機能を理解するのに役立つ)ページをまとめておくので参考にして頂けると幸いである。

MySQL 5.5登場

MySQL 5.5がリリースされた。「えっ?!この前5.4をリリースしたばっかりでしょ?!まだ5.4すら使ってないよ!!」と驚かれた方はご安心を。これは開発リリースモデルが変更されたためで、MySQL 5.4はこれでいったん開発終了して今後の開発はバージョン5.5をベースにして継続されることになる。バージョン5.4も5.5も「マイルストーンリリース」(以下MR)という位置づけであり、GA(正式リリース)版ではない点に注意して頂きたい。MR版の位置づけは次のようなもの。

2009-12-12

mysqldumpの出力結果をデータベースごとに分割するパッチ

先日は、mysqldumpの出力結果をawkを使ってデータベースごとに分割する方法について紹介したが、セミナーも終わったことなのでパッチを書いてみた。awkで分割するというのはUNIXユーザーの伝統芸能なので嫌いではないがまどろっこしいと感じる方も居るかもしれない。そもそもmysqldump自体がそのような機能をサポートしていれば問題ないのだから!

というわけで、興味のある人は次のバグレポートからパッチをダウンロードして試してみて欲しい。

http://bugs.mysql.com/45003

そして試した後にはフィードバックを残して頂きたい!!

パッチの適用方法は以下。

まずはMySQLのソースコードを入手する。ダウンロードサイトから最新のものを入手するか、bzrでゲットして頂いて構わない。

ダウンロードサイト:
http://dev.mysql.com/downloads/mysql/5.1.html

bzrコマンド:
shell> bzr branch lp:mysql-server
ダウンロードサイトから入手した場合は、ソースコードを展開しておいて欲しい。

次に、上記のバグレポートから、bug45003.patchというファイルをダウンロードして、ソースコードのトップディレクトリ(展開した後に作成されるディレクトリ。ダウンロードサイトから入手した場合にはmysql-5.1.41、bzrで入手した場合はmysql-server)へコピーしよう。
shell> cp bug45003.patch mysql-5.1.41
そしてパッチを適用する。
shell> cd mysql-5.1.41
shell> patch -p 0 < bug45003.patch
あとはビルドして生成されたmysqldumpを実行するだけである。パッチを適用したmysqldumpを使ってデータベースごとにファイルを作成するには--backup-basedirオプションを使う。このオプションは--databasesまたは--all-databasesオプションと併用しなければならないという制約がある。また、--tabオプションと同時に使うことは出来ない。コマンド実行例は次の通り。
shell> mysqldump --backup-basedir=/backup\
--single-transaction --master-data=2 --flush-logs\
--databases db1 db2 db3
そうすると、/backupディレクトリに6桁の数字、例えば000001というディレクトリが作成され、そのディレクトリの下にdb1.sql、db2.sql、db3.sqlという具合に「データベース名.sql」というファイルがそれぞれ作成されるという寸法である。6桁の数字のディレクトリは、既に他のディレクトリが存在する場合、次の数字が使われる。(000001が存在すれば000002が、000002が存在すれば000003が作成される。)常に同じコマンドラインでバックアップを作成できるというワケだ。

皆様からのフィードバックをお待ちしております!!

2009-12-09

ギークが己の世界観で語る、コミュニケーションが論理的になりすぎてはいけない理由。

論理的なコミュニケーションをしろと言ったりするなと言ったり、お前は一体どっちなんだ?!と突っ込みたくなるところをぐっと抑えて、まずはこの記事を最後まで読んで欲しい。話はそれからだ。

論理は手段(ツール)であって目的ではない

ある記述が論理的に正しいことは、論理的なコミュニケーションの場ではとても重要なことであり、言わば論理的であることはコミュニケーション(主に議論)を建設的なものにすることの前提条件であると言って差し支えない。理論的なことを思考するにはもの凄い集中力が必要なので、ついつい議論に集中し過ぎて「自分の主張の正しさ」だけを追求してしまい、話が噛み合わず不毛な時間を過ごしてしまうということになりがちである。人と人が何かについて話合ったり議論したりするということは、「今抱えている問題を解決したい」「建設的な意見を出し合ってプロジェクトを進めたい」などの目的があるはずであるから、「論理的な議論」というのは目的達成のための手段であるに過ぎないのである。目的を忘れて「論理の正しさ」ばかりに集中してしまうと、頓珍漢なやりとりを繰り広げてしまうことになるのである。

会話がちぐはぐになるだけならまだいい。しかし理論的な正しさばかりを追求すると本来の目的を見失うどころか、逆にとんでもない弊害をもたらすことがあるので注意が必要だ。例えばサポートエンジニアが論理的な正しさばかり追求することに白熱してしまい、

「お客様のおっしゃることはまちがっています。なぜなら、理由はxxxxxだからです。問題が解決しないのはお客様の認識が間違っているからです。」

などという意味のことを言った場合を想像してみて欲しい。かなりの高確率でクレームを頂き、クレーム対応という理不尽な世界≒地獄への片道切符を手に入れることになるだろう。そもそもサポートエンジニアの役割はお客さんの問題や悩みを解決することであって、理論的なアプローチはそのための手段でしかない。単に論理的なアプローチが効果的だから選択しているに過ぎないということである。従って極論してしまえば問題が解決してしまえば理論的な正しさなどどうでもいい。理論的な正しさを優先させてお客さんを怒らせてしまうと悲惨な結末が待っている。まさに「どうしてこうなった?」と言わんばかりの結末が・・・。

くれぐれも理論的な正しさを追求するあまり、本来の目的を見失ってはいけないのである。

論理的思考の限界

論理的なコミュニケーションを行うには論理的に物事を考える必要があるのだが、そもそもその論理的思考には限界があるということについてここで紹介したい。

ところで、理論的に正しい記述というのはどのようなものだろうか。極力誤解のないようにストレートに表現すると、「論理的に正しい記述」というのは「論理学的に正しい記述」と言い換えることが出来る。論理学的に正しいとは、ある命題(前提)から別の命題(結論)を演繹(えんえきと読む。≒論理演算)だけを用いて導出できるということだ。つまり、演繹だけで構成された記述だけが、論理的に正しい記述と言えるのである。(ただし、演繹をショートカットするための定理は用いても可)それ以外の記述はすべて論理的な記述ではない。「なんだって?!そんなバカな!?だったら論理的な文章なんて殆ど存在しないじゃないか!!」と思われるかも知れない。いや、実はまさにその通りなのである。世の中に存在する「論理的な見た目を装った文章」の99.9999%は実は論理的ではない!!と俺は断言する。殆どの文章は論理的な見た目を装って自分の主張をタレ流しているだけである、と。

そもそもであるが、論理的に正しい記述をするというのは気が遠くなるほど地道な作業である。そのことを説明するために例として演繹の代表格である「三段論法」について考えて見よう。言わずもがなであるが、三段論法とは次のようなものである。
  • Aが正しいならばBも正しい
  • Bが正しいならばCも正しい
  • よってAが正しければCも正しい
三段論法によってもたらされるものは命題A、B、Cの関係性だけである。三段論法では大前提であるAの正しさについてはどこでも言及されていないところがミソだ。三段論法を用いて何か論理的に正しい主張をするとしよう。「Aという事実がある。AならばBなので、よってCというのは世の中の真理である」と。この主張が論理的に正しいことを証明するためには、大前提のAが正しい命題でなくてはならない。果たしてAの正しさを我々はどのように証明するべきなのだろうか。

そこで登場するのが「公理」というものである。公理とは数学用語であるが、あらゆる命題を導きだすための大前提として用意された最も基本的な仮定のことであり、公理の集合を公理系という。公理を組み合わせて導き出された帰結が「定理」であり、定理の正しさは公理系によって保証されていると言える。従って、真に論理的な正しさを追求するならば、「公理からの演繹によって導き出された帰結以外は全て非論理的」と切り捨てなければならない。

ここで勘の良い人ならばもうお気づきだろう。「公理系の正しさはどうやって証明するんだ?」と。

実は完全無欠の公理系は存在しない!ということが既に天才数学者ゲーデルによって証明されている。かの有名な「ゲーデルの不完全性定理」である。不完全性定理を要約すると「完全な公理系を用いてその公理系そのものの無矛盾性を証明することはできない」ということだ。つまり、実は完全無欠の論理というのは端から存在しないということなのだ!!

な、なんだってーっ!!(AA略)

完全無欠の論理が存在しないということは、どのような命題でも論破出来るということである。よくネットで「ハイ、論破」などという表現を見かけるが、どのような主張でも論破出来ることは最初から分かっている(ゲーデルが証明した)ので「論破したよ!」などとアピールするのは全くもって無意味かつ自らの無知をさらけ出す行為であると言えよう。

従って、如何に論理的な記述を突き詰めようと思ってみても完全な論理体系というものは存在しないので、論理の正確さに固執しても仕方がないのである。

フレーム問題

論理的な思考の有効性を否定する問題がもう一つ存在する。それは俗に言うところの「フレーム問題」だ。フレーム問題とは人工知能学者が古くから直面している由緒正しき問題で、平たく言うと「人間にとってごく身近で易しい問題であっても、コンピュータを用いた演繹では解決できない問題が存在する」というものである。以下はWikipediaからの引用で、フレーム問題、つまりコンピュータが解決出来ない問題についての有名な例である。

状況:洞窟の中に、ロボットを動かすバッテリーがあり、その上に時限爆弾が仕掛けられている。このままでは爆弾が爆発し、ロボットは動かなくなってしまうので、洞窟の中からバッテリーを取り出してこなくてはならない。ロボットは、「洞窟からバッテリーを取り出してくること」を指示された。

人工知能ロボット1号機R1は、うまくプログラムされていたため、洞窟に入って無事にバッテリーを取り出すことができた。しかし、1号機はバッテリーの上に爆弾が載っていることには気づいていたが、バッテリーを運ぶと爆弾も一緒に運び出してしまうことに気づかなかったため、洞窟から出た後に爆弾が爆発してしまった。これは、1号機が、バッテリーを取り出すという目的については理解していたが、それによって副次的に発生する事項(バッテリーを取り出すと爆弾も同時に運んでしまうこと)について理解していなかったのが原因である。

そこで、目的を遂行するにあたって副次的に発生する事項も考慮する人工知能ロボット2号機R1-D1 (D = deduce (演繹) ) を開発した。しかし、このロボットは、洞窟に入ってバッテリーの前に来たところで動作しなくなり、そのまま時限爆弾が作動してロボットは吹っ飛んでしまった。2号機は、バッテリーの前で「このバッテリーを動かすと上にのった爆弾は爆発しないかどうか」「バッテリーを動かす前に爆弾を移動させないといけないか」「爆弾を動かそうとすると、天井が落ちてきたりしないか」「爆弾に近づくと壁の色が変わったりしないか」などなど、副次的に発生しうるあらゆる事項を考え始めてしまい、無限に思考し続けてしまったのである。これは、副次的に発生しうる事項というのが無限大にあり、それら全てを考慮するには無限大の計算時間を必要とするからである。ただ、副次的に発生する事項といっても、「壁の色がかわったりしないか」などというのは、通常、考慮する必要がない。

そこで、目的を遂行するにあたって無関係な事項は考慮しないように改良した人工知能ロボット3号機R2-D1を開発した。しかし、このロボットは、洞窟に入る前に動作しなくなった。3号機は、洞窟に入る前に、目的と無関係な事項を全て洗い出そうとして、無限に思考し続けてしまったのである。これは、目的と無関係な事項というのも無限大にあるため、それら全てを考慮するには無限大の計算時間を必要とするからである。

このようにR2-D2の実現は難しいのである。

人間にとってこのロボットの思考は素っ頓狂であり、このような思考を展開することはまずない。何故ならば、我々は自然に「問題を解決するために必要なもの」だけを数多く存在する事象の中から瞬時に選択して行動することが出来るからだ。何故そのような能力が人間に備わっておりコンピュータでは簡単に実現できないか?とうことについては話が脱線するので書かないが、この話のミソは論理的な思考だけを突き詰めて行くと「論理的思考の持ち主の代表格」であるコンピュータと同様のフレーム問題に直面するということである。Xという問題を解決するのにYという事象が無関係であることを論理的に証明しなければならないとしたら、Y', Y'', Y'''・・・と永遠に全ての事象についても同様に無関係であることを証明しなければならず、我々の思考はそこで停止してしまうことだろう。

フレーム問題を考察によって得られるひとつの帰結は、皮肉にも「問題の解決策を探るのに必要なアプローチは論理的であってはならない」ということである。つまり、「Xという問題について考えよう!」となったとき、非論理的な思考を導入しなければ議論は一向に進まないのである。とはいえ、そのような非論理的な思考は我々が自然に発揮することが出来る能力だから我々がフレーム問題に直面する心配はない。

常識という暗黙の了解

これまでの話のポイントを(非論理的に)整理すると次のようになる。
  • ディスカッションの目的を見失ってはならない。
  • そもそも完璧な論理というものは幻想なので、そのようなものを追求するのは徒労に終わる。(根拠1:ゲーデルの不完全性定理、根拠2:フレーム問題)
  • ゆえに、論理的な正しさにこだわりすぎるのは良くない。
「それならばそもそも論理的に議論するということ自体が無駄じゃないの?」と思われる方も居るだろう。しかしそのような身も蓋もないことがまかり通ってはどのような議論も不毛なものにならざるを得ないし、このブログを読んで下さっている諸氏の時間を無駄にしてしまうことになるだろう。完璧な論理というものが存在しないと仮定した上で、我々が建設的な議論をする(もしくは単に論理的な思考をする)にはどうすればいいだろうか。

我々が何かについて議論、例えば「AならばCという命題が正しいか」どうかと言うことについて議論するとき、議論に参加しているメンバーは前提条件である「Aが正しい」という命題を無条件で肯定する必要がある。何故ならば、「そもそもAという命題が正しくない」となったら、「AならばC」という命題の正しさを考えるのは無意味だからだ。Aが正しいことを証明することは不可能だが、一般的な問題、例えば「日常生活におけるマナーについて」といったことを議論する場合、その前提となっている暗黙の了解は「常識」に基づいていると考えて差し支えない。つまり、「Aという命題が正しいこと」や、「Xという問題を解決するにはZというアプローチが有効である」というような思考は常識(ないしは前提知識)によってもたらされるわけである。

共通の前提知識が共有されている場合、論理的なアプローチによるディスカッションはとても建設的なものになるだろう。しかし逆に、ある命題についての認識が異なる場合(一方はAが正しいと思っていて、他方はAが正しくないと考えている場合など)は、ディスカッションは悲惨な結果にしかならない。俗に言う「水掛け論」の状態である。とは言え、個々人の常識などというものにはどうしようもない個人差が存在するので、実際のディスカッションではお互いの常識が同じかどうかということについては白黒ハッキリしないのが当然であり、言わば常に「前提がグレーな状態」で議論を交わすことになるといって差し支えない。そのような状態で議論を建設的なものにするには次のようなアプローチを取るのが良いだろう。
  • 相手との共通点を確認する。例:「xxxxxは正しいという認識で合ってますね?」
  • 相手の主張を受け入れる。例:「xxxxxという主張は自分は100%正しいとは思わないが、いったんその前提で話を進めようか。」
  • 議論を通じて共通の認識を構築する。例:「xxxxxという点は合意に至りました。それでは議論をさらに進めましょう。」
要するに、お互いの共通の認識の上にさらに次の共通認識を作り上げるというのが、建設的かつ論理的なコミュニケーションなのである。(同様に、ある命題を前提条件として、さらなる次の命題へと演繹によって発展させるのが論理的思考であると言えよう。)

まとめ

ここでさらに話を強引にまとめると、「やっぱり常識とかバランス感覚って大事なんだね!」ということに集約される。結局常識がなければ論理的なコミュニケーションは成り立たないのだから。最近の日本では常識というものが非常に多様化してきており、これまで島国という特殊な環境で(つまり価値観が非常に似通っているという状況で)過ごしてきた日本人にとっては少々厄介な世の中になってきていると言えるだろう。価値観が多様化すればそれだけ柔軟な思考、別の言い方をすると相手の常識や価値観を認めるというスキルが求められる。つまり謙虚さが必要なのである。

謙虚さを忘れず相手の意見を尊重し、建設的な意見交換を行いたいものである。

おまけ。Windows vs Mac vs Linux

議論を建設的なものにするには共通の認識、つまり互いの常識が重要であることは述べた通りであるが、逆に言うと常識が異なるもの同士が議論をするとロクでもないことになってしまうということが言える。ギークにとって最も代表的な水掛け論はOS論争ではないだろうか。Windows信者、Mac信者、Linux信者でそれぞれ価値観や常識が異なるのだから、お互いが例えば「どのOSの作業効率性が最も優れているか」について議論しても建設的になることはないだろう。

つまり、意気投合する者同士好き勝手喋ってろ!ということである。(あ、コレやっぱり身も蓋もないw)

2009-12-04

サポートエンジニアが経験から語る、論理的文章によるコミュニケーションのススメ

俺はこれまで一貫してIT業界でエンジニアとしてのキャリアを進んできたのだが、これまでのキャリアでもう一つ一貫していることがある。それは、ずっとサポートエンジニアであるということだ。実はサポート職というのはかなり論理的なコミュニケーションを必要とする職種であり、如何に論理的な文章を上手に書くかということが、如何に良い仕事をするか(短い時間で成果=顧客満足度を得られるか)ということに繋がるという側面がある。(もちろん高い技術力が必要なのは言うまでもないが。)サポートエンジニアはメールや報告書という形で日々論理的な文章を書かなければならないので、サポートの経験を重ねることによって論理的にコミュニケーションをする能力というのは徐々に磨かれよう。しかし、論理的にコミュニケーションをするというのは意外と皆出来ているようで出来ていないし、筋が悪いといつまで経っても身につかないこともあり、上手にお客さんを説得することが出来ずにクレームを受けやすい人が居るのも確かだ。

そこで、今日は漢がサポート職を通じて身につけた「論理的な文章の書き方」ということについて、ポイントを紹介しようと思う。

最も大事なことは、ちゃんと質問に回答すること。

何を今更ワケの分からないことを言ってるんだ?そんなの当たり前じゃないか?と思ってしまうかも知れない。しかし、この基本中の基本とも言えることが実は意外と出来てないことが多いのである。実は質問というのは、内容はバリエーションに富んでいるが、質問の形式というのは種類が決まっている。そして、個々の質問の形式に合った回答をしないと、質問に答えたことにはならないのである。如何に有益な情報を書いて相手にメールを送ったとしても、相手の質問に回答していなければ意味がない。それどころか、お客さんは「ちゃんと俺の質問に答えていない」とイライラを募らせてメールをよこす羽目になってしまうのである。

3つしかない「質問」の形式

形式はたったの3つしかないだと?「ハァ?バカにするなよ!」と思われる方はまず落ち着いて続きを読んで欲しい。それは紛れもない事実なのである。「なんだって?質問だったら何でも聴けるんじゃないのか?」という意見もあるしそれは確かに正しいのだが、質問の内容は千差万別でもその形式にはバリエーションはないのである。3つしかないのだから誰だって覚えられるし対策もできる!というわけで、是非これを読んでいるアナタも試してみて欲しい。その3つの形式とは次の通り。

  1. Yes/Noで回答できる質問
  2. 5W1Hの質問
  3. それ以外の質問

それではこれらについて、順を追って説明していこう。

Yes/Noで回答できる質問

最もシンプルかつ多く見受けられるのが、YesかNoで回答出来る質問だ。最もシンプルな例を挙げると「Is this a pen?」というような質問がこのカテゴリに該当する。YesかNoで回答できる質問(以下Yes/No質問)には、YesかNo以外の回答をしてはいけない。そんなの当たり前じゃないかと思うだろうが、これは実は多くの人が無意識のうちに破ってしまう約束事である。どういう事かというと、相手はYesかNoか?と聞いているのについそれ以外の回答をしてしまうということだ。ちょっと卑近な例として、スーパーの生鮮食品売り場で買い物をするときの例を見てみよう。(ちょっとバカ会話だが。。。)

客:このハマチは日本海側でとれたの?
店員:つやがいいでしょう?たくさん餌を食べた証拠です。ひとつどうですか奥さん。
客:そうねえ、ひとついただこうかしら。

この文章を見ておかしいと思わない人はアウトーーーーッ!!である。「だって普通の日常会話じゃこんなのよくあるだろ?」と思われるかも知れない。確かにその通りなのだが、そもそも日常会話自体が論理的ではない。論理的なコミュニケーションをする上で、日常会話の常識は邪魔なのである。この質問では、お客さんは日本海側で取れたのかどうかということを聞いているのだから、論理的に回答しようとするならばYesかNo、つまり「はい」か「いいえ」以外の答えしかあり得ないのである。サポートの仕事では、この形式の質問として次のようなものを多く見かける。

xxxxxxがxxxxxxという動作をするのは仕様ですか?
xxxxxが起きた原因はxxxxxですか?
xxxxxでxxxxxという操作をすることは可能ですか?

因みに、今話題の仕分け人が放った質問「1位じゃなきゃダメなんですか?」というのもYes/No質問である。

この形式の質問では、まずYesかNoではっきりと回答すること!言い回しは何でもいい(例:おっしゃる通りですetc)のだが、まずはYesかNoの意思表示が重要なのである。

ただし、Yes/No質問には一つ注意しなければいけない罠がある。それは、例えば答えがYesだったとき、「はい」だけ回答しただけではいけないということである。

例えば、

> xxxxxが起きた原因はxxxxxですか?
はい、そうです。

というようなメールを送ったとしたら、相手は「なんて不親切なサポートなんだろう」と思ってしまう。何故ならば、相手は暗黙的にさらにその回答に対してコメントを求めていることが多いからである。上記の「xxxxxが起きた原因はxxxxxですか?」というような質問では、相手はその裏付けとなる根拠を説明して貰いたいと思っている場合がほとんどであり、その暗黙的な質問に対しても回答しなければ相手を満足させることは出来ない。このように、額面の裏に隠された質問を察することが、Yes/No質問では大事なのである。

もう一つ注意点としては、相手の質問に対してYesかNoで答えることが不可能な場合がある。例えば、

MySQLはPostgreSQLよりも高速ですか?

と聞かれてもYesかNoでは答えられないだろう。このような場合には、「一概に言えない」とか「場合による」といった回答が相応しい。ただし、この場合ももちろんその根拠をコメントすることを忘れてはならない。

5W1Hの質問

5W1Hとはつまり、Who(誰が) What(何を) When(いつ) Where(どこで) Why(どうして)How(どのように)したのか、という形式の質問である。勘の良い方なら、5W1Hに対してどのように回答すれば論理的な回答になるかということがおわかりだろう。そう、聞かれたことに回答すれば良いのである。5W1Hを聞かれたら、まずはその対象を答えるべきなのだ。次は夫婦の会話だが、夫はちゃんと妻の質問に答えていない。
妻:今日は何時に帰ってくるの?
夫:ちょっと取引先の人と会ってくるよ。

この場合、夫は帰宅時刻のおおよその見積もり(When)を答えなければならないはずであるが、取引先の人と会うという事柄(What)について述べているのでこれは論理的ではない。「取引先の人と会うから遅くなるということを察しろ」という意見があるかも知れない。それは確かに日常会話ではそれは通じる場合が多いのだが、論理的なコミュニケーションではそのようなやり取りは相応しくないということを理解して貰いたいのである。

サポートで見かける5W1H質問には、例えば次のようなものがある。
xxxxという操作をするためのコマンドは何ですか?(What)
xxxxがクラッシュした原因は何ですか?(Why)
このエラーはいつの時点から発生していたのでしょうか?(When)
この状態から復旧するにはどのようにすれば良いのでしょうか?(How)

ちなみに、WhoやWhereを聞かれることはあまりない。例えば「誰が作業をしたのか?」などという質問をされても、サポートサイドでは回答出来ない(ということをお客さんも当然知っている)からである。

5W1Hの場合は、Yes/No質問のように暗黙的な隠れた質問があることは少ない。質問者はダイレクトに自分の疑問を聞いている場合が多く、聞かれたことを全力で説明すれば良いというわけである。

それ以外の質問

3つのパターンの中で最も答えるのが難しいのが、Yes/Noにも5W1Hにも当てはまらない質問である。漠然としたことについて意見を求めるようなケースである。この手の質問としては、例えば次のようなものがある。

MySQL Clusterについて教えて下さい。
バイナリログの仕組みを教えて下さい。
MySQLをバックアップするにはどうすればいいでしょうか。
データベースのパフォーマンスチューニングはどのようにすれば良いのでしょうか。

このような質問をしてくる背景として、お客さんが何かを知りたいのだがどこから聞いて良いのか掴み切れていないという状況が多い。このような質問をされると、

オーケー。じゃあまず何から話そうか。

ということになってしまう。何を回答するかは回答者次第、言ってみれば自由なのだ。自由だから何でも書いて良いというわけではない。質問者を満足させる回答でなければならないので、正直言ってこれが一番回答に困る質問の形式であると言えよう。だからこそ腕の見せ所であると言える。

ここで注意しなければいけないのは、「マニュアル嫁」という味も糞もミソもカンガルーもない反応をしてしまうことである。確かにそれは真理である場合もあるのだが、そのような回答は英語では「RTFM=Read The F@cking Manual」として揶揄されるよくない対応である。サポートエンジニアたるもの、努々RTFM的な回答をするなかれ。なんたってお金を頂いているわけだから。

ではRTFMの代わりにどのような回答をすれば良いのだろうか。このような質問をしてくる質問者は、たいてい質問している内容についてあまり詳しくない場合が多い。そんな質問者は質問している対象を1〜100まで全部知りたいわけでなく、その概要を知りたがっていると見なすべきである。従って、この手の「漠然とした質問」に対しては一般的な見解をすっきり短くまとめるのが良い。つまり、ここでは「要約して説明する」というスキルが求められるのである。要約した回答を送った上で、質問者がさらに詳しく知りたいと思ったならばさらに質問が送られてくることになるが、追加質問についてもこれまでに紹介した3パターンに当てはめあらた回答すれば良いだろう。

ただ、人に何かを要約して説明するというのは、仕事には欠かせないにも関わらず非常に難しい高度なスキルである。しかもそのスキルの追求には終わりがなく、如何に分かり易い文章を書くかということは文章を書く者全てにとっての永遠のテーマであると言えるだろう。自由なフォーマットで相手に何かを要領よく説明する場合、文章全体の構成をどのようにするか、説明する内容をどこに絞るかということが重要だとよく言われる。つまり、相手が知りたがっている情報を効果的に提供することが大事なのである。

サポートの場合、相手の立場を考えた上で必要な情報を提供するには次のポイントが大事である。

一、ユーザーの運用を理解する。

この手の「一般的な質問」をする場合、質問者は間違いなくその機能が質問者の環境でどのように利用出来るかどうかということを検討していると言って良い。従って、運用者の立場、即ちユーザーの利用シーンを考えることが重要なのである。例えばMySQL Clusterの場合、高可用性や運用方法などが、質問者の目的に合っているかどうかということを判断したいわけだ。

一、技術(製品)についてよく理解する。

回答する対象の技術や製品について詳しく研究しておくことがとても重要である。つまり、ネタ帳の中身が詰まっていないと良いネタが出てこないということである。対象の製品について、日々研究することもやはり大事なのである。

一、よく聞かれる質問についてはテンプレートとしてまとめておく。

毎回同じ文章を書いても良いが、毎回同じ回答になるような質問についてはテンプレート化しておくと便利である。テンプレートを作っておくのは効率が良いし、何よりそのテンプレートを随時更新することによって回答の品質が高まっていくことになるからだ。手間はRTFM的な回答をする場合と比べてそれほど増えないにも関わらず、質問者に対する印象は180℃違うことになるので非常にお得である。

ここではカスタマーサポートにおいて「漠然とした質問」に回答する際に役立つポイントについて紹介したが、この形式の質問に対する回答の質を高めるには、とにかく書いて書いて練習するのが最も重要であるということを付け加えておく。

まとめ

というわけで、質問には3つの形式があって、それぞれの形式に合った方法で回答しなければいけない。その3つの形式とは、
  • Yes/No質問
  • 5W1Hの質問
  • それ以外の(漠然とした)質問
である。それぞれ聞かれたことに対して回答する際の注意点については上で述べた通りである。くれぐれもRTFM的な回答をしてはならない。この法則に当てはめて確認すれば、書いた文章が論理的であるかどうかを判断することが出来るだろう。論理的なコミュニケーションを行うのは易しいことではないが、文章の論理性を高めて建設的な意見交換をする一助になれば幸いである。

2009-12-02

特定のデータベースだけをmysqldumpで作成したダンプファイルから抜き出すawkスクリプト

タイトルのまんまのプチトリビアを紹介しようと思う。mysqlの--one-databaseオプションを使えば「mysqldumpで--all-databasesとか--databasesオプションを使って作成したダンプファイルに含まれる複数のデータベースから、一つのデータベースだけを選択してリストアする」という操作ができるけど、毎回ダンプファイル全体を読み込むのは無駄じゃないか?と思われることもあるだろう。だったら事前にダンプファイルを分けちゃいたい!と考えるのが人情というもの。そんなときはawkコマンドを使うといい。
#!/usr/bin/awk -f

BEGIN {
  dump_current_db = 0;
  num_db = split(databases, db_arr, ",")
  for (i = 1; i <= num_db; i++) {
    db_arr[i] = "`" db_arr[i] "`";
  }
}

/^\-\-/ {
  print $0;
  if ($2 == "Current" && $3 == "Database:") {
    dump_current_db = 0;
    for (i = 1; i <= num_db; i++) {
      if ($4 == db_arr[i]) {
        dump_current_db = 1;
        break;
      }
    }
  }
}

/^\/\*.+\*\/;/ { print $0 }

/^$/ { print $0 }

/^[^\-]/ { if (dump_current_db == 1) print $0 }
このawkスクリプトを例えばcut-database.awkとかに保存して、
shell> ./cut-database -v databases=db1,db2,db3... < dump.sql > sub_dump.sql
てな具合にコマンドを起動すれば、目的のデータベースだけを含んだダンプファイルがいっちょあがり。 そもそもmysqldumpコマンドでダンプするときにファイルを分ければ?なんて考える人も居るかも知れないけど、それは出来ない相談だったりする。ロールフォワードリカバリとかを考えてバイナリログと同期をとっておかないといけなかったりするし、そもそもデータベースが複数あるときにはデータベース間でデータが同期していないといけない。ところがデータベースを個別にダンプするとロールフォワードリカバリが出来ないどころか、データが使い物にならないことになってしまう。よって--all-databasesとか--databasesの利用は必須なのである。 そこでもう一つ紹介するのが、mysqldumpコマンドの出力をそのまま別々のファイルに保存するawkスクリプト。
#!/usr/bin/awk -f

function is_new_db(db_name) {
  for (i = 1; i <= num_db; i++) {
    if (db_name == db[i]) {
      return 0;
    }
  }
  return 1;
}

BEGIN {
  num_db = 0
  num_prelines = 0
  num_postlines = 0
  current_file = "/dev/null"
}

/^\-\-/ {
  if ($2 == "Current" && $3 == "Database:") {
    close(current_file);
    db_name = $4
    gsub("`", "", db_name);
    current_file = db_name ".sql";
    if (is_new_db(db_name)) {
      db[++num_db] = db_name;
      print "--\n" $0 "\n--\n" > current_file;
      for (i = 1; i <= num_prelines; i++)
        print prelines[i] >> current_file;
    }
  } else if (num_db == 0) {
    num_prelines++;
    prelines[num_prelines] = $0;
  } else if ($2 == "Dump" && $3 == "completed") {
    num_postlines++;
    postlines[num_postlines] = "";
    num_postlines++;
    postlines[num_postlines] = $0;
  } else {
    print $0 >> current_file
  }
  next;
}

/^\/\*.+\*\/;/ {
  if (match($0, "character|collation")) {
    print $0 >> current_file;
  } else if (match($0, "SET")) {
    if (num_db == 0) {
      if (match(prelines[num_prelines], "^\-\-")) {
        num_prelines++;
        prelines[num_prelines] = "";
      }
      num_prelines++;
      prelines[num_prelines] = $0;
    } else {
      num_postlines++;
      postlines[num_postlines] = $0;
    }
  } else {
    print $0 >> current_file;
  }
  next;
}

{ print $0 >> current_file }

END {
  for (i = 1; i <= num_db; i++) {
    current_file = db[i] ".sql";
    print "" >> current_file
    for (j = 1; j <= num_postlines; j++) {
      print postlines[j] >> current_file;
    }
  }
}
このスクリプトを例えばseparate-dump.awkというファイルに保存して実行権限を与えてやれば、
shell> mysqldump -A --single-transaction --master-data=2 --flush-logs | ./separate-dump.awk
という具合にこのコマンドを使うことができる。そうするとカレントディレクトリに「データベース名.sql」というファイルにダンプが分けられて保存されるという寸法。DB数が多い場合は"Too many open files”エラーが出てしまうので注意すること。(色々直しました。) もちろん既存のダンプファイルを分けることも可能。
shell> ./separate-dump.awk < dump.sql

なお、このスクリプトの利用は自己責任でお願いします。ライセンスはGPLv3で。何か不具合等があれば直して使って下さい。

2009-11-04

MySQL Clusterが苦手とするJOINを如何にして克服するべきか。

シェアードナッシング型の負荷分散機能を持ち、なおかつ同期レプリケーションによるHA機能まで備えたMySQL Cluster最大の弱点といえば、JOINの遅さであろう。MySQL ClusterのJOINは偽りなく遅い。JOINを多用するアプリケーションでMySQL Clusterを利用するのはある意味マゾヒスティックな行為であると言えよう。何故MySQL ClusterはJOINが遅いのか?それはMySQL Clusterが分散データベースだからである。

ご存じの通り、MySQLにおけるJOINのアルゴリズムにはNested Loopしかない。他のストレージエンジンを利用していればそれでも十分実用に耐えうるぐらい高速なのだが、MySQL Clusterの場合はそうはいかない。JOINでは自ずとストレージエンジンからデータをフェッチする回数が増えるが、MySQL Clusterの場合レコードのフェッチはネットワークを経由しなければいけないのでここがボトルネックになってしまう。

例えば、2つのNDBストレージエンジン(MySQL Cluster)のテーブルをJOINする場合を考えよう。外部表からM行フェッチし、外部表の一行につき内部表から平均でN行フェッチする必要があるとする。その場合、外部表から1回(1回のスキャンオペレーションでデータをフェッチできる)、内部表からM回のフェッチをしなければならない。1回のフェッチにつき、ネットワーク上をパケットが往復するわけであるから、InnoDBやMyISAMのように同一ホストから(特にメモリ上のキャッシュから)データをフェッチする場合と比べてJOINは不利なのである。

ではMySQL ClusterにおいてJOINを高速化するにはどうすればいいだろうか?

単純に「ネットワーク接続を高速化すればいいじゃないか。10GbEのNICを使えば?」などと思うかも知れない。それはある意味正しいが、正しいアプローチではないと思う。確かにJOINの性能は向上するのだが、10GbEとてレイテンシは無視できないので同一ホスト上のメモリからデータをフェッチする場合より遅いのは明らかである。

少し話はそれるが、何かを処理するユニットを増強して(もしくはたくさん並べて)何とかしてしまおうというのは、いかにもBruteなやり方である。確かにハードウェアの性能向上はBruteなやり方でも良いと思うし、Bruteなやり方で成功した事例もたくさんある。例えばグラフィックスチップにたくさんの演算回路(シェーダ)を組み込んだり、ハイエンドサーバにCPUを満載したり、安価なマシンを並べてスケールアウトしたり。しかし、Bruteなアプローチではシステムの性能の限界はハードウェアの性能の限界によって頭打ちしてしまうことになる。だが一方で、ソフトウェアの性能向上を考える場合には、同じ条件のハードウェアで如何に高速化するかということを検討しなければならないと思う。つまり、もっとSmartなやり方でないといけない。ハードウェアはBruteに。ソフトウェアはSmartに。それがシステムを高速化する際のコツだろう。

そんなわけで話は戻るが、つまり単純にネットワーク接続を高速化するのは、一定の効果は上がるがすぐに限界を迎えてしまう可能性が高いのである。

現時点でも実装可能かつスマートなアプローチは、レプリケーションを利用することである。Kaj Arno氏のエントリでも紹介されているが、MySQL Clusterから通常のMySQL Serverへのレプリケーションを行い、JOINを伴う複雑なSELECTに関してはスレーブで実行することにより、複雑なSELECTを高速化するというテクニックが存在する。(詳細はKaj氏のブログエントリの図を参照して頂きたい。)スレーブへのレプリケーションは非同期なので、厳密な最新のデータに対するクエリは実行出来ないが、厳密な最新のデータが必要ない場合この方法は大抵うまくいく。システムの構築がちょっと面倒臭くなる以外弊害もない。複雑なクエリは集計データなどに利用されることが多いので、適用出来るシーンも多いだろう。

この方法で気をつけるべきポイントは、replicate[-wild]-do-tablereplicate[-wild]-ignore-tableオプションを利用して、複製するテーブルを限定することである。そうしないとndb_apply_statusテーブルへの更新が出来ないというエラーに見舞われてしまうことになる。MySQL Clusterテーブルを更新すると、バイナリログは自動的にmysql.ndb_apply_statusテーブルへの更新が含まれてしまう。このテーブルはNDBストレージエンジンで定義されているテーブルでMySQL Cluster同士のレプリケーションに利用されるのだが、MySQL Clusterから通常のMySQL Serverへレプリケーションする場合には不要などころかエラーの元凶になるだけなのできっちりとフィルタリングしておこう。例えば、worldデータベースに存在するテーブルだけを対象にしたい場合は、スレーブのmy.cnfに次のようにreplicate-wild-do-tableを使って記述するといいだろう。

[mysqld]
replicate-wild-do-table=world.%

MySQL ClusterのSQLノード上で新規にテーブルを作成する場合、つまりCREATE TABLE tbl(...) ENGINE NDB;とした場合に、スレーブ側ではデフォルトのストレージエンジンが使用されることになる点にも注意したい。(通常のMySQL ServerにはNDBストレージエンジンは含まれていないからだ。)--storage-engineオプションを好みのもの(InnoDB等)に設定しておこう。

しかし、MySQL Clusterの開発者たちは、JOINが遅いという現状をいつまでも放置しておくつもりはない。

将来的にはMySQL ClusterのJOIN性能は大幅に改善される予定である。まず、近い将来に搭載される機能として挙げられるのがBKA(Batched Key Access)というJOIN最適化手法である。この方法では、これまで1+M回必要だったデータのフェッチが、最も効率的な場合にはたったの2回にまで減少する。2つのNDBテーブルのJOINにおいて外部表からM行フェッチし、外部表の一行につき内部表から平均でN行フェッチする必要がある場合、BKAの動作は次のようになる。
  1. 外部表からM行フェッチ(一回のスキャン)
  2. JOINに利用するキーの値をリストアップする。
  3. リストアップされたキーをNDBストレージエンジンにPush-Downする。
  4. 内部表からN行フェッチ(一回のスキャン)
内部表からレコードをフェッチする際、ICT(Index Condition Pushdown)という機能が利用されるのだが、ICTではストレージエンジンに対してフェッチしたい行を含むキーを一気に送信し、レコードを一気にフェッチするのである。その結果、MySQL Clusterではネットワーク上のパケット往復の回数が劇的に減少し、JOINの性能が向上するというわけだ。従って、BKAが実装された暁には、通常のMySQL Serverへレプリケーションするといった面倒な運用は一切不要になるだろう。少なくとも他のストレージエンジンと同等程度までJOINの性能が改善するはずであるから。

BKAブラボー!!と思うかも知れない。
しかし、そんなところで終わるようなMySQL Cluster開発チームではないのである!!

実装されるのはかなり先になるだろうが、MySQL ClusterのJOINを劇的に高速化することが出来ると予想される機能が実装される見込みである。それはDbspjと呼ばれる機能であり、言うなれば「分散JOIN」とでも呼ぶべきシロモノである。かなり貪欲な性能の追求である。MySQL Clusterは分散型のRDBMSであるから、JOINの処理も分散して行えば良いじゃないかと考えるのが人情というもであるが、一方でそのような機能を実装するのは難しいということもまた事実である。(従って現時点ではそのような機能は実装されていない。)しかし難しいというのを理由にして諦めないのが真の漢。MySQL Cluster開発チームはこの難題にチャレンジしており、既に初期段階のテスト結果が開発者Jonas Oreland氏のブログで公表されている。ぶっちゃけ通常のJOINと比べると格段に速い。MySQL Clusterの正式リリースに搭載されるのはずっと先になるだろうが、楽しみな機能の一つである。

2009-11-02

GPLソフトウェアのパッチをBSDライセンスで提供することの意義

先日の投稿「GPLが適用されているソフトウェア=MySQLのパッチをBSDライセンスでリリースする。では、GPLが適用されているソフトウェアにBSDライセンスのパッチを提供することが出来るということを書いた。ただし、それが出来ることによってどのような意義があるのかということについては触れていなかった。その結果、
単独で動かないパッチに元のと違うライセンスをつける感覚がよくわからない。
という疑問が生じたらしい(ブコメ参照)ので、パッチをBSDライセンスで提供するということはどういうことなのかを説明しようと思う。

まず第一に、パッチ自身はBSDライセンスなので、BSDライセンスに従う限り他のプログラムへ流用することが出来る。
パッチといえども、それが何かの機能を追加する類のものであれば巨大なプログラムになり得るだろう。事実、Googleが提供するMySQLのパッチもかなりデカイ。パッチの規模がでかくなれば、独立して機能する有益なロジックが多々含まれることになるだろう。パッチのライセンスがBSDライセンスであれば、その機能をGPL以外のライセンスのソフトウェア、例えばBSDライセンスのPostgreSQLなどに追加するということも可能である。つまり、パッチをBSDライセンスにすることで、MySQLとPostgreSQLに同じ機能を追加するということが出来るわけだ。

第二に、
MySQLはデュアルライセンスなので、BSDライセンスで提供されたパッチであればGPL版とコマーシャルライセンス版の両方に機能を追加することが出来る。従って、BSDライセンスのパッチはMySQLにとっては都合が良いのである。(MySQLがデュアルライセンスを貫く以上、GPLで提供されたパッチは適用出来ないのである。)

ちなみに、GPLソフトウェアであるMySQL 6.0からforkしたDrizzleも、
全てのContributionはBSDライセンスのもとに行われている。(Drizzleに提供された全てのソースコードはBSDライセンスが適用されている。)従って、Drizzleに追加された全ての機能は、GPL版、コマーシャルライセンス版のいずれのMySQLにも取り込むことが出来るのである。また、DrizzleにContributeされたコードは、PostgreSQLなどの他のライセンスのRDBMSソフトウェアにも取り込むことが出来るので、PostgreSQLerの人は是非Drizzleのソースコードを覗いて見ると良いのではないだろうか。ただし、Drizzleでは積極的に外部のライブラリを取り込んで利用しようという方針があるので、外部のGPLが適用されたライブラリに依存した機能については、BSDライセンスによる利用は出来ない点には注意が必要である。(もちろん元のMySQL 6.0から残っているコードはPostgreSQLに取り込むことは出来ないので注意しよう。)

さて、ここまで書くと「GPLよりBSDライセンスの方が優れている」ということを言い出す人が居るかも知れないので、この点について少し捕捉しておく。
GPLとBSDライセンスを比較するのはハッキリ言って無意味である。確かにBSDライセンスの方が再利用出来るソフトウェアの範囲が広い。(商用、無償、プロプラエタリ、OSSを問わず利用可能である。)しかし一方で、GPLはソフトウェアの利用者に(それをカスタマイズすることを含めて)未来永劫最大限の自由を約束するライセンスであり、GPLを継承することによって再利用可能な場面が限定されることは、その自由を約束するために必要な措置なのである。つまり、GPLとBSDライセンスはそれぞれ異なる属性を持ったライセンス(かたやCopyleft、かたやPermissive)であり、それぞれのライセンスを適切に使い分けるのが重要だということである。ライセンスに対する理解とそれらの使い分けは、オープンソースに生きる人々にとっては最も重要な嗜みと言えるだろう。

2009-10-30

GPLが適用されているソフトウェア=MySQLのパッチをBSDライセンスでリリースする。

Googleがリリースしている有名なMySQL 5.0用パッチは、なんとBSDライセンスで提供されている。MySQLは周知の通りGPLでリリースされているが、GPLソフトウェアはその性質上、改変するとそのソフトウェアもGPLでリリースしなければいけない。だったら何故そのパッチをBSDライセンスで提供することが出来るのか?!ホントにそんなこと出来るのか?!Googleは何か間違ってるんじゃないか?!などと疑問に思われることだろう。

結論から言うと、Googleは何らライセンスの間違いを犯しているわけではなく、GPLソフトウェアにGPL互換のライセンスでパッチを書くことが出来るのは、GPLの条文そのものにしっかりと書いてあるのである。

以下、GPLv2の日本語訳より抜粋。
以上の必要条件は全体としての改変された著作物に適用される。著作物の一部が『プログラム』から派生したものではないと確認でき、それら自身別の独立 した著作物であると合理的に考えられるならば、あなたがそれらを別の著作物として分けて頒布する場合、そういった部分にはこの契約書とその条件は適用されない。しかし、あなたが同じ部分を『プログラム』を基にした著作物全体の一部として頒布するならば、全体としての頒布物は、この契約書が課す条件 に従わなければならない。というのは、この契約書が他の契約者に与える許可は『プログラム』丸ごと全体に及び、誰が書いたかは関係なく各部分のすべてを保護するからである。 よって、すべてあなたによって書かれた著作物に対し、権利を主張したりあなたの権利に異議を申し立てることはこの節の意図するところではない。むしろ、その趣旨は『プログラム』を基にした派生物ないし集合著作物の頒布を管理す る権利を行使するということにある。

つまり、パッチとしてオリジナルのGPLソフトウェアから完全に切り離された部分に関しては、GPLが適用されないわけである。ただし、そのパッチをGPLソフトウェアに適用するためには、そのパッチはGPL互換のライセンス(例えばBSDライセンスなど)でリリースしなければならない。そして、それをオリジナルのGPLソフトウェアと合体した時点でGPLが適用される。つまり、

GPLソフトウェア + BSDLパッチ = 改変されたGPLソフトウェア

という関係が成り立つわけである。従って、件のGoogleパッチがBSDLでリリースされているのは、一切問題はないというわけであり、Googleパッチに含まれるソースコードはBSDライセンスで利用することが可能である。

なぜ上記のような条項がGPLに盛り込まれているのか?と疑問を持たれることだろう。もし上記の条項がなければ、全ての変更はGPLを適用したソフトウェアで行わなければならず、従って他のライセンスでリリースされた優秀なソフトウェアやライブラリをGPLソフトウェアと組み合わせて利用することが出来ないという事態になってしまう。例えそれがFSFが作成した他のライセンス、例えばLGPLなどを適用したソフトウェアであっても!である。上記の条項があれば、ライセンス上は安全に他のGPL互換のライセンス(BSDライセンスなど)のソフトウェアとGPLライセンスのソフトウェアを組み合わせて別のソフトウェアを開発することが可能になる。

まったくもってややこしい話であるが、オープンソースソフトウェアに携わる人間としてライセンスの組み合わせは避けて通ることが出来ない問題であり、数あるオープンソースライセンスの中でも最もシェアが多いのはGPLなので、GPLの互換性に関する知識は身につけておく必要があるだろう。GPLが嫌いな人は「GPL汚染」などと揶揄してとかくGPLソフトウェアに対して脊髄反射的な嫌悪を示すことが多いのだが、それはきっと未知なるものに畏怖の念を抱くのは人間の性だからであり、しっかりライセンスを読んでよく理解すれば何も恐れる必要はないのである。

2009-10-28

MySQLerのTwitterアカウントまとめ。

松信氏の、

MyISAMとInnoDBのどちらを使うべきか
Twitterで話題になってたので簡単にまとめました。

というエントリが人気を博しているが、松信氏が言うように最近はTwitterでMySQL関連の話題も結構増えてきているように思う。Twitterの流行の勢いは凄まじく、今は右を向いても左を向いてもTwitter、寝ても覚めてもTwitter、猫も杓子もTwitterという雰囲気である。従ってMySQLもTwitterで盛り上がるのは当然の成り行きというもであるし、Twitterを活用しない手はない。

しかしMySQL関連の話で盛り上がると言っても「じゃあ誰をフォローすれば話に入れるんだよ?!」と多くの皆さんは疑問に思われることだろう。そこで、今日はMySQL関連のTwitterアカウントを独断と偏見と愛と勇気と努力をもって紹介する。MySQLの情報が欲しい人、もしくは話題の輪に入ってみたい人はぜひフォローして頂きたい。

まずはオフィシャルなアカウント関係から。オフィシャルなアカウントメッセージを一方的に発信するだけなので、話題に入るのではなく、情報源として、つまりRT(Re−Tweet)の対象として活用して頂きたい。

@mysql

基本中の基本。新しいリリースやWebinarの告知などが行われる。特にバージョンアップによる新機能の追加は、話のネタには持ってこいなのでMySQLerは必ずフォローしよう。

@mysql_jp

MySQL公式日本語アカウント。国内で行われるイベントやセミナーの告知とかがされる模様。2009年11月13日オープン!

@planetmysql_jp

こちらもMySQLerフォロー必須のアカウントである。コレはPlanet MySQL日本語版のフィードを呟くボットアカウントで、Planet MySQL日本語版に登録されているブログに記事が投稿される度にフィードを読み取って呟いてくれる。ブログ記事にツッコミを入れたりコメントしたり友人に広めたりするのに持ってこいだろう。

なお、MySQL関連のブログを書いている人は是非Planet MySQLに登録しよう。ブログは見る人が居てナンボであるが、Planet MySQLに登録することでより多くの人に見て貰える機会が増えるからである。MySQLブロガーがPlanet MySQLに登録し、MySQLer全員がそのRSSを購読したり@planetmysql_jpをフォローすれば品質の高い情報交換が出来るようになるだろう。

関連リンク

@planetmysql

こちらはPlanet MySQL英語版のボットアカウントである。英語が堪能なら是非こちらのアカウントもフォローしよう。英語圏におけるMySQLブログ記事の投稿数は相当なものであり、非常に質の高い情報が飛び交っている。英語の練習にもどうぞ。

関連リンク

では続いて日本人MySQLerのアカウントを紹介しよう。友好的な人が多いので、気軽にフォローして突っ込んでみて頂きたい。

@tmtms

言わずと知れたとみた まさひろ氏。MyNAの会長にして日本最古参MySQLerのひとり。MySQL徹底入門の著者、MySQLにおける日本語文字コードの初期実装、なおかつ超^128重要なモジュールであるMySQL/Rubyの開発者としても知られる偉人である。(しかし本人は奇策・・・もとい気さくなひと)Rubykaigi 2009では「MySQL/Ruby終了のお知らせ」という楽しいプレゼンをして話題を呼んだ。これからはPure-Ruby実装であるRuby/MySQLを継続されるそうなので頑張って頂きたい。


関連リンク

@sakaik

MyNAのMLでおなじみの坂井氏。MySQL 徹底入門 第2版や、その他数多くのMySQL関連書籍の共著者として知られる。

関連リンク

@ikdttr

MySQLにおいて日本語フルテキストインデックスを使った検索を可能とする「Sennaストレージエンジン」の開発者である池田氏。最近はMySQL 5.1対応版の開発に忙しいらしい。早くでないかと心待ちにする毎日である。池田氏をフォローしたら「リリースマダー?」と呟くのを忘れてはならない。

関連リンク

@hirohama

日本におけるMySQL Clusterの第一人者にして実力者の廣濱氏。カメラ好き、ガジェット好き、女好き^H^H^H^H。MySQL Clusterについて語ることの出来る貴重な人材である。

関連リンク

@kazuho

天才エンジニアとして国際的な評価も高いサイボウズ・ラボの奥一穂氏。Q4Mストレージエンジン、Pacificドライバなど秀逸なソフトウェアを世に送り出している。ツッコミも的確で示唆的である。しかしそれでいて茶目っ気を忘れないというのが心憎い。

関連リンク

@yonekawa

サイボウズ株式会社の米川氏。サイボウズはMySQLを利用するプロプラエタリソフトウェアの代表格である。

関連リンク

@sh2nd

OracleおよびInnoDBのエキスパート平塚氏。ブログでは度々気合いの入ったベンチマークなどをしてくれるのでwktk度高し。Rethink DBを真っ先に試すなど、人柱としても秀逸である。

関連リンク

@kentokushiba

スパイダーマンこと斯波氏。SPIDERストレージエンジンの開発者として有名である。最近はVertical Partitioningエンジン(カラムごとにパーティショニングをするタイプのストレージエンジン)の開発も精力的に行っている。

関連リンク

@kazeburo

大規模分散野郎Aチーム。Mixiの長野氏。Mixiのインフラを支える職人的DBAである。

関連リンク

@tmaesaka

Mixiの前坂氏。Drizzleやmemcachedなどのプロジェクトにおいて精力的に活動している。長きにわたりニュージーランドに在住しているため英語はペラペラである。最近はTokyo Cabinetにデータを格納するDrizzle用ストレージエンジンであるBlitzDBの開発に勤しんでいる。

関連リンク

@stanaka

とあるはてな社員こと田中氏。はてなを果てしなくスケーリング(注:ダジャレではありません。)

関連リンク

@tokuhirom

えとらぼ松野氏。だまってコードを書く人。

関連リンク

@hirose31

えとらぼのひろせまさあき氏。ブログのネタはいつも秀逸。

関連リンク

@ichii386


GREEの一井氏。InnoDBラブなMySQLerが多い中で異色のMyISAMラヴ!!な逸材。一井氏曰く、分析計の処理にはMyISAMの取り回しの手軽さが便利とのこと。


関連リンク



お次はMySQLの中の人。まずは日本人から。

@matsunobu

言わずと知れたMySQLのコンサルタント松信氏。数多くの書籍を執筆し、印税でウハウハしているMySQLの普及に大きく貢献している。最近受けたOkyuu.comのインタビュー記事では、「夢はエンジニアに強い影響を与える本を書くこと」と述べているのは感心する志である。この調子でこれからも頑張って頂きたい。

関連リンク


@rkajiyama

トレーナーから技術支援まで幅広くこなすタフガイ梶山氏。日本語の(Webを含む)セミナーやイベントではまず梶山氏が登場するので、ご存じの方も多いのではないだろうか。APAC地域担当であるため、かなりの期間を海外で過ごしている。

@meijik

同じMySQLサポートエンジニアにしてキムラデービー代表の木村氏。カレーが大好きで、ランチはカレー率が非常に高い。ブログにもカレーの記事が満載である。たまにDB Magazine等の雑誌に記事を投稿している。また、OSS RDBMSとしてはMySQLだけでなくFirebird関連の活動も活発に行っている。現在Firebird(徹底)入門書籍執筆中。

関連リンク


@nippondanji

いわゆる。フォロー歓迎。


続いて英語圏の中の人たち。英語が堪能ならぜひフォローを。

@brianaker

OSSの申し子Brian Aker氏。MySQLの各種ストレージエンジン(FEDERATED、ARCHIVE、Blackhole)、memcached、Drizzle、Gearmanなど、様々な実績を残している天才プログラマである。使用しているエディタはvim。MySQLに入社する条件として「絶対にノベルティのTシャツは着ない」というものを提示した頑固者。彼の語り口は非常にマイルドで、それでいて常に論理的である。Aker氏は尊子Richard Stallmanとディベートを行ったのだが、尊子よりも主張が論理的ですらあるように感じてしまうから驚きである。俺は二人とも大好きだ!

関連リンク

@stewartsmith

元MySQL Clusterの開発者にして、Drizzleの開発者Stewart Smith氏。写真ではオッサンっぽく見える場合もあるが実は結構若い。もちろん技術的にはエキスパートであり、彼のブログでは度々参考になる情報が掲載されているから見逃せない。

関連リンク

@kajarno

MySQLコミュニティ担当副社長のKaj Arno氏。MySQLのスポークスパーソン的存在。MySQL ABがコミュニティと良好な関係を保ってこられたのは彼の功績によるところが大きい。Bad Newsを魔法のようにGood Newsに変えるともっぱらの噂である。

関連リンク

@datacharmer

MySQLコミュニティ担当のGiuseppe Maxia氏。Datacharmerというのは彼のニックネーム。ジュゼッペ氏はMySQL::Sandboxの作者としても知られる。MySQL::Sandboxは相当便利なので使うべし!

関連リンク

@LenzGr

同じくMySQLコミュニティ担当のLenz Grimmer氏。Planet MySQLを管理しているのは彼である。


さらに中の人を紹介するが、以下はサポートチームの面々である。詳しい説明は省略する。

@maximuscub

俺の上司のLachlan。若くてマッチョなオーストラリア人。

@adamtdixon

APAC地区でMySQL Clusterを担当しているAdam。

@geertjanvdk

EMEA地区でMySQL Clusterを担当しているGeert。

@lathiat

見たまんまギークなTrent。かなりの早口なので、脳をオーバークロックしている疑いが持たれている。

@garypendergast

長期休暇取得中のGary。今はイタリアを放浪しているらしい。しかし仕事はチョッパ。


以下はその他の英語圏のMySQL関連アカウント。

@jzawodn

誉れ高き名著「High Performance MySQL」の著者、Jeremy Zawodny氏。元米Yahoo!のDBA。MySQLのレプリケーションで参照系の負荷を分散できる!ということを、実際のシステムで証明して見せたのは彼が最初ではないだろうか。

関連リンク

@martenmickos

元MySQL ABのCEO、Marten Mickos氏。MySQLは技術者集団だが、Mickos氏は経営のプロ。惜しい人物を放出したものである。

@launchpad_net

MySQLの公開リポジトリをホスティングしているLaunchpadの公式アカウント。

関連リンク

@Kickfire

MySQLを用いたDWHアプライアンスを販売している米Kickfire社の公式アカウント。KickfireはDWH用のストレージエンジンであるが、興味深いのは「SQLチップ」なるものを用いた専用のハードウェアで動作するるところ。汎用CPUでは達成できない性能を叩き出す。

関連リンク

@webyog

MySQLのGUIを販売するWebyog社のアカウント。

関連リンク

@Percona

MySQL Performance Blogでお馴染みのPercona社のアカウント。InnoDBの達人である木下氏が所属する会社でもある。(木下氏はPercona社にてXtraDBやXtraBackupの開発に勤しんでいる。オトコ的には木下氏にも呟いて貰いたいところである。)

関連リンク

というわけで、思いつくままにMySQLerなTwitterアカウントを並べてみたが、是非皆さんも彼らをフォローしてみて頂きたい。データベースを開発や運用でどう上手に使いこなすかということは、システム屋ないしはWeb系のエンジニアにとって非常に重要な課題である。Twitterを活用して情報を仕入れたりディスカッションに参加したりして、ぜひスキルアップに役立てて貰いたいものである。ここに挙げたアカウントはほんの一部であることを断っておく。実際にはまだまだこんなものではなくもっと大勢の優秀なMySQLerが存在する。もし、「この人が抜けてるだろ!」とか「俺も載せろ!」という方がいらっしゃったら、Twitterで@nippondanjiへこっそりとダイレクトメッセージを送って頂きたい。

一家に一冊。あのオプションなんだっけ?と思った時のために備えて。- #書評_ - MySQL全機能バイブル

MySQL全機能バイブル ~現場で役立つAtoZ~著者鈴木啓修様より献本御礼。(←一度言ってみたかったw)

本書は鈴木氏の前著である「MySQL全機能リファレンス」からのアップデートであるが、この度は最新バージョンであるMySQL 5.1対応になっての登場である。

今の時代、一家に一台テレビがあるように、はたまたパソコンがあるように、いやいや冷蔵庫があるように、一家に一冊本書があってもいいのではなかろうか。MySQLがオフィシャルに提供しているリファレンスマニュアルを除いて、MySQLをここまで網羅的に解説している書籍を私は知らない。その網羅性は目次だけで13ページも費やしていることからも、容易に想像出来ることだろう。

もくじを見ただけでもその網羅性がよく分かるだろう。このもくじを書いただけで既に腕がつりそうである。

Chapter 01 イントロダクション
■■ 概要
1-01 MySQL™とは
1-02 MySQLの概要
1-03 データベースシステムの構造
1-04 ストレージエンジン
Chapter 02 MySQLの内部構造
■■ プロセスとメモリ構造
2-01 プロセス構造
2-02 メモリ構造
■■ 問い合わせ処理
2-03 問い合わせ処理
2-04 プランナ
2-05 MyISAMのエクゼキュータ処理
■■ データベースディレクトリの構造
2-06 データベースディレクトリの構造
■■ テーブルの構造
2-07 MyISAM型
2-08 InnoDB型
■■ トランザクションの隔離レベル
2-09 トランザクションの隔離レベル
■■ INSERT DELAYED文
2-10 INSERT DELAYED文
■■ クエリキャッシュ(Query Cache)
2-11 クエリキャッシュ(Query Cache)
Chapter 03 MySQLのインストール
3-01 インストール準備
3-02 インストール
Chapter 04 MySQLサーバ管理
■■ イントロダクション
4-01 MySQLサーバ管理
■■ 初期設定
4-02 初期設定
■■ サーバの起動/停止
4-03 MySQLサーバの起動と停止
4-04 MySQLサーバの起動
4-05 MySQLサーバの停止
4-06 MySQLサーバをデーモンとして起動する
■■ データベースユーザ管理
4-07 MySQLにおけるデータベースユーザの概念
4-08 データベースユーザの管理
■■ システム変数の設定
4-09 システム変数の設定
4-10 サーバの動作に関するシステム変数
4-11 通信関連のシステム変数
4-12 問い合わせ処理に関するシステム変数
4-13 ストレージエンジン関連のシステム変数
4-14 ログ関連のシステム変数
4-15 表示や文字コードに関連するシステム変数
4-16 SQL_MODE
4-17 レプリケーション関連のシステム変数
4-18 その他のシステム変数
■■ ストレージエンジン
4-19 MyISAM型
4-20 InnoDB型
4-21 MEMORY型(旧 HEAP型)
4-22 パーティション
■■ ログ
4-23 ログファイル
4-24 バイナリログ(binary log)
4-25 スロークエリのログ(slow query log)
4-26 一般クエリログ(general query log)
■■ データベースのダンプ/リストア
4-27 データベースのダンプ/リストア(再構築)
4-28 ファイル群のコピーによるダンプ/リストア
4-29 mysqldumpによるダンプ/リストア
■■ 管理ツール
4-30 mysqladminとは
4-31 データベースの作成/削除
4-32 サーバの情報表示
4-33 FLOSH/RELOAD
4-34 パスワードの変更
4-35 スレーブ機能の開始/停止
4-36 mysqlcheck
■■ 文字コード
4-37 MySQLのサポートする文字コード
4-38 文字コードの設定と確認
■■ レプリケーション
4-39 レプリケーションとは
4-40 MySQLにおけるレプリケーションの仕組み
4-41 レプリケーションの設定
4-42 運用/管理
■■ クエリキャッシュ
4-43 クエリキャッシュ(Query Cache)
Chapter 05 mysqlの使い方
■■ mysqlの使い方
5-01 mysqlの使い方
■■ mysqlの起動オプション
5-02 MySQLサーバとの接続と切断
5-03 表示と結果出力
5-04 バッチ処理とSQL文の実行
5-05 実行制御
■■ mysqlのメタコマンド
5-06 再接続と切断
5-07 表示の制御
5-08 バッチファイルの処理,および結果のファイル出力
5-09 SQL文の編集と表示
5-10 プロンプト
5-11 接続中のセッション情報を表示
Chapter 06 SQL
■■ SQL
6-01 SQL文一覧
6-02 語彙
■■ データベースの作成/削除/接続
6-03 データベースの作成 CREATE DATABASE
6-04 データベースの削除 DROP DATABASE
6-05 データベースの属性変更 ALTER DATABASE
6-06 データベースの一覧表示 SHOW DATABASES
6-07 データベースへの接続 USE
■■ テーブルの作成/削除
6-08 テーブルの作成 CREATE TABLE
6-09 テーブルの削除 DROP TABLE
■■ テーブルの情報表示
6-10 テーブル定義(テーブルスキーマ)の表示 SHOW CREATE TABLE
6-11 列の属性を表示 SHOW COLUMNS FROM/SHOW FIELDS FROM/DESCRIBE/DESC
6-12 テーブルの一覧表示 SHOW TABLES
6-13 テーブルの情報表示 SHOW TALBE STATUS
■■ テーブルの属性変更
6-14 テーブル属性の変更 ALTER TABLE
6-15 列の追加と削除 ALTER TABLE ADD COLUMN/ALTER TABLE DROP COLUMN
6-16 インデックスの追加と削除 ALTER TABLE ADD INDEX|CREATE INDEX/ALTER TABLE DROP INDEX|DROP INDEX
6-17 主キーの追加と削除 ALTER TABLE ADD PRIMARY KEY/ALTER TABLE DROP PRIMARY KEY
6-18 一意性制約の追加 ALTER TABLE ADD UNIQUE
6-19 外部キー制約の追加と削除 ALTER TABLE ADD FOREIGN KEY/ALTER TABLE DROP FOREIGN KEY
6-20 デフォルト値の設定と削除 ALTER TABLE ALTER SET DEFAULT/ALTER TABLE ALTER DROP DEFAULT
6-21 列定義、列名の変更 ALTER TABLE MODIFY COLUMN/ALTER TABLE CHANGE COLUMN
6-22 テーブル名の変更 ALTER TABLE RENAME
6-23 テーブル名の変更 RENAME TABLE
■■ データベースユーザの作成と削除
6-24 データベースユーザの作成と削除 CREATE USER/DROP USER
■■ データベースユーザの管理
6-25 データベースユーザの権限設定と削除 GRANT/REVOKE
6-26 データベースユーザの権限表示 SHOW GRANTS
■■ データの挿入
6-27 データの挿入 INSERT
6-28 データの挿入 REPLACE
■■ SELECT
6-29 データの検索 SELECT
6-30 重複する行を削除 DISTINCT
6-31 FROM句
6-32 テーブル結合 CROSS JOIN/INNER JOIN/OUTER JOIN
6-33 WHERE句
6-34 グループ化 GROUP BY, HAVING
6-35 検索結果の並び替え ORDER BY
6-36 検索結果の出力範囲を指定 LIMIT, OFFSET
6-37 排他的六句と共有ロック FOR UPDATE/LOCK IN SHARE MODE
6-38 問い合わせの結合 UNION
6-39 副問い合わせ
■■ データの更新
6-40 データの更新 UPDATE
■■ データの削除
6-41 データの削除 DELETE
6-42 全データの削除 TRUNCATE
■■ 式や関数の実行
6-43 式や関数の実行 DO
■■ プリペアードステートメント
6-44 プリペアードステートメントの準備、実行、削除 PREPARE/EXECUTE/DEALLOCATE PREPARE
■■ 問い合わせ計画の表示
6-45 問い合わせ計画の表示 EXPLAIN
■■ ストアドプロシージャ・ストアドファンクション
6-46 ストアドプロシージャ・ストアドファンクションの定義表示 SHOW CREATE PROCEDURE/SHOW CREATE FUNCTION
6-47 ストアドプロシージャ・ストアドファンクションの状態表示 SHOW PROCEDURE STATUS/SHOW FUNCTION STATUS
■■ インデックスの表示
6-48 インデックスの表示 SHOW INDEX/SHOW KEYS
■■ インデックス情報の更新
6-49 インデックス情報の更新 ANALYZE TABLE
■■ ビュー
6-50 ビューの作成、変更、削除 CREATE VIEW/ALTER VIEW/DROP VIEW
6-51 ビューの定義表示 SHOW CREATE VIEW
■■ トリガ
6-52 トリガの定義、変更、削除 CREATE TRIGGER/ALTER TRIGGER/DROP TRIGGER
6-53 トリガの定義表示 SHOW TRIGGERS
■■ テーブルの最適化
6-54 テーブルの最適化 OPTIMIZE TABLE
■■ テーブルの検査と修復
6-55 テーブルの検査 CHECK TABLE
6-56 テーブルの修復 REPAIR TABLE
■■ トランザクション
6-57 トランザクション BEGIN|START TRANSACTION/COMMIT/ROLLBACK
6-58 セーブポイントの設定とロールバック SAVEPOINT/ROLLBACK TO SAVEPOINT
6-59 トランザクションの分離レベル設定 SET TRANSACTION ISOLATION LEVEL
■■ ロック
6-60 テーブルのロックと解除 LOCK TABLES/UNLOCK TABLES
■■ テーブルデータのインポートとエクスポート
6-61 テーブルデータのインポート LOAD DATA INFILE
6-62 テーブルデータのエクスポート SELECT INTO OUTFILE/SELECT INTO DUMPFILE
■■ テーブルのバックアップとリストア
6-63 テーブルのバックアップ BACKUP TABLE
6-64 テーブルのリストア RESTORE TABLE
■■ ログの管理
6-65 ログの切り換え FLUSH LOGS
6-66 バイナリログ一覧表示 SHOW BINARY LOGS/SHOW MASTER LOGS
6-67 バイナリログの内容表示 SHOW BINLOG EVENTS
6-68 バイナリログの全削除 RESET MASTER
6-69 バイナリログの削除 PURGE MASTER LOGS
■■ サーバの制御と状態表示
6-70 スレッドの情報表示とKILL SHOW PROCESSLIST/KILL
6-71 システム変数の変更 SET|SET OPTION
6-72 システム変数の表示 SHOW VARIABLES
6-73 データベースサーバの状態表示 SHOW STATUS
6-74 各種情報やログのリセット FLUSH
6-75 権限テーブルの再読込み FLUSH PRIVILEGES
6-76 クエリキャッシュの出フラグメント FLUSH QUERY CACHE
6-77 テーブルのクローズ FLUSH TABLES|FLUSH TABLE/FLUSH TABLES WITH READ LOCK
6-78 ステータス情報のリセット FLUSH STATUS
6-79 問い合わせ実行回数のリセット FLUSH USER_RESOURCES
■■ レプリケーション
6-80 レプリケーションに関するスレッドの状態表示 SHOW PROCESSLIST
6-81 マスターサーバの状態表示 SHOW MASTER STATUS
6-82 接続しているスレーブの一覧表示 SHOW SLAVE HOSTS
6-83 スレーブ機能の起動と停止 START SLAVE (SLAVE START) / STOP SLAVE (SLAVE STOP)
6-84 スレーブの状態表示 SHOW SLAVE STATUS
6-85 スレーブ機能のリセット RESET SLAVE
6-86 マスターサーバの変更 CHANGE MASTER
Chapter 07 データ型、演算子と関数
■■ データ型
7-01 MySQLがサポートするデータ型
7-02 数値データ型
7-03 文字データ型
7-04 ENUM型、SET型
7-05 BLOB(BINARY LARGE OBJECT)型
7-06 日付/時刻データ型
7-07 ビット型
■■ 演算子
7-08 MySQLのサポートする演算子
7-09 論理演算子
7-10 比較演算子
7-11 算術演算子
7-12 日付/時刻演算子
7-13 COLUMNパターンマッチング
■■ 関数
7-14 MySQLがサポートする関数
7-15 算術関数
7-16 集約関数
7-17 文字列関数
7-18 日付/時刻関数
7-19 型変換関数
7-20 その他の関数
Chapter 08 ストアドプロシージャ・ストアドファンクション
■■ 概要
8-01 ストアドプロシージャ・ストアドファンクションとは
8-02 ストアドプロシージャ・ストアドファンクションの定義と実行、削除
■■ プログラミングの基本
8-03 ローカル変数宣言と値の代入
8-04 SELECT INTO文
■■ 制御構造
8-05 条件分岐と場合分け
8-06 ループ処理
8-07 ハンドラー
■■ カーソル
8-08 カーソル
8-09 カーソル変数の宣言とオープン、クローズ DECLARE CURSOR FOR/OPEN/CLOSE
8-10 FETCH文によるカーソル行の取得 FETCH
8-11 カーソルを使った例

この本は、とても簡潔な(悪い言い方をすると淡々とした)文体で書き進められている。リファレンスなので淡々としているのは当然と言えば当然なのであるが、それでいて説明が明快なのは感心するところである。しかし本書の真の価値は文章ではないと断言する!本書を手にとって少しめくればすぐに気付くであろう。その図表の多さに。

そう、この本の真の価値は図表にある。文章による説明は必要最低限であるのだが、その代わり豊富な図表が補って余りあるぐらい雄弁にMySQLの各種機能を説明してくれるのである。文章をいちいち読むのではなく、図表で素早く内容を理解できるというのは、リファレンス本にとって至上命題の一つであろう。また、図表以外に目をひくのがコマンドやSQL文の実行例の多さである。各種機能の説明には必ずと言って良いほどSQLやコマンドの実行結果が掲載されている。説明を読んだだけではちょっとピンと来ないな・・・と思うような機能であっても、実行例を見れば一目瞭然という寸法である。

本書の内容を改めて見てみると、MySQLには膨大な機能があるんだなということに気付く。もちろん本書ではカバーされていない機能もあるが、それにしても膨大な機能である。(MySQLは高速だが機能が少ないと言う定説を疑いたくなるぐらいである。)その膨大な機能の説明を成し遂げた鈴木氏の努力は、並大抵のものではないと言えよう。

ちなみに、本書の最後には「参考書籍」が紹介されているのだが、その中には私(つまりこのブログの筆者)が執筆した出版予定の書籍(仮題:MySQLエキスパートトラブルシューティングガイド)が紹介されている。まだ出版されていない(鈴木氏に原稿を見せたということもない)書籍を「参考書籍」として紹介するというのは前代未聞の所業ではないだろうかと思うのだが、鈴木氏曰く「参考にした書籍ではなく、参考になる書籍という意味で掲載するからOK!」ということらしい。
※この点については鈴木氏本人より「誤解を招く表現」との指摘があったので修正させて頂く。この文面からすると鈴木氏は架空の内容を参考にしたように読み取れるがそうではない。鈴木氏は次の2点を見て「この書籍なら参考にするに値する」と判断して下さったそう。
オモシロおかしく書いたつもりが、思わぬ茶々になってしまって面目ないです>鈴木氏
MySQLエキスパートトラブルシューティングガイド(仮題)では、本書で取り上げられていない機能、例えばSHOW INNODB STATUSの見方やINFORMATION_SCHEMA、プロファイリング、トレースファイル、DTraceプローブなども解説するので乞うご期待。

そんなわけで、本書は網羅的で図表や実行例を駆使してとても分かり易いMySQLのリファレンスであり、初心者から上級者まで幅広い方々におすすめである。

2009-10-26

Snow Leopardにしてから困っていたこと=ファンクションキーが効かなくなる問題・・・が解決!

既に知って居るひともたくさん居るだろうが、自分がSnow Leopardを利用し始めてから困っていたことが解決したのでこのブログでも紹介しておこう。OSをLeopardからSnow Leopardにアップグレードしてから、「作業中に突然ファンクションキーが効かなくなる」という事態が度々発生して困っていた。何しろSpacesやExpose、Dash Boardはファンクションキーで呼び出すようにしているので、突然それらが使えなくなると不便で仕方がない。OSを再起動すると直っていたので度々OSを再起動する羽目になっていたから最悪である。(何故かブラウザをFirefoxやChromeからSafariにすると発生頻度が下がっていたのでSafariを利用するという回避策をとっていたのだが、これからはそれも不要である!アップルの陰謀かと思ったけど違うようだった。疑って悪かったよ>アップル)

で、その回避策とはズバリDockを再起動することだ。

どうやらショートカットキーの類はDock.appが一括して仕切っているようなので、Dock.appだけを再起動してやればOSごと再起動しなくても済むわけである。ちなみに、Dockを再起動しても他の作業に影響は出ない。なので、とりあえずファンクションキーの動作がおかしくなったら次のコマンドでDock.appを再起動してみるといいだろう。

shell> killall Dock

MySQL Clusterソースコード探検隊!

これまで「MySQL Clusterの進化とその構造について」および「NDBカーネルブロックの種類」について説明した。今日はその続きとしてMySQL Clusterのソースコードについて紹介しようと思う。シグナルを交換し合うマルチプルステートマシンは間違いなくこれからの時代にフィットするアーキテクチャなので、MySQL Clusterに興味を持たれた方が「膨大なMySQL Clusterのソースコードを探検する場合にどの入り口から入ればいいのか」ということを判断する一助になればと思う。とりとめなく書いてるのであんまりまとまってないかも知れないが、その点は容赦して頂きたい。

まず、ソースコードの入手方法であるが、これは最新のソースツリーをBazaarで入手する方法と、MySQLのWebページからダウンロードする方法の2つがある。Bazaarで入手するには、次のコマンドを実行すれば良い。(Bazaarを事前にインストールしておこう。)

shell> bzr branch lp:~mysql/mysql-server/mysql-cluster-7.0

するとカレントディレクトリ以下にソースコードがコピーされる。結構時間がかかるので注意しよう。

MySQLのWebページからダウンロードするには、次のページをブラウザでアクセスしよう。

http://dev.mysql.com/downloads/cluster.html

するとプラットフォームの選択メニューが出てくるので、ZIP形式のソースコードが欲しければWindowsを、TAR形式のものが欲しければLinuxを選択しよう。一番小さいファイルがソースコードである。ソースコードのファイルはmysql-cluster-gpl-VERSION.tar.gzというような名前になっている。

MySQL Clusterのソースコードが含まれる場所は次の2つである。

  • src-top-dir/storage/ndb
  • src-top-dir/sql

src-top-dirはソースコードのトップディレクトリ、つまりZIPまたはTARファイルを展開したときに作成されるディレクトリ(mysql-cluster-gpl-VERSIONというような名前のディレクトリ)のことである。

storage/ndbにはndbdやndb_mgmdといったコマンドのソースコードが収められている。つまりSQLノードを除く全てのコマンドのソースコードはここにある。一方、sqlディレクトリにはSQLノードのソースコードが格納されている。ファイル名はha_ndbcluster*。(*はワイルドカード。)ここは元々mysqldのソースコードが収められているディレクトリなので、そこに居候しているのである。(将来的にはstorage/ndbへ移動したいらしいが、タスクの優先順位は低くなかなかそうならない。)肝心のNDBカーネルのソースコードはstorage/ndb以下にあるのでこちらを中心に説明する。ha_ndbcluster*には、ストレージエンジンとしてMySQL Clusterへアクセスする際に必要なソースコード、つまりmysqldがNDB APIを通じてNDBにアクセスするためのロジックが記述されているので、ストレージエンジンAPIおよびNDB API興味のある人は覗いて見るといいだろう。

ここからは、NDBカーネルのソースコードを見る際のポイントについて列挙しよう。

  • NDBカーネルのソースコードの位置は、storage/ndb/src/kernelである。main()関数を含むmain.cppはこのディレクトリである。ndbdの初期化プロセスについて知りたい場合には、main.cppを見よう。
  • ヘッダファイル類はstorage/ndb/include/kernel配下に収められている。C++のヘッダファイルはstorage/ndb/src/kernel以下にも含まれているが、共通のヘッダファイルはこちらのディレクトリに含まれているので注意しよう。
  • storage/ndb/src/kernel/vmには、PLEX仮想実行環境のソースコードが含まれている。最も重要なのはSimulatedBlock.[c|h]ppで、ここで定義されているSimulatedBLockクラスはこれらは全てのブロックの親クラスとなる。つまり、NDBDカーネル内の各ブロックは、SimulatedBlockクラスを継承しているのである。また、SimulatedBlockが交換するメッセージは、VMSignal.[c|h]ppで定義されている。(シグナルを表すクラスはSignalである。)面白いことに、SimulatedBlockは他のあらゆるカーネルブロックへ、sendSignal()関数を通じてシグナルを送信することが出来る。同じプロセス内のブロックであろうが、他のホストで動作しているブロックであろうが、同じ方法(関数)でシグナルを送信することが出来るのである。
  • storage/ndb/src/kernel/blocksには各ブロックのソースコードが含まれている。ブロックごとにサブディレクトリに分かれているので見易いだろう。ここで定義されている各カーネルブロックは、上記の通りSimulatedBlockクラスを継承している。各カーネルブロックの動作を定義しているこのディレクトリは、NDBのソースコードの心臓部と言っていいだろう。
  • storage/ndb/include/kernel/BlockNumbers.hには、各カーネルブロックのIDが定義されている。ブロック番号は16ビット符号無し整数なのだが、同じく16ビット符号無し整数であるノードIDと組み合わせることで、32ビットの符号無し整数としてクラスタ全体を通じたID(BlockReference)を合成することが出来る。storage/ndb/include/kernel/RefConvert.hppにはノードIDとブロック番号からBlockReferenceへ変換するロジックおよびその逆が定義されている。(ただのビット演算だけどね!)
  • storage/ndb/src/kernel/SimBlockList.cppには、作成したカーネルブロックのインスタンス化と、そのインスタンスへのポインタをリストにして保管しておくためのロジックが記述されている。ただし、NDBカーネルの各ブロックはインスタンス化された段階ではまだ初期化されず、その後STTORシグナルを受け取った時点で初期化が始まる点には注意したい。
  • storage/ndb/include/kernel/GlobalSignalNumbers.hでは、各シグナルにつけられた番号が記述されている。実に700種類以上のシグナルが定義されている!(2009年10月現在)
  • storage/ndb/include/kernel/signaldataディレクトリには、シグナルにおいて送信されるデータ(ペイロード)を定義するクラスのソースコードが格納されている。シグナルが送信するデータはフリーフォーマット(単なるワード列)なので、頻繁に利用されるデータについてはその構造が定義されているのである。
  • storage/ndb/src/common/transporterディレクトリには、トランスポーターに関するソースコードが格納されている。トランスポーターとは、MySQL Clusterの各ノード同士が通信し合うための仮想的なインターフェイスである。これにより、通信する実際のプロトコル(TCP/IPなのかSCIなのか)に因らないロジックの記述が可能になる。
  • storage/ndb/src/mgmsrvディレクトリには、管理ノードのソースコードが格納されている。特に重要なのはstorage/ndb/src/mgmsrv/ConfigInfo.cppで、このファイルには各種設定パラメーターとそのデフォルト値に関する記述がなされている。また、storage/ndb/src/mgmclientにはndb_mgmコマンドのソースコードが、storage/ndb/src/mgmapiにはNDB MGM API(設定情報をやり取りするためのAPI)のソースコードが格納されている。
  • storage/ndb/src/ndbapiディレクトリには、NDB APIに関するソースコードが格納されている。
そんなわけでMySQL Clusterのソースコードのレイアウトについてとりとめもなく紹介してみた。「よし、ソースコードを見るか!」と思った時に参考にして頂けると幸いである。

2009-10-23

MySQL Clusterカーネルの中身を覗いてみよう。

MySQL Clusterのデータノードであるndbd(もしくはndbmtd)プロセスは、内部的にはマルチプルステートマシン(ブロック)がシグナル(もしくはメッセージ)を交換するという構造になっており、高い同時実行性を実現しているということについては前回述べた通りである。今日は、ndbd内部にどのようなカーネルブロックが存在するかということについて大まかに説明しよう。前回の話を踏まえて読んで頂ければ、何となくイメージだけでも掴めるのではないかと思う。まずは次の絵を見て頂きたい。これは俺の脳内から引っ張り出したndbdの構造のイメージ図である。




矢印はブロック同士の相関関係(シグナルの送受信など)を示すのだが、この絵に描かれているものは非常に省略されたものであり、実際にはもっと複雑に絡み合っているのだということを覚えておいて欲しい。例えばQMGRやDBDICTといったブロックは、他のブロック全てとシグナル交換をするのだが、それを全て描くと何が何だか分からなくなるので省いているわけである。もし全てを描いたなら、思わず「それ何てスパゲティ?」と叫んでしまうこと請け合いである。

というわけで、以下淡々と各ブロックについて簡単に説明しよう。MySQL Clusterの各ブロックは、いくつかのカテゴリに分類することが出来るので、以下ではそのカテゴリごとに説明している。

NDBカーネルを管理するブロック
  • CMVMI・・・Cluster Manager Virtual Machine Interfaceの略。OSへのリクエストを処理したり、ndb_mgmd(管理ノード)と通信をしてndbdの構成を決定する。
  • NDBCNTR・・・NDB CordiNaToRの略。NDBコントローラーか?と思ってしまいがちだが、コーディネーターの意味。役割はndbd起動時の初期化とシャットダウン。
  • QMGR・・・クラスタマネージャブロック。ハートビートを通じて各ブロックの状態を管理している。NDBカーネルの親玉的存在。
  • NDBFS・・・ファイルシステムへのI/Oを一手に引き受けるブロック。このブロックのおかげでファイルへの非同期I/Oが容易に実装できている。
ローカルノード(自ノード)のデータを管理するブロック。
  • DBLQH・・・ローカル・クエリ・ハンドラ。自ノードに対するトランザクションを処理する。MySQL Clusterのndbmtdでマルチスレッド化されたのはこのブロック。図を見れば分かると思うが、このブロックの負荷はかなり高い。(次いで負荷が高いのはDBTC)
  • DBACC・・・自ノードの主キーを管理するブロック。ACCはアクセスの意味。
  • DBTUP・・・データを管理するブロック。TUPはタプルの意味。
  • DBTUX・・・TUple indeXの略。OrderedIndexを管理する。
  • DBUTIL・・・トランザクション管理やデータ管理のための便利な機能が詰まったユーティリティブロック。
並列分散処理のためのブロック
  • DBDICT・・・ディクショナリブロック。テーブルやテーブルスペース、ログファイルのメタデータの管理を一手に引き受ける。SQLノードが直接アクセス出来るブロックである。
  • DBTC・・・Transaction Cordinatorの略。SQLノードからリクエストされたトランザクションの面倒を始まりから終わりまで面倒を見るブロックである。該当するデータが自ノードの担当でなければ、別のデータノードへ要求を送ったりする。
  • DBDIH・・・DIstribution Handlerの略。レプリカを管理し、どのフラグメント(パーティション)がどのノードに格納されているかについて責任を持つ。また、LCPGCPといった処理を行うのもこのノードである。
  • TRIX・・・TRansactions and IndeXesの略。このブロックは内部的なトリガとユニークインデックスを管理する。MySQL Clusterはデータが複数のノードに分散しているので、行の一意性を保証するのにはどうしても分割の対象となる主キーが必要となるため、サポートテーブルという別の内部テーブルが作成される。実テーブルと内部テーブルは、トリガによって同期されるというわけである。
ディスク型テーブル用のブロック
  • PGMAN・・・バッファページを管理するブロック。名前の由来はPaGe MANagerである。
  • TSMAN・・・テーブルスペースを管理するブロック。名前の由来はTableSpace MANagerである。
  • LGMAN・・・ログファイルグループを管理するブロック。名前の由来はLogfile Group MANagerである。
バックアップ関係
  • BACKUP・・・オンラインバックアップの実行。
  • RESTORE・・・取得したバックアップのリストア。ndb_restoreコマンドからデータを受け取ってリストアする。ndb_restoreコマンドは、一種のSQLノードとして動作する。
  • SUMA・・・SUbscription MAnager。MySQL Server(mysqld)へバイナリログの元になるデータを送信する。
以上がNDBカーネルブロックの概要である。

ブロック同士がシグナルを交換して実現しているのは「データベース管理システム」である。各カーネルブロックは、データベース管理システムに必要な機能の要素ひとつひとつを具現化したものであると考えられるので、どのようなブロックが存在するかということはデータベースエンジニアにとって興味深いものとなっているのではないだろうか。また、MySQL Clusterのログにはブロック名がたくさん登場するので、ブロックの役割について知っていればログを見る際に役立つはずである。次回は、MySQL Clusterのソースコードのレイアウトについて説明する予定である。

2009-10-21

MySQL Cluster進化の歴史

MySQL Cluster開発者の一人であるFrazer Clement氏がその歴史についてとても興味深いエントリを自身のブログで綴っているのだが、いかんせん英語の長文で日本人には辛いかも知れないので今日はその日本語訳を皆さんにも紹介しようと思う。進化の歴史とその結果生じた構造を知ることにより、MySQL Clusterの仕組みに興味を持って頂けると幸いである。(わかり辛いところにはところどころ訳者による注釈を入れてある。ただし翻訳は結構大ざっぱなので、英語が達者であれば細かいニュアンスなどはオリジナルのエントリを参照して頂きたい。なお、日本語訳をすることに関してはFrazer氏の了解を得ているのであしからず。)
NDB(MySQL Clusterの略称。元々はNetwork DBという名称であった。)の開発の正確な歴史について、きっと他の誰かのほうが上手く解説できると思うのだが、限られて曖昧かも知れないが私の見解を以下に述べようと思う。
  • NDBは元々、EricssonのPLEXというプログラム言語が使われている環境で(EricssonのAXE交換機用に)開発された。PLEXはマルチプルステートマシン(ブロックと呼ばれる)がメッセージ(シグナルと呼ばれる)を互いに交換し合うことによって、いくつかのシステムレベルの起動、再起動、およびメッセージクラスなどのタスクを実行する構造になっている。各ブロックは内部に状態を持っており、シグナルごとにそれを処理するルーチンが定義されているという具合である。ただしブロックがサブルーチンに対してサポートしている抽象化(訳者注:定義出来る機能の実装)はごく限られたものであった。(私=FrazerはPLEXについて、それがどのように進化したかをもっと詳しく聞きたいと思っている。)このことは、AXEのプロセッサのデザインにそのまま反映されている。AXEは常識とは異なり、シグナルバッファがソフトウェアではなくハードウェアとしてシリコン上に実装されているのである。このような「ハードコーディング」がされているため、当初NDBは最長で25 x 32ビット長のシグナルしかサポート出来なかった。
  • PLEXの仮想実行環境(VM)がUNIX上のプロセスとして実行された。ブロック上で実行されるPLEXのコードはVM用のコードに逐次解釈(interpret)され、シグナルはVMによってブロックへ転送された。これにより、PLEXベースのシステムのUNIX上での開発が始まったのである。その結果、PLEXベースのシステムが容易にUNIXソフトウェアと通信することが可能になった。それぞれのVMのインスタンスはシングルスレッドのプロセスで、送られて来たシグナルをブロック内に定義されている処理シグナル処理ルーチンへ振り分けるという仕組みになっていた。 
  • PLEXからC++への変換システムが設計された。ブロックが巨大なC++のクラスに変換され、シグナル処理用のメンバ関数とブロックごとのグローバルな状態がメンバ変数が定義された。PLEX環境における限られた命名規則と抽象化された機能が、C++クラス内にC言語スタイルの機能として実装された。
  • VM環境は元々のPLEX/AXE環境から分岐し、NDBのベースとして独自の進化路線をとった。その結果、NDBはOSの各種サービス(通信、ディスクI/Oなど)へアクセスすることが可能となった。PLEXコードの逐次解釈(インタプリタ)機能は取り除かれ、PLEXのコードはすべてC++のコードに書き直された。VMインスタンスは各種通信経路を用いて相互に通信出来るようになり、分散システムを形成するようになった。
  • このぐらいの時期にNDBとその開発チームがEricssonを去ることになった。(訳者注:Ericossonはベンチャー企業であるAlzato社を作ってNDBを独立した製品にし、さらにその後Alzato社がMySQL ABに買収されることになる。)
  • ブロックの共通した機能がベースまたはユーティリティクラスへと抽象化された。これにより、ハードウェアやシステムに起因した制限が緩和され、抽象化の度合いが上昇することになる。現在では、ブロックはPLEXの(負の)遺産に悩まされることなく、C++の抽象化機能を活用して実装されている。元々存在していたブロックは全て作り直された。
  • マルチスレッドのNDBデーモン(ndbmtd)が開発された。ブロックの各インスタンスが異なるスレッドで実行されるようになった。といってもこれは急激な変更ではなく、PLEX実行環境で元々採用されていた「1つのブロックを1つのプロセッサとして実装する」という設計への回帰である。(訳者注:ndbmtd内にはおよそ20種のブロックが存在し、それらが予め定められた数のスレッドで実行されている。)
というわけで、現在NDBはシグナルモデルを利用してブロックがお互いに通信するような仕組みになっているのである。シグナルはもはや25ワード長に制限されていない。シングルスレッド版のNDBデーモン(ndbd)もあり、それは全てのブロックが一つのスレッドを共有しているが、VM同士の通信やディスクI/Oなどのための専用のスレッドが実装されている。(訳者注:I/Oなどのスレッドが別途あるという意味では厳密にシングルスレッドプロセスであるわけではない。)いずれの場合にしても、ひとつひとつのブロックはシングルスレッドのままであり、スレッドは複数のブロックによって共有されている。(訳者注:スレッド対ブロックは1対Nの関係である。)

このようなブロック-シグナルモデルは、ErlangHoareのCSPを思い起こさせる。つまり、同時実行性がシーケンシャルなプロセスがお互いに明示的なメッセージを交換し合うことによってモデル化されているようなシステムである。これは共有メモリモデル、つまりメモリへのアクセス整合性をロックやメモリ保護機能、アトミック命令などで保証するというモデルとは対照的である。もしくは、ブロック-シグナルモデルはMPIやActiveオブジェクト/Actorモデルに似ているとも言える。

明確なメッセージ交換によって同期または通信を行うのはコストが掛かる。つまり、実行時により多くのメモリコピーが発生するということである。プログラム設計時には、潜在的な同時実行制御はメッセージ交換および状態遷移というモデルで明示的に表現されていなければならず、マルチスレッドセーフな共有メモリとロックを用いたモデルよりも多くのソースコードを改変または記述する必要が生じてしまう。

しかしながら、これらのデメリットはコードの見通しがよくなるという利点によって十分に報われると思う。ステートマシン間の同期はとても見通しが良く、同期のためのコストを容易に理解することができる。明確なメッセージ交換をスレッドまたはプロセスの通信手段として利用すれば、ごく僅かな部分だけをマルチスレッドの(スレッドセーフな)カーネルとして実装するだけで済み、そのカーネルは正しく最適化されているということが保証されるであろう。そして多くのコードがシングルスレッドのスタイルで(マルチスレッドを意識する必要なく)記述することが出来る。マルチスレッドのためにライブラリを作り直す必要もない。(訳者注:ブロックがシグナルに応答する各種ロジックは全てシングルスレッドで実行されるからである。)その結果、プロセッサとシステムアーキテクチャに依存したコードおよびトレードオフが最小化されるのである。

内部的には、NDBのVMはブロック同士の通信は非同期のものだけをサポートしているが、そのような非同期のメッセージ交換を用いることは多くのメリットがある。第一に、メッセージを送信したスレッドは、そのメッセージの処理が送信先のブロックにおいて完了するのを待たなくても良いので、他に多くの作業ができる。同じスレッドを共有している他のブロックにメッセージを送った場合は自らが送信したメッセージを即座に処理するということもあるだろう。これにより、CPU内のデータおよび命令キャッシュが最大限に活用され、コンテキストスイッチが減少し、デッドロックの可能性が低減することになる。ブロッキングI/O(ネットワークおよびディスク)は専用のスレッドプールへ処理が割り振られるため、シグナルを処理するスレッドがブロックすることは絶対にない。(ただし保留中のシグナルがなくなった場合にはスレッドが停止する)システムの応答性は、優先付けされたジョブキューを使い、どのジョブを先に処理するべきかということを決定して各種ジョブに掛かる時間を最小化することによって実現している。形式的な見方をすれば、スレッド同士が相互作用する必要のある状況は、スレッドが同時に実行されている状態とほぼ同等まで減少することが可能となる。つまり、スレッド同士の同期はシグナル処理の境界だけで必要なのである。このように、前述のような制限は、(シングルスレッド処理に起因する)システムの正しさやタイミング特性(応答性の向上)を容易にするのである。

しかしながら、このような非同期で、イベントドリブンなスタイルの開発はとても難しいというのもまた事実である。全てのブロッキング操作(ディスクアクセス、ブロックされる通信、他のスレッドやプロセスへの要求など)をリクエストとレスポンスのペアとして実装しなければならないからである。また、広く一般的に使われる数多くのデータ構造やアルゴリズムは単一の(その処理を開始したスレッドの)スタックを(データを格納したり関数の引数を渡したりするために)利用するという前提に立っているが、このようなメッセージ交換によりシステムを実装するとそれらのデータ構造やアルゴリズムを活用することが出来ない。また、非同期のスタイルで開発されたソフトウェアはこまごまとした詳細が分からず、つかみ所がないため新しい機能を設計するのは時として難しい場合がある。その上、抽象化の深いレイヤーでのコードであっても、並列化が可能なものであれば常に最もレベルの浅い呼び出し元(コールポイント)までリターンしなければならないため、非同期のシステムは構造が平坦になってしまいがちである。(訳者注:つまりスタックが深くなることはない。)このような構造をとることによる副作用は、エラー処理のコードがエラーの発生源になっているブロックに固有のものではないという点である。しかし、まあそれもこのような非同期(の並列)システムをいじる楽しみの一つだと言える。C++環境はそのような抽象化された要素を設計するために、非常に幅広いツールを提供してくれる。そして、個々の改善が将来の作業を易しくしてくれるのである。
以上が翻訳である。このように、MySQL Clusterはシグナル(メッセージ)交換を基礎として実装されており、通常の共有メモリ方式の並列ソフトウェアとは大きく構造が異なっている。その結果として、MySQL Clusterは高い同時実行性と素早い応答性を実現しているのである。排他ロックを使わずに同時実行制御をする構造はロックがボトルネックにならないためCPU数に応じてスケールし易く、CPUコア数が増加すると予想されるこれからの時代にはとても有利に働く可能性があり、これからMySQL Clusterがどこまで性能を向上させられるかとても楽しみである。

しかし、はっきり言ってMySQL Clusterの構造を理解するのは少し敷居が高い。動作不良を起こした場合に原因を特定するためには、各ブロックのソースコードを行ったり来たりしなければならないので必然的に解析には時間が掛かってしまうし、各ブロックの状態は刻々と変化するので問題の発生条件の特定も難しい。なので慣れるまでは結構大変かも知れない。その内部構造を詳しく知るようになればFrazer氏が言うようにそれもまた魅力になるかも知れないが、構造が分からないうちは単なる苦痛である可能性が高い。というわけで、次回はNDBデーモンの各カーネルブロックについて紹介しようと思う。

2009-09-17

私は如何にして高性能ファンレスPCから超小型LinuxマシンにMediawikiを実質数時間の作業で移行したか。

ある日、オフィスに行くとキムラデービーの木村さんに面白いマシンがあると言うので見せて貰った。

マシンと言っても、小さい白い箱からプラグがニュッと出ているだけである。そう、一昔前に話題になったあのSheevaplugである。

Sheevaplugはニュースで見て知って居たが、実物を見るのは初めてだ。とはいっても、実際に稼働しているものを見たわけではなく箱から出したばかりのものを見せて貰っただけである。実物を見た第一印象は、軽い!小さい!の一言だ。この小さな箱でサクサクとUbuntu Linuxが動いてたったの$99(送料別)というから、俺が欲しくなるのは当たり前というものである。Sheevaplugを知らない人のために、簡単にSheevaplugのスペックを紹介しよう。
  • ARM 1.2GHz CPU
  • 512MB RAM
  • 512MB フラッシュメモリ
  • ギガビットイーサネット
  • SDカードアダプタ
  • USB 2.0 x1
  • 110mm (L) x 69.5mm (W) x 48.5 mm (H)
少々RAMやフラッシュメモリが貧弱な気はするが、$99ならば十分納得のスペックである。しかも完全ファンレスだから無音。そして19W程度の低消費電力。家庭でこっそりと使いたい男性諸氏にとって何とも有り難い仕様ではないだろうか。家庭にも財布にも優しいとはこのことである。

詳しい仕様などについては、Sheevaplugを販売しているGlobal Technologies社のページを見て頂きたい。ここまで低価格な製品に仕上げられたのは、ひとえにSystem-On-a-Chipだからであろう。(それでも安すぎるが、それはβ版という扱いだからだろうか。)

なんでこのSheevaplugが欲しかったかというと、MySQL Practice Wikiを運用するためのハードウェアをもっと小型のものにしたかったからだ。完全に無音で、低消費電力で、運用が楽ちんなもの。今は静音PCの老舗オリオスペックで購入したHFX MicroにSolaris 10をインストールして使っているのだが、さらにもっと静かで低消費電力でコンパクトなものに変えたかったのである。(ついでにHFX Microを他の用途で利用したくなったからである。)

このSheevaplug、色々弄ってみたがとても素直でいいこちゃんである。あれよあれよという間に設定が進み、電源を入れてからものの数時間程度の実作業でWikiを移行することが出来てしまった。まあ、ぶっちゃけMediawikiを移行したかっただけなので大した作業は必要なかったといえばなかったのだが、こうも作業がすんなり運ぶのはちょっと感動である。あまりにも作業がスムーズだったので、「よく分からないから手を出しづらいな」と思っている人のために設定すべき内容を残しておくことにする。皆さんの購買意欲に繋がれば幸いである。いや、ホントコレ$99の割にちゃんと動いてお買い得ですよ、ちょっとそこの奥さん!

というわけでまずは購入についてであるが、日本に代理店がないので海外から直接取り寄せる必要がある。しかも購入できるのはGlobal Technologies社のWebサイトだけ。海外からなので送料はけっこうかかる。Fedexなら$34.77。Sheevaplug本体$99とあわせると合計$133.77なり。円高だから12000円ちょっと。それでも安い!

Sheevaplugが届いたらまずは電源投入!であるが、Sheevaplugにはボタンなどの類は一切なく、電源を入れるといきなりOSが起動する。しかもSheevaplugにはディスプレイアダプタというものが存在しないので、モニタに接続することもできない。どうやって操作すればいいのだろうか??

答えはUSBケーブルである。Sheevaplugの側面にはデバッグ用のミニUSBポートがついており、付属のケーブルを使ってパソコンと接続することによって操作が可能である。筆者の場合はMacを使って設定したのだが、MacからSheevaplugへ接続するための設定方法はHisao's Blogさんで紹介されているのでそちらを参照した。至って簡単である!(筆者は種々のサーバーマシンをメンテナンスしてきた経験があるので、この手のコンソールからマシンにアクセスするのは抵抗がないのだが、PCしか触ったことがない人はちょっと抵抗があるかも知れない。けど簡単だからやってみるといいよ!)

LinuxやWindowsを母艦にしたい場合には、このへんこのへんを参考にすると良いだろう。

USBのコンソールから接続すると、u-bootというファームウェア(PCでいうところのBIOSの役割に相当)が表示され、それからUbuntu Linuxが起動する。サーバー用途で利用したいので、もちろんOSには固定IPを割り当てたりDNSの設定をしたりするわけであるが、この辺の諸設定は普通のUbuntu Linuxとまったく同じである。のら犬にさえなれないさんで、設定すべき項目がよくまとめられているのでそちらを参照して欲しい。

諸設定が終わったら、今度はカーネルの更新を行う。デフォルトで搭載されているカーネルは、2.6.22.18なのだが、ファイルの書き込みが遅いらしい。そこで、カーネルを2.6.30.5へアップグレードしよう。といっても作業は簡単で、有志が作成してくれたスクリプトをイッパツ実行するだけである。

1. まずはwgetをインストールする。

shell> apt-get install wget

2. 実行出来る不思議なREADMEをゲットする。

shell> wget http://sheeva.with-linux.com/sheeva/README-2.6.30.5

3. READMEのパーミッションを変更して実行する。

shell> chmod 700 README-2.6.30.5
shell> ./README-2.6.30.5

するとこのスクリプトがカーネルのバイナリをダウンロードして、フラッシュメモリへの書き込みまで行ってくれる。簡単楽チンである。詳細な手順はHisao's Blogさんで紹介されているのでそちらを参照して欲しい。

さて、ここで問題になるのがデフォルトのフラッシュメモリが512MBしかないということである。流石にMediawikiしか利用しないといっても、これでは直ぐにデータが溢れてしまうことだろう。(パッケージも色々追加したいしね。)ならばSheevaplugに搭載されたSDカードスロットにSDカードを差し込んで利用すれば良い。SDカードは適宜事前に準備しておこう。筆者はちょっと奮発して、Sandiskの超速いヤツを購入した。SheevaplugよりもSDカードの方が高額だったのはご愛敬!である。SDカードを利用するには、u-Bootと呼ばれるファームウェアを更新する必要がある。u-BootはUSBケーブルでコンソールに接続し、OSが起動する前にキーを押すことで操作することができる。キーを押すタイミングは次の通り。(次はUSBケーブルを使って接続し、Sheevaplugを起動したときの出力例だ。)

       __  __                      _ _
        |  \/  | __ _ _ ____   _____| | |
        | |\/| |/ _` | '__\ \ / / _ \ | |
        | |  | | (_| | |   \ V /  __/ | |
        |_|  |_|\__,_|_|    \_/ \___|_|_|
 _   _     ____              _
| | | |   | __ )  ___   ___ | |_ 
| | | |___|  _ \ / _ \ / _ \| __| 
| |_| |___| |_) | (_) | (_) | |_ 
 \___/    |____/ \___/ \___/ \__| 
 ** MARVELL BOARD: SHEEVA PLUG LE 

U-Boot 1.1.4 (Aug 22 2009 - 11:36:42) Marvell version: 3.4.16

U-Boot code: 00600000 -> 0067FFF0  BSS: -> 006CF100

Soc: 88F6281 A0 (DDR2)
CPU running @ 1200Mhz L2 running @ 400Mhz
SysClock = 400Mhz , TClock = 200Mhz 

DRAM CAS Latency = 5 tRP = 5 tRAS = 18 tRCD=6
DRAM CS[0] base 0x00000000   size 256MB 
DRAM CS[1] base 0x10000000   size 256MB 
DRAM Total size 512MB  16bit width
Flash:  0 kB
Addresses 8M - 0M are saved for the U-Boot usage.
Mem malloc Initialization (8M - 7M): Done
NAND:512 MB

CPU : Marvell Feroceon (Rev 1)

Streaming disabled 
Write allocate disabled


USB 0: host mode
PEX 0: interface detected no Link.
Net:   egiga0 [PRIME], egiga1
Hit any key to stop autoboot:  0 <---- ココでキーを押す!

u-Bootはコマンドを入力して操作するのだが、以下は主なコマンドである。
  • help...コマンド一覧を表示する。
  • boot...OSを起動する。
  • printenv...環境変数を表示する。
  • setenv...環境変数を設定する。
  • saveenv...環境変数を保存する。(setenvだけではフラッシュメモリに書き込まれない。)
  • run...環境変数に設定されたコマンドを実行する。
  • mmcinit...SDカードを認識する。
  • bubt...u-Bootを更新する。
というわけで、bubtコマンドを使ってu-Bootを更新するわけである。更新する対象のu-Bootは、アクセス可能なtftpサーバーに事前に置いておかなければならない。Mac OS Xならば、デフォルトでtftpサーバーを利用することができる。u-Bootの新しいイメージを、/private/tftpbootディレクトリにコピーしよう。u-Bootのイメージは、Hisao's blogさんの方で配布されているのでそちらからダウンロードして欲しい。ついでに言うと詳細な更新手順もそちらに載っているので参照して欲しい。以下、実行手順例のダイジェストである。

Marvell>> setenv ipaddr 192.168.1.123
Marvell>> setenv serverip 192.168.1.100
Marvell>> setenv netmask 255.255.255.0
Marvell>> saveenv
Marvell>> bubt u-boot-rd88f6281Sheevaplug_400db_nand.bin

すると「Override Env parameters? (y/n)」と聞かれるので、必ず「n」を選択しよう。リセットすればいっちょあがりである。

Marvell>> reset

リセットが完了したらもう一度u-Bootに入り、mmcinitコマンドを実行しよう。これでSDカードを利用する準備は整った。OSを起動して、fdiskコマンドを利用するとSDカードを認識しているのが分かるだろう。

ここで次に考えるのは、恐らくSDカードからOSをブートすることが出来ないか?ということではないだろうか。実はこの作業、めちゃくちゃ簡単である。簡単であるにも関わらずその効果は絶大で、OSの起動がもの凄く高速化したり(u-Bootからものの5秒程度で起動するようになってしまう!)、SDカードから起動するようにしておけば、SDカードを差し替えることでOSを入れ替えるといった芸当も可能になり、超オススメなのである。SDカードからOSを起動する手順は次の通り。

1. パーティションを切る。

shell> sudo fdisk /dev/mmcblk0

パーティションの切り方はお好みで。筆者はswap用に1GB、残りをファイルシステム用に設定した。

2. ファイルシステムを作成する。

shell> sudo mkfs -t ext3 /dev/mmcblk0p1
shell> sudo mkswap /dev/mmcblk0p2
shell> sudo mount /dev/mmcblk0p1 /mnt

3. OSをコピーする。

shell> sudo cp -ax / /mnt
shell> sudo cp -a /dev /mnt

4. カーネルを/mntにコピーする。

カーネル本体はREADME-2.6.30.5を実行したときにダウンロードされているはずなので、これを使う。ファイルの場所は/mntではなく/mnt/bootでも構わない。/mnt/uImageとしてリンクを作成しておこう。

shell> sudo mv /root/sheeva-2.6.30.5-uImage /mnt
shell> sudo ln /mnt/sheeva-2.6.30.5-uImage /mnt/uImage

ついでに/mnt/etc/fstabを編集して、スワップを追加しておこう。

/dev/mmcblk0p2 none swap sw 0 0

5. u-Bootを設定する。

OSを全てSDカードにコピーしたら、再起動してu-Bootへ入ろう。そしてbootargs環境変数を変更し、「root=/dev/mtdblock1」となっているところを「root=/dev/mmcblk0p」に書き換えよう。また、OSを起動する前にu-Bootでmmcinitコマンドを実行する必要があるが、これはbootcmd環境変数の先頭に「mmcinit;」という一文を追加することで対処可能である。

6. OSを起動する。

OSはSDカードから起動しただろうか?これまでの一連の作業はPlug Wikiのページ(英語)にも載っているので、そちらも参照して欲しい。上記の手順は筆者が多少アレンジしたものである。

上記の設定では、SDカードが抜かれている場合にOSが起動しない。さらに一歩進んでu-Bootを設定すると、SDカードがある場合にはSDカードから、SDカードがない場合には内蔵のフラッシュメモリからOSが起動する・・・という具合に動作させることが可能である。この手順はのら犬にすらなれないさんで紹介されているので、そちらを参照して欲しい。

さて、ここまで来れば後は通常のUbuntu Linuxとまったく同じように操作が可能である。ディスク容量もそこそこあるので、あまり神経質になる必要もない。(あえて解説する必要すらないかも知れない。)しかし、こんな風にすればちゃんと出来ますよ!ということを紹介するために、実際に筆者が行った設定を紹介しておく。

1. MySQLのビルド(笑)

いきなりコレかよ!?と思うかも知れないが、MySQLerたるものまずはMySQLをコンパイルしたくなるのが人情というものだろう。MySQLをビルドするには、build-essentialおよびlibncursesw5-devパッケージをインストールする必要がある。

shell> sudo apt-get install libncursesw5-dev build-essential

ま、以下はお好みで。

shell> sudo apt-get install libtool bzr

MySQL Community Serverのソースコードをダウンロードサイトから入手し、解凍し、おもむろに...

shell> ./configure [オプション色々] && make

を実行する。さすがにSheevaplugのCPUではビルドに時間が掛かってしまう。筆者はコンパイル中に外食していたので実際にどれぐらい掛かったかは不明であるが、見るからにコンパイルが遅いので相当時間を要するのだろう。無事にビルドが完了したら

shell> sudo make install

でMySQLのインストールは完了である。/etc/mysql/my.cnfを編集しよう。ついでにソースコードに含まれるsupport-files/mysql.serverを/etc/init.dにコピーし、MySQL Serverが自動で起動するようにしておくといいだろう。

shell> sudo cp support-files/mysql.server /etc/init.d
shell> update-rc.d mysql.server defaults

データディレクトリの初期化とか諸々の設定に関しては説明を割愛する。筆者はMySQL 5.1.38に含まれるInnoDB Pluginを利用したかったのでソースコードからビルドしたが、まあ、ふつうは自分でビルドするよりはUbuntu標準のMySQLパッケージを利用するといいだろう。その場合のインストール方法は以下。

shell> sudo apt-get install mysql-server mysql-client

2. Apache/PHPのインストール

MySQL Practice Wikiは、Wikipediaと同じMediawikiを使って構築している。MediawikiはPHPで記述されているので、ApacheやらPHPやらをインストールする。

shell> sudo apt-get install apache2 php5 php5-mysql

3. データ移行

あとは既存のマシン(HFX Micro)からMySQLのデータをmysqldumpを使って移行し、利用しているMediawikiのファイル(ApacheのDocumentRoot以下)を全てコピーすれば作業は完了である。めでたしめでたし!!

以下、Sheevaplugを利用するにあたって参考になるサイトをリストアップしておく。この投稿を読んで「興味がわいたよ!」と思ってくれたギーク諸氏は、ぜひSheevaplugを試してみて頂きたい。さすがに発売からかなり経過しており、なおかつOSも標準的なLinuxなので、Sheevaplugは結構使えるというのが筆者の感想である。


PlugWiki
http://plugcomputer.org/plugwiki/

SheevaPlug@Pukiwiki
http://mizupc8.bio.mie-u.ac.jp/pukiwiki/index.php?SheevaPlug

Yu's Blog
http://notepad4yu.wordpress.com/

Hisao's Blog
http://www.alpha.or.jp/

のら犬にさえなれない
http://xeon.cocolog-pikara.com/blog/

Ubuntu Weekly Recipe: 第69回 GW特別企画・電源プラグ型コンピューターSheevaPlugの使い方(1):基礎編
http://gihyo.jp/admin/serial/01/ubuntu-recipe/0069

Ubuntu Weekly Recipe: 第70回 GW特別企画・電源プラグ型コンピューターSheevaPlugの使い方(2):インストール編
http://gihyo.jp/admin/serial/01/ubuntu-recipe/0070