新卒メンバー全員でシャッフルランチをつくり、PDCAサイクルを回してみました(後編)

2018年4月に入社した新卒エンジニアの堤です。前回に引き続き、入社後に新卒メンバー全員で初めて企画・開発した「シャッフルランチ」の取り組みについてご紹介します。

f:id:rettydev:20180925185708j:plain ▲2018年の新卒入社は総合職3名、エンジニア4名の計7名。職種を問わず新卒メンバー全員が参加する研修が2週間ほど行われました

1. シャッフルランチトライアル後のシステム改善

まずは、トライアルでのシャッフルランチ導入後の改善について。

主に、

  • 構成の刷新
  • シャッフルロジックの改良

についてお話します。

(1) 構成の刷新

前半でもお話しましたが、シャッフルランチの実施初期はGASを利用していました。ただ、運用していく上で大きく2点課題がみつかり、構成を刷新することになりました。 具体的には下記の2点です。

  1. GASがチーム開発に向かない
  2. Slackボタンが使えない

1について、GASが標準ではバージョン管理に対応していません。基本的にはWeb上のIDEからGASのソースコードを直接編集する形になります。この場合、

  • 複数人で開発するときに編集箇所が競合し、編集が適用されないなどの面倒が生じる可能性がある
  • バージョン管理がされないので、以前の状態に戻すことが難しい

という状況になります。 トライアル開発時は完全に分担しており、開発量も多くなかったので問題になりませんでしたが、運用にあたって加えたい機能が次々と出てきたため、このまま開発を続けることが難しくなりました。 ちなみに、GASとローカルを同期する機能は以下にまとめられているので、個人開発であればバージョン管理の問題は解決されそうです。

https://techblog.recruitjobs.net/development/maneged_google-apps-script_by_github

2つ目の課題は、Slackボタンが使えない点でした。 背景として、アンケートや出欠確認でSlackのボタンを使いたいよね、という話が上がっていました。ただ、Slackのボタンには3秒以内にレスポンスを返さないとTimeoutする仕様があり、GASだと3回に1回程度はTimeoutしてしまいました。 これに関してはGASを使っている以上はどうしようもないので、トライアル時にはボタンの利用を諦めました。 その他にも、GASのJavaScriptが古い(ECMA Script 5)だったり、動作時間に制限(1度に6分まで)があるなど、今後の運用を考えると移行したほうが良さそうだという話になりました。

以上の理由から、最初のトライアルを終えて2度目のトライアルまでに、主に新卒エンジニアの神(こう)と諏訪が以下の状態にお引越ししてくれました。

  • バックエンド
    • Botkit (Node.js)
  • 開発環境
    • GitLab CI
    • Rancher

