高速日記

ソフトウェアの高速化・チューニングの話について好き勝手にまとめていくブログです

LINE Developer Days 2015に行ってきたメモ

あわせて読みたい

Opening CEO 出澤さん

LINEは世界でもっとも早く成長しているアプリの1つである

最初のブレークスルーは無料通話とスタンプ

1億8千万ユーザ、170億コミュニケーション以上

日本では5800万ユーザ

GameだけでなくEntertainment領域でもPlatformを作っている

LINE関連アプリで76アプリ9億ダウンロード

これからGlobalとLifeの2点においてビッグプレイヤーに対して追いつき追い抜かなければいけない

LINE Global Culture朴 CTOの話

8カ国にブランチがあり、協力して開発している。東京、福岡、大連、ソウルなどなど

Autonomous Teams

LINEが大事にしていることとして、主体的に動けるチームである、ということを目指している

Cold-caseプロジェクト

開発をしているとバックログが溜まっていくが。バックログを消化するため年に一度、未消化のバックログを集めてプロジェクトとして立ち上げる。

それをCold-Caseプロジェクトと言う。エンジニアで協力してバックログを片付ける

普通自分が経験できなかった領域のプロジェクトに参加することもできる

Remote Collaboration

遠隔地のチームと一緒に作業をするため、課題の可視化、議論の可視化が基本となる

  • 色々喋っていたけどメモできず

Challenge and Contribution

機能開発をしていくにあたり、スケーラビリティやパフォーマンスを基本として考える必要がある

安定していなくてもLINEの水に合えばオープンソースを入れて、Contributeしていく

Trust & Respect

信頼と尊重がベースとなり、各自が自主的に動いていくことに価値を置いている

Trust & Respect
↓
Responsibility-basedPlanning & Self-directing Work & Peer Code Review
↓
Positive Peer Pressure & Co-worker Review

Global Player

Global Enginnerを目指す人はみなシリコンバレーに向かっている

が、シリコンバレーとの競争が激しいからこそ日本発のグローバルサービスを作っていきたい

感想

信頼をベースにしたマネジメントフリーな組織を作っている、というのはとても興味深い話だと思う。

人材の質がある程度のレベルを超えたのを揃えないと難しい話ではあるが、達成できている、ということなのかな

LINEメッセンジャー基盤の話

LINE遠征隊

現地に行って、どういう使われ方をしているのかを把握する。そのチームをLINE遠征隊と呼んでいる

開発者は様々な地域に遠征している

現地と同じネットワーク環境を整備して、スタンプの送受信とか写真の利用とかをしている

飛行機内のWifiが不安定だったので飛行機の中でテストした。

日本と海外の違いとしてモバイルネットワークの通信環境の品質差がある

IDLE → CELL_DCH → CELL_FACH

実際のメッセージの前に先にサーバにウォームアップ用のパケットを送っておくことによって3G環境下のユーザ体験を改善する

日本の場合は問題ないが、海外の低速な回線では非常に意味がある

上記の技術を3G WARMUP と呼んでいる

グローバルなメッセンジャーの特徴としてPakistanからの発信がPakistanよりもSaudiArabiaへの発信の方が多い

そういう国の事情を考慮して実装をする必要がある

スペインでAndroidのバッテリー消耗が激しいという注文が来ていた。素早く通知して欲しい、長い間待ち受けて欲しいという命題を満たす必要がある

メッセンジャーがサーバと通信する頻度を減らしたり、というような細かいチューニングを1年かけてやった

ネットワーク的な位置の近さを実現するためにPOP(Point to Peer)を設置する

LINEアプリ→Frontend→Backendという3層構造となっている

開発言語は基本的にJavaを使用しているが、POPについてはErlangを使用してPOPしている

ユーザ体験の向上について

ユーザがどう思っているのかを知らなければいけない

AppStoreやGoogle Playのレビューを集計して、ある程度定量化して調べられるようにしている

image

それにより改善のプロセスを早めている

イベントの送信によってイベントがあってシステムからわかるようになる

AppReviewとEvent Analyticsの2つからーザの志向を分析している

まとめ

現地に行って同じ環境を作るというエモーショナルなアプローチとアナリティクスのアプローチの両方のアプローチをとっている

感想

