DeNA TechCon 2019 ベストトークセッションをご紹介します

2019.02.06_133.jpg

こんにちは!技術広報の玉田です。2019年2月6日に開催し、社内外から約1500名の方にご参加いただいた DeNA TechCon 2019 について、社内社外で実施したアンケートの満足度が高かったセッション Top5 をご紹介します。

社外アンケート 満足度 Top5 セッション

約400名の社外の皆様にアンケートにご回答いただき、参加したセッションの満足度を「満足、やや満足、どちらでもない、やや不満、満足」の5段階で評価いただきました。ご協力いただいた皆様どうもありがとうございました!! 評価いただいた中から満足度Top2(満足、やや満足)の割合が高かったセッション Top5 をご紹介します。

1位. AI によるアニメ生成の挑戦

  • 満足度Top2:98%
  • 登壇者:濱田 晃一、李 天琦
AIによるアニメ生成の挑戦 from Koichi Hamada

2位. 『モビリティ・インテリジェンス』の社会実装

  • 満足度Top2:94.3%
  • 登壇者:織田 拓磨、益子 遼介
『モビリティ・インテリジェンス』の社会実装 [DeNA TechCon 2019] from DeNA

3位. 10年目の『エブリスタ』を支える技術

  • 満足度Top2:91.7%
  • 登壇者:松尾 卓朗、井田 祐太
10年目の『エブリスタ』を支える技術 from DeNA

4位. 「マンガボックス」の価値を革新するエンジニアのチャレンジ

  • 満足度Top2:89.4%
  • 登壇者:神武 里奈

5位. スマホゲームのチート手法とその対策

  • 満足度Top2:88.6%
  • 登壇者:舟久保 貴彦
スマホゲームのチート手法とその対策 [DeNA TechCon 2019] from DeNA

DeNA社内アンケート ベストトークセッション5つ

実はDeNA社内メンバーにもアンケートに協力してもらい、「あなたが思うベストトークはどのセッションでしたか?」と聞き、回答してもらいました。その結果ベストトークとして推薦された推薦率が高かったセッション5つをご紹介します。

1位. AI によるアニメ生成の挑戦

スライドは上記となりますが、こちらでは「AI によるアニメ中割生成結果」についてもご紹介します。

 

2位. ゲーム開発者からMaaS開発者へ

  • 登壇者:惠良 和隆


3位. 「マンガボックス」の価値を革新するエンジニアのチャレンジ

  • 登壇者:神武 里奈

3位. スマホゲームのチート手法とその対策

  • 登壇者:舟久保 貴彦


5位. 車載カメラの画像を使用した3次元点群復元と物体認識技術における深層学習の活用

  • 登壇者:葛岡 宏祐


5位. DeNAのインフラ戦略 〜クラウドジャーニーの舞台裏〜

  • 登壇者:金子 俊一

おわりに

いかがでしたでしょうか。DeNA TechCon 2019 ではこの他にも様々なセッションを実施し、それらのセッションについても皆様に評価いただきました。ご来場の皆様、アンケートにご回答いただいた皆様、ご協力どうもありがとうございました。

その他のスライドや動画についても今後ご紹介していきますので、以下公式 Twitter アカウントをぜひフォローいただければと思います。それでは引き続きどうぞよろしくお願いします!

ツイート
シェア
あとで読む
ブックマーク
送る
メールで送る

DroidKaigi 2019 に参加しました!!

DroidKaigi 2019 お疲れ様でした!技術広報の玉田です。DroidKaigi 2019 では DeNA から7名のエンジニアの発表が採択され、それぞれ登壇を行いましたのでご報告します。

採択された7名6セッション

DroidKaigi2019.png

マルチモジュールなプロジェクトでテストはどう変わる?

初日の2/7の10:20から、Hall A にて DeNA SWET チームの田熊が登壇しました。詳しくはこちらのブログ記事でもコメントしていますのでぜひご覧ください。

Espresso のテストを Android の最新トレンドに対応させよう

2/7 の 12:50 から Room2 にて DeNA SWET チームの外山が登壇しました。詳しくはこちらのブログ記事でもコメントしていますのでぜひご覧ください。

外部デバイスと密に連携する Android アプリに最適なアーキテクチャとは?

2/8 の 10:30 から Room6 にて 次世代タクシー配車サービス「MOV」のエンジニアである三輪と本戸が登壇しました。

Wi-Fi RTT による屋内測位アプリを作ろう

2/8 の 11:20 から Room6 にて 次世代タクシー配車サービス「MOV」のエンジニアである @napplecomputerが登壇しました。

WiFi Direct + VpnService で SIM 無し Android を Web 世界に社会復帰させる話

次世代タクシー配車サービス「MOV」のエンジニアである空中が登壇予定でしたが、インフルエンザで当日は登壇できなかったため、 Android Reject Conference 2019/2 で登壇しました。

WiFi Direct + VpnServiceでsim無しAndroidをweb世界に社会復帰させる話 from Kiyotaka Soranaka

UI テスト (Espresso) の高速化をさらにすすめる

2/8 の 16:50 から Room3 にて DeNA SWET チームの平田が登壇しました。詳しくはこちらのブログ記事でもコメントしていますのでぜひご覧ください。

UIテスト(Espresso)の高速化をさらにすすめる from Toshiyuki Hirata

ブース展示も行いました

DroidKaigi 2019 のブース展示にて、 次世代タクシーアプリ「MOV」の車載機器、クラウドアーキテクチャ図の展示などを行いました。

その他、WebCamカバーのプレゼント企画、ライブ配信アプリ「Pococha」のチョコやステッカーなども展示しました。

おわりに

登壇いただいたみなさま、当日含め準備いただいた運営のみなさま、参加者のみなさまのお陰でとても濃い2日間を過ごすことができました!どうもありがとうございました!!

DeNA では引き続き CI/CD Test NightAndroid Test Night など Android アプリ開発者のコミュニティ活動をサポートさせていただきますので、今後共どうぞよろしくお願いいたします。 ベイスターズのビール2.jpg

ツイート
シェア
あとで読む
ブックマーク
送る
メールで送る

DeNA TechCon 2019を開催いたしました

こんにちは。システム本部品質管理部SWETグループの加瀬です。

techcon_2019_1.jpg

2019年2月6日にDeNA TechCon 2019を開催いたしました。今年で早くも4回目の開催となりますが、今年もたくさんの方にお越しいただき、大盛況のうちに幕を閉じることができました。 ご来場の皆様、登壇された皆様、運営の携わったスタッフの皆様、ありがとうございました!

早速ですが、今年のTechConの様子を紹介したいと思います。

オープニング

オープニングはDeNAのエンジニアリングの統括を務める小林より、今回のテーマである「SHIFT UP」についてや、後の発表で詳しく語られるオートモーティブやクラウド移行の話の紹介がありました。 最後に時間の都合上紹介しきれない技術はたくさんあるものの、吟味したAI・ゲーム開発・エンタメ・ヘルスケア・オートモーティブ・開発基盤、この6つを主とした発表があることを紹介して今年のTechConが開幕となりました。

techcon_2019_2.jpg

会場

今年もステージを4つに分け、それぞれのステージでDeNAの様々な事業における技術的なチャレンジについての発表が行われました。 発表後には登壇者に質問できる場が設けられ、参加者とディスカッションしている様子が見られました。

techcon_2019_3_2.jpg techcon_2019_4.jpg techcon_2019_5_2.jpg techcon_2019_6.jpg