BotkitはNode.jsによるbot作成フレームワークの一つで、Slack以外にも様々なChatBotを作成することができます(https://botkit.ai/)。 また、GitLabを立て、CIツールとしてGitLab CIを用いることで、Docker Image作成の自動化を図っています。GitLab CIについてはこちら(https://qiita.com/bremen/items/f47f383b9931a840a25c) に詳しく書かれています。 さらに、Rancherを利用することで、GitLab CIによって作成されたDocker ImageのデプロイをGUIから簡単に行えるようにしています(https://www.slideshare.net/recruitcojp/rancherrancher)。 これによって、

  • チーム開発のスピード向上
  • (レスポンス速度改善により)Slackのボタンが利用可能に
  • botフレームワークの利用により、bot機能の開発が楽に

が実現されました。

(2) シャッフルロジックの改良

トライアルを実施してみると、「よく話す人と同じグループになったためシャッフル感がない」「同じ部署の人と一緒になった」などという意見が散見されました。 今までは完全にランダムシャッフルを行ってグループを作っていましたが、「似ている社員が違うグループになるようにシャッフルしたほうがいいのではないか?」という話が上がりました。 そこで、社員の下記の属性を利用し、似た社員が同じグループになりにくいようなシャッフルを行うこととしました。

  • 社員属性
    • チーム
    • 職種
    • 性別
    • 勤続年数

要件はこちらです。

  1. 属性の似た社員が同じグループになりにくい
  2. メンバーは毎回異なるようにしたい

「属性の似た社員が同じグループになりにくい」ということで、確率を利用したロジックを用いることにします。今回は「焼きなまし法(Simulated Annealing)」1という方法を用いることにしました。 焼きなまし法組み合わせ最適化問題に対するアルゴリズムの一種で、巡回セールスマン問題(TSP)などを解決するときに利用されます。 今回は

  • 条件
    • 同一グループに属する社員同士の類似度をコストとする
  • 制約
    • 全体のコストを低下

と設定し、ロジックを作成しました。 ロジックの大まかな流れがこちらです。

  • 全体のコストが小さくなるように、以下のようにSwapをR(=2000)回程度繰り返す
    1. 別々のグループからランダムに2人選ぶ
    2. 2人を入れ替えたときのコスト変化を計算する
    3. コスト減少ならSwap、そうでなくても確率PでSwap

焼きなまし法では、こちらの「確率P」が徐々に下がっていくことで、最初はコストが増加するSwapも許容しつつ、だんだんコストが減少するSwapのみ許容に変化していき、最適な解に近づけていきます。 今回は「メンバーは毎回異なるようにしたい」という要件があったため、確率Pの値は割と高い値を保ったままにしています。そうでないと最適解に近い値を求めてしまい、毎回メンバーが固定されてしまうからです。 今回はこちらのロジックを採用することにより、属性の似た社員が同じグループに固まることを防ぎつつ、メンバーが毎回異なるようなシャッフルを実現できました。

補足
今回のコストは以下のように設定しています。
グループgのコストは以下のように定義する
- groupCost(g) := (baseCost(g) / groupSize(g) ** 2) ** 2
ただし、
- baseCost(g) := グループgに属するメンバー同士の類似度合計
- メンバー(a, b)の類似度 := sameJob(a, b) + sameTeam(a, b) * 2 + sameSex(a, b) + distHist(a, b)
- sameXXX(a, b) := XXXが同じなら1、そうでないなら0
- distHist(a, b) := 勤続年数が近いほど大きくなる値
このとき、全体のコストは各グループコストの合計である。

その他、出欠の自動化であったり、取得に時間のかかるSpreadSheetのCache作成など、課題が上がるごとに機能を追加していきました。 現在もシャッフルランチの運用をより良く、より楽にするために改善を重ねています。

2. 本格運用を開始

2018年4月に新卒でRettyに入社し、Webプランナーを担当している山田陸です。

新卒メンバーみんなで試行錯誤を重ね、トライアル期間に見つけた課題も解消し、7月より全社でシャッフルランチの本格運用を開始しました。 新たな課題が出る一方で、社内ではポジティブな変化もありました。

(1) 課題:参加率の低下

トライアル期間中は、出席者に直接声をかけることも行なっていたため多くの社員が参加してくれましたが、自動化するために出席確認をbotで送る仕組みに変えたところ、大幅に参加率が低下してしまいました。

原因は、シャッフルランチの目的やメリットが社内に浸透しきれていないことや、既に予定が入っていて参加できない人を含めて選定している点などが考えられます。 完全自動化からは少し離れてしまいますが、社内でのアナウンスなど、シャッフルランチが定着するための取り組みも行なっていこうと考えています。

(2) ポジティブな変化:社員同士の声のかけ合いやすさ向上

一度ランチをしたことで、その後も社内で声をかけやすくなったという声がありました。ランチを通じて、仕事だけでなくお互いのプライベートなども知れば、互いの距離はグッと縮まります。シャッフルランチをきっかけに、仕事でのコミュニケーションにもつながることを垣間見ることができたことは、非常に嬉しいです。

3. 今後のシャッフルランチについて

Rettyはこれからも事業の拡大に伴い、社員の数も増えていくことが予想されます。社員同士の交流は、会社全体が「チームRetty」として成果を生み出していく上で欠かせません。 社員同士の交流を活性化するためにも、シャッフルランチの改良を重ね、参加率を向上させていきたいと思います。

私たち新卒メンバーが企画した「シャッフルランチ」によって社内のコミュニケーションが活性化され、サービスやビジネスの成長に貢献できたら嬉しいです。

新卒メンバー全員でシャッフルランチをつくり、PDCAサイクルを回してみました(前編)

こんにちは、2018年4月に新卒でRettyに入社し、現在はプロダクト部門でWebプランナーを担当している山田陸です。

2018年の新卒入社は、総合職が私を含めて盛山、武藤、私の3名、エンジニア職が神(コウ)、諏訪、堤、山田(翔哉)、の4名、計7名います。今回は、新卒で入社した私たちが入社後に初めて企画・開発した「シャッフルランチ」について、メンバーを代表して私とエンジニアの堤からご紹介します。

f:id:rettydev:20180925184148j:plain ▲入社式の記念撮影(2018年4月、メッセージフラッグを囲む7名が新卒メンバー)

1.なぜシャッフルランチなのか?

(1) 研修中に得た気づき

今年の新卒入社研修は、職種を問わず新卒メンバー全員が参加する研修が2週間ほど行われました。同期間、私たちは毎日、話してみたい先輩社員に声をかけ、ランチに出かけていました。

それぞれのチームの仕事内容や雰囲気などについて、ざっくばらんに話を聞くことがランチの主な目的でしたが、先輩たちからは「以前よりも社員同士の交流が減っている気がする」といった声がありました。

社員数は100名を超え、部署の数も増え、顔を合わせる機会の少ないメンバーが増えていると感じていたようです。

成長と共に組織が拡大するベンチャー企業ではよくある話だと思い、当初はこの課題に対して私たち自身が何かするという発想はありませんでした。しかし、研修では「チームで動いてこそ、大きな成果を生み出すことができる」という話を繰り返し聞き、Rettyではいかにチームワークを重視しているかについて知ったことで、改めてこの課題に向き合うことを考えました。

(2) 課題解決方法の検討とシャッフルランチの決定

  入社して1週間が経過した4/9(月)の研修後に新卒メンバー全員で集まり、他社の事例なども参考にアイデアを出し合いました。そうして検討が始まったのが、他社でも導入事例が増えている「シャッフルランチ」です。グルメサービスを運営するRettyでは、「User Happy」なサービスを提供するために、まずは社員自身が「食」を楽しむことを大切にしています。部門や職種の垣根を超えた交流を活性化する方法としても、「食」に関わることの方が、Rettyらしいと思いました。また、「シャッフルランチ」であれば、2週間の研修期間の中でも企画・開発し、研修後もPDCAサイクルを回すことができそうだと判断しました。

早速、研修期間のランチで感じた課題や、それを解消したい旨を研修責任者に伝え、新卒メンバーのプロジェクトとして取り組むことが決定し、4/13(金)には全社員が集まる総会でも発表しました。

開発に向けて、まずはトライアルとしての運用フローを検討しました。私たちが考えたフローは、下記です。

  • 社内のコミュニケーションツールSlackに、シャッフルしたメンバーのチャンネルを自動で作成
  • 新卒メンバーが音頭を取りながらお店選び、予約などを実施
  • シャッフルメンバーでランチ
  • ランチ後にメンバーにアンケートを実施

まずは上記のフローでトライアルを実施し、シャッフルランチが上手くいきそうかどうかを検証することにしました。

2.シャッフルランチシステムの開発

新卒エンジニアの堤です。

ここからは、神(コウ)、諏訪、山田(翔哉)、堤の4名による新卒エンジニアチームで行った、シャッフルランチ導入までの取り組みを紹介します。

(1) 技術選定と役割分担

シャッフルランチを新卒プロジェクトとして決めたのが4/9(月)ですが、それを社内で発表しデモを動かすのを4/13(金)の総会の日に設定しました。 そのため作業期間は4日、しかも日中は研修のため、空き時間を使っての短い時間で作り上げる必要がありました。 そこで新卒エンジニア4人で相談し、サービスの仕様や構成、役割分担を決定し、各自進めていきました。

  • 仕様
    • 社員のランチ出欠をSpreadSheet上に保存しておく
    • 決まった日時に、ランチ参加社員をシャッフルしてグループを複数作成
    • Slackにてグループチャットを作成し、ランチを促す
    • Googleカレンダーにランチの予定を登録
  • 構成
  • 役割分担
    • DB連携機能
    • 環境構築・スケジューリング
    • Slack連携機能・Googleカレンダー連携機能
    • ランダムシャッフル

全社発表の日までにデモを実行できるまで作成し、5月の半ばに最初のバージョンを完成させてトライしました。

(2) 実際の動作

実際に作動させた場合、Slack上でグループを作成した後、このようにメッセージを投げてシャッフルランチを促します。 f:id:rettydev:20180925103139p:plain

(3) 構成について

今回は機能がシンプルなため、GAS + SpreadSheet(DB) + Slack(UI) とすることで、サーバを用意せず準備・運用の手間を省く構成としました。 GASとは、

Google Apps Script は、Googleが提供するサーバーサイド・スクリプト環境です1

GASの詳細は省きますが、簡単なWebアプリケーションや定期実行スクリプトJavaScriptで作成し、動作させることができます。 また、GASを利用するときにデータベースが必要な場合は、SpreadSheetが一緒に用いられます。GASからのアクセスが簡単で、かつSQLの知識がなくともデータベースを編集できるという利点があります。今回参加者リストを管理したのですが、新卒総合職もリストを編集・閲覧する必要があり、この利点が活きました。 また、UIとしてSlackを利用しています。理由として、

  • 社内で日常的にコミュニケーションツールとして利用されている
  • APIが充実している

ことが挙げられます。 Slack連携やこれら全体の連結は、新卒エンジニアの諏訪が行ってくれました。

(4) SpreadSheet連携

GASでSpreadSheetを利用するに当たって、表を配列として扱う必要があります。2 読み込み・書き込み時に配列への操作が必要となるため、例えば次のようなSheetがあった場合に、

id team user
0 営業 Shogo
1 App Yutaka
2 検索 Shiho
3 経理 Taro

3行目のuser列の値を取り出す操作は以下のようになります。

// シートを取得
var sheet = SpreadsheetApp.getActive().getSheetByName('sheet1');
// 3行目
var rowIndex = 3;
var colStartIndex = 2;
var rowNum = 1;
var colNum = 1;
var data1 = sheet.getRange(rowIndex, colStartIndex, rowNum, colNum).getValues();
// または
var sheetData = sheet.getValues();
var data2 = sheetData[rowIndex][colStartIndex];

ただ、これだと1行目のタイトル行の扱いが面倒だったり、数値での列指定のため列の追加に弱かったりします。そこで、新卒エンジニアの山田が以下のライブラリを作ってくれました。

https://5hyn3.github.io/posts/use-spreadsheets-from-gas-without-thinking-about-difficulties/

詳細はリンク先で書かれていますが、SpreadSheetの各行をオブジェクトとして扱えるようにし、上記の問題点を解決してくれました。また、updateやsave等のメソッド作成により、DBを扱うようにSpreadSheetを扱えるようになりました。

(5) サービスの運用と課題

最初のトライアル実施までに、念入りに新卒メンバーでテストしていたこともあり、無事社員をシャッフルしてランチに行くことができました。 ただ、いくつか足りないこと、やりたいことが数回のトライアル実施を通じて挙がってきました。次回の記事では、挙がった課題とその解決策についてお話します。

PyCon ThailandでGeoDjangoについて話してきました

こんにちは、Retty Global Team サーバーサイドエンジニアの omega (@equal_001) です。

PyCon Thailand参加に参加し、GeoDjangoについて話してきました。

PyCon Thailand

th.pycon.org

6/16, 6/17の二日間で開催されました。 今回が第一回目の開催で、参加者は200人程だったそうです。

現地の学生さんやTHAI PROGRAMMER というタイのプログラマコミュニティの方々も参加されていました。

話した内容

CFP: Powerful geographic web framework GeoDjango

docs.google.com

GeoDjangoというDjango地理空間情報を扱うための公式モジュールについて話しました。 Retty Global でもレストランの位置情報を扱う際に使用しています。

今回はBeginner向けの発表にしたのであまり深い話はしませんでしたが、当日の参加者でGeoDjangoを知る人が少なかったので発表後に良いフィードバックをいくつかいただけました。

感想

タイでもブロックチェーン, 機械学習系の発表が多めでした。 タイのプログラマ事情は日本にいるとなかなか耳にしないのですが、自国向けサービスがたくさんあり近年はスタートアップも増えてきているとのことです。

来年も開催するかもしれないとのことだったので、次回はDjangoを使った開発の知見などを発表したいと思います。

一緒にRetty 海外向けサービスの開発をしたい人を募集しています!

Retty Global Teamでは海外向けサービスの開発に興味のあるエンジニアを募集しています!

iOSエンジニア(Swift) | Retty株式会社

iOSDCでiOSアプリのリニューアルについて話をしてきました

RettyでiOSをメインに開発とかマネジメントをしているkosakoです。 先日iOSDC 短期間でやり遂げるための、 大規模リニューアルの進め方 というタイトルで話をしてきましたので、レポートとかネットでの反応に応えてみます。

f:id:rettydev:20170926145915j:plain

提出したCfPとスライド

Rettyでは2年半ぶりに大規模なリニューアルを行っています。 まだリリースはされていませんが、言語をObjective-cからswift4.0へ移行したり、アーキテクチャの刷新も短期間で行おうとしています。 やり遂げるためにどんなことをやっているのか、リニューアルなど大きな開発で起きる仕様の変更による手戻りの発生への対応、全員の共通認識をどうやって合わせてチームビルディングを行っていくかなどをお話します。

ネットの反応

概ね好評だったようでよかったです。 サグラダファミリアと一日8時間コードがかけると思っているは結構うけたようでよかったです。

Design Docや自前のHIGなどへの取り組みも興味を持っていただけたようです。

テストについて

  • QAさんによるテストやテスト仕様書の話をしなかったので、自動テストだけでいくと思われてたかもしれません
  • 仕様書とテスト仕様書はちゃんと作って、継続的な運用にしていく予定です

感想

会場がすごく広くて、自分が発表したA会場は500人ぐらいはいるかなり大きな会場でした。 4会場あって、様々な発表があり視点が広がって非常に楽しい時間でした。 リニューアル関係の話も結構あって、いろんな会社がいろんな取り組みをしているのが興味深かったです。

来年はリニューアルしたアプリでの具体的な成果を発表できたらと思っています。

最後に。今年はストラップスポンサーとしても参加していました。 今年のオープニングは三石 琴乃さんによる某アニメ風になっております。弊社も読み上げられていますので見てみてください。

カラムナフォーマットのきほん 〜データウェアハウスを支える技術〜

こんにちは、Retty.Inc ソフトウェアエンジニア兼データサイエンティストのchie(@chie8842)です。 好きなたべものは焼肉とみかんです。

現在Rettyでは、次世代分析基盤を構築しています。Rettyでは、サービス拡大に伴いログの急増や分析需要の拡大が見込まれるため、高いスループットとコストパフォーマンスを両立する、スケールするアーキテクチャ設計が求められています。

今回は、こうしたスケールするアーキテクチャ設計の実現のために理解しておくべきDWHのコア技術の一つである、カラムナフォーマットに焦点を当てて紹介します。

はじめに - カラムナフォーマットとは

カラムナフォーマットとは、データベースの分析用途に利用されるファイルフォーマットの種類の一つです。大量のデータを扱う際に効率的に圧縮してストレージコストを下げたり、計算時に必要なデータだけを取り出して計算コストを小さくできる設計がされています。
本稿では、分析基盤で利用されるファイルフォーマットの概要を紹介し、 そのあとに、カラムナフォーマットにおける符号化方式、データモデル、ファイルフォーマットについて説明しようと思います。

分析基盤で利用されるフォーマット

最近は分析基盤用途として、Hive、Presto、Sparkといった並列分散処理プロダクトやそれらのマネージドシステムであるAmazonのEMRやAthena、GCPのDataProc、そしてフルマネージドなBigQueryやRedShiftが利用されるようになりました。

これらのプロダクトで取り扱えるフォーマットは、大きく以下3つに分けることができます。

  • テキストフォーマット(例:CSVJSON
  • 行指向フォーマット(例:AVRO)
  • 列指向(カラムナ)フォーマット(例:Parquet、ORC)1

CSVJSONといったテキストフォーマットは、人間からの可視性が高い、アプリケーション連携がやりやすいというメリットがあります。しかしながら、データベース用途のフォーマットとしては、人間からの可視性よりも、保存時の圧縮効率や機械による処理のしやすさを追求する必要があります。データベース用途に向いているフォーマットの種類としては、行指向フォーマットと列指向フォーマットがあります。
行指向フォーマットと列指向フォーマットの違いは、データの格納方式です。
行指向フォーマットは、行方向に連続してデータを格納するため、一つの行をまとめて操作することの多いOLTP処理に向いています。従来のデータベースはもともとこの行指向フォーマットが利用されてきました。
ストレージ技術などの発展により、DWH用途での利用を行うようになって、注目されるようになったのが列指向フォーマットです。列指向フォーマットは、列方向に連続してデータを格納する方式で、列単位でデータを取り出す分析用途に向いています。

主要なOSSのカラムナフォーマットのライブラリとしては、ParquetとORCがあります。
ParquetはTwitter社とCloudera社が、2010年のGoogleの論文Dremel: Interactive Analysis of Web-Scale Datasets(以下Dremel Paper)におけるデータレイアウトに関する内容をOSS実装したもので、ORCはもとはApache Hiveのためのフォーマットとして実装されたという背景の違いがあります。

カラムナフォーマットにおける符号化方式の基礎

カラムナフォーマットでは、データ型やカーディナリティ等の特性に応じて、様々な符号化方式から決定木等によって各列に最適なエンコード方式を選択します。これらの符号化技術自体は、行指向フォーマットでも利用されるものですが、カラムナフォーマットでは、型が同じデータが並んだり、規則的にインクリメントするデータが並ぶなど、符号化によるデータ圧縮が効きやすいというメリットがあります。

ここで符号化方式の一部を紹介します。

Null Suppression

これは、nullの多い列の圧縮に大きく寄与する技術です。nullの値を埋め込む代わりに、どこにいくつnullが存在するかの情報を保持することで、データサイズを小さくします。

Dictionary Encoding

以下の図のように、辞書情報を作成して、その辞書情報を利用して符号化する方式です。
データのカーディナリティの低いString形式のデータに有効ですが、データのカーディナリティが高くなると、辞書情報が肥大化して圧縮率は低くなります。 スクリーンショット 2017-06-05 2.25.22.png

Run-Length Encoding(RLE)

RLEは、繰り返しが続くデータに対して、下図のように繰り返し項目をまとめて保存する方法です。
繰り返しの長さが長くなるほど、圧縮率が高くなる特徴があります。
スクリーンショット 2017-06-05 2.24.41.png

Delta Encoding

Delta EncodingはTimestamp型などのインクリメンタルなデータで効果的なエンコード方式です。
Delta Encodingでは、まず最初に参照値を決め、それ以外の値をブロックに分けます。
それぞれのデータにおいて、一つ左隣の値との差分をとります。
この値の最も小さい値を使って標準化し、最後にビット数に直します。
図の例だと、最初の112bitから40bitと、3分の1程度に圧縮されていますが、データ量が多くなるほど圧縮率が高くなります。^2 スクリーンショット 2017-06-05 2.28.10.png

Bit-Vector Encoding

Bit-Vector Encodingは、Boolean型などの限られた値をとるデータに用いるエンコード方式です。
ある値と合致するかどうかを1と0で表したものを保持します。データのカーディナリティが著しく低い場合に有効です。
スクリーンショット 2017-06-05 2.34.59.png

Dremelのデータモデル

次に、BigQueryやParquetで実装されている、Dremelのデータモデルについて紹介します。
カラムナフォーマットについて書かれた論文に、GoogleのDremel Paperがあります。BigQueryはこのDremelの外部公開版であり、また、Parquetもこの論文をOSS実装したものです。
Dremelの新規性として、ネストされたデータに対応できる柔軟なデータモデルが挙げられます。下図(Dremel PaperのFigure1を引用)の左のように、record orientedな方式では、ネストされた型や特性の異なるデータが、並ぶ形となり、上記で述べたエンコードの効果を受けにくく、またネストされた一部のフィールドを利用する際にも、不必要なフィールドも含めてデコードする必要があります。対して右のcolumn orientedな方式では、同じフィールドのデータをまとめて保存でき、ネストされたデータの一部を利用する際には、木構造をたどることで必要なフィールドのみを抽出することができます。

スクリーンショット 2017-06-05 2.49.04.png

しかし、1つの行に何回同じフィールドが出現するかわからないようなrepetableなデータを扱う場合、そのデータ構造を欠落させることなく小さいオーバヘッドで木構造のデータを保持するための工夫が必要となります。
Dremelでは、下図(Dremel PaperのFigure2,3を引用)のように、反復レベル(Figure3の表におけるr列)と定義レベル(Figure3におけるd列)をもつことで、データ構造を復元できるようにしています。
スクリーンショット 2017-06-05 2.49.18.png 反復レベルと定義レベルの説明は以下のとおりです。

  • 反復レベル
    • あるレコードにおいてそのフィールドが初めて出現する場合は0とする
    • 2つ目以降については、親フィールド配下での反復回数を表す
  • 定義レベル
    • 一意でないフィールドの階層を表す

BigQueryでは、repetableなデータで構成されるデータを対象とした分析を行う場合などにこのデータモデルによるクエリ速度向上が見込まれます。

ただし、私個人の意見としては、Parquetの場合はクエリエンジン側がこのようなデータモデルに対応したものである必要があることもあり、現状でこのデータモデルの恩恵が生かされている例は少ないのではないかと考えています。

ファイルフォーマット

ParquetやORCでは、分散処理を行うことを前提として、Encoding/Compressionの単位、IOの単位、MapReduceの単位で処理しやすいようにデータが分割配置の工夫がされています。
以下の図はParquetのファイルフォーマットの説明図です。
スクリーンショット 2017-06-05 2.51.28.png File/Row Group/Column/Pageといった単位でデータを分割配置されていることがわかります。
また、上記の分割単位ごとに、ヘッダ/フッタにメタ情報を持っています。メタ情報の内容としては、

  • レコード数
  • データの最大値/最小値
  • メモリに展開した際のサイズ

などがあげられます。
メタデータを利用することで、データを読み込む際に、必要のないデータを読み飛ばすことができます。たとえば、

SELECT tbl1.colA, tbl2.colB FROM tbl1 JOIN tbl2 ON tbl1.colA == tbl2.colA;

といったクエリの場合、最終的に必要となるのは、tbl1のcolA、tbl2のcolAとcolBだけとなります。ParquetやORCを利用すると、ファイルスキャンの段階で、これらの必要なデータのみを抽出することが可能になります。
ただし、メタデータによる最適化が利用されるかどうかはクエリエンジンのオプティマイザによって作られる実行プランに依存します。

分析基盤におけるフォーマットの選定について

ここまでカラムナフォーマットのアーキテクチャと分析基盤における有効性についてざっくり説明しました。
上述したとおり、カラムナフォーマットにはクエリパフォーマンスをあげるための仕掛けが施されています。ただし、フォーマットはあくまで最適化しやすいデータ形式であって、それらを活かし切るかどうかは実際に処理を行うクエリエンジン側に依存します。
データの特性や利用するプロダクト、実行するクエリパターンによって、フォーマットを適切に使い分けることができるとよいと考えます。

まとめ

以上、目新しい技術というわけではないですが、分析基盤の縁の下の力持ち的なカラムナフォーマットの技術について、淡々と述べてみました。

尚、本稿の内容については、5/18のBIGDATA-JAWSにて、「カラムナフォーマットのきほん」というタイトルで発表をさせていただきました。

speakerdeck.com

Rettyでは、DWH技術を学びたい技術者を募集しています。
www.wantedly.com よろしくお願いいたします!

参考資料


  1. BigQueryとRedShiftも内部的にカラムナフォーマットが用いられている。

How to make a machine learning infrastructure that supports 22 million users

Original article (日本語): http://qiita.com/taru0216/items/dda1f9f11397f811e98a

Retty “How to make a machine learning infrastructure that supports 22 million users”

f:id:rettydev:20170530150841p:plain

Hello, everyone. My name is Taruishi, and I’m the CTO at Retty.

There’s not much time left until the year is over. Have you already decided how you’ll spend the rest of the year?

The number of engineers at Retty have nearly doubled in the past year. As a result, we have enough people to who can write articles which allows us to participate in this year’s Advent Calendar. I’m pleased to see that everyone seems to be having fun doing it.

http://qiita.com/advent-calendar/2016/retty

For the final post for this year’s Retty Advent Calendar I had considered writing about what I did over this past year at Retty, but that’s not very unique or interesting. Instead, I decided to write about something fairly crazy that I did this year.

That is, “Building Retty’s machine learning infrastructure using parts purchased while walking around Akihabara”.

※ This is not a post about machine learning techniques or history. If that’s what you’re looking for, then I recommend checking out Rakuten Institute of Technology’s Mori’s Advent Calendar (日本語) or check out this summary (日本語) and start reading from there.
※ This post has a lot of logos and images to make it easier to read. The names of all software, products, companies, stores, and their logos, are copyrighted by their respective owners.
※ This article was written with the intent of being as accurate as possible, but no guarantees can be made.

Overview of Retty’s machine learning infrastructure system architecture

First, I would like to explain the architecture of Retty’s machine learning infrastructure.

We have 5 ATX-sized machines running on Intel processors, all equipped with 2 consumer-grade NVIDIA GPUs.

f:id:rettydev:20170530151144p:plain

All machines are running a Docker container with SSH enabled. The GPU can be used by logging into any of the machines. The home directory of the Docker container is shared through NFS so you have access to the same data no matter what machine you are using.

From the machine learning engineer’s point of view, all 10 GPUs are part of a “preemptible container1 where you can access the same files no matter where you are logged in”.

Examples of techniques developed using Retty’s machine learning infrastructure

I’d like to introduce some of the stuff that has been developed using Retty’s machine learning infrastructure now.

Image Categorization

A classic machine learning problem. At Retty, we separate images into 4 different categories: “food”, “restaurant exterior”, “restaurant interior”, and “menu”.

f:id:rettydev:20170530151348p:plain

Source: https://retty.me/area/PRE13/ARE14/SUB1401/100001178822/photos/ (日本語)

This was all done manually until we were able to come up with a CNN model that produced results accurate enough for us to be able to put it into production.

Tagging Food Pictures

Using image categorization, we were able to create techniques to tag what kind of food is displayed in a picture. As you can see below, the image tagged “pancake” is automatically being chosen to represent the restaurant in the search results.

Before

Search keyword: Pancake

After

Search keyword: Pancake

Source: https://retty.me/area/PRE01/ARE164/LCAT9/CAT161/ (日本語)

Previously only one pre-selected image would be displayed to represent the restaurant in the search results. But, using the above “Omurice and Pancakes” restaurant as an example, some restaurants are known for more than just one type of food. In this case, since the omurice picture would normally be displayed, users searching for pancakes would end up seeing omurice instead.

Using the image tagging technique, we are now able to show omurice to people searching for omurice, and pancakes to users who are searching for pancakes.

Super Resolution (Making images clearer)

Super resolution is the process of making an image a higher resolution and then converting it into an even clearer picture.

Up until recently it was common to filter the image based on edge enhancement, but in recent years it’s there has been great development of techniques using deep learning to create super resolution images.

We also tried our hand at using deep learning to create super resolution images here at Retty.

f:id:rettydev:20170530151508p:plain

(Image from restaurant: https://retty.me/area/PRE13/ARE1/SUB101/100000868744/ (日本語))

It might be difficult to tell the difference between the two methods from just the side by side embedded image, so let’s take a closer look.

f:id:rettydev:20170530151624p:plain

f:id:rettydev:20170530151627p:plain

※ This technique could possibly be used to improve the compression ratio of lossy images. I think it’s worth keeping an eye on.

In addition, we’ve had several people develop about 30 new techniques to solve such problems as extracting unique characteristics about a restaurant based on user reviews (日本語) and detecting high quality images that look like they were taken with a DSLR camera (日本語). When I say new techniques, I mostly mean it in the way that that it takes our company some time to get caught up with all of the new papers coming out.

Machine learning web apps have also been developed to make it easier for non-machine learning engineers to take advantage of the new techniques.

f:id:rettydev:20170530151706p:plain

They are lovingly known as ICACHAN (for image classification), MICANCNN (for image modification), and TACOCNN (for natural language processing).

6 reasons we built the machine learning infrastructure ourselves

Retty has run its service on AWS from launch all the way up until last year. Starting with this year, we have started using other cloud services such as Google’s BigQuery and Microsoft’s Azure, but we hadn’t attempted anything outside of the cloud.

There are reasons why I decided that it was a good idea for Retty to build its own infrastructure with parts we bought ourselves.

  • A GPU is required for deep learning
  • Our deep learning engineers had sticker shock after seeing the price of cloud instances with GPUs
  • Since there was little information available about the efficiency of the GPUs, it was hard to tell how much it would cost to use for machine learning
  • Our engineers got too caught up in trying to figure out what instance would perform the best for a given algorithm based various bottlenecks that may be present such as CPU, GPU, memory, IO, or network, which meant less time spent working on the actual machine learning tasks
  • Since we would be SSHing into the machines for development work, the latency between the cloud service and our office did not help with productivity
  • Since the price of GPUs get cheaper by the month, I thought maybe it would be possible to build a low cost system by buying only the parts required at the time they were needed

There were various reasons why I chose to build our own system in addition to those already listed above, but if I had to choose one reason in particular, it would be that we wanted to create an environment that the engineers could freely use at any moment. Now, with the creation of our own system, there is always at least 1 person using the GPUs at any given time of the day.

How the machine learning infrastructure was implemented

When designing our system, requirements for future development had to be taken into consideration.

  • A system that could easily be improved and scale to the current demands
  • The data and environment should be prepared in such a way that machine learning tasks can be started immediately without issue
  • When the machines are reinstalled each iteration, the engineers’ data should still remain untouched
  • In order to get the best return on our investment and increase the amount of techniques available to us, another goal was to use the cheapest parts and to use open source software and techniques

After iterating through PDCA many times, our architecture ended up looking like this.

f:id:rettydev:20170530152137p:plain

  • juju for configuration management
  • MaaS for automatic OS deployment and AWS spot instancing
  • ceph for distributed storage system
  • corosync/pacemaker for the NFS cluster
  • A Docker image including all software required for machine learning
  • Kubernetes for VXLAN management and Docker container scheduling

juju for configuration management

juju is an infrastructure configuration management tool. There are other similar tools out there like Ansible, Chef, and Puppet. juju is available as a standard tool within Ubuntu and can be instance bootstrapped which works very well with the previously mentioned MaaS software, and is also easy to scale. For example, you can add 48 machine learning machines using the following command2:

juju add-unit -n48 akiba

※This is just my personal opinion, but I think that juju is much more easier to use than other similar tools. The approach in regards to ease of use might just be the way of Debian-based distributions, similar to apt.

Retty’s machine learning infrastructure makes heavy use of Docker (Kubernetes). Since a large majority of the management is being done through Docker, juju is being used when creating the Docker (Kubernetes) environment.

MaaS for automatic OS deployment and AWS spot instancing

MaaS is an OS deployment system that is capable of automatically installing an OS from a bare metal environment. Using PXE booting, it’s possible to automatically install Ubuntu on top of the bare hardware. It a fully featured system that has other features such as software RAID and bonding. We use MaaS on our custom built machine learning cluster.

juju can also be used with not just MaaS, but also cloud services such as AWS, Azure, and GCP. When more GPU power is required than is available within our cluster, we scale using the cloud’s spot resource3.

ceph for distributed storage system

f:id:rettydev:20170530152251p:plain

ceph is a distributed storage system that allows for one virtual storage system over the network to be used across multiple servers. A common use for ceph is as a distributed block device, which is also how we’re using it in the Retty machine learning infrastructure.

(We’ve also started using the recently released stable version of cephfs lately.)

corosync/pacemaker for the NFS cluster

Source: http://clusterlabs.org/

In order to create a NFS server that does remains running during machine maintenance, ceph acts as the block device while corosync and pacemaker are used to create a single master and failover NFS server.

A Docker image including all software required for machine learning

In addition to tensorflow and chainer, we require other libraries like genism, mecab (日本語), cabocha (日本語), word2vec, fastText, keras, etc. To ease the pain of having to install all of the required libraries, we’ve created a Docker image that can automatically install everything. As long as NVIDIA drivers are installed on the host machine, you can run a command such as

docker run --privileged -it --rm 192.168.0.1/retty-runtime-anaconda

and it will set up a machine learning environment just like that. Since the Docker image is 10gb (5gb compressed), we use a Private Docker Registry on our servers and pull the image directly from there. What used to take about 70 minutes to complete now takes a mere 5 minutes.

(Since the machine learning Docker image can also work in a CPU-only environment, it’s possible to do this all from a Mac as well.)

Kubernetes for VXLAN management and Docker container scheduling

Kubernetes uses the SSH-enabled Docker images to run on each individual machine. It is running through a simple VXLAN virtual network created with flannel. Home Docker is running on all of the host machines, so the machine learning engineers are able to log into any machine. The home directory is setup using the previously mentioned NFS server with failover enabled. This setup allows the engineers to have the same files no matter what machine they are using at the time.

There is also Docker running within Kubernetes. This allows the machine learning engineers to easily run simple Docker features through the command line, such as docker-compose.

The techniques behind the Retty machine learning infrastructure

In order to increase performance and productivity, various techniques are in place for the Retty machine learning infrastructure.

Disk Performance

All machines have 6 separate SSDs, bringing us to a total of 30 SSDs being used to create a distributed storage system. Using iotop to measure performance and ceph to rebalance the data (data management), 1 node can reach a max throughput of up to 450 MB/s (3.6Gbps). I think there’s still more room for improvement, but for now it’s good enough for our purposes.

I should also point out that the motherboard that we use in our machines (z170 chipset) has only 6 SATA ports. Since all 6 ports are dedicated to ceph, the systems are booted using an SSD connected using a SATA to USB adapter. Therefore, there are 7 drives used per 1 node. The reasoning for this is to make better use of ceph’s block device, and also because we had the need to add more disk space.

Network Performance

In addition to the internal ethernet board we are bonding 3 dual port gigabit ethernet PCIe devices. We originally wanted to use a cheap fanless L2 switch, so we use Adaptive Load Balancing instead of link aggregation to distribute traffic.

There are a lot more ethernet cables than there are machines, as you can see from the above picture.

GPU Benchmarks

Since we are in possession of various GPUs that can run tensorflow and chainer, we took benchmarks throughout development. We had a few cards that ran on the Maxwell architecture (GTX 750ti, 970, 980ti) and a majority of the cards that ran on the Pascal architecture (GTX 1050ti, 1060, 1070, 1080). What we found out is that the performance, power efficiency, and cost performance of each card changed depending on the algorithm being used.

Here are some of our findings. This data was collected at varying points in time which unfortunately means we weren’t able to measure performance within the same environments, so it’s a little difficult to draw direct comparisons.

Speed

We measured how many seconds it took to process a given amount of data (the meaning of batch changes per algorithm, so we chose process / sec out of convenience). The results of two algorithms, train.py and char_cnn.py, when run on all available GPUs is shown below. A larger value means more data being processed (better). As expected, the performance increases with more power GPUs. However, there’s an odd case with train.py running much faster on the GTX 980ti.

f:id:rettydev:20170530152833p:plain

In comparison, char_cnn.py actually runs slower on the GTX 980ti. At the time of benchmarking, the GTX 980ti was running in a machine with a cheap AMD CPU. We believe that char_cnn.py is a CPU sensitive algorithm which could explain the large difference. One thing that has me scratching my head is that while train.py seemed to have the best performance on the AMD CPU in general, char_cnn.py did not have any real change in performance using the 750ti. We’re recruiting (日本語) anyone who is interested in digging deeper into this mystery.

Energy Efficiency

Next up we measured energy efficiency. Measured as QPS (process / sec) / W.

f:id:rettydev:20170530152848p:plain

The Pascal architecture in general had pretty good energy efficiency when compared to the Maxwell’s 970, but the GTX 750ti was a very pleasant surprise considering it does not require any additional power.

Cost Performance

This was calculated based on the price of the GPU as of early October 2016 and the energy consumption subtracted from that price. One yen per iteration. Since the prices of the cards change so much, I don’t think this is a very helpful benchmark.

3c49c1b6-017f-94f4-27aa-d112f09b4811.png f:id:rettydev:20170530152901p:plain

Energy consumption was measured using an off-the-shelf power meter.

Other

One thing that I should note is that the energy efficiency of the Pascal architecture has improved. The Maxwell architecture required a lot of energy, but that problem was fixed with Pascal.

As for the cost performance statistic, it all really depends on the timing of when you calculate the numbers because of how quickly the prices of GPUs can drop. For example, the 980ti dropped in price by half after 5 months.

With the way development of GPUs is currently going, products are going to the outlet bin and dropping prices fairly quickly. That’s why we decided it was best buy little by little in order to mitigate potential loss from fluctuating prices. It makes me wonder how SaaS providers who share GPUs deal with that issue.

And lastly, since our server architecture is mostly decided now, I believe it’s time for us to do some proper benchmarking. There’s functionality in place to scale using the cloud, so it’s possible to compare how consumer grade GPUs do against server grade GPUs as well. If that sounds like something that interests you then please subscribe to the Retty Advent Calendar or come check us out (日本語). You don’t have to be a student either, we’re open to everyone.

http://qiita.com/advent-calendar/2016/ranking/subscriptions/categories/company

Personal Database

Data is required for machine learning. Lots of data. At Retty, we have a massive database consisting of millions of user reviews and even more food-related pictures as well as other related information that we are able to use publicly.

To make it as smooth as possible to experiment with, we thought it would be convenient to use that database as a base for a personal database that you can tweak as you see fit. But, due to the massive size of the database, building such a thing is not an easy task. Restoring an AWS RDS database snapshot for use as a personal database ended up taking almost half a day to finish, which isn’t very realistic for real world purposes.

The Retty machine learning infrastructure takes advantage of ceph’s block device snapshot and cloning functionalities. What took up to half a day, now only took 3 seconds4. That’s roughly 12,000 times faster. To put it into a more conventional comparison, that’s fast enough to escape Earth’s gravity. The world sure has changed5.

Snags along the way

There were issues with our servers crashing completely. The biggest two reasons are as follows.

A DoS attack on CIFS

We were using an cheap off-the-shelf NAS to store images when we first built the machine. NAS was not able to handle all of the requests from the machine learning machine, which caused the CIFS file system kernel module to act up and causing all of the machine learning machines to spit out a Linux kernel oops. Since we couldn’t hook up a monitor to the machine it proved difficult to debug, but we were able to investigate it once we installed kdump. The problem was solved by moving on from CIFS and switching to NFS.

Only 1 network segment

Currently, all of our machine learning servers are hooked up to the same 24 port fanless hub. Sometimes there was just so many broadcast packets that the L2 segment became unresponsive (this happened about 2 times in half a year). At this point 2 times doesn’t seem like a huge deal to us, but it’s something we might fix in the future.

Although it’s not exactly a good thing when looked at from a SPOF point-of-view, including the physical network and power to the office, when the server does happen to go down, we all take advantage of the lunch taxi (日本語) or all-expenses-paid meal (日本語) perks to go out and enjoy a nice meal. You could say that the SPOF helps strengthen communication in a ways, so it’s not completely bad.

Retty’s machine learning infrastructure’s development environment

The infrastructure went through many improvements at the beginning while it was it was being made available to others. There was only one person to make use of it at the beginning and worked reasonably well. Eventually the infrastructure grew into a cluster and another person also started using the systems, which proved difficult to make improvements smoothly. For that reason, a development environment for the machine learning infrastructure itself was born.

f:id:rettydev:20170530150841p:plain

This environment uses a virtual machine that can do everything including the automatic OS deployment. It uses VT-d to share the GPU with the specified virtual machines. It’s not possible to use the GPU with just a certain virtual machine which makes this machine restrictive for development that requires GPU usage.

Virtual Machine Creation

We’re using libvirt to handle the management of virtual machines. The biggest plus is that it’s easy to manage virtual machines through the command line, and since it’s made by RedHat it’s able to run well on many Linux distributions.

The virtual machine’s primary disk is running off the machine learning infrastructure’s ceph drive. ceph had problems when installing the virtual machines using the virt-install command, so we added some new code to it.

※ Since virt-install is licensed under GPL, the following patch code is also licensed under GPL

diff -ru /usr/share/virt-manager/virtinst/devicedisk.py /usr/local/share/virt-manager/virtinst/devicedisk.py
--- /usr/share/virt-manager/virtinst/devicedisk.py      2015-11-30 20:47:47.000000000 +0000
+++ /usr/local/share/virt-manager/virtinst/devicedisk.py        2016-11-09 05:12:36.513295726 +0000
@@ -464,6 +464,7 @@
         "source_volume", "source_pool", "source_protocol", "source_name",
         "source_host_name", "source_host_port",
         "source_host_transport", "source_host_socket",
+        "auth_username", "auth_secret_type", "auth_secret_uuid",
         "target", "bus",
     ]
 
@@ -744,6 +745,9 @@
 
     seclabel = XMLChildProperty(Seclabel, relative_xpath="./source")
 
+    auth_username = XMLProperty("./auth/@username")
+    auth_secret_type = XMLProperty("./auth/secret/@type")
+    auth_secret_uuid = XMLProperty("./auth/secret/@uuid")
 
     #################################
     # Validation assistance methods #
@@ -867,6 +871,12 @@
         self._change_backend(None, vol_object, parent_pool)
 
     def set_defaults(self, guest):
+        pool = self._storage_backend.get_parent_pool_xml()
+        if pool.source_auth_type != "":
+            self.auth_username = pool.source_auth_username
+            self.auth_secret_type = pool.source_auth_type
+            self.auth_secret_uuid = pool.source_auth_secret_uuid
+
         if self.is_cdrom():
             self.read_only = True
 
diff -ru /usr/share/virt-manager/virtinst/storage.py /usr/local/share/virt-manager/virtinst/storage.py
--- /usr/share/virt-manager/virtinst/storage.py 2015-12-24 16:30:15.000000000 +0000
+++ /usr/local/share/virt-manager/virtinst/storage.py   2016-11-05 04:29:29.270748502 +0000
@@ -380,7 +380,10 @@
                        "capacity", "allocation", "available",
                        "format", "hosts",
                        "_source_dir", "_source_adapter", "_source_device",
-                       "source_name", "target_path",
+                       "source_name",
+                       "source_auth_type", "source_auth_username",
+                       "source_auth_secret_uuid",
+                       "target_path",
                        "permissions"]
 
 
@@ -406,6 +409,10 @@
                               default_cb=_default_source_name,
                               doc=_("Name of the Volume Group"))
 
