はじめまして、エキサイト株式会社の中尾です。
今回はMemcachedからRedisに移行した話をします。
半年ほどかかりましたが、、、なんとかやりました。。(時間かかりすぎなのは申し訳ございません)
- はじめに
- まずはcacheの中身を精査する。
- apiサーバーのcacheの向き先変更に成功
- twig cacheをfileに
- アプリケーションのcacheをRedisに(1回目)
- アプリケーションのcacheをRedisに(2回目)
- アプリケーションのcacheをRedisに(3回目)
- 長い長い戦いの終わりに
はじめに
まず、なぜ移行をしたかという話の前に、構成を説明します。 webサーバーが2種類とapiサーバーが1種類あるのですが、 片方のwebサーバーが7台存在し、その中でApacheとMemcachedが共存しておりました。 webサーバーのスペックはmemory 16G * 7台のハイスペックとなっていました。
メリットとしては、総合的なサーバコストは安くなります。 デメリットとしては、webサーバーとメモリが同一のサーバーに存在しているので、システムの依存度が強く、管理が非常に難しいです。
オンプレのサーバーであり、ほとんどのサービスのcacheをwebサーバーに載せているため、Memcachedが載っているwebサーバーのメンテナンスが非常に困難でした。 twemproxyの設定を外すにはMemcachedの設定も変更する必要があったりと、現実的にかなり難しいです。
よって、MemcachedをやめてRedisに向けるプロジェクトをやりました。
構造はシンプルです。
まずはcacheの中身を精査する。
ではRedisに切り替えていきますが、向き先を変更するだけではありませんでした。
謎の無限TTLのキャッシュが大量に入っており、大半の容量を占めておりました。
それはフレームワークがEtagという形で、謎にアプリケーションのキャッシュを3つに分解して保存しているからです。
key | value | TTL | |
---|---|---|---|
Etag | key名 | valueのハッシュ値 | 無限 |
EtagValue | valueのハッシュ値 | key名 | 無限 |
cache | key | value | アプリケーションで指定したTTL |
フレームワークの中を覗くと、上記の表の形で保存していました。
正直、この仕組みのメリットが理解できなかったのですが、今回はシンプルに keyとvalueを保存するだけにしようと思いました。
これで、かなりcacheが保存される量が減りました。
apiサーバーのcacheの向き先変更に成功
apiサーバーの変更はうまく成功しました。
しかし、web側のcacheの向き先変更はすんなり進みませんでした。。。
twig cacheをfileに
twig cacheがMemcachedに書き込まれていたので、fileに吐き出しました。この修正自体は1行で終わります。しかし、この6時間後、サーバー容量が足りないとアラートが飛んできます。
原因を調べると、どうやらテンプレートファイルを動的に作成していました(?)
何をいっているかというと、twig templateって以下のようなテンプレートファイルなのですが、こちらがPHPの文字列として書き込まれていて作成されていたのです。
<!DOCTYPE html> <html> <head> {% block head %} <title>{% block title %}{% endblock %}</title> {% endblock %} </head> <body> <main>{% block content %}{% endblock %}</main> <footer> {% block footer %} © Copyright {% endblock %} </footer> </body> </html>
PHPでテンプレートファイルを作成し、なおかつユーザーやページごとにテンプレートが変わり結果毎回テンプレートファイルのキャッシュファイルが作成されます。
リリース後6時間でサーバー容量が足りないという事態になったので即座に戻しました。
テンプレートファイルを動的に作成している箇所を探し出して修正していく毎日が続きます。
修正し、cache fileを確認し、増えているなら差分を出して修正する当たりをつけて修正しを繰り返してなんとか無限キャッシュを防ぎました。
これでようやくtwig cacheをfile出力できます。
あれ、、、目的は、、、Memcached から Redis に移行なので、まだまだ戦いは終わりません。
アプリケーションのcacheをRedisに(1回目)
今度こそ、Redisに向けました。すると、RedisのCPU使用率、サーバ負荷率が100%に一瞬で跳ね上がり、サービスが固まります。。。
見間違いだろうと思って、2回くらいやっても意味ないです。。。
単純にスペックが低すぎたのかと思いましたが、かなりのハイスペックにしていて、これ以上の処理件数を増やすとなるとクラスターを組むしかないぐらいのスペックです。
原因を探ると、Redisにcacheで書き込んでいる処理のうちvalueが200kb超えているものがありました。それが毎秒に近いくらい書きこまれておりサーバーの負荷を高めておりました。
ログを仕込みながら、1件1件潰していき警告が出ないところまで行きました。
長い長い戦いは続きます。
アプリケーションのcacheをRedisに(2回目)
再度挑戦します。すると、RedisのCPU使用率、サーバ負荷率が100%に一瞬で跳ね上がり、サービスが固まります。。。
これ以上打つ手がない、、、と思ってcacheされるべきデータをチェックします。
すると不要にキャッシュしているもの、キャッシュ時間が極端に短すぎるものなどいろいろありました。
すべてチェックし、整理をします。
アプリケーションのcacheをRedisに(3回目)
再度挑戦します。すると、RedisのCPU使用率、サーバ負荷率が100%に一瞬で跳ね上がり、サービスが固まります。。。
これ以上打つ手がない、、、と思ってRedisの調整をします。
以前の記事に maxmemory-reserved
を記載しましたが、ここで役に立ちます。
書き込み不可の高いワークロードでしたので、こちらを60%の最大値振り分けました、
するとなんと!!なんと!!!安定しました!!!
長い長い戦いの終わりに
ようやくMemcachedの脱却に成功しました。
すると、webサーバで7台で構えていたシステムがなんと4台まで減らせました。
Redisのサイズも踏まえるとコスト的には同等なのですが、アプリケーションの安定感が全然違います。
むしろ、アプリケーションの方にはまだまだ余裕があるため、サイズを減らすか、サーバーの台数を減らすこともできそうです。
なにも気にすることなく、サーバを減らしたり増やしたりできるようになりました。
ほかにも問題点はたくさんあるのですが、ひとまずアプリケーションとcacheを分離に成功しました。
まるでマリク(人形) vs 遊戯の戦いのようでした。。
究極のコンボ「ゴッド・ファイブ」
完全無欠にして無敵、攻略不可能な神の領域かと思いました。
しかし、海馬社長のいう通り、無限などありません。神の幻想です。
ドローカード一枚でなんともなりません。ショートカットできる方法はありません。地道に戦うことしか道はありません。諦めず頑張りましょう。
もし、アプリケーションとcacheを同一のサーバーで管理しているシステムがあり、分離を考えているなら参考になれば嬉しいです。