SVVR報告会

こんにちは。根岸(@CST_negi)です。
現在新卒2年目で、VRアプリ開発の業務を行っております。
業務の傍ら、趣味でもVRアプリを開発しております。Unity/C#が好きです。

今回は、出張で3/29-3/31にサンノゼで行われたSVVR EXPOに参加してきたのでその話をします。現地のVR事情を視察しにいっただけではなく、自作のVRアプリをSVVR EXPOで展示してきましたのでその知見を含めてお話します。
渡米は初めてで英語を人に話すのも初めてな状況でしたが、様々な成果を得ることができました。

SVVR EXPOとは

SVVR(Silicon Valley Virtual Reality)というコミュニティが開催するVRイベントです。VRに関連したテーマについて講演が行われるほか、各企業や個人が制作したアプリを展示する場も設けられています。有料イベントなので、参加者が全員真剣だったのが印象的でした。
テーマに関しては、ゲームだけでなくソーシャルVRや医療系VR、Vスポーツ(VR+eSports)やWebVRなど、VRに関連したものなら幅広く取り扱っていました。

201705170001.png

展示したもの

VR本屋という仮想空間内に実際の本屋のような空間を再現しながらマンガを読めるアプリを作っていて、そのプロトタイプを展示しました。
実はDeNATechConでも同様にこのアプリを展示しまして、その時からアプリを英語対応させ、リファクタリングした上で展示に臨みました。

05-17 17.12.13.png

VR本屋は海外でもウケは良かった

体験者は期間の割に多くはないですが、「ポテンシャルはある!」「とてもいいプロダクトだね!」などの意見をいただきました。サービス化したら教えてねという話やその他ありがたい申し出などもありました。
印象としてはアジア圏(現地でお会いしたのは中国や韓国やタイ出身の方)の方からの反応が特に良かったと思います。マンガの文化が浸透しているからかもしれません。
体験後のアンケートも取ったので、それで得た意見を参考にしつつ製作を進めて行こうと思います。

海外での展示を経て知見など

2点あります。
まずは英語の話。展示というのはある程度言うことが決まっているので、話すことに関してはアピールポイントを説明できる英文をあらかじめ頭にいれておくと効果的です。一方でリスニングは聞き取れないこともあったので、自分の場合は本当にわからなかった時はノートPCでGoogle翻訳を出して「これを使ってくれませんか?」というお願いをするなどして対処しました。ちなみに、これを断る人は全くいなかったので、恥ずかしくても聞きたいという姿勢は崩さないのが良いと思います。

次に展示の話。これは日本とあまり変わらないことですが、何をやっているブースなのかちゃんと分かるようにしましょう。私の場合はデモ動画を用意して、現地の方からお借りした50インチの大画面で展示をアピールしたのが効果的でした。
大画面で「こんな事をやってるよ」というのをアピールして、それを見て立ち止まった人に「Try this?」と声をかけて、どんどん展示に引き込んでいきました。

現地のVR市場について

今回は特にソーシャルVRの領域について視察してきました。VRにおけるソーシャルプラットフォームはまだ大きなものは確立されておらず、それを獲りに行く動きが活発で多様な動きがあったのが印象的です。
Facebook社も最近ではソーシャルVRのアプリをリリースしましたが、それ以外の企業ではゲームに特化したものや、イベントに特化したものなど、それぞれ尖りが明確なサービスをリリースしています。国外のみならずソーシャルVR分野は国内でもいくつかサービスがロンチされていますので、競争は世界的に激しくなりそうです。

社内報告会での報告

帰国後、SXSWに行った小倉さんと共に社内での報告会を行いました。(SXSWの記事は後日公開されます。)
先に記した知見や、出来事などを共有しました。自分と同じように英語に不慣れな人でも、割となんとかなるということは伝えられたかなと思います。

2017-05-17 17.14.37.png

AR/VRの市場規模は2021年には現在の20倍以上に拡大すると市場予測がされており、この背景からも海外の企業では積極的に投資が行われていることを肌で感じました。また、そうした企業の目に見えた成果をSVVR EXPOで確認することができ、VR市場の拡大については私も期待を持つことが出来ました。

今回の展示では海外に飛び込んでいったからこそ新たに見えたものがありました。ここで得た知見と経験を活かしつつ、更なる発展への努力と今後のVR市場の拡大に個人としても備えていこうと思います。
ありがとうございました。

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

ICST 2017参加報告

システム本部SWETグループの薦田(こもだ、と読む)です。SWET(スウェット、と読む)はE2Eテストの自動化を中心にDeNAの事業の開発生産性と品質の向上をミッションとするチームです。

SWETでは社外における新しいテスティング技術をウォッチし発信していくこともそのミッションの一つとなっています。そのような活動の一貫として、3月13日から17日にソフトウェアテストに関する国際会議ICST 2017に参加してきました。

ICST 2017での発表内容は大学での研究が中心でしたが、Googleやトヨタ自動車など産業界のテスト・エンジニアの参加も多かった印象です。会議期間中は発表セッションだけでなく、休憩時間や会場の通路などで、産業界からの参加者とアカデミックからの参加者が入りまじり、プログラミング教育におけるテストの位置づけの話から泥臭いテスト実装のケーススタディまで幅広いトピックについて、熱い議論が行われていました。

ICST 2017全体のスコープはソフトウェアテスト全般です。必ずしもモバイルアプリケーションやウェブアプリケーションだけがターゲットというわけではなく、車載向けシステムの検証の話やファクトリ・オートメーションの話などもあり、普段聞けないような話を聞くことができるのは、大きな魅力と感じました。

さて今回はそうしたICST 2017の発表の中でも、SWETの業務と特に関連が深いウェブアプリケーションのUI自動テストに関する「Using Semantic Similarity in Crawling-based Web Application Testing」というタイトルの、カリフォルニア大学アーバイン校Jun-Wei Lin氏の発表について紹介させていただきます。

フォーム入力自動化における実装上の課題

論文の内容について紹介する前に、弊社内でのこれまでのUI自動テスト開発の経験の中で上がっていた課題について説明させていただきます。

ウェブアプリケーションを対象にE2EのUI自動テストを書くとして、例えばログインページにメールアドレスとパスワードを入力する、という操作を自動化することを考えます。 この処理の実装としてよくあるのが、例えば以下のような実装です。

# テスト対象のログインページに移動
visit "https://test-target.com/login"
# nameが"emailAddress"であるフォームにemailを埋める
# この値は、テスト対象ページの実装依存
fill_in "emailAddress",  with: "hogehoge@fuga.com"

# nameが"passwd"であるフォームにパスワードを埋める
# この値は、テスト対象ページの実装依存
fill_in "passwd", with: "password"

# idが"btnNext"であるボタンを見つけてきて、クリックする
find('#btnNext').click

テスト対象ページのHTMLタグのidやnameの値をハードコードして、そこに特定の値を入力するという実装です。

このような実装では、テスト対象画面の入力フォームのidやnameの値をテストコード側で管理しなくてはなりません。テスト実行に必要なテスト対象固有のデータのことをテストアセットと呼びますが、テストの規模が大きくなってくるとこのテストアセットの管理が複雑になるという問題があります。

さらに悪いことに、HTML内のidやname属性の値は、テスト対象のHTMLの変更によって容易に変わってしまうものです。実際に弊社内で運用しているUI自動テストでも、HTMLの変更によってユーザから見れば全く問題がないにも関わらず、リグレッションテストが失敗することがしばしば起こります。リグレッションテストを利用するエンジニアはテストの実装者と異なる場合も多く、このようなUIテスト実行失敗の原因をシューティングすることは時間がかかり面倒な作業となっているのが現状です。