+    source_auth_type = XMLProperty("./source/auth/@type")
+    source_auth_username = XMLProperty("./source/auth/@username")
+    source_auth_secret_uuid = XMLProperty("./source/auth/secret/@uuid")
+
     target_path = XMLProperty("./target/path",
                               default_cb=_get_default_target_path)

Using the patch above, it’s possible to specify in the command line arguments a way to allocate the virtual machine’s primary disk on the ceph block device.

virt-install --name=hoge --vcpus=4 --memory=4096 --disk rbd:hoge/fuga ...

Usage as Desktop

This development machine has been turned into a desktop that shows information about the machines. We call it the “Retty Machine Learning Infrastructure Dashboard”. Using the development machine’s GPU, we display the current system information for all of the machines in the infrastructure using a 50 inch 4K monitor.

There’s also an HDMI splitter available that lets engineers have their own view of the dashboard as well.

We thought it would be a waste if that’s all we used it for, though. So the computer has also been turned into a machine that anyone in the office is able to do development directly using the machine or test their own code on it.

This machine has 128GB of memory. It’s also connected directly to all of the machines using a 3Gbps shared bus (3 port ethernet), so it’s acting as if it’s all one machine.

In other words, Retty has a desktop machine with a combined total of 448GB of memory. Since memory is directly related to development capabilities, it’s a good time to be alive. In addition, the 12 GPUs give this desktop machine over 20,000 cores to work with. If this is something you’d like to try out then please check out or post here (日本語).

