無気力生活 (ノ ´ω`)ノ ~゜

脱力系エンジニア。てきとーに生きてます。

Rails+MySql→Rails+MariaDBで、mysql2 Gemでエラー出る問題

Spiderエンジンとかその辺の検証をするために、開発で使ってたMySQLMariaDBに変更した時の話。

Spiderエンジンについては、開発者の方のスライドを見ていただければ。

要は、シャーディングをアプリではなくDB側で解決させてしまおう、というコンセプトのシロモノ。
まあ、このへんはある程度検証できたら、まとめるので今回は置いておく(`・ω・´)

問題は表題の通り。環境は、Rails4.0.8 + Ruby 2.1.1。
すでに入っていた Mysql 5.6をbrew uninstall mysqlで削除した後、brew install mariadbする。おもむろにmysql.server start

ローカルオンリーのため、テキトーにrootで。

mysql起動させたので、rake db:migrate && rake db:seedやるとこんなエラーが発生しました。

rake aborted!
Incorrect MySQL client library version! This gem was compiled for 5.6.20 but the client library is 10.0.13-MariaDB.
./config/application.rb:7:in `<top (required)>'
./Rakefile:4:in `<top (required)>'
(See full trace by running task with --trace)

どうやら、SQLクライアントのmysql2のGemが、導入したMariaDBには対応していなかった模様(´・ω・`)

gem uninstall mysql2 後、 再度、gem install mysql2なり、bundle install 実行で、mysql2入れなおすと、エラーが解消しました。

導入されているDBによって、Gemの自動判別とかやってくれてるんですかね。

データ分析担当者向けセミナー 「gloops流データアナリストの部署間連携術」に行ってきた

昨日、2014/10/8に開催された、gloopsさんのデータアナリスト向けセミナーにいってきました(`・ω・´)

私はただの1エンジニアではあるんですが、今後自社プロダクトの分析環境つくる仕事が待ってそうな気がするので、データサイエンティストの皆様の中、混ざりこんでまいりました。