今回紹介する論文「Using Semantic Similarity for Input Topic Identification in Crawling-based Web Application Testing」では、このようなフォームの自動入力処理の実装に自然言語処理の手法を適用することで、テスト実装とテスト対象システムの実装を疎結合化し、テスト対象システム内の特定のHTML属性値に依存しないロバストなフォーム入力の自動化を実現する、という内容です。

フォーム入力自動化への自然言語処理の適用

この論文の中心となるアイディアはフォーム入力自動化を、HTMLタグをその意味ごとに分類するという機械学習の分類問題として取り扱ってみようというものです。機械学習によってテスト対象ページにあるフォームの意味が分類できれば、idやname属性の具体的な値をテスト側で知らずとも、 フォームを埋めることができます。例えば、ログインページであればページ内に存在する入力フォームを、1.ログインID、2.パスワード、3.ログインとは関係のないフォーム、の3種類に分類できれば良いといった具合です。

さてこの論文中では、フォームの実体であるHTMLを機械学習、特に自然言語処理の枠組みで扱うために少し工夫をしています。具体的には、各フォームに対応するHTMLタグを以下のように変換してしまいます。

変換前のHTMLタグ

<input type="email" id="subject-id" name="subject_id" autocomplete="on" placeholder="メールアドレス" class="txtfield w-max" value="">

変換後の単語列

["email", "subject", "id", "subject", "id", "メールアドレス", "txtfield", "w-max"]

この変換は単純に<input>タグの属性値を抜き出して単語ごとに区切っただけですが、論文中ではフォーム周辺の文字列を単語列に含めるなど、もう少し賢い変換を行っていますが本質は同じです。このような変換をかませることで、既存の自然言語処理の文書分類手法を、そっくりそのままHTMLに対して使うことができるでしょう、という点がこの論文の2つ目のアイディアです。

実験

この手法について、簡単な再現実験も行ってみましたのでその結果も報告させていただきます。

具体的には、DeNAの提供するいくつかのサービスのログインページに対して、出現する<input>タグを分類して、ログインIDを入力するフォーム、パスワードを入力するフォームを判別できるかどうかを試してみました。

詳細

グーグルで「ログイン」で検索して出てくる上位の41のサイトのログインページのHTMLから、

<input>タグを抽出し
・これらの<input>タグがログインIDなのか、パスワードなのか、ログインと関係ないタグなのかを手動でラベル付けした

ものを学習データとして利用しています。 学習データは合計218個のフォームで、ラベルの分布は

hyu01.png

のようになっています。

学習データ(mysqlのダンプ形式)

学習ログインページURLリスト

・文書のベクトル表現にはBag of Wordsを用いている

・文書ベクトルはLSI(潜在意味解析)による次元圧縮を行ったのち、ロジスティック回帰を用いてラベル推定を行っている

アルゴリズム実装にはPythonの機会学習ライブラリgensimを用いました。

学習・推定スクリプト

また、モデルの精度を評価するためのテストデータはいくつかの弊社サービスのログインページ内の10のフォームに対して検証を行っています。

hyu02.png

実験結果

検証実験の結果は以下のようになります。ログインIDに対するPrecision、Recall、パスワードに対するPrecision、Recallおよび全体のAccuracyを評価しています。

hyu03.png

データ数が小さいので確定的なことを述べるのは難しいですが、なんとなくうまくいっていそうです。再実行が簡単にできるUI自動テストというユースケースを考えると、Precisionが低いことはある程度許容できること、また本当は入力対象のフォームだったが推定時に取りこぼしてしまったケースがなかったこと(Recall 100%)を考えると実用的に利用できそうな気もしてくる結果です。

さて、誤判定をしている2つのケースですがこれはどちらも、本当はログインIDではないフォームを、ログインIDフォームとして誤判定しています。具体的にには、例えば以下のようなものでした。

<input type="email" id="register-subject-id" name="subject_id" autocomplete="on" placeholder="メールアドレス" class="txtfield w-max" value="">

このフォームタグがあるログインページは

image18392389.png

のような画面です。

このログインページには「メールアドレスでログイン」と「メールアドレスで会員登録」の2つのメールアドレス入力欄がありますが、今回の実験ではこの2つのフォームをどちらもログインID用の入力フォームと判定しています。本物のログインIDフォームの属性値と会員登録用フォームの属性値はほとんど同じであり、このケースは<input>タグの属性値のみを用いて判別するのは難しかった例と言えるかと思います。

今回の実験では簡単のため、原論文の実装とは異なり<input>タグ内部の属性直のみを用いていました。これを原論文と同じように各フォームの周辺のHTMLタグの値(ラベルの値など)を学習・推定に用いれば、このような誤判定も解決できるかもしれません。

まとめ

今回はICST 2017で発表された「Using Semantic Similarity in Crawling-based Web Application Testing」という論文について紹介させていただきました。再現実験では、とても単純な例とはいえ、UI自動テストへの機械学習適用の可能性を感じさせる結果を得ることができました。

本当にこのような手法がうまくいくのであれば、フォーム入力の自動化だけでなく自動テスト実装の様々な場面で利用することができると考えられ、より実践的なユースケースでの実験を引き続き進めていく予定です。

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

mithril.js v1.0 の変更点

こんにちは。DeNA Games Osaka 技術編成部のさい(@sairoutine)です。
DeNA Games OsakaはDeNAの大阪拠点です。今後ともよろしくおねがいします。

2017年01月31日に、mithril.jsのv1.0がリリースされました。 (2017年5月現在、v1.1.1までリリースされています)

軽い/高速/低学習コストというmithril.js本来の特徴はそのままに、これまでのバージョンでは制約となっていた機能が大幅に変更されています。

本記事では、v1.0のリリースに当たって、大きな変更となる箇所をご紹介したいと思います。
なお、mithril.js自体の紹介については、下記の記事をご参照ください。

最速フレームワーク Mithril 入門
http://developers.mobage.jp/blog/mithril-introduction

JSX が推奨に

仮想DOMのHTML like な独自拡張構文として React には JSXがありました。同様に、mithril.js にも MSX というのがありましたが、MSX は 1.0 から非推奨になり、公式のドキュメントでも、babel と transform-react-jsx が推奨となりました。

m.deferred が廃止され、Promise が使用される

v0.2.5 までは m.deferred という Promise like な非同期処理のための関数があり、m.request 等の一部の関数は m.deferred を使用していました。これが v1.0 からはブラウザネイティブな Promise を使用するようになりました。Promise 非対応ブラウザではpolyfill を使用してくれるので、引き続き IE9 までの古いブラウザでも、mithril.js が使用できることに変わりはありません。

m.prop が廃止され stream に

v0.2.5 までは、(主に Model)クラスのプロパティの getter/setter を作成するために m.prop という関数がありました。 v1.0 からはこれが廃止され、stream という命名で別モジュールに切り出されました。

stream では今までの getter/setter 機能に加えて、stream から新しい stream を生成して、元の stream の内容の変更を新しい stream に伝播させたり、あるいは stream 同士の合体をすることができるようになりました。

// stream から新しい stream の生成
var value = stream(1)

var doubled = value.map(function(value) {
    return value * 2
})

console.log(doubled()) // 2

// stream の合体
var firstName = stream("John")
var lastName = stream("Doe")
var fullName = stream.merge([firstName, lastName]).map(function(values) {
    return values.join(" ")
})

console.log(fullName()) // "John Doe"

firstName("Mary")

console.log(fullName()) // "Mary Doe"

streamモジュールは他にも色々と出来ることがあるので、詳しくは公式ドキュメントの stream の項を参照頂ければと思います。

vnode の概念の追加

v1.0 から vnode (Virtual DOM nodes)という概念が追加されました。vnode とは仮想DOMツリーを表すオブジェクトです。コンポーネントの view 関数や、あるいは後述するライフサイクルイベントに定義された関数が mithril から呼ばれる際に、引数として渡されます。

