Mobage を支える Ruby の技術 ~ 複数DB編 ~

43
Copyright (C) 2014 DeNA Co.,Ltd. All Rights Reserved. Mobageを支える November 11th, 2014 Naotoshi Seo @sonots DeNA Co., Ltd. Rubyの技術 ~ 複数DB~

Transcript of Mobage を支える Ruby の技術 ~ 複数DB編 ~

Copyright (C) 2014 DeNA Co.,Ltd. All Rights Reserved.

Mobageを支える

November 11th, 2014 !Naotoshi Seo @sonotsDeNA Co., Ltd.

Rubyの技術~ 複数DB編 ~

Copyright (C) 2014 DeNA Co.,Ltd. All Rights Reserved.

2

自己紹介・瀬尾 直利 @sonots ・DeNA, Co., Ltd ・インフラの Dev ・Rubyist ・OSS 活動家 ・Fluentd コミッタ

Copyright (C) 2014 DeNA Co.,Ltd. All Rights Reserved.

背景

3

!

Perl の会社と名高いこの DeNA でも Ruby (on Rails) のプロジェクトが立ち上がり始めている

Copyright (C) 2014 DeNA Co.,Ltd. All Rights Reserved.

インフラ要件の壁

4

!

• ホットデプロイ • カスタムフォーマットのロガー • デプロイサーバでビルドした gem を web サーバにアプリコードと共に撒く

• 社内 rubygems ミラー • Q4M 非同期ジョブキュー • プロファイリングツール、調査ツール

Copyright (C) 2014 DeNA Co.,Ltd. All Rights Reserved.

複数DB対応

5

!

• Rails で複数DBに対応する必要性 • 冗長化・高速化 • 既存のインフラの仕組みにのっかる必要性

• 今回はここに特化した話

Copyright (C) 2014 DeNA Co.,Ltd. All Rights Reserved.

目次

6

!

• DB接続を都度接続に • クライアントサイドDNSキャッシュ • DBパスワード一元管理 • DBスキーマ一元管理ツール • 複数DB接続

Copyright (C) 2014 DeNA Co.,Ltd. All Rights Reserved.

DB接続を都度接続にすべし

7

要件1

Copyright (C) 2014 DeNA Co.,Ltd. All Rights Reserved.

DeNAでの複数DB構成

8

!

• MySQL: Master/Slave • DNSラウンドロビンでSlaveを振り分ける • MHA で Master の高可用化 • DNS サーバには MyDNS を使用

Copyright (C) 2014 DeNA Co.,Ltd. All Rights Reserved.

MySQL Slave 1

MySQL Slave 2

MySQL Slave 3

MyDNS

Web

10.1.1.2

10.1.1.3

10.1.1.4

10.1.1.2sample_r

1回目

| id | zone | name | data | aux | |----|------|----------|----------|-----| | 2 | 1 | sample_r | 10.1.1.2 | 100 | | 3 | 1 | sample_r | 10.1.1.3 | 100 | | 4 | 1 | sample_r | 10.1.1.4 | 100 |

2回目

Slave参照: DNSラウンドロビン

Copyright (C) 2014 DeNA Co.,Ltd. All Rights Reserved.

MySQL Slave 1

MySQL Slave 2

MySQL Slave 3

MyDNS

Web

10.1.1.2

10.1.1.3

10.1.1.4

2回目

Slave参照: 永続接続

ずっとココ!! ダメ!

| id | zone | name | data | aux | |----|------|----------|----------|-----| | 2 | 1 | sample_r | 10.1.1.2 | 100 | | 3 | 1 | sample_r | 10.1.1.3 | 100 | | 4 | 1 | sample_r | 10.1.1.4 | 100 |

Copyright (C) 2014 DeNA Co.,Ltd. All Rights Reserved.

MySQL Slave 1

MySQL Slave 2

MySQL Slave 3

MyDNS

Web

10.1.1.2

10.1.1.3

10.1.1.4

10.1.1.3sample_r

2回目

Slave参照: 都度接続

1/3 の確率

| id | zone | name | data | aux | |----|------|----------|----------|-----| | 2 | 1 | sample_r | 10.1.1.2 | 100 | | 3 | 1 | sample_r | 10.1.1.3 | 100 | | 4 | 1 | sample_r | 10.1.1.4 | 100 |

Good

Copyright (C) 2014 DeNA Co.,Ltd. All Rights Reserved.

MySQL Slave 2

MySQL Slave 3

MySQL Master 1

MyDNS

Web

10.1.1.2

10.1.1.3

10.1.1.1

10.1.1.4

sample_w

MHA | id | zone | name | data | aux | |----|------|----------|----------|-----| | 1 | 1 | sample_w | 10.1.1.1 | 100 | | 2 | 1 | sample_r | 10.1.1.2 | 100 | | 3 | 1 | sample_r | 10.1.1.3 | 100 | | 4 | 1 | sample_r | 10.1.1.4 | 100 |

MySQL Slave 1