仕事が長引いて、遅れて参加になったのが残念(`;ω;´) CMの効果測定話聞きたかったなぁ… とはいえ、後半の部署間連携の話しはガッツリ聞けたので、かなり有益だったと思います。

gloopsさん、話には聞いていましたが、かなり徹底してデータ解析に力入れている感を感じました。ここまで徹底的にやれると、プロダクトの改善がはかどりますね。

ここから、セミナー内容のメモを元に、雑多なまとめを紹介します。

2014/10/15
先週くらいになるんですが、Social GameInfo さんが素晴らしいまとめを公開しております。こっちの方がよく纏まっているので、詳しい内容はこちらへ。 【セミナー】データアナリストが他部署とうまく連携するコツは「問題設定」…『スカイロック』の大規模プロモーションを題材に | Social Game Info

プロダクトと一緒に、どう走っていくかの話

いまやグループスさんの看板コンテンツとなった、「スカイロック」のCM配信と、それに付随するゲーム施策の話。

キャラデザがアレだとかいろいろ話題になった作品ですが、天下の集英社がなにも言わんとこみると、許可はもらってる感じなんですかね。それはそれとして。

スカイロックのユーザー獲得のため、CMをマスで配信していたそうです。割りとゴールデンタイムに配信してた印象。自分も何回か見たことあります。
CM配信と合わせて、ユーザー獲得のための施策を22本ほど平行して走らせていたそうです。普段が8本ほどらしいので、かなり多めの施策を走らせていたみたいですね。

この施策を決定するために、ディレクタとデータアナリストが、どのような施策を打つか調整していたそうです。 gloopsさんでは、

「HBU」

という指標を第一に行ったとのこと。
この指標は

  • 直近30日間で、ほぼすべての日数を遊んでいるユーザー

を意味しているそうです。この数値が高ければ高いほど、ユーザーが楽しんで率先して遊んでいることになる。
なので、この数値を向上させていくことが、プロダクトの成長につながる、とのこと。

つまりHBUを向上させる≒「継続率」の向上、が言えるのですが、この数値を向上させるのはかなり難しいとのお話でした。

ユーザーがゲームをやめるタイミングは、ユーザー自身が感じたことがトリガーとなるため、施策単位でコントロールすることが不可能であると。
また、「この施策があれば万全だよね」という、銀の弾丸まがいのものは存在しないため、闇雲に施策を打っても改善していかない。

gloopsではどうやったか

そこで、gloopsさんでは、プロダクト側と、自社データアナリストが連携して、

  • どのタイミングで、ユーザーが飽きてしまうのか?
  • ユーザーのレベルや、セグメント毎に、なにか関連があるのか?

を分析して、今回のCM施策に役立てたそうです。その時の指標として、例に出されていたのが、

  1. ゲーム内の強さが、ある数値を超えると、継続率が伸びる
  2. ゲーム内のクエスト進行度が、一定より上になると、継続率が伸びる

の2点だそうです。これは普段の運営で蓄積したデータを使って出した指標です。
この指標を元に行った施策で、セミナーで紹介されたものはこんな感じでした。

  • 未インストール者向けに、強キャラクタと進化アイテムを配布する、ログインボーナス
  • 離脱ユーザー向けに、カムバック限定パネルミッション
  • 既存ユーザー向けにも特殊な施策(ここ聞きそびれました)

ユーザーの属性毎に、異なる施策を用意するようにしていますね。

分析と施策

ここで、ちょっと前に書いた、データアナリストの分析結果を思い出してください。
前に戻るのも面倒だと思うので、さくっとコピペ。

  1. ゲーム内の強さが、ある数値を超えると、継続率が伸びる
  2. ゲーム内のクエスト進行度が、一定より上になると、継続率が伸びる

これです。この指標が、即ち「継続率が高いユーザー」の条件です。CM施策はこの条件に合うように、

  • 初心者ユーザーが、一定以上の強さに、すぐ到達できるように、強いキャラクタ配る
  • 離脱ユーザーが、また継続してくれるように、パネルミッションに、クエスト進行度絡みのミッション含める

を狙って打たれました。これすごいですね。仮説があって、データ分析して、最適な施策を導き出す。

実際、この施策を実行した結果、期間中のHBUが1.5倍。売上が期間平均1.1倍ほど、向上がみられた、とのことでした。

分析内容の共有はどうするべきか - データアナリストがコストハウスにならないために -

さて、このような成果を出した、分析と施策のコラボレーションですが、普通こんなにうまく回るとは思えないです。
データアナリストと企画陣で、データの見方や、必要としている情報が異なりますからねぇ…。
どのように、うまくデータの話共有を行うかどうか、の話題がありました。

データアナリストが分析したデータを、そのまま渡すとどうなるか。
おおかた、膨大なデータにあふれて、どこを見るべきか、の判断に時間かかるようになります。

そうすると、企画陣は、せっかく解析してできたデータを、読まずに放置しがちになってしまいますよね?企画担当者も、プロダクトの改善や、新規施策策定に忙しいですから。しかたない。

では、そのデータをいかにして企画陣に見てもらうか。

gloopsさんでは、企画担当者が分析したデータから、企画陣が興味を持ちそうな、施策に直結したデータに加工して渡しているそうです。 企画担当者も、どんなに忙しかろうが、自分の興味ある、担当している施策に関するデータを、読まずに放置することはないです。

gloopsさんでは、データアナリストに必要な条件として、以下3つ、挙げられてました。

  • 伝えたいことを明確にする
    期待されている、要求されているモノを適切に伝える方法を知っていること
  • 解析する対象自身を知る
    自身のプロダクトは、どのように使われているか、を理解する
  • データを共通認識させる
    データアナリスト以外が、データとどう向き合うか、の意識づくり

もっと自分たちのプロダクトを知り、その分析結果をわかりやすく伝えられるか。データをチームで利用できる空気になっているか。データが正しく理解されるように報告できるかどうか。

最初から全部カバーすることは大変ですが、ここまでできれば優秀なデータアナリストになれそうですね。

総評

仕事切り上げが遅くなり遅れていったため、前半部分のメモがなかったりするんですが、後半の部分だけでも、かなりボリュームがあるセミナーだったと思います。
ただ、今回のセミナーでは、具体的な体制づくりの話には、多く触れられなかったことに、物足りなさを感じたり。これから体制作っていく人にとっては、この部分が一番聞きたいところじゃないかなー、と思いました。

次回も、セミナー開催頂けるとのことだったので、また次回に期待して、参加したいと思います( ・`ω・´)

開発環境(mac)を:beers:まみれにするためにやること

https://assets-cdn.github.com/images/icons/emoji/unicode/1f37b.png

やるたびに忘れるので、個人用メモ程度に。

Homebrew

自家醸造しないと始まりません。サクッといれる。
rubyとcommand line tools for xcodeが必要らしい。RubyはデフォルトでOK。
command line tools for xcodeは導入課程でインストールが要求されてた気がする。まあダメだったら入れる感じで。

ruby -e "$(curl -fsSL https://raw.github.com/Homebrew/homebrew/go/install)"

インストール後、以下コマンド実行。なにか問題あるならエラーなり警告がわかりやすく表示されるので解消しておく

