Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.
トレタのMySQL
MySQL casual #8 (小規模限定回)
2015/11/20
Hiroaki Sano
me
• Name:
• 佐野裕章(Hiroaki Sano)
• Personal info:
• https://hiroakis.com/blog/
• https://twitter.com/la_luna_azul
• https:/...
トレタ
• 飲食店向け予約管理アプリケーション、一般ユーザ向けにウェブ予約も提供
• 顧客:レストラン、居酒屋などの飲食店
• 例えば…
• 俺の株式会社様(俺のイタリアン、俺のフレンチ…etc)
• 株式会社大庄様(庄や、やるき茶屋…etc)...
これを
こうじゃ
トレタのコンセプト
• 飲食店の予約管理、顧客管理をIT化
• 予約事故を防ぐ
トレタ
• アクセスのピーク
• 時刻:夕方6 pm JSTあたり
• 曜日:金曜日 > 他 > 土曜日 > 日曜日
• 夜の営業開始直後くらいに当日の予約確認をしていると思われる
トレタのMySQL
話すこと
• 経験上、大規模から小規模に変わった時に感じたこ
とか、小規模ならでは(?)のことをば…
トレタ
MySQL

Master
Engineyard
ブラウザiPad
MySQL

Slave
MySQL

Slave
Users
App
• サーバ側のコア機能はEngineyardで稼働
• 一部機能はAWS(S3, Route53...
トレタのMySQL
MySQL

Master
Appサーバ
MySQL

Slave
MySQL

Slave
Rails
HAProxy
Write
Read
Replication
TCP 127.0.0.1:3306
• MySQL o...
小規模ならではのことってなんだろう
• トレタの場合…
• Likeフィルタによる全文検索が割と動く
• キューっぽい使い方をしても割と動く
• 大規模に比べると運用が楽(シンプルなので)
全文検索
全文検索
SELECT DISTINCT `reservations`.`id`
FROM `reservations`
LEFT OUTER JOIN `customers`
ON `customers`.`id` = `reservatio...
全文検索
• InnoDBのフルテキストインデックスは使っていない
• Mroongaも使っていない
• WHERE `reservations`.`restaurant_id` = XXXXでの
絞り込み
• (レコード数が少なければ)案外な...
カジュアルな話:なぜ部分一致検索は遅くなりがちか
• ここで試しに本当にカジュアルな話も挟んでみます…
• select * from t where col like ‘%word%’
• 理由:インデックスが効かないから
• Indexin...
Likeフィルタで発生した事案
• select * from t where col like ’{POST_DATA}%’
• 空のPOST_DATA
• select * from t where col like ’%’
• DBマスタ...
MySQLでキューのようなことをする
MySQLでキューのようなことをする
MySQL

Master
Appサーバ
MySQL

Slave
MySQL

Slave
Rails
HAProxy
Write
Read
Replication
TCP 127.0.0.1:3306
...
MySQLでキューのようなことをする
MySQL
WorkerWorkerWorkerWorker
CREATE TABLE `queues` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`reservati...
MySQLでキューのようなことをする
• 下記の記事で指摘があるように、正直、悪手ではある
• http://www.engineyard.co.jp/blog/2013/5-subtle-ways-
youre-using-mysql-as-...
大規模に比べると運用が楽
大規模と小規模の構成の違い(経験上)
大規模時代 今
バージョン 4.1, 5.0, 5.1, 5.5, 5.6 5.6
ストレージエンジン MyISAM, InnoDB, Blackhole InnoDB
インフラ
大量のハイエンド物理サーバ...
大規模に比べるとシンプルなので運用が楽
• 小規模だから楽、というよりは構成がシンプルだか
ら楽。
• 大規模になってもシンプルなアーキテクチャを保つ
べき。
• Railsのmigrationで運用が回る
まとめ
• 小規模だと…
• 多少の悪手でも大丈夫
• Likeフィルタの部分一致検索
• キューもどき
• かといってインデックスが全く効かないのは危険
• ちゃんとインデックスを張る。インデックスを使うようなSQL投げる。
• ちゃんとモニ...
迫り来る課題
• 悪手からの脱却
• その用途に最適化されたミドルウェアの導入etc
• Railsのmigrationに依存した運用からの脱却
• 生のalterがだんだんキツくなってくる
最後にサラリーマンとして言わせてください
We are hiring!
https://toreta.in/recruit
おわり
トレタのMySQL MySQL casual #8
トレタのMySQL MySQL casual #8
Upcoming SlideShare
Loading in …5
×

トレタのMySQL MySQL casual #8

2,234 views

Published on

A presentation at MySQL casual #8

Published in: Engineering
  • Be the first to comment

トレタのMySQL MySQL casual #8

  1. 1. トレタのMySQL MySQL casual #8 (小規模限定回) 2015/11/20 Hiroaki Sano
  2. 2. me • Name: • 佐野裕章(Hiroaki Sano) • Personal info: • https://hiroakis.com/blog/ • https://twitter.com/la_luna_azul • https://github.com/hiroakis • Company: • SIer(2006/4-) • CyberAgent, Inc(2011/3-) • Toreta, Inc (2014/11-)
  3. 3. トレタ • 飲食店向け予約管理アプリケーション、一般ユーザ向けにウェブ予約も提供 • 顧客:レストラン、居酒屋などの飲食店 • 例えば… • 俺の株式会社様(俺のイタリアン、俺のフレンチ…etc) • 株式会社大庄様(庄や、やるき茶屋…etc) • ローストホース様 • etc • ローンチは2013年12月 • 導入店舗数:3700店舗∼ • 店舗あたりの月額課金 • オフィスは五反田
  4. 4. これを
  5. 5. こうじゃ
  6. 6. トレタのコンセプト • 飲食店の予約管理、顧客管理をIT化 • 予約事故を防ぐ
  7. 7. トレタ • アクセスのピーク • 時刻:夕方6 pm JSTあたり • 曜日:金曜日 > 他 > 土曜日 > 日曜日 • 夜の営業開始直後くらいに当日の予約確認をしていると思われる
  8. 8. トレタのMySQL
  9. 9. 話すこと • 経験上、大規模から小規模に変わった時に感じたこ とか、小規模ならでは(?)のことをば…
  10. 10. トレタ MySQL
 Master Engineyard ブラウザiPad MySQL
 Slave MySQL
 Slave Users App • サーバ側のコア機能はEngineyardで稼働 • 一部機能はAWS(S3, Route53..etc)やHerokuにも存在 • モニタリング、分析などはSaaSを利用
 Mackerel, NewRelic, BigQuery…etc
  11. 11. トレタのMySQL MySQL
 Master Appサーバ MySQL
 Slave MySQL
 Slave Rails HAProxy Write Read Replication TCP 127.0.0.1:3306 • MySQL on Engineyard • MySQL5.6 • InnoDB • m3.largeが3台(Master:Slave=1:2) • ほとんどがRead • スレーブは主にバッチの参照用、調査用、昇格 用 • 小規模(だと思う)。 worker
  12. 12. 小規模ならではのことってなんだろう • トレタの場合… • Likeフィルタによる全文検索が割と動く • キューっぽい使い方をしても割と動く • 大規模に比べると運用が楽(シンプルなので)
  13. 13. 全文検索
  14. 14. 全文検索 SELECT DISTINCT `reservations`.`id` FROM `reservations` LEFT OUTER JOIN `customers` ON `customers`.`id` = `reservations`.`customer_id` LEFT OUTER JOIN `customer_phones` ON `customer_phones`.`customer_id` = `customers`.`id` LEFT OUTER JOIN `customer_emails` ON `customer_emails`.`customer_id` = `customers`.`id` WHERE `reservations`.`restaurant_id` = XXXX AND ( concat(customers.last_name, customers.first_name) like '%さの%' OR concat(customers.last_name_reading,customers.first_name_reading) like '%さの%' OR customers.company_name like '%さの%' OR customers.note like '%さの%' OR reservations.note like '%さの%' OR customer_emails.email like '%さの%' OR ) ORDER BY `reservations`.`start_at` DESC LIMIT 10 OFFSET 0; • Likeの部分一致検索
  15. 15. 全文検索 • InnoDBのフルテキストインデックスは使っていない • Mroongaも使っていない • WHERE `reservations`.`restaurant_id` = XXXXでの 絞り込み • (レコード数が少なければ)案外なんとかなる
  16. 16. カジュアルな話:なぜ部分一致検索は遅くなりがちか • ここで試しに本当にカジュアルな話も挟んでみます… • select * from t where col like ‘%word%’ • 理由:インデックスが効かないから • Indexing LIKE Filters • http://use-the-index-luke.com/sql/where-clause/searching-for-ranges/like-performance- tuning • インデックスとは索引。つまりそのままの意味。 • 前方一致のみインデックスが効く。
  17. 17. Likeフィルタで発生した事案 • select * from t where col like ’{POST_DATA}%’ • 空のPOST_DATA • select * from t where col like ’%’ • DBマスタのCPUが100%になってしまった • バリデーション漏れ
  18. 18. MySQLでキューのようなことをする
  19. 19. MySQLでキューのようなことをする MySQL
 Master Appサーバ MySQL
 Slave MySQL
 Slave Rails HAProxy Write Read Replication TCP 127.0.0.1:3306 • 現地時間の午後3時に一部の顧客にメールを送る機能 • 定期的に各appサーバのworkerが一斉に動き出して MySQLに参照/更新を行う • あるworkerが処理中のレコードは他のworkerに処理 させたくない • workerはsidekiq(非同期処理を行うgem)で実装 • 基本的には非同期的な処理を行っているがこのよう なバッチ処理ぽいこともworkerにやらせている worker
  20. 20. MySQLでキューのようなことをする MySQL WorkerWorkerWorkerWorker CREATE TABLE `queues` ( `id` int(11) NOT NULL AUTO_INCREMENT, `reservation_id` int(11) NOT NULL, `status` tinyint(4) NOT NULL DEFAULT '0', `reminded_at` datetime DEFAULT NULL, `created_at` datetime DEFAULT NULL, `updated_at` datetime DEFAULT NULL, PRIMARY KEY (`id`), KEY `index_reservation_remind_emails_on_reservation_id` (`reservation_id`), KEY `index_reservation_remind_emails_on_status_and_reminded_at` (`status`,`reminded_at`) ) ENGINE=InnoDB AUTO_INCREMENT=343046 DEFAULT CHARSET=utf8 select * from queues where status = 0 and reminded_at < now() => レコードが未処理(status=0)
 かつ現地時間午後3:00を過ぎているもの(reminded_at < now())を取得 update queues set status = 1 where id = ? and status = 0
 => レコードを処理中としてマーキング(status=1)
 => ここでaffected_rowsが1なら自分が処理する
 0だと他のworkerが処理するので何もしない => 処理に成功したらレコードを消す • 参考 • http://qiita.com/masuyama/items/645b25f03dc9e321cb96
  21. 21. MySQLでキューのようなことをする • 下記の記事で指摘があるように、正直、悪手ではある • http://www.engineyard.co.jp/blog/2013/5-subtle-ways- youre-using-mysql-as-a-queue-and-why-itll-bite-you/ • が、レコードが大量でなければ問題なく動く。
  22. 22. 大規模に比べると運用が楽
  23. 23. 大規模と小規模の構成の違い(経験上) 大規模時代 今 バージョン 4.1, 5.0, 5.1, 5.5, 5.6 5.6 ストレージエンジン MyISAM, InnoDB, Blackhole InnoDB インフラ 大量のハイエンド物理サーバ
 Write Heavyな箇所にはフラッシュを活用 クラウドに3台
 特徴 種々の課題に対応するためにインフラ、MySQL側 やることが多くなりがち(だった)。
 シャーディング、レプリケーションフィルタによる テーブルの分散、InnoDBの圧縮の活用、カスケー ド構成…etc 業務アプリケーションのバックエンドなの でトラフィックはある程度予測できる。ウ ェブ予約で多少のスパイクあり。 コンフィグとしては基本的な設定をケアす れば良い。
  24. 24. 大規模に比べるとシンプルなので運用が楽 • 小規模だから楽、というよりは構成がシンプルだか ら楽。 • 大規模になってもシンプルなアーキテクチャを保つ べき。 • Railsのmigrationで運用が回る
  25. 25. まとめ • 小規模だと… • 多少の悪手でも大丈夫 • Likeフィルタの部分一致検索 • キューもどき • かといってインデックスが全く効かないのは危険 • ちゃんとインデックスを張る。インデックスを使うようなSQL投げる。 • ちゃんとモニタリングする • 大規模よりは運用は楽 • 構成がシンプル • 大規模になってもシンプルな構成を維持すべき • ある程度の規模まではMySQL+著名なフルスタックフレームワークでビジネス 要件が満たせるシステムが構築できている
  26. 26. 迫り来る課題 • 悪手からの脱却 • その用途に最適化されたミドルウェアの導入etc • Railsのmigrationに依存した運用からの脱却 • 生のalterがだんだんキツくなってくる
  27. 27. 最後にサラリーマンとして言わせてください
  28. 28. We are hiring! https://toreta.in/recruit
  29. 29. おわり

×