SlideShare a Scribd company logo
SmartNews AdServer
解体新書 / ポストモーテム
@tamtam180 SmartNews, Inc.
公開用に何枚かスライドを削除しています。
一部画像の削除、およびモザイクを入れています。
自己紹介
• 名前: たむたむ
• 職業: ソフトウェアエンジニア
• Twitter: @tamtam180
• 趣味: オンラインゲーム, セクシーなサービスを作る事
• OSS-Contribute: TokyoTyrant, Hadoop, Hive, ArangoDB,
PipelineDB
• SIer (2年)
• Square Enix (約6年)
– PlayOnline, FF-XIV
• Freelance (2年)
• SmartNews (いまここ)
自己紹介
• スクエニを退職したら2chにスレッド立てられて晒された
• こんな事が書かれていた
• 豆腐ハンバーグ美味しいし、
貧乏じゃねーし、
余計なお世話だ
自己紹介
• 広告の事、何もやったことない
広告用語は略語が多い
アジェンダ
• 初期の開発スケジュール
• 使っている技術
• アドサーバが持っている機能
• 広告処理概要, 要素技術, 思想
• 事件簿
• 2016 に向けて
アジェンダ
• 初期の開発スケジュール
• 使っている技術
• アドサーバが持っている機能
• 広告処理概要, 要素技術, 思想
• 事件簿
• 2016 に向けて
初期の開発スケジュール
• 08/15 API仕様確定
• 08/22 iOS SDK提供開始
• 08/29 Android SDK提供開始
• 09/12 Web SDK 提供開始
• 09/15 Adサーバ リリース
• 09/25 Android版テスト配信(public test)
• 10/08 Web版テスト配信
• 10/15 iOS版テスト配信(public test)
• 10/27 iOS Submit
• 10/28 Android Release
• 11/04 Standard Ad配信開始
• 11/16 Premium Ad配信開始
• 12/01 正式リリース & セールススタート
というスケジュール表が
8月20日に
投稿されていた
複数のアドバイザ
• 思想も設計も既に決まっているのに
後は走るだけなのに
–外部からアドバイザが次々とやってくる
–「思想や設計を説明してくれ」
Initial Commit
テスト
SmartNews TechNight Vol5 : SmartNews AdServer 解体新書 / ポストモーテム
アジェンダ
• 初期の開発スケジュール
• 使っている技術
• アドサーバが持っている機能
• 広告処理概要, 要素技術, 思想
• 事件簿
• 2016 に向けて
使っている技術
• Scala
使っている技術
• Scala
• Java
使っている技術 – Java -
• Scala
• Java(1.8)
• Jetty (Embedded)
• Spring Framework (DI)
• Jackson
• SLF4j / Logback
• FastUtil
• Kryo
• Trie4j
• MyBatis
• Flyway
• Nashorn
• gRPC / ProtoBuf
• Guava
使っている技術 – Middle Ware -
• NewRelic
• JMX with DataDog
• MySQL
• Redis
• DynamoDB
• Fluentd
• Kinesis
使っている技術 – AWS -
• EC2
• S3
• CloudFront -> Akamai
• RDS
• DynamoDB
• ElastiCache(Redis)
• Redshift
• Kinesis
• Route53
Lambda
EC2 Container Service
CodeDeploy
CloudWatch
EMR
Device Farm
SNS
CloudSearch
Elastic Transcoder
SQS
Kernel Parameter
kernel.sysrq =	0
kernel.core_uses_pid =	1
kernel.sem =	250	256000	100	1024
kernel.msgmnb =	65536
kernel.msgmax =	65536
kernel.shmmax =	68719476736
kernel.shmall =	4294967296
#	auto	configure	by	kernel
#fs.file-max	=	524280
#kernel.threads-max	=	500000
net.ipv4.ip_local_port_range	=	10000	65535
net.ipv4.ip_forward	=	0
net.ipv4.tcp_syncookies	=	1
net.ipv4.conf.default.rp_filter	=	1
net.ipv4.conf.default.accept_source_route	=	0
net.ipv4.tcp_wmem	=	4096	16384	16777216
net.ipv4.tcp_rmem	=	4096	87380	16777216
net.ipv4.tcp_fin_timeout	=	5
net.ipv4.tcp_keepalive_time	=	10
net.ipv4.tcp_keepalive_probes	=	3
net.ipv4.tcp_keepalive_intvl	=	4
net.ipv4.tcp_max_syn_backlog=8192
net.core.somaxconn =	65535
net.core.netdev_max_backlog =	65535
net.ipv4.tcp_max_syn_backlog	=	65535
net.ipv4.conf.all.arp_ignore	=	1
net.ipv4.conf.all.arp_announce	=	2
net.core.rmem_default =	87380
net.core.rmem_max =	16777216
net.core.wmem_default =	16384
net.core.wmem_max =	16777216
net.core.netdev_max_backlog =	16384
net.ipv4.tcp_tw_reuse	=	1
net.ipv4.tcp_tw_recycle	=	0
net.ipv4.tcp_window_scaling	=	0
net.ipv4.tcp_timestamps	=	0
net.ipv4.icmp_echo_ignore_broadcasts	 =	1
net.ipv4.tcp_no_metrics_save	=	1
net.ipv4.tcp_ecn	=	0
rc.local
#!/bin/bash
touch	/var/lock/subsys/local
for	path	in	/proc/sys/net/ipv4/conf/*
do
nic=$(basename "$path")
if	[[	$nic ==	eth*	]];	then
/sbin/ifconfig $nic txqueuelen 10000
/sbin/ethtool-K	$nic rx off	tx off	sg off	tso off	ufo off	gso off	gro off	lro off
fi
done
アジェンダ
• 初期の開発スケジュール
• 使っている技術
• アドサーバが持っている機能
• 広告処理概要, 要素技術, 思想
• 事件簿
• 2016 に向けて
アドサーバが持っている機能
• Filters
• Beacon Endpoint
• Budget Control
• Frequency Control
• Auction
• Bloom Filter
• Ad Allocation (Minimum Cost Flow)
• Optimizer
• Impression Smoother
• Web Tracking
• Preflight Mode
• Rehearsal Mode
• Restrict Mode
• SelfServe Delivery
• Admin API
アジェンダ
• 初期の開発スケジュール
• 使っている技術
• アドサーバが持っている機能
• 広告処理概要, 要素技術, 思想
• 事件簿
• 2016 に向けて
広告処理概要
SDK AdServerELB
CDN S3
Dispatcher
Transform
Filter
JSON
Image
Redis MySQL
Dynamo
DB
Auction
Allocation(最適化問題)
Serializer
初期バージョン設計思想
• なるべく通信はしない
• データはなるべくオンメモリ
• リフレクションは使わない
• 各種処理は計算量O(1), O(LogN)で実装する
• ログ基盤に割くリソースはないので、フロントであ
る程度頑張る
アドサーバが扱うデータの種類
広告処理概要 - データの種類 -
• アドサーバが扱うデータの種類
– ユーザー主体の情報
– キャンペーン主体の情報
– メディア主体の情報
– マスタ情報
– 速報値カウンタ
広告処理概要 - オンメモリ -
AdServer
Redis
Pubsub
MySQL
Master
MySQL
Slave
管理画面
Pub
1.	Sub
2.	起動時に一気にLoad
6.	キャッシュ更新
キャンペーン情報
OnMemory
各種情報はオンメモリで
Queue
4.	Latch
5.	Load
3.	キャッシュ更新
レプリケーション遅延対策
広告処理概要 - レプリケーション遅延対策 -
AdServer
Redis
Pubsub
MySQL
Master
MySQL
Slave
管理画面
1.	Update
3.	Pub(ID,	LastTimestamp)
Sub
4.	Timetamp比較
6.	キャッシュ更新
キャンペーン情報
OnMemory
キャンペーン Table
最終更新時間 Table 2.	Update5.	Retry
各種情報はオンメモリで
速報値カウンタ
広告処理概要 – 速報値カウンタ -
AdServer
Redis
速報値情報
OnMemory
SDK
Beacon
LogFile Fluentd
S3
Kinesis
Redis
WriterCounter
ReadCounter
予算消化情報
時系列カウンタ
広告識別子
広告識別子
• 払い出した広告には1件ずつユニークなIDを割り当てている
• UUIDは使っていない
• OTS (One Time Signature)
– 120Bit
– Base64URIしたもの
• ASCII: 20文字
• サーバ間で協調する事無く、ユニークなIDを生成できる
広告識別子
Name Bit Description
Version 4 OTS Version
Timestamp 41 2012/12/10 00:00:00	起点のミリ秒
NodeId 24 サーバのID
RedisId 8 格納先RedisのID
Sequence 19 ラウンドロビンカウンタ
BitOptions 8 各種フラグ
Reserved 16 予約
広告識別子とメタ情報
OTS
Redis
Hash
Key Field
Hash OTS
META
Value
RES
IMP
VIMP
CLICK
CONV
Time
Time
Time
Time
Time
Object
Impression Smoothing
Impression Smoothing
ベース
Device * Channel * DayOfWeek
/ Per Minute
xxx	IMP
プラン
ScoreXScoreX
Remain
Counter
Base
Debt
Assist
Prediction
MixedScore
Allocation
IMP売り商品
• Standardのアドサーバは2つの広告を扱って
いる
–IMP売りの商品(純広告)
–パフォーマンス広告(運用型広告)
• これを1回のリクエストで返す必要がある
純広告と運用型広告の処理
Channel Channel Channel Channel
純広告
運用型広告
Smoothing
Allocation(最適化問題)
AuctionAuction
Allocation(最適化問題)
Merge
Impression Smoothing
アジェンダ
• 初期の開発スケジュール
• 使っている技術
• アドサーバが持っている機能
• 広告処理概要, 要素技術, 思想
• 事件簿
• 2016 に向けて
注意事項
• ここから、とても残念な発表の連続です。
• 前提として、
–リリーススケジュールが過酷
–大量の機能リリースが必要
• だったという事を念頭にお願いします。
Release頻度
16
34 34
19 20
12
21
13
18
25 25
15 14
16
7
12
2014.11
• 基本機能は実装
– iOS, Android, WebSDKは実装済み
– Budget Control
– Auction
– Frequency Control
– Rehearsal Mode
– Restrict Mode
– Naive Allocation
– TrackingTool
– WebTag
パフォーマンス事件簿 File.1
パフォーマンス障害
• ピークタイムでELBから外れてしまう
• Monitor競合がとても多い事を観測
Java Blocking
• MersenneTwisterがMTSafeじゃなかった
• JavaのPropertiesをオンライン処理で参照してブロック
– getPropertyがsynchronized
• SecureRandomが刺さる
– nextBytesがsynchronized
• NewRelicの@Traceが多いと時々刺さる
Java Blocking
• 暗号化ライブラリがスレッドブロッカー
– Cipherのインスタンスはスレッドセーフではないので毎
回生成する必要がある
– ただし、Instance化する時にsynchronizedが存在する
– GenericObjectPoolを使った
• GenericObjectPoolもsynchornizedなコードが多い
– ThreadLocalを使うようにして回避
Java Blocking
• getClass().get**Name()がBlockする
– OpenJDKのソースを追っていくとBlockする箇所がある
集団食中毒 事件
集団食中毒事件
• みんなでランチに豚カツを食べに行った
• 夕方に体調を崩して早退
• 家で壮大に吐く
• 他にも被害者多数
IAAS事件簿
CDN障害
• クリエイティブ画像が表示されない障害が発生
– CloudFrontの障害
– この年はCloudFrontの障害が多かった
• SLA100%のCDNへ移行
AWS
• ElastiCache
– 自動snapshot取得中にtimeoutが頻発
– Server側に存在しない接続情報が大量に残っていてTCPレベ
ルでACKを返さなくなる
• AMI(EC2)
– 2015.09のAMIで頻繁にインスタンスチェックが失敗する
iOSクラッシュ事件
iOSクラッシュ
• 前回、広告を取得した件数よりも、
今回、広告を取得した件数が小さい場合にクラッシュす
る
• 急遽、求人広告を作ってフィラーとして配信する
パフォーマンス事件簿 File.2
パフォーマンス事件 File.2
パフォーマンス事件 File.2
• 2015年4月28日
• 最近、日に日に負荷が高くなっている。
• ゴールデンウィークが危ない
パフォーマンス事件 File.2
パフォーマンス事件 File.2
• 現象
–GC時間が増加している
–FULL GCが10秒に1回くらい発生していた
• 対処
–速報値カウンタのTimeline取得をO(N+LogN)から
O(1)に
–大量のインスタンス生成箇所をつぶした
パフォーマンス事件 File.2
パフォーマンス事件簿 File.3
パフォーマンス事件 File.3
• 2015年5月8日
• GCがやばい
• Class Unloadingが多い
• チューニングしないと!!
パフォーマンス事件 File.3
パフォーマンス事件 File.3
• 現象
– FullGCが多い
– ClassUnloadingが何故か多い
• 対処
– GC抑止のためにパラメータチューニング
– レキシカルスコープを参照しているLambda式
の排除
パフォーマンス事件 File.3
• GCパラメータ(before)
-Xmx****m
-Xms****m
-XX:+UseConcMarkSweepGC
-XX:CMSInitiatingOccupancyFraction=70
パフォーマンス事件 File.3
• GCパラメータ(after)
-Xmx****m	-Xms****m	-XX:+UseConcMarkSweepGC
-XX:CMSInitiatingOccupancyFraction=70	-XX:NewRatio=1	
-XX:SurvivorRatio=2	-XX:TargetSurvivorRatio=90	
-XX:MaxTenuringThreshold=15	
-XX:+DisableExplicitGC
-Xloggc:/data/logs/_gc.log -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=10	
-XX:GCLogFileSize=1024m	
-XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintTenuringDistribution
-XX:+TraceGen0Time	-XX:+TraceGen1Time
パフォーマンス事件 File.3
パフォーマンス事件簿 File.4
パフォーマンス事件 File.4
• 現象
– バックグラウンド処理が遅い
• 対処
– 各種実装の最適化
•一部処理の並列化
•不要なデータの読み込みを回避
•通信の回数を減らす
パフォーマンス事件 File.4
パフォーマンス事件 File.4
パフォーマンス事件 File.4
パフォーマンス事件 File.4
アラート通知事件 File.番外編
アラート通知
• 全台バランサから外れていた
• 数時間気づかなかった
• そもそもアラートが来ない
• 何故?
• PagerDutyに登録している電話番号間違ってた
サービスインする
前の話です
アラート通知
• 一時期、毎朝7時のピークで障害が発生した。
• 好きな着メロだったのに嫌いになった。
パフォーマンス事件簿 File.5
パフォーマンス事件 File.5
• 現象
– 速報値を扱っているRedisの通信帯域がつらい
• 対処
– アーキテクチャの変更
パフォーマンス事件 File.5
AdServer
Scan
Timeline	Summary
ToCache
RedisAdServerAdServer
パフォーマンス事件 File.5
• スケールしないもの(Redis)と直接通信をすると
アドサーバがスケールしなくなる
• 速報値を扱うプロセスを用意し、アドサーバは
それと通信をする。
パフォーマンス事件 File.5
AdServer
Scan
Timeline	Summary
ToCache
RedisAdServerAdServer
Process
Summaried Data
パフォーマンス事件 File.5
パフォーマンス事件 File.5
確率計算ミス File.番外編
確率計算ミス
• 確率計算ミス
– 70%で配信したいところが、確率計算をする度にサイコロ(乱
数)を振っていた
– 1回の広告取得で3チャンネルを同時に取得する
– 1回の広告で70%にしないといけない設定だった
– 各チャンネルで70%の判定をしていた
– 70% * 70% * 70% = 34.3%
– しかも、オペレーション担当に体感30%くらいなんですけど?と
言われて発覚した
確率計算ミス
サービスIN前
です
パフォーマンス事件簿 File.6
パフォーマンス事件 File.6
• 現象
– OTSに紐付くMeta情報が日々肥大化している
• 対処
– Serializerを変更
パフォーマンス事件 File.6
• 今まではデバッガビリティのためにJSONで保
存
• KryoのTagFieldSerializerを使用
• BooleanフラグをOTS側に移動
パフォーマンス事件 File.6
• 空間効率が1/3
• SerdeのCPU処理負荷が1/2
パフォーマンス事件簿 File.7
パフォーマンス事件 File.7
• 現象
– オンメモリのキャッシュがObject生成しすぎ
– そもそもObject生成が多すぎ
– GCが荒ぶっている
• 対処
– データ構造、および処理を大幅改修
パフォーマンス事件 File.7
• リクエストの度に大量にオブジェクトを生成し
ている箇所がある
• キャッシュからのコピーが大量に発生しており、
1リクエスト中のフットプリントが大きい
• 時系列情報をナイーブに持たないでサマライズ
• HistogramのBin構造を最適化
パフォーマンス事件 File.7
パフォーマンス事件 File.7
パフォーマンス事件 File.7
パフォーマンス事件 File.7
Kryoの前方互換性問題
Kryoの前方互換性問題
• KryoのTagFieldSerializerは前方互換性が無い
– TicketにあるPRも問題を解消できない
Kryoの前方互換性問題
• サーバの更新中に発生する
• 更新中は古いサーバと新しいサーバが混在する
• 新しいサーバが広告を払い出す
• 古いサーバがビーコンを受け取る
• 古いサーバは古い定義のまま新しいバイナリを
受け取る
Kryoの前方互換性問題
• TagFieldSerializer
–Tagの順番に処理していない(Field名でソートし
ている)
–知らないTagIDを読み込むとエラーが出る
Kryoの前方互換性問題
• 改善版
–Tagの順番でソートしてSerializeする
–UnknownなTagを読み込んだら処理を中断す
る
–SKIPしてはいけない
レプリケーション事件簿
レプリケーション事件簿
• レプリケーション遅延
– レポートテーブルが同居していて、しかも巨大なトラン
ザクションが発行されていた
– 30分以上遅延することがあった
– リロードが失敗する事が多発
レプリケーション事件簿
• クエリを修正
• そもそも、レポートDB分離
• キャパシティプランニングを楽にするためにAuroraへ
gRPC事件
gRPC
• サーバ間通信でgRPCを採用した
–ProtoBuf Beta
–Netty Beta
• ELBを通すとNettyの不具合を踏む
• 異常系の不具合をたくさん踏む
アジェンダ
• 初期の開発スケジュール
• 使っている技術
• アドサーバが持っている機能
• 広告処理概要, 要素技術, 思想
• 事件簿
• 2016 に向けて
次のステージへ
• スケールできる土台は一通り作った
• Stream処理、オンライン処理への準備も出来
つつある
今の構成
AdServer
ELB
Redis MySQL
Dynamo
DB
LogFile Fluentd
S3
Kinesis
Provider
HA-PROXY CONSUL
CPU	BOUND
MEM	BOUND
RedShift
BQ
Hive
Presto
Pipeline
DB
Realtime
Report
DMP
Batch
AdHoc
最後に
• 意外と広告は面白い
– ソフトウェアエンジニアリング, 大量のログ, 機械学習, 最適
化問題, 大規模トランザクション
– 実時間で実現する必要がある
• 技術だけでなく、ビジネスも楽しもう
• もしかしたら、誰でも出来るかもしれない
• 誰でも出来る事は、誰にも出来ないレベルまで昇華しよう
• イノベーションは個人の裁量から生まれる

More Related Content

SmartNews TechNight Vol5 : SmartNews AdServer 解体新書 / ポストモーテム