キャッシュしてもいいHTMLを返すCGIであれば、以下のようにすることでレスポンスがとても高速になる
coreserverとかcoreserverとか、fastcgiが使えないので考えた苦し紛れではあるが用途によってはかなり効果がありそう
- mod_rewriteでキャッシュがあるかを判別し、あればキャッシュを返し、なければCGIに処理が渡る
- CGIはHTMLを生成し、キャッシュを出力してからHTMLを返す
- キャッシュはCronで定期的に削除される
メリットは「キャッシュがあればCGIを立ち上げる必要がない」こと
mod_rewriteはapacheでの処理なので、キャッシュのレスポンスは静的なHTMLと同じ
また要求があった際にのみCGIでHTMLが生成されるので、ページ数が大量であっても全部を最初に生成したりする必要がない
があるとして
Options +ExecCGI AddHandler cgi-script .py RewriteEngine On #とりあえずキャッシュのパスに書き換える RewriteRule ^hoge/([0-9a-z]*([0-9a-z])([0-9a-z]))/$ cache/hoge/$2/$3/$1 #mime-typeを設定 RewriteRule ^cache - "[T=text/html;charset=utf-8]" #キャッシュが存在していないなら RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} !-s #hoge.pyにパスを書き換え RewriteRule ^cache/hoge/[0-9a-z]/[0-9a-z]/([0-9a-z]+)$ hoge.py&page=$1 [L]
hoge.py
def putCache(data, key): #keyは36進数 key = '0' + key import re cpath = re.search( '^[0-9a-z]*([0-9a-z])([0-9a-z])$', key ) cp1 = cpath.group(1) cp2 = cpath.group(2) import os root, d = os.path.split( os.path.abspath(__file__) ) path = os.path.join( root, 'cache', 'hoge', cp1, cp2, key ) fo = file( path, 'wb' ) fo.write( data ) fo.close()
こんな感じで
gzipもついでにしておく場合は
def genGZ(html): import cStringIO import gzip gzbuf = cStringIO.StringIO() gz = gzip.GzipFile( mode = 'wb', fileobj = gzbuf, compresslevel = 9 ) gz.write( html ) gz.close() data = gzbuf.getvalue() return data def resGZ(data): print 'Status: 200 OK' print 'Content-Type: text/html; charset=utf-8' #rewriteのForceMIMEで上書きされる print 'Content-Encoding: gzip' print 'Content-Length: %d' % (len(data)) print '' print data
この場合、キャッシュはContent-Encodingが出力されないので化ける
/cache/.htaccess
Header set Content-Encoding "gzip"
を作るとOK
デメリットは
- htaccessを触るのでこのあたりを書き換えるときにミスがあるとサイト全体が500になる
- Cronで定期的にキャッシュを削除しないといけない
ぐらいかな
おまけ
/cache/〜/[0-9a-z]/[0-9a-z]/を作る
dirs = ['hoge', 'foo', 'bar'] root = os.path.dirname( os.path.abspath(__file__) ) for dir in dirs: for i in xrange(36): for j in xrange(36): path = os.path.join( root, 'cache', dir, to36(i), to36(j) ) #to36で36進数に os.makedirs(path)