brew doctor

こんな感じで使います。

brew install git

インストールしたモジュールは、/usr/local/Cellar/配下に置かれる(変更はできる)
また、/usr/local/bin配下にシンボリックリンクが置かれる

Homebrew-Cask

brewコマンドで、Chromeのようなアプリケーションを入れられるようになるやつ。
brewコマンドでインストール

brew install caskroom/cask/brew-cask

# アプリインストール
brew cask install google-chrome

インストールしたアプリケーションは、デフォルトだと/opt/homebrew-cask/Caskroom/に配置される。パスは通っているらしく open -a アプリ名 とかで起動できる。

caskroom/versions

Homebrew-Caskはアプリを入れてくれるけども、英語しかない。ユトラーなので日本語ないとつらい。そこでcaskroom/versions。 brew caskの別バージョンアプリをインストールできるようになるやつ。 *1
これを導入することで、日本語パッケージがリポジトリに含まれる。

brew tap caskroom/versions
brew cask install thunderbird-ja

デジタルマーケティグ普及の旗手となるかっ!? 株式会社テクロコへ行ってきました

私は、株式会社テクロコ を応援しています
https://www.wantedly.com/companies/techloco



こんにちわ! 最近、いろんな会社さんのお話を聞きに回っております。 事業の話や今後の目標等のお話、その会社さんの熱意に触れられる。そうところを楽しみに聞かせて頂いてます。

さて、もちろん、そういう良い話だけでなく、困っているお話も伺うこともあります。 よく話題になるのが、 エンジニア不足 の問題です。


近頃、個人でもいろいろサービスを開始できる環境が整ってきたこともあり、様々な企業さんが参入しています。
ただ、優秀なエンジニアは、いろんな企業さんで取り合いになってしまい、なかなか確保できません。
どの企業さんも、人材確保には躍起になっていまして、
ソーシャルでの採用活動を行ったり、エンジニアによりよい環境を用意したり、等、いろいろな試みをしています。

そういった、エンジニアにやさしい環境 をつくった or つくろうとしている企業さんを応援するべく、

勝手に記事を書いていこう

という企画です。 ※掲載許可は頂いております
今後、定期的に会社見学して、いろんな企業さんの紹介をやっていこうと思っています。


さて、この企画、第一号です。
株式会社テクロコ!!

先週の、大雨があった日に行ってきましたorz 油断して傘持ってこなかったせいで、道中コンビニに全力ダッシュするハメになったのは秘密(´・ω・`)

テクロコさんは、
Web広告業界の大手企業、株式会社オプト さんのグループ企業です。
他のグループ企業さんに、マーケティングツールを開発して卸す事業をしています。
その卸したツールは、グループ企業さんが導入支援した上で、ユーザー企業さんが使われています。

アドテク業界は、今後大きくなっていく業界だと言われています。
参考: http://www.meti.go.jp/statistics/toppage/report/bunseki/pdf/h19/h4a0803j2.pdf
これまで、CMや紙ベースだった企業さんが、より手軽に打て、高い効果が期待できるネット広告に流入しています。 そうすると、その広告を配信する企業や、効果を測定する企業の需要が高くなります。

テクロコさんも、自社開発の分析ツールにおいて、ユーザーさんが順調に増えており、今後さらに導入が広がっていくと思われます。 自分の作ったサービス、ツールがたくさんの人に使われていく。そういう体験はすごく嬉しいものだと思います。

さて、このテクロコさんですが、
今後、マーケティングツール以外にも、様々なサービスを行っていきたいとのこと。
そのためのエンジニア、を募集しているんですが、採用活動に苦慮しているそうです。

どうしても、

  • 目立つサービスを作っている企業
  • スーパーエンジニアがいる企業

に、行ってしまい、なかなか応募が来てくれないんだそうです。

現在、所属するエンジニアさんは、数名程で、組織を作っている途中とのこと。
その組織を引っ張っていけるコアメンバーを募集しているそうです。

一から、会社を育てて見たい人、環境を作ってみたい人には、 大変やりがいがある環境だと思います。

テクロコさんの、エンジニアの私から見て、良い所を上げてみます。

  1. 残業が少ない
    最近、このような募集が増えてきています。
    長く残業して開発するより、早く帰って自主学習する。それを仕事に活かしてもらったほうが、意義があると考える企業が増えているようです。
    テクロコさんも、同じ考えなんだそうです。
  2. 福利厚生が充実
    広告系サービスの会社ですからね。そこらの企業より充実しています。
  3. 今後、大きく伸びる業界
    企業が生産活動を行い、ユーザーさんに届けるため、広告は必要不可欠。ゆえに、今後なくならない業界だと思います。
    手堅い業界は強い!

この記事をみて興味が湧いてきましたら、
次に自分が戦っていくフィールドに、選んでみてはいかがでしょうか?
http://www.green-japan.com/job/27133

第二回ゲームサーバー勉強会に参加してきた

7/19(土)に開催された、ゲームサーバーに特化した勉強会についてのメモです。

広くてきれいな場を提供していただいたGREEさん、ありがとうございました。 そういえばGREEさんに入るのは、今回が初めてですね( ・ω・)

今回の勉強会では、以下のようなお話を頂きました。

  • データベースの再入門
    (@nsega様 )
  • 分割と整合性をがんばる話 ソーシャルゲームの整合性対策
    (株式会社gumi 小林様)
  • MMOのサーバーについて「剣と魔法のログレス 〜いにしえの女神〜」の実装例 (株式会社Aiming 山藤様)

スライド資料はまだ公開されてない模様でしたが、一部共有をして頂けるとの事だったので、公開され次第リンク貼っておきます。
今回、書いているメモは、あくまで私個人のメモから抜粋しているので、正確でない部分があるかもしれません。その部分はご指摘いただければと思います。( ・`ω・´)

