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.

遅いクエリと向き合う仕組み #CybozuMeetup

12,534 views

Published on

サイボウズで作ったデータベース関係のライブラリの話

Published in: Engineering
  • Be the first to comment

遅いクエリと向き合う仕組み #CybozuMeetup

  1. 1. 遅いクエリと向き合う仕組み サイボウズ株式会社 ⾚井 駿平 1
  2. 2. whoami ▌⾚井 駿平 l 2013年4⽉⼊社 l アプリケーション基盤チーム所属 l プログラミング⾔語の研究→博⼠号取得→サイボウズ ▌ミドルウェアからWebアプリまで l 副業では個⼈でiOSアプリを作ってます 2
  3. 3. アプリケーション基盤チーム ▌サイボウズ内の複数の製品で使うプログラムを作るチーム l ミドルウェア l メッセージキュー、全⽂検索、サムネイル作成、ログ… l Webアプリ l ユーザー管理機能、プロフィール表⽰… l Webアプリのライブラリ、フレームワーク l Javaで作ってる製品 l 選定したり、作成したり 3
  4. 4. 今⽇話すこと ▌ライブラリを作った話 l データベース周り l 障害を減らす仕組み l パフォーマンスを改善するためのORマッパー 4
  5. 5. kintoneの話 5
  6. 6. kintone? ▌Webでデータベースを作れるようなサービス l ドラッグ&ドロップで⼊⼒フォームとデータベースが作れる l SQLでのtable ≒ アプリ l ただし、スキーマがどんどん変わる l ドキュメント指向データベースっぽい 6
  7. 7. 7
  8. 8. 8
  9. 9. kintoneの中⾝のはなし ▌永続化にはRDBMS (MySQL) を使っている l 1アプリ=1table ではない l 固定のtableに⾊々な形のアプリがマッピングされる l 複雑なクエリが多く発⾏される場合が… l 複雑な条件での絞込 l パフォーマンスが… ▌詳しくは「kintoneの検索⾼速化への取り組み」を参照 l https://www.slideshare.net/RyoMitoma/kintone-73674134 9
  10. 10. 複雑なクエリで障害が ▌複雑な絞り込みが⾏われるとリクエストに⼗分単位で時間が掛 かる場合が l DBが遅い/⼤量のクエリ/⼤量のメモリ ▌ロードバランサーでは5分以上掛かるリクエストは強制切断し ている l アプリケーションサーバー側ではリクエストは⽣き続ける l リロードされると… 10
  11. 11. どうしたものか ▌ クエリ⾃体を改善する l 当然必要 l kintoneの性質上、遅いクエリはどうしても発⽣し得る l 起きちゃった場合の対応をしないといけない ▌ クエリのタイムアウト l MySQL 5.7ではSELECTのタイムアウトが出来る l 当時使ってたのは5.6… l kintoneではそこそこ遅いクエリが多く⾛る l 使えない ▌ 遅すぎるリクエストのみを強制的に終了させたい l JavaのServlet上で動いているのでkillとか出来ない 11
  12. 12. リクエストが⾃分で終了すればいい 12 ▌リクエストの中のチェックポイントで経過時間を判定 l 超えていたら例外を投げて終了 ▌コード中のあらゆる場所に判定するコードを書く? l 量が多くて⼤変 l コードが汚くなる l 漏れが発⽣する
  13. 13. よし、アスペクト指向だ! ▌アスペクト指向プログラミング(AOP) l プログラミングの⾊々な場所に処理を挿⼊出来る技術 l リフレクションの凄いやつ l JavaのWebフレームワークには⼊ってたりする l あまり流⾏らなかったけど ▌データベースにアクセスするたびに経過時間をチェックする 13
  14. 14. aspectの例 14 public class RepositoryAspect { @Pointcut("execution(public * com.cybozu.Repository+.*(..))") void timeoutTarget() { } @After(value = "timeoutTarget()") public void after() { DateTime expire = ((DateTime) request.getAttribute(“expire”)); if (expire != null && expire.isBeforeNow()) { throw new RequestTimeoutException(); } } } DBにアクセス全 てのメソッド を実⾏した後で以 下の処理を実⾏す る
  15. 15. 効果は? ▌とある1⽇にタイムアウトしてたリクエストは90件くらい l 致命的な障害は防げてそう ▌タイムアウトしたログを頼りにクエリを改善していけるかも 15
  16. 16. ORマッパーを乗り換える 16
  17. 17. S2Dao ▌kintone等ではS2Dao/Seasar2を使ってました l アノテーションでクエリを書くと、メソッドが⾃動⽣成 17 @S2Dao(bean = User.class) public interface UserDao { @Query(“SELECT * FROM user WHERE id = /*id*/”) List<User> getById(Long id); }
  18. 18. ORマッパーがEOL!? ▌S2DaoがEOLになりそう! 移⾏しないと ▌Spring Data JPA + Hibernate に移⾏しました l S2Daoと同じようにアノテーションで書ける l JPAという標準だ l JPAの中ではHibernateがメジャー? 18
  19. 19. ⼤失敗 19
  20. 20. パフォーマンスが出ませんでした ▌制御できないキャッシュ l kintone では可変⻑の巨⼤なIN句が使われていた l それぞれの⻑さでクエリがキャッシュ l メモリを圧迫してGC多発 l 他にも性能問題がぽろぽろと ▌詳しくはブログに l 「我々はいかにして技術選択を間違えたのか? 2016」 l http://blog.cybozu.io/entry/2016/12/28/101500 20
  21. 21. Hibernateをやめたい ▌よい乗り換え先ある? l 他のJPA実装? l 仕組み上あまりかわらなそう l MyBatis? l IN句を使うのにforeach⽂みたいなのを書かないといけない l SpringのJdbcTemplate l 書き⽅が⼤きく変わる l jdbcTemplate.query(“SELECT * FROM user”, rowMapper) ▌困った困った 21
  22. 22. ⾃分で作っちゃえ ▌JdbcTemplateをSpring Dataでラップするものを作る l 何故か誰も作ってないっぽい ▌コンセプト l 今までと同じようにアノテーションで書ける l 余計なことはしないシンプルなラッパー l has-many has-one等すらサポートしない 22
  23. 23. コードの例 ▌S2DaoやSpring Data JPAと⼤体同じように書ける 23 @Table(name = “user”) class User { @Id @GeneratedValue public Long id; @Column(“login_name”) public String loginName; } @Repository public interface UserRepository extends JdbcTemplateRepository<User> { @Query(“SELECT * FROM user WHERE id=:id”) List<User> getById(@Param(“id”) Long id); }
  24. 24. 切り替えた結果 ▌kintoneで全⾯的に乗り換えてから約1ヶ⽉ l 今のところクエリ関係が原因の障害は起きてなさそう l 社内独⾃の性能測定では、10%ほど性能が向上した 24
  25. 25. オープンソース化します ▌Spring Data Jdbc Template l https://github.com/cybozu/spring-data-jdbc-template ▌まだソースのみ l maven等に上げるのはこれから検討 ▌もうすこし詳しい話はブログに書くかも 25
  26. 26. まとめ ▌アプリケーション基盤チームでは社内のライブラリの整備もし ています ▌ものによってはオープンソース化もします 26

×