例えば、コンポーネントに状態を持たせて、状態を参照したり変更したりしたい場合は、vnode.state に状態を追加/変更します。

var Component = {
    oninit : function(vnode) {
        vnode.state.fooga = 1
    },
    view : function(vnode) {
        return m("p", vnode.state.fooga)
    }
}

vnode オブジェクトは他にも色々なプロパティを持つので、詳しくは公式のドキュメントの vnode の項目を参照頂ければと思います。

ライフサイクルイベント

v0.2.5 までは、仮想DOMに対する config 属性で一部のライフサイクルイベント(oninit, onupdate 等)に対する処理を実装していました。v1.0 からは config が廃止され、コンポーネントに対して、以下のライフサイクルイベントで処理される関数を定義することができるようになりました。

oninit
コンポーネントが初期化される際に呼びだされるフックです。実DOMが追加されるより前に呼び出されます。

oncreate
oninit と異なり、oncreate はコンポーネントが初期化されて、実DOMが作成した後に呼び出されます。実DOMが作成した後に呼ばれるため、vnode.dom 経由で実DOMを取得して操作を行うことが可能です。

onupdate
mithril.js による再描画によって、一度生成された DOMに更新があると呼び出されます。onupdate が呼び出された際には、既に更新された実DOMが生成されているので、vnode.dom 経由で更新後の実DOMを取得したり、操作することが可能です。

onbeforeupdate
onupdate と同様に、一度生成されたDOMに更新があると呼び出されます。onupdate が、更新された実DOMが生成された後に呼ばれるのに対して、onbeforeupdate では更新された実DOMが生成される前の、仮想DOMの差分比較のタイミングで呼び出されます。この時、onbeforeupdate で定義した関数でfalse を返すことで、差分検知をスキップすることができます。

onbeforeremove
DOMが削除される前に呼ばれます。このタイミングでは、削除される実DOMはまだ削除されていないので、vnode.dom で実DOMにアクセスすることが可能です。また、onbeforeremove で定義した関数がPromise オブジェクトを返すと、mithril.js はそのPromise が完了するまで、実DOMの削除を遅延します。

onremove
DOMが削除される際に呼ばれます。onbeforeremove に関数が定義されていると、onremove は onbeforeremove が完了した後に呼び出されます。

controller の廃止

controller という概念がなくなり、今まで controller のコンストラクタで行っていたことは、コンポーネントの oninit で行うことが推奨されました。またコントローラに紐づく関数は、コンポーネントの関数として記述することが推奨となりました。

最後に

v1.0 アップデートに当たっての大きな変更点をご紹介させていただきました。その他にも細かい変更がありますので、詳細は公式の change log を参照頂ければと思います。

コンポーネントに対するライフサイクルイベントの追加や、あるいは controller の廃止により、所感としてMVC フレームワークというより、コンポーネント指向なフレームワークに近くなった印象です。

一方で、軽い/高速/低学習コストという mithril.js 本来の特徴は失われていません。 SPAを構築する上で充分かつ必要最小限なAPIに加えて、他のライブラリやビルドツールに対して低依存であることから、JSフレームワークにおけるスイスアーミーナイフのような存在です。

v1.0 にアップデートされた mithril.js にぜひ一度皆様も触れてみてください。

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

Google Cloud Next'17 で GCP の中の人達と話してきた

こんにちは。村田 (yuichi1004) です。スマホアプリが PC でプレイできるプラットフォーム AndApp の開発に携わっています。App Engine + Go が好きです。

この度、3/8-10 にサンフランシスコで行われた Google Cloud Next'17 (Next) に参加してきました。その中で、『Next は GCP の中の人と話をする絶好の機会である』ことが分かったので、その話をしようと思います。

Nextとは

各地で開催される Google Cloud Platform (GCP) の技術発表会です。昨年までは GCP 中心のイベントでしたが、今年からは GSuite を中心としてエンタープライズ系の技術発表も兼ねたイベントとなりました。その関係もあってか、昨年の 2,000 人を大きく上回る 10,000 人規模で開催されました。

IMG_3016.JPG

我々 DeNA は、積極的に GCP を使っています(弊社のGCP導入にあたってはGoogle Cloud Platform Japan Blog の紹介記事をご確認ください)。今年は特に本腰を入れて、総勢 12 名でイベントに押しかけ、情報収集とディスカッションにあたりました。

Next は中の人と話す絶好の機会

Next の情報はすでに各種メディアで公開されていますし、各セッションの動画 は無料で公開されています。ですから、話を聞きに行く・情報を仕入れるだけならばわざわざカリフォルニアまで出向く必要はありません。Next の真髄は GCP の中の人と話せる絶好の機会 であるということです。

GCP の各セッションで登壇する人は各プロダクトを担当するプロダクトマネジャーやエンジニアになります。セッション以外にも、プロダクトの紹介ブースや、Meet The Expert というコーナーもあります。普段自分たちが使っている製品や興味のある製品を開発している人たちと直に話せるということです。

「Cloud Spanner のインスタンスって何なの?」と質問をぶつけてみました

自分は Cloud Spanner に特に興味をもっているのですが、どうしても Cloud Spanner の「インスタンス」や「ノード」が何を指しているのか分かりませんでした。そこで Cloud Spanner のブースに行ってプロダクトマネジャーとセールスエンジニアにこの疑問をぶつけてみました!

cloud-spanner-instance.JPG

担当者がその場で図を描いて事細かに説明してくれました。Google の Spanner の論文 と見比べてみると、ノードとは論文で言うところの Spanserver であり、インスタンスはノードの集合のようです。

ここで大事なことは、Cloud Spanner 上でノード数を 1 と指定すると、3 つのゾーンにそれぞれノードと書かれた箱が描かれる点です。つまり、 特定の物理マシン上で稼働するソフトウェアではなく、3 つのゾーンに分散して動作するソフトウェアスタックをノードと呼ぶ ということのようです。そのため Cloud Spanner は仮にノード数 1 で動作させたとしても 3 つのゾーンに分散して可用性を確保してくれます。

こうしたディープな話をダイレクトに聞くことができることこそが Next 最大の魅力だなと思いました。

英語が苦手、わざわざカリフォルニアまで行けないという方も多いと思います。そういう場合は Google Cloud Platform Community Slack をチェックすることをおすすめします。こちらの Slack にも、プロダクトマネジャーや開発者が目を通しています。質問すると丁寧に返事が返ってきます。

社内報告会も行いました

帰国後、DeNA 社内で Next 参加報告会を開催しました。各自現地で仕入れてきた情報や、ディスカッションを経て得られた情報を共有しました。

internal-report.jpg

GCP の注目度が上がる中、DeNA 社内でも GCP を活用したプロダクトの開発が注目されつつあります。現地のプロダクトマネジャーやエンジニアから得た情報を活かしつつ、今後のより魅力的な製品開発に活かしていきたいです。

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

JSONデータ圧縮方式をSnappyからzstdに切り替えた事例紹介

JSONデータ圧縮方式をzstdに切り替えデータ量を38.3%削減した事例、及びマイクロサービスの無停止アップデート事例について紹介したいと思います。

はじめに

JPRゲーム事業本部開発基盤部の池田周平です。先日Rails5対応についてDeNA techブログに投稿した@namusyakaと同じチームで働いています。

JSON文字列をRDBに格納する際の圧縮フォーマットをSnappyからzstdに切り替え、データ量を削減した事例を紹介したいと思います。本対応を実施した目的はDB負荷対策です。DBで扱うデータをより小さくすることで、DBサーバのDiskI/O負荷とMaster-Slave間のレプリケーション遅延対策を目的としています。

