Top Banner
YAPC Asia 2010 Inside Mobage Platform Inside Mobage Platform Toru Yamaguchi (=zigorou) Toru Yamaguchi (=zigorou) DeNA Software Engineer DeNA Software Engineer [email protected] [email protected] http://d.hatena.ne.jp/ZIGOROu/ http://d.hatena.ne.jp/ZIGOROu/ http:// http:// twitter.com/zigorou twitter.com/zigorou / /
58

Inside mobage platform

Jun 11, 2015

Download

Technology

Toru Yamaguchi

Inside Mobage Platform Architecture
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: Inside mobage platform

YAPC Asia 2010YAPC Asia 2010

Inside Mobage PlatformInside Mobage PlatformInside Mobage PlatformInside Mobage Platform

Toru Yamaguchi (=zigorou)Toru Yamaguchi (=zigorou)DeNA Software EngineerDeNA Software Engineer

[email protected]@cpan.orghttp://d.hatena.ne.jp/ZIGOROu/http://d.hatena.ne.jp/ZIGOROu/

http://http://twitter.com/zigoroutwitter.com/zigorou//

Page 2: Inside mobage platform

YAPC Asia 2010YAPC Asia 2010

Y!mobage ReleasedY!mobage ReleasedY!mobage ReleasedY!mobage Released

Page 3: Inside mobage platform

YAPC Asia 2010YAPC Asia 2010

ngmocongmocongmocongmoco

Page 4: Inside mobage platform

YAPC Asia 2010YAPC Asia 2010

AgendaAgendaAgendaAgenda

• How to make OpenSocial ContainerHow to make OpenSocial Container– 情報の少ない 情報の少ない OpenSocial Container OpenSocial Container の作り方のの作り方の概要について概要について

– Shindig Shindig の何を利用して何を使わないかの何を利用して何を使わないか

• Inside Social RESTful API & JSON-RPC API Inside Social RESTful API & JSON-RPC API – 大規模ウェブアプリケーションの実際大規模ウェブアプリケーションの実際

• Inside Social Activity with Q4M Inside Social Activity with Q4M – Q4M Q4M を利用した数万を利用した数万 qpsqps を捌く非同期ジョブを捌く非同期ジョブ

Page 5: Inside mobage platform

YAPC Asia 2010YAPC Asia 2010

1. How to make1. How to makeOpenSocial Container OpenSocial Container 1. How to make1. How to makeOpenSocial Container OpenSocial Container

Shindig Shindig を利用したを利用したOpenSocial Container OpenSocial Container の作り方の作り方

Page 6: Inside mobage platform

YAPC Asia 2010YAPC Asia 2010

What is OpenSocial ContainerWhat is OpenSocial ContainerWhat is OpenSocial ContainerWhat is OpenSocial Container

• PC PC の世界だと次のような定義の世界だと次のような定義– JavaScript API JavaScript API を提供しているを提供している

– Gadget XML Gadget XML のパース&レンダリングが可能のパース&レンダリングが可能

• また自ずと以下のような機能も要求されるまた自ずと以下のような機能も要求される– アプリケーションを実行する為の画面アプリケーションを実行する為の画面

– Activity (Streams) Activity (Streams) を流すためのフィード画面を流すためのフィード画面

– Gadget Gadget を管理する為のツール を管理する為のツール (c.f. DeNA Develo(c.f. DeNA Developer Site)per Site)

– などなど…などなど…

Page 7: Inside mobage platform

YAPC Asia 2010YAPC Asia 2010

Terms (1)Terms (1)Terms (1)Terms (1)• ContainerContainer

– SNS SNS 本体の事だと思っていい本体の事だと思っていい

• Gadget ServerGadget Server– Gadget XML Gadget XML をパース&レンダリングするサーバーをパース&レンダリングするサーバー

– gadgets.io.makeRequest() gadgets.io.makeRequest() などを中継するなどを中継する

– JavaScript API JavaScript API のコードをサーブするのコードをサーブする

• JavaScript APIJavaScript API– Appliacation Appliacation を作る際に使える を作る際に使える JavaScript JavaScript の の APIAPI

– Social Data (Person, Activity, Message, AppData) Social Data (Person, Activity, Message, AppData) などにアなどにアクセス出来るクセス出来る

Page 8: Inside mobage platform

YAPC Asia 2010YAPC Asia 2010

Terms (2)Terms (2)Terms (2)Terms (2)• Core & Social APICore & Social API

– JSON-RPC JSON-RPC と と RESTful API RESTful API の両方の両方– JSON-RPC JSON-RPC は表向きに出している物ではなく は表向きに出している物ではなく JavJav

aScript API aScript API の の Social Data Social Data アクセスのバックエアクセスのバックエンドとして利用ンドとして利用

– RESTful API RESTful API はサーバー間でのソーシャルデータはサーバー間でのソーシャルデータへのアクセスに利用へのアクセスに利用• Mobile Mobile 向けはモバイル用の 向けはモバイル用の Gadget Server (Gadget Server ( コンテンコンテンツ ツ Proxy Server) Proxy Server) が発行する が発行する Access Token Access Token を原則要を原則要する する OAuth OAuth でアクセス。でアクセス。

• PC PC 向けはすべて 向けはすべて Consumer Request (2-legged OAuth)Consumer Request (2-legged OAuth)

Page 9: Inside mobage platform

YAPC Asia 2010YAPC Asia 2010

Terms (3)Terms (3)Terms (3)Terms (3)

• ViewView– canvas, home, profile canvas, home, profile などの などの view view があるがある

– canvas canvas はいわゆる一番でかい画面はいわゆる一番でかい画面

– 日本のガラケー向けに 日本のガラケー向けに mobile mobile という という view view もあもありますります• OpenSocial WAP ExtensionOpenSocial WAP Extension

• http://http://wiki.opensocial.org/index.php?titlewiki.opensocial.org/index.php?title==Opensocial-wap-extensionOpensocial-wap-extension

• yoichiro++, weboo++ yoichiro++, weboo++

Page 10: Inside mobage platform

YAPC Asia 2010YAPC Asia 2010

Canvas ViewCanvas ViewCanvas ViewCanvas Viewyahoo-mbga.jpyahoo-mbga.jpyahoo-mbga.jpyahoo-mbga.jp

mbga-platform.jpmbga-platform.jpmbga-platform.jpmbga-platform.jp

Page 11: Inside mobage platform

YAPC Asia 2010YAPC Asia 2010

Apache Shindig (1)Apache Shindig (1)Apache Shindig (1)Apache Shindig (1)• OpenSocial Container OpenSocial Container の唯一のリファレンスの唯一のリファレンス実装実装– MySpace MySpace を除くほぼ全ての を除くほぼ全ての OpenSocial ContaineOpenSocial Containe

r r で採用されていると思われるで採用されていると思われる– JavaJava 版と版と PHPPHP 版がある版がある

• DeNA, mixi DeNA, mixi では では Java Java 版を採用版を採用• GREE GREE は は PHP PHP 版版

– Gadget Parsing & RenderingGadget Parsing & Rendering– JavaScript APIJavaScript API– JSON-RPC & RESTful APIJSON-RPC & RESTful API

Page 12: Inside mobage platform

YAPC Asia 2010YAPC Asia 2010

Apache Shindig (2)Apache Shindig (2)Apache Shindig (2)Apache Shindig (2)