今年は開催前にgihyo.jp様よりTechConの見どころを紹介(前篇 後編)して頂いたり、Twitterにてそれぞれの発表の紹介をしてきました。
登壇で使用した資料や動画も、準備ができ次第公開する予定です。興味があったものの当日聞くことができなかった発表については、公開をお待ち頂ければと思います。

それでは、来年もまたDeNA TechConでお会いしましょう!

techcon_2019_7.jpg

当日のツイートの様子

ツイート
シェア
あとで読む
ブックマーク
送る
メールで送る

DeNA TechFes 2019を開催します

denatechfes_cover.gif 明日2019年2月6日(水)は、DeNAの技術を活用した取り組みや新たなチャレンジについて紹介する技術カンファレンス「DeNA TechCon(テックコン) 2019」開催日です。

今年度は、「参加したかったけど参加できなかった方」や「参加したけど、詳細をもっと聞きたい方」などの方向けに、DeNA TechCon 2019 の After Party として DeNA TechFes 2019 を開催します!

DeNAの事業やサービスにフォーカスしたTechイベントやエンジニアのキャリアにフォーカスした採用イベントを小規模で週代わりに開催予定です。

皆さんと近い距離でお話しできることを楽しみにしております。

イベント詳細

※アップデートがあり次第更新いたします!
※各イベントで参加登録が必須となりますので、イベントページをご確認の上ご登録ください。

2/13(水)マンガボックスTech Night

DeNAが提供する週刊マンガ雑誌アプリ「マンガボックス」を対象とした、サーバーサイドエンジニア向けのキャリア採用イベントを少人数制で開催いたします。 2018年12月で5周年を迎えた、マンガボックス。さらなる進化を目指し言語の移行など大規模なリニューアルを予定しており、即戦力となるサーバーサイドエンジニアの募集を始めました。 本イベントではこれまでお話ししてこなかった、開発現場のリアルや今後サービス拡充に向けてテクノロジー観点で考えていることなど、プロダクトオーナーと担当エンジニアがお話しさせていただきます!

2/20(水)Meet the DeNA #Engineer career night

DeNAのエンジニアが経験してきたキャリアパスをエンジニアの方向けに赤裸々にお伝えするためのMeetupです。実際の働き方やキャリアの広がりの可能性を知りたい方は是非ともご参加ください。当日はDeNAでのキャリア形成、エンジニアカルチャーや制度、ものづくり組織の取り組みをメインにお話させていただきます。システム本部本部長の小林(nekokak)や、DeNA内外でキャリアチェンジを行なってきた多様なキャリア経験のあるエンジニアの登壇を予定しております。

3/6(水)オートモーティブ×ヘルスケア TechNight 〜テクノロジーのちからで社会課題を解決する〜

オートモーティブ・ヘルスケア事業に関わるエンジニアがTechConで伝えきれなかった開発の裏側に加え、働き方やキャリアについてパネルディスカッションを交えながら赤裸々にお話します。 新しい技術領域やキャリア形成にチャレンジしている部署なので、既存のDeNAのイメージにはない新しい気づきを感じてもらえればと思います! ※DeNA Engineers' Blogにて詳細発表予定。

3/15(金)DeNA GAME tech talk 〜モバイルゲームを支える基盤の技術チャレンジ〜

ソーシャルゲームにおいてネイティブゲームが主流になっている昨今、それを支えるバックエンドシステムに求められる要件の高さや技術的難易度は高くなっています。DeNAのゲームを支えるバックエンドシステムにフォーカスしたセッションを行います。mobage時代からネイティブシフトを経験したDeNAだからこそ語れるこれまでのゲーム開発と現在のネイティブゲーム開発の違いや、今後のバックエンドシステムに求められる要件を元に現在DeNAがチャレンジしている内容についてお伝えさせていただきます。

日程調整中:PocoDevMeetup

ライブ配信アプリ「Pococha」のエンジニアが開発にまつわる勉強会を開催します。ライブ配信サービスの領域は、今が旬で、皆で寄ってたかって領域を盛り上げていくタイミングだと思っています。ライブ配信アプリ・機能を作りたい方、エンタメサービス開発に携わっている方、Pocochaのことを知りたい方、サービスの新規立ち上げからグロースの苦労やノウハウ、開発の裏側を大公開しますので、是非、ご参加ください!

ツイート
シェア
あとで読む
ブックマーク
送る
メールで送る

MOV タクシー配車アプリ RubyからGolangへ刷新 マイクロサービス化

RubyからGolangへの移行を進める過程で、システムアーキテクチャがマイクロサービス化していくという稀有な体験をしたので記事を書きました。

次世代タクシー配車アプリMOV(モブ)及び、タクシー車両内の乗務員向けアプリに係る WebAPI 50前後をRailsからGolang net/http に刷新しました。その過程でマイクロサービス化が進んだ事例を紹介します。MOV サーバエンジニア池田 周平です。サービスを継続しつつシステム刷新するために、なぜその判断を行ったかについてお伝えできれば幸いです。

MOV(旧タクベル)ご存知でしょうか?神奈川、東京でサービス提供中のタップ操作でタクシー配車ができる配車アプリです。 スクリーンショット 2018-12-28 11.03.58.png

実証実験を繰り返しサービスリリースしました。 立ち上げ初期段階から居たメンバーに話を聞くとRailsで高速にプロトタイピングを繰り返していたそうです。 リリース直前にGAE FEサーバのスケールとスピンアップ速度の観点でGAE SE Golangへ刷新を決め、新設WebAPIはGolangで実装しましたが大部分はRailsのままリリース当日を迎えました。

スクリーンショット 2019-01-08 19.19.41.png

APIバージョンをv1, v2, v3と上げ、アプリの強制バージョンアップでRubyからGolangに切り替える作戦を立てるも、後方互換性を維持し古いアプリでも配車可能であり続けるという運用方針があり、コード2重メンテ問題を回避するため断念しました。開発チームではGolang刷新を完遂したいとたまに話題にしつつも、日々の機能追加や運用に工数を割いていました。

GAE 1%カナリアリリース

リリース直後特有の繁忙期が過ぎたある日、マネージャからGolang移行チーム設立と担当を任されました。移行チームが出来て任されると自分ごとになりムクムクとやる気が出てくる点ワタシ自身が驚きました。

まず最初に考えたことは安全に移行するための仕組みです。

車両軌跡データやユーザアプリと乗務員アプリ間で配車ステート更新を行うため一部のデータ構造や通信シーケンスが複雑です。開発環境でバグ取りきれず本番環境で不具合に繋がる可能性がどうしてもありました。電車やタクシー内で考えた結論はカナリアリリースの仕組みを作り WebAPIごとに最初の24時間はRuby99%, Golang1%でトラフィックを分割して監視、その後割合を増やしていくという作戦でした。

GAEはservice versionごとの段階的なトラフィック切り替えをサポートしていますが、ルーティングを制御するdispatch.yamlの更新はゼロイチ切り替えのためproxyサーバを用意して切り替えることにしました。

GAE標準のトラフィック切り替え機能

スクリーンショット 2018-12-28 13.20.36.png

Golang移行対象WebAPIの1%カナリアリリース

Proxyのversion1と2の差は、刷新対象のWebAPIについてトラフィック流し先がRuby版かGolang版であるかの違いです。 スクリーンショット 2018-12-28 13.47.20.png

このようなアーキテクチャ設計にした狙いは、ゼロイチでルーティングを切り替えるGAE disptach.yamlの仕組みから最小工数でカナリアリリースできるように変更できる点、RubyとGolangサービスで共通formatのログを出力できる点です。1手で2つのメリットあるため採用しました。Cloud Functionsを利用するといった他の選択肢もありました。複数ある選択肢から早期に絞りこめたのはGoogleテックコンサルの皆様に定期的に相談できる恵まれた環境にあった点が大きかったです。サポートとても感謝しています。