結構、分量が多くなってしまったことを反省…その分濃い勉強会でした。

データベースの再入門

初心者しかいないと仮定した説明をします、との前置きがありました。内容もDBを使うにあたっての基本的なお話が中心でした。

nsegaさんは、MongoDBの人で有名な方です サーバーサイドの開発、直近だとネイティブもやってるそうです。 DBはPosgtre、Mysqlをよく使うそうです。

2014/08/27
資料が公開されている旨いただきましたので、貼っつけておきます。

ここからメモ

データベースについて

データベースを扱うためには、データの定義を明確にする必要がある。
論理的、物理的問わず、最初に定義を固めておく。

DBMSと、問い合わせするためのSQLには、以下のような種類があり、目的が異なる。

  • DDL (Create等の)データ定義言語
  • DML (Insert等の)データ操作言語
  • DCL (Rollback等の) データ制御言語

複数人で同時に操作する、壊れたら大変なデータ、を扱うときはDB。
DBを使うケース = 検索性重視、障害時のリカバリを迅速に行う、整合性を保証したい場合

必要なデータを探すときは、インデックスがパフォーマンスにかなり影響する。DBで使われるインデックスの特性を理解すること

  • B+Treeインデックス
  • ハッシュインデックス
トランザクションを重視する理由
  • データ更新の並列性を保つ
  • データの整合性を保障する
レプリケーション
  • DBのデータを複製できる。障害が発生しても、ある程度、データが元に戻せる。
  • マスタ-スレーブ構成。Update等の更新は、マスタに対して行う。
    マスタの変更は随時、スレーブに配信する、アプリからのReadはスレーブから。

RDBMSとNoSQLについて

  • RDBMS

    • データの一貫性保つことが得意。SELECTでの複数条件を使った柔軟な検索ができる。
    • 苦手
      • たくさんの通信があるとつらい。
      • インデックス作成などの、構成変更で時間がかかる
      • カラムのパターンが、固定しづらいケースだと苦手
      • 汎用的に使おうとすると、予備カラムが増殖してやばい
      • 結果を早く返すこと苦手(トランザクション効くとどうしても)
  • NoSQL

    • 何種類かある(KV型、ドキュメントベース型、カラムファミリ型)
      • データ分散しやすい。大量データもOK。
      • スケールアウトさせやすい(分割が楽)
      • 安いサーバーでも十分
    • 苦手

お互いが不得意なことを、無理に置き換える必要はない 。適材適所が大事。DBかKVSの選択は、要件を解決するための手札でしかない。

KVSの使いどころは、タイムライン表示とか、リアルタイムランキング。 セッションステートとしても良い感じ 。

データベースを使った使用事例

データモデリング大事。あとで矛盾があっても、手戻りは基本できない。
これから勉強する人は、IPAデータベーススペシャリストの勉強が、おすすめできる。

  • データの種類と管理方法

    • マスタ系データ
      アイテムとかモンスターそのもののデータ。頻繁にかわることはあまりない
      • M_xxxのようなプレフィックスつけて管理してる
    • トランザクション系データ
      ユーザーデータ。頻繁に更新追加が行われるもの
      • T_xxxのようなプレフィックスをつけて管理してる
  • ER図自動生成
    ジークレストではEclipse使っているので、ERMaster使って、ER図からクエリ自動生成してる