グローバルなサービスを作るために各国のネットワーク回線や端末品質、文化などを知っておく必要がある、という話

Erlangでfront serverを作るというのは自分には無い発想だけど、生Cで書くよりは良さそうだ。

なぜErlangなのかをもっと深掘りして話を聞いてみたい

アプリレビュー分析などは自社サービスで作らなくてもありそうな気はするけど以外と無いのが不思議

Line Platform Developer Chronicle

LINEサーバサイドの開発をしているつるはらさん

  • LINEメッセージング基盤の進化
  • LINE流マイクロサービス

LINEメッセージング基盤の進化の歴史について

2011年6月 リリース。開発開始から2ヶ月でリリース

image

Polling+Push通知の問題点として以下のような問題があった * Pushは自社でコントロールできないのでメッセージの通知が遅れる * pollingをずっとやっているので、無駄なリクエストが大量に来る

ClientとServerの間にgatewayという層を容易した

image

ClientがGatewayにfetchをリクエストするとGatewayはServerにたいしてコネクションを確立し、Serverからレスポンスが返ってくるのを待つ

Gateway層はnginxと拡張モジュールで層を作っている

拡張モジュールでsegmentation fault地獄におちいった

image

同期処理が上手くいっていなかった。共有メモリらへん?

やはり安定性に問題があったのでErlangを採用してnginxの層を置きかえた

Erlangホットスワップ機能があり、並行性や分散性に優れるのでとても良い

image

LEGYという名前のLINE Event Delivery Gatewayというものを作った

image

2012年7月 にconnection数が多すぎるという問題になった。

Connectionにまつわる問題としてProtocolがHTTPでLong Pollingのコネクションを貼り続けている

API用コネクションもLong Polling用コネクションも必要だったのでたくさんコネクションを貼る必要があった

image

SPDYを採用した

image

ClientとLEGY間の通信が

1 Connection Multiplex
ヘッダ圧縮

で行われるようになり、メリットが大きかった

2012年10月頃 に海外でのパフォーマンスを追求した。

image

Clientは最寄りのLEGYに接続する。LEGYは専用線でApplication Serverと接続をする

image

LEGY-メインサーバは距離が離れていて遅いので、LEGYは返事を待たずにClientにレスポンスを返す。それによってClient側のUXが向上する

LINEのサービスをどのように実装してきたか

スピード & 機能 & 品質を満たさなければならない

マイクロサービス的に開発をしている。モノシリックな場合、優秀な人が入ってきても全体を把握しないと開発できない。マイクロサービスとして作成し、その間をAPIなりJob Queueなりで繋いでいる

Talk-Serverはメッセージング・ソーシャルグラフの機能のみ実装している

それ以外は別のサービスとして動いていて、開発プロセスやデプロイフローもそれぞれ独自である

Talk-ServerはJava、公式アカウント系の機能はScalaなど、ものによって色々なツールを使っている

image

バックエンドサービス:認証管理、Abusing、Push通知、イベント処理、外部連携gateway、などなど

マイクロサービスは単にサービスを分けて開発すればいい、というものではない。組織に関する問題も一緒に考える必要がある

LINE流マイクロサービスを支える組織

image

組織図や会社をまたぐアドホックなチームを形成し、独立して裁量を持たせないと単にサービスを分割しただけではコミュニケーションコストが増加してしまう

チームは短期間でiterationをまわし、目的を達成したら縮小あるいは解散する

LINE流マイクロサービスを支えるプロトコル管理

Apache Thrift、Protobuf、REST

image

ドキュメントでAPIの仕様の定義をして、これを使ってください、というやり方もあるがそうではなくApacheThriftで仕様を定義している

Apache ThriftはIDLでのプロトコル定義から各種言語のStubを吐いてくれる

LINE流マイクロサービスを支えるファシリティ

image

 github→Jenkins→maven repository→PMC(内製のデプロイツール)→Server→IMON(モニタリングツール)

といった開発フローが共有されている

今やっていること、今後やっていくこと

マルチデータセンター

各拠点にはフロントエンドサーバしかない。

マイクロサービスの発展

Talk-Serverの機能がふくれ上がっているのでマイクロサービス化していかなければならない

具体的なところは午後のセッションで説明する

HBaseとRedisを使った100億超/日メッセージを処理するLINEのストレージ