「Sakasho」は、DeNAが持つモバイルゲームのためのプラットフォームです。複数タイトルのゲームを取り扱っており、一部データはゲーム毎の仕様差を吸収し柔軟に取り扱うため、あえてスキーマレスなJSONを採用しています。JSON文字列に圧縮を掛けRDBに保存しているのです。RDBにJSONを格納している狙いはデータ不整合を避けるためで、トランザクションを張りデータ操作しています。

Snappy vs zstd

サンプル数はそれぞれ500万件くらいで、平均6Kbyte 最大2MbyteのJSONデータに対する圧縮時のログを集計して計算しました。結果データ圧縮率はzstdが12.4062% Snappyが20.1272%でした。Snappyからzstdに切り替えた結果データ量が38.3%削減されました。またAPPサーバのCPU使用率は反映前後で変化がなくサーバ追加等の対応は発生しませんでした。

あくまでDeNAで運用しているサービスの1事例です。正確な情報はZstandard公式ページをご覧ください。

Snappyとzstdについて

zstd正式名称Zstandardは、Facebookが2016年に公開したBSDライセンスのリアルタイム圧縮アルゴリズムです。リアルタイム圧縮とはデータを高速に圧縮と解凍することに主眼を置いたアルゴリズムであることを意味しています。公式ドキュメントによるとzlibと比較して圧縮率は変わらず、圧縮速度3.9倍、解凍速度2.8倍の性能です。またトレーニング機能を有し、これはデータ毎に固有辞書を生成する機能で、より効率的なデータ圧縮を実現します。

※ 圧縮解凍速度は、Zstandard公式ページに公開されているベンチマークデータから計算しました。またSnappyはGoogleが2011年に公開した圧縮アルゴリズムです。

Sakashoとは

Sakashoは、DeNAが持つモバイルゲームのためのプラットフォームです。 モバイルゲームを開発するために必要な機能を一通り提供し、ゲームの開発の効率化を図るための共通基盤として開発・運用されています。マイクロサービス構成となっており、役割ごとに10の独立したサービスと、管理ツールによって構成されています。

sakasho.jpg

マイクロサービスの無停止アップデート

データ圧縮方式をSnappyからzstdに切り替えるにあたり、無停止でアップデートを実施するためにdeploy方法を工夫しました。

仮にマイクロサービス群に対して順にdeployを行っていくと、後半にdeployするサービスで障害が発生してしまいます。 zstd_deploy_1.png

無停止でアップデートするために、下図のようにdeployを2段階に分け、1段目でSnappyとzstdどちらでもデータをreadできる対応をdeployし、2段目でデータ圧縮方式を切り替える対応をdeployすることで複数のマイクロサービスにまたがる修正を本番反映しました。

zstd_deploy_2.png zstd_deploy_3.png

zstdライブラリの選定

各サービスは主にRubyで開発しています。zstdもRubyから扱う場合がほとんどです。gemに登録されている複数のzstdライブラリのうち、どれを選ぶべきか悩んでいたらruby expertな先輩からnative extentionでビルドしているため、メモリリークの観点で調査するべきだとアドバイスもらいました。

検証結果とコードはこちらです。


# memory_usage_zstd.rb
require 'zstd'

def current_process_memory_usage
  `ps ax -o pid,rss | grep -E "^[[:space:]]*#{Process.pid}"`.strip.split.map(&:to_i)[1]
end

JSONFILE_PATH = 'data_139k.json'
json_data = open(JSONFILE_PATH){ |io| io.to_s }
compressed_data = Zstd.new.compress(json_data)

1_000_000_000.times do |n|
  Zstd.new.decompress(compressed_data)
  puts "loop:#{n} memory usage: #{current_process_memory_usage} Kbytes" if n % 1_000_000 == 0
end

# memory_usage_zstd_ruby.rb
require 'zstd-ruby'
.....
compressed_data = Zstd.compress(json_data)

1_000_000_000.times do |n|
  Zstd.decompress(compressed_data)
  puts "loop:#{n} memory usage: #{current_process_memory_usage} Kbytes" if n % 1_000_000 == 0
end

# gem: zstd (残念ながらメモリリークした)
# https://rubygems.org/gems/zstd/

$ ruby memory_usage_zstd.rb
loop:0 memory usage: 10884 Kbytes
loop:1000000 memory usage: 43200 Kbytes
loop:2000000 memory usage: 74776 Kbytes
loop:3000000 memory usage: 106692 Kbytes
loop:4000000 memory usage: 138616 Kbytes
loop:5000000 memory usage: 169960 Kbytes
loop:6000000 memory usage: 201592 Kbytes
loop:7000000 memory usage: 233584 Kbytes
loop:8000000 memory usage: 265236 Kbytes
loop:9000000 memory usage: 297132 Kbytes
loop:10000000 memory usage: 329136 Kbytes

# gem: zstd-ruby 
# https://rubygems.org/gems/zstd-ruby

$ ruby memory_usage_zstd_ruby.rb
loop:0 memory usage: 10836 bytes
loop:1000000 memory usage: 13060 Kbytes
loop:2000000 memory usage: 13808 Kbytes
loop:3000000 memory usage: 13816 Kbytes
loop:4000000 memory usage: 13944 Kbytes
loop:5000000 memory usage: 13944 Kbytes
loop:6000000 memory usage: 13944 Kbytes
loop:7000000 memory usage: 14176 Kbytes
loop:8000000 memory usage: 14176 Kbytes
loop:9000000 memory usage: 14184 Kbytes
loop:10000000 memory usage: 14184 Kbytes

まとめ

JSONをzstd圧縮してDBに格納したら、Snappyと比較してデータ量が38.3%削減。JSON文字列と比較して87.6%データ削減できました。 Rubyでzstdフォーマットを扱う場合はzstd-rubyがオススメです。

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

「Sakasho」のRubyを2.4に、Railsを5にアップグレードしました

はじめに

JPRゲーム事業本部開発基盤部の@namusyakaです。

業務ではDeNAのゲームプラットフォームであるSakashoのバックエンドやインフラ周りの開発・運用をしています。

そして最近アイコンを8~9年ぶりくらいに変えました。よろしくお願いいたします。

さて本題ですが、Sakashoでは今年の2月に管理アプリケーションのRuby・Railsのバージョンの大幅なアップグレードを実施しました。この記事ではそのアップグレード対応について、一つの事例として紹介させていただければと思います。

概略

冒頭でも触れましたが、アップグレードしたのはDeNAのモバイルゲームプラットフォームであるSakashoの機能を制御するための管理アプリケーションになります。

Sakashoとは

Sakashoは、DeNAが持つモバイルゲームのためのプラットフォームです。 モバイルゲームを開発するために必要な機能を一通り提供し、ゲームの開発の効率化を図るための共通基盤として開発・運用されています。

Sakasho全体のアーキテクチャは次のようなイメージです。

sakasho architecture

今回のアップグレードは、この図の右端に位置する管理アプリケーションが対象となります。 ところで、余談ではありますが、SakashoのAPIは原則としてRailsではなくSinatraをベースに実装されています。 機会があれば、そのアプリケーションアーキテクチャについても、今後紹介できればと思います。

管理アプリケーションの特性

主に次のような特性を持ちます。

  • ruby-2.1.4/rails-4.1.1で動作している
  • ゲームプラットフォームが持つ全機能に対する制御系統を持つ。
    • ゆえに、コードベースがかなり大きい。
  • 複数DBを前提とした作りになっている。
    • 一部シャーディングもしている。
  • テストはある程度揃っている

実際の規模感をお伝えするために、rake statsの実行結果を貼っておきます。