Summary

Thank you for reading this post.

The Retty machine learning infrastructure has become a desktop machine with 20,000 GPU cores, nearly 500 GB of memory that our engineers can use at any time and scale in the cloud like an amoeba as needed.

I started this project thinking “Just what is a GPU anyway?”. I went through many iterations with the restrictions of buying the cheapest parts available at the local stores, and using open source software and techniques for the software-side of things. The creation of the machine learning infrastructure has lead to the discovery of new server side techniques that can be applied even outside of the infrastructure. Retty also started participating in the open source community.

Having lining up at 5am in my university days at the electronics store to buy a 980 yen VHS player limited to the first customer only, to also successfully living off 800 yen worth of gas a month (日本語), I would like to think that the low cost development has been a great success. (At that price, it’d even be possible to make one server per engineer.)

And at the same time Retty’s earnings have greatly grown which has lead to an increase in the technology budget. Next year we will finally be able to make great progress on the tech side. These benefits will flow back to the engineers, the power behind the technology, further strengthening the investment.

To anyone into machine learning that wants to sink their teeth into a big data-capable desktop machine with 500 GB of memory, and to server-side engineers who would like to innovate with a machine learning infrastructure that can scale like an amoeba using the cloud: following Retty’s vision of “making the world happier, one meal at a time”, we plan to kick new development into full throttle.

