MySQL Users Conference Japan 2007 講演概要

こんにちは。ガルーン開発グループの米川です。

9 月 11 日 ~ 12 日に、日本科学未来館にて MySQL Users Conference Japan 2007 が開催されました。

私は 12 日に「サイボウズの MySQL に対する取り組み」というタイトルで、 MySQL のスケールアウトと全文検索エンジンの導入について講演をさせていただきました。 今回は、その講演内容と資料を公開いたします。

PDF 版 ダウンロード : MySQL Users Conference Japan 2007 講演資料 ( 1.4MB )

大規模利用環境でも快適に利用できる製品を目指して

弊社が開発・販売している中堅~大企業向けグループウェア「サイボウズ ガルーン 2」では、 データベースエンジンに MySQL を採用しています。

現在のバージョン ( 「ガルーン 2」2.1.3 ) では、 グループウェアを快適に利用できる状態として、分間 1,500 アクセス程度の利用頻度を目安としています。

これを、次期バージョンでは分間 5,000 アクセス程度でも快適に利用できるよう 開発を進めているところです。

また、全文検索エンジンの Senna を組み込み、 グループウェア内の各アプリケーションにある情報を横断的に検索できるようにします。

070919ph.jpg

全文検索エンジンの導入

現在のバージョン ( 「ガルーン 2」2.1.3 ) ではグループウェア内に保存されるデータが増えるにつれて、 検索の処理スピードが徐々に遅くなっていきます。

この原因としては、検索実行時の SQL に LIKE 文を使用していること、 また、データに対する「アクセス権」を評価するために複雑な SQL 処理が発生することが挙げられます。

まず、LIKE 文を使用した検索処理時間の問題については、 全文検索エンジンを導入することで解決することにしました。

全文検索エンジンには、インターネット全体、イントラネット内、アプリケーション内と、 検索対象(範囲)別にいくつかの製品があります。

その中でサイボウズでは、アプリケーションからは その存在を意識することなく利用できる点などが優れている Senna を採用しました。 また Senna の MySQL バインディングとして Tritonn を利用しています。

次に、アクセス権の評価の処理については、 検索対象のデータとそれに対するアクセス権の情報を事前に収集するようにし、 ユーザーによって検索が実行されるタイミングではアクセス権の評価処理を行わなくて済むようにしました。

このデータ収集のためのクローラは、定期的にアプリケーション ( ここでは「ガルーン 2」) に 新規追加または変更修正されたデータがないか問い合わせを行い、 そのようなデータがあれば、そのデータ本体とアクセス権の設定情報を取得します。

データ本体はキューにためられ、インデクサによって順に Senna 用の index として登録されていきます。 その際、データファイルをテキスト抽出フィルタに通し、 表計算ソフトのデータや発表スライド内の文字列も検索対象として登録されるようになっています。

スライド16 : データ収集エンジンのスライド画像
スライド 16 : データ収集エンジンのスライド画像
( 画像クリックで拡大表示 )

検索エンジンは、アプリケーション側の各ユーザーから呼び出され、 API 経由で検索を実行し、アプリケーションに結果を返します。

スライド 17 : 検索エンジンのスライド画像
スライド 17 : 検索エンジンのスライド画像
( 画像クリックで拡大表示 )

この全文検索エンジンは今回「ガルーン 2」のために開発されましたが、 各機能を API 化しているため他の環境からも利用可能なものになっています。

また Tritonn の進化により、マルチセクション機能の利用や NGRAM の文字種分割の制御が可能になりましたので、こちらの利用も現在検討をしています。

大規模企業での利用を実現するためのスケールアウト

これまでの「ガルーン 2」( バージョン 2.1.x ) では、 負荷分散のために Web サーバを複数台構成にして運用することは可能ですが、 データベースサーバを複数台立てて運用することはできませんでした。 そのため、データベースサーバの性能が事実上のパフォーマンスの上限となっていました。

そこで、次期バージョンでは、データベースサーバの複数台構成を実現し ( アプリケーション単位で分散 )、 また、ユーザー単位でテーブル分割をし、そのテーブルを分散配置できるようにしました。

また、キャッシュサーバ ( Memcached ) を搭載し、データベースサーバへの負荷を軽減するようにしています。

パフォーマンス改善への取り組みを、時系列にそってご紹介します。

機能単位の DB 分散

まずは、利用時に高い負荷が発生するアプリケーションのテーブルを、 別のデータベースサーバに分散配置できるようにしました。

これにより、ユーザー企業様のアプリケーション別の利用頻度・利用特性に合わせて サーバ構成をカスタマイズすることが可能になります。

その際、各アプリケーションから参照される「ユーザー情報」や「組織情報」などの全アプリ共通の情報については、 更新処理を常にマスタサーバに対し行うようにし、 MySQL のレプリケーション機能を利用して、マスタサーバと分散用の各サーバの同期をとっています。


スライド 32 : 機能単位の DB 分散のスライド画像

スライド 32 : 機能単位の DB 分散のスライド画像
( 画像クリックで拡大表示 )

クエリチューニング