Copyright (C) 2014 DeNA Co.,Ltd. All Rights Reserved.

MySQL Slave 2

MySQL Slave 3

MySQL Master 1

MyDNS

Web

10.1.1.2

10.1.1.3

10.1.1.1

10.1.1.4

sample_w

MHA | id | zone | name | data | aux | |----|------|----------|----------|-----| | 1 | 1 | sample_w | 10.1.1.1 | 100 | | 2 | 1 | sample_w | 10.1.1.2 | 100 | | 3 | 1 | sample_r | 10.1.1.3 | 100 | | 4 | 1 | sample_r | 10.1.1.4 | 100 |

MySQL Master 2

再接続 or 都度接続

Copyright (C) 2014 DeNA Co.,Ltd. All Rights Reserved.

DBWeb

DBを再起動

restart再接続 or 都度接続

※ただし、ActiveRecord の reconnect は正しく動かなかったり ※そのため、アプリの再起動が必要だったりして、ツライ

Copyright (C) 2014 DeNA Co.,Ltd. All Rights Reserved.

MySQL Slave 1

MySQL Slave 2

MySQL Slave 3

MyDNS

Web

10.1.1.2

10.1.1.3

10.1.1.4

Slaveダウン検知(check_slave) | id | zone | name | data | aux | |----|------|----------|----------|-----| | 2 | 1 | sample_r | 10.1.1.2 | 100 | | 3 | 1 | sample_r | 10.1.1.3 | 100 | | 4 | 1 | sample_r | 10.1.1.4 | 100 |

10.1.1.3sample_r

再接続 or 都度接続

Copyright (C) 2014 DeNA Co.,Ltd. All Rights Reserved.

すべて都度接続で解決

16

Copyright (C) 2014 DeNA Co.,Ltd. All Rights Reserved.

しかしActiveRecord には都度接続オプションがない

17

Copyright (C) 2014 DeNA Co.,Ltd. All Rights Reserved.

18

なんだってーーーΩΩΩ

Copyright (C) 2014 DeNA Co.,Ltd. All Rights Reserved.

作りました

19

Copyright (C) 2014 DeNA Co.,Ltd. All Rights Reserved.

activerecord-refresh_connection

20

Rack レイヤーでリクエスト毎に接続を切るやつ 1行追加でおk # config/application.rb class Application < Rails::Application config.middleware.swap ActiveRecord::ConnectionAdapters::ConnectionManagement, "ActiveRecord::ConnectionAdapters::RefreshConnectionManagement" end

https://github.com/sonots/activerecord-refresh_connectionhttp://blog.livedoor.jp/sonots/archives/38797925.html

Copyright (C) 2014 DeNA Co.,Ltd. All Rights Reserved.

クライアントDNSキャッシュ

21

要件2

Copyright (C) 2014 DeNA Co.,Ltd. All Rights Reserved.

クライアントDNSキャッシュ

22

!

• ruby 実装 • キャッシュしないと名前解決遅い • 重み0なmasterへのfallback

Copyright (C) 2014 DeNA Co.,Ltd. All Rights Reserved.

MySQL Slave 1

MySQL Slave 2

MySQL Slave 3

MySQL Master 1

MyDNS

Web

10.1.1.2

10.1.1.3

10.1.1.1

10.1.1.4

テーブルを キャッシュselect

DNSキャッシュ | id | zone | name | data | aux | |----|------|----------|----------|-----| | 1 | 1 | sample_w | 10.1.1.1 | 100 | | 2 | 1 | sample_r | 10.1.1.2 | 100 | | 3 | 1 | sample_r | 10.1.1.3 | 100 | | 4 | 1 | sample_r | 10.1.1.4 | 100 |

10.1.1.2

ファイルに落とす

Copyright (C) 2014 DeNA Co.,Ltd. All Rights Reserved.

MySQL Master 2

MySQL Slave 2

MySQL Slave 3

MyDNS

Web

10.1.1.2

10.1.1.3

10.1.1.4

重み0へのfallback | id | zone | name | data | aux | |----|------|----------|----------|-----| | 1 | 1 | sample_w | 10.1.1.1 | 100 | | 2 | 1 | sample_w | 10.1.1.2 | 0 | | 3 | 1 | sample_r | 10.1.1.3 | 100 | | 4 | 1 | sample_r | 10.1.1.4 | 100 |

MySQL Master 1

10.1.1.1

weight:100

weight: 0

DNSプロトコルで引くと重み0のエントリが見えない。 Unbound などのDNSキャッシュを使えない。

Copyright (C) 2014 DeNA Co.,Ltd. All Rights Reserved.

ResolverMyDNS

25

resolver = ResolverMyDNS.new( zone: 'mobage.local',! cache_dir: "cache_dir/",! host: 'localhost',! username: 'root',! passowrd: nil,! database: 'mydns',!)!resolver.get_server 'foo.mobage.local' #=> 10.1.1.10

MyDNSのテーブルエントリをクライアントサイド でキャッシュして名前解決するやつ

@Spring_MT