Proxyサーバを実装する

GAE dispatch.yamlを代替するサービスを便宜上proxyサーバと呼んでいます。実態はHTTPサーバでHTTP CONNECT methodはログ出力するため利用していません。次のようなざっくり目標と設計で開発しました。

  • Proxyは通信の土管に徹するサービス
  • 処理のオーバーヘッドは50ms以下が目標
  • APIサービスへのHTTP通信はNon-blocking I/Oで必ず行う
  • JSONパースは処理時間が掛かるため行わない
  • BigQueryへログ出力を行う

Golangで素直に書いていけば実現する仕様です。本体は200行くらいでどのサービスに通信を振り分けるかはrouterをそのまま利用して実装します。仮想コードの方が伝わるので載せておきます。


func init() {
    router := router.New()
    setAction(router, "/", iamproxy)
    setAction(router, "/v1/drivers/*path", rubyService)
    setAction(router, "/v1/users/*path", golangService)
    http.Handle("/", router)
}

func main() {}

先ほど本番サーバをStackdriver traceで計測したらproxyの処理時間は15msでした。サービス間の通信はurlfetchを利用していて、GAEだとGCPの同一データセンター内にdeployされる特性があるためレイテンシは低めです。詳細は公式の Google App Engine 上でのマイクロサービス アーキテクチャ に記載があります。

routerはwild card routingといった標準的な機能が利用できるものを採用しました。特に高速化のために内部で Radix tree を生成し、サーバ起動時にURL routingの名前空間が重複しているとエラー吐いてどこが重複したか教えてくれるようならライブラリを利用するとよいです。複数のAPIを段階的に移行する際の助けになりました。

Proxy導入でログ出力を強化する

複雑な構造を持つJSONをRubyからGolangに移行したとき、RubyとGolangの細かな仕様差、たとえばゼロ値で苦しめられます。 元の構造では気軽nullを扱っておりJSON objectの各プロパティの型がnullableになっていました。ArrayやStringが空のとき [] or "" or null がAPIごとにバラバラだったため、正しく移植しきれず何箇所かで失敗することが予想できました。

現行WebAPIがどういった構造のJSONを送受信しているか蓄積し知るためProxyサーバで HTTP Request/Response/Headerを全てStackdriverにログ出力して、Stackdriver exportでBigQueryにsyncしました。この設定はボタンポチポチで設定できる割に効果が大きく移行をサポートする強力なツールになりました。(開発者用のログはオートモーティブ事業部内での厳しい個人情報取扱規程・個人情報保護指針があり、位置情報や選択内容及びアカウント情報は全てサーバ内部のメモリ上で削除し個人を特定出来ない形でログ送信しています)

億単位の通信ログからBigQueryで目当てのログを検索できたときは、1歩時代が進んだ感あって気に入っています。またStackdriverはStackdriverMonitoringで簡単に監視設定を作り込みSlackやPagerDutyと連携できるため頻度高く利用しています。

機能追加とGolang移行のバランス

サービスへの機能追加とシステム刷新のバランスは難しい問題です。開発の手を止めることが出来ればよいのですが、システム刷新を理由にリリース直後のアプリで機能追加速度を落としたくはありませんでした。50前後あったWebAPI次の5つに分類し段階ごとにリリースしました。特にHTTP GETなWebAPIはステートレスでテスト容易だったため早期に移行を行いました。5段に分けてリリースした理由は、1段目は単純なAPIを移行し実行可能性を調査するため、2段目移行は移行対象が大きすぎて全体把握と品質担保が難しいといった問題を回避するために、QAを行いやすい単位で分割していきました。

  • アカウントAPI
  • 配車API(method:GET)
  • 配車正常系API
  • 配車準正常系・異常系API
  • その他(お知らせ等)

移行中のGoとRubyどちらに実装すればいいといったコンフリクトが複数発生するなと予期していました。実際はごく少数しか発生せずスムースに移行完了でき、きっと私が気づかない所で開発チームメンバーが配慮・調整してくださっていたんだと思います。

振り返るとシステム刷新する上で開発チーム全体への影響を最小にするポイントはいかに早く刷新コードをmasterブランチへマージするかという点です。Proxyサーバでトラフィックを切り替えない限り蓋ができる構造だったため、完成次第masterブランチに投入して本番リリースを行いました。蓋を開けるタイミングはQA完了後です。早い段階で刷新したコードが他の開発者の目に触れる場所に設置できた点はとても良かったです。

マイクロサービス化と開発組織

現在アプリから見えるサーバは次のような構成になっていて9名の開発者で開発しています。(これ以外にもFleet Management System, タクシー事業者向け管理サービス, CS対応向け管理サービスとその開発チームありますが図からは省略しています)定めたというより自然とこのような形に落ち着きました。言語化すると次の基準です。現在のスナップショットでしかないため人員が増えるとルールは変化していきそうです。ポイントはサーバ間認証のサービスを増やしていっている点で部品としてふるまうためマイクロサービス化の副作用少なくメリットを享受できると考えています。

  • API Service本体は全員が開発
  • 各マイクロサービスは2名前後で開発
  • user/driverのaccess tokenを認証認可するサービスはAPIに集約する
  • MOV以外でも利用需要がありそうな機能はサーバ間認証でマイクロサービス化

スクリーンショット 2018-12-29 15.13.53.png

GEOはgeographyの略で一緒に開発していたエンジニアがすごい勢いで空間参照系について詳しくなり、いつの間にか作り終わっていた機能です。代表的な機能はユーザや車両がどの営業区域にいるか経度緯度情報からの地域判定です。PostGIS DBのCPUで判定計算している点が特徴です。

E2Eテストを書く

proxyを対象にE2Eテストを書きました。テストケースは本番の配車履歴から頻出パターンを抽出しました。検査項目はHTTP ResponseのJSON SchemaチェックとRDBのレコード状態の確認です。RSpecの生産性の高さと、使い捨て前提の割り切りでサクサク書け手動で再現するには2時間くらい掛かる分量になりました。捨てるにはもったいない出来だったのでbotに組み込みQA環境を自動試験しています。

スクリーンショット 2018-12-29 16.43.36.png

まとめ

振り返るとRubyからGolangへの移行を進める過程で、システムアーキテクチャがマイクロサービス化していくという稀有な体験ができしました。短期間で大きなトラブルなく安全に移行完了できたのはカナリアリリース、ログ基盤、E2Eテストと足回りを強化したあと移行を行った点にあると思います。

このアーキテクチャは現在のスナップショットであって、今後開発リストにあまたある新規開発を行っていく上で変化していくでしょう。チーム内では配車サービスを独立といった話をしています。

お話変わってDeNAでは年に1度TechConを開催しています。今回移行作業を強力にサポートしてくださった惠良 和隆さんの発表もあります。ぜひ。 https://techcon.dena.com/2019/

最後まで読んで頂きましてありがとうございます。

ツイート
シェア
あとで読む
ブックマーク
送る
メールで送る

QA Night #1 開催レポート(第二部)

はじめに

品質管理部の河野です。 開催レポートが遅くなってしまってしまったのですが、「おわりに」で遅くなった言い訳を書かせて頂きます。
すでに第一部の松尾谷さんの講演はこちらでレポートさせて頂きました。
こちらの第二部では、DeNAパートの中でも事例のところにフォーカスを当ててレポートいたします。 今回、DeNA QA の事例として、テストプロセス標準化の取り組みを発表させて頂きました。以降、発表の背景と概要をレポートいたします。

