(1)はこちら、(2)はこちらから。
システムの安定運用のための取り組み
(3)では、システムの安定運用のために最近行った取り組みを紹介します。
cpanfileによるモジュールのバージョン管理
fluctではCartonとcpanfile
によるモジュール管理を行っています。
fluctでは、モジュールは基本的に最新版を用いています。具体的には、cpanfile
に明示的なバージョン指定の記述をしていません。
# 2016年11月現在で最新の1.0042がインストールされる
requires 'Plack';
これは、最新を用いることによって、使える機能が増える、バグフィクスされるなどのメリットがあるためです。また、バージョンを固定すると、いつの間にかそれが足かせになり、バージョンアップをためらうようになってしまいがちです。それらを考慮したうえで、積極的にバージョンを上げていくポリシーを持っています。
最新バージョンを選択する功罪
ただし、機能面で非互換なバージョンアップがなされるケースもあります。モジュールの利用者側としてはバージョンアップによって起こる効果や影響を把握し、変更内容によっては指定バージョンを選択して利用しなければいけません。
前述のとおり、fluctではシリアライザとしてData::MessagePackを用いていますが、このモジュールに、2016年6月のバージョン0.50で変更がありました。それまでMessagePackの旧仕様に対応していましたが、0.50で新仕様に対応したのです。新仕様ではformat
型が追加され、それに伴いシリアライズ方式が変更になりました。
広告配信サーバのライブラリ管理はプロセスごとに異なっており、アドサーバはデプロイ時に都度cartoninstall
を実行してからプロセスを立ち上げています。このため、0.50がリリースされた以降のデプロイ時にバージョンが上がり、アドサーバ側とフロントやRTB側とのシリアライズ方式が異なり、正しくデータの受け渡しができない障害が起こりました。
バージョン指定による選択管理
上記障害の対応としては、いったんアドサーバのシリアライズを旧形式に戻す処置をしました。具体的には、cpanfile
にインストールするバージョン指定のオプションを追加しました。
# 0.49がインストールされる
requires 'Data::MessagePack', '== 0.49';
cpanfile
は等号のほかに不等号による指定もできます。Data::MessagePackは0.51で一度旧仕様に戻ったあと、新仕様に対応した1.00がメジャーバージョンとしてリリースされ、2016年11月現在は1.00が最新です。仮に上記の障害と逆パターンで、相対するプロセスが新仕様にのみ対応している場合などは明示的に新仕様のモジュールを指定してインストールしておくほうが良いでしょう。
# 1.00以降がインストールされる
requires 'Data::MessagePack', '>= 1.00';
バージョン指定の詳しい設定は、公式リファレンスを参考にしてください。
アクセスログの取得
Webサーバを運用するうえで、ログ管理は大事な作業です。plackup
で立ち上げていて、PSGIアプリケーションが直接リクエストを受けるケースでは、アプリケーションからログの出力管理をする必要があります。
アドサーバでは少し前まで、このログ管理をしていませんでした。広告配信サーバ全体としてはフロントのアクセスログを取っており、アドサーバのログが抜けていた形ですが、この問題が顕在化したのは前述のData::MessagePackの障害時です。プロセスどうしのやりとりのどこで不具合が起きているかをトレースするには、各プロセスへのリクエスト内容とレスポンス内容がわかるログが必要でした。
障害の件を踏まえ、現在はPlack::Middleware::AxsLogとFile::RotateLogsを用いてアクセスログを出力しています。psgi
ファイルに次の設定をしています。
use strict;
use warnings;
use Plack::Builder;
use File::RotateLogs;
use Fluct::Adsever;
my $adserver = Fluct::Adserver->new();
my $rotatelogs = File::RotateLogs->new(
logfile =>
'/var/log/adserver/%Y/%m/%d/%H/access_log',
rotationtime => (60 * 60)
);
builder {
enable 'AxsLog',
combined => 1,
response_time => 1,
logger => sub {
$rotatelogs->print(@_)
};
mount '/' => sub {
$adserver->top(shift)
},
mount '/other' => sub{ ... }, # 別のエンドポイントの処理
};
このアクセスログの出力は、結果としてこれまでの紹介事例とは逆にアドサーバのレスポンス性能を下げました。しかし、サービスの安定運用に必要なトレードオフとして許容しました。処理をそぎ落として性能を高めることと、冗長な部分を持ちつつ安定性を高めることは、常に天秤にかけつつシステムを構築していく必要があります。
複数のログの一括確認
ここまではアドサーバのプロダクトとしてのPerlの紹介でしたが、ここではちょっとしたTipsとして、簡単なスクリプトをPerlで用意した事例を紹介します。
リリース時の動作確認では、広告配信サーバ内で動く複数のプロセスが出力するいずれのログも確認する必要があります。デプロイのアーキテクチャについては割愛しますが、手順としては、一時的にサービスを提供するサーバ群から取り除いた1台にデプロイして動作を確認しています。
このときの確認対象は、各プロセスのWebサーバとしてのアクセスログとアプリケーションログです。1つ2つならまだしも、これらを全部tail
するのは面倒です。こういった「常々やるけど、地味に手間がかかる作業」は、なるべく減らしたいものです。
CPANにはFile::Tailモジュールがあり、これとTerm::ANSIColorを使えば、複数のファイルを色分けして一括表示できます。Webアプリケーションに限らず、開発のさまざまな側面で使える道具がそろっているのもCPANの魅力の一つです。これらを使って簡潔な一つのスクリプトを作り、ちょっとした業務効率の改善を達成できました。
このコードは汎用化した形で公開しています。みなさんのケースにそのままは当てはまらないかと思いますが、簡単に書ける点がリファレンスとして伝わればうれしいです。
こういった改善に終わりはありません。たとえば、複数台の広告配信サーバからログを取得したい、定点測したログを一定間隔でほしいなどの要件が挙がった場合は、別の解決方法になるでしょう。その際にはWeb API化して結果を返すアプリケーションが必要かもしれませんし、監視作業ととらえて小手先のスクリプトではない対応を取るほうが良いかもしれません。いずれにしても目的に応じた手段を選べると良いでしょう。
まとめ
本稿では広告配信の運用を、PerlとCPANモジュールの使い方を交えて紹介しました。モジュールの選択や課題解決にゴールはなく、今後もさまざまな検討と運用をしていきます。本稿が、みなさんがサービスを支える際の参考になれば幸いです。
さて、次回の執筆者は一野瀬翔吾さんで、テーマは「PerlでのRedis活用法」です。お楽しみに。
- 特集1
イミュータブルデータモデルで始める
実践データモデリング
業務の複雑さをシンプルに表現!
- 特集2
いまはじめるFlutter
iOS/Android両対応アプリを開発してみよう
- 特集3
作って学ぶWeb3
ブロックチェーン、スマートコントラクト、NFT