Thank you for reading until the very end. Although I got really technical here, I hope this post is a Christmas present for all of the young people out there that aspire to learn machine learning. And I would also be happy if this post made you interested at all in our company. In that case, check this page out next. Thank you very much, and have a good rest of the year.

Bonus

Our PC gamer engineer Yuta building the first machine

Opened

Finished

Everyone disappointed after losing the lottery drawing for the GTX 1080


  1. Since any machine can go down for maintenance and undergo changes, the idea behind this is to say that all of the files are shared between machines, so you should always make sure to create checkpoints and have functionality to restore on any other machine. It might sound like a rough way of doing things, but when done correctly it provides a low cost way to speed up innovation. Please check out the following article: https://cloudplatform.googleblog.com/2015/05/Introducing-Preemptible-VMs-a-new-class-of-compute-available-at-70-off-standard-pricing.html

  2. akiba is what we call the Retty machine learning infrastructure.

  3. For example, a g2.2xlarge spot instance in the AWS Tokyo region is roughly $0.15/h as of 2016/12/20.

  4. Since the kernel module handling ceph block devices does not support snapshots for cloned block devices, we make use of a personal database stored in a VM to do what we want.

  5. Having previously worked at a cloud-native company before joining Retty, the latest techniques in the field of infrastructure technologies felt like a completely different world to me. However, I came to realize that applying various available techniques and tweaking them to perfection lead to a significant impact on operations. So, from now on it’s my goal to try applying the latest techniques whenever possible in the future in an effort to increase operation speed even more.