Tips

  • ER図レビュー、ソースレビュー、クエリレビューやる

    • 実行計画を見る
    • リクエスト回数が多すぎないか(ORM使っているとある)
    • 事前に事故防止ができる
    • わかってるエンジニアのアサインが必須になる
  • レプリケーション設計

    • 最初からDB負荷を分散できる
    • レプリケーション遅延を見越して設計する必要ある。マスタ反映後スレーブ反映しているので、若干遅延が出てしまう。タイミングによって、変更が反映されていない情報が取れる問題が。
    • そのため、時にはせっかくスレーブに向けてたSelectクエリを、Master側に向ける必要も出てくる
  • シャーディング

    • 水平分割: レコード単位で別DBに向ける
    • 垂直分割: 1テーブル内の、更新が多い項目だけを別テーブルに切り出す。
      シャーディングすることによって、DB性能、管理しやすさ、可用性に優しくなる。ただ、テーブルJoinが難しく…設計で考慮することが、増える。
  • 開発

    • フロントとサーバーサイド分けずに、一人でやったほうが効率いい
    • API定義書とかつらい。全部自分で作ることで、コミュニケーションレスでできる。楽に。
    • ただし、両方できる人は貴重…

分割と整合性をがんばる話 ソーシャルゲームの整合性対策

gumiの清水さんのお話でした。ソーシャルゲームの運用を通して、いろいろ工夫されたことを中心に、話されてました。

gumiさんは、python使ってることで有名な、SAPですね。 最近、大口の資金調達で話題になっていたりもしました。

ここからメモ

負荷対策

新規サービスが大ヒットして、負荷が限界に…
当時の、AWS最高インスタンスでもダメだったので、単純なスケールアップでは対応できなかった。サービス側で色々改修した。

  • Player系データを、単独のDBサーバーに。
  • 機能単位で、DB先を変更していたものを、Master、Trade、Guild、Friendをそれぞれ別サーバーに分割する方法に変更(垂直分割)
    • 性能限界にぶち当たるたびに試行錯誤してた。
    • 外部キーを外して、別DBに移す作業をひらすら実施。
  • 一つの機能に負荷が集中して、対処不可能に
    • KVSにも、じゃんじゃん流す

複数ユーザーが、同時に使う機能は、分割することが難しい - Player情報系は負荷が多く、分割難しい - ロックの粒度で負荷変わらない... なので、Player毎に、接続先DBを変更する、水平分割を行って解決。
ユーザー増えたらサーバー増やす→ 性能限界の問題は解消できた。

しかし、複数DBをまたがせると、

  • 多発する不具合
  • 消えた更新、消えたカード
    トレード機能で、カードを他のユーザー所有に変更するとき、カードから、ユーザーのヒモ付を消すようにしていた。
    → このユーザーが、分割キーだったので、分割キーを消すことで、このカードはどのDBに置くべきか、判断つかなくなった。
    結果、他のユーザーの資産が影響受ける問題に。
    → 水平分割した時は、分割キーは消しちゃいけない

トランザクション

  • 不整合と戦う
    一から抜本的に対応

    • 負荷は水平分割で対処
    • XA Transactionによる一貫性担保
    • ロックによる排他制御
  • 水平分割を前提とした構成にする

    • プレイヤーデータはPlayer用のShardにまとめる。
    • ただし、ギルドテーブルだけは、全ユーザに対する網羅的なアクセスが発生するので、これは1DBサーバーにまとめるようにした。
    • マスタデータはJsonにして、デプロイ時にメモリ上に展開するような方法に。
  • DBのみで実装する

    • プレイヤーのデータはすべてDBに
    • 自動回復系ステータスもDB
       いままではKVSに格納→Redisを水平分割してた→ 人が動くたびにデータが生成されるので、サーバーを都度増やす自体に、つらい。
       DBだけ更新、KVSだけ更新が発生していて、どちらかが、漏れる事故があった。
    • 何か問題が起こると、ユーザーに特になる場合は裏技として2chで祭られ、ユーザーが損する場合は、CSが爆発。
    • なので、トランザクションを重要視してた。
    • 正規化を徹底

XA Transaction

分散トランザクション

  • XAに参加するいずれかのDBで問題起これば、ロールバック可能
  • 複数DBをまたいだトランザクションいける
  • フレームワーク側が対応していなかったので自社開発
  • Preapared後のデータコミット時に、コミット途中で死んだら?
    • 裏でCron回して、コミットされていないやつを、解除するタスクを回そうとしていた。
    • DBのバージョンアップで、Prepared状態で固まっていると、自動でロールバックする対応が入ったので、結局使わなかった。
    • が、DBが死んだ際に、復旧のため使った

