Perl Hackers Hub

第42回 大規模広告配信でのCPANモジュールの活用(2)

この記事を読むのに必要な時間:およそ 3 分

前回の(1)こちらから。

アドサーバで用いているCPANモジュール

Perlで書かれているアドサーバでは,多くのCPANモジュールを用いています。主なものを表1にまとめました。

表1 アドサーバで用いている主なCPANモジュール

モジュール名概要
Data::MessagePackMessagePackのデータ構造へのコンバータ
GazellePSGI仕様のアプリケーションとWebサーバをつなぐPlackハンドラの一種。高パーフォマンスなPrefork型
Cache::Memcached::Fastmemcachedと接続するためのクライアントモジュール

前述のとおり,広告配信サーバは3つの内部プロセスが連携して成り立っています。プロセスを分けることにより,プロセスごとに適した技術を選択できるという設計上のメリットがあります。一方で,プロセス間で通信する必要があるため,その際のオーバーヘッドによる処理速度の低下という運用面でのデメリットがあります。このため,アドサーバでは処理速度を一つの基準としてCPANモジュールを選択しています。以降では,それぞれのモジュールについて,選択理由を解説していきます。

Data::MessagePack─⁠─データ圧縮率の高いシリアライザ

アドサーバがフロントやRTBとやりとりするリクエスト/レスポンスのシリアライザには,Data::MessagePackを使っています。この対抗としては,JSON::XSを用いてJSON形式でシリアライズする案もあります。

両者を比較検討する場合,シリアライズ処理単体の速度だけでなく,データの圧縮効率も判断ポイントとなります。JSONは可読性に優れますが,圧縮効率についてはMessagePackのほうが優れています。今回はサーバ内部のプロセス間の通信ですので,データがより小さく,通信時間を短縮できるMessagePackのパフォーマンスのほうが良いと判断しました。

次のコードでは,JSONとMessagePackで,複数の型がそれぞれある程度の分量を持った集合データの圧縮を行っています。アドサーバでは通信前にBase64エンコードをしているため,その処理も含めています。対象にしたバージョンはそれぞれ,Data::MessagePackが0.49,JSON::XSが3.02です。

use strict;
use warnings;
use JSON::XS;
use Data::MessagePack;
use MIME::Base64 qw/encode_base64/;

# 100文字のscalar値
my $string;
$string .= 'a' for (1..100);
# 要素100個の配列
my @array;
push @array , 1 for (1..100);
# 100個のキーペアを持つハッシュ
my %hash;
for my $count (1..100){
    $hash{"key_$count"} = $count;
}

my %data = (
    string => $string,
    array => \@array,
    hash => \%hash
);

my $json = JSON::XS::encode_json(\%data);
my $message_pack = Data::MessagePack->pack(\%data);
my $json_base_64 = encode_base64($json);
my $message_pack_base_64 = encode_base64($message_pack);

printf "json_length : %d byte\n" , length($json_base_64);
printf "msg_pack_length : %d byte\n" , length($message_pack_bas
e_64);

実行結果は以下です。MessagePackはJSONの70%の容量でデータを表現できています。

json_length : 2319 byte
msg_pack_length : 1638 byte

サンプル抽出した本番環境のデータで同様の算出を行ったところ,MessagePackはJSONの85%の容量でデータを表現できました。

Gazelle─⁠─Starletと互換性のある高速なPSGIサーバ

アドサーバはPSGIPerl Web Server Gateway Interfaceの仕様にのっとったPSGIアプリケーションとして実装されています。

plackupで指定するサーバとして,以前はStarletを使っていました。StarletはPrefork型で高速なWebサーバとして実績のあるモジュールです。起動オプションには以下を用いていました。

$ plackup -s Starlet -E production \
  -a /path/to/adserver.psgi \
  --port=xxxx --max-workers=160 \
  --max-reqs-per-child=50000 \
  -I lib -MFluctPreLoad -R .lib

そのあと,長野雅広さんが作ったGazelleがリリースされたため,アドサーバのアプリケーションとして両者を比較したところ,Gazelleのほうが約15%程度良い結果になりました。単体のベンチマークだと1.7倍の性能差があるとのことです。

このベンチマーク結果に加え,Starletと起動オプションの互換性があったため,乗り換えを決断しました。両者はKeepAliveのサポートなど一部実装差異がある部分以外は,オプションパラメータが同一です。そのためplackupコマンドの変更は,サーバ選択部分のみになります。

$ plackup -s Gazelle (以降のオプションはStarletと同様)

ほかとの互換性が考慮されているモジュールは,アプリケーション側を変更しなくてよく,検証や導入のハードルを下げてくれます。互換性が意識されている事例はほかにもあります。たとえばJSON::XSJSON::PPはメソッドのインタフェースに高い互換性があり,モジュールの切り替えによるアプリケーションの修正が軽微になります。

モジュール切り替えのためにアプリケーションを修正する必要があると,修正過程でバグを仕込む可能性があります。また,アプリケーションを修正しないで切り替えられれば,動作検証において何らか不具合が発覚したとしても問題点の切り分けが容易になります。このことから,互換性の高さもCPANモジュールの導入時や切り替え時の検討要素の一つとしています。

Cache::Memcached::Fast─⁠─永続的なデータに高速アクセス

このモジュールは,ほかのキャッシュアクセスモジュールとの比較ではなく,RDBアクセスとの比較になります。詳しくは,広告配信のためのデータの管理方法とともに次節で説明します。なお,fluctでは,使用例として一般的な揮発性のあるキャッシュデータへのアクセスではなく,永続的なデータにアクセスするために用いています。

著者プロフィール

星野将(ほしのまさる)

1982年東京都生まれ。Perl育ち。

株式会社ミクシィではSNS「mixi」の開発において,株式会社VOYAGE GROUPでは子会社の株式会社fluctが提供するSSP「fluct」にて,主に「開発のための開発」業務を担当してきた。

開発の無駄をなくし,開発効率を上げられるエンジニアを目指している。

GitHub:https://github.com/masartz

コメント

コメントの記入