発表の背景

ちょうど1年前の12月くらいから部門横断の改善活動を開始したのですが、そのとき真っ先に着手したのがテストプロセスの標準化でした。各チームでバラバラだったテストの進め方をまずは全体的に共通化しようと言うのが本発表の取り組みです。
その後、標準テストプロセスが概ね出来上がった段階でその導入を進めつつ、TPI NEXTを使ったテストプロセスのアセスメントや標準テスト観点の整備などの取り組みを進めてきました。また、テストプロセスが標準化されたことで、今後はテスト活動のメトリクスの収集を行っていく予定です。
ということで、まずはテストプロセスを標準化していくことで、その後の活動がスムーズに進んだように思います。 それでは、当日の発表概要に移ります。その前に、当日のスライドはこちらになります。

DeNA QA Night #1 DeNA part from Tetsuya Kouno

発表の概要

当日の発表では、上記のような背景を初段に説明して、その後は、具体的にどのようにテストプロセスを標準化していったのかという事例を紹介しました。
テストプロセスの標準化というと難易度が高そうに見えますが、我々が取ったアプローチは以下になります。
1.各チームのテストプロセスの見える化する
2.上記テストプロセスの共通化する(積の共通とする)
3.成果物や処理の名称を決める
それで、当日は1.の見える化を「カレーライスを作る」演習を交えて、皆さんで少しワークをしてもらいました。思いの外、盛り上がってよかったです。
その後は、2.と3.を具体例を交えながら解説していき、最後の方で標準化のメリットなどを示しました。

後日談1:プロセスに関しての松尾谷さんの発表について

松尾谷さんの発表で、品質関連のアプローチとして「プロセスや技法」は負け犬の遠吠え、
のような解説がありました。 それに関して、後日というよりは発表後の話になるんですが、
松尾谷さんから以下のような意図のコメントを頂きました。

私が言ったのは河野さんの発表のようなプロセスではなくて
スタッフ部門や管理部門が押し付ける規範的なプロセスを指しているので
逆にこのようなプロセスを標準化するのは良いことだ

ということで、今回の取り組みはそれほどずれていなかったようで安心しました。
今回、気をつけたのは、ボトムアップのアプローチで進めたのでやはりそれが良かったと思いました。

後日談2:PFDってそんなに簡単なだっけ?

本イベントに参加した私の知り合いに、とあるイベントであったのですが、こんなことを言われました。

PFDでプロセスを書くのを簡単に発表してたけど、
そもそも目の前の業務をPFDに書くことは結構難易度高いんじゃない

はい、おっしゃる通りで、よく見かけるのはフローチャートになっていたり、
成果物と処理がごっちゃになったりして、PFDで表現するのは結構難しです。
それで、私は以下のような工夫をしております。

  • 最終成果物から戻るようにプロセスを書いていく
     最終成果物からその前の処理、その処理の入力成果物といった感じで考えるほうが
     経験的に知的ハードルが低くなるように感じます
  • 最初はメタに捉えて、作業の粒度を荒くする
     細かく考えるとキリがないです。まずはメタに捉えて、細かくしていきましょう。
     細かくしていくところは参考資料を見てみてください。
  • ホワイトボード / 紙と鉛筆で書く
     いきなりpptで清書すると挫折します。挫折というより、時間切れになると思います。
     なので、まずはラフにスケッチしましょう。
     スケッチできなければ、よくわかっていないことなので、次の工夫です。
  • 一人で考えすぎずに、他の人を巻き込む
     実態がわからなくて、PFDで表現できないところが出てきます。
     なので、そういうところは知っている人に聞くのが早いです。
  • 成果物と処理の名前付けに気をつける
     これは重要です。周りのメンバが共感できるような実態にあった名前をつけましょう。
     それと、成果物と処理にふさわしい名前、特に処理は動作を表す名前をつけましょう。

おわりに

今回の第一回、DeNA QA Night は参加者・講演者の皆さんのおかげで成功だったと思います。ただ、これは終わりではなくて始まりです。
次回もやります。日程は3月6日(水)で決まっております。次回も業界の一線級の識者にお声がけしてます。是非、期待して下さい。
ということで、次回日程が決まってから開催レポートを書きたいと思っておりましてこんな遅い開催レポートとなってしまいました。という、言い訳でした。
皆様、良いお年を!

ツイート
シェア
あとで読む
ブックマーク
送る
メールで送る

ここでしか見られない DeNA TechCon 2019 のセッション4つ

og.png

DeNA の様々な技術的なチャレンジをみて参加者のみなさんに「面白かったー」と思ってもらいたい DeNA TechCon。こちら次回開催は 2019年2月6日(水) で、登壇情報もほぼ全て出揃いました!(ゲストセッション、LTセッションなどはまた後日お知らせします!)

DeNA グループ全社で取り組んでいる様々な取り組みの中から厳選した21セッションをお届けするので、本当に全部おすすめ。そんな21セッションの中から、社外では発表する機会が少なかったり、DeNA TechCon だからこそ話せるような、他の技術系イベントでは見ることが難しいと思われるセッションを各トラックから1つずつご紹介します。

「AI 技術の事業への応用」トラック

パネルディスカッション:データサイエンスの競技者、Kagglerたちが活躍する職場とは

2018年8月末、DeNAのKagglerである小野寺和樹と加納龍一を含むチームが、過去最大のKaggleコンペである"Home Credit Default Risk"にて、7198チーム(参加者数8572名)中2位に入賞しました。

彼らを含め、DeNA では データサイエンス競技「Kaggle」のトッププレイヤーが集まっています。この Kaggler たちは一見すると事業貢献からは遠い競技者だと見えてしまいますが、 彼らと連携するメンバーの協力もあり、Kaggler たちは事業でも大活躍しています!

Kaggler とはどういった人たちでどのように事業でも成果をだしているのか、「Kaggler たち自身の立場」、「彼らと連携するメンバーの立場」の両面から話を聞ける機会は少ないと思います。そのためおすすめのセッションです!

参考記事

「クラウド活用」トラック

DeNAのインフラ戦略 〜クラウドジャーニーの舞台裏〜(仮)

現在約 3,000 台のオンプレミスのサーバーを運用している DeNA は、3年かけてオンプレミスで運用する全てのシステム基盤を全面的にクラウドに移行することを決定しました。
その決定にいたるまでの裏側の話は、現在オンプレミスだがクラウドに移行しようか悩んでいる人や、現在クラウドを使っているが低コストと安定運用を両立したい人にとって、とても参考になる話だと思われます。
多くの人に興味を持ってもらえるだろうこの登壇内容について、この意思決定を推進した 金子 俊一が自ら登壇してお話ししますので、是非見てもらいたいです!

参考記事

オンプレミスに強みをもつDeNAはなぜクラウド化を決めたのか?その舞台裏と今後の展望

「サービス開発」トラック

ヘルスケアサービス開発の裏側 〜品質と開発効率の両立〜

ヘルスケアは一般的なサービスに比べるとセキュリティに求められる水準が高く、どうしても開発スピードと両立させることが難しいそうです。そんなヘルスケアのサービスでセキュアな状態を維持しつつも開発スピードが高いままで - オンプレからクラウドに移行する - マイクロサービス化するという点 の2つを推進しており、様々なサービスにとって参考になる情報が盛りだくさんで、非常に見応えある内容だと思われます。当日はサーバサイドの池松、クライアントサイドの四方がそれぞれ話すので、アプリケーション開発、サービス開発に携わるエンジニアにはぜひ見ていただきたいです。