聞いたけどHBaseの知識が乏しく説明できる自信が無いのでパス

4年に渡るLINE Androidアプリの進化とチャレンジ

2011.4 開発開始。Androidアプリの開発経験もないが一ヶ月半でリリース

秘訣はない。試行錯誤が多い

印象にある苦労したことは デザインの適用 。デザイナが少ないため、iPhoneのデザインをAndroidに適用した。Androidは画面解像度など端末の種類が多いので、画像サイズを9-patchで適切に変更する必要があった。画面下にコントロールが集まるなど、Androidのアプリとしては違和感のある配置だった。

現在 iPhoneAndroidでデザインが異なっている。9-patchもデザイナーがやってくれる

image

当初はGoole PlayのDeveloper Consoleを使っていたが以下のような問題があった

  • コードを難読化しているので、クラッシュレポートが読みづらい
  • クラス名などで検索したい
  • BTSと連動したい
  • 任意の場所でレポートしたい

特に最後の問題が重要で、そもそもクラッシュをすべきではない。不明の異常が起こった場合でもクラッシュはしないようにしたい、その場合も任意の場所でレポートさせる必要がある

そのため独自のCrash Reporting System を用意している(Treasure DataSDKなどで同様のことができそう)。専用のSDKも用意している。難読化を元に戻してからスタックトレースを投げている

ソースコードのsubmoduleによる分割

ソースコードを一箇所で管理すると、開発・運用規則などのコミュニケーションがめんどいので、gitのsubmoduleを利用してソースコードを分離した。

main repositoryから機能ごとにsubmoduleを作ることにより、コミュニケーションコストを削減した。

リリースのときと共通サブモジュールの変更のときだけ意識合わせが必要

開発進行方法 について以下のような問題があった * 同じようなクラスが作成される * チーム間で知識が共有されない

新しい機能を開発するときに、一時的なチームを作り、終わればそのメンバーは解散するようにしていた

2013年

通信方法の改善

大きな修正項目として通信方法の改善を行った(実は2012年から継続してやっていた)

接続するサーバの数が増えていった。公式アカウント、メッセージ管理、スタンプ情報などなどのサーバにアクセスする必要があったが、それぞれのサーバにコネクションを貼るのはコストが高い。

Gatewayサーバが手前に入ることになった。1つのコネクションを使い回すので簡単にリクエストを送信できる

HTTP pipeliningを使うが、1,2,3と投げたときに2番目が遅くなると3番目も合わせて遅くなる

↑説明用の写真が欲しい

SPDYは1,3,2と受けとることができる

自社製Pushサービス

Google Play Serviceを利用できない端末がある。(子供向けのらくらくフォンなど)

Google Play Serviceが使えないと → 位置情報が使えない、Google Mapが使えない、GCMが使えない

対策として自社で開発したPushサービスを利用している。状況によって、GCMと自社Push Serviceを切り替えて使用している

GCMを利用できないと判断した場合のみ自社のpush serviceを利用している

低スペック端末に対する最適化

最初はデフォルトのイメージを表示し、ダウンロードしたイメージと切りかえているが、fade inのアニメーションを使っている

低スペック端末の場合、fade inが重くスムーズに切りかわらない

CPUの速度に問題がある場合、画面効果を切り替えている

バッテリー容量に対する最適化

サーバとの通信の話をしていたがメモできず

現在 開発メンバー:22名 ソースコード量:437000行 コミット:200 commits/week

ビッグデータを活用するための分析プラットフォーム

データ分析について

  • Collecting(集約)
    • リーズナブルなデータの収集
    • 大量データの保持
  • Reporting(報告)
    • 柔軟なデータの集計
    • わかりやすいチャートでの可視化
  • Analyzing(分析)
    • 簡便で高速なデータの抽出

異なるニーズ

  • エンジニアの声
    • UIなんてどうでもいい
    • 生のデータに触りたい
  • プランナーの声
    • KPI
    • きれいなグラフで見たい
    • Excelでダウンロードできる

Forエンジニア

  • 凝ったことをする必要がない
  • クエリを自由に発行できる
  • APIによるバッチ処理との連携ができる

image

サーバ→LogCollector→[Realtimeanalyzing(Norikia)→Notification Dashboard]
                  →[Data lake(Hadoop)→ Query UI]