Copyright (C) 2014 DeNA Co.,Ltd. All Rights Reserved.

26

@ryopeko

これアプリコード内でIPアドレス取得して establish_connection に渡す必要あるけど、めんどいよね?

そうすな~

Copyright (C) 2014 DeNA Co.,Ltd. All Rights Reserved.

ResolverReplace

27

resolver = ResolverMyDNS.new(...)!# Resolver を resolver_mydns にすげかえる!ResolverReplace.load_plugin('mysql2')!ResolverReplace.register!(! getaddress: resolver.method(&:get_server),! getaddresses: resolver.method(:get_server_list),! error_class: ResolverMyDNS::Error,!)

Rubyの名前解決を挿げ替えるやつ

https://github.com/sonots/resolver_replace

Copyright (C) 2014 DeNA Co.,Ltd. All Rights Reserved.

ResolverReplace

28

!

• ぶっちゃけると ruby が持っている resolv-replace のパクリ

• resolv-replace は ruby の名前解決を libc から Resolv クラスに置き換えるやつ

• 任意のクラスに置き換えられるように拡張

Copyright (C) 2014 DeNA Co.,Ltd. All Rights Reserved.

ResolverMyDNS 欲しい人???

29

ResolverReplace は OSS になってる

https://github.com/sonots/resolver_replace

Copyright (C) 2014 DeNA Co.,Ltd. All Rights Reserved.

DBパスワード管理

30

要件3

Copyright (C) 2014 DeNA Co.,Ltd. All Rights Reserved.

DeNAでのDBパスワード管理

31

!

• yaml で一元管理(インフラ管理. アプリ毎に管理させない)

• DBIx::DBHResolver という perl モジュールを通して取得する

• stage, sandbox など環境毎にパスワードが違うが、同じコードで取得できる

Copyright (C) 2014 DeNA Co.,Ltd. All Rights Reserved.

dbhresolver

32

!

• 既存の yaml を処理して ActiveRecord が受け取る形式で吐き出してくれる ruby gem

production: <<: *default <%= dbh.connect_spec('SAMPLE_R') %> sample_r_production: <<: *default <%= dbh.connect_spec('SAMPLE_R') %> sample_w_production: <<: *default <%= dbh.connect_spec('SAMPLE_W') %>

Copyright (C) 2014 DeNA Co.,Ltd. All Rights Reserved.

マイグレーション

33

要件4

Copyright (C) 2014 DeNA Co.,Ltd. All Rights Reserved.

DeNAでのスキーマ管理

34

!

• git レポジトリで一元管理(インフラ管理. アプリ毎に管理させない)

• SQL::Translator::Diff という perl モジュールを使って実際のDBスキーマとの diff をとった alter 文を作ってもらいマイグレーション

• ruby である必要はないのでそのまま利用

Copyright (C) 2014 DeNA Co.,Ltd. All Rights Reserved.

複数DB接続

35

要件5

Copyright (C) 2014 DeNA Co.,Ltd. All Rights Reserved.

複数DB接続

36

!

• read/write 用モデルそれぞれ作ってゴリゴリ実装することもできる

• が、良い仕組みを使って実装を楽にしたい

Copyright (C) 2014 DeNA Co.,Ltd. All Rights Reserved.

37

ク社どうやってるの?octopus辛みありそう...

switch_pointというのがあってだな @sora_h

Copyright (C) 2014 DeNA Co.,Ltd. All Rights Reserved.

完全に実用段階!!!

38

SwitchPoint

詳しくはeagletmt先生の資料をご参照ください

Copyright (C) 2014 DeNA Co.,Ltd. All Rights Reserved.

SwitchPoint

39

SwitchPoint.configure do |config| config.define_switch_point :db1, readable: :db1_readonly, writable: :db1_writable, config.define_switch_point :db2, readonly: :db2_readonly end   class Book1 < ActiveRecord::Base use_switch_point :db1 end   class Book2 < ActiveRecord::Base use_switch_point :db2 end

https://github.com/eagletmt/switch_point

Copyright (C) 2014 DeNA Co.,Ltd. All Rights Reserved.

Adminsbar

40

http://admins.bar/3/

Copyright (C) 2014 DeNA Co.,Ltd. All Rights Reserved.

まとめ ~ 複数DB編 ~

41

!

• DB接続を都度接続に • activerecord_refresh_connection

• クライアントサイドDNSキャッシュ • resolver_mydns / resolver_replace

• DBパスワード一元管理 • DBスキーマ一元管理ツール • 複数DB対応 • switch_point

Copyright (C) 2014 DeNA Co.,Ltd. All Rights Reserved.

その他インフラ要件の壁

42

!

• ホットデプロイ • カスタムフォーマットのロガー • デプロイサーバでビルドした gem を web サーバにアプリコードと共に撒く

• 社内 rubygems ミラー • Q4M 非同期ジョブ • プロファイリングツール、調査ツール

Copyright (C) 2014 DeNA Co.,Ltd. All Rights Reserved.

We're hiring!!

43