まだ重たいCMSをお使いですか?
毎秒1000リクエスト を捌く超高速CMS「adiary

2006/06/23(金)6/23版スナップショット

スケルトンコンパイラの改良

スケルトンコンパイラをさらに改良しました。今回の変更は多大な労力を割いた割に、テスト環境においてたった1msしか高速化しませんでした*1。コンパイル時間は絶対遅くなっていると思いますが……、1度コンパイルすればキャッシュされるので気にしない方向で(汗)

しかし、スケルトンシステムの仕様は、後々コンパイラ次第である程度性能を改善出来るよう設計していました。今回たまたま気になって、泥沼に入ってしまったのですが、改良に改良を重ねた遍歴で用のない(スマートでない)コンパイル処理を何度も行っていたためスリム化。

とか言いながらパスは7パスになりましたけど……(^^;

newコンパイラ@VIA C3

VIA C3@500 という、とてつもなく環境にやさしい(遅い)CPUで今回の変更を試してみました。非キャッシュ環境(cgi動作)ではそこそこでしたが*2、キャッシュされた環境(mod_perl2 or SpeedyCGI)で実行してみたら、びっくり!!

Total time : 39.3 ms

とても C3@500MHz とは思えないレスポンスをたたき出しております(笑)*3

*1 : 27.1ms → 21.5ms → 20.1msというわけで最初から考えると、約25%の実行速度改善

*2 : 古いsnapshotと比較したら850ms→650msぐらい。バラ付きが大きいのと同じ条件ではないのでうまく比較できない

*3 : 体感速度が明らかに違いますもん(^^;

2006/06/10(土)プログラムの実行速度と形式美

またもデータベースカラム追加

adiary ては、各ユーザーあたり3つのテーブルを使用しています。

  1. 日記本文のテーブル
  2. コメントのテーブル
  3. トラックバックのテーブル

従来から、日記本文のデータの中に、その日記に付いたコメント数やトラックバック数というデータを持たせていました。データベースの正規化の立場からすると、やってはいけないことなのですが、アクセスの度にいちいちSQLで集計とってたら遅くてかなわないということで。

今ではそれを逆に利用して、コメント数やトラックバック数が0のときは、そもそもコメントやトラックバックをロードするSQLを発行しないようにしています。

さらに一歩進めて。今回、コメントの一覧やトラックバックの一覧を機能をつける際*1、コメントごとに元記事のタイトルやら日付やらを引っ張ってくるようにしました*2。ですが、たかだか元記事の「日付」と「タイトル」だけを取得するために、コメント1件につき1回SQLを発行するのはなんとも効率が悪すぎる。

今回の変更で、コメントテーブル、トラックバックテーブル双方に元記事の「日付」と「タイトル」を保存するようにしました。せっかく正規化されているデータを分散させるなんて「なんてことだ!」とか言われそうですし、不整合が起こらないように管理するのが面倒ですが、背(形式美)に腹(処理速度)は代えられません

実はadiaryには、処理速度や見通しのために、プログラムの重複記述*3を敢えて行っている箇所が何カ所かあります。

*1 : 最近のコメント、最近のトラックバックでも同様に使用しています

*2 : つまり、コメントが参照している日記キー(diary_pkey)から日記本文をjoin……なのですが、擬似データベースも使えるようにする都合上、データベースではjoinせずにプログラム側でjoin相当の処理をしていました

*3 : ルーチン化可能だけど敢えて行っていない

よくみるプログラムたち

1.一本道プログラム

要求された処理を満たすようにだけ書かれた、能率も形式美も何もない「のっぺり」としたプログラム。いわゆる「プログラムを書ける人」の7割ぐらいが*4、こういうプログラムを書きます。

必要な処理が順列組み合わせで、なんの抽象化も、構造モデリングもなされずに記述され、大抵の場合はメンテ不可能なまでに*5巨大化し、下手をしたら1/3のソース量で同じ処理が書けるんじゃないか? と思えるものです。

2.形式美プログラム

機能ごとにソースが分離され、処理はきれいなまでに抽象化され、またはクラス化(オブジェクト指向)が徹底されて、非常に美しいプログラム。である反面、メモリの多重確保やメモリ間コピーなどは意図にも介さない。

事務系のプログラムやミッションクリティカルなプログラム(たとえば銀行システムや金銭を扱うような通販システム)では能率なんて求めず安全第一で書くべきだけど、処理速度や処理効率が(極端に)求められるプログラムである場合はときとして失格*6。頭の良い人がプログラムを教科書的に学んだ際に陥りやすい。

3.効率主義プログラム

自分はこのタイプ。限られたリソースや有限な資源を用いて、または計算量がNPであるような大問題を効率よく求めたときなどに書くプログラム。一見するとタイプ1の「一本道プログラム」と似て映るが、きちんと眺めれば効率を求めたものか、何も考えずに書きつづったものかは一目瞭然。

また、形式美をある程度理解した人間が書いた効率主義プログラムと、そうではない効率主義プログラムではメンテ性という意味で大きな差が出てくる。実行効率は形式美とある程度両立可能であるが、たまに調子に乗って必要以上に高効率を求め*7無駄にソースが見づらくなることもある(T-T

4.adiaryは?

  1. perlがあればどこでも動くという汎用性
  2. 抽象化され、差し替え可能な構成と形式美
  3. それでいて限定された環境でも高速に動くこと(cgi動作 & pure perl)
  4. 恵まれた環境ではさらに高速に動くこと(mod_perl2 or SpeedyCGI)

の優先度で作成されています。

*4 : とくにプログラムを学んだのではなくプログラムを教えてもらった人間に多い

*5 : メンテするぐらいなら最初から書き直した方がよっぽど速いし

*6 : 美しく書けば雑然と書くよりは普通に速いので、よっぽど速度重視な場面以外ではあまり構わない

*7 : ワンパスしか処理しないような場所で不必要な最適化をするとか