LogCollector = Fluentd

Norikra(リアルタイム集計処理システム)

Shib/ShibUI(Webベースのクエリツール)

Forプランナー

  • データを可視化
  • データのダウンロード
  • NoSQL

image

Hadoop

大規模分散データ処理環境

HDFS/MapReduce/YARN

Hive/Presto: PrestoはHiveより高速なのでBIツールのバックエンドに使用している

PrestogresというPrestoをPostgresのように見えるコネクタを使っている

DWHはInfiniDBを使っている いまいち何でだっけというのがわからん

InfiniDBはカラム型分散データベースで、フロントエンドからはMySQLとして認識される

BIツール

IBM Cognosを使っている。レポートオーサリンツール

ヒートマップのような複雑なものも作れる

Pentaho:OLAP型の多次元分析システム

重要視すること

  • データはなるべく隠蔽する
  • ユーザトラッキングはしない ユーザ数が多すぎて苦労の割にメリットがないのでやっていない

グローバル化で見えてきた課題

  • サービスの変化
  • 人の変化
    • プランナーの増加

結果的にKPIが増加する

サービス x メジャー x ディメンションで種類が爆増してしまう。

KPIが増加し、忙しくなる → 誰もKPIをつぶさに見なくなる

KPIなんて人手で見なくても良い。KPIの変化を伝えることをツールでサポートしてあげれば良い

KPIモニタリングシステムを開発している

  • すべてのKPIのトレンド分析の自動化
  • 時系列から予測値を算出する
  • 異常値を検出してアラート

Spark Clusterを使っている

  • KPIの時系列データを分析して予測モデルを構築し、Kafkaに保存する
  • 予測値と実際値を比較し、大幅に異なる場合通知する

まとめ

Akka ActorとAMQPで作るLINEメッセージングパイプライン

LINEのメッセージングとは * 人と人(一般アカウントと一般アカウント) * 人とシステム(一般アカウントと公式アカウント)

公式アカウントはたくさん友達がいて、一気にブロードキャストする必要がある

なのでトラフィックがバーストしやすい

LINEメッセージングパイプライン

image

デバイス -> Talk -> Fethcher -> 受信キュー → Pusher → 外部システム
               ← FanOut← 送信キュー ← APIサーバ ← 外部システム
  • 1: 受信キュー(RabbitMQ) AMQPを使っている
  • 2: Pusher
  • 3: FanOut

メッセージングならではの要件として * 送信した順序で受信側に到達しなければならない

通常のProducer/Workerパターンだと処理順序が保証されない。そこで1Q1C(1 Queue 1 Consumer)という構成にしなければならない

Consumerが死ぬとキューが溜まりつづけるのでFailOverする必要がある。

AMQP ACK

これからの話としてAMQPの仕組みとして↓のような状態遷移をするという前提知識が必要

image

実装例

image * メッセージキュー(3) * コンシュマー(4) * コーディネーションキュー(キューの名前を入れる)

コンシュマーはコーディネーションキューからメッセージキューの名前を取りにいく。このとき、コンシュマーはackを返さないであえてキューデータの状態をunackedのままにする。

特定のコンシュマーがダウンした時にキューデータがunlockされるので空いたメッセージキューが待機中のconsumerに割り振られる

課題 スループットの改善

image

micro batch処理をしていたがstreaming処理に変更した

並行プログラミングがあるが、職人芸的なやり方になるのでScalaのAkkaを使った

Akkaのアクターモデルについて

actorがmailboxをもっていて、順に処理していく

古くからあるthread and lockingだと定期的にlockingしないといけないから大変

Scala/Javaで使用できる並行プログラミングモデル

有限ステートマシンとしてのアクター

  • Receive Functionの切り替えが可能
  • 内部ステートを引き継ぎつつ、状況に応じて異なる動作を定義できる
  • 複雑なメッセージフローを

Supervisorによるエラー処理フローの分離

image

Akka ActorによるPusherの実装

後で説明を埋める

メッセージ送信をFIFOからラウンドロビンに変更する

ネットワークのQOSラウンドロビンと同じものを実装している

なぜ非同期技術が重要なのか

  • マイクロサービスの採用によりサービス間通信の重要性が高まった
  • 同期サービスは連鎖的な障害が起きやすい