デッドロック

  • トランザクション掛けた、Updateが2回、クロスしたりする起きる。 解決できないので、サービス側でレコードロックをするようにした。
  • innoDBはインデックス使ってレコードロックかけれる
  • Whereで抽出する際に、インデックスが張っていれば、レコードが特定されてそこだけ行ロックできる
  • インデックスがないと、行が特定できないのでテーブルロックが走る

発生した事例では、テーブルにインデックス貼ってなかったせいで、テーブルロックがかかる。そのため、デッドロックで、DBサーバーのCPUが張り付く問題が発生した。
また、無駄インデックスが残っていると、意図しないインデックスが使われて、思いもよらないロックが取られることがあった。

回避するためには、処理時に

  • ロックの順番を統一すること
    • DBまたがってる場合、DB順もソート
    • 別のテーブルにまたがってる場合、テーブルもソート
  • 参照に、更新処理まぜない(あればSelect、なければInsertSelect)のケース

MYSQLは親切。同じDB内のデッドロックを検知して解除してくれる

  • 片方をロールバックして、いい感じにしてくれる
  • DB分割している場合、他のDBのデッドロックは、検知できないので自力でロック解除できない

まとめ

  • KVSに移すのは問題の先延ばしにしかならない
  • デッドロック対策の前に適切なインデックスを
  • インデックスショットガン、ダメ絶対
  • プロファイラ大事

MMOのサーバーについて「剣と魔法のログレス 〜いにしえの女神〜」の実装例

Aimingの、山藤さんのお話です。

近頃、ランキングで目立ってきている、あのログレスの、実装についての内容でした。
今、目立つタイトルだけに、会場の期待度もかなり大きい印象でした。

MMOのタイトルらしく、通信周りの工夫の話が、大きくウェイト割かれていたように思います。

ここからメモ

ログレスのサーバー

フロントエンド側のサーバー、バックエンド側のサーバーを、それぞれ、階層分けて冗長化している。 WANを縦につなぐ、同階層での接続はしていない。

フロントエンドサーバー

  • ユーザークライアントが、直接接続するサーバー
  • 通信を2種類使いわけている。

バックエンドサーバー

  • ユーザークライアントは接続しないサーバー。
  • フロントエンドサーバー間の、データやりとりを、Socketで行っている。
    サーバー中では、DBとのやりとりも行っていた。
  • サーバーはC++で実装している

Socket

  • サーバープッシュが必要な箇所で使用。
  • レスポンス速度が要求される、常時接続、差分更新
  • 利点
    • オペレーション都度の、接続コストが発生しない
    • 一回の、送受信量を少なくできる
  • 欠点
    • バッテリー消費(セッション維持するとどうしてもつらい)
    • 回線切れに弱い
    • ソフトウェアで対応しないといけないことが増える
    • セッション維持している関係上、ロードバランサー使ったスケールアウト難しい

HTTP

  • サーバープッシュがいらないところ
  • レスポンス速度を要求しないところ
  • 必要都度、通信、切断、
  • 一括更新

実装例

  • キャラクタの移動

    • 歩けない場所の制御、等あるため、サーバーでも管理する
    • キャラクタが動くと
      • 描画範囲外で、見えなかったものが見えるように
      • 見えなかったユーザーも見えるように
  • 見えなかったものが、見えると、どうなる

    • 自分の行動を他のユーザーにも反映しないといけない
    • 見えてる人がとった行動を、自分に反映しないといけない 人が増えることによってやりとりするデータが増えていく
  • 移動すると、

    • 描画通信範囲の更新を繰り返す
    • 移動フロー
    • クライアントで移動開始
    • サーバー側に目的値と到達点を送信
    • サーバー側で移動の妥当性を検証
    • 周辺のプレイヤーに送る

移動の都度、サーバー介すると反応が悪くなるので、いろいろと工夫が必要。

  • 他の人は多少遅れても気にならない
  • クライアントだけで移動させてしまうと、通信範囲の計算できない
  • クライアントだけで移動させると、マップの当たり判定無視できてしまう。
  • チート問題が付きまとうので、サーバー側の妥当性は検証必須

チャット

文字ベースコミニュケーション

  • キャラクタの、チャット送信でのポップアップはSocketで表示させている。
    • チャットの吹き出しは見える人だけ見えればいよね
    • 吹き出しは発言後なるべく早く画面にだしたい
  • チャット履歴はHTTPで
    • チャットログは、オフライン時のやつも見れる必要がある
    • コミニュケーションの途切れを防ぐ