• どこまで使えるかどこまで使えるか– Gadget Parsing & Rendering Gadget Parsing & Rendering はほぼそのままはほぼそのまま使える使える

– 認証部は自前で結合しないといけない認証部は自前で結合しないといけない– JavaScript API JavaScript API は自分たちの環境に合わせて結構は自分たちの環境に合わせて結構手直ししないといけない手直ししないといけない

– またオレオレ またオレオレ API API は当然自分で実装しないとだは当然自分で実装しないとだめめ

– RESTful & JSON-RPC RESTful & JSON-RPC は実際のデータアクセスは実際のデータアクセス部分を 部分を Java or PHP Java or PHP で記述しないと使えないで記述しないと使えない

Page 13: Inside mobage platform

YAPC Asia 2010YAPC Asia 2010

Apache Shindig (3)Apache Shindig (3)Apache Shindig (3)Apache Shindig (3)• Shindig Shindig や や OpenSocial OpenSocial と付き合う為のベストプラクティと付き合う為のベストプラクティ

スス– Shindig Shindig は唯一のリファレンス実装ですがは唯一のリファレンス実装ですが– Spec Spec 違反はざらなので転んでも泣かない!違反はざらなので転んでも泣かない!

• 何を使い何を作るか何を使い何を作るか– Container (SNS) Container (SNS) は連携部も含め当然ながら自前で作るは連携部も含め当然ながら自前で作る– Gadget Parsing & Rendering Gadget Parsing & Rendering は仕様がごついのと原則ほとんどそは仕様がごついのと原則ほとんどそ

のまま使えるので のまま使えるので Shindig Shindig の物を使うの物を使う– JavaScript API JavaScript API は手直し&追加で対応可能は手直し&追加で対応可能– Social API (RESTful & JSON-RPC) Social API (RESTful & JSON-RPC) は自前でデータバインディングは自前でデータバインディング

を実装しないと使えない を実装しないと使えない • 結論結論

– Social API Social API は自前で実装するは自前で実装する

Page 14: Inside mobage platform

YAPC Asia 2010YAPC Asia 2010

OpenSocial ArchitectureOpenSocial ArchitectureOpenSocial ArchitectureOpenSocial Architecture

ContainerContainerContainerContainer

Gadget ServerGadget ServerGadget ServerGadget Server JavaScript APIJavaScript APIJavaScript APIJavaScript API

Social Data APISocial Data API(JSON-RPC/RESTful)(JSON-RPC/RESTful)

Social Data APISocial Data API(JSON-RPC/RESTful)(JSON-RPC/RESTful)

ApplicationApplicationApplicationApplication

Gadget XMLGadget XML

Request with AuthenticationRequest with AuthenticationRequest with AuthenticationRequest with Authentication

Fetch & ParseFetch & ParseFetch & ParseFetch & Parse

RenderRenderRenderRender

ExecuteExecuteExecuteExecute

XMLHttpRequestXMLHttpRequestXMLHttpRequestXMLHttpRequest

Gadget RPCGadget RPCGadget RPCGadget RPC

External APIExternal API

XMLHttpRequestXMLHttpRequestXMLHttpRequestXMLHttpRequest

HTTP Request/ResponseHTTP Request/ResponseHTTP Request/ResponseHTTP Request/Response

Iframe ContentsIframe ContentsIframe ContentsIframe Contents

Page 15: Inside mobage platform

YAPC Asia 2010YAPC Asia 2010

Authentication (1)Authentication (1)Authentication (1)Authentication (1)• Security Token Security Token 方式と 方式と OAuth OAuth の二通りの二通り

– 通常は 通常は Security Token Security Token を を Iframe Iframe に渡す に渡す URL URL 中にクエ中にクエリストリング リストリング (st (st 値値 ) ) として渡すとして渡す• つまり つまり Container (SNS) Container (SNS) 側での 側での Authentication Authentication 情報を 情報を Security TSecurity T

oken oken にして にして iframe iframe に渡さないとだめに渡さないとだめ

– Gadget Servlet Gadget Servlet 側で 側で Authentication Authentication • Rendering Rendering された された HTML HTML 中に 中に JavaScript JavaScript で再利用可能な形で記で再利用可能な形で記述される述される

• 以降、以降、 Social API Social API を間接的に利用する を間接的に利用する opensocial.DataRequest opensocial.DataRequest や や gadgets.io.makeRequest() gadgets.io.makeRequest() などを などを JavaScript JavaScript から利用する場から利用する場合にこの 合にこの Security Token Security Token を用いるを用いる

Page 16: Inside mobage platform

YAPC Asia 2010YAPC Asia 2010

Authentication (2)Authentication (2)Authentication (2)Authentication (2)

ContainerContainerContainerContainer

Gadget ServerGadget ServerGadget ServerGadget Server JavaScript APIJavaScript APIJavaScript APIJavaScript API

Social Data APISocial Data API(JSON-RPC/RESTful)(JSON-RPC/RESTful)

Social Data APISocial Data API(JSON-RPC/RESTful)(JSON-RPC/RESTful)

Create and Pass Create and Pass Security TokenSecurity TokenCreate and Pass Create and Pass Security TokenSecurity Token

ApplicationApplicationApplicationApplicationEmbed Security TokenEmbed Security TokenAs JavaScript CodeAs JavaScript CodeEmbed Security TokenEmbed Security TokenAs JavaScript CodeAs JavaScript Code

Signed RequestSigned Requestusing Security Tokenusing Security TokenSigned RequestSigned Requestusing Security Tokenusing Security Token

Signed RequestSigned Requestusing Security Tokenusing Security TokenSigned RequestSigned Requestusing Security Tokenusing Security Token

Gadget RPCGadget RPCusing Security Tokenusing Security TokenGadget RPCGadget RPCusing Security Tokenusing Security Token

Page 17: Inside mobage platform

YAPC Asia 2010YAPC Asia 2010

Authentication (3)Authentication (3)Authentication (3)Authentication (3)#!/usr/bin/perl#!/usr/bin/perl

use strictuse strict; ;

use warningsuse warnings; ;

use use File::Slurp File::Slurp qw(slurp)qw(slurp); ;

use use Shindig::Authen::Java::BasicBlobCrypter; Shindig::Authen::Java::BasicBlobCrypter;

use use Shindig::Authen::Java::BlobCrypterSecurityToken; Shindig::Authen::Java::BlobCrypterSecurityToken;

mymy ( ( $container$container, , $domain$domain ) = ( ) = (

'default''default', , 'mbga-platform.jp''mbga-platform.jp'

); );

mymy $master_key$master_key = slurp( = slurp('/path/to/securityTokenKey''/path/to/securityTokenKey'); );

mymy $crypter$crypter = Shindig::Authen::Java::BasicBlobCrypter-> = Shindig::Authen::Java::BasicBlobCrypter->newnew( (

master_key master_key => => $master_key$master_key

); );

#!/usr/bin/perl#!/usr/bin/perl

use strictuse strict; ;

use warningsuse warnings; ;

use use File::Slurp File::Slurp qw(slurp)qw(slurp); ;

use use Shindig::Authen::Java::BasicBlobCrypter; Shindig::Authen::Java::BasicBlobCrypter;

use use Shindig::Authen::Java::BlobCrypterSecurityToken; Shindig::Authen::Java::BlobCrypterSecurityToken;

mymy ( ( $container$container, , $domain$domain ) = ( ) = (

'default''default', , 'mbga-platform.jp''mbga-platform.jp'

); );