+----------------------+--------+--------+---------+---------+-----+-------+
| Name                 |  Lines |    LOC | Classes | Methods | M/C | LOC/M |
+----------------------+--------+--------+---------+---------+-----+-------+
| Controllers          |  19075 |  15518 |     247 |    2224 |   9 |     4 |
| Helpers              |   1879 |   1657 |       0 |     225 |   0 |     5 |
| Models               |  21974 |  16928 |     581 |    1442 |   2 |     9 |
| Mailers              |      0 |      0 |       0 |       0 |   0 |     0 |
| Javascripts          |   3000 |   2763 |       0 |     620 |   0 |     2 |
| Libraries            |  10018 |   7358 |      96 |     395 |   4 |    16 |
| Tasks                |   4416 |   3132 |       2 |      15 |   7 |   206 |
| Config specs         |     23 |     20 |       0 |       0 |   0 |     0 |
| Controller specs     |  45014 |  40239 |      28 |       4 |   0 | 10057 |
| Helper specs         |    850 |    727 |       0 |       1 |   0 |   725 |
| Lib specs            |   9852 |   8384 |       1 |      10 |  10 |   836 |
| Model specs          |  17982 |  15974 |       0 |       3 |   0 |  5322 |
| Support specs        |   1038 |    943 |       2 |      13 |   6 |    70 |
| Validator specs      |    396 |    328 |       2 |       7 |   3 |    44 |
+----------------------+--------+--------+---------+---------+-----+-------+
| Total                | 135517 | 113971 |     959 |    4959 |   5 |    20 |
+----------------------+--------+--------+---------+---------+-----+-------+
  Code LOC: 47356     Test LOC: 66615     Code to Test Ratio: 1:1.4

簡単に見方を説明すると、LOCというのはLines Of Codeの略で、コードの行数を指します。 その他にも、例えばモデルと分類されるクラスが何個あるか、といった情報を読み取ることができるため、参考にしていただければ幸いです。

改修期間

対応のために掛けた期間は着手から本番リリースまで凡そ一ヶ月弱です。 大きく「開発」・「テスト」の2つのフェーズに分けることができ、それぞれにかかった期間としては次のようになります。

  • ruby-2.4.0・rails-5.0.1にアップグレードし、全てのテストケースがpassすること (一週間)
  • QAによるテスト (二週間)

開発期間中のアップグレード作業は私一人で進め、変更点のレビューなどはチームメンバー全体に依頼する形で進めました。 今思うと大分駆け足だった感はありますが、現時点で大きな障害もなく稼働しています。

なお、一応補足しますが、この記事は「テスト」ではなく「開発」のフェーズについての解説となります。

アップグレード戦略

前提となりますが、この管理アプリケーションはruby-2.1.4/rails-4.1.1で動作していました。

それらを目的のruby-2.4.0/rails-5.0.1にアップグレードするために参考にしたのが、Railsが公式に提供しているA Guide for Upgrading Ruby on Railsです。

このアップグレードガイドによると、rails-5にアップグレードするには、対象のアプリケーションはrails-4.2でなければならないようです。 したがって、目標のアップグレードを実施するには段階を踏んでアップグレードする必要があり、まずはrails-4.1.1をrails-4.2.7.1にアップグレードしなければなりません。

実際のアップグレードの流れは次のとおりです。

  • rails-4.1.1をrails-4.2.7.1までアップグレード
  • ruby-2.1.4をruby-2.4.0までアップグレード
    • ruby-2.4にバージョンをあげたらrails-4.2.7.1では動作しなかったので、railsの4-2-stableにこの時点でスイッチしました。
  • rails-5.0.1までアップグレード

一つのフェーズごとにテストが全てpassすることをゴールと設定しています。

そして、各バージョンにアップグレードする前には、可能な限りdeprecation warningsを潰すようにしました。 これは、将来的に削除される機能などを事前に回避しておくことでトラブルを防ぐ意味合いがあります。

また、この戦略を進めるにあたり、リリースブランチとは別にアップグレード専用のブランチを用意するほか、ruby-2.4でテストするための専用のjenkins jobを用意して、通常のリリースフローとは独立する形で作業を進めました。

変更点

この手の作業はbundle updateを通す作業から始まります。 幸いにして5.0.1は去年の12月リリースだったこともあって、ある程度依存しているgemは対応済みで、gemに対してパッチを当てたりforkしたり、といったことは特にする必要はありませんでした。 新しいバージョンが出たばかりのHotな時期にアップグレードするのもいいですが、数年間アップグレードされてこなかった規模の大きいアプリケーションを対象とする場合は、数ヶ月程度の時間を置いてから進めた方がハマりどころが少なくて助かるかもしれません。

次に実際の変更点について紹介します。 しかしながらあまりに数が多すぎるため、特に影響範囲が大きかった変更と、deprecation warningsなどの中から、アップグレードガイドに記載されていないものを中心にいくつか取り上げようと思います。

rails-4.2.7.1対応

元がrails-4.1.1なので、まずはUpgrading from Rails 4.1 to Rails 4.2に従って粛々と対応しました。 Upgrade guideに書いてあることは割愛するとして、主要な変更点を挙げます。

deprecations & minor changes

Primary keyでないidcolumnを持つテーブルにおいて、取得したレコードをinspectした結果、idがnilと表記される

idというカラムは存在するが、primary keyではないケースで発生する不具合です。 不具合といってもinspectの結果がおかしい程度ではあるのですが、次のようなコードで正常にidが出力されない問題がありました。

Book.find_by(id: 1).inspect #=> "#<Book id: nil, ...>"

これについてはRails側を修正することで対応しました。たまたま見つけた不具合という感じです。

Pull Request: Fix inspection behavior when the :id column is not primary key by namusyaka · Pull Request #27935 · rails/rails · GitHub

t.timestampsのデフォルトがNULLを許可からNOT NULLに変更

次のように指定することで解決しました。

create_table :books do |t|
  t.timestamps null: false
end

従来どおりの挙動にしたければnull: trueとします。 動的にtableを生成するケースなどがもしあれば、要注意といえるでしょう。

JSON.loadnilを渡さないように修正

4.2.7.1では例外が出るようになっていました。 nullが返されることを期待しているわけでもなかったので渡さないように変更しました。

関連: Fixed JSON coder when loading NULL from DB by chancancode · Pull Request #16162 · rails/rails · GitHub

MySQL-5.6以上では時刻のミリ秒を保存するようになった

MySQLにミリ秒を持たせるのは別の意味でしんどくなりそうだったので、モンキーパッチで回避しました。

参考

ActiveRecord/ActiveModelが範囲外の値に対して例外を吐くようになった

例えば、次のようなコードについて考えます。

Book.where(id: -1).first

この処理はrails-4.1と4.2で挙動が異なり、4.1ではnilが返り、4.2以降はActiveModel::RangeError: -1 is out of range for ActiveModel::Type::UnsignedInteger with limit Xといった例外が発生するようになっています。

ActiveModelにtype castingの機構が実装されたお陰だと思います。 ロジックに問題のあるコードがこれで顕在化されることになるため、これを機に既存の実装を見直しました。

ところで、この機構は明示的にlimitが指定されていない場合に、signed int(4bytes)を自動的にリミットとして定めてしまうという問題があります。

参考: Avoid RangeError without explicit limit by kamipo · Pull Request #26302 · rails/rails · GitHub

Adequate Recordの影響で動的にテーブル名をセットしているところが壊れた件

Adequate Recordはactive_record/core.rbに定義されている.find.find_by.find_by_xxx系のメソッドに対して、ActiveRecord::StatementCacheを用いてキャッシュを有効化する機能を指します。 Arelを経由したSQLへの変換を行わなくて良くなるので二倍ほど高速化が見込めるという話のようです。

この機能自体は非常に素晴らしいのですが、これを実現するために内部的に使用されているキャッシュキーはprimary keyをベースにしたものとなっており、テーブル名については一切考慮されていませんでした。 したがって、テーブル名が動的に変わった場合もprimary keyが一致すればキャッシュが効いてしまうので、誤ったSQLを発行してしまうリスクが存在しています。

