MySQLのシステムアーキテクチャはじめに本稿では、MySQLの内部構造を見ていきます。MySQLサーバのさまざまな部分がどのように連携して動いているかを知ることは、楽しくてためになります。MySQLの実装は、テクノロジーの魅惑的な組み合わせです。このテクノロジーは、おびただしい数の開発者の長年にわたる汗とインスピレーションから生み出された、真に目覚ましい功績にほかなりません。 オープンソーステクノロジーの楽しみの1つは、それがオープンソースであるという、まさにその点にあります。MySQLのような巨大なシステムのソースコード(※1)を見ると、そのソフトウェアの進化の過程で開発者たちが直面したジレンマを深く理解することができます。本稿では、サーバ自体のソースコードを詳細に検討していくので、どうぞ心してお読みください。たとえ何も手を加えるつもりがなくても、ソースコードを見てみることをお勧めします。それによって、MySQL ABの開発チームが取り組んでいる作業の途方もない大きさを認識できるようになるだけでなく、このソフトウェアがどのように機能しているか、ひいてはMySQLの長所を最大限に活用し、弱点を回避するために自分のプログラムをどのように最適化すればよいかをより深く理解できます。 ※1
執筆時点で、MySQLサーバはざっと50万行のソースコードで構成されています。
本稿で説明する内容は、MySQLデータベースサーバーシステムの内部構造のドキュメント、および実際のソースコードが基になっています。MySQLのコードリポジトリは絶えず進化しているので、ここで説明するデザイン機能の一部は現在では変化している可能性があり、今後も時間の経過とともに変化し続けると思われます。バージョンの異なるソースコードを見比べると、サブシステムの実装や相互関連の方法に違いがあることに気付くでしょう。しかし、システムの全般的な機能の大部分は、ソフトウェアの進化を通じて維持されています。 ここで扱う内容の大部分は、Cプログラミングの達人でなくても理解できるはずです。ここではコード自体よりも、サーバ内部の処理の構造と流れや、さまざまなコードライブラリが互いにやりとりするしくみに重点を置きます。本稿の目的は、読者が自分でソースコードやドキュメントを見て回れるように、基本的なロードマップを示すことです。ただし、一部のセクションには、CおよびC++プログラミングのかなりの知識を必要とする上級者向けの内容も含まれます。Cプログラミングの経験が浅い読者は、あまり気にせずに、できる範囲で理解するよう努めてください。 MySQLのソースコードとドキュメントここではMySQLサーバのソースコードを扱うので、本稿の説明を理解し、自らコード調査の冒険に乗り出すために、MySQLの最新のソースコードをダウンロードする必要があります。本稿で使うソースコードは、バージョン5.0.2のソースコードが基になっています。ソースコードをダウンロードするには、MySQLのダウンロードサイトにアクセスし、目的のバージョンをダウンロードします。 注意
本稿で分析に使ったソース配布物は、5.0.2-alphaソースツリーから取得したものです。MySQLは絶えず進化しているソフトウェアであるため、本稿で説明しているさまざまな実装の詳細は、時間の経過とともに変化する可能性があります。必ず適切なバージョンのソースの開発ドキュメントを入手してください。
ソースコードソースコードは、MySQLサーバの主要なライブラリと、各種の拡張機能が含まれる浅いディレクトリツリーで構成されます。 トップレベルのディレクトリ表1に、トップレベルの主要なすべてのディレクトリと、各ディレクトリにあるファイルの簡単な説明、およびファイルの一般的な用途を示します。以降の説明では、この表に示す情報を、各サブシステムに関連するより小さなグループに分類していきます。この大きな表をリファレンスとして使用するとよいでしょう。 表1 ソースツリーのトップレベルのディレクトリ
ここで少し時間を取り、ソースコードを見て回って楽しんでもかまいませんが、きっとすぐにソース配布物を構成するクラス、構造体、およびC関数の迷路で迷子になってしまうでしょう。最初に参照すべき場所は、/Docsディレクトリにある配布物のドキュメントです。その後で、本稿の説明に従って主要なサブシステムや、さまざまなシステム機能に対応するコアファイルがある場所を見ていきます。 CおよびC++のプログラミング用語 本稿では、CおよびC++のさまざまなプログラミングパラダイムを扱います。Cのソースコードファイルは、配布物の中で「.c」という拡張子が付いているファイルです。C++のソースファイルには「.cc」という拡張子が付いていますが、Windowsの一部のシステムでは「.cpp」という拡張子が付いている場合もあります。CとC++のどちらのソースファイルでも、「.h」という拡張子を持つヘッダーファイルを 通常、ヘッダーファイルにはソースファイルと同じ名前を付けて「.h」という拡張子を付けますが、必ずしもそうでないこともあります。システムのソースコードを見るときに最初にすることの1つは、変数と関数が「どこで」定義されているかを確認することです。ときには、ヘッダーファイルの広大な階層を調べて、変数や関数がどこで公式に定義されているかを見つけることが必要になります。 当然、読者は変数や関数がどのようなものかをよく知っているはずなので、ここではあまり詳しく解説しません。ただし、CおよびC++のプログラミングでは、それ以外のデータ型と用語が頻繁に使われます。特に、本稿では次の用語を使います。
「構造体」は、本質的に一連のデータのコンテナです。構造体は一般に次のような形で定義されます。 typedef struct st_heapinfo /* Struct heap_info */ { ulong records; /* Records in database */ ulong deleted; /* Deleted records in database */ ulong max_records; ulong data_length; ulong index_length; uint reclength; /* Length of one record */ int errkey; ulonglong auto_increment; } HEAPINFO; ここに示したのは、/include/heap.hで定義されている構造体です。ここでは、 一方、「クラス」はCの構造体に似たC++のオブジェクト指向構造ですが、「メンバ変数」の他に「メンバメソッド」を持つことができます。メンバメソッドはクラスの関数で、クラスの「インスタンス」を通じて呼び出すことができます。 ソースコードの分析に役立つDoxygenソースコードの分析には、Doxygenなどのツールを使うことをお勧めします。Doxygenを使うと、ソース配布物からコードの構造を調べることができます。このツールは、MySQLのように、1つの実行処理で何百ものクラスメンバと関数を呼び出す巨大なソース配布物の関数を調査するのにきわめて有効です。ドキュメント形式の出力を見ると、クラスや構造体がどこで定義され、どこで実装されているかがわかります。 Doxygenでは、このツールで生成されるドキュメントの出力形式を必要に応じて設定でき、UMLの継承図やコラボレーション図を生成することさえできます。ソースコード内のクラス階層を示すだけでなく、関数が定義および実装されている場所へのリンクも生成できます。 Unixマシンでは、DoxygenのWebサイトからソースコードをダウンロードし、手順に従ってインストールします(インストール方法の説明もWebサイトから入手できます)。グラフィカルな出力を生成するには、先にGraph Visualizationツールキットをhttp://www.graphviz.org/からダウンロードしてインストールします。Doxygenをインストールしたら、次のコマンドを実行し、Doxygenが処理するデフォルトの設定ファイルを作成します。 # doxygen -g -s /path/to/newconfig.file # doxygen </path/to/config-file> 参考のために、MySQL 5.0.2のDoxygenの出力例をhttp://www.jpipes.com/mysqldox/で公開しています。 MySQLのドキュメントシステムの内部構造のドキュメントは、MySQLのソースコードをダウンロードすると利用できるようになります。ファイルはソースツリーのDocsディレクトリにあり、「internals.texi」というTEXIドキュメントになっています。 このTEXIドキュメントでは、次のトピックが詳しく説明されています。
内部構造のドキュメントは、サーバの特定の主要な要素(特にクエリオプティマイザ)を調べるうえで非常に役立ちますが、各サブシステムが相互にやりとりする方法には直接触れていないことに注意してください。このやりとりの方法を調べるには、ソースコード自体と開発者のコメントを確認する必要があります(※2)。 ※2
サブシステムの通信の変化に対応できるように、開発者が通信に関する説明を意図的に省いたかどうかが議論を呼ぶところです。
注意
最新の「internals.texi」ドキュメントにも、誤ったハイパーリンク、参照、および不正確なファイル名やパスが数多く含まれるため、すべての内容をそのまま受け入れずにきちんと確認する必要があります。「internals.texi」ドキュメントは、使用しているMySQLサーバのバージョンよりも古いことがあります。
TEXIおよびtexi2htmlの表示TEXIはGNU標準ドキュメント形式です。さまざまなユーティリティを使い、TEXIのソースドキュメントを他の(おそらくもっと読みやすくて移植性のある)形式に変換することができます。Emacsやそれに類するエディタでは、TEXI形式を読みやすくするTEXIメジャーモードがサポートされています。 HTML形式で表示したければ、texi2htmlという無料のPerlベースのユーティリティを利用できます。このユーティリティでは、TEXIのソースドキュメントから、非常に柔軟な設定ができるHTML出力を生成できます。texi2htmlはhttp://cvs.savannah.gnu.org/viewvc/texi2html/texi2html/からダウンロードできます。このユーティリティをダウンロードしたら、次のような方法でインストールします。 # tar -xzvf texi2html-1.76.tar.gz # cd texi2html-1.6 # ./configure # make install ここでは、執筆時点の最新版のtexi2htmlを展開し、Linuxシステムにインストールしています。次に、ソース配布物に含まれる「internals.texi」ドキュメントのHTML版を生成します。 # cd /path/to/mysql-5.0.2-alpha/ # texi2html Docs/internals.texi このコマンドを実行すると、ソースツリーの/Docsディレクトリに「internals.html」という新しいHTMLドキュメントが生成されます。これで、内部構造のドキュメントをWebブラウザで参照できるようになります。参考のために、このHTMLドキュメントもhttp://www.jpipes.com/で公開しています。 MySQLのアーキテクチャの概要MySQLのアーキテクチャは、相互に関連する関数セットの集まりで構成されます。これらが連携し、データベースサーバのさまざまな要求を満たします。多くの著者が、これらの関数セットは実際にはコンポーネント、つまり完全にカプセル化されたパッケージであることを示唆しています(※3)。しかし、ソースコードにはこれが事実であることを示す証拠はほとんどありません。 ※3
たとえば、Vikram Vaswani著『MySQL: The Complete Reference』(McGraw-Hill/Osborne)やhttp://wiki.cs.uiuc.edu/cs427/High-Level+Component+Diagram+of+the+MySQL+Architectureを参照してください。
たしかに、このアーキテクチャには類似のタスクを処理する関数から成る独立した関数ライブラリが含まれています。しかし、従来のオブジェクト指向プログラミングの意味での、完全なコンポーネントレベルの機能の分離は行われていません。ですから、ソースコードでBufferManagerやQueryManagerというクラスを探しても期待を裏切られることになります。そのようなクラスは存在しないからです。一部の開発者、特にJavaの経験を持つ開発者にとっては、クライアントオブジェクトの要求をオブジェクト中心のアプローチで満たすために各種の「マネージャ」オブジェクトを含むコードを書くのが普通のことになっていますが、MySQLでは状況が異なります。 場合によっては、特にクエリキャッシュやログ管理サブシステムのソースコードでは、オブジェクト指向に近いアプローチを取っていることがあります。しかしほとんどの場合、MySQLのシステム機能は、各種の関数ライブラリ(構造体のコアセットの引渡しを担当)とクラス(コード実行の詳細を担当)を通じて実行されます。カプセル化されたアプローチのような、コンポーネント自身が内部の実行を管理し、他のコンポーネントに対してAPIを提供するという形は取りません。 その理由の1つとして、システムアーキテクチャが複数の言語で書かれており、CとC++の両方のソースファイル、およびユーティリティとして機能する多数のPerlおよびシェルスクリプトで構成されていることが挙げられます。CとC++では機能上の特性が異なります。C++は完全なオブジェクト指向言語で、Cは手続き型に近い言語です。MySQLのシステムアーキテクチャでは、特定のライブラリがすべてCで書かれているため、オブジェクト指向のコンポーネント型のアーキテクチャを実現することはほぼ不可能です。もちろん、サーバーサブシステムのアーキテクチャはパフォーマンスと移植性の問題にも大きくかかわっています。 メモ
MySQLは絶えず進化しているソフトウェアなので、コーディングや命名のスタイルと整合性にばらつきがあります。たとえば、古いMyISAMハンドラファイルと新しいクエリキャッシュのソースファイルを見比べると、命名規則、開発者のコメントの付け方、および関数名の基準に著しい違いがあることがわかります。しかも、本書の印刷間際になって、MySQL 5.1ではディレクトリ構造とソースレイアウトが大幅に変更されるという噂が流れています。
さらに、ソースコードや内部構造のドキュメントを分析すると、コンポーネントやパッケージについて言及されている部分がほとんどないことがわかります(※4)。代わりに、さまざまなタスク関連の機能についての記述が見つかります。たとえば、内部構造のTEXIドキュメントでは「オプティマイザ」に言及していますが、ソースコードにはOptimizerという名前のコンポーネントもパッケージもありません。代わりに、内部構造のTEXIドキュメントには、「オプティマイザは、RDBMSでクエリ用にどの実行パスを選択すべきかを判断する一連のルーチンである」と記載されています。わかりやすくするために、ここでは関連する一連の各機能を「コンポーネント」ではなく「サブシステム」と呼ぶことにします。そのほうが、さまざまな関数ライブラリの構成をより正確に表しているように思われるからです。 ※4
/sql/mysqld.cppの
init_server_components()関数は奇妙な例外です。ただし実際には、このメソッドはいくつかの機能サブシステムの起動時に実行され、ストレージハンドラとコアバッファを初期化します。各サブシステムは、サーバの他のサブシステムからの情報を受け付けるとともに、他のサブシステムにデータを提供するように設計されています。これを標準的な方法で行うために、これらのサブシステムは明確に定義された「関数アプリケーションプログラミングインターフェイス(API)」を通じてこの機能を公開します(※5)。サーバのパイプラインを通じて要求とデータが送られると、サブシステムはこれらの明確に定義された関数とデータ構造を介して相互に情報をやりとりします。ここでは、それぞれの主要なサブシステムについて考察しながら、これらのデータ構造とメソッドの一部を見ていきます。 ※5
この抽象化により、通常は、関連する関数セットが相互に疎結合(つまり依存)するようになります。いくつかの例外を除き、MySQLのコンポーネントはおおむね疎結合です。
MySQLサーバのサブシステムの構成MySQLサーバーアーキテクチャの全体の構成は、レイヤー型ではあるものの、特に階層型ではない構造をしています。ここでこのような区別をしているのは、MySQLサーバーアーキテクチャのサブシステムが互いにまったく依存していないからです。 階層型の構成では、コンポーネントがツリー状の一連のクラスから派生するため、サブシステムは互いに依存して機能します。たしかに、一部のサブシステム(特にSQL解析および最適化サブシステム)内にはツリー状のクラスの構成がありますが、サブシステム自体は階層型の配置に従っていません。 基本関数ライブラリおよびサブシステムの特定のグループは、低レベルの処理を担っています。これらのライブラリとサブシステムは、ストレージエンジンシステムの抽象化をサポートする役目を果たしています。ストレージエンジンシステムは、要求側のクライアントプログラムにデータを提供します。図1に、このレイヤー構造の全体図とそれらのサブシステムを示します。 クライアントプログラムがストレージエンジンの抽象化されたAPIとやりとりしている点に注意してください。これにより、クライアント接続はストレージエンジンに依存しないステートメントを発行することができます。つまり、クライアントはどのストレージエンジンがデータ要求を処理しているかを知る必要がありません。InnoDBとMyISAMのどちらのレコードを取得する場合でも、クライアントに特別な機能は必要ありません。このしくみのおかげで、MySQLではさまざまなストレージ要件とメディアに合わせて機能を拡張することができます。 基本関数ライブラリMySQLのすべてのサブシステムは、共通関数の基本ライブラリを共有して使います。これらの関数の多くは、サブシステム(および開発者)がオペレーティングシステム、メインメモリ、または物理的なハードウェア自体を直接操作せずに済むようにするために存在しています(※6)。さらに、基本関数ライブラリによって、コードの再利用と移植が可能になります。この基本ライブラリの大部分の関数は、/mysysおよび/stringsディレクトリのCソースファイルにあります。表2に、この基本ライブラリのコアファイルと場所の一部を示します。 表2 関数の一部のコアファイル
※6
ただし、特定のコンポーネントやライブラリは、パフォーマンスやその他のメリットを実感できる場面では、引き続きオペレーティングシステムやハードウェアを直接操作することになるでしょう。
まとめデータベースサーバの内部構造の世界への小旅行をお楽しみいただいたでしょうか。本稿では、MySQLのソースコードを手に入れる方法と、ドキュメントをさまざまな形式で設定および取得する方法を紹介しました。次に、サーバのサブシステムの全体的な構成の概要について説明しました。
本稿はMichael Kruckenberg、Jay Pipes共著『Pro MySQL』(Apress、2005年7月、ISBN:159059505X)第4章からの転載です。出版社の許可を得て転載しています。
著者紹介Mike Kruckenberg(Mike Kruckenberg)
古くからのMySQLの愛好者で、Webベースのアプリケーションの初期の時代からMySQLを公私ともに利用してきた。本業で長年にわたってMySQL全般の大黒柱となってきただけでなく、MySQLコミュニティの活発なメンバーでもある。『Pro MySQL』の共同執筆の他に、『MySQL Cluster Certification Study Guide』の共同執筆もしており、『Linux Magazine』誌ではMySQL関連の記事を定期的に書いている。MySQLのソースコードの変更を扱った近日刊行予定の書籍『Expert MySQL』(Apress)では技術レビューを担当。「MySQL Speakers, Writers, and Experts Guilds」のメンバーとして、技術カンファレンスで定期的に講演を行い、mike.kruckenberg.comではMySQLやその他の(大半は)技術的な事柄について精力的に記事を書いている。
Jay Pipes(Jay Pipes)
MySQLのNorth American Community Relations Manager。『Pro MySQL』(Apress、2005年)の共同執筆者で、『Linux Magazine』誌でも記事を書いている。また、ソフトウェア開発者がMySQLを最も有効に活用する方法を見いだすための支援を定期的に行っている。MySQL Users Conference、RedHat Summit、NY PHP Conference、OSCON、Ohio LinuxFestなどで、パフォーマンスチューニングに関する会議を開催してきた。現在は妻のJulie、および4匹のペットとともにオハイオ州コロンバスに在住。ありあまるほどの自由時間に、腹を空かした2匹の猫と騒がしい2匹の犬に邪魔されていなければ、PHPコードの空想にふけり、_clone()の分岐について熟考している。
|