alexander dymo. how to make your ruby/rails app 10x faster

36
How to make your Ruby/Rails app 10x faster Александр Дымо RubyC www.acunote.com

Upload: svitla-systems-inc

Post on 09-May-2015

1.946 views

Category:

Documents


2 download

TRANSCRIPT

Page 1: Alexander Dymo. How to make your Ruby/Rails app 10x faster

How to make your Ruby/Rails app

10x faster

Александр ДымоRubyC

www.acunote.com

Page 2: Alexander Dymo. How to make your Ruby/Rails app 10x faster

2 / 70

Что не так с Ruby?

Ruby – это медленно!

Page 3: Alexander Dymo. How to make your Ruby/Rails app 10x faster

3 / 70

Что не так с Ruby?

Ruby – это очень медленно!

Page 4: Alexander Dymo. How to make your Ruby/Rails app 10x faster

4 / 70

Что не так с Ruby?

Причины?

Page 5: Alexander Dymo. How to make your Ruby/Rails app 10x faster

5 / 70

Что не так с Ruby?

1. GC (cборка мусора)

Page 6: Alexander Dymo. How to make your Ruby/Rails app 10x faster

6 / 70

Что не так с Ruby?

2. Мелкие неприятности

Page 7: Alexander Dymo. How to make your Ruby/Rails app 10x faster

7 / 70

Что не так с Ruby?

1. GC (cборка мусора)

Page 8: Alexander Dymo. How to make your Ruby/Rails app 10x faster

8 / 70

Garbage Collection

Сборка мусора происходит:

каждые 8 Мб выделенной памяти

выделенная однажды память повторно используется

но никогда не возвращается!

Page 9: Alexander Dymo. How to make your Ruby/Rails app 10x faster

9 / 70

Garbage Collection

в среднем приложении 1 сборка мусора == 100ms

выделяете 1Gb?

- ожидайте 1024/8 = 128 вызовов GC

- потеряете 128 * 0,1 = 12,8 sec!!!

- навсегда оставите себе этот гиг

Page 10: Alexander Dymo. How to make your Ruby/Rails app 10x faster

10 / 70

Garbage Collection

class TestControllerdef index

gc_statistics {#дайте-ка мне гиг памяти!1024.times {

"x"*1024*1024}

}end

end

app.get '/test'> : allocated: 1049602K total in 2052 allocations, GC calls:

146, GC time: 17281 msec

Page 11: Alexander Dymo. How to make your Ruby/Rails app 10x faster

11 / 70

Garbage Collection

Патч, включающий сбор статистики про GC

http://blog.pluron.com/2008/02/memory-profilin.html

Page 12: Alexander Dymo. How to make your Ruby/Rails app 10x faster

12 / 70

Garbage Collection

RUBY_HEAP_MIN_SLOTS=8000000

RUBY_GC_MALLOC_LIMIT=10000

Page 13: Alexander Dymo. How to make your Ruby/Rails app 10x faster

13 / 70

Garbage Collection

Эффект сборки мусора:

GC GC

Tasks 100 (C) 0,54 0,24 2.2х

Sprint 20 x (1+5) (C) 0,46 0,3 1.5х

Copy 120 3,43 2,41 1.4х

Import 71 5,02 3,81 1.3х

Ruby приложение будет в 1.5 - 2 раза медленнее!

"Спасибо" сборщику мусора!

Page 14: Alexander Dymo. How to make your Ruby/Rails app 10x faster

14 / 70

Garbage Collection

Mark & Sweep GC?

Настроить параметры GC?

Почему невовремя?

Почему не то?

Page 15: Alexander Dymo. How to make your Ruby/Rails app 10x faster

15 / 70

Что не так с Ruby?

2. Мелкие неприятности

Page 16: Alexander Dymo. How to make your Ruby/Rails app 10x faster

16 / 70

Что не так с Ruby?

Медленная интерпретация

Page 17: Alexander Dymo. How to make your Ruby/Rails app 10x faster

17 / 70

Медленная интерпретация

Что не так с Date?

> puts Benchmark.realtime { 1000.times { Time.mktime(2009, 5, 6, 0, 0, 0) } }

0.005

> puts Benchmark.realtime { 1000.times { Date.civil(2009, 5, 6) } }

0.080

16x медленнее чем Time! Почему?

%self total self wait child calls name

7.23 0.66 0.18 0.00 0.48 18601 <Class::Rational>#reduce

6.83 0.27 0.17 0.00 0.10 5782 <Class::Date>#jd_to_civil

6.43 0.21 0.16 0.00 0.05 31528 Rational#initialize

5.62 0.23 0.14 0.00 0.09 18601 Integer#gcd

Page 18: Alexander Dymo. How to make your Ruby/Rails app 10x faster

18 / 70

Медленная интерпретация

Исправляем Date: Вася, используй C!

Date::Performance gem с переписанным на С Date

(с) Ryan Tomayko (с моими патчами)

> puts Benchmark.realtime { 1000.times { Time.mktime(2009, 5, 6, 0, 0, 0) } }

0.005

> puts Benchmark.realtime { 1000.times { Date.civil(2009, 5, 6) } }

0.080

> require 'date/performance'

puts Benchmark.realtime { 1000.times { Date.civil(2009, 5, 6) } }

0.006

gem install date-performance

Page 19: Alexander Dymo. How to make your Ruby/Rails app 10x faster

19 / 70

Медленная интерпретация

Влияние Date::Performance:

До: 0.95 sec

После: 0.65 sec

1.5x!

Page 20: Alexander Dymo. How to make your Ruby/Rails app 10x faster

20 / 70

Медленная интерпретация

Используем String::<< вместо String::+=

> long_string = "foo" * 100000

> Benchmark.realtime { long_string += "foo" }