Retty裏入社式2017を行いました!

みなさん、こんにちは。 新卒エンジニアとして4月から入社しました新卒エンジニアの田松、竹野、Brenton(ブレントン)です。 今回はRettyの伝統行事になりつつある「裏入社式」というものについて紹介します。

f:id:rettydev:20170522164423j:plain

Retty裏入社式とは

裏入社式と聞いてピンと来ない方も多くいらっしゃると思いますが、決して怪しいことをしている訳ではありません(笑) Retty裏入社式とは、2016年の新卒が企画し実行したことが始まりとなった行事で、新卒全員で社員を巻き込む行事を企画、運営し、実際に行っているものとなります。 去年の裏入社式の様子はこちらに記事が挙がっています。

今年はこんな新卒が入ってきたんだよ!と全社を巻き込む最初の機会であり、入社後の新卒同士、他社員との繋がり強化や、伝統作りとして今年も開催させて頂きました。また、入社式で社員さんに祝ってもらった僕たちが今度は社員さんに恩返しという意味も込めて楽しい行事を考えてみました。

今年の裏入社式のテーマ

さて、今年の裏入社式ですが新卒の総合職が企画を考案し、今年の新卒にはエンジニアがいるので、その企画に合わせて僕たちエンジニアがサービスを一つ作らせて頂きました。