「ものづくりを支える技術」トラック

スマホゲームのチート手法とその対策

スマホゲームではさまざまなチート方法があるそうなのですが、その方法について「チート手法」と「その対策」を紹介してくれる場はあまり無いそうです。
チート方法はセキュリティエンジニアだけが知っていたら良いものではなく、アプリ開発やサービス開発するエンジニアも知っておくべき知識ですよね。セキュリティエンジニアとして知識を深めたい人、アプリ開発エンジニアだけど知識としてチート方法と対策を知っておきたい人にはぜひ見ていただきたいです。

終わりに

本当にすべてのセッションがおすすめなのですが、今回はその中でも 社外では発表する機会が少なかったり、DeNA TechCon だからこそ話せるような、他の技術系イベントでは見ることが難しいと思われるセッション 4つをご紹介しました。

また、実はまだ公開していないゲストセッションや、LTに関しては 公式 Twitter アカウントの DeNAxTech で今後ご紹介していきますので、まだフォローしていない方はぜひご登録下さい。

icon_tw@2.png
また肝心の DeNA TechCon 2019 について、まだ参加登録していない人は以下の Peatix から参加登録のほどよろしくお願いいたします!!

ツイート
シェア
あとで読む
ブックマーク
送る
メールで送る

LLVMを用いたチート対策ツールを作っている話

この記事はDeNA Advent Calendar 2018の24記事目です。

こんにちは、セキュリティ部セキュリティ技術グループ ツール開発チームの小竹 泰一(aka tkmru)です。 脆弱性診断業務の傍ら、ツール開発チームでは、パッチ管理ツールやチート対策、脆弱性診断のためのツール開発を行っています。 この記事では開発中のLLVMを用いたチート対策ツールの紹介をしたいと思います。

はじめに

本題に入るまえに、チートをされるとどのような問題があるのか、チートの方法やチート対策技術にはどのようなものがあるのかということを軽く説明しようと思います。

チートによるリスク

スマートフォンのゲームアプリのチートでよくあるものとしては、 「スタミナが減らないようにするもの」や、 「ステータスを不正に上昇させバトルで勝利するもの」、 「不正に課金アイテムを取得するもの」などがあります。

もし、このようなチートが横行してしまうと、適切に利用しているユーザの快適なプレイが阻害されてしまうかもしれません。 また、不正に課金を回避したり、ステータスをアップさせているユーザの存在は他のユーザの納得感を得られないでしょう。 チーターの存在はゲームバランスにも影響し、ゲームからユーザーが離れる一因となります。 ゲームアプリの脆弱性診断では、ゲームに対して実際に攻撃を行うことで、このようなチートからゲームを守ることができるかを確認しています。

チート対策技術とは

上で述べたように、チート対策はゲームの魅力を守るために重要です。 とくに、近年のゲームアプリはUX向上の為クライアント側の計算により多くのゲームロジック(スコア・ダメージの計算、勝敗判定など)を寄せています。 そのため、リバースエンジニアリングを伴う攻撃への耐性を上げることが重要なチート対策となっています。

ゲームアプリに限った話ではなく一般的に言えることですが、リバースエンジニアリングの手法は、アプリケーションを実際に動作させメモリや通信内容を解析する動的解析と、 ディスアセンブラやデコンパイラにかけた結果を解析する静的解析の2つに分類されます。 ARMアセンブリのコードを読む必要のある静的解析は動的解析に比べ、難易度が高いですが、 用いられている暗号方式などの詳細な解析結果を得るには行う必要があります。

ゲームアプリのチート対策では、この2つに対して対策する必要があります。 ここではひとつひとつを詳細に説明することはしませんが、チート対策技術には以下のようなものがあります。

  • 通信の暗号化
  • Root化端末、JailBreak端末の検知
  • VMの検知
  • デバッガ検知
  • メモリ上のデータの暗号化
  • パッキング
  • コード改ざんの検知
  • 難読化
  • ... etc

紹介するLLVMを用いたチート対策ツールでは、コードの処理の流れを追いにくくする難読化と、 パッチを当てられたことを検知するコード改ざん検知を担っています。 コードの改ざんを検知した後にやることとしては、アプリを強制的に終了させることや、ログをサーバーに送信することが考えられます。

LLVMとコンパイラ

LLVMは、コンパイラ開発のためのオープンソースの基盤ソフトウェアです。 主な特徴として、コンパイルに必要な機能がモジュール化され,各機能を統合するドライバで構成されており、拡張性、移植性に優れていることが挙げられます。

コンパイラの設計手法の一つにフロントエンド、optimizer、バックエンドの3つの構成要素に分割して設計するThree-Phase Designがあります。 LLVMを用いてThree-Phase Designを採用してコンパイラを設計すると、 内部構造は以下の画像(The Architecture of Open Source Applications: LLVMより引用)のようになります。

LLVMCompiler1.png

フロントエンドがプログラムのソースコードをLLVM IRという中間表現に変換し、 LLVM optimizerがLLVM IRのコードに対して最適化をかけます。 そして最後にLLVMバックエンドがLLVM IRのコードからターゲットのアーキテクチャのアセンブリコードを生成し、 実行可能ファイルを生成する流れになっています。

コンパイラ開発にLLVMを利用すると、中間表現をLLVM IRに統一することができ、 異なるアーキテクチャ向け、異なる言語向けのコンパイルであっても最適化部分を共通化できます。 しかも、その最適化機構はPassとしてLLVMが提供してくれています。 また、バックエンドを置き換えるだけで異なるアーキテクチャに対応できたり、フロントエンドを置き換えるだけで異なるプログラミング言語に対応できたりもします。 このようにLLVMを利用することで、1からコンパイラを作成するより効率よくコンパイラを作成することができます。

LLVM IR

LLVM IRについてもう少しくわしく見ていきましょう。 LLVM内部で用いられる中間表現であるLLVM IRは、 アセンブリ言語に似た表現で、表現力や拡張性、軽量であることを追求して作られています。 基本的な命令による操作の組み合わせで、 様々な高級言語に対応した簡潔な表現が可能になっています。 また、LLVM IRのレジスタは数に制限が無く、値の代入が一箇所でしか行えないSSA(Static Single Assignment)形式になっており、 これを用いて柔軟に変数を表現することができます。 LLVM IRには様々な種類の型が存在し、レジスタに型が対応しており、 細分化された型は高度な最適化を可能にします。 例えば、32bit整数型を表すi32型や、 128bit浮動小数点数型を表すfp128型などがあります。 これらの基本となる型と組み合わせて、構造体、配列、ベクトルといった 派生型を構成することができます。

実際にLLVM IRのコードを見てみましょう。 以下のような西暦を出力するだけのコードをLLVM IRに変換します。もうそろそろ2019年ですね。

#include <stdio.h>

int main(){
  int year = 2018;
  printf("%d", year+1);
  return 0;
}

clangに-S-emit-llvmの2つのオプションを指定するとLLVM IRコードが出力されます。

$ clang new-year.c -S -emit-llvm
$ cat new-year.ll
; ModuleID = 'new-year.c'
source_filename = "new-year.c"
target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-apple-macosx10.13.0"

@.str = private unnamed_addr constant [3 x i8] c"%d\00", align 1

; Function Attrs: noinline nounwind optnone ssp uwtable
define i32 @main() #0 {
  %1 = alloca i32, align 4
  %2 = alloca i32, align 4
  store i32 0, i32* %1, align 4
  store i32 2018, i32* %2, align 4
  %3 = load i32, i32* %2, align 4
  %4 = add nsw i32 %3, 1
  %5 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @.str, i32 0, i32 0), i32 %4)
  ret i32 0
}