無論そんな使い方をするなという話もあるかもしれませんが、動きそうなところが動かないのは困るということで、Railsを修正しました。 直し方としてはtable_name=が実行されたらキャッシュをリセットするように修正する、というものです。

Pull Request: Make table_name= reset current statement cache by namusyaka · Pull Request #27953 · rails/rails · GitHub

ちなみにこれを回避するには、Adequate Recordが効かないQueryMethodsを使ってやるだけで良いので、次のように書き換えるのが簡単です。

Book.find_by(id: 1) # before

Book.where(id: 1).first # after

ruby-2.4.0対応

rails-4.2.7.1の対応を終えた後に、ruby-2.1.4からruby-2.4.0にアップグレードしたところ全く動きませんでした。 どうやら4.2.7.1はruby-2.4.0に対応していないようで、ruby-2.4にアップグレードする前に一旦4-2-stableを使うように変更しました。

なお、私が対応していた時点では4.2系のバージョンの中では4.2.7.1が最新版でしたが、つい先日4.2.8がリリースされ、公式にruby-2.4がサポートされています。今後アップグレードする際には4.2.8を使用することをオススメします。

さて、この項ではruby-2.1.4からruby-2.4.0にアップグレードしたことで発生した主要な問題点を挙げてみます。といっても、Railsほど苦労はなかった印象です。

FixnumIntegerに統合

軽く書いてはいますが、native extension系のgemは要注意です。 以下は具体例です。

アップグレードする対象のアプリケーションが依存するgemのruby-2.4 対応状況については事前に洗い出しておいた方が良さそうです。 必要であればパッチを送り、新バージョンのリリースをねだりましょう。

サブクラスの抽出に自前のObjectSpace#each_objectではなくActiveSupportのコア拡張であるClass#subclassesを使うように変更

ruby-2.3.0からObjectSpace#each_objectがシングルトンクラスを含むようになりました。 SakashoではClass#subclassesの自前実装をObjectSpace#each_objectをベースに持っていて、そちらを修正しようとも考えたのですが、ActiveSupportのコア拡張でほぼ同じことをやっていたので、そちらを使うようにして修正しました。

参考

openssl系の標準添付ライブラリにて、keyやivの文字数がvalidでないと例外が発生するようになった

もともとの実装では、文字数がオーバーしている場合は丸められていたようです。 したがって、事前に文字列を適切にsliceするように変更して修正しました。

参考: openssl: make Cipher#key= and #iv= reject too long values · ruby/ruby@ce63526 · GitHub

rails-5.0.1対応

rails-5.0.1にアップグレードする際にも、まずはUpgrade guideに沿って進めました。

5へのアップグレードには設定ファイルの追加やinitializerの追加などを含むため、そのあたりを中心に対応を自動化するための機構として、app:updateというRakeタスクが提供されています。 対話的に大きな差分を自プロダクトに反映していくことになりますが、ある程度既存のコードにも影響のある部分なので、しっかり差分を注視しながら進めた方が良さそうです。

このフェーズについても、Upgrade guideの内容は割愛し、主要な変更点を挙げていこうと思います。

deprecations & minor changes

ActionController::ParametersがHashを継承しなくなった

多くの場所で取り上げられている変更点ですが、例に漏れず対応が困難だったもののうちの一つです。 Hashが持つメソッドや振る舞いに依存しているコードの多くが正常に動作しなくなるため、アップグレードする際には事前にその辺を洗い出しておくと楽かもしれません。

参考: Make AC::Parameters not inherited from Hash by sikachu · Pull Request #20868 · rails/rails · GitHub

datetime_selectに入力された値をDateTimeとして取得する際に、受け取った値をそのままhidden_fieldtext_fieldに渡すとRubyのHashをinspectした値がvalueに埋め込まれてしまう件

例えば次のような要素があるとします。

= f.datetime_select :opened_at, use_month_numbers: true, start_year: default_start_year

このヘルパーは、日付にかかる情報を扱うために複数のselect要素をレンダリングします。 そして、opened_at(1i)opened_at(2i)...といった複数のキーからなるopened_atにかかる情報をサーバに送信し、それらのパラメータをActiveRecord::Baseインスタンスに渡してやることで、よしなにopened_atに時刻情報が代入されるという作りになっています。

これはもとからRailsが持つ機能ではありますが、Sakashoでは、更にこのsubmitされた値を確認画面などでhidden_fieldに埋め込むケースが非常に多いです。

サンプルとしては、次のようなコードになります。

= f.hidden_field :opened_at

form_forなどに代表されるこれらのform methodは、第一引数で受け取ったカラム名を用いて、対象となるインスタンスに対して実行し、その結果をvalue属性に代入します。 今回はこの代入される値に問題がありました。次のようになります。

<input type="hidden" value="{1=&gt;2017, 2=&gt;2, 3=&gt;27, 4=&gt;21, 5=&gt;0, 6=&gt;0}" name="archive[opened_at]" id="archive_opened_at" />

これは、内部的に実行されるxxx_before_type_castという、その値をキャストする前の値を返す機構に起因します。 今回のケースでは、opened_atにはもともとdatetime_selectによって生成された複数のselect要素群から作られたHashが代入されています。 当然、validationを通過した結果の確認画面ではそのHashがopened_atの値として埋め込まれており、確認画面を経て、いざ作成しようとした際にエラーが発生して保存できない、といった問題が発生することになります。

この問題についてはPull Requestを投げてはいるものの、まだレビュー待ちという状態です。

反省点

今回は短期間で一気にアップグレードを実施しましたが、本来であれば計画的に実施すべきだと思います。 Railsを使ってアプリケーションを作って終わりではなく、定期的に依存するgemのアップグレードに追従しようとする姿勢こそがRailsと付き合っていくコツといえるでしょう。 そこでSakashoでは、bundle updateを自動で行い、アップグレードされたgemの差分を表示しつつ、そのGemfile.lockの変更差分をコミットするPull Requestを自動で作成する機構を導入しました。

これにより、普段の業務でも自分たちが採用しているossのリリースを考慮して取り組めるようになると考えています。

おわりに

大規模なRailsアプリケーションで、かつ長らくアップグレードされてこなかったプロダクトを最新バージョンにアップグレードするのは非常に骨の折れる作業でしたが、短期間で集中的に取り組めたことは良い経験となりました。

また、管理アプリケーションとしての特性上複数DBを前提としているなど、一般的なRailsアプリケーションのそれとは異なる構成であり、それをきっかけとして発見したRailsのいくつかの不具合を修正することができました。

このような環境下で運用されるRailsアプリケーションはそう多くはない認識ですし、Sakashoのような環境でしか発生しない不具合はまだ存在するはずです。Railsを利用する立場として、そういった不具合に積極的に対処してコミュニティに還元していく姿勢が今後重要であると考えています。

最後になりますが、Railsを採用される際には、用法用量を守って正しくお使いください。

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

DeNA TechCon 2017 開催レポート【4】

こんにちは。ゲーム事業本部開発基盤部の池田です。

去る2月10日、DeNAは技術カンファレンス「DeNA TechCon2017」を開催しました。
全4回に渡る振り返り記事も本記事で最後となります。

今回は、筆者が聴講した以下のセッションの内容を紹介します:

  • Bステージ「AndApp開発における全て」KOBAYASHI ATSUSHI
  • Dステージ「DeNA内製ゲームエンジンの現状と目指す未来」ERA KAZUTAKA

また、最後のレポート記事ということで、カンファレンスのクロージングの模様なども合わせてお伝えします。

AndApp開発における全て

