Railsアプリ開発環境の高速化

 Railsアプリ開発環境の高速化

開発環境のパフォーマンスチューニング - クックパッド開発者ブログ
http://techlife.cookpad.com/entry/2015/10/13/101031

cookpad/chanko - GitHub
https://github.com/cookpad/chanko

開発環境のデータをできるだけ本番に近づける - クックパッド開発者ブログ
http://techlife.cookpad.com/entry/2014/10/03/110806

分散テスト実行システムRRRSpecをリリースしました - クックパッド開発者ブログ
http://techlife.cookpad.com/entry/2014/03/24/rrrspec/

Scalable Deployments - How we deploy Rails app to 150+ hosts in a minute
https://speakerdeck.com/sorah/scalable-deployments-how-we-deploy-rails-app-to-150-plus-hosts-in-a-minute

cookpad/reuse_query_results - GitHub
https://github.com/cookpad/reuse_query_results

08d5432a5bc31e6d9edec87b94cb1db1?s=128

Takashi Kokubun

January 23, 2016
Tweet

Transcript

  1. 3BJMTΞϓϦ։ൃ؀ڥͷߴ଎Խ !LLVCVO $PPLQBE5FDI$POG

  2. ࣗݾ঺հ • ࠃ෼ਸࢤ • GitHub, Twitter: @k0kubun • ٕज़෦։ൃج൫άϧʔϓ •

    ։ൃج൫ͷӡ༻ • ։ൃޮ཰ͷ޲্
  3. ΞδΣϯμ • ͳͥ։ൃ؀ڥͷߴ଎Խ͕ඞཁ͔ • ߴ଎ԽͷͨΊʹԿΛ͔ͨ͠ • RailsΞϓϦͷDOMContentLoaded • ΞηοτϓϦίϯύΠϧ

  4. ͳͥ։ൃ؀ڥͷߴ଎Խ͕ඞཁ͔ ͳͥ։ൃ؀ڥͷߴ଎Խ͕ඞཁ͔ ߴ଎ԽͷͨΊʹԿΛ͔ͨ͠ 3BJMTΞϓϦͷ%0.$POUFOU-PBEFE ΞηοτϓϦίϯύΠϧ

  5. ΫοΫύουͷշదͳ։ൃ؀ڥ • ػೳ։ൃ • ߴ଎ͳϓϩτλΠϐϯά Chanko (@eudoxa, @r7kamura)

  6. ΫοΫύουͷշదͳ։ൃ؀ڥ • ػೳ։ൃ • ߴ଎ͳϓϩτλΠϐϯά Chanko • ຊ൪͔ΒϨϓϦ͞ΕΔ։ൃ༻DB (@eudoxa, @r7kamura)

    (@adorechic, @sorah)
  7. ΫοΫύουͷշదͳ։ൃ؀ڥ • ػೳ։ൃ • ߴ଎ͳϓϩτλΠϐϯά Chanko • ຊ൪͔ΒϨϓϦ͞ΕΔ։ൃ༻DB • ςετ࣮ߦ

    • ෼ࢄRSpec࣮ߦ RRRSpec (@eudoxa, @r7kamura) (@adorechic, @sorah) (@draftcode, @eagletmt)
  8. ΫοΫύουͷշదͳ։ൃ؀ڥ • ػೳ։ൃ • ߴ଎ͳϓϩτλΠϐϯά Chanko • ຊ൪͔ΒϨϓϦ͞ΕΔ։ൃ༻DB • ςετ࣮ߦ

    • ෼ࢄRSpec࣮ߦ RRRSpec • σϓϩΠ • ߴ଎ͳσϓϩΠπʔϧ Mamiya (@eudoxa, @r7kamura) (@adorechic, @sorah) (@draftcode, @eagletmt) (@sorah)
  9. ΞϧόΠτ࣌୅ͷࢲͷؾ࣋ͪ Q. ΫοΫύου͸։ൃ͠΍͍͔͢ʁ

  10. ΞϧόΠτ࣌୅ͷࢲͷؾ࣋ͪ Q. ΫοΫύου͸։ൃ͠΍͍͔͢ʁ A. ػೳ։ൃͷͨΊͷ࢓૊Έ͕੔͍ͬͯͯɺ ςετ΋σϓϩΠ΋ߴ଎Ͱ։ൃ͠΍͍͢ …͚Ͳ։ൃ؀ڥ͕஗͍

  11. 3BJMTΞϓϦͷ%0.$POUFOU-PBEFE • Կ͔มߋͯ͠Ϧϩʔυ͢Δͱ16.2ඵ଴ͨ͞ΕΔ ʢϨγϐݕࡧϖʔδͷDOMContentLoadedʣ

  12. 3BJMTΞϓϦͷ%0.$POUFOU-PBEFE • ผʹมߋՃ͑ͯͳͯ͘΋10.3ඵ଴ͨ͞ΕΔ

  13. DPPLQBEDPNͷΞηοτϓϦίϯύΠϧ $ time rake assets:precompile 1436.01 real 1092.28 user 338.06

    sys • ΞηοτϓϦίϯύΠϧʹ23෼56ඵ͔͔Δ • 2.5 GHz Inel Core i7, SSD Ͱͷܭଌ
  14. ΞηοτϓϦίϯύΠϧ͕஗͍ͱԿ͕ࠔΔ͔ • CI͕஗͘ͳΔ • CIͰຊ൪σϓϩΠ༻ͷΞηοτΛࣄલʹίϯύΠϧ͍ͯ͠ ΔͨΊ • εςʔδϯά؀ڥ΁ͷσϓϩΠ͕஗͘ͳΔ • ຊ൪؀ڥҎ֎΁ͷσϓϩΠͰ͸σϓϩΠ࣌ʹίϯύΠϧ͠

    ͍ͯΔͨΊ
  15. ͳͥ։ൃ؀ڥͷߴ଎Խ͕ඞཁ͔ • ։ൃ؀ڥ͕஗ͯ͘։ൃ͠ʹ͍͘ͱɺૉૣ͘Ձ஋Λ ಧ͚Δ͜ͱ͕Ͱ͖ͳ͍͔Β

  16. 3BJMTΞϓϦͷ%0.$POUFOU-PBEFE ͳͥ։ൃ؀ڥͷߴ଎Խ ߴ଎ԽͷͨΊʹԿΛ͔ͨ͠ 3BJMTΞϓϦͷ%0.$POUFOU-PBEFE .Z42- 4PMS ($ "TTFU ΞηοτϓϦίϯύΠϧ ߴ଎ԽͷͨΊʹԿΛ͔ͨ͠

  17. 3BJMTΞϓϦߴ଎ԽͰ৮ΕΔτϐοΫ • 1. MySQL • 2. Solr • 3. GC

    • 4. Asset
  18. 3BJMTΞϓϦߴ଎Խ.Z42- • ActiveRecordͷDBΞμϓλʔͷϨΠϠʔͰSELECTΫΤϦͷ ݁ՌΛMemcachedʹΩϟογϡ • INSERT, DELETE, UPDATE͕૸ͬͨΒJOIN΋ߟྀͯ͠Ωϟ ογϡΛΫϦΞ •

    εΩʔϚ΍σʔλΛ௚઀มߋ͠ͳ͕Β։ൃ͢Δ৔߹͸ແޮʹ ͢Δ ࢪࡦ: cookpad/reuse_query_results (@eudoxa)
  19. 3BJMTΞϓϦߴ଎Խ.Z42- ։ൃ؀ڥʹ͓͚ΔݕࡧϖʔδͷDOMContentLoaded 10,300ms 9,520ms ࢪࡦ: cookpad/reuse_query_results (@eudoxa)

  20. 3BJMTΞϓϦߴ଎Խ4PMS • SunspotʹΑΔSolr΁ͷΫΤϦͷ݁ՌΛΩϟογϡ͢Δ • ݩʑݕࡧΠϯσοΫε͸όονॲཧ͞Ε͍ͯͯߋ৽ස౓͕ߴ͘ ͳ͍ͷͰɺΩϟογϡΛഁغ͠ͳ͍ • SunspotपΓͷ։ൃΛ͢Δ৔߹͸ແޮʹ͢Δ ࢪࡦ: Cache

    sunspot result (@adorechic)
  21. 3BJMTΞϓϦߴ଎Խ4PMS ࢪࡦ: Cache sunspot result (@adorechic) ։ൃ؀ڥʹ͓͚ΔݕࡧϖʔδͷDOMContentLoaded 9,520ms 8,990ms

  22. 3BJMTΞϓϦߴ଎Խ($ • ϦΫΤετॲཧதʹGC͕΄ͱΜͲ૸Βͳ͍Α͏ʹ͢Δ • WEBrickʹϞϯΩʔύον͢ΔͷΛආ͚ૄ݁߹ʹ͢ΔͨΊɺ Rack middleware ͰεΠον͢Δ • Ruby

    2.0.0Λ࢖͍ͬͯͨ౰࣌͸ޮՌ͕͕͋ͬͨɺ2.2Ͱ͸ࠩ ͕খ͘͞ͳ͍ͬͯͨ • ࠷৽ͷRuby࢖͏ͷେࣄ ࢪࡦ: GC.disable
  23. 3BJMTΞϓϦߴ଎Խ($ 3BDL)BOEMFS 8&#SJDL 3BDLBQQMJDBUJPO 3BJMT 3BDLNJEEMFXBSFT 3FRVFTU 3FTQPOTF ($EJTBCMF ($FOBCMF

    ($ࢭΊΔ3BDLNJEEMFXBSF ࢪࡦ: GC.disable
  24. 3BJMTΞϓϦߴ଎Խ($ ࢪࡦ: GC.disable ։ൃ؀ڥʹ͓͚ΔݕࡧϖʔδͷDOMContentLoaded 8,990ms 6,310ms

  25. 3BJMTΞϓϦߴ଎Խ"TTFU • config.assets.digest = true ʹ͢Δ͚ͩ (Railsඪ४) • Cache-Control: no-cache

    → public, max-age=31536000 • ͨͩ͠ Sprockets 2 ͩͱ 304 ࣌ʹ no-cache ʹͳΔ • ࠷৽ͷgemΛ࢖͍ඪ४ͷઃఆʹै͓ͬͯ͘ͱupstream͔Β ྑ͍ԸܙΛड͚ΒΕΔ ࢪࡦ1: ΞηοτͷϦΫΤετΛϒϥ΢βͰΩϟογϡ
  26. 3BJMTΞϓϦߴ଎Խ"TTFU ࢪࡦ1: ΞηοτͷϦΫΤετΛϒϥ΢βͰΩϟογϡ ։ൃ؀ڥʹ͓͚ΔݕࡧϖʔδͷDOMContentLoaded 6,310ms 4,910ms

  27. 3BJMTΞϓϦߴ଎Խ"TTFU • Ͳͷϖʔδ΋ڞ௨ͰಡΈࠐΜͰΔେ͖ͳౕ͚ͩ੾Δ • stylesheet_link_tag '...', debug: false • javascript_include_tag

    '...', debug: false • require਺ͱಉ͡਺͚ͩ͋Δscriptλά͕1ͭʹͳΔ • debug: false ʹ͢ΔͱϓϦίϯύΠϧର৅ʹೖ͍ͬͯΔ͔ͳͲ ͷ֬ೝΛͯ͘͠Εͳ͘ͳΔͷͰɺςετͰ֬ೝ͢ΔΑ͏ʹͨ͠ ࢪࡦ2: sprockets-railsͷσόοάػೳΛ੾Δ
  28. 3BJMTΞϓϦߴ଎Խ"TTFU ࢪࡦ2: sprockets-railsͷσόοάػೳΛ੾Δ

  29. 3BJMTΞϓϦߴ଎Խ"TTFU ࢪࡦ2: sprockets-railsͷσόοάػೳΛ੾Δ ։ൃ؀ڥʹ͓͚ΔݕࡧϖʔδͷDOMContentLoaded 4,910ms 3,790ms

  30. 3BJMTΞϓϦߴ଎Խݱঢ় ·ͩ·ͩ஗͍ͷͰվળ͕ඞཁ ։ൃ؀ڥʹ͓͚ΔݕࡧϖʔδͷDOMContentLoaded 10,300ms 3,790ms

  31. ΞηοτϓϦίϯύΠϧ ͳͥ։ൃ؀ڥͷߴ଎Խ ߴ଎ԽͷͨΊʹԿΛ͔ͨ͠ 3BJMTΞϓϦͷ%0.$POUFOU-PBEFE ΞηοτϓϦίϯύΠϧ ฒྻίϯύΠϧ ࠩ෼ίϯύΠϧ MJCTBTTͷಋೖ ຅ΞΠσΞ ߴ଎ԽͷͨΊʹԿΛ͔ͨ͠

  32. Ͳ͕͜஗͍͔ • ֤֦ுࢠʹର͔͔͍ͯͬͯ͠Δ࣌ؒͷ߹ܭΛܭଌ • .css: 71.0% • .js: 22.6% •

    1ճͷίϯύΠϧͰԿʹ࣌ؒΛ࢖͍ͬͯΔ͔ • 70%: sass.gem ΍ execjs.gem (nodejs runtime) • 30%: શΞηοτڞ௨ͷॲཧ (Sprockets)
  33. ΞηοτϓϦίϯύΠϧߴ଎ԽͷτϐοΫ • 1. ฒྻίϯύΠϧ • 2. ࠩ෼ίϯύΠϧ • 3. libsassͷಋೖ

    • 4. ຅ΞΠσΞ
  34. • Sprockets ΁ͷੲ͔Βͷಠࣗύον • parallel.gemͰϚϧνϓϩηείϯύΠϧ • Ωϟογϡ͕ฒྻॲཧʹ଱͑Δ͔ߟ͑Δඞཁ͋Γ • gemԽͯ͠ΔͷΛ࢖͍͍ͨ৔߹ •

    sprockets-derailleur.gem ͱ͍͏ͷ͕͋Δ (ผ෺) ฒྻίϯύΠϧ (@os0x, @mrkn, @eagletmt, @k0kubun)
  35. ฒྻίϯύΠϧ 23෼56ඵ 9෼0ඵ ΞηοτϓϦίϯύΠϧʹ͔͔Δ࣌ؒ

  36. • લճطʹίϯύΠϧࡁΈͷ΋ͷΛ࠶ར༻͢Δ • ௨ৗ௨ΓϑΝΠϧΩϟογϡΛ༗ޮʹͨ͠ • ಠࣗύονͷӨڹͰલճίϯύΠϧ࣌ͷΩϟογϡΛ࢖͏ͱ յΕΔͷͰ࢖Θͳ͘ͳ͍ͬͯͨ • ৽͍͠SprocketsΛݟΔݶΓΩϟογϡͷget/set࣌ʹflock(2) Λ࢖͑͹ಈ͖ͦ͏ͩͬͨͷͰͦ͏ͨ͠

    ࠩ෼ίϯύΠϧ
  37. ࠩ෼ίϯύΠϧ લճ͔Βࠩ෼͕ͳ͍৔߹ 9෼0ඵ 1෼12ඵ ΞηοτϓϦίϯύΠϧʹ͔͔Δ࣌ؒ

  38. • libsass: sassͷC++࣮૷ • sassc-ruby, sassc-rails͔Β࢖͑Δ • Sprockets 4Ͱඪ४αϙʔτ •

    ΄΅sass 3.4ޓ׵ͳͷͰsass 3.4ʹҠߦͰ͖ͯclang͔gcc 4.6 Ҏ্͕࢖͑Ε͹ಈ͘ MJCTBTTͷಋೖ
  39. MJCTBTTͷಋೖ Ωϟογϡͳ͠ͷॳճͷΈ 9෼0ඵ 5෼58ඵ ΞηοτϓϦίϯύΠϧʹ͔͔Δ࣌ؒ

  40. ຅ΞΠσΞ • Ωϟογϡͳ͠Ͱ଎͘͢ΔΞΠσΞ͸·ͩ͋ͬͨ • Sprockets 2 ʹ໭͢ (5෼58ඵ → 3෼14ඵ)

    • Rails 5͕Sprockets 3Ҏ্ཁٻ͖ͯͨ͠ΒࠔΔ • therubyracerΛ࢖͏ (3෼14ඵ → 1෼58ඵ) • Ϗϧυ΍֦ுࣗମ͕ෆ҆ఆͰӡ༻ίετ͕ߴ͍
  41. ΞηοτϓϦίϯύΠϧ࣌ؒͷվળ݁Ռ 23෼56ඵ 1෼12ඵ ΞηοτϓϦίϯύΠϧʹ͔͔Δ࣌ؒ ࠷୹ 5෼58ඵ ࠷௕

  42. ݁࿦ • σϑΥϧτͷઃఆʹ௥ै͠ɺRuby΍gem͸࠷৽ͷ΋ͷΛ࢖ͬͯ ͍Ε͹ී௨͸ࠔΒͳ͍ • ୭͔͕ࠔͬͯupstreamΛ௚͢͠ɺࣗ෼΋ͦ͏͢΂͖ • ͦΕͰ΋Ͳ͏ʹ΋ͳΒͳ͍࣌͸ɺຊ౰ʹඞཁͳ৔ॴʹݶΓࣃΛ ৯͍͠͹ͬͯಛผͳઃఆ΍gemΛಋೖ͢Δ