実際に起こった問題と対応

  • 一台のサーバーにログインできるプレイヤー数が限られる
    • エリア毎に別サーバーで割り当て。で分散。
  • クライアントは、裏で、フロントエンドサーバー間の接続を、切り替えながら動いている
    • この切替時のサーバー負荷が大きい
    • ユーザー移動が大量に起こると、バックエンドが時間かかってローディングが終わらない
      • サーバーをラウンドロビンして、解決
      • 影響範囲はバックエンドとフロントエンドの通信部分だけ。
        クライアントには影響なしで修正できた。構成が分離されていることによるメリット。

RoslynかわいいよRoslyn

サンプル見てて大層感動したので、いじってみた。
解説は後日。

using System;
using System.Collections.Generic;
using System.Linq;
using Roslyn.Compilers.CSharp;
namespace Sample
{
    class Program
    {
        static void Main(string[] args)
        {
            SyntaxTree tree = SyntaxTree.ParseCompilationUnit(
                @"
                using System;
                using System.Collections.Generic;
                using System.Linq;
                using System.Text;

                namespace Roslyn_Sample
                {
                    public class Person
                    {
                        public string Name { get; private set; }
                        public Person(string name)
                        {
                            Name = name;
                        }

                        public string Speak()
                        {
                            return string.Format(""Hello My Name is {0}"", Name);
                        }
                    }
                }");

            // 外部ファイルから読み込む用
            // var code = new StreamReader("../../Person.cs").ReadToEnd();
            // SyntaxTree tree = SyntaxTree.ParseCompilationUnit(code);

            var root = (CompilationUnitSyntax)tree.GetRoot();
            root.Usings.ForEach(x => Console.WriteLine("Using Block: {0}", x.Name));
            root.Members.ForEach(member =>
            {
                if (member is NamespaceDeclarationSyntax) (member as NamespaceDeclarationSyntax).Members.ForEach(nsM => {
                    if (nsM is ClassDeclarationSyntax) (nsM as ClassDeclarationSyntax).Members.ForEach(csM => {

                        if (csM is ConstructorDeclarationSyntax)
                            Console.WriteLine("Constructor:\n " + (csM as ConstructorDeclarationSyntax).GetText());
                        if (csM is PropertyDeclarationSyntax)
                            Console.WriteLine("Property:\n " + (csM as PropertyDeclarationSyntax).GetText());
                        if (csM is MethodDeclarationSyntax)
                            Console.WriteLine("Method:\n" + (csM as MethodDeclarationSyntax).GetText());
                        if (csM is FieldDeclarationSyntax)
                            Console.WriteLine("Field:\n" + (csM as FieldDeclarationSyntax).GetText());
                    });
                });
            });
            Console.ReadKey();
        }
    }