オープンプラットフォーム事業本部システム開発部のKOBAYASHI ATSUSHIは、2016年11月にローンチされたAndAppというサービスの舞台裏について発表しました。

056_20170227.JPG

AndAppはスマートフォン向けゲームをPC上でプレイできるプラットフォームで、2017年3月現在、15タイトルが配信されています。
そのサーバサイドのシステムは、従来のオンプレミス環境のサービスとは異なり、Google App Engine Standard Environment(以下、GAE SE)上で動作しています。
また、開発言語も従来のPerlとは異なり、GAE SEで利用可能なGo言語が採用されました。

講演の前半では、AndAppの開発の中で、どのように技術選定を行って上記の構成となったかを述べました。その大きな理由の1つとして、開発・運用する上で絶対に必要な工数以外は、サービスを作る工数に当てたかったから、という点が挙げられました。

後半のトピックは、AndAppのシステムアーキテクチャや開発体制、コストについてでした。
アーキテクチャとしては機能単位でコンポーネント化するMicroservices構成が取られ、それに合わせて、少人数チームを数多く作る開発体制が取られました。
Microservicesとして、本講演時点で26のサービスが稼働しています。

講演のまとめの中で、既存の技術や運用にとらわれずにモノづくりに集中できる環境を作ることの重要性が述べられました。
最後に、「一番大切なことは、めいっぱい楽しむこと。ワクワクしよう!」と締め括られました。

スライド資料

DeNA内製ゲームエンジンの現状と目指す未来

Japanリージョンゲーム事業本部開発基盤部のERA KAZUTAKAは、DeNA内製ゲームエンジン「Lift Engine」の現状と目指す未来について発表しました。

DSC_4350.jpg

Lift Engine®Cocos2d-xをベースとして、ゲーム開発において不足していた機能を実装し、最適化を施した内製ゲームエンジンです。
採用タイトルとしては、「デナレンジャー」や「ガールアックス(*1)」があります。

2DゲームエンジンとしてのLift Engineの紹介の後、Lift Engineを3Dゲームエンジンとして使うための取り組みについて、説明しました。

Lift Engine 3Dで新規に実装した機能として、コマンドバッファを用いてレンダリングを専用スレッドで行うレンダリングパイプライン、コリジョン判定やSIMD対応した行列演算を含む算術関数、独自クラスを用いたシリアライザなどが挙げられました。

Arcana」は、Lift Engine 3Dと共に用いられるゲーム開発のためのアプリケーションフレームワークです。
Lift Engine 3Dでは汎用的・基本的な機能の提供に留め、上位レイヤに位置付けられるArcanaによって、よりゲーム機能の実装に即したモジュール群や、ゲームの作り方を規定する仕組み等を提供します。

講演のまとめの中で、「面白いゲームを作るためには、品質向上に時間を割くことが重要」と述べられました。
今後のLift Engine 3Dでは、まずはゲーム開発のトライ・アンド・エラーの周期を短くすることに注力し、開発・運用効率の最大化を目指していきます。

スライド資料

クロージング

カンファレンスを締め括るクロージングでは、今年も弊社取締役の川崎が登壇し、総括と謝辞を述べました。

DSC_7597.jpg

以前のDeNAでは、レガシーな技術にこだわって使い続ける傾向もありましたが、最近はユーザにより大きな価値を届けるため、新しい技術も積極的に採用しています。
本カンファレンス全体を通して、そのようなDeNAの技術に対する姿勢が伝わったなら幸いです。

昨年に続いて今年も会を開催できただけでなく、昨年を上回る規模のご来場を頂けたことを嬉しく思います。
この場をお借りして、御礼を申し上げます。
特にカンファレンスに足を運んで頂いた方々については、誠にありがとうございました。

本記事執筆時点では、まだ各セッションの動画は公開されておりませんが、追ってTechConのサイトにて公開を予定しています。
Twitterの公式アカウントFacebookページによる案内をお待ち下さい。

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

IMG_0390.jpg

スタッフ集合写真

脚注

(*1) ガールアックス - Google Play の Android アプリ

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

DeNA TechCon 2017 開催レポート【3】

こんにちは、 SWET グループの加藤です。

DeNA TechCon 2017 が2017年2月10日に開催されました。

DeNA TechCon レポート第 3 回となる本記事では、 DeNA の基盤技術に迫った

の 3 つの発表をご紹介します。

DeNAの動画配信サービスを支えるインフラの内部

024.JPG

IT基盤部の HATA がライブ配信の SHOWROOM とスマートフォンの生放送・実況配信サービス Mirrativ を題材に、動画配信サービスを安定して運用するためのノウハウについて発表しました。

生放送のための Origin サーバと Edge サーバの構成、負荷分散、障害発生時の自動対応、低遅延を実現するための工夫、インスタンスの状態遷移、監視体制、オートスケールの仕組みについてなど、盛りだくさんの内容でした。

特に、オートスケールに関しては、求められるものに応じて何度もスクラッチから実装し直しているとのこと。

こうして作られたインフラ基盤によって、 SHOWROOM 3周年記念の 24 時間生放送や AKB48 45th シングル選抜総選挙、横浜DeNAベイスターズ主催試合生中継など多くの視聴者のいた放送でも安定して配信できたそうです。

スライド: DeNAの動画配信サービスを支えるインフラの内部 #denatechcon from DeNA

DeNAでのチート診断・脆弱性診断の取り組み

134.JPG

セキュリティ技術グループの SUGIYAMA が、サーバー・クライアントで成り立つスマホ向けゲーム開発におけるチート対策について発表しました。

セキュリティ・キャンプでの講義 にも使われたチート対策の学習用アプリを題材に、典型的なチート手法が紹介されました。

この学習用アプリはブラウザで動くため開発者ツールで簡単に改竄できるため、チートを行う攻撃者の視点から脆弱性対応を学べるとのこと。また、ネイティブアプリであってもチートの手法は基本的に同じであり、クライアントに関しては完全なチート防止は無理なので、サーバ側でのデータ改竄を防止することが重要だそうです。

スライド: DeNA_Techcon2017_DeNAでのチート・脆弱性診断への取り組み from Toshiharu Sugiyama

147.JPG

また、スマートフォン向けゲームのチート対策に関しては、同じセキュリティ部の MURAKAMI の発表「SafetyNetを使ってゲームを守る」もありました。こちらもあわせて見ると、より理解が深まると思います。

DeNAの取り組むテストエンジニアリング

157.JPG

SWET グループの OKITA KUNIO が発表しました。 SWET は SoftWare Engineer in Test を意味する言葉であり、 DeNA ではソフトウェアテストをリードする役割を持つ部署です。

テストエンジニアリングに求められるスキルの紹介や、事業サポートとテスト基盤といった、ロールにあわせた SWET 内でのチーム体制が説明されました。

また、新たな取り組みとして、ツールのバージョンアップを監視し、即座に動作確認を行い、アップデートしても安全化をチェックするマスティフというツールや、安定したパイプラインを実現するための Microservices の構成、クローラの探索による自動チェッキングといった挑戦が語られました。

さらに、 AI による E2Eテストの自動化にも取り組んでいるとのこと。現在はまだ学習データを収集するための基盤づくりの段階だそうですが、将来的にはこれまで踏み込まれなかった領域にまで自動化が進みそうです。

最後に

この他にも、 TechCon では数多くの発表がなされました。公式サイトのスケジュール画面 に、発表の動画とスライドへのリンクがありますので、どうぞごらんください。

次回の記事が DeNA TechCon レポートの最終回となります。お楽しみに!

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

DeNA TechCon 2017 開催レポート【2】

こんにちは。ゲーム事業本部開発基盤部の池田です。

去る2月10日、DeNAは技術カンファレンス「DeNA TechCon2017」を開催しました。
公開可能な資料については、公式サイトのスケジュール画面からリンクしておりますので、まだチェックしていないという方は是非ご覧ください。
追って、各セッションの動画もアップ予定です。