declare i32 @printf(i8*, ...) #1

attributes #0 = { noinline nounwind optnone ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+fxsr,+mmx,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
attributes #1 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+fxsr,+mmx,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }

!llvm.module.flags = !{!0, !1}
!llvm.ident = !{!2}

!0 = !{i32 1, !"wchar_size", i32 4}
!1 = !{i32 7, !"PIC Level", i32 2}
!2 = !{!"Apple LLVM version 9.1.0 (clang-902.0.39.2)"}

レジスタが%数値で表されているのが特徴的ですね。 アセンブリとは違い、アドレスの概念がないので操作しやすそうなのが分かると思います。

Three-Phase Designについて説明をした際、異なるアーキテクチャに対して最適化部分を共通化できると述べましたが、それ以外にも LLVM IRを用いることで対象のソースや機械語に手を加えることなく、最適化を行うことができるというメリットがあります。

LLVMをなぜ使うのか

LLVM IRを最適化に使うと便利だということを述べましたが、これは難読化やコード改ざん検知機能を実装するのにも同じことが言え、 LLVM IRを用いることで対象のソースや機械語に手を加えることなく、出力されるバイナリに難読化やコード改ざん検知機能を施すことができます。 また、現在スマートフォンで用いられているCPUはARMが主流ですが、異なるアーキテクチャのCPUを用いたスマートフォンが出てきたときの対応も容易になります。 LLVMを使って難読化に行うこと自体は、新しい手法ではなく、OSSの実装としてobfuscator-llvm/obfuscatorが知られています。

Unityで作られたゲームアプリのコードはIL2CPPを利用してC++のコードに変換することができます。 開発中のチート対策ツールでは、 この出力されたC++のコードをLLVM IRに変換し、 難読化やコード改ざん検知をいれ、 最終的にバイナリにするという方式をとっています。

難読化例

プロトタイプのチート対策ツールを使用するとCFG(Control Flow Graph)を以下のように変化させることができます。 CFGはIDA Proを使って生成しました。 これによって処理の流れが追いにくくなります。

難読化前のCFG

before_cfg.png

難読化後のCFG

after_cfg.png

今のところ、まだIDAのGraph viewでCFGを表示することができますが、最終的にはAnti-Disassemblyを施してCFGを表示できないようにする予定です。

おわりに

開発中のチート対策ツールの技術的な背景を紹介しました。 マルウェアがアンチデバッグに使っている手法などを検証しながら、 低レイヤーでの開発ができる、 このツールの開発はとてもおもしろいと思っていて、 商用ツールに負けないようなツールにしていきたいと思っています。 チート対策やLLVMを使ったツール開発の面白さが少しでも伝われば幸いです。

宣伝

DeNA TechCon 2019 を2019年2月6日(水)に開催します! ぜひご登録下さい! セキュリティに関する話もあります!! techcon2019.png

また、弊社についての技術情報は @DeNAxTech より配信しています。ぜひフォローをお願いします!!

ツイート
シェア
あとで読む
ブックマーク
送る
メールで送る

チーム内でJIRAを使ったペアプロ大会の企画をやった話

はじめに

これは DeNA Advent Calendar 2018 その2 の 19 日目の記事です。

はじめまして、FINAL FANTASY Record Keeper(FFRK)チームの今江です。現在は、FFRKチーム内の新機能開発チームでリードエンジニアを務めています。 FFRKは、2018年時点で4周年を迎えた長寿タイトルで、チームの規模も大きいプロジェクトとなっています。当然エンジニアの人数も多く、多数のエンジニアが日々開発を行なっています。

今回は、FFRKチーム内で行なったJIRAを使ったペアプロ大会の企画に関して紹介できればと思います。 この企画はペアプログラミングによるエンジニアの交流・成長の機会の提供や、着手されずに放置されているタスクを解決しつつ、チームの文化を醸成する目的がありました。同様の問題を抱えている方の参考になると幸いです。

JIRAとは?

JIRAとは、チケット管理型のプロジェクト管理ツールです。あらゆるタスクが「チケット」として管理され、進捗/タスク/アサイン管理など、プロジェクトの見える化に一役買っています。 FFRKチームでは、JIRAを使ったチケット駆動開発でプロジェクト開発を行なっています。

jiracon.000.png

企画の背景

FFRKチームでは、チーム内のエンジニアが集まる定例「エンジニア定例」という場があります。 エンジニア定例は普段は各チームの情報共有で終わっているのですが、せっかく定期的にやっているので、普段やらないような新しい取り組みをやったり、日頃感じているがなかなか解消できていない課題を解決したいという話題が上がっていました。

で、何かしらの取り組みをする上で、あがった要望が以下です。

  • みんな、ペアプロとかしたいって言ってる
  • JIRAが溜まっている
  • 業務とかに活きることやりたいよね
  • ゲームの改善にできるだけ工数を使いたい/繋げたい
  • チームビルディングは大事だよね。

「お、モリモリの要件やん。」ということで、しばらくネタを考えて思いついたのが、 今回紹介するチーム内のJIRAを使ったペアプロ大会 「JIRACON 2018」です。

JIRACON 2018

「JIRACON 2018」は、FFRK内の「業務効率化や既存の不具合などに関するJIRA」を題材にしたペアプロ大会です。

  • 概要
    • 1チーム3人で、JIRAをたくさんやったチームが優勝
    • どの程度「やった」かで点数がもらえて、一番点数が多かったチームが優勝
    • 出題するJIRAは、FFRK内のJIRAから適当に選出されたJIRA群
  • ルール
    • 時間: 1時間
    • チームのPC: 1台(コードを触れるPC)
    • チーム内容: リーダー1人 + メンバー2人

ざっと、こんなルールだったのですが、「やった」という基準は以下のように設定しました。

  • やったの定義
    • JIRAに調査結果を記入 1点
    • JIRAに解決策を書く 3点
    • JIRAの修正PRを作る 10点

ルールとして、何かしらJIRAに対して解決に繋がる取り組みを行うと、点数がもらえる方式を取っています。

取り組みの意図

企画の詳細を詰める中で、最終的にJIRACONの目的は以下のように整理しました。

  • 主目的
    • 互いの作業 (調査、コーディング、etc.) を見ることで、相互に良いところを吸収しあい、今後の業務に生かす
    • 今回で「JIRAをサクッと解決する」という感覚をつかみ、今後もすぐに解決できるものは溜めずに解決していく習慣づけの端緒にする
    • 限られた時間の中で調査や解決策の検討を行うことで、調査力や問題解決力の向上を図る
  • 副目的
    • 日頃触れない領域のコードに触れる
    • 溜まっているJIRAの数を少しでも減らす
    • エンジニア間の交流

この目的に沿って、JIRACONを進めるように詳細を詰めて行きました。

当日の流れ

JIRACONの当日の流れについて、説明します。

スケジュール

当日の進行スケジュールです。

  • 15:00 : ルール説明
  • 15:05 : 出題JIRAの公開
  • 15:05-15:55 コンテスト時間「50分」
  • 16:00 : 終了

※ 結果は、次回のエンジニア定例で発表

最初にルール説明を行い、またこのタイミングで再度JIRACONの目的を説明し、目的を踏まえて取り組んでもらうような流れを取っています。

jiracon.png

コンテスト中の流れ

JIRACONは、以下のような流れに沿って取り組みます。

jiracon.001.png