次に、純粋なパフォーマンスチューニングとして、スロークエリログに出現した処理の遅いクエリの見直し、 インデックスの追加や張り直し、非正規化などを行い、処理速度が向上するようにしました。

Memcached の導入

上記チューニングにより、重いクエリを排除することはできたのですが、 今度はクエリの数が問題になってきました。

そこで、データベースサーバへの負荷を減らすために、 更新の少ないデータについてはキャッシュをし、クエリの数を減らすようにしました。

Memcached は、複数のサーバ構成にして Memcached 自体の処理の負荷を分散させることができます。 その際、ある Memcached サーバがダウンしても、自動で他の Memcached サーバにアクセスしにいくという、 フェイルオーバー機能が実装されています。

この機能は便利である一方、以下のような状態になり不整合が発生したこともありましたので、 注意が必要です。( この問題は、PHP の Memcache 関数側の実装問題かもしれません。)

  • サーバ A が key = value 1 を保持
  • サーバ A がダウン ( key = value 1 消失 )
  • サーバ A の代わりとして、サーバ B が key = value 2 を保持
  • サーバ A が復帰
  • サーバ A が key = value 3 を保持
  • 再度サーバ A がダウン ( key = value 3 消失 )
  • key の情報が参照され、サーバ A の代わりとして、サーバ B が古い情報 key = value 2 を返す
  • 不整合発生 ( key = value 3 が返されるべき )
ユーザー単位のテーブル分割

以上のパフォーマンス対策により、各アプリケーションの負荷状況に応じて、 バランス良くサーバの構成を組むことが可能になりました。 しかしこの仕組みでは、1 つのアプリケーションに対してアクセスが集中した場合には、やはり処理が重くなります。

利用可能なユーザー数が増えれば、その分 1 つのテーブルに保持するレコード数が増えますので、 ある 1 つの情報を参照するためにテーブルを開くのにも、次第に時間がかかるようになります。

また、各アプリケーションから共通で利用されるアプリケーション ( 具体的には、各アプリケーションにおける新着・更新の情報を伝える「通知」アプリケーションなど ) の 処理もユーザー数の増加に比例して重くなり、対策を講じる必要が出てきました。

そこで、これらのアプリケーションで利用するテーブルをユーザー単位で分割しました。 さらに、この分割したテーブルをデータベース間で分散配置できるようにもしました。

ユーザー ID の範囲を指定することによって、 どのユーザーがどのデータベースサーバを利用するかという設定を行えるようにしましたので、 負荷の低いサーバに多くのユーザーテーブルを割り当てるような構成も可能になっています。

setting.ini のサンプル
memcache_host = host1,host2
mysql_master_host = host3
 ...
mysql_schedule_host = host4
 ...
mysql_notification_host1-1000 = host3
mysql_notification_host1001- = host4

この設定はインストール時に行い、 以後アプリケーション利用時には、接続先情報が書かれた設定ファイルを参照し接続、情報を取得・更新します。

この分割処理により、かなり柔軟なサーバ構成の設計が可能となり、 分間 5,000 アクセス程度でもストレスなく利用できるようになりました。

今後の課題と展望

これまでご紹介してきた方法で、スケーラビリティとパフォーマンスの向上を図ってきましたが、 まだ改善していきたい課題点もあります。

複数のデータベースサーバに対する処理のパフォーマンス

データベースサーバの複数台構成の実現やテーブル分割を行いましたので、 これまで 1 つのクエリで済んでいた処理が、複数のクエリで処理しなくてはならない場合がでてきました。 このクエリ数の増加により、データベース単体構成の場合に比べて処理に時間がかかる場合があり、この点は現在改善に向け注力しています。

分割により大量に作られるテーブルへの対策

ユーザー単位でテーブル分割を行ったことで、 例えば、ユーザー情報マスタテーブルには大量のリレーションが張られた状態になっています。

MySQL では、このようなテーブルに起動後最初にアクセスした際、 リレーションが張られているテーブルをすべてなめる処理 ( テーブルキャッシュにテーブル情報を格納する処理 ) が走るため、結果を返すのに時間がかかるという問題があります。こちらも現在対応策を検討しています。 ( リレーションを張っているテーブルにリレーションが張られていると、そのテーブルにも同じ処理が走ります。 )

また、パフォーマンスの向上に使える機能はないか、 MySQL の開発の動向は常にチェックをしています。

現在は MySQL 5.1 の次の機能を利用して性能改善ができないか、注目しています。

  • パーティショニング
  • 行ベースレプリケーション

ここまで、サイボウズの MySQL への取り組みについてお伝えしてきました。

弊社では現在、データベースエンジニアの採用の募集をしております。 採用情報ページに詳細がありますので、ぜひご覧ください。

腕に自信をお持ちの方の多数のご応募をお待ちしております。

070919auth_ph.jpg

MySQL Users Conference Japan 2007
「サイボウズの MySQL に対する取り組み 」
講演者 :
丹羽 純平 ( 開発本部 プロダクト開発部 ガルーン開発グループ ) : 写真右
米川 健一 ( 開発本部 プロダクト開発部 ガルーン開発グループ ) : 写真左