今年のテーマは「修学旅行」です。 社会人の僕たちが学生の頃を思い出せるような内容を企画組が考えてくれました。修学旅行と聞くと誰でもワクワクしますよね!

開発したサービスは、人から探すマップです。Rettyの強みである実名制という性質を使って、信頼できるあの人が実際に行ってオススメしているお店を地図上から探すことができるというサービスです。このサービスを社員向けに作成し、使って頂きました。

実際に行った内容

実際に行なった内容ですが、複数チームに別れて社員とのゆかりある店をクイズ形式で出題し、そこに来店を朝昼夜と行い、クイズの正解数に応じて景品がもらえるとういうものです。また、途中のレクリエーションでは花屋敷に伺いみんなで遊び、面白い写真大会を行いました。ここで面白い写真を撮ったチームにポイントを付与し、そこでもポイントを稼げる形を取りました。

そこで、クイズの選択肢としてエンジニアが作ったマップ内のお店、口コミを使い、そのままマップのルートに従って来店しました。

サービス概要

今回のサービスは、現段階ではリリースされるものではないので、アプリ内には実装せずスマホwebを利用しました。 自分が選択した人の行ったお店リストが地図上に表示され、口コミを見ることができます。 アプリ版のRettyの地図表示に似たような画面になっていますが、現在、Rettyでは自分が信頼できる人の行ったお店をリストから閲覧することが出来ますが、それをマップに表示する機能が備わっていませんので、今回はこの課題を新卒エンジニア3人で解決してみました。