mymy $master_key$master_key = slurp( = slurp('/path/to/securityTokenKey''/path/to/securityTokenKey'); );

mymy $crypter$crypter = Shindig::Authen::Java::BasicBlobCrypter-> = Shindig::Authen::Java::BasicBlobCrypter->newnew( (

master_key master_key => => $master_key$master_key

); );

mymy $token$token = Shindig::Authen::Java::BlobCrypterSecurity = Shindig::Authen::Java::BlobCrypterSecurityToken->Token->newnew( ( $crypter$crypter, , $container$container, , $domain$domain ); );

mymy $authen_info$authen_info = +{ = +{

app_id app_id => => 1200012012000120, ,

owner_id owner_id => => 1002010020, ,

viewer_id viewer_id => => 1002110021, ,

}; };

forfor ( (%$authen_info%$authen_info) { ) {

$token$token->->$_$_( ( $authen_info$authen_info->{->{$_$_} ); } );

} }

warnwarn $token$token->encrypt; ->encrypt;

mymy $token$token = Shindig::Authen::Java::BlobCrypterSecurity = Shindig::Authen::Java::BlobCrypterSecurityToken->Token->newnew( ( $crypter$crypter, , $container$container, , $domain$domain ); );

mymy $authen_info$authen_info = +{ = +{

app_id app_id => => 1200012012000120, ,

owner_id owner_id => => 1002010020, ,

viewer_id viewer_id => => 1002110021, ,

}; };

forfor ( (%$authen_info%$authen_info) { ) {

$token$token->->$_$_( ( $authen_info$authen_info->{->{$_$_} ); } );

} }

warnwarn $token$token->encrypt; ->encrypt;

Page 18: Inside mobage platform

YAPC Asia 2010YAPC Asia 2010

Authentication (4)Authentication (4)Authentication (4)Authentication (4)• という訳で作ったという訳で作った

– Shindig::Authen::*Shindig::Authen::*

– Security Token Security Token の の encrypt/decrypt encrypt/decrypt が出来るが出来る

– Shindig (JavaShindig (Java 版版 ) ) 互換互換

– まだオープンソースではないまだオープンソースではない

– ニーズがあれば公開しようかなとニーズがあれば公開しようかなと

– ちなみに ちなみに key file key file は以下のように作りますは以下のように作ります• dd if=/dev/random bs=32 count=1 | openssl base64 > /tmp/key.tdd if=/dev/random bs=32 count=1 | openssl base64 > /tmp/key.t

xtxt

• via org.apache.shindig.common.crypto.BasicBlobCryptervia org.apache.shindig.common.crypto.BasicBlobCrypter

Page 19: Inside mobage platform

YAPC Asia 2010YAPC Asia 2010

Shindig + Social APIShindig + Social APIShindig + Social APIShindig + Social API

Gadget ServerGadget ServerGadget ServerGadget Server

JavaScript APIJavaScript APIJavaScript APIJavaScript API

Social Data APISocial Data API(JSON-RPC/RESTful)(JSON-RPC/RESTful)

Social Data APISocial Data API(JSON-RPC/RESTful)(JSON-RPC/RESTful)

ShindigShindigShindigShindig

ChariotChariot(mobage Open Pl(mobage Open Pl

atoform API)atoform API)

ChariotChariot(mobage Open Pl(mobage Open Pl

atoform API)atoform API)

Reverse PrReverse Proxyoxy

(lighttpd)(lighttpd)

Reverse PrReverse Proxyoxy

(lighttpd)(lighttpd)