本記事は、この「DeNA TechCon2017」振り返り記事の第2弾となります。

今回は特に、DeNAの新たなチャレンジ領域である AI 分野について、Aステージで筆者が聴講した以下の3講演について取り上げます:

  • 基調講演:「実世界の人工知能」株式会社Preferred Networks岡野原大輔様
  • 「強化学習を利用した自律型GameAIの取り組み〜高速自動プレイによるステージ設計支援〜」MASHIKO RYOSUKE, SEKIYA EIJI
  • 「DeNA AIシステム部におけるクラウドを活用した機械学習基盤の構築」SEO NAOTOSHI

基調講演―実世界の人工知能

基調講演では、株式会社Preferred Networks岡野原大輔氏が登壇しました。

DSC_6045.jpg

講演の前半では、畳み込みニューラルネットワークが近年の研究でどのように複雑に進化し、ディープラーニング(深層学習)と呼ばれるようになったかを解説しました。
深層学習で使われる畳み込みニューラルネットワークでは、ネットワークの層数やニューロン数が、それまでのものより桁違いに多くなっています。

この深層ニューラルネットワークが、現在、様々な分野で応用されつつあります。

講演では、応用分野として「自動車」「ロボット」「異常検知」「バイオ・ヘルスケア」「コミュニケーション」「クリエーター」といった分野における取り組みについて取り上げられました。

特に、「クリエーター」分野においては、線画にいい感じに着色する PaintsChainer が最近インターネットなどで話題になったことは、記憶に新しいのではないでしょうか。

結びとしては、深層学習・教科学習の進化は著しく、研究段階から実用化・ビジネス化チームが付き添うことが大事と締め括られました。

強化学習を利用した自律型GameAIの取り組み〜高速自動プレイによるステージ設計支援〜

こちらのセッションは前半・後半の2部構成でした。

前半では、強化学習そのものについてAIシステム部SEKIYA EIJIが発表しました。
まず、強化学習の仕組みについて簡単な解説をした後、2014年に登場した新手法であるDeep Q-Networksの概要を示しました。
次に、強化学習に関する最新の動向として、NIPS 2016で発表されたDeepMind LabやOpenAI Universeなどについて取り上げました。

後半では、強化学習の利用例として、FINAL FANTASY Record Keeperにおける自律型GameAIの活用事例について、同じくAIシステム部のMASHIKO RYOSUKEが発表しました。

DSC_6525.jpg

FINAL FANTASY Record Keeperでは、ボスのパラメータ調整を行うため、バトルを自動プレイするAIに対するニーズがありました。

このバトルAIの行動決定アルゴリズムとして、探索的アプローチであるMonte Carlo Tree Searchと、ニューラルネットを用いたアプローチであるNEAT, Q-learningを適用した結果が比較解説されました。
結果として、ニューラルネットを用いた方法において、学習時間が掛かるなど課題はあるものの、人がプレイする場合と遜色ないレベルでの勝率を達成することができました。

講演の最後では、ゲームへのAI活用のポイントとして、ゲームシステムの設計段階でどこまでAIを利用するか考慮し、シミュレータやデータ形式を用意しておくことの重要性が挙げられました。

DeNA AIシステム部におけるクラウドを活用した機械学習基盤の構築

AIシステム部のSEO NAOTOSHIは、DeNAにおけるクラウドを活用した機械学習システム基盤の構築について発表しました。

DSC_6743.jpg

DeNAの機械学習システムのインフラ面においては、「潤沢なGPU」「隔離された環境」「素早い構築」「運用が楽」「自由度を高く」「ミスが起きにくい」という6つの要素が求められていました。
本発表では、これらの要素一つひとつを達成するために、AWSやGCPを活用したインフラ環境の構築方法について示しました。
例えば、「素早い構築」については、TerraformやItamaeといったツールを活用し、AWS, GCPの両方に対応した環境構築をコード化していることが語られました。

発表の後半には、GPU学習環境をオンデマンドでスケールさせるために整備したツールや、APIサービス環境の構成が取り上げられました。
GPU環境をスケールさせるための内製ツール「ec2-scale-run」の中ではDockerが活用されています。このツールでは、使われなくなったインスタンスを再利用し、また不要になったら確実にシャットダウンする仕組みがあることが説明されました。

結びに

本記事を通して、DeNAがAI分野においてどのようなチャレンジ・取り組みをしているか、少しでも伝われば幸いに思います。

余談ですが、Aステージの講演では社員によるグラフィックレコーディングがリアルタイムに行われ、完成したものは展示スペースに貼り出されました。

下の写真は、基調講演のグラフィックレコードとなります。

CR9A7145.jpg

次回の記事でも引き続き、発表されたセッションの模様を紹介していく予定です。
お楽しみに!

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

DeNA TechCon 2017 開催レポート【1】

こんにちは、 SWET グループの加藤です。

DeNA TechCon 2017 が2017年2月10日に開催されました。昨年に続き、第2回目です。

今回から全4回に渡り、 TechCon 2017 の様子をお伝えします。

第1回となる本記事では、 Opening の様子、そして SAKAI KENGO による『DeNA private cloudのその後』のセッションについてご紹介します。

CR9A6825.jpg

CR9A6920.jpg

オープニング

IMG_0018.jpg

オープニングでは木村 (hidek) による Dena TechCon の主旨が述べられました。

TechCon は DeNA の技術チャレンジ総決算です。先人の技術と知恵で DeNA はここまで成長したわけですが、その恩返しの意味も込めて、エンジニアの挑戦で得た知見を社会に還元したいという思いが語られました。

特に、 DeNA は、これから力を入れていく AI についてのアウトプットを増やしてゆくつもりです。 AI は社会を変革する可能性を持ちます。 DeNA の創業技術はインターネット関連技術ですが、それに加えて AI も DeNA の技術の中心に据えて、本気でやっていくという姿勢を表明しました。

展示

CR9A6814.jpg

IMG_9874.jpg

CR9A6801.jpg

トークセッションだけでなく、 DeNA の技術を紹介する会場展示も行われました。たくさんの方が、実機ゲームサンプルやキービジュアル、社内開発のミドルウェア紹介の展示に足を止めていました。

DeNA private cloudのその後

IT 基盤部の SAKAI KENGO が DeNA の社内インフラ基盤について発表しました。

スライド: DeNA private cloudのその後 #denatechcon from DeNA

昨年の Dena TechCon で紹介した、サーバやネットワークの構成がこの一年間でどう変わったかに焦点が当てられました。

過去のエンジニアブログの記事にも書かれたように、 DeNA はオンプレミスのサーバにおいて、 Ceph を SDS(Software Defined Storage) として使い、 OpenStack で構築した Private Cloud 構成を取っています。

2016 年 7 月より開発環境を OPenStack へ移行し、現在ではインスタンス数は 1730, Node 数は 34 まで増えたそうです。また、将来的には LXD の導入などを計画しているとのこと。

また、従来はネットワークとサーバの管理は担当エンジニアが分かれていましたが、それを統合し、 IT 基盤エンジニアがネットワーク、サーバどちらも担当できるようにしました。これによりネットワークグループへの「依頼」削減に成功したそうです。

DeNA のインフラに関する記事は こちらこちら など、 Mobage Developer blog にもあります。読み比べると、インフラ構成について理解が深まると思います。

他記事

DeNA TechCon 2017 を紹介した記事を探してみたところ、いくつかの Web ページが見つかりました。

セッションや会場の雰囲気が伝わってきますね。

最後に

DeNA TechCon 2017 に参加されたみなさま、ご来場ありがとうございました!

次回以降は、各セッションの様子をご紹介します。

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