    // foreachなんて書いてられっかヽ(`Д´)ノ
    public static class Extentions
    {
        public static void ForEach<T>(this IEnumerable<T> src, Action<T> func)
        {
            IEnumerator<T> enumrator = src.GetEnumerator();
            while (enumrator.MoveNext()) func(enumrator.Current);
        }
    }
}

Hadoopハンズオンセミナーに参加してきました。

黄色いゾウさんすげー!な体験です(`・ω・´)
昨日04/14に開催されました、Hadoop初心者向けハンズオンセミナーに参加してきました。

セミナーでは、前半にHadoopについての説明。後半から実際にHadoopを使ったプログラミングを行いました。
後半のプログラミングでは事前に提示されていた準備があったのですが、事前準備のメールが来ていないことに到着してから気づき、会場についてから必死で準備していたのは私です。
ええ、UbuntuJavaも準備出来ていませんでしたよと。モウシワケナイ・・・
メール来なかったのは、メールアドレス間違えてたこちらのミスでした。大変お手数をおかけしました。快く主催さんのサーバー環境貸して頂き、なんとかハンズオン中に動くものができました。感謝してもしきれません。
主催のAcroquest Techonology株式会社様。貴重な体験をさせて頂き大変勉強になりました。ありがとうございました。

セミナーではHadoopの動作の中身といった詳しいお話もあり、初めて触れたHadoopでしたが、概要は理解できました(・ω・)
Hadoopについて知ったことを書いてみたいとおもいます。

そもそも、Hadoopとはなんぞや?

Hadoopとは、ある巨大なデータを複数のマシンで分散処理しより高速に分析を行うことができるフレームワークで、Googleが提唱したMapReduceJavaで実現したものです。Apacheのトップレベルプロジェクトの一つとして位置づけられています。2007/9/04に最初の版がリリースされています。思っていたより昔ですね。
Hadoopの用途としてよく聞くのが、ログやデータの分析や大量データを扱うバッチ処理ですね。多くのユーザーを抱える企業では殆ど使われているんじゃないんでしょうか?

Hadoopはノードを追加するだけで処理をスケールアウトすることができます。性能を上げたければその辺に転がっている古いPCでも、たくさん集まれば処理性能は高くなります。セミナーで聞いたところ、4000台を使ってスケールアウトした事例もあるらしいです。Hadoop自体の限界は、現在開発版の0.23で10000台を見込んでいるらしいですね。

Hadoopの仕組みについて

Hadoopを構成する要素は、大きく分けて2つあります。

  1. HDFS
  2. MapReduce
HDFS

HDFS(Hadoop Distributed File System)とは、Hadoopが持つ独自のファイルシステムです。複数のサーバーを使って分散的にデータを管理することができます。
HDFSは、"Name Node"、"Data Node"の2つで構成されており、Data Nodeはファイル自体を管理し、Name NodeはData Nodeを管理します。*1

ある大きなデータをHadoopで処理するとき、どのように分散するんでしょうか?
説明のためName Nodeを"管理ノード"、Data Nodeを"ノード"として説明します。

まず、管理ノードがお仕事します。クライアント側で持っているデータを64MB程度のブロックに分割し各ノードに渡します。
この時、ブロックのコピーを複数のノードに割り当ててレプリケーションしたりします。
管理ノードはブロックをどのノードに渡したかを管理し、処理のマスターして機能します。各ノードに指示を発行するのはこの管理ノードの役割です。

MapReduce

もう一つのMapReduceは、"複数のマシンで並列処理を実行する仕組み"です。Hadoopの実処理部分は、このMapReduceが請け持っています。
MapReduceには、処理全体を管理する"JobTracker"(以下、マスターノード)と、処理を実行する"TaskTracker"(以下、スレーブノード)があります。
HDFSと連携してデータを各スレーブに割り当て、"各スレーブ毎に"分析処理を行います。
"各スレーブ毎に"がキモです。マスターノードが各スレーブに指示して処理を実行するわけではないんですね。
2012/04/17削除
なにか処理を実行するとき、マスタノードからスレーブノードに対して、分析開始指示を行います。
指示を受けたスレーブノードは、自身にあるHDFSのDataNodeからデータを読み出して、以下の順序でデータを処理します。

  • 1.Mapステップ

処理を実行する前処理にあたります。スレーブノードに渡されたデータをKeyとValueの形式に変えて、入力を作ります。
キモになるのが、入力はKey-Valueのセットであるということです。どの値を入力に使うかは、利用者が自分で調整しなければなりません。
入力値の整形は、開発者側が実装して行います。

  • 2.Shuffleステップ

Mapステップで整形した入力値を、Keyでグルーピングし、実処理(Reduceステップ)を行うワーカーに渡します。
データをグルーピングすることによって、高速に処理する準備をするらしい。

  • 3.Reduceステップ

Shuffleステップで渡されたグルーピング済みのデータを処理します。どのような処理をするかは、開発者が実装して行います。

上記処理を実行した後は、全スレーブノードの処理結果をマスターノードに渡してまとめ、最終的な処理結果をクライアントに返します。
これがMapReduceの動きの概要になります。

並列処理をする黄色いゾウにも弱点があった。

そんなHadoopですが、パフォーマンスを発揮できないケースが存在します。

  • 小さなファイルがいっぱい存在する

Hadoopは内部で64MBごとにデータを配置していく方法をとっています。そのため小さなファイルが多量に存在する場合、そのファイルをまとめてブロック化しなければなりません。Name Nodeの管理が複雑になってしまうことが想像されます。

  • 短時間で終わる処理

Hadoopは前処理に時間がかかります。詳しいことは調べきれてませんが、各ノードの整合性や、データの破損状況をチェックしたりしているらしく、どうしても時間がかかります。
短時間で終わる処理(数分)程度だと、前処理時間 > 処理時間となるため、Hadoop使わずに処理した方が早くなります。
Hadoopがその力を発揮できるのは、膨大なデータがあり、処理時間が数時間以上かかる場合に限られます。

Hadoopはどう使うの?

長くなりそう+日を跨ぎそうなので、また後日纏めてエントリ上げます。更新するまで暫くお待ち下さいな。

おまけ

自宅に帰って調べてみたら、NTTデータさんの詳しい資料がありました。
http://www.meti.go.jp/policy/mono_info_service/joho/downloadfiles/2010software_research/clou_dist_software.pdf
Hadoopのチューニングをコード付きで提示されており、これだけでも十分勉強できそうです。
気になる方はぜひ一読をおすすめします。

*1:"Secoundary Name Node"と呼ばれるName Nodeのコピーを持つことができ、冗長化のために使われることもある