第三回ライブドア・テクニカルセミナーに行ってきました
クラウド時代のWebストレージ/データベース戦略
自己紹介
- ライブドア 池邊さん
利用者から見て
- 物理的なサーバ、ネットワークを意識しない
- 高可用性
- 柔軟な課金体系
- Amazon S3,CloudFiles...
提供者から見て
- 高価な機器に依存しない=>スケールアウト
- リソース有効活用でコスト効率
- 管理、運用の手間の効率化
ライブドアの考え
- 物理サーバリソースは投資済み
- 提供しているサービスはSaaS的なもの
- さらにコスト効率をあげたい
- (l|P)aaS的なクラウド環境を自分達で付くって自分達で使う
- プライベートクラウド
- クラウドっぽいという言葉が社内で流行
名前
REST
- GET/PUT/DELETE
- Bucketの作成/削除
- Objectの取得/作成/更新/削除
- レプリカの作成数はヘッダで指定
- オリジナル画像は3つくらいレプリカが必要
- サムネイルは再コンバートできるから2つでいいかとか
Example
- http://str.example.com/
は/を含むことが可能 - URIはOSファイルシステムとは独立した論理URI
PUT /ikebe/picture.jpg HTTP/1.1
X-Replication-Count: 3
Content-Length: 10240<内容>
基本戦略
CAP定理
- Consistency
- Availability
- Partition Tolerance
- 一貫性を捨てる
MySQL
Dual Masterが使えるようにAutoIncrement等使ってなくて
PerlのロジックをCにコピペして実装
MySQL :: MySQL 5.6 リファレンスマニュアル :: 12.18 その他の関数
UUID は、スペースおよび時間においてグローバルに一意の数字としてデザインされています。UUID() へのふたつの呼び出しは、互いに接続されていない別々のコンピュータ上で行った場合でも、それぞれ異なるふたつの値を生成することが想定されます。
mod_stf_strage.c
- mod_dav_fileに似ている
- GET/PUT/DELETE メソッドを受け付けてファイルの読み書き
- GETはdefault-handlerに任せ
- PUTはRecursiveにディレクトリを作成
- 同一ファイル名での上書きはできない
- 更新は一回消して内部的には別ファイルを作成
TODO
質問
- ストレージのサイズはどのくらい?
- MAX:20TB-30TB位
- 運用:10T程度
- 月に1Tづつ増える
- mogile FSでは何がダメでSTFなのか
- 作りたい
- mogilefs · GitHubはソースコードが長い
ニーズ
- Webフロントサーバをクラウドにする
- サービス規模に応じて、短時間のリソース増減が可能
- バックエンドは専用サーバ
実装決定までの試行錯誤
技術
目指すもの
- スケールアップ,スケールアウト
- ユーザ操作で即時に行うことが
- なぜ?
- 急激なトラフィック増加があるサービスへの対応
- スモールスタートの規模を最小にとどめて個人開発者の支援
- 人的リソース温存
TODO
- LVS DSR構成
- Auto Scalling
- Auto Scaleも今後対応予定
- PC3?
質問
- DSRでも裁けなくなったらどうする?
- 1顧客の量を制限
- 現状はLVSには余裕があるが、今後増えてきた場合はセットごと追加
- APIを公開することは?
- 今後は必須の条件になってくる
- お値段は?
- EC2よりも性能良くて(メモリ1GB)5,000-6,000
- EC2はネットワーク従量課金であるが、PC2は?
- 社内で賛否両論
- インスタンス監視
- cactiに自動追加
- インスタンスは月額?時間課金?
- まだ話がいっていない
- ログをとっているので1秒単位でも1時間単位でもできる
- お客さまの都合により柔軟に
- インスタンスの重複
- 同じ顧客のインスタンスは同じHWに作らない
- Migration先はシステムが勝手に決める?
- 決めてない
- お客さんに選んでいただいてもよいかな?
livedoor Readerの新機能とは?
自己紹介
- ma.laさん
- ライブドア
- livedoor reader
- livedoor clip
- API,liverary,UIデザイン
- 自社サービスのセキュリティ監査
Livedoor ReaderのStreaming API
- livedoor readerのクロールしているフィードの更新情報をリアルタイムに取得
- キーワードに絞りこみ
- リアルタイム検索エンジン
ポイント
- 外部ドメインでも動く
- 非公開フィードの記事はでない
リアルタイム
- Readerがクロールしたタイミング
Streaming APIのサーバサイド実装
- クローラ
- apache
- nginx+Plackに変更予定
- 5+2台
- mysql
- memcached
- perl
- Q4M
- ジョブ管理
- MySQL(64bit)*2台
- TokyoTyrant
- memcachedの代替
- HashDB*7台
- キャッシュ
- InnoDBPlugin
- 改良されたInnoDB
- データを圧縮してメモリ利用効率向上
- Nginx
- ロシア生まれのWebサーバ
- Streaming APIのフロント
- long-pollコネクション可
- PSGI/Plack
- 負荷試験ツール
- Coroで作られたDoSツール
- 大量のコネクションを張る
- 記事データサイズ
- テキストだけで1TB
- 過去記事の削除->やってない
- 件数不明
- 対象:180Mフィード
- 更新があるフィードは約1時間
- クローラ
- 4台
クローラの処理
Front (古いブラウザ)
- 同一ドメインからAbout | Digg.com
- window.postMessageで呼出て送信
Front (IE)
- window.name+IFRAME間送信
Android/XPERIA勉強会にいってきた
Androidアプリ開発体験記(テックファーム様)
自己紹介
- 矢吹さん
- ピクトリズムというアプリをリリース
- Androidマーケットにて発売
- 前職は居酒屋の店長 8年
セカイカメラに関して
- 本日エアタグAPIが発表予定だったが,PlaceEngineの問題でセカイカメラが審査に落ちる
シンプルがぶちささる
- ユーザが一目でこれってこういうアプリだというのが伝わるアプリ
- マーケットでも3行説明で理解できる
機能ごとに理由を付ける
- 何故?を繰り返す
- 無駄な機能を減らす
- なんでこの機能が必要なのか?
Xperiaタッチ&トライ
BPStudy#30 Django vs Rails
Intruduction to Rails
Akira Matsuda (@a_matsuda) | Twitterさん
Opinioned Software
特に2つの思想
- DRY,CoC
DHHがイケメン天才プログラマ
Rails3ではViewがHTML5採り入れる
Railsを使っているうちに筋の良い習慣や技術が自然に身につく
Head First Railsがお薦め
O/Rマッピング
デプロイ
開発環境
Rails
エディター
- emacs
- pyscripter
- py-dev
SocialWeb Conference vol.5 〜OpenSocial Night #2〜 に行ってきました
GAEとソーシャルアプリの話
- @tmatsuoさんの話
AppEngineを使ったソーシャルアプリの開発と運用 by Takashi Matsuo on Prezi
GAEの良い点
- ほとんど落ちない
- アクセスが増えたら勝手に分散してくれる
- BigTableが使える
- データが増えても参照速度が変わらない
- シャーディングやパーティショニング不要
- データが増えても参照速度が変わらない
- 値段
- ¥0
- Google Code Archive - Long-term storage for Google Code Project Hosting.とkayoauthを使えば signed??(聞き取れませんでした) もできる
- PVが増えたら課金
- 70万PV $10/day
- 20万PV $1/day
OpenSocialHost
OpenSocial-Host.pdf - Google Drive
HeartRails - ハートレイルズ - 新規事業開発のエキスパート
- HeartRailsの人
- HeartRailsはスタッフが全て在宅勤務!!
- OpenSocialHost
JavaScript API(PC/Mobile) |
ファイル,KVS |
オートスケーリング,有人対応 |
管理コンソール |
今後
-
- OpenSocialの課金/決裁プラットフォームの提供(今週中)
- OpenSocial Virtual Currency API
- poncan
- payca
- Cron機能
- サーバサイドのJavaScriptを割り当てる
- 国際化
- アプリケーションテンプレート
- アプリの雛型を提供
- 管理コンソール上でカスタマイズ可能
- 汎用PaaS
- JavaScriptのためのプラットフォーム
- OpenSocialの課金/決裁プラットフォームの提供(今週中)
実績
- 数万User程度
- サーバの1/100のリソースも使ってない
大規模SNSにおけるソーシャルアプリの運用マネタイズ
- ドリコム 神谷さん
- マネタイズポイント
- おもしろさ
- 安定した稼働
- 絶え間ない更新
- ユーザのモチベーション
- もてたい
- 勝ちたい
- 自慢したい
- 相手が必要->ソーシャル
- 課金
- 直接課金
- 間接課金
- 広告
直接課金
- mixiポイントやモバコインでお買物
- おもしろさ
- 成長
ゲームのソーシャルならではの強み
- 友達
- 他ユーザ
時間消費型成長
- モンスターを戦って経験値を積む
金銭消費型成長
- お金を払うことによって手に入れるもの
マネタイズに必要な安定稼働
- ゲームにもっとも重要な事絶対安定
- 一度落ちたゲームへの復帰はかなり難しい
巨大SNSならでは
- 想定すべき負荷がすごい
- 数秒以内に200返却MUST
- アクセス数のピーク
- リリース直後がお祭り
- イベント直後、日付変更直後、定時アイテム配布時
- ソーシャル、信じられない位ユーザが
- EC2等のクラウドな環境でスタート
罠
- ec2
- 西海岸にある
- 西海岸<->日本で2秒
- うまレーシング
- うまを撫でる機能
- MySQLでは耐えられずTTに移行
appengine ja night #5に いってきました
Kayの人
@tmatsuo
正規化しすぎるとだめ
class Tag(db.Model) name = db.StringProperty() count = db.IntegerProperty() class Post(db.Model) tags = db.ListProperty(db.Key) body = db.TextProperty()
JOINが使えないので検索はこんな感じ...
t =Tag.get_by_key_name(tag_input) if t is None: raise Http404 posts = Post.all().filter("tags = ",t.key()).fetch(200)
上記の場合はPostモデルにStringListを持った方が、無難
- 質問
- Q:タグ名を変更する場合は全Postをなめて変更するのか?、
- A:TaskQueueかRemoteAPIで全部を変更するか,Modelにバージョンを持つ
- 最近1.3.1でクエリが早くなった->複数クエリを発行することに躊躇する必要はなくなった?
- GETとQueryは変わらない
- KeyでGETは18msec程度
- KeyでQueryは23msec程度(ヒットが1つの場合)
- 場合場合によってモデル設計を考える
不要なIndexを付けないように
db.StringPropertyはデフォルトでIndexが付いてしまう
class Foo(db.Model) prop1 = db.StringProperty() prop2 = db.StringProperty() prop3 = db.StringProperty() prop4 = db.StringProperty()
インデックスを付けない
class Foo(db.Model) prop1 = db.StringProperty(indexed=false) prop2 = db.StringProperty(indexed=false) prop3 = db.StringProperty(indexed=false) prop4 = db.StringProperty(indexed=false)
インデックス名を短くする
class Foo(db.Model) prop1 = db.StringProperty(name="p1") prop2 = db.StringProperty(name="p2") prop3 = db.StringProperty(name="p3") prop4 = db.StringProperty(name="p4")
GQLを書いた場合kindが必要だが
kind名を短くする
@classmethod def kind(cls) return "z"
参考
http://code.google.com/intl/ja/appengine/docs/python/datastore/gqlreference.html
- 無料で保存できるデータ容量は限られているのでこれらをできるだけ短い名前にする
- app engineの管理ツールでDBのうちどれくらいがメタデータかを見ることができる
- モデルにIndexが何個あるかによってもパフォーマンスが変わる 1個Indexが追加される毎に16msec(cpu time)
- 検索に使わないのであればIndexを無駄に張らない
db.StringProperty(indexed=false)
から
db.StringProperty(indexed=true)
に変更したばあいfalse時代のものは検索に反映されない!!
http://code.google.com/intl/ja/appengine/docs/python/datastore/queriesandindexes.html
Exploding Index
q = MyModel.all().filter("contents ="."word1").¥ filter("contents ="."word2").¥ filter("contents ="."word3").¥ order("-created") entries = q.fetch(10)
このクエリにたいしてcontents,contents,contents,createdというインデックスを作ろうとする
content数xcontent数xcontent数xcreated数 の膨大なIndexを作ってしまう(Max 5,000件)
q = MyModel.all().filter("contents ="."word1").¥ filter("contents ="."word2").¥ filter("contents ="."word3").¥ finter("created_month=".this_month) entries = q.fetch(1000) entries.sort(cmp=lmbda x,y: cmp(x.created,y.created)
on memoryでsortするように心がける
Composite Indexを作ると危険!!
- アイデア
- Keyに時刻を埋め込むとorderが不要になる
- marge joinの仕様でsortされることがおそらく保証されている
- Keyに時刻を埋め込むとorderが不要になる
- 質問
- Q.1000件を越えるInmemory sortは?
- A.ヒープ領域(100M程度)が許す限りin memoryで可能
Greedy module loading
- 一部でしか使用しないモジュールは遅延ロードするべき
- スピンアップはなるべく短く
# -*- coding: utf-8 -*- from kay.utils import render_to_response import hoge_utils import fuga_utils import moge_utils def index(request) return render_to_response('myapp/index.html',{'message':'hello'}) def hoge(request) hoge_utils.get_entries() return render_to_response('myapp/index.html',{'message':'hello'}) def fuga(request) fuga_utils.get_entries() return render_to_response('myapp/index.html',{'message':'hello'}) def moge(request) moge_utils.get_entries() return render_to_response('myapp/index.html',{'message':'hello'})
先頭でimportしている
apache+mod_pythonの場合はこの方が効率が良い
GAEでは以下の用に 遅延ロードしたほうがよい
許されるスピンアップは10秒程度
# -*- coding: utf-8 -*- from kay.utils import render_to_response def index(request) return render_to_response('myapp/index.html',{'message':'hello'}) def hoge(request) import hoge_utils hoge_utils.get_entries() return render_to_response('myapp/index.html',{'message':'hello'}) def fuga(request) import fuga_utils fuga_utils.get_entries() return render_to_response('myapp/index.html',{'message':'hello'}) def moge(request) import moge_utils moge_utils.get_entries() return render_to_response('myapp/index.html',{'message':'hello'})
参考
1.3.1の新機能紹介
Transactional Task Queue
http://pixiv.cc/mix3/archives/51343747.html
DBのTransacion内にTaskQueueを積む動作を入れておく
commitが成功した場合にのみ積まれる
不整合が起きにくい
- 質問
- Q.TaskQueueは一時間後とか指定できる
- A.できる etaかcount downで指定可能 正確とは限らないけど。
- Q.TaskQueueのQueueのサイズに上限がある?
- A.なし、ただしスピードは同時に秒間20タスクが上限
Cursor
Pagingに使えそう
任意ページに飛んだり、戻るにはもう一捻り
Appstats(Python版のみ)
http://blog.shehas.net/2009/12/11/Kay-appstats
- 以下のYSlow的なものが見える
- RPCの統計
- URLアクセス統計
- Requestの履歴
app.yaml
- url: /sats_*
ひがやすをさん
複数のエンティティグループに跨ったTransaction(グローバルトランザクション)
エンティティグループはできるだけ小さく作る
2phase commit
複数のDBに跨るようなTransactionのプロトコル
分散トランザクションに挑戦しよう!
- リソースマネージャ
- トランザクションコーディネータ
- 一般的なトランザクション
- ジャーナルに書きだし
- 内部コミット
- ジャーナルの適応
Mac OS X X11 + kinput2/cannaの環境でリモートのUbuntuのfirefoxを動かす
リモートサーバにて
$ sudo apt-get install ttf-japanese-mincho ttf-kochi-gothic $ cat .bashrc export XMODIFIERS='@im=kinput2' export GTK_IM_MODULE=kinput2
MacOSXでCUIからアプリケーションを起動する
http://straitmouth.jp/blog/setomits/682が非常に参考になった
このようなエラーがでたので少しだけ書き換えた
$ . .apprc -bash: alias: `Address Book.app': invalid alias name