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

24,895 views

Published on

広告システムを全く知らなかった私が約2ヶ月弱の開発期間で初期バージョンをローンチ、アーキテクチャも日々変更していき、あれから1年が経過しました。 SmartNews Adsは一般的な広告配信サーバとは異なる特徴をいくつか持っています。今回は運用型広告と純広告型の配信サーバのアーキテクチャを中心に、個人の裁量でどのように設計し、何を採択し、どのように変更していったのかを可能な限り公開し、発生した障害(課題)も晒しながらポストモーテムをします。

Published in: Technology
0 Comments
38 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
24,895
On SlideShare
0
From Embeds
0
Number of Embeds
11,584
Actions
Shares
0
Downloads
46
Comments
0
Likes
38
Embeds 0
No embeds

No notes for slide

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

  1. 1. SmartNews AdServer 解体新書 / ポストモーテム @tamtam180 SmartNews, Inc.
  2. 2. 公開用に何枚かスライドを削除しています。 一部画像の削除、およびモザイクを入れています。
  3. 3. 自己紹介 • 名前: たむたむ • 職業: ソフトウェアエンジニア • Twitter: @tamtam180 • 趣味: オンラインゲーム, セクシーなサービスを作る事 • OSS-Contribute: TokyoTyrant, Hadoop, Hive, ArangoDB, PipelineDB • SIer (2年) • Square Enix (約6年) – PlayOnline, FF-XIV • Freelance (2年) • SmartNews (いまここ)
  4. 4. 自己紹介 • スクエニを退職したら2chにスレッド立てられて晒された • こんな事が書かれていた • 豆腐ハンバーグ美味しいし、 貧乏じゃねーし、 余計なお世話だ
  5. 5. 自己紹介 • 広告の事、何もやったことない
  6. 6. 広告用語は略語が多い
  7. 7. アジェンダ • 初期の開発スケジュール • 使っている技術 • アドサーバが持っている機能 • 広告処理概要, 要素技術, 思想 • 事件簿 • 2016 に向けて
  8. 8. アジェンダ • 初期の開発スケジュール • 使っている技術 • アドサーバが持っている機能 • 広告処理概要, 要素技術, 思想 • 事件簿 • 2016 に向けて
  9. 9. 初期の開発スケジュール • 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日に 投稿されていた
  10. 10. 複数のアドバイザ • 思想も設計も既に決まっているのに 後は走るだけなのに –外部からアドバイザが次々とやってくる –「思想や設計を説明してくれ」
  11. 11. Initial Commit
  12. 12. テスト
  13. 13. アジェンダ • 初期の開発スケジュール • 使っている技術 • アドサーバが持っている機能 • 広告処理概要, 要素技術, 思想 • 事件簿 • 2016 に向けて
  14. 14. 使っている技術 • Scala
  15. 15. 使っている技術 • Scala • Java
  16. 16. 使っている技術 – Java - • Scala • Java(1.8) • Jetty (Embedded) • Spring Framework (DI) • Jackson • SLF4j / Logback • FastUtil • Kryo • Trie4j • MyBatis • Flyway • Nashorn • gRPC / ProtoBuf • Guava
  17. 17. 使っている技術 – Middle Ware - • NewRelic • JMX with DataDog • MySQL • Redis • DynamoDB • Fluentd • Kinesis
  18. 18. 使っている技術 – 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
  19. 19. 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
  20. 20. 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
  21. 21. アジェンダ • 初期の開発スケジュール • 使っている技術 • アドサーバが持っている機能 • 広告処理概要, 要素技術, 思想 • 事件簿 • 2016 に向けて
  22. 22. アドサーバが持っている機能 • 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
  23. 23. アジェンダ • 初期の開発スケジュール • 使っている技術 • アドサーバが持っている機能 • 広告処理概要, 要素技術, 思想 • 事件簿 • 2016 に向けて
  24. 24. 広告処理概要 SDK AdServerELB CDN S3 Dispatcher Transform Filter JSON Image Redis MySQL Dynamo DB Auction Allocation(最適化問題) Serializer
  25. 25. 初期バージョン設計思想 • なるべく通信はしない • データはなるべくオンメモリ • リフレクションは使わない • 各種処理は計算量O(1), O(LogN)で実装する • ログ基盤に割くリソースはないので、フロントであ る程度頑張る
  26. 26. アドサーバが扱うデータの種類
  27. 27. 広告処理概要 - データの種類 - • アドサーバが扱うデータの種類 – ユーザー主体の情報 – キャンペーン主体の情報 – メディア主体の情報 – マスタ情報 – 速報値カウンタ
  28. 28. 広告処理概要 - オンメモリ - AdServer Redis Pubsub MySQL Master MySQL Slave 管理画面 Pub 1. Sub 2. 起動時に一気にLoad 6. キャッシュ更新 キャンペーン情報 OnMemory 各種情報はオンメモリで Queue 4. Latch 5. Load 3. キャッシュ更新
  29. 29. レプリケーション遅延対策
  30. 30. 広告処理概要 - レプリケーション遅延対策 - AdServer Redis Pubsub MySQL Master MySQL Slave 管理画面 1. Update 3. Pub(ID, LastTimestamp) Sub 4. Timetamp比較 6. キャッシュ更新 キャンペーン情報 OnMemory キャンペーン Table 最終更新時間 Table 2. Update5. Retry 各種情報はオンメモリで
  31. 31. 速報値カウンタ
  32. 32. 広告処理概要 – 速報値カウンタ - AdServer Redis 速報値情報 OnMemory SDK Beacon LogFile Fluentd S3 Kinesis Redis WriterCounter ReadCounter 予算消化情報 時系列カウンタ
  33. 33. 広告識別子
  34. 34. 広告識別子 • 払い出した広告には1件ずつユニークなIDを割り当てている • UUIDは使っていない • OTS (One Time Signature) – 120Bit – Base64URIしたもの • ASCII: 20文字 • サーバ間で協調する事無く、ユニークなIDを生成できる
  35. 35. 広告識別子 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 予約
  36. 36. 広告識別子とメタ情報 OTS Redis Hash Key Field Hash OTS META Value RES IMP VIMP CLICK CONV Time Time Time Time Time Object
  37. 37. Impression Smoothing
  38. 38. Impression Smoothing ベース Device * Channel * DayOfWeek / Per Minute xxx IMP プラン ScoreXScoreX Remain Counter Base Debt Assist Prediction MixedScore Allocation
  39. 39. IMP売り商品 • Standardのアドサーバは2つの広告を扱って いる –IMP売りの商品(純広告) –パフォーマンス広告(運用型広告) • これを1回のリクエストで返す必要がある
  40. 40. 純広告と運用型広告の処理 Channel Channel Channel Channel 純広告 運用型広告 Smoothing Allocation(最適化問題) AuctionAuction Allocation(最適化問題) Merge
  41. 41. Impression Smoothing
  42. 42. アジェンダ • 初期の開発スケジュール • 使っている技術 • アドサーバが持っている機能 • 広告処理概要, 要素技術, 思想 • 事件簿 • 2016 に向けて
  43. 43. 注意事項 • ここから、とても残念な発表の連続です。 • 前提として、 –リリーススケジュールが過酷 –大量の機能リリースが必要 • だったという事を念頭にお願いします。
  44. 44. Release頻度 16 34 34 19 20 12 21 13 18 25 25 15 14 16 7 12
  45. 45. 2014.11 • 基本機能は実装 – iOS, Android, WebSDKは実装済み – Budget Control – Auction – Frequency Control – Rehearsal Mode – Restrict Mode – Naive Allocation – TrackingTool – WebTag
  46. 46. パフォーマンス事件簿 File.1
  47. 47. パフォーマンス障害 • ピークタイムでELBから外れてしまう • Monitor競合がとても多い事を観測
  48. 48. Java Blocking • MersenneTwisterがMTSafeじゃなかった • JavaのPropertiesをオンライン処理で参照してブロック – getPropertyがsynchronized • SecureRandomが刺さる – nextBytesがsynchronized • NewRelicの@Traceが多いと時々刺さる
  49. 49. Java Blocking • 暗号化ライブラリがスレッドブロッカー – Cipherのインスタンスはスレッドセーフではないので毎 回生成する必要がある – ただし、Instance化する時にsynchronizedが存在する – GenericObjectPoolを使った • GenericObjectPoolもsynchornizedなコードが多い – ThreadLocalを使うようにして回避
  50. 50. Java Blocking • getClass().get**Name()がBlockする – OpenJDKのソースを追っていくとBlockする箇所がある
  51. 51. 集団食中毒 事件
  52. 52. 集団食中毒事件 • みんなでランチに豚カツを食べに行った • 夕方に体調を崩して早退 • 家で壮大に吐く • 他にも被害者多数
  53. 53. IAAS事件簿
  54. 54. CDN障害 • クリエイティブ画像が表示されない障害が発生 – CloudFrontの障害 – この年はCloudFrontの障害が多かった • SLA100%のCDNへ移行
  55. 55. AWS • ElastiCache – 自動snapshot取得中にtimeoutが頻発 – Server側に存在しない接続情報が大量に残っていてTCPレベ ルでACKを返さなくなる • AMI(EC2) – 2015.09のAMIで頻繁にインスタンスチェックが失敗する
  56. 56. iOSクラッシュ事件
  57. 57. iOSクラッシュ • 前回、広告を取得した件数よりも、 今回、広告を取得した件数が小さい場合にクラッシュす る • 急遽、求人広告を作ってフィラーとして配信する
  58. 58. パフォーマンス事件簿 File.2
  59. 59. パフォーマンス事件 File.2
  60. 60. パフォーマンス事件 File.2 • 2015年4月28日 • 最近、日に日に負荷が高くなっている。 • ゴールデンウィークが危ない
  61. 61. パフォーマンス事件 File.2
  62. 62. パフォーマンス事件 File.2 • 現象 –GC時間が増加している –FULL GCが10秒に1回くらい発生していた • 対処 –速報値カウンタのTimeline取得をO(N+LogN)から O(1)に –大量のインスタンス生成箇所をつぶした
  63. 63. パフォーマンス事件 File.2
  64. 64. パフォーマンス事件簿 File.3
  65. 65. パフォーマンス事件 File.3 • 2015年5月8日 • GCがやばい • Class Unloadingが多い • チューニングしないと!!
  66. 66. パフォーマンス事件 File.3
  67. 67. パフォーマンス事件 File.3 • 現象 – FullGCが多い – ClassUnloadingが何故か多い • 対処 – GC抑止のためにパラメータチューニング – レキシカルスコープを参照しているLambda式 の排除
  68. 68. パフォーマンス事件 File.3 • GCパラメータ(before) -Xmx****m -Xms****m -XX:+UseConcMarkSweepGC -XX:CMSInitiatingOccupancyFraction=70
  69. 69. パフォーマンス事件 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
  70. 70. パフォーマンス事件 File.3
  71. 71. パフォーマンス事件簿 File.4
  72. 72. パフォーマンス事件 File.4 • 現象 – バックグラウンド処理が遅い • 対処 – 各種実装の最適化 •一部処理の並列化 •不要なデータの読み込みを回避 •通信の回数を減らす
  73. 73. パフォーマンス事件 File.4
  74. 74. パフォーマンス事件 File.4
  75. 75. パフォーマンス事件 File.4
  76. 76. パフォーマンス事件 File.4
  77. 77. アラート通知事件 File.番外編
  78. 78. アラート通知 • 全台バランサから外れていた • 数時間気づかなかった • そもそもアラートが来ない • 何故? • PagerDutyに登録している電話番号間違ってた サービスインする 前の話です
  79. 79. アラート通知 • 一時期、毎朝7時のピークで障害が発生した。 • 好きな着メロだったのに嫌いになった。
  80. 80. パフォーマンス事件簿 File.5
  81. 81. パフォーマンス事件 File.5 • 現象 – 速報値を扱っているRedisの通信帯域がつらい • 対処 – アーキテクチャの変更
  82. 82. パフォーマンス事件 File.5 AdServer Scan Timeline Summary ToCache RedisAdServerAdServer
  83. 83. パフォーマンス事件 File.5 • スケールしないもの(Redis)と直接通信をすると アドサーバがスケールしなくなる • 速報値を扱うプロセスを用意し、アドサーバは それと通信をする。
  84. 84. パフォーマンス事件 File.5 AdServer Scan Timeline Summary ToCache RedisAdServerAdServer Process Summaried Data
  85. 85. パフォーマンス事件 File.5
  86. 86. パフォーマンス事件 File.5
  87. 87. 確率計算ミス File.番外編
  88. 88. 確率計算ミス • 確率計算ミス – 70%で配信したいところが、確率計算をする度にサイコロ(乱 数)を振っていた – 1回の広告取得で3チャンネルを同時に取得する – 1回の広告で70%にしないといけない設定だった – 各チャンネルで70%の判定をしていた – 70% * 70% * 70% = 34.3% – しかも、オペレーション担当に体感30%くらいなんですけど?と 言われて発覚した
  89. 89. 確率計算ミス サービスIN前 です
  90. 90. パフォーマンス事件簿 File.6
  91. 91. パフォーマンス事件 File.6 • 現象 – OTSに紐付くMeta情報が日々肥大化している • 対処 – Serializerを変更
  92. 92. パフォーマンス事件 File.6 • 今まではデバッガビリティのためにJSONで保 存 • KryoのTagFieldSerializerを使用 • BooleanフラグをOTS側に移動
  93. 93. パフォーマンス事件 File.6 • 空間効率が1/3 • SerdeのCPU処理負荷が1/2
  94. 94. パフォーマンス事件簿 File.7
  95. 95. パフォーマンス事件 File.7 • 現象 – オンメモリのキャッシュがObject生成しすぎ – そもそもObject生成が多すぎ – GCが荒ぶっている • 対処 – データ構造、および処理を大幅改修
  96. 96. パフォーマンス事件 File.7 • リクエストの度に大量にオブジェクトを生成し ている箇所がある • キャッシュからのコピーが大量に発生しており、 1リクエスト中のフットプリントが大きい • 時系列情報をナイーブに持たないでサマライズ • HistogramのBin構造を最適化
  97. 97. パフォーマンス事件 File.7
  98. 98. パフォーマンス事件 File.7
  99. 99. パフォーマンス事件 File.7
  100. 100. パフォーマンス事件 File.7
  101. 101. Kryoの前方互換性問題
  102. 102. Kryoの前方互換性問題 • KryoのTagFieldSerializerは前方互換性が無い – TicketにあるPRも問題を解消できない
  103. 103. Kryoの前方互換性問題 • サーバの更新中に発生する • 更新中は古いサーバと新しいサーバが混在する • 新しいサーバが広告を払い出す • 古いサーバがビーコンを受け取る • 古いサーバは古い定義のまま新しいバイナリを 受け取る
  104. 104. Kryoの前方互換性問題 • TagFieldSerializer –Tagの順番に処理していない(Field名でソートし ている) –知らないTagIDを読み込むとエラーが出る
  105. 105. Kryoの前方互換性問題 • 改善版 –Tagの順番でソートしてSerializeする –UnknownなTagを読み込んだら処理を中断す る –SKIPしてはいけない
  106. 106. レプリケーション事件簿
  107. 107. レプリケーション事件簿 • レプリケーション遅延 – レポートテーブルが同居していて、しかも巨大なトラン ザクションが発行されていた – 30分以上遅延することがあった – リロードが失敗する事が多発
  108. 108. レプリケーション事件簿 • クエリを修正 • そもそも、レポートDB分離 • キャパシティプランニングを楽にするためにAuroraへ
  109. 109. gRPC事件
  110. 110. gRPC • サーバ間通信でgRPCを採用した –ProtoBuf Beta –Netty Beta • ELBを通すとNettyの不具合を踏む • 異常系の不具合をたくさん踏む
  111. 111. アジェンダ • 初期の開発スケジュール • 使っている技術 • アドサーバが持っている機能 • 広告処理概要, 要素技術, 思想 • 事件簿 • 2016 に向けて
  112. 112. 次のステージへ • スケールできる土台は一通り作った • Stream処理、オンライン処理への準備も出来 つつある
  113. 113. 今の構成 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
  114. 114. 最後に • 意外と広告は面白い – ソフトウェアエンジニアリング, 大量のログ, 機械学習, 最適 化問題, 大規模トランザクション – 実時間で実現する必要がある • 技術だけでなく、ビジネスも楽しもう • もしかしたら、誰でも出来るかもしれない • 誰でも出来る事は、誰にも出来ないレベルまで昇華しよう • イノベーションは個人の裁量から生まれる

×