/gadgets/*/gadgets/*

/social/*/social/*

XMLHttpRequestXMLHttpRequest

Same Origin Policy Same Origin Policy のためのため同一ドメインに 同一ドメインに Shindig Shindig と と API API を を Reverse Proxy Reverse Proxy で実で実現する現する

Same Origin Policy Same Origin Policy のためのため同一ドメインに 同一ドメインに Shindig Shindig と と API API を を Reverse Proxy Reverse Proxy で実で実現する現する

Page 20: Inside mobage platform

YAPC Asia 2010YAPC Asia 2010

Other thingsOther thingsOther thingsOther things• その他にやるべきことその他にやるべきこと

– config/container.js config/container.js • security token security token を有効にするを有効にする

– lockedDomain (app lockedDomain (app ごとに異なるドメインごとに異なるドメイン ))• XHR XHR の の Same Origin Policy Same Origin Policy • Domain Cookie Domain Cookie

– features features 以下の 以下の JS JS の手直しや追加の手直しや追加• JSON-RPC JSON-RPC とのやり取りの部分とかとのやり取りの部分とか• gadgets.rpc gadgets.rpc の実装とか の実装とか (updateToken (updateToken などなど ))• カスタムの カスタムの JS API JS API の実装とかの実装とか

Page 21: Inside mobage platform

YAPC Asia 2010YAPC Asia 2010

2. Inside Social API2. Inside Social API2. Inside Social API2. Inside Social API

Plack Plack を使った を使った Social API Social API の作り方の作り方

Page 22: Inside mobage platform

YAPC Asia 2010YAPC Asia 2010

Domain SpecificDomain SpecificDomain SpecificDomain Specific• Web API Web API を作るに当たってを作るに当たって

– Spec Spec に極力準拠したいに極力準拠したい• 手堅い実装を心がける、テスト書くのは当たり前手堅い実装を心がける、テスト書くのは当たり前

– テスト自体は多分 テスト自体は多分 xaicron xaicron さんが前のトークで話してるはず!さんが前のトークで話してるはず!

– 軽く速くシンプルかつ可読性も担保したい軽く速くシンプルかつ可読性も担保したい• 余計な機能や汎用性は要らない。余計な機能や汎用性は要らない。

• 最低限の階層 最低限の階層 (Dispatch -> Filter -> Controller -> API Service -> Dat(Dispatch -> Filter -> Controller -> API Service -> DataSource Service)aSource Service)

• 既存の 既存の Web Application Framework Web Application Framework は使わないは使わない– 好きなモジュールをチョイス好きなモジュールをチョイス

– Plack Plack あるし自分で目的に特化した奴を作ればいいよねあるし自分で目的に特化した奴を作ればいいよね

Page 23: Inside mobage platform

YAPC Asia 2010YAPC Asia 2010

Basic ArchitectureBasic ArchitectureBasic ArchitectureBasic Architecture

• Web Application Server Web Application Server の構成の構成– lighttpd lighttpd

•最初のチョイスから結局変えてない最初のチョイスから結局変えてない

• もし改めてやり直すなら多分 もし改めてやり直すなら多分 Apache Apache 使いますw使いますw

– Plack with FastCGI External ServerPlack with FastCGI External Server• rpm rpm 管理の都合上、管理の都合上、 Starman/Starlet Starman/Starlet はまだ使ってまはまだ使ってませんせん

• もし改めてやり直すなら もし改めてやり直すなら rpm rpm で で CPAN CPAN モジュールのモジュールの管理はしないと思いますw管理はしないと思いますw

– それ それ local::lib local::lib で配布すれば出来るよ!で配布すれば出来るよ!

Page 24: Inside mobage platform

YAPC Asia 2010YAPC Asia 2010

DispatcherDispatcherDispatcherDispatcher• 文字通りの司令塔文字通りの司令塔

– Routing (PATH <-> Controller) Routing (PATH <-> Controller) の決定の決定• use Router::Simpleuse Router::Simple

• tokuhirom++tokuhirom++

– Controller Controller の初期化、実行の初期化、実行• config config で指定した で指定した Filter Filter を実行出来るを実行出来る

• Intercepting Filter (via J2EE ServletFilter)Intercepting Filter (via J2EE ServletFilter)

• ConfigConfig– メインはひとつ、環境別の差分は別に記述出来るメインはひとつ、環境別の差分は別に記述出来る

– 原則 原則 Perl (.pl) Perl (.pl) 形式で記述形式で記述• YAML YAML 書けない書けない

Page 25: Inside mobage platform

YAPC Asia 2010YAPC Asia 2010

Intercepting FilterIntercepting FilterIntercepting FilterIntercepting FilterFilterChainFilterChainFilterChainFilterChain Filter1Filter1Filter1Filter1 Filter2Filter2Filter2Filter2 ControllerControllerControllerController

順方向は 順方向は FilterChain FilterChain 経由で経由で登録された 登録された Filter Filter が順次実行されるが順次実行される順方向は 順方向は FilterChain FilterChain 経由で経由で登録された 登録された Filter Filter が順次実行されるが順次実行される

逆方向は順方向と逆の順序で逆方向は順方向と逆の順序で処理が戻ってくる処理が戻ってくる逆方向は順方向と逆の順序で逆方向は順方向と逆の順序で処理が戻ってくる処理が戻ってくる

Page 26: Inside mobage platform

YAPC Asia 2010YAPC Asia 2010

Model (1)Model (1)Model (1)Model (1)

• API Service (1)API Service (1)– API API でやるべきロジックを記述するでやるべきロジックを記述する

– DataSource DataSource へのアクセスロジックをフローに応へのアクセスロジックをフローに応じて呼び出して最終的に戻り値を じて呼び出して最終的に戻り値を Formatter Formatter に渡に渡すす•戻り値はたとえば 戻り値はたとえば Array<Person> Array<Person> みたいなデータ構造みたいなデータ構造を表現しているを表現している

•但しこのデータ構造はオブジェクトではなく 原則 但しこのデータ構造はオブジェクトではなく 原則 HaHashRef, ArrayRef, Scalar shRef, ArrayRef, Scalar のみで表現 のみで表現 ((無駄なインスタン無駄なインスタンスは作らないスは作らない ))

Page 27: Inside mobage platform

YAPC Asia 2010YAPC Asia 2010

Model (2)Model (2)Model (2)Model (2)

• API Service (1)API Service (1)– 特にリクエスト毎にインスタンス化するような設特にリクエスト毎にインスタンス化するような設計ではないので 計ではないので Object::Container Object::Container に突っ込んでに突っ込んでおくおく• fork fork 前にインスタンス化しておく 前にインスタンス化しておく (CoW)(CoW)

•環境ごとに異なる設定値は 環境ごとに異なる設定値は Config Config で制御 で制御 (GlobalID (GlobalID の の prefix prefix である である mbga.jp mbga.jp みたいな文字列とかみたいな文字列とか ))

• また好きな時に異なる また好きな時に異なる API Service API Service に差し替える事がに差し替える事が可能可能

• typester++typester++

Page 28: Inside mobage platform

YAPC Asia 2010YAPC Asia 2010

Model (3)Model (3)Model (3)Model (3)

• DataSource Service (1)DataSource Service (1)– DB (MySQL) DB (MySQL) や や Memcached Memcached などへのアクセスなどへのアクセス

– DB DB アクセスに関しては次のようなモジュールでアクセスに関しては次のようなモジュールで全て記述している全て記述している• DBIx::DBHResolverDBIx::DBHResolver

• DBIx::ConnectorDBIx::Connector

• SQL::Abstract::Limit + SQL::Abstract::Plugin::InsertMultiSQL::Abstract::Limit + SQL::Abstract::Plugin::InsertMulti

• DBIx::AbstractSequence (not exists CPAN)DBIx::AbstractSequence (not exists CPAN)

Page 29: Inside mobage platform

YAPC Asia 2010YAPC Asia 2010

Model (4)Model (4)Model (4)Model (4)

• DataSource Service (2)DataSource Service (2)– Memcached Memcached は接続情報が は接続情報が Memcached Memcached にあるとにあると言うモバゲーの流儀に従っている言うモバゲーの流儀に従っている•起動時に設定値を取得したら後は 起動時に設定値を取得したら後は Cache::File Cache::File に数十に数十分間キャッシュしておく分間キャッシュしておく

– この辺りのコードは この辺りのコードは Web Application Web Application 以外にも以外にもバッチや バッチや Q4M Q4M の の worker worker などでも再利用などでも再利用

– 例によって 例によって Object::Container Object::Container で省メモリかつ差で省メモリかつ差し替え可能な実装し替え可能な実装

Page 30: Inside mobage platform

YAPC Asia 2010YAPC Asia 2010

DBIx::DBHResolver (1)DBIx::DBHResolver (1)DBIx::DBHResolver (1)DBIx::DBHResolver (1)• 大量にある 大量にある DB DB へのハンドルを管理するへのハンドルを管理する

– Written by Kosuke Arisawa (DeNA)Written by Kosuke Arisawa (DeNA)– Maintainance by zigorou ^^Maintainance by zigorou ^^

• その他の特徴としてその他の特徴として– オブジェクトとしてもクラスとしても動作するオブジェクトとしてもクラスとしても動作する– 各種設定ファイルで記述可能各種設定ファイルで記述可能– 原則は 原則は DBI DBI での接続だが での接続だが DBI DBI のサブクラスや のサブクラスや DBIx::CoDBIx::Co

nnector nnector に書き換えたりも可能 に書き換えたりも可能 – Sharding Sharding した した DB DB の管理も楽の管理も楽

• Hash, List, Range Hash, List, Range などの分割手法に対応などの分割手法に対応• Sharding Sharding に用いられるキー郡を各ノードごとに分配する事が出来に用いられるキー郡を各ノードごとに分配する事が出来るる

Page 31: Inside mobage platform

YAPC Asia 2010YAPC Asia 2010

DBIx::DBHResolver (2)DBIx::DBHResolver (2)DBIx::DBHResolver (2)DBIx::DBHResolver (2)use use DBIx::DBHResolver; DBIx::DBHResolver;

mymy $r$r = DBIx::DBHResolver-> = DBIx::DBHResolver->newnew; ;

$r$r->config(+{ ->config(+{

connect_info connect_info => +{ => +{

main_master main_master => +{ => +{

dsn dsn => => 'dbi:mysql:‘, user 'dbi:mysql:‘, user => => 'master_use'master_user'r', ,

password password => => '''', , attrs attrs => +{ => +{ RaiseError RaiseError ==> > 11, , AutoCommit AutoCommit => => 00, }, , },

}, },

main_slave main_slave => +{ => +{

dsn dsn => => 'dbi:mysql:''dbi:mysql:', , user user => => 'slave_user'slave_user'', ,

password password => => '''', , attrs attrs => +{ => +{ RaiseError RaiseError ==> > 11, , AutoCommit AutoCommit => => 11, }, , },

}, },

}, },

}); });

use use DBIx::DBHResolver; DBIx::DBHResolver;

mymy $r$r = DBIx::DBHResolver-> = DBIx::DBHResolver->newnew; ;

$r$r->config(+{ ->config(+{

connect_info connect_info => +{ => +{

main_master main_master => +{ => +{

dsn dsn => => 'dbi:mysql:‘, user 'dbi:mysql:‘, user => => 'master_use'master_user'r', ,

password password => => '''', , attrs attrs => +{ => +{ RaiseError RaiseError ==> > 11, , AutoCommit AutoCommit => => 00, }, , },

}, },

main_slave main_slave => +{ => +{

dsn dsn => => 'dbi:mysql:''dbi:mysql:', , user user => => 'slave_user'slave_user'', ,

password password => => '''', , attrs attrs => +{ => +{ RaiseError RaiseError ==> > 11, , AutoCommit AutoCommit => => 11, }, , },

}, },

}, },

}); });

mymy $dbh_master$dbh_master = = $r$r->->connectconnect(('main_master''main_master'); );

$dbh_master$dbh_master->->dodo( ( 'UPDATE people SET ...''UPDATE people SET ...', , undeundeff, ... ); , ... );

mymy $dbh_slave$dbh_slave = = $r$r->->connectconnect(('main_slave''main_slave'); );

mymy $people$people = = $dbh_slave$dbh_slave->selectrow_hashref( ->selectrow_hashref(

'SELECT * FROM people WHERE id = ?''SELECT * FROM people WHERE id = ?', , undefundef, , 2020

); );

mymy $dbh_master$dbh_master = = $r$r->->connectconnect(('main_master''main_master'); );

$dbh_master$dbh_master->->dodo( ( 'UPDATE people SET ...''UPDATE people SET ...', , undeundeff, ... ); , ... );

mymy $dbh_slave$dbh_slave = = $r$r->->connectconnect(('main_slave''main_slave'); );

mymy $people$people = = $dbh_slave$dbh_slave->selectrow_hashref( ->selectrow_hashref(

'SELECT * FROM people WHERE id = ?''SELECT * FROM people WHERE id = ?', , undefundef, , 2020

); );

Page 32: Inside mobage platform

YAPC Asia 2010YAPC Asia 2010

DBIx::DBHResolver (3)DBIx::DBHResolver (3)DBIx::DBHResolver (3)DBIx::DBHResolver (3)• connect_infoconnect_info

– 各サーバーの接続情報をノード名をキーとして記各サーバーの接続情報をノード名をキーとして記述する述する• 接続先ホスト名は 接続先ホスト名は DeNA DeNA の場合、の場合、 MyDNS MyDNS を使っていを使っていて、て、 Slave Slave はさらに はさらに DNSRR DNSRR としているとしている

• clustersclusters– ノード郡と ノード郡と sharding sharding アルゴリズムをクラスタ名アルゴリズムをクラスタ名をキーとして記述するをキーとして記述する

Page 33: Inside mobage platform

YAPC Asia 2010YAPC Asia 2010

DBIx::DBHResolver (3)DBIx::DBHResolver (3)DBIx::DBHResolver (3)DBIx::DBHResolver (3)use use DBIx::DBHResolver; DBIx::DBHResolver;

mymy $r$r = DBIx::DBHResolver-> = DBIx::DBHResolver->newnew; ;

$r$r->config(+{ ->config(+{

connect_info connect_info => +{ => +{

PEOPLE001_W PEOPLE001_W => +{ ... }, => +{ ... },

PEOPLE002_W PEOPLE002_W => +{ ... }, => +{ ... },

}, },

clusters clusters => +{ => +{

PEOPLE_W PEOPLE_W => +{ => +{ strategy strategy => => 'Key''Key', ,

nodes nodes => [=> [qw/PEOPLE001_W PEOPLE002_W/qw/PEOPLE001_W PEOPLE002_W/] },] },

}, },

}); });

### connect to PEOPLE001_W### connect to PEOPLE001_W

mymy $dbh$dbh = = $r$r->->connectconnect( ( 'PEOPLE_W''PEOPLE_W', , 1010 ); );

use use DBIx::DBHResolver; DBIx::DBHResolver;

mymy $r$r = DBIx::DBHResolver-> = DBIx::DBHResolver->newnew; ;

$r$r->config(+{ ->config(+{

connect_info connect_info => +{ => +{

PEOPLE001_W PEOPLE001_W => +{ ... }, => +{ ... },

PEOPLE002_W PEOPLE002_W => +{ ... }, => +{ ... },

}, },

clusters clusters => +{ => +{

PEOPLE_W PEOPLE_W => +{ => +{ strategy strategy => => 'Key''Key', ,

nodes nodes => [=> [qw/PEOPLE001_W PEOPLE002_W/qw/PEOPLE001_W PEOPLE002_W/] },] },

}, },

}); });

### connect to PEOPLE001_W### connect to PEOPLE001_W

mymy $dbh$dbh = = $r$r->->connectconnect( ( 'PEOPLE_W''PEOPLE_W', , 1010 ); );

Page 34: Inside mobage platform

YAPC Asia 2010YAPC Asia 2010

DBIx::DBHResolver (4)DBIx::DBHResolver (4)DBIx::DBHResolver (4)DBIx::DBHResolver (4)• DBIx::DBHReslver DBIx::DBHReslver での での Sharding Sharding の実施の実施

– あらかじめ何でどう分割するか決めておくあらかじめ何でどう分割するか決めておく• user user の の id id だったり だったり application application の の id id だったりだったり• また また JOIN JOIN の利用も適材適所での利用も適材適所で

– 一律 一律 JOIN JOIN しないという戦略は誤りしないという戦略は誤り

– 分割しててもしてなくても決めた 分割しててもしてなくても決めた key key の値を渡の値を渡すことによって特にエラーにならず、設定どおりすことによって特にエラーにならず、設定どおりの の $dbh $dbh が返ってくるので、ちょっと直せば原則が返ってくるので、ちょっと直せば原則動く。動く。•但し 但し sharding sharding の の key key を複数利用した処理などはこれを複数利用した処理などはこれだけではうまく記述できないだけではうまく記述できない

Page 35: Inside mobage platform

YAPC Asia 2010YAPC Asia 2010

DBIx::DBHResolver (5)DBIx::DBHResolver (5)DBIx::DBHResolver (5)DBIx::DBHResolver (5)use use DBIx::DBHResolver; DBIx::DBHResolver;

mymy $resolver$resolver = DBIx::DBHResolver-> = DBIx::DBHResolver->newnew; ;

$resolver$resolver->config(+{ ->config(+{

clusters clusters => +{ => +{ MASTER MASTER => +{ => +{ nodes nodes => [=> [qw/MASTER001 MASTER002 MASTER003/qw/MASTER001 MASTER002 MASTER003/], ],

strategy strategy => => 'Key''Key', } }, , } },

connect_info connect_info => +{ => +{ MASTER001 MASTER001 => +{ ... }, => +{ ... }, MASTER002 MASTER002 => +{ ... }, => +{ ... },

MASTER003 MASTER003 => +{ ... }, }, });=> +{ ... }, }, });

mymy @keys@keys = ( = ( 33 .. .. 88 ); );

mymy %node_keys%node_keys = = $resolver$resolver->resolve_node_keys( ->resolve_node_keys( 'MASTER''MASTER', , \@keys\@keys ); );

### %node_keys = ( MASTER001 => [ 3, 6 ], ### %node_keys = ( MASTER001 => [ 3, 6 ],

### MASTER002 => [ 4, 7 ], MASTER003 => [ 5, 7 ] )### MASTER002 => [ 4, 7 ], MASTER003 => [ 5, 7 ] )

whilewhile ( ( mymy ( ( $node$node, , $keys$keys ) = ) = eacheach %node_keys%node_keys ) { ) {

# # それぞれのノードで処理する それぞれのノードで処理する (bulk insert (bulk insert とかとか ))

process_node( process_node( $node$node, , $keys$keys ); );

} }

use use DBIx::DBHResolver; DBIx::DBHResolver;

mymy $resolver$resolver = DBIx::DBHResolver-> = DBIx::DBHResolver->newnew; ;

$resolver$resolver->config(+{ ->config(+{

clusters clusters => +{ => +{ MASTER MASTER => +{ => +{ nodes nodes => [=> [qw/MASTER001 MASTER002 MASTER003/qw/MASTER001 MASTER002 MASTER003/], ],

strategy strategy => => 'Key''Key', } }, , } },

connect_info connect_info => +{ => +{ MASTER001 MASTER001 => +{ ... }, => +{ ... }, MASTER002 MASTER002 => +{ ... }, => +{ ... },

MASTER003 MASTER003 => +{ ... }, }, });=> +{ ... }, }, });

mymy @keys@keys = ( = ( 33 .. .. 88 ); );

mymy %node_keys%node_keys = = $resolver$resolver->resolve_node_keys( ->resolve_node_keys( 'MASTER''MASTER', , \@keys\@keys ); );

### %node_keys = ( MASTER001 => [ 3, 6 ], ### %node_keys = ( MASTER001 => [ 3, 6 ],

### MASTER002 => [ 4, 7 ], MASTER003 => [ 5, 7 ] )### MASTER002 => [ 4, 7 ], MASTER003 => [ 5, 7 ] )

whilewhile ( ( mymy ( ( $node$node, , $keys$keys ) = ) = eacheach %node_keys%node_keys ) { ) {

# # それぞれのノードで処理する それぞれのノードで処理する (bulk insert (bulk insert とかとか ))

process_node( process_node( $node$node, , $keys$keys ); );

} }

Page 36: Inside mobage platform

YAPC Asia 2010YAPC Asia 2010

DBIx::DBHResolver (6)DBIx::DBHResolver (6)DBIx::DBHResolver (6)DBIx::DBHResolver (6)• resolve_node_keys() resolve_node_keys() による による key key の分類の分類

– Activity Streams Activity Streams の処理などで使ってますの処理などで使ってます• 自分の友達全てのタイムラインに 自分の友達全てのタイムラインに Activity Activity フィードをフィードを飛ばす際とか飛ばす際とか

– またこの処理自体も実際に またこの処理自体も実際に sharding sharding されてないされてない環境でも同様に動きます^^環境でも同様に動きます^^

• という訳でという訳で– ある程度大きな環境になったら是非利用してみてある程度大きな環境になったら是非利用してみて下さい下さい

Page 37: Inside mobage platform

YAPC Asia 2010YAPC Asia 2010

DBIx::Connector (1)DBIx::Connector (1)DBIx::Connector (1)DBIx::Connector (1)• DBI DBI の薄い の薄い wrapperwrapper

– シンプルなインターフェースシンプルなインターフェース• transactiontransaction

• pingping

• reconnectreconnect

• fork/thread safefork/thread safe

– 基本はコードリファレンスにやりたい処理を書く基本はコードリファレンスにやりたい処理を書く• その その CodeRef CodeRef の引数に接続先の の引数に接続先の $dbh $dbh が渡されるが渡される

• $dbh_foo, $dbh_bar $dbh_foo, $dbh_bar とかいろいろ書かなくて良くなるとかいろいろ書かなくて良くなるのも利点のも利点

Page 38: Inside mobage platform

YAPC Asia 2010YAPC Asia 2010

DBIx::Connector (2)DBIx::Connector (2)DBIx::Connector (2)DBIx::Connector (2)use use DBIx::Connector; DBIx::Connector;

use use Try::Tiny; Try::Tiny;

mymy $conn$conn = DBIx::Connector-> = DBIx::Connector->newnew( (

$dsn$dsn, , $user$user, , $pass$pass, , $attrs$attrs ); );

try { try {

$conn$conn->txn( ->txn( subsub { {

mymy $dbh$dbh = = shiftshift; ;

### transaction### transaction

$dbh$dbh->commit; ->commit; ### Don’t forget commit!!!### Don’t forget commit!!!

} ); } );

} }

catch { catch {

mymy $e$e = = $_$_; ;

### error handling### error handling

};};

use use DBIx::Connector; DBIx::Connector;

use use Try::Tiny; Try::Tiny;

mymy $conn$conn = DBIx::Connector-> = DBIx::Connector->newnew( (

$dsn$dsn, , $user$user, , $pass$pass, , $attrs$attrs ); );

try { try {

$conn$conn->txn( ->txn( subsub { {

mymy $dbh$dbh = = shiftshift; ;

### transaction### transaction

$dbh$dbh->commit; ->commit; ### Don’t forget commit!!!### Don’t forget commit!!!

} ); } );

} }

catch { catch {

mymy $e$e = = $_$_; ;

### error handling### error handling

};};

Page 39: Inside mobage platform

YAPC Asia 2010YAPC Asia 2010

SQL::Abstract::* (1)SQL::Abstract::* (1)SQL::Abstract::* (1)SQL::Abstract::* (1)• SQL SQL は原則 は原則 SQL::Abstract SQL::Abstract で記述するで記述する

– 但し複雑な 但し複雑な JOIN JOIN や や GROUP BY GROUP BY だとかはそのまだとかはそのままヒアドキュメントで記述するまヒアドキュメントで記述する

– SQL_CALC_FOUND_ROWS SQL_CALC_FOUND_ROWS だとか だとか FORCE INDEX, IFORCE INDEX, INSERT IGNORE NSERT IGNORE とかは無理やりどうにかするとかは無理やりどうにかする• そろそろ新しい そろそろ新しい SQL SQL 生成モジュールがほしい所生成モジュールがほしい所

– 例によってアプリケーション全体でひとつのイン例によってアプリケーション全体でひとつのインスタンスでかまわないので スタンスでかまわないので Object::Container Object::Container にに入ってます入ってます

Page 40: Inside mobage platform

YAPC Asia 2010YAPC Asia 2010

SQL::Abstract::* (2)SQL::Abstract::* (2)SQL::Abstract::* (2)SQL::Abstract::* (2)• LIMIT, OFFSET LIMIT, OFFSET を使いたいを使いたい

– SQL::Abstract::Limit SQL::Abstract::Limit で出来るよ!で出来るよ!

• Bulk insert Bulk insert したいしたい– SQL::Abstract::Plugin::InsertMulti SQL::Abstract::Plugin::InsertMulti で出来るよ!で出来るよ!

– ON DUPLICATE KEY UPDATE ON DUPLICATE KEY UPDATE も出来るので も出来るので (duplicate (duplicate がが ) ) 多い日でも安心です!多い日でも安心です!

– bulk insert bulk insert は は 1000 1000 件程度を上限にしてやるのがいいで件程度を上限にしてやるのがいいですす• 速度や 速度や Too many connection, Max allow packets Too many connection, Max allow packets の問題の問題

Page 41: Inside mobage platform

YAPC Asia 2010YAPC Asia 2010

MySQL (1)MySQL (1)MySQL (1)MySQL (1)• MySQL Partitioning MySQL Partitioning の利用 の利用 (1)(1)

– 主に日時による 主に日時による Range Partitioning Range Partitioning を利用していますを利用しています• モバゲーマイページの「友達のゲーム状況」、「ゲームからのおモバゲーマイページの「友達のゲーム状況」、「ゲームからのお知らせ」の辺り知らせ」の辺り

• こちらはパージの手軽さが一番の利用目的こちらはパージの手軽さが一番の利用目的

– 一部 一部 List Partitioning List Partitioning も使っていますも使っています• TextData API TextData API の の status status 値で 値で List Partitioning List Partitioning してますしてます

– UNIQUE UNIQUE 制約が犠牲になったり外部キーが貼れなくなった制約が犠牲になったり外部キーが貼れなくなったりしますりします• 常にそれらとのトレードオフである事を考える常にそれらとのトレードオフである事を考える

Page 42: Inside mobage platform

YAPC Asia 2010YAPC Asia 2010

MySQL (2)MySQL (2)MySQL (2)MySQL (2)• MySQL Partitioning MySQL Partitioning の利用 の利用 (2)(2)

– EXPLAIN PARTITIONS SELECT …EXPLAIN PARTITIONS SELECT …• その その SQL SQL でどのパーティションが選択されるかまででどのパーティションが選択されるかまで分かる分かる

• パーティションが絞り込めれば速度が上がるパーティションが絞り込めれば速度が上がる– インデックスとの併用なども考えたりしてますインデックスとの併用なども考えたりしてます

– ALTER TABLE tablename ADD PARTITIONSALTER TABLE tablename ADD PARTITIONS• 追加もすぐ終わります追加もすぐ終わります

– ALTER TABLE tablename DROP PARTITIONSALTER TABLE tablename DROP PARTITIONS•削除もすぐ終わります削除もすぐ終わります

Page 43: Inside mobage platform

YAPC Asia 2010YAPC Asia 2010

MySQL (3)MySQL (3)MySQL (3)MySQL (3)• TRIGGER TRIGGER の積極的な利用の積極的な利用

– TRIGGER TRIGGER のメリットは大体デメリットだったりしますけのメリットは大体デメリットだったりしますけどど• アプリケーション変更しなくても特定の処理が出来るけど、アプアプリケーション変更しなくても特定の処理が出来るけど、アプリケーション外で起こっているのは気持ち悪いとかリケーション外で起こっているのは気持ち悪いとか

• ストアドプロシージャ構文が馴染めないとかwストアドプロシージャ構文が馴染めないとかw

– どのあたりで使ってるかどのあたりで使ってるか• サマリテーブルの更新サマリテーブルの更新• テーブルスキーマの追加や変更時テーブルスキーマの追加や変更時• Partitioning Partitioning されたテーブルの されたテーブルの unique unique 制約制約

– そもそも そもそも Partitioning Partitioning するなって話でもあるwするなって話でもあるw• 特定の条件時に 特定の条件時に Q4M Q4M への への insert insert とかとか

Page 44: Inside mobage platform

YAPC Asia 2010YAPC Asia 2010

MySQL (4)MySQL (4)MySQL (4)MySQL (4)• TRIGGER TRIGGER とスキーマ変更とスキーマ変更

– 例えば 例えば Range Partitioning Range Partitioning されていない複数のされていない複数のテーブルがあるテーブルがある•親にしか日時カラムが無い親にしか日時カラムが無い

– 子テーブルも同様に 子テーブルも同様に Range Partitioning Range Partitioning したいしたい•新しい系統を用意して、新スキーマの日時カラムは親新しい系統を用意して、新スキーマの日時カラムは親の日時をトリガーで入れるの日時をトリガーで入れる

• トリガーは通常 トリガーは通常 mysqldump mysqldump だとデータのインポートだとデータのインポート後に適用されるが、日時カラムに 後に適用されるが、日時カラムに default default 値を設定し値を設定した上で事前にトリガーを定義してデータのインポートた上で事前にトリガーを定義してデータのインポートをするをする

Page 45: Inside mobage platform

YAPC Asia 2010YAPC Asia 2010

MySQL (5)MySQL (5)MySQL (5)MySQL (5)• TRIGGER + Q4M TRIGGER + Q4M でテーブルを自在に変更でテーブルを自在に変更

– これはまだ検証中です!これはまだ検証中です!– 特定の 特定の slave slave に に Q4M Q4M をインストールしておくをインストールしておく– 特定の 特定の slave slave だけにトリガーを作り、特定の条だけにトリガーを作り、特定の条件の際に 件の際に Q4M Q4M に に queue queue を を insert insert するする

– 既存のテーブルの特定の部分だけを抽出してメッ既存のテーブルの特定の部分だけを抽出してメッセージに出来るセージに出来る• 垂直分割でまったく新しいテーブルにデータをコピー垂直分割でまったく新しいテーブルにデータをコピー出来る出来る

• レプリケーション開始前の元データの生成はさっきのレプリケーション開始前の元データの生成はさっきのスキーマ変更時のトリガー利用と同じスキーマ変更時のトリガー利用と同じ

Page 46: Inside mobage platform

YAPC Asia 2010YAPC Asia 2010

MySQL (6)MySQL (6)MySQL (6)MySQL (6)

Old PeopleOld PeopleOld PeopleOld People Old FriendOld FriendOld FriendOld FriendPeoplePeopleQueueQueue

PeoplePeopleQueueQueue

FriendFriendQueueQueue

FriendFriendQueueQueue

New PeopleNew PeopleNew PeopleNew People New FriendNew FriendNew FriendNew Friend

People ReplicationPeople ReplicationWorker (Perl)Worker (Perl)

People ReplicationPeople ReplicationWorker (Perl)Worker (Perl)

Friend ReplicationFriend ReplicationWorker (Perl)Worker (Perl)

Friend ReplicationFriend ReplicationWorker (Perl)Worker (Perl)

Insert queue by triggerInsert queue by triggerInsert queue by triggerInsert queue by trigger

queue_wait()queue_wait()queue_wait()queue_wait()

insert/update/deleteinsert/update/deleteinsert/update/deleteinsert/update/delete insert/update/deleteinsert/update/deleteinsert/update/deleteinsert/update/delete

SlaveSlave SlaveSlave

MasterMaster

replicationreplicationreplicationreplicationreplicationreplicationreplicationreplication

Page 47: Inside mobage platform

YAPC Asia 2010YAPC Asia 2010

3. Inside Social Activity 3. Inside Social Activity with Q4Mwith Q4M3. Inside Social Activity 3. Inside Social Activity with Q4Mwith Q4M

Q4M Q4M を利用したを利用した大規模メッセージングシステム大規模メッセージングシステム

Page 48: Inside mobage platform

YAPC Asia 2010YAPC Asia 2010

Q4M usageQ4M usageQ4M usageQ4M usage

• 使い方はとてもシンプル使い方はとてもシンプル– SELECT * FROM table_name WHERE queue_wait( ‘tSELECT * FROM table_name WHERE queue_wait( ‘t

able_name’, wait_time );able_name’, wait_time );• enqueue enqueue されるまで されるまで wait_time(sec) wait_time(sec) 待って、待って、 enqueue enqueue されたらされたら 11 レコードだけ取得できますレコードだけ取得できます

– SELECT queue_end()SELECT queue_end()• dequeuedequeue

– SELECT queue_abort()SELECT queue_abort()• queue queue を元に戻すを元に戻す

Page 49: Inside mobage platform

YAPC Asia 2010YAPC Asia 2010

Worker (1)Worker (1)Worker (1)Worker (1)

• Q4M Q4M や や Gearman Gearman を使った を使った worker worker の実装の実装– Parallel::Prefork Parallel::Prefork を使えば簡単に書けますを使えば簡単に書けます

• この辺りは この辺りは kazuho kazuho さんのトークや さんのトークや tokuhirom tokuhirom の部の部ログにいろいろ書いてありますログにいろいろ書いてあります

– 後は 後は daemontools daemontools で起動するで起動する

– API API で説明した で説明した DataSource Service DataSource Service を再利用すを再利用する形で簡単に実装出来まする形で簡単に実装出来ます

Page 50: Inside mobage platform

YAPC Asia 2010YAPC Asia 2010

Worker (2)Worker (2)Worker (2)Worker (2)

• Worker Worker の設定と配置の設定と配置– 原則どのサーバーにも同じソースコードと設定原則どのサーバーにも同じソースコードと設定ファイルが ファイルが deploy deploy されてますされてます

– 但し、サーバーごとに異なる設定をしたい場合が但し、サーバーごとに異なる設定をしたい場合があります あります (( あとで説明あとで説明 ))• ~/etc/sysconfig/production/daemon_env ~/etc/sysconfig/production/daemon_env のような設定のような設定ファイルを共通で ファイルを共通で deploydeploy

•上記の設定を 上記の設定を /etc/sysconfig /etc/sysconfig 以下に特定のルールでコ以下に特定のルールでコピーピー

• 以降、上記のファイルは必要に応じて設定値を書き換以降、上記のファイルは必要に応じて設定値を書き換える場合があります える場合があります

Page 51: Inside mobage platform

YAPC Asia 2010YAPC Asia 2010

Scaling Q4M (1)Scaling Q4M (1)Scaling Q4M (1)Scaling Q4M (1)

• enqueue enqueue が凄まじい環境での が凄まじい環境での Q4MQ4M– enqueue enqueue される順序が重要でない場合は、同じ用される順序が重要でない場合は、同じ用途の 途の Q4M Q4M を複数台用意して、を複数台用意して、 Round Robin Round Robin で で insert insert すれば解決すれば解決• とも行かなかった。。。とも行かなかった。。。

– 理由は実際に 理由は実際に worker worker が行う処理時間に が行う処理時間に queue queue の中身によって大きくばらつきがある場合に、の中身によって大きくばらつきがある場合に、 ququeue eue の残数が均衡しないと言う問題が出たの残数が均衡しないと言う問題が出た

Page 52: Inside mobage platform

YAPC Asia 2010YAPC Asia 2010

Scaling Q4M (2)Scaling Q4M (2)Scaling Q4M (2)Scaling Q4M (2)

Q4MQ4MQ4MQ4M

Worker (Perl)Worker (Perl)Worker (Perl)Worker (Perl)

insert queueinsert queue(DNSRR)(DNSRR)insert queueinsert queue(DNSRR)(DNSRR)

Q4MQ4MQ4MQ4M

queue_wait()queue_wait()and Running joband Running jobss(DNS RR)(DNS RR)

queue_wait()queue_wait()and Running joband Running jobss(DNS RR)(DNS RR)

Page 53: Inside mobage platform

YAPC Asia 2010YAPC Asia 2010

Scaling Q4M (3)Scaling Q4M (3)Scaling Q4M (3)Scaling Q4M (3)

Q4MQ4MQ4MQ4M

Worker (Perl)Worker (Perl)Worker (Perl)Worker (Perl)

insert queueinsert queue(DNSRR)(DNSRR)insert queueinsert queue(DNSRR)(DNSRR)

Q4MQ4MQ4MQ4M

queue_wait()queue_wait()and Running joband Running jobss

queue_wait()queue_wait()and Running joband Running jobss

Worker (Perl)Worker (Perl)Worker (Perl)Worker (Perl)

Page 54: Inside mobage platform

YAPC Asia 2010YAPC Asia 2010

Scaling Q4M (4)Scaling Q4M (4)Scaling Q4M (4)Scaling Q4M (4)• queue_wait() queue_wait() する する worker worker からの接続先も からの接続先も DNSRR DNSRR

すると、ゆらぎが収まらない場合があるすると、ゆらぎが収まらない場合がある– worker worker は特定のサーバーだけを見るようにするは特定のサーバーだけを見るようにする

– またこうしておけば万が一障害が起きた場合にも切り替えまたこうしておけば万が一障害が起きた場合にも切り替えが楽が楽• 手動 手動 compaction compaction も片方サービスアウトしてゆるりと対応ってのも片方サービスアウトしてゆるりと対応ってのも可能になるも可能になる

– 先の設定値をサーバーごとに異なる設定云々先の設定値をサーバーごとに異なる設定云々• worker worker の動作するサーバーごとに異なる の動作するサーバーごとに異なる Q4M Q4M に接続したいといに接続したいというニーズからでしたうニーズからでした

• 他にも急な負荷の増大のときに一時的にプロセス増やすとかそう他にも急な負荷の増大のときに一時的にプロセス増やすとかそういうのでいちいち いうのでいちいち deploy deploy なんてやってられないwなんてやってられないw

Page 55: Inside mobage platform

YAPC Asia 2010YAPC Asia 2010

Other topicsOther topicsOther topicsOther topics

• 最近の事例最近の事例– 最新データを元に 最新データを元に memcached memcached にキャッシュをにキャッシュを作りに行く処理が重たい作りに行く処理が重たい• やたらと やたらと CPU CPU を食うを食う orz…orz…

– 色々試して見ると 色々試して見ると Cache::Memcached::Fast Cache::Memcached::Fast に に no_wait no_wait をつけると解決するらしい をつけると解決するらしい (by xaicron)(by xaicron)• no_wait no_wait は確認なしに は確認なしに set() set() を完了しちゃう設定を完了しちゃう設定

Page 56: Inside mobage platform

YAPC Asia 2010YAPC Asia 2010

4. Conclusion4. Conclusion4. Conclusion4. Conclusion

まとめまとめ

Page 57: Inside mobage platform

YAPC Asia 2010YAPC Asia 2010

ConclusionConclusionConclusionConclusion• Shindig Shindig を使った を使った OpenSocial OpenSocial コンテナコンテナ

– そこまでびっくりするほど大変じゃないですそこまでびっくりするほど大変じゃないです– 但し実用レベルまでだと色々と(ry但し実用レベルまでだと色々と(ry

• API API のような画面を伴わない のような画面を伴わない Web AppWeb App– そのドメイン特化のアプリケーションとしてフルスクラッそのドメイン特化のアプリケーションとしてフルスクラッチで書くのもいいよチで書くのもいいよ

– Plack Plack や他の や他の CPAN CPAN モジュールがあるので後は設計の妙モジュールがあるので後は設計の妙

• Q4M Q4M の利用の利用– Mobage Platform Mobage Platform の根幹部分を日々担ってるので相当な負の根幹部分を日々担ってるので相当な負荷に耐えられます荷に耐えられます

– でも初めて体験するような事も^^でも初めて体験するような事も^^

Page 58: Inside mobage platform

YAPC Asia 2010YAPC Asia 2010

Thanks & Questions?Thanks & Questions?Thanks & Questions?Thanks & Questions?

• ご清聴ありがとうございましたご清聴ありがとうございました• 時間余ってたら質問?時間余ってたら質問?