0.0003

> Benchmark.realtime { long_string << "foo" }

0.000004

Избегаем конверсий BigDecimal в строки и числа

> n = BigDecimal("4.5")

> Benchmark.realtime { 10000.times { n <=> 4.5 } }

0.063

> Benchmark.realtime { 10000.times { n <=> BigDecimal("4.5") } }

0.014

in theory: 4.5xin practice: 1.15x

in theory: 75xin practice: up to 70x

Page 21: Alexander Dymo. How to make your Ruby/Rails app 10x faster

21 / 70

Медленная интерпретация

Переписывать на C не такая уж плохая идея:

date-performance

github.com/rtomayko/date-performance

ускоряет операции с датами в 13 раз!

ускоряет приложения в 1.5 раза

monkeysupport

http://github.com/burke/monkeysupport

ActiveSupport переписанный на C

Page 22: Alexander Dymo. How to make your Ruby/Rails app 10x faster

22 / 70

Медленная интерпретация

Переписывать Rails приложение на SQL

тоже неплохая идея:

– иногда ускорение в 5х

– иногда делает возможным то, что невозможно в Ruby

операции над большим кол-вом (1млн) объектов

– детали в моей презентации "Быстрее, Выше, SQL'нее"http://www.slideshare.net/adymo/alexander-dymo-barcamp-2009-faster-higher-sql-2644467

Page 23: Alexander Dymo. How to make your Ruby/Rails app 10x faster

23 / 70

Альтернативные Ruby?

Page 24: Alexander Dymo. How to make your Ruby/Rails app 10x faster

24 / 70

Альтернативные Ruby?

Интерпретация GC

1.8.7EE tmalloc настройки

1.9 VM Lazy GC

jruby JavaVM Java VM GC

rubinius LLVM LLVM GC

Page 25: Alexander Dymo. How to make your Ruby/Rails app 10x faster

25 / 70

Чистая производительность, без GC

Page 26: Alexander Dymo. How to make your Ruby/Rails app 10x faster

26 / 70

Производительность с GC

Page 27: Alexander Dymo. How to make your Ruby/Rails app 10x faster

27 / 70

Влияние настроек

37 Signals:RUBY_HEAP_MIN_SLOTS=600000RUBY_GC_MALLOC_LIMIT=59000000

Page 28: Alexander Dymo. How to make your Ruby/Rails app 10x faster

28 / 70

GC против "без GC"

Page 29: Alexander Dymo. How to make your Ruby/Rails app 10x faster

29 / 70

История

2 года назад сейчас

Page 30: Alexander Dymo. How to make your Ruby/Rails app 10x faster

30 / 70

Инструменты: Производительность

Медленный Ruby

Что делать?

Профилировать с Ruby-Prof

Переписывать на C

Переписывать на SQL

Page 31: Alexander Dymo. How to make your Ruby/Rails app 10x faster

31 / 70

Инструменты: Производительность

Ruby-Prof (http://ruby-prof.rubyforge.org/)

Всегда скажет что не так:

%self total self child calls name 8.39 0.54 0.23 0.31 602 Array#each_index 7.30 0.41 0.20 0.21 1227 Integer#gcd 6.20 0.49 0.17 0.32 5760 Timecell#date 5.11 0.15 0.14 0.01 1 Magick::Image#to_blob

gem install ruby-prof

KCachegrind для визуализации результатов

http://kcachegrind.sourceforge.net

Page 32: Alexander Dymo. How to make your Ruby/Rails app 10x faster

32 / 70

Инструменты: Производительность

Page 33: Alexander Dymo. How to make your Ruby/Rails app 10x faster

33 / 70

Инструменты: Производительность

До какой степени оптимизировать?

Пока не будет так:

%self total self child calls name 1.42 0.39 0.25 0.14 1033 Range#each-1 0.85 0.43 0.15 0.28 2221 Array#each-1 0.74 0.13 0.13 0.00 113447 Array#[] 0.40 0.07 0.07 0.00 5008 Hash#initialize_copy 0.40 0.07 0.07 0.00 45467 Hash#[]= 0.40 0.13 0.07 0.06 37784 Hash#[] 0.17 0.15 0.03 0.12 176 Array#collect 0.17 0.08 0.03 0.05 22371 String#gsub 0.17 0.03 0.03 0.00 44881 Array#<< 0.17 0.03 0.03 0.00 15936 String#== 0.17 0.75 0.03 0.72 1218 Array#each 0.17 0.03 0.03 0.00 37274 PGresult#getvalue 0.11 0.18 0.02 0.16 137 Array#collect! 0.11 0.02 0.02 0.00 3227 User#id

Page 34: Alexander Dymo. How to make your Ruby/Rails app 10x faster

34 / 70

Инструменты: Производительность

Что нужно помнить при профилировке Ruby приложений?

не забывать профилировать память

в среднем приложении 1 сборка мусора == 100ms

выделяете 1Gb?

- ожидайте 1024/8 = 128 вызовов GC

- потеряете 128 * 0,1 = 12,8 sec!!!

Page 35: Alexander Dymo. How to make your Ruby/Rails app 10x faster

35 / 70

Инструменты: Производительность

Что нужно помнить при профилировке Ruby приложений?

выключать GC (GC.disable), иначе можно увидеть:

class Foodef do_smth

return "x" * 1024 # займем 1Kb памятиend

endsmth = "x" * 7999999 # займем почти 8Mb памятиFoo.new.do_smth # здесь произойдет GC

--------------------------%self calls name0.10 1 Foo#do_smth # do_smth такой медленный???0.01 2 String#*

Page 36: Alexander Dymo. How to make your Ruby/Rails app 10x faster

36 / 70

Спасибо за внимание!

Александр ДымоDirector of [email protected]