キャッシュの導入について考えたこと、試したことなどメモ。
キャッシュ機構の導入
CMSの場合、主なI/Oは
- RDBMSへのアクセス
- 画像やjs/cssなどアセットの取得
の二つ。後者はnginxなどのフロントエンドサーバで対処すべきことと思われるのでSashimiでは扱わない。
RDMBSへのアクセスでは、ブログという特性上
- 少数の人気記事にアクセスが集中する(Zipf's law)
- データサイズは小さい(テキストデータ)
という感じだと思われる。
サイズが小さいのでRedisなどの外部キャッシュサービス(KVS)を使用するメリットはあまり無いと思われる。RDBMSにはそもそもキャッシュ機構が備わっている(クエリキャッシュとか)ので、Redisを使用した場合とRDBMS任せにした場合とで、性能に大差は無いだろうと予測。
というわけで試してみた。今回テストしたハードウェアはノートパソコン(Lenovo E450)なので、以前示したデータほどのパフォーマンスは出ていない。また、計測ツールにwrkを使用していたが、今回の環境上だとなぜかwrkが終了しないのでabコマンドでの測定に切り替えている。
Maria クエリキャッシュ
パラメータは一切チューニングしていない。デフォルトのまま。結果は5196.66 reqs/sec
Server Software: sashimi Server Hostname: localhost Server Port: 9001 Document Path: /about Document Length: 6662 bytes Concurrency Level: 12 Time taken for tests: 1.924 seconds Complete requests: 10000 Failed requests: 0 Total transferred: 67790000 bytes HTML transferred: 66620000 bytes Requests per second: 5196.66 [#/sec] (mean) Time per request: 2.309 [ms] (mean) Time per request: 0.192 [ms] (mean, across all concurrent requests) Transfer rate: 34402.48 [Kbytes/sec] received Connection Times (ms) min mean[+/-sd] median max Connect: 0 0 0.2 0 4 Processing: 0 2 1.1 2 11 Waiting: 0 2 1.0 2 10 Total: 0 2 1.1 2 11 Percentage of the requests served within a certain time (ms) 50% 2 66% 2 75% 3 80% 3 90% 3 95% 4 98% 6 99% 7 100% 11 (longest request)
Redis
同一マシン上でRedisサーバを1台立ててキャッシュした場合。4257 reqs/sec. スコアは悪化している。
Server Software: sashimi Server Hostname: localhost Server Port: 9001 Document Path: /about Document Length: 6662 bytes Concurrency Level: 12 Time taken for tests: 2.349 seconds Complete requests: 10000 Failed requests: 0 Total transferred: 67790000 bytes HTML transferred: 66620000 bytes Requests per second: 4257.39 [#/sec] (mean) Time per request: 2.819 [ms] (mean) Time per request: 0.235 [ms] (mean, across all concurrent requests) Transfer rate: 28184.43 [Kbytes/sec] received Connection Times (ms) min mean[+/-sd] median max Connect: 0 0 0.2 0 5 Processing: 0 3 1.5 2 19 Waiting: 0 2 1.2 2 17 Total: 0 3 1.5 3 19 Percentage of the requests served within a certain time (ms) 50% 3 66% 3 75% 3 80% 4 90% 4 95% 5 98% 7 99% 9 100% 19 (longest request)
さらなる高速化
この性能でもおそらく殆どのブログ運用で十分な性能であると思われるが、sashimiの開発方針は最速のCMSなのでもうちょっと頑張ってみる。
MySQLであれRedisであれ、ネットワークI/Oは発生するのであとはアプリ内で何とかするしかない。とりあえず一番シンプルにJavaのConcurrentHashMapを使用してみた。ScalaにはTrieMapというスレッドセーフなMapがあるらしいが、パフォーマンスはConcurrentHashMapのほうが優れているみたいだ。TrieMapの利点は任意の時点で正確なイテレータを取得することができることらしい。
結果は8929 reqs/secと大幅に高速化することができた。
Server Software: sashimi Server Hostname: localhost Server Port: 9001 Document Path: /about Document Length: 6662 bytes Concurrency Level: 12 Time taken for tests: 1.120 seconds Complete requests: 10000 Failed requests: 0 Total transferred: 67790000 bytes HTML transferred: 66620000 bytes Requests per second: 8929.07 [#/sec] (mean) Time per request: 1.344 [ms] (mean) Time per request: 0.112 [ms] (mean, across all concurrent requests) Transfer rate: 59111.51 [Kbytes/sec] received Connection Times (ms) min mean[+/-sd] median max Connect: 0 0 0.1 0 2 Processing: 0 1 0.8 1 13 Waiting: 0 1 0.8 1 12 Total: 0 1 0.8 1 13 Percentage of the requests served within a certain time (ms) 50% 1 66% 2 75% 2 80% 2 90% 2 95% 3 98% 4 99% 5 100% 13 (longest request)
ということで何か問題が出るまではシンプルにConcurrentHashMapで行こうと思う。
今回検証したコードを示すのはちょっとだるいので、気になる人はGitHubでコミット履歴等を見て下さい(なげやり)。