Edited at

Webアプリ性能をnscd使って改善した話


はじめに

Webサイトにおけるパフォーマンス(サイト表示速度)を改善するポイントはいくつもあります。

以下一例です。


  • フロントエンドの改善


    • リクエスト回数を減らす

    • 通信量を減らす

    • レンダリング速度の最適化

    • CDN活用



  • サーバサイド


    • (Memcached/Redis等)キャッシュ活用

    • アプリロジック改善


      • n+1問題回避やらいろいろ



    • APサーバと静的コンテンツ配信サーバ分離

    • 開発言語バージョンアップ

    • DBチューニング


      • インデックス見直し

      • SQLチューニング





弊社サービスでは、これまでも上記に取り組み、少しずつ改善はしていました。

それもそろそろ今のアーキテクチャでは頭打ちかな?という状況でしたが、最近実施して意外にも

大きく改善したことがあったのでご紹介します。


環境構成


  • インフラは全てAWS

  • APサーバには、apache2.4 + php7.2 + opcache

  • Cacheサーバには、ElastiCache(セッション用、キャッシュ用の2つ)

  • DBサーバには、RDS for PostgreSQL

よくある構成ですね。^^;


主題:nscdでDNSキャッシュ

弊社の環境では、Route53のPrivateDNSでRDS/ElastiCacheエンドポイントに別名のホスト名を

割り当ててそれをAPサーバから使うことで、リソース切り替えを容易にしています。(疎結合!)

この方式の弊害としては、PrivateDNSだとALIASレコードが使えないため、CNAMEレコードを設定する必要が

あり、これにより名前解決に余計に1回クエリが飛んでしまうというもの。


PrivateDNSでもALIASレコードは使えるようです(コメント欄参照)

また、phpは(apache)プロセス内でDNSクエリ結果をキャッシュしないようで、毎回DNSクエリを投げます。

このRDS/ElastiCacheの名前解決処理により、遅延が発生している可能性を疑いました。

そこで、nscdを用いてDNSクエリ結果をキャッシュを試してみました。

nscd(name service cache daemon)とは、その名の通り、DNSやNISなどの一般的なネームサービスの

内部DBを保持し、passwd、group、hostsファイルなどの情報をキャッシュするサービスです。


nscd導入手順

$ sudo yum install nscd

$ sudo vi /etc/nscd.conf # 後述のnscd.confの内容にする
$ sudo systemctl start nscd
$ sudo systemctl enable nscd
$ sudo apachectl graceful # Apache利用の場合


/etc/nscd.conf

    logfile             /var/log/nscd.log

# threads 4
# max-threads 32
server-user nscd
# stat-user somebody
debug-level 0
# reload-count 5
paranoia no
# restart-interval 3600

enable-cache hosts yes
positive-time-to-live hosts 60
negative-time-to-live hosts 5
check-files hosts yes
shared hosts yes

enable-cache passwd no
enable-cache group no
enable-cache services no
enable-cache netgroup no



効果

結果として、 約30% サイトの平均レスポンスタイムが改善しました。

(当社比。もちろん、SDKや各種エンドポイントの利用頻度によって効果は違います)

DNSクエリをtcpdumpで確認してみると、RDS/ElastiCacheだけではなくS3やCloudFrontなど他の

AWSリソースにもリクエストを投げており、それらSDKを利用したアクセスにも効果がありました。


注意点

DNSキャッシュしている期間は、フェイルオーバー遅延などが起こるので、許容できる範囲でttlを設定する必要があります。


おまけの改善:リリース回数が増えると性能劣化する問題

次に、nscdでレスポンスが速くなったことで リリース後にレスポンスが遅くなる という問題が顕在化しました。

(nscdの改善に比べればおまけみたいなものですが)


原因

OPcacheのCache Fullが発生し、キャッシュにのりきらなくなったことが原因でした。

※OPcacheについては、php.netQiita記事を参照ください。

Opcache Control Panelを使って性能劣化時のOPcacheキャッシュ利用状況を取得してみました。

取得した結果(抜粋)が以下です。

ocp.png

Cache Fullが1になってますね。^^;

弊社では、php実装したWebアプリは、

デプロイサーバでコード取得→composer install→APサーバ配布→シンボリックリンク切り替え

という流れでアトミックにデプロイしています。よくある方法ですね。

最近リリース頻度が増えてきており、1日に数回リリースすることがあります。(多分2桁はいかないけど)

OPcacheは、一度キャッシュしたデータは放置すると消えません。

キャッシュをクリアするには再起動するかopcache_reset()を実行する必要があります。

なので、リリースを繰り返した結果キャッシュサイズ上限を超えると、毎回コンパイルが走り、性能が劣化することになります。


対策


  • Apache再起動してキャッシュクリア

  • 上限超えないように共有メモリサイズ(opcache.memory_consumption)を増やす

  • 変更なしファイルは同じタイムスタンプでデプロイする(不要なキャッシュを回避)

などなど、いろいろやり方はあると思いますが、

今回は簡単にできるhttpd再起動(apachectl graceful)の定期実行でキャッシュクリアするようにしました。


効果

一部サーバのレスポンスタイムの推移です。後半は性能劣化が起きなくなっています\(^o^)/

restime_avg.png


まとめ

頭打ちと思っていても、まだまだ改善できる余地はあるのだなぁ(スキル不足w)と実感。

ちなみに今回の改善をする前に、php5.6 -> php7にあげたのですが、その時に全然改善しなかったのは

他のボトルネックが大きすぎて、見えづらかったのかも。と今になって思いました。

最後に、今回あげた改善例も種類は違えどキャッシュの改善。

やっぱりキャッシュ戦略大事ですね!!