f:id:rettydev:20170524144055p:plain

機能要件

サービス中の機能要件は

  • Google Map APIを利用し、複数店舗の店の地図表示機能
  • 作成された上記の地図の複製・編集機能
  • ユーザーIDを入力としたお店の簡易な検索ロジック

の3点になります。

サービスの構成

今回作成したWebアプリケーションは、特段凝ったつくりでなくシンプルです。

フロントエンド側は

バックエンド側は

開発時間も限られていることから、なるべく危険を犯さずシンプルな作りにして分業をしやすくし 各分担の担当者が使い慣れているようなもの、を使った形です。

tornado(Python)を利用したWebサーバ

tornadoは、スケーラブルでノンブロッキングなWebサーバを 簡単に構築するためのライブラリです。

C10K問題の解決に向けて、スレッドの使い回しを行ってくれます。 今回のサービスは社員向けだったため 、やや過剰性能になりますが 使い慣れている技術を使う、ということで採用しました。

以下のようなコードでWebサーバが構築できます

from tornado import ioloop, httpserver, httpclient


class MainHandler(web.RequestHandler):

    def __init__(self, *args, **kwargs):
       super().__init__(*args, **kwargs)
       logger.debug(self.get_template_path())

    # GETリクエスト
    def get(self):
       # do something ...
       self.render("index.html")

    # POSTリクエスト
    def post(self):
       # do something ...
       fuga = {"hoge" : "fuga"}
       self.render("index.html", data=fuga)


def make_app():
    return web.Application([
          (r"/", MainHandler), # {endpoint}/ -> MainHandler に ルーティング
       ],
       template_path=os.path.join(os.getcwd(),  "templates"),
       static_path=os.path.join(os.getcwd(),  "static"),
       debug=True, # ファイルの更新の自動同期機能等が有効となる
    )


def main():
    port = 10000
    app = httpserver.HTTPServer(make_app())
    app.bind(port)
    app.start(1)  # CPU数. 0:全てのCPU 
    ioloop.IOLoop.current().start()

また簡易なテンプレートエンジン*1も備えており、下記のようなテンプレートの使い回しが可能です.

<html>
   <title> {% block title %}裏入社式プロジェクト 2017{% end %} </title>

   {% block ext_block %}
   <p> デフォルトの表示  </p>
   {% end %}
</html>
{% extends "base.html" %}

{% block title %}Viewモード{% end %}

{% block ext_block %}
  <p>Hello world!</p>
{% end %}

MySQLにおける地図のハッシュIDの生成

今回サービスを構築する上で GETリクエストのパラーメータに ハッシュIDごとに地図を表示/編集します.

例えば、以下のようなURLを発行します

https://[endpoint]?id=7ae63asofmkl23iord

今回、重複がないような新しいハッシュ値の発行をMySQLだけで実現しました. やり方としては、新しいレコードをINSERTするときのAFTER トリガーに 以下のようなSQLを発行し これを各種データと関連づけただけになります

INSERT INTO ura2017_map_hash (map_id, hash) 
VALUES (NEW.map_id, MD5(NEW.map_id))

UNIQUE制約を設けておくことで, 重複する場合には新しいINSERTは失敗します.

裏入社式を終えて

今回の裏入社式が新卒メンバーでの初めてのチーム開発となりました。新卒だけでチームを組み、企画から開発までみんなで行うといった経験はなかなかできるものではなく大変貴重な機会でした。この行事を通して新卒同士はもちろん、普段喋れないような社員さんたちとも深く交流することができ、多くのことを学ばせていただくことが出来ました。裏入社式がRettyの伝統となり、来年以降も続いていくと面白いですね!

*1:tornado.templateに具体的な仕様・利用例があります.