corner2009年02月2009年02月28日PostgreSQLを使っている人が使いたい外部ツール前作PostgreSQLを本当に高速化したい人のための10のポイントが結構受けたようなのと、外部ツールの話が書ききれなかったので次回作を。こっちは受けないと思うが、ついでに備忘録をかねて。内容としては「RDBMSだけ使ってもどうしようもないよね」というのは多い。残念ながらL.starは、PostgreSQL本体に比べてこの種のツールの組み合わせについて精通しているとはいいがたい。「PostgreSQLとしては、こんな部分は外部ツールに任せたいよね!」という思いをまとめるように書いてみた。10000tps位平然とこなしちゃう。server数台分ぐらいのバックエンドになれるので、それで十分ではないかすら思ってしまうだろう。実際は、超大規模を想定するとまったくお話しにならない。slashdottedするような負荷は、web数台+DB1台では現実問題として到底捌ききれない。スループットの話だけなら上記で良いが、同時にレイテンシの話もしないといけない。実はRDBMSはトランザクション管理がからむため、結構レイテンシが高い。どちらかというと中スループット、高レイテンシ、高耐障害性のソフトウェアになる。高スループット、低レイテンシ、低耐障害性なキャッシュ用オンメモリDBと組み合わせるのがよい。こいつらが捌けるスループットは一桁違う。単純なkey-valueストアであるためもともとレイテンシも低く、かつ分散もきわめて容易である。最近このような形態をサポートできるフレームワークが増えているようだ。返答をキャッシュしつつ返すと言う動作をするproxyを作ったら受けるだろうか?コネクションプーリング1-Mar-2009追記:よく分からないという指摘を受けIRCで追加説明をした。それを元に修正しようとしたら、pg_pconnectその後というところで綺麗に3行でまとめられていた。以下は技術的詳細について色々書いてあるが、結論が欲しい人はそのまま上記に行って欲しい。PostgreSQLの場合、泣き所はfork()を使ってセッションを受けているところである。これにはいくつかのメリット(ここでは割愛)と2つのデメリットがある。一つはfork()がコストの高いAPIであるため、接続確立のためのコストが大きいこと。一つはプロセスというのがコストの高い資源であるため、たくさん生成すると重くなってしまうことにある。前者については、実は(スレッドを使う)MySQLよりも早いと言うデータを見たことがあるので、必ずしも今となっては当てはまらない部分がある。普通、2000プロセスも立ち上げるとLinuxが(もしLinux以外でPostgreSQL2000接続以上しても平気なOSがあったら、是非教えて欲しい。実質サービスダウンに等しい状態に追い込まれる。接続をしていると、検索している居ないにかかわらずプロセスがいるのである。pg_pconnectに気をつけろ!では、この後者の点を指摘している。pg_pconnectは前者の解決策を提供しているが、後者については考えもしないろくでもない代物である。安直な大量コネクション確保は性能劣化の原因になりかねない、と心しておくべきだろう。PostgreSQLの場合、昔は目安として256接続がこの重さに引っかかる境目だった。最近のPCではまた違う結果かもしれない。下書きをしているうちにpg_pconnectに気をつけろという話に気をつけるべき理由という対立エントリが出ている。前半の話は「負荷が下がるとプロセスも減る」という話だが、問題は負荷が高い状況の話であるため何ら議論の本質とは関係がない。pg_pconnect使うと障害対応で人間やめることになるよなどという意味不明な極論ではなくて、例えば「PHPスクリプトを動かすhttpdと画像やCSSを送り出すhttpdは別にしよう」ということだ。いうのは正論ではある。その後でPHPスクリプトが動いているhttpdの性能が逼迫したとき「DB接続を伴うphpスクリプトとそれ以外のスクリプトを動かすhttpdを分けよう」言い出すのだろうか。Javaのコネクションプーリング(あるいは相当品)は比較的しっかりしているので、最大リソースをきっちり指定できるし、接続しないプロセスまでコネクションを要求することはない。そのため、確保リソースを間違えなければおそらく大丈夫だと思われる。この管理が及ぶのも、Webサーバ1台の時に限られる。複数台ある場合には、動的に最適な接続割り振りをしつつ最大数を超えない、というような芸当は無理だ。言う場合、どこかで中央集権的な管理が可能な別のソフトウェアを使わなければならない。選択肢は2つ、pgpoolとpgbouncerである。上記エントリでも示されている、last.fmでの結果が、pgbouncerのほうがより大規模向けであることを如実に示している。Last.fm個人的にコネクションプーリングだけであれば、pgbouncerがお勧めだろう。pgpool-IIはもはやコネクションプーリングだけのソフトではないので、他のかねあいもあるだろう。正直に白状すると、本当にコネクションプーリングを使うべきかどうか、L.starはもう分からなくなってしまった。poolingはわざわざ処理をしたりロックが発生する関係上かえって遅くこともあるそうだ。本当はdeveloperWorksに良い記事があったのだが、思い出せない。覚えている人はコメントかメールをください。これは当然コネクションプーリングにも当てはまる。ポイントはコネクション生成のコストvsロック管理コストなどがどっちに軍配が上がるか、なのだ。この割合は日々変化しており、結局今のPCでコネクションプーリングすべきかどうかというと、とんと自信がない。古いシングルプロセッサ時代の昔は、確実にすべきだと言えたのだが。3/3追記:ただし、上記dWの記事でも確かに、データベースとの接続やスレッドの生成が必要なクラスオブジェクトの作成は、メモリ確保時に高い負荷がかかりますし、プール領域にオブジェクトを確保しておけば、データベースとの接続等に限られたリソースを有効に使うことができるため、この手法は有効と言えます。とあるため、やはり有効なのだろう。言いたいのは、この種のパフォーマンス趨勢はどんどん変わる。そのため特に性能面の話においては、以前正しいと思っていたことが、あっさり覆されることがあるということである。高可用性の追求RDBMSは常に高い稼働率を求められる。データストアの根幹であるから、落ちるわけにはいかない。RDBMS自体が99.99%の高可用性に対応しているようなことはまず無い。マシン単体で実現することが不可能だからだ。そのためのソフトウェアが用意されている。ソリューションや運用体制まで含めて高可用性と言うべきであろう。(例:DRBD+Heartbeat)ノンストップ型ハードウェアこのとき注意するのは、どの程度の可用性を要求するか、とどの程度の手作業を許容するか、ということである。手作業は当然復旧時間と待機の人員コストを増加させる。可用性追求のためのソフトウェア及びハードウェアはたいてい目が飛び出るほど高価である。検証が完了した組み合わせでないとトラブル頻発しまくる、ということになる。高可用性構成はとにかくノウハウがいる。スキルの高い人材を訓練育成し、テストし、環境に適合させて、その環境がきちんと動くように現場調整して初めて真の高可用性が得られる。これも根拠のない職人感覚だが、L.starの考える高可用性構成のPostgreSQLを導入したい場合、それにかかるコストは以下のようになると考えている。数千万円(ノンストップハードウェア+データセンター+それを支える運用体制)ざっくり言うと「停止時間1/10にするためには、コストは10倍掛かる」という感じである。日本人は「落ちない」を当たり前のようなことと考えているが、実際にはとても金と手間のかかるものである、というのは、プログラマだけではなく、みんなに理解して欲しいものだと思っている。コストと稼働率のかねあいについて、みんなが真剣に考えてくれればなあ、と思うのである。standby機能である。実装の手間が大きいが、これがきっちり使えるようになったら、99.9%レベルの稼働率を従来より安価に使えるようになるだろうと期待している。残念ながら原理上わずかながらのデータロスが避けられない。レプリケーションレプリケーションを使うのは高可用性と負荷分散的な両面で、である。高可用性的な面では上で述べたが、正直高可用性「だけ」を追求するのであれば、実績のある共有ディスククラスタなどを使うことを強くお勧めする。ここでは負荷分散部分を話したい。負荷分散と書いているが、ここでは「検索の負荷分散」である。レプリケーションはデータを何らかの形で複数箇所に投入する仕組みであるため、ほぼ確実に導入前より更新が遅くなる。更新の負荷分散に有効なのは、shared-nothing式クラスタリングと呼ばれる、データを複数ノードに分散して配置する方法であり、この2つは組み合わせられるが相容れないものだ。レプリケーションはいろいろな仕組みがあるが、以下のような部分に注目して選定すると良い。高可用性のところで述べたのと同じく、これもまた「ソリューション」である。ソフトは無料化もしれないが、ノウハウや人的コストは結構かかるので、覚悟すべし。範囲・・・どれだけの範囲の複製を取るか。通例クエリベースは全体を一気にできるのがメリットであり、トリガベースはテーブルごとで細かく設定できる点がよい。通常非同期のほうが色々と良い。クエリの制限が少なかったり、性能が高かったりする。データ同期が遅れるという違いだけは、アプリケーション設計で吸収しないといけない。通常レプリケーション機能には負荷分散の意味はないため、別途組み合わせる必要がある。pgpool(-II)だけは、同時に負荷分散機能を持っている。アプリケーション側でラウンドロビンを実装したり、lvsを組み合わせたり、pgpoolやpgbouncerを組み合わせる、というのはあり。場合、一部のクエリが使用できない。クエリベースはたいていシーケンスやnow(),random()のような特殊関数の取り扱いに難があり(絶対出来ないわけではない)、トリガベースではtruncateなど、トリガが動かないのにデータが変わるものがやばい。生のファイルシステム意外に思われるだろうか。RDBMSに数十KB以上の、例えば画像ファイルを格納するというのは賢明ではない。そもそも構造自体小さなレコードを格納検索するのに最適化しているのがRDBMSの歴史である。でかいファイルを入れる方法として、BLOB/CLOBのような手法も提供されているが、どうもどれもいまいちという印象がぬぐえない。そので外部ツールという話になるのだが、特に大きなファイルをkey-value形式で格納する方法として、未だにたんなるファイルシステム以上のものを見たことがない。言う目的に特化しているのだから。言うこともあり、画像ファイル等を格納する場合に別途ファイルサーバを用意しているような設計のサイトはとても多い。どの程度までのファイルを格納できるか、というのは難しい問題だ。L.starは特に根拠があげられるでもなく64KB程度と考えている。いずれにしても数百KB程度であればもうDBに置くのはつらい。たんなる格納だけと言うことであれば、あるいはとても遅くてもかまわないというのであれば、それほど問題にはならない。前述のエントリの通り「検索しないデータをRDBMS上に配置するのは無駄使い」はL.starの持論である。全文検索PostgreSQLを高速化する16のポイントでは、全文検索にはLudiaを使おう、と紹介されている。同様にtsearch2やtextsearch-jaも紹介されていて、PostgreSQLには全文検索機能があると言っても良い。ここに「全文検索」を上げるのか?なぜなら「全文検索したいデータは、たいていの場合大きい」からである。前述のファイルシステムで述べたとおり、大きいデータの格納は、RDBMSの専門分野ではない。あと、これらのIndexは残念ながら未だ枯れているとは言い難い。tsearch2はcontrib歴こそ長いが、昇格は8.2とごく最近である。Ludiaは8.3と利用するとvacuumが出来ないしろものだ。インデックスアルゴリズムの優劣については何とも言えない。個人的には例えばtsearch2よりhyperestraierのほうが高速だなと感じる。L.starのDB歴は結構古く、最初に真面目に使ったのは(PostgreSQLと同じルーツを持つ)Illustraである。10年近く前だが、日本語全文検索DataBladeを使いつつ、「うーん、あまり性能が出るものじゃないな。外部のエンジン使った方が早いわ」と思ってた。それから10年、時代の変化はRDBMSの全文検索Indexを身近なものにしている。コネクションプーリングの項では「時代の変化で分からなくなった」と書いたが、全文検索に関しては、変化によってRDBMSに組み込めるようになった代物と言えるだろう。書いているうちに気力が尽きてしまった。自分で思っているよりずいぶんPostgreSQLについて覚えていたな、と言う印象だが、とはいえ最新の、外部ツールまで含めた事情はやはりカバーできていないなぁ、と感じる。postgresqlグループ.の元エントリを読んで思うところがあったのだが、PostgreSQLを高速化する16のポイントだからそんなせまっくるしいところでトンチンカンにdisる暇あるんだったら自分のブログでお好みの議論を書くかさもなきゃ/dev/nullにでも吐けとやんわりと言ってるんだよハゲ。