時間になると、JIRACONのWebページから問題一覧のページにアクセスできるようになるので、 各チームごとにJIRAを精査しJIRAに取り組みます。

SECCONなどのイメージが近かったので、専用のページをGoogle Sitesで作成しています。

jiracon.002.png

それっぽいWebページがサクッと作れたので、ちょっとしたWebページ作成におすすめです(サーバも用意する必要がない)。

全体のシステム構成としては以下のような感じです。

jiracon.003.png

(ほぼGoogleですね) あとは、採点を自動化できなかったので、ここはやむなしという感じです。

JIRAの一覧ページはこんな感じです。

jiracon.004.png

やってみてどうだったか?

最後にJIRACONを開催してみての振り返りを含めて、アンケートの結果を紹介できればと思います。 それぞれ、「取り組みの意図」で説明した3つの目的に関してのアンケートを取っています。

1. 互いの作業を見たことで、今後の業務に活かせそうか?

jiracon.005.png

一つ目の目的だった

互いの作業 (調査、コーディング、etc.) を見ることで、相互に良いところを吸収しあい、今後の業務に生かす

に関しては、綺麗に3分割されました。基本3人チームなので、役割ごとに意見が別れたようでした。 定性的なアンケートを結果を見た所、

  • 時間的な制約で、他の人の効率のいい面を見る余裕がなかった
  • 点数など競技性があったことで、個々が得点を取るための動きをしてしまっていた
  • どういうところで困っているのか/分からないのかを見れてよかった
  • 単純にスキルを吸収してもらう方へ力を入れたので、自身の得るものはなかった
  • いつも触らない領域を触って知見が広がった、業務に活きそう

傾向としては、時間的な猶予が厳しかった人、他人に吸収してもらう役回りだった人が低評価で、 競技性が合っていた人や、教えてもらう/見る側の人は目的を果たせたという結果でした。

2. JIRA解決の敷居が下がったか?

jiracon.006.png

二つ目の目的は、

今回で「JIRAをサクッと解決する」という感覚をつかみ、今後もすぐに解決できるものは溜めずに解決していく習慣づけの端緒にする

に関しては、全体的にJIRA解決の敷居は下がったという結果になりました。 代わりに、自分から能動的に動く習慣が付いたかという意識改革までには至らない結果になりました。

また、最終的に、総計 「21件」のJIRAが解決されていましたので、JIRA解決という副目的もそれなりに満たされた結果になりました。 入賞ラインのチームは、「17点、13点、12点」といずれも、修正PR 10点を1つ以上は出していました。

3. 限られた時間の中で、調査力や問題解決力の向上が感じられたか?

jiracon.007.png

最後の目的に関しては、1つ目のアンケートでも出ていましたが、時間的な制約がネックになっているという結果でした。 調査力・問題解決力が微増、全体的にポジネガが半々という状態でした。

ただ、時間に関しては「1時間では短いが、2時間だとダレそう」という意見があったので、単純に伸ばせばよかったとは言えない感じでした。

まとめ

最後に、JIRACONという取り組みをやってみた、まとめになります。

JIRAというプロジェクト管理ツールを使って、ペアプロ大会をやってみました。 互いの作業を見ながら、相互に刺激をもらえる機会を作ることができました。 また、チーム内に溜まったJIRA解決の敷居を下げつつ、ゲームの改善に繋がるような取り組みを行いました。

  • 主目的
    1. 互いの作業 (調査、コーディング、etc.) を見ることで、相互に良いところを吸収しあい、今後の業務に生かす
      • → 人の作業風景が見れてよかった or 余裕がなかった
    2. 今回で「JIRAをサクッと解決する」という感覚をつかみ、今後もすぐに解決できるものは溜めずに解決していく習慣づけの端緒にする
      • → JIRA解決の敷居は下がったが、マインド改革までには至らない
    3. 限られた時間の中で調査や解決策の検討を行うことで、調査力や問題解決力の向上を図る
      • → 一部の人には効果があったが、限られた時間だとその余裕が作りづらい
  • 副目的
    • 日頃触れない領域のコードに触れる → 人によってはあった
    • 溜まっているJIRAの数を少しでも減らす → 21件のJIRA解決
    • エンジニア間の交流 → まぁなったかなと

今後の展望

上記踏まえて、今後似た企画を行う場合のアイデアとしては、以下のようなことを考えています。

  • 時間的な制約がネックになったので、競技性のない取り組み
  • 普段関わりのある人で固めてチームを組んだので、チームを跨いだ交流の場
  • スタートから実装に取りかかれるような企画
  • 簡単なゲームを1から作る企画

JIRACONは競技性が高かったので、ゆとりを持って他人の作業を見ることに注力しやすい企画だったり、調査が必要なくやることが明確な手を動かせる企画が良いのではと考えています。

以上、FFRKチーム内で行なったJIRAを使ったペアプロ大会「JIRACON」に関して紹介してきました。 チケット駆動開発を行なっているチームがいれば参考にしていただければと思います。

jiracon.008.png

ツイート
シェア
あとで読む
ブックマーク
送る
メールで送る

ISUCON8予選問題においてPerl実装で25万点を突破する方法

この記事はDeNA Advent Calendar 2018の15日目の記事です。遅刻!

こんにちは、@karupaneruraです。今日はDeNAが問題提供したISUCON8予選に関する話です。

ISUCONとは

ISUCONはIiknajini Speed Up CONtestのことで、Webアプリケーションのチューニング技術を競うコンテストです。 競技開始時刻にそれまで秘密にされていたあるアプリケーションがチームごとにサーバーごとまるっと渡されて、それを制限時間内にどこまでチューニングできるかを競います。

サーバーでは参照実装としてある仕様を満たしたアプリケーションが動いていて、その外部仕様を崩さずに(外見上)同様の挙動をするアプリケーションをそれぞれのチームがチューニングしていきます。 そして、ベンチマーカーをチームごとに実行すると仕様や整合性のチェックとパフォーマンス計測が行われて総合的にスコアとして数値化されてランキングが作れるという感じです。

参照実装は各言語の実装が提供されていて、各々の得意な言語を使うことができるほか、フルスクラッチで書き直すことも許されます。ミドルウェアの制限もないので、時間の許す限り本当に各々がベストだと思うソリューションを選択できる競技です。ぼくはWebエンジニアリング技術の総合格闘技のような競技だと思っています。

ISUCON8はどうだったか

そんなISUCONですが2018年は第8回目のISUCON8として開催されました。主催はLINEさん、サーバー提供はGMOさん(ConoHa)、問題提供はカヤックさんとDeNAで行いました。 DeNAは予選問題、カヤックさんは本戦問題という形で役割分担をした形です。

僕は予選問題の作問と模範解答(事前チューニング)を行いました。 解説記事も書いています。(おかげさまで大変好評でした)

ところで、ISUCON8では感想戦という形でチューニングの続きを行ってもらえる試みをやったのですが、その際にこの模範解答のスコアを出していました。

261421点というスコアですが、25万点オーバーを安定して出していました。 作問者なので当然に勘所はわかってるし、問題をブラッシュアップしながら並行して育てたので競技参加者の皆さんと同じ条件下のスコアではないわけですが、ここまではPerlでチューニングできるという事実を示しています。ちなみに競技中の最高スコアは10万点ほどでした。

前置きが長くなりましたが、今回の記事はこのスコアを出す構成はどのようにして作られたのかを語っていきます。

模範解答を作る目的

模範解答は、そのアプリケーションを最適化したときにベンチマーカー側に問題が起きないことの確認、攻略の際にどのボトルネックがどのように現れるのかの確認のために作成しました。(便宜上、模範解答という呼び方をしています。) これがあることで、ベンチマーカー側のレースコーディション問題の発見や問題の調整の意思決定がすばやく行えます。また、 攻略難易度が高すぎる/低すぎるの判断や、問題の調整もしやすくなります。 そのため、模範解答は早めの段階から作成していました。

模範解答を作るときに考えたこと

上記のような目的があるので、競技中に到達し得るスコアより高いスコアを出す実装にする必要があります。 そのため、実装時間は度外視して極限までチューニングすることを考えました。

極限までチューニングするにはどうするか、全体観を得たらそこから逆算して設計を考えていきます。 今回の場合は大きな難関はマイページと予約/キャンセルです。ユーザー毎にレスポンスが変わる部分があるので、ISUCON2の模範解答のアプローチのような、静的ファイルとしてすべてのデータを書き出すといった方法はとりにくいでしょう。なので、動的にレスポンスを返す形で高速化していきました。

動的に返すレスポンスを最適化するには、最終的に返したいデータモデルから逆算して必要なデータを考えていきます。最小限の手数で高速にレスポンスを作るために今回はRedisを使いました。Redisは低レイテンシーでレスポンスを返してくれて、かつメモリ消費量がMySQLと比べて少なく済む点が今回の課題では有利に働きました。

基本的な戦略は以下です:

  • キャッシュできる情報は基本的にキャッシュする
  • レスポンスはRedisのデータだけで基本的に解決できるようにする
  • 更新はRedis上のデータとMySQLを更新する
  • レポートだけデータ量の多さと整合性を顧みてMySQLを使って返す

また、構成としては最終的にアプリケーションのCPUがボトルネックになったため以下の構成を採用しました:

  • nginx - h2o - app / mysql / redis
  • h2o - app
  • h2o - app

nginxをLBとして、h2oでhttpを受けてアプリケーションへはunix domain socketでデータを送ります。

アプリケーションの実装はこちら: webapp/perl/lib/Torb/Web.pm

基本的にはこの方針と解説記事に書いたアプローチを理解できればすべての実装に説明が付きます。 ほか、細かいMySQLやRedisのチューニングやカーネルパラメータのチューニングも当然やっていますが、それらは普通のことしかやってないので今回は特に紹介しません。リポジトリにあるのでよかったら見てください。

実装は難しい部分もあるので実装の分かりにくいポイントを紹介します

GET /initialize

ベンチマーカーからベンチマーク開始時に叩かれるデータ初期化用エンドポイントですが、ここはレギュレーション上一定時間以内の処理が許されています。 そこで、初期データをキャッシュに載せてしまうことで全体の高速化を図ります。

基本的にRedisにpipelineしてクエリを投げまくるだけなのですが、ユーザー毎の最終更新イベントを作るときに課題があります。 ユーザー毎の最終更新イベントは、各ユーザーが最後に予約/キャンセルしたイベントをユニークに5件表示するという機能です。これをRedisでやる場合はSorted Setを使ってユーザーとイベントの組み毎に最終予約/キャンセル時刻を入れておく必要があります。 しかし、これを素直に解決するとユーザー数ぶんのN+1問題になってしまいます。SQL一撃で解決するためには窓関数を使う必要があります。

-- https://github.com/karupanerura/isucon8-qualify-tuned/blob/master/webapp/perl/lib/Torb/Web.pm#L249
SELECT id, user_id, event_id, updated_at FROM (SELECT user_id, event_id, id, updated_at, ROW_NUMBER() OVER (PARTITION BY user_id, event_id ORDER BY updated_at DESC) AS `rank` FROM reservations) a WHERE a.rank = 1 GROUP BY user_id, event_id

これで一発です。MySQLは8.0から窓関数をサポートしているのでこういうことができます。

また、全体売上レポートも一定のデータはキャッシュしておくことができます。終了していないイベントでまだキャンセルされてないまたは終了したイベントの最も古い予約より古い予約は、すべて終了しているイベントかキャンセルされた予約になっているはずです。そのため、そのID以前までキャッシュすることができます。

-- https://github.com/karupanerura/isucon8-qualify-tuned/blob/master/webapp/perl/lib/Torb/Web.pm#L171
SELECT MIN(r.id) FROM reservations r INNER JOIN events e ON r.event_id = e.id WHERE NOT ((e.closed_fg = 0 AND r.canceled_at IS NOT NULL) OR e.closed_fg = 1)

こういう感じで取ってきてCSVをファイルに書き出して使っておくと便利です。 この実装ではPSGIのStreaming Responseのフォーマットでレスポンスを返しているので、それを直接つかってキャッシュファイルを生成することができます。(レスポンスをそのままファイルに書き込みます)

# https://github.com/karupanerura/isucon8-qualify-tuned/blob/master/webapp/perl/lib/Torb/Web.pm#L173
my $rid = $self->dbh->select_one('SELECT MIN(r.id) FROM reservations r INNER JOIN events e ON r.event_id = e.id WHERE NOT ((e.closed_fg = 0 AND r.canceled_at IS NOT NULL) OR e.closed_fg = 1)');
my $res = $self->render_report_csv('SELECT * FROM reservations WHERE id < ? ORDER BY id ASC', $rid);
$res->finalize()->(sub {
    my $header_line = shift;
    open my $fh, '>', "/tmp/report_all_prefix_$rid.csv" or die $!;
    return Plack::Util::inline_object(
        write => sub {
            print {$fh} @_;
        },
        close => sub {
            close $fh or die $!;
        },
    );
});

ちなみに、これらの処理の過程でそこそこのメモリアロケーションが発生します。psgix.harakiri.commit を使ってプロセスごと殺してまっさらにしておくとスッキリです。

GET /admin/api/reports/sales

前の項で触れたとおりキャッシュデータを使える場合はそれをまるっと流しつつ、解説記事でも触れたとおり mysql_use_result を使ってMySQLから受け取ったデータをそのまんま流しましょう。適度にバッファリングしてwriteすると本当はもっとよいです。 なお、KossyはデフォルトでStreaming Responseをサポートしていないので、以下のようなモンキーパッチでお茶を濁しました。(忘れてなければ年末正月あたりの暇な時間にPull-Requestを投げます)

# https://github.com/karupanerura/isucon8-qualify-tuned/blob/master/webapp/perl/lib/Torb/Web.pm#L981-L1001
package Kossy::Response {
    use Scalar::Util qw/reftype/;

    sub new_with_code {
        my ($class, $code) = @_;
        bless \$code, $class;
    }

    BEGIN {
        my $super = \&finalize;
        no warnings qw/redefine/;
        *finalize = sub {
            my $self = shift;
            if (reftype $self eq 'REF') {
                return $$self;
            }

            $self->$super(@_);
        };
    };
};

まとめ

こういうアプローチでISUCON8予選問題の模範解答としては25万点オーバーを安定して出すことができました。 普段あまり使わない機能もときと場合によっては便利に使えるので、たとえば仕事で突然ISUCONになったときのためにも普段から素振りしておけると良いですね。ちなみに僕は初めて使う機能が結構ありました!(窓関数とか) ISUCONを出題するとこんな感じで色々と遊ぶことができるので楽しいです。みなさんもチャンスがあればぜひ出題にチャレンジしてみてください!

また、DeNAでは大規模なトラフィックを捌く仕事もあって楽しいです。よかったらぜひ一緒に働きましょう!

16日目はrexitorgさんです!もう読めます: GAE/Go, Firestoreでマスターデータを管理してみた件

ツイート
シェア
あとで読む
ブックマーク
送る
メールで送る