SlideShare a Scribd company logo
1 of 77
Gotcha!
        Things that will come back to bite you




David Tollmyr, Lead Platform developer
Show of hands
Who?
Who?


Lead platform developer at Burt
Who?


Lead platform developer at Burt
Ad analytics startup
Who?


Lead platform developer at Burt
Ad analytics startup
Real time analytics processing
Who?


Lead platform developer at Burt
Ad analytics startup
Real time analytics processing
~15k requests/s
Who?


Lead platform developer at Burt
Ad analytics startup
Real time analytics processing
~15k requests/s
JRuby 1.6.x, RabbitMQ, MongoDB, Redis,
Cassandra
What?
What?



Experiences learned while building our system
What?



Experiences learned while building our system
Long running application
What?



Experiences learned while building our system
Long running application
One specific task
What?



Experiences learned while building our system
Long running application
One specific task
Thousands of times per second
What?



Experiences learned while building our system
Long running application
One specific task
Thousands of times per second
Strings
Strings

“this creates a new string”
Strings

“this creates a new string”
String.new(“this creates a new
string”)
Strings

“this creates a new string”
String.new(“this creates a new
string”)

1_000_000.times do
 hash[“string_key”] += 1
end
Strings




string     2.107s
constant   1.730s   -0.377s
symbol     1.693s   -0.414s
int        1.197s   -0.91s
Strings

KEY = “string_key”.freeze
1_000_000.times do
 hash[KEY] += 1
end


string        2.107s
constant      1.730s        -0.377s
symbol        1.693s        -0.414s
int           1.197s        -0.91s
Strings

-verbose:gc
[GC   419456K->21351K(6239040K),   0.0497610   secs]
[GC   440807K->31195K(6239040K),   0.0349782   secs]
[GC   450651K->37050K(6239040K),   0.0297697   secs]
[GC   456506K->26561K(6239040K),   0.0304456   secs]
[GC   446017K->38585K(6239040K),   0.1181651   secs]
[GC   458041K->29042K(6239040K),   0.0050885   secs]
[GC   448498K->25417K(6239040K),   0.0047236   secs]
[GC   444873K->24514K(6239040K),   0.0048243   secs]
[GC   443970K->24288K(6239040K),   0.0049824   secs]
[GC   443744K->24241K(6239040K),   0.0046804   secs]
[GC   443697K->24241K(6239040K),   0.0048907   secs]
[GC   443697K->24239K(6239040K),   0.0046102   secs]
[GC   443695K->24243K(6239040K),   0.0049074   secs]
[GC   443699K->24242K(6239040K),   0.0045477   secs]
[GC   443698K->24242K(6239040K),   0.0051179   secs]
[GC   443698K->24246K(6239040K),   0.0049280   secs]
[GC   443702K->24250K(6239040K),   0.0050470   secs]
[GC   443706K->24251K(6239040K),   0.0050648   secs]
[GC   443707K->24255K(6239040K),   0.0048519   secs]
[GC   443711K->24254K(6239040K),   0.0044326   secs]
[GC   443710K->24257K(6239040K),   0.0048402   secs]
[GC   443713K->24259K(6239040K),   0.0051717   secs]
[GC   443715K->24263K(6239040K),   0.0048119   secs]
[GC   443719K->24263K(6239040K),   0.0043401   secs]
[GC   443719K->24267K(6239040K),   0.0054948   secs]
[GC   443723K->24266K(6239040K),   0.0045278   secs]
[GC   443722K->24269K(6239040K),   0.0051420   secs]
[GC   443725K->24271K(6239040K),   0.0044680   secs]
[GC   443727K->24273K(6239040K),   0.0049075   secs]
[GC   443729K->24274K(6239040K),   0.0042977   secs]
Strings
Strings
Array.join
Array.join

data = [“NS”, :key, “site”, 1, nil]
key = data.join(“/”)
#=> “NS/key/site/1/”
Array.join

data = [“NS”, :key, “site”, 1, nil]
key = data.join(“/”)
#=> “NS/key/site/1/”

self        calls method
-----------------------------------
0.35         1000 Array#join
8.11       101000 BasicObject#method_missing
0.07       201000 Kernel#respond_to?
0.04       101000 NoMethodError#initialize
0.02       100000 Symbol#to_s
0.02       201000 Kernel#respond_to_missing?
Array.join

data = [“NS”, :key, “site”, 1, nil]
key = data.join(“/”)
#=> “NS/key/site/1/”

self        calls method
-----------------------------------
0.35         1000 Array#join
8.11       101000 BasicObject#method_missing
0.07       201000 Kernel#respond_to?
0.04       101000 NoMethodError#initialize
0.02       100000 Symbol#to_s
0.02       201000 Kernel#respond_to_missing?



Array.join uses to_str, not to_s
Array.join

Joining an array of 1 000 entries, 10 000 times
strings        0.771s
symbols        3.171s     +2.4s
int            6.588s     +5.817s
Array.join

Joining an array of 1 000 entries, 10 000 times
strings        0.771s
symbols        3.171s     +2.4s
int            6.588s     +5.817s

class Symbol/Numeric/NilClass
  alias_method :to_str, :to_s
end
Array.join

Joining an array of 1 000 entries, 10 000 times
strings        0.771s
symbols        3.171s     +2.4s
int            6.588s     +5.817s

class Symbol/Numeric/NilClass
  alias_method :to_str, :to_s
end

strings       0.771s
symbols       1.781s     +1.01s    (-1.39s)
int           5.484s     +4.713s   (-1.104s)
Array.join

  Struct.new("Customer", :name, :address)
customer = Struct::Customer.new("Dave", "123 Main")
customer.name, customer.address

Customer = Struct.new(:name, :address)
customer = Customer.new("Dave", "123 Main")
Array.join

  Struct.new("Customer", :name, :address)
customer = Struct::Customer.new("Dave", "123 Main")
customer.name, customer.address

Customer = Struct.new(:name, :address)
customer = Customer.new("Dave", "123 Main")




NameError: identifier name needs to be constant
	   from org/jruby/RubyStruct.java:210:in `new'
Array.join

Joining an array of 1 000 entries, 10 000 times
strings        0.771s
symbols        3.171s     +2.4s
int            6.588s     +5.817s
Array.join

Joining an array of 1 000 entries, 10 000 times
strings        0.771s
symbols        3.171s     +2.4s
int            6.588s     +5.817s


data.map(&:to_s).join(“/”)
Array.join

Joining an array of 1 000 entries, 10 000 times
strings        0.771s
symbols        3.171s     +2.4s
int            6.588s     +5.817s


data.map(&:to_s).join(“/”)


strings     0.771
symbols     2.242    +1.471s    (-0.929s)
int         5.638    +4.867s    (-0.95s)
Queues
Queues
Queues

Internal FIFO queue using an array
Queues

Internal FIFO queue using an array
Putting data with shift/push or pop/unshift
Queues

Internal FIFO queue using an array
Putting data with shift/push or pop/unshift



Alternatives:
Queues

Internal FIFO queue using an array
Putting data with shift/push or pop/unshift



Alternatives:
Fixed size array with sweeping index
Queues

Internal FIFO queue using an array
Putting data with shift/push or pop/unshift



Alternatives:
Fixed size array with sweeping index
LinkedList
Queues

Internal FIFO queue using an array
Putting data with shift/push or pop/unshift



Alternatives:
Fixed size array with sweeping index
LinkedList
LinkedBlockingQueue
Queues

Sweeping index


   Start         End
Queues

Sweeping index


      Start      End
Queues

Sweeping index


 End   Start
Queues
queue = Queue.new(size)
100_000.times do |i|
  data = queue.pop
  queue.push(i)
end

Queue(1_000)
array        0.065s
index        0.030s
LinkedList 0.056s
Queues
queue = Queue.new(size)
100_000.times do |i|
  data = queue.pop
  queue.push(i)
end

Queue(1_000)
array        0.065s
index        0.030s
LinkedList 0.056s

Queue(100_000)
array       3.996s        85 times slower
index       0.047s
LinkedList 0.137s
Queues
queue = Queue.new(size)
100_000.times do |i|
  data = queue.pop
  queue.push(i)
end

Queue(1_000)
array        0.065s
index        0.030s
LinkedList 0.056s

Queue(100_000)
array       3.996s        85 times slower
index       0.047s
LinkedList 0.137s

Queue(1_000_000)
array      53.895s        216 times slower!
index       0.249s
LinkedList 0.847s
Concurrency
Concurrency
Concurrency

Use a thread pool (ie
java.util.concurrent.Executors)
Concurrency

Use a thread pool (ie

java_import java.util.concurrent.Executors

executor = Executors.newFixedThreadPool(2)
10.times do
  executor.submit do
    # do stuff
  end
end
Concurrency

Use a thread pool (ie
java.util.concurrent.Executors)
Ruby’s Mutex? You’re doing it wrong
Concurrency

Use a thread pool (ie
java.util.concurrent.Executors)
Ruby’s Mutex? You’re doing it wrong
 java.util.concurrent is your friend
Concurrency

Use a thread pool (ie
java.util.concurrent.Executors)
Ruby’s Mutex? You’re doing it wrong
 java.util.concurrent is your friend
 AtomicInteger, ConcurrentHashMap,
 LinkedBlockingQueue
Concurrency

Use a thread pool (ie
java.util.concurrent.Executors)
Ruby’s Mutex? You’re doing it wrong
 java.util.concurrent is your friend
 AtomicInteger, ConcurrentHashMap,
 LinkedBlockingQueue
 Lock, Semaphore, CountdownLatch - IF you have to!
Some more, just because
Other stuff to keep in mind
Other stuff to keep in mind

Shelling out is significantly slower in JRuby
Other stuff to keep in mind

Shelling out is significantly slower in JRuby
 `mkdir -p /some/path/deep/1`
Other stuff to keep in mind

Shelling out is significantly slower in JRuby
 `mkdir -p /some/path/deep/1`
 rake, capistrano, bundle exec
Other stuff to keep in mind

Shelling out is significantly slower in JRuby
 `mkdir -p /some/path/deep/1`
 rake, capistrano, bundle exec
 There’s almost always a way of doing it without shelling
Other stuff to keep in mind

Shelling out is significantly slower in JRuby
 `mkdir -p /some/path/deep/1`
 rake, capistrano, bundle exec
 There’s almost always a way of doing it without shelling
Don’t pass binary RubyString to Java
Other stuff to keep in mind

Shelling out is significantly slower in JRuby
 `mkdir -p /some/path/deep/1`
 rake, capistrano, bundle exec
 There’s almost always a way of doing it without shelling
Don’t pass binary RubyString to Java
 Example: Hot_bunnies (JRuby RabbitMQ gem)
Other stuff to keep in mind

Shelling out is significantly slower in JRuby
 `mkdir -p /some/path/deep/1`
 rake, capistrano, bundle exec
 There’s almost always a way of doing it without shelling
Don’t pass binary RubyString to Java
 Example: Hot_bunnies (JRuby RabbitMQ gem)
 Serialized data -> Ruby -> Java -> Network -> Java ->
 Ruby
Other stuff to keep in mind

Shelling out is significantly slower in JRuby
 `mkdir -p /some/path/deep/1`
 rake, capistrano, bundle exec
 There’s almost always a way of doing it without shelling
Don’t pass binary RubyString to Java
 Example: Hot_bunnies (JRuby RabbitMQ gem)
 Serialized data -> Ruby -> Java -> Network -> Java ->
 Ruby
 String#to_java_bytes / String.from_java_bytes
Conclusion
Conclusion
Conclusion

Beware of unnecessary string creation
Conclusion

Beware of unnecessary string creation
Watch out for array.join with non-string objects
Conclusion

Beware of unnecessary string creation
Watch out for array.join with non-string objects
Don’t shift/unshift large arrays
Conclusion

Beware of unnecessary string creation
Watch out for array.join with non-string objects
Don’t shift/unshift large arrays
java.util.concurrent is your friend!
Conclusion

Beware of unnecessary string creation
Watch out for array.join with non-string objects
Don’t shift/unshift large arrays
java.util.concurrent is your friend!
Don’t shell if you don’t have to
Conclusion

Beware of unnecessary string creation
Watch out for array.join with non-string objects
Don’t shift/unshift large arrays
java.util.concurrent is your friend!
Don’t shell if you don’t have to
Remember String#to_java_bytes
We’re hiring!



david@burtcorp.com
      @effata
    burtcorp.com
Thank you



david@burtcorp.com
      @effata
    burtcorp.com

More Related Content

What's hot

Heap Hand note
Heap Hand noteHeap Hand note
Heap Hand noteAbdur Rouf
 
Parallel Computing With Dask - PyDays 2017
Parallel Computing With Dask - PyDays 2017Parallel Computing With Dask - PyDays 2017
Parallel Computing With Dask - PyDays 2017Christian Aichinger
 
The Ring programming language version 1.5.1 book - Part 44 of 180
The Ring programming language version 1.5.1 book - Part 44 of 180The Ring programming language version 1.5.1 book - Part 44 of 180
The Ring programming language version 1.5.1 book - Part 44 of 180Mahmoud Samir Fayed
 
اسلاید اول جلسه چهارم کلاس پایتون برای هکرهای قانونی
اسلاید اول جلسه چهارم کلاس پایتون برای هکرهای قانونیاسلاید اول جلسه چهارم کلاس پایتون برای هکرهای قانونی
اسلاید اول جلسه چهارم کلاس پایتون برای هکرهای قانونیMohammad Reza Kamalifard
 
Python chapter 2
Python chapter 2Python chapter 2
Python chapter 2Raghu nath
 
python chapter 1
python chapter 1python chapter 1
python chapter 1Raghu nath
 
Analyzing the Performance Effects of Meltdown + Spectre on Apache Spark Workl...
Analyzing the Performance Effects of Meltdown + Spectre on Apache Spark Workl...Analyzing the Performance Effects of Meltdown + Spectre on Apache Spark Workl...
Analyzing the Performance Effects of Meltdown + Spectre on Apache Spark Workl...Databricks
 
2015 11-17-programming inr.key
2015 11-17-programming inr.key2015 11-17-programming inr.key
2015 11-17-programming inr.keyYannick Wurm
 
Introduction to Apache Spark / PUT 06.2014
Introduction to Apache Spark / PUT 06.2014Introduction to Apache Spark / PUT 06.2014
Introduction to Apache Spark / PUT 06.2014bbogacki
 
Data Wars: The Bloody Enterprise strikes back
Data Wars: The Bloody Enterprise strikes backData Wars: The Bloody Enterprise strikes back
Data Wars: The Bloody Enterprise strikes backVictor_Cr
 
Crushing the Head of the Snake by Robert Brewer PyData SV 2014
Crushing the Head of the Snake by Robert Brewer PyData SV 2014Crushing the Head of the Snake by Robert Brewer PyData SV 2014
Crushing the Head of the Snake by Robert Brewer PyData SV 2014PyData
 
Wrangle 2016: (Lightning Talk) FizzBuzz in TensorFlow
Wrangle 2016: (Lightning Talk) FizzBuzz in TensorFlowWrangle 2016: (Lightning Talk) FizzBuzz in TensorFlow
Wrangle 2016: (Lightning Talk) FizzBuzz in TensorFlowWrangleConf
 

What's hot (20)

Python tutorial
Python tutorialPython tutorial
Python tutorial
 
Heap Hand note
Heap Hand noteHeap Hand note
Heap Hand note
 
Parallel Computing With Dask - PyDays 2017
Parallel Computing With Dask - PyDays 2017Parallel Computing With Dask - PyDays 2017
Parallel Computing With Dask - PyDays 2017
 
Five
FiveFive
Five
 
The Ring programming language version 1.5.1 book - Part 44 of 180
The Ring programming language version 1.5.1 book - Part 44 of 180The Ring programming language version 1.5.1 book - Part 44 of 180
The Ring programming language version 1.5.1 book - Part 44 of 180
 
R part iii
R part iiiR part iii
R part iii
 
اسلاید اول جلسه چهارم کلاس پایتون برای هکرهای قانونی
اسلاید اول جلسه چهارم کلاس پایتون برای هکرهای قانونیاسلاید اول جلسه چهارم کلاس پایتون برای هکرهای قانونی
اسلاید اول جلسه چهارم کلاس پایتون برای هکرهای قانونی
 
Python chapter 2
Python chapter 2Python chapter 2
Python chapter 2
 
python chapter 1
python chapter 1python chapter 1
python chapter 1
 
Analyzing the Performance Effects of Meltdown + Spectre on Apache Spark Workl...
Analyzing the Performance Effects of Meltdown + Spectre on Apache Spark Workl...Analyzing the Performance Effects of Meltdown + Spectre on Apache Spark Workl...
Analyzing the Performance Effects of Meltdown + Spectre on Apache Spark Workl...
 
2015 11-17-programming inr.key
2015 11-17-programming inr.key2015 11-17-programming inr.key
2015 11-17-programming inr.key
 
Spock and Geb in Action
Spock and Geb in ActionSpock and Geb in Action
Spock and Geb in Action
 
FNT 2015 PDIS CodeEU - Zanimljiva informatika - 02 Djordje Pavlovic - Live_ch...
FNT 2015 PDIS CodeEU - Zanimljiva informatika - 02 Djordje Pavlovic - Live_ch...FNT 2015 PDIS CodeEU - Zanimljiva informatika - 02 Djordje Pavlovic - Live_ch...
FNT 2015 PDIS CodeEU - Zanimljiva informatika - 02 Djordje Pavlovic - Live_ch...
 
Introduction to Apache Spark / PUT 06.2014
Introduction to Apache Spark / PUT 06.2014Introduction to Apache Spark / PUT 06.2014
Introduction to Apache Spark / PUT 06.2014
 
Data Wars: The Bloody Enterprise strikes back
Data Wars: The Bloody Enterprise strikes backData Wars: The Bloody Enterprise strikes back
Data Wars: The Bloody Enterprise strikes back
 
Crushing the Head of the Snake by Robert Brewer PyData SV 2014
Crushing the Head of the Snake by Robert Brewer PyData SV 2014Crushing the Head of the Snake by Robert Brewer PyData SV 2014
Crushing the Head of the Snake by Robert Brewer PyData SV 2014
 
Wrangle 2016: (Lightning Talk) FizzBuzz in TensorFlow
Wrangle 2016: (Lightning Talk) FizzBuzz in TensorFlowWrangle 2016: (Lightning Talk) FizzBuzz in TensorFlow
Wrangle 2016: (Lightning Talk) FizzBuzz in TensorFlow
 
Finding Clojure
Finding ClojureFinding Clojure
Finding Clojure
 
Hanya contoh saja dari xampp
Hanya contoh saja dari xamppHanya contoh saja dari xampp
Hanya contoh saja dari xampp
 
Quick Wins
Quick WinsQuick Wins
Quick Wins
 

Similar to Gotcha! Ruby things that will come back to bite you.

Troubleshooting JIRA & Confluence
Troubleshooting JIRA & ConfluenceTroubleshooting JIRA & Confluence
Troubleshooting JIRA & ConfluenceAtlassian
 
Analytics at Speed: Introduction to ClickHouse and Common Use Cases. By Mikha...
Analytics at Speed: Introduction to ClickHouse and Common Use Cases. By Mikha...Analytics at Speed: Introduction to ClickHouse and Common Use Cases. By Mikha...
Analytics at Speed: Introduction to ClickHouse and Common Use Cases. By Mikha...Altinity Ltd
 
Beyond PHP - it's not (just) about the code
Beyond PHP - it's not (just) about the codeBeyond PHP - it's not (just) about the code
Beyond PHP - it's not (just) about the codeWim Godden
 
New SPL Features in PHP 5.3 (TEK-X)
New SPL Features in PHP 5.3 (TEK-X)New SPL Features in PHP 5.3 (TEK-X)
New SPL Features in PHP 5.3 (TEK-X)Matthew Turland
 
CSS parsing: performance tips & tricks
CSS parsing: performance tips & tricksCSS parsing: performance tips & tricks
CSS parsing: performance tips & tricksRoman Dvornov
 
The Ring programming language version 1.6 book - Part 42 of 189
The Ring programming language version 1.6 book - Part 42 of 189The Ring programming language version 1.6 book - Part 42 of 189
The Ring programming language version 1.6 book - Part 42 of 189Mahmoud Samir Fayed
 
Beyond php - it's not (just) about the code
Beyond php - it's not (just) about the codeBeyond php - it's not (just) about the code
Beyond php - it's not (just) about the codeWim Godden
 
fog or: How I Learned to Stop Worrying and Love the Cloud
fog or: How I Learned to Stop Worrying and Love the Cloudfog or: How I Learned to Stop Worrying and Love the Cloud
fog or: How I Learned to Stop Worrying and Love the CloudWesley Beary
 
Distributed load testing with K6 - NDC London 2024
Distributed load testing with K6 - NDC London 2024Distributed load testing with K6 - NDC London 2024
Distributed load testing with K6 - NDC London 2024Thijs Feryn
 
Distributed Load Testing with k6 - DevOps Barcelona
Distributed Load Testing with k6 - DevOps BarcelonaDistributed Load Testing with k6 - DevOps Barcelona
Distributed Load Testing with k6 - DevOps BarcelonaThijs Feryn
 
fog or: How I Learned to Stop Worrying and Love the Cloud (OpenStack Edition)
fog or: How I Learned to Stop Worrying and Love the Cloud (OpenStack Edition)fog or: How I Learned to Stop Worrying and Love the Cloud (OpenStack Edition)
fog or: How I Learned to Stop Worrying and Love the Cloud (OpenStack Edition)Wesley Beary
 
Beyond php - it's not (just) about the code
Beyond php - it's not (just) about the codeBeyond php - it's not (just) about the code
Beyond php - it's not (just) about the codeWim Godden
 
Top k string similarity search
Top k string similarity searchTop k string similarity search
Top k string similarity searchChiao-Meng Huang
 
Prometheus – Storage
Prometheus – StoragePrometheus – Storage
Prometheus – Storagefabxc
 
An introduction to Deep Learning with Apache MXNet (November 2017)
An introduction to Deep Learning with Apache MXNet (November 2017)An introduction to Deep Learning with Apache MXNet (November 2017)
An introduction to Deep Learning with Apache MXNet (November 2017)Julien SIMON
 
Weather of the Century: Design and Performance
Weather of the Century: Design and PerformanceWeather of the Century: Design and Performance
Weather of the Century: Design and PerformanceMongoDB
 
Spark And Cassandra: 2 Fast, 2 Furious
Spark And Cassandra: 2 Fast, 2 FuriousSpark And Cassandra: 2 Fast, 2 Furious
Spark And Cassandra: 2 Fast, 2 FuriousJen Aman
 

Similar to Gotcha! Ruby things that will come back to bite you. (20)

Load Data Fast!
Load Data Fast!Load Data Fast!
Load Data Fast!
 
Troubleshooting JIRA & Confluence
Troubleshooting JIRA & ConfluenceTroubleshooting JIRA & Confluence
Troubleshooting JIRA & Confluence
 
Analytics at Speed: Introduction to ClickHouse and Common Use Cases. By Mikha...
Analytics at Speed: Introduction to ClickHouse and Common Use Cases. By Mikha...Analytics at Speed: Introduction to ClickHouse and Common Use Cases. By Mikha...
Analytics at Speed: Introduction to ClickHouse and Common Use Cases. By Mikha...
 
Beyond PHP - it's not (just) about the code
Beyond PHP - it's not (just) about the codeBeyond PHP - it's not (just) about the code
Beyond PHP - it's not (just) about the code
 
New SPL Features in PHP 5.3 (TEK-X)
New SPL Features in PHP 5.3 (TEK-X)New SPL Features in PHP 5.3 (TEK-X)
New SPL Features in PHP 5.3 (TEK-X)
 
Solr @ Etsy - Apache Lucene Eurocon
Solr @ Etsy - Apache Lucene EuroconSolr @ Etsy - Apache Lucene Eurocon
Solr @ Etsy - Apache Lucene Eurocon
 
CSS parsing: performance tips & tricks
CSS parsing: performance tips & tricksCSS parsing: performance tips & tricks
CSS parsing: performance tips & tricks
 
The Ring programming language version 1.6 book - Part 42 of 189
The Ring programming language version 1.6 book - Part 42 of 189The Ring programming language version 1.6 book - Part 42 of 189
The Ring programming language version 1.6 book - Part 42 of 189
 
Beyond php - it's not (just) about the code
Beyond php - it's not (just) about the codeBeyond php - it's not (just) about the code
Beyond php - it's not (just) about the code
 
fog or: How I Learned to Stop Worrying and Love the Cloud
fog or: How I Learned to Stop Worrying and Love the Cloudfog or: How I Learned to Stop Worrying and Love the Cloud
fog or: How I Learned to Stop Worrying and Love the Cloud
 
Distributed load testing with K6 - NDC London 2024
Distributed load testing with K6 - NDC London 2024Distributed load testing with K6 - NDC London 2024
Distributed load testing with K6 - NDC London 2024
 
Distributed Load Testing with k6 - DevOps Barcelona
Distributed Load Testing with k6 - DevOps BarcelonaDistributed Load Testing with k6 - DevOps Barcelona
Distributed Load Testing with k6 - DevOps Barcelona
 
fog or: How I Learned to Stop Worrying and Love the Cloud (OpenStack Edition)
fog or: How I Learned to Stop Worrying and Love the Cloud (OpenStack Edition)fog or: How I Learned to Stop Worrying and Love the Cloud (OpenStack Edition)
fog or: How I Learned to Stop Worrying and Love the Cloud (OpenStack Edition)
 
Beyond php - it's not (just) about the code
Beyond php - it's not (just) about the codeBeyond php - it's not (just) about the code
Beyond php - it's not (just) about the code
 
ScalaBlitz
ScalaBlitzScalaBlitz
ScalaBlitz
 
Top k string similarity search
Top k string similarity searchTop k string similarity search
Top k string similarity search
 
Prometheus – Storage
Prometheus – StoragePrometheus – Storage
Prometheus – Storage
 
An introduction to Deep Learning with Apache MXNet (November 2017)
An introduction to Deep Learning with Apache MXNet (November 2017)An introduction to Deep Learning with Apache MXNet (November 2017)
An introduction to Deep Learning with Apache MXNet (November 2017)
 
Weather of the Century: Design and Performance
Weather of the Century: Design and PerformanceWeather of the Century: Design and Performance
Weather of the Century: Design and Performance
 
Spark And Cassandra: 2 Fast, 2 Furious
Spark And Cassandra: 2 Fast, 2 FuriousSpark And Cassandra: 2 Fast, 2 Furious
Spark And Cassandra: 2 Fast, 2 Furious
 

Recently uploaded

The Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxThe Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxMalak Abu Hammad
 
Understanding the Laravel MVC Architecture
Understanding the Laravel MVC ArchitectureUnderstanding the Laravel MVC Architecture
Understanding the Laravel MVC ArchitecturePixlogix Infotech
 
Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024BookNet Canada
 
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Drew Madelung
 
CNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of ServiceCNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of Servicegiselly40
 
Salesforce Community Group Quito, Salesforce 101
Salesforce Community Group Quito, Salesforce 101Salesforce Community Group Quito, Salesforce 101
Salesforce Community Group Quito, Salesforce 101Paola De la Torre
 
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationFrom Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationSafe Software
 
A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)Gabriella Davis
 
Unblocking The Main Thread Solving ANRs and Frozen Frames
Unblocking The Main Thread Solving ANRs and Frozen FramesUnblocking The Main Thread Solving ANRs and Frozen Frames
Unblocking The Main Thread Solving ANRs and Frozen FramesSinan KOZAK
 
Injustice - Developers Among Us (SciFiDevCon 2024)
Injustice - Developers Among Us (SciFiDevCon 2024)Injustice - Developers Among Us (SciFiDevCon 2024)
Injustice - Developers Among Us (SciFiDevCon 2024)Allon Mureinik
 
The Evolution of Money: Digital Transformation and CBDCs in Central Banking
The Evolution of Money: Digital Transformation and CBDCs in Central BankingThe Evolution of Money: Digital Transformation and CBDCs in Central Banking
The Evolution of Money: Digital Transformation and CBDCs in Central BankingSelcen Ozturkcan
 
Presentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreterPresentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreternaman860154
 
SQL Database Design For Developers at php[tek] 2024
SQL Database Design For Developers at php[tek] 2024SQL Database Design For Developers at php[tek] 2024
SQL Database Design For Developers at php[tek] 2024Scott Keck-Warren
 
How to convert PDF to text with Nanonets
How to convert PDF to text with NanonetsHow to convert PDF to text with Nanonets
How to convert PDF to text with Nanonetsnaman860154
 
Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024The Digital Insurer
 
A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024Results
 
Histor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slideHistor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slidevu2urc
 
IAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsIAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsEnterprise Knowledge
 
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhi
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | DelhiFULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhi
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhisoniya singh
 
The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024Rafal Los
 

Recently uploaded (20)

The Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxThe Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptx
 
Understanding the Laravel MVC Architecture
Understanding the Laravel MVC ArchitectureUnderstanding the Laravel MVC Architecture
Understanding the Laravel MVC Architecture
 
Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
 
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
 
CNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of ServiceCNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of Service
 
Salesforce Community Group Quito, Salesforce 101
Salesforce Community Group Quito, Salesforce 101Salesforce Community Group Quito, Salesforce 101
Salesforce Community Group Quito, Salesforce 101
 
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationFrom Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
 
A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)
 
Unblocking The Main Thread Solving ANRs and Frozen Frames
Unblocking The Main Thread Solving ANRs and Frozen FramesUnblocking The Main Thread Solving ANRs and Frozen Frames
Unblocking The Main Thread Solving ANRs and Frozen Frames
 
Injustice - Developers Among Us (SciFiDevCon 2024)
Injustice - Developers Among Us (SciFiDevCon 2024)Injustice - Developers Among Us (SciFiDevCon 2024)
Injustice - Developers Among Us (SciFiDevCon 2024)
 
The Evolution of Money: Digital Transformation and CBDCs in Central Banking
The Evolution of Money: Digital Transformation and CBDCs in Central BankingThe Evolution of Money: Digital Transformation and CBDCs in Central Banking
The Evolution of Money: Digital Transformation and CBDCs in Central Banking
 
Presentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreterPresentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreter
 
SQL Database Design For Developers at php[tek] 2024
SQL Database Design For Developers at php[tek] 2024SQL Database Design For Developers at php[tek] 2024
SQL Database Design For Developers at php[tek] 2024
 
How to convert PDF to text with Nanonets
How to convert PDF to text with NanonetsHow to convert PDF to text with Nanonets
How to convert PDF to text with Nanonets
 
Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024
 
A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024
 
Histor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slideHistor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slide
 
IAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsIAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI Solutions
 
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhi
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | DelhiFULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhi
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhi
 
The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024
 

Gotcha! Ruby things that will come back to bite you.

  • 1. Gotcha! Things that will come back to bite you David Tollmyr, Lead Platform developer
  • 5. Who? Lead platform developer at Burt Ad analytics startup
  • 6. Who? Lead platform developer at Burt Ad analytics startup Real time analytics processing
  • 7. Who? Lead platform developer at Burt Ad analytics startup Real time analytics processing ~15k requests/s
  • 8. Who? Lead platform developer at Burt Ad analytics startup Real time analytics processing ~15k requests/s JRuby 1.6.x, RabbitMQ, MongoDB, Redis, Cassandra
  • 10. What? Experiences learned while building our system
  • 11. What? Experiences learned while building our system Long running application
  • 12. What? Experiences learned while building our system Long running application One specific task
  • 13. What? Experiences learned while building our system Long running application One specific task Thousands of times per second
  • 14. What? Experiences learned while building our system Long running application One specific task Thousands of times per second
  • 16. Strings “this creates a new string”
  • 17. Strings “this creates a new string” String.new(“this creates a new string”)
  • 18. Strings “this creates a new string” String.new(“this creates a new string”) 1_000_000.times do hash[“string_key”] += 1 end
  • 19. Strings string 2.107s constant 1.730s -0.377s symbol 1.693s -0.414s int 1.197s -0.91s
  • 20. Strings KEY = “string_key”.freeze 1_000_000.times do hash[KEY] += 1 end string 2.107s constant 1.730s -0.377s symbol 1.693s -0.414s int 1.197s -0.91s
  • 21. Strings -verbose:gc [GC 419456K->21351K(6239040K), 0.0497610 secs] [GC 440807K->31195K(6239040K), 0.0349782 secs] [GC 450651K->37050K(6239040K), 0.0297697 secs] [GC 456506K->26561K(6239040K), 0.0304456 secs] [GC 446017K->38585K(6239040K), 0.1181651 secs] [GC 458041K->29042K(6239040K), 0.0050885 secs] [GC 448498K->25417K(6239040K), 0.0047236 secs] [GC 444873K->24514K(6239040K), 0.0048243 secs] [GC 443970K->24288K(6239040K), 0.0049824 secs] [GC 443744K->24241K(6239040K), 0.0046804 secs] [GC 443697K->24241K(6239040K), 0.0048907 secs] [GC 443697K->24239K(6239040K), 0.0046102 secs] [GC 443695K->24243K(6239040K), 0.0049074 secs] [GC 443699K->24242K(6239040K), 0.0045477 secs] [GC 443698K->24242K(6239040K), 0.0051179 secs] [GC 443698K->24246K(6239040K), 0.0049280 secs] [GC 443702K->24250K(6239040K), 0.0050470 secs] [GC 443706K->24251K(6239040K), 0.0050648 secs] [GC 443707K->24255K(6239040K), 0.0048519 secs] [GC 443711K->24254K(6239040K), 0.0044326 secs] [GC 443710K->24257K(6239040K), 0.0048402 secs] [GC 443713K->24259K(6239040K), 0.0051717 secs] [GC 443715K->24263K(6239040K), 0.0048119 secs] [GC 443719K->24263K(6239040K), 0.0043401 secs] [GC 443719K->24267K(6239040K), 0.0054948 secs] [GC 443723K->24266K(6239040K), 0.0045278 secs] [GC 443722K->24269K(6239040K), 0.0051420 secs] [GC 443725K->24271K(6239040K), 0.0044680 secs] [GC 443727K->24273K(6239040K), 0.0049075 secs] [GC 443729K->24274K(6239040K), 0.0042977 secs]
  • 25. Array.join data = [“NS”, :key, “site”, 1, nil] key = data.join(“/”) #=> “NS/key/site/1/”
  • 26. Array.join data = [“NS”, :key, “site”, 1, nil] key = data.join(“/”) #=> “NS/key/site/1/” self calls method ----------------------------------- 0.35 1000 Array#join 8.11 101000 BasicObject#method_missing 0.07 201000 Kernel#respond_to? 0.04 101000 NoMethodError#initialize 0.02 100000 Symbol#to_s 0.02 201000 Kernel#respond_to_missing?
  • 27. Array.join data = [“NS”, :key, “site”, 1, nil] key = data.join(“/”) #=> “NS/key/site/1/” self calls method ----------------------------------- 0.35 1000 Array#join 8.11 101000 BasicObject#method_missing 0.07 201000 Kernel#respond_to? 0.04 101000 NoMethodError#initialize 0.02 100000 Symbol#to_s 0.02 201000 Kernel#respond_to_missing? Array.join uses to_str, not to_s
  • 28. Array.join Joining an array of 1 000 entries, 10 000 times strings 0.771s symbols 3.171s +2.4s int 6.588s +5.817s
  • 29. Array.join Joining an array of 1 000 entries, 10 000 times strings 0.771s symbols 3.171s +2.4s int 6.588s +5.817s class Symbol/Numeric/NilClass alias_method :to_str, :to_s end
  • 30. Array.join Joining an array of 1 000 entries, 10 000 times strings 0.771s symbols 3.171s +2.4s int 6.588s +5.817s class Symbol/Numeric/NilClass alias_method :to_str, :to_s end strings 0.771s symbols 1.781s +1.01s (-1.39s) int 5.484s +4.713s (-1.104s)
  • 31. Array.join Struct.new("Customer", :name, :address) customer = Struct::Customer.new("Dave", "123 Main") customer.name, customer.address Customer = Struct.new(:name, :address) customer = Customer.new("Dave", "123 Main")
  • 32. Array.join Struct.new("Customer", :name, :address) customer = Struct::Customer.new("Dave", "123 Main") customer.name, customer.address Customer = Struct.new(:name, :address) customer = Customer.new("Dave", "123 Main") NameError: identifier name needs to be constant from org/jruby/RubyStruct.java:210:in `new'
  • 33. Array.join Joining an array of 1 000 entries, 10 000 times strings 0.771s symbols 3.171s +2.4s int 6.588s +5.817s
  • 34. Array.join Joining an array of 1 000 entries, 10 000 times strings 0.771s symbols 3.171s +2.4s int 6.588s +5.817s data.map(&:to_s).join(“/”)
  • 35. Array.join Joining an array of 1 000 entries, 10 000 times strings 0.771s symbols 3.171s +2.4s int 6.588s +5.817s data.map(&:to_s).join(“/”) strings 0.771 symbols 2.242 +1.471s (-0.929s) int 5.638 +4.867s (-0.95s)
  • 38. Queues Internal FIFO queue using an array
  • 39. Queues Internal FIFO queue using an array Putting data with shift/push or pop/unshift
  • 40. Queues Internal FIFO queue using an array Putting data with shift/push or pop/unshift Alternatives:
  • 41. Queues Internal FIFO queue using an array Putting data with shift/push or pop/unshift Alternatives: Fixed size array with sweeping index
  • 42. Queues Internal FIFO queue using an array Putting data with shift/push or pop/unshift Alternatives: Fixed size array with sweeping index LinkedList
  • 43. Queues Internal FIFO queue using an array Putting data with shift/push or pop/unshift Alternatives: Fixed size array with sweeping index LinkedList LinkedBlockingQueue
  • 47. Queues queue = Queue.new(size) 100_000.times do |i| data = queue.pop queue.push(i) end Queue(1_000) array 0.065s index 0.030s LinkedList 0.056s
  • 48. Queues queue = Queue.new(size) 100_000.times do |i| data = queue.pop queue.push(i) end Queue(1_000) array 0.065s index 0.030s LinkedList 0.056s Queue(100_000) array 3.996s 85 times slower index 0.047s LinkedList 0.137s
  • 49. Queues queue = Queue.new(size) 100_000.times do |i| data = queue.pop queue.push(i) end Queue(1_000) array 0.065s index 0.030s LinkedList 0.056s Queue(100_000) array 3.996s 85 times slower index 0.047s LinkedList 0.137s Queue(1_000_000) array 53.895s 216 times slower! index 0.249s LinkedList 0.847s
  • 52. Concurrency Use a thread pool (ie java.util.concurrent.Executors)
  • 53. Concurrency Use a thread pool (ie java_import java.util.concurrent.Executors executor = Executors.newFixedThreadPool(2) 10.times do executor.submit do # do stuff end end
  • 54. Concurrency Use a thread pool (ie java.util.concurrent.Executors) Ruby’s Mutex? You’re doing it wrong
  • 55. Concurrency Use a thread pool (ie java.util.concurrent.Executors) Ruby’s Mutex? You’re doing it wrong java.util.concurrent is your friend
  • 56. Concurrency Use a thread pool (ie java.util.concurrent.Executors) Ruby’s Mutex? You’re doing it wrong java.util.concurrent is your friend AtomicInteger, ConcurrentHashMap, LinkedBlockingQueue
  • 57. Concurrency Use a thread pool (ie java.util.concurrent.Executors) Ruby’s Mutex? You’re doing it wrong java.util.concurrent is your friend AtomicInteger, ConcurrentHashMap, LinkedBlockingQueue Lock, Semaphore, CountdownLatch - IF you have to!
  • 58. Some more, just because
  • 59. Other stuff to keep in mind
  • 60. Other stuff to keep in mind Shelling out is significantly slower in JRuby
  • 61. Other stuff to keep in mind Shelling out is significantly slower in JRuby `mkdir -p /some/path/deep/1`
  • 62. Other stuff to keep in mind Shelling out is significantly slower in JRuby `mkdir -p /some/path/deep/1` rake, capistrano, bundle exec
  • 63. Other stuff to keep in mind Shelling out is significantly slower in JRuby `mkdir -p /some/path/deep/1` rake, capistrano, bundle exec There’s almost always a way of doing it without shelling
  • 64. Other stuff to keep in mind Shelling out is significantly slower in JRuby `mkdir -p /some/path/deep/1` rake, capistrano, bundle exec There’s almost always a way of doing it without shelling Don’t pass binary RubyString to Java
  • 65. Other stuff to keep in mind Shelling out is significantly slower in JRuby `mkdir -p /some/path/deep/1` rake, capistrano, bundle exec There’s almost always a way of doing it without shelling Don’t pass binary RubyString to Java Example: Hot_bunnies (JRuby RabbitMQ gem)
  • 66. Other stuff to keep in mind Shelling out is significantly slower in JRuby `mkdir -p /some/path/deep/1` rake, capistrano, bundle exec There’s almost always a way of doing it without shelling Don’t pass binary RubyString to Java Example: Hot_bunnies (JRuby RabbitMQ gem) Serialized data -> Ruby -> Java -> Network -> Java -> Ruby
  • 67. Other stuff to keep in mind Shelling out is significantly slower in JRuby `mkdir -p /some/path/deep/1` rake, capistrano, bundle exec There’s almost always a way of doing it without shelling Don’t pass binary RubyString to Java Example: Hot_bunnies (JRuby RabbitMQ gem) Serialized data -> Ruby -> Java -> Network -> Java -> Ruby String#to_java_bytes / String.from_java_bytes
  • 71. Conclusion Beware of unnecessary string creation Watch out for array.join with non-string objects
  • 72. Conclusion Beware of unnecessary string creation Watch out for array.join with non-string objects Don’t shift/unshift large arrays
  • 73. Conclusion Beware of unnecessary string creation Watch out for array.join with non-string objects Don’t shift/unshift large arrays java.util.concurrent is your friend!
  • 74. Conclusion Beware of unnecessary string creation Watch out for array.join with non-string objects Don’t shift/unshift large arrays java.util.concurrent is your friend! Don’t shell if you don’t have to
  • 75. Conclusion Beware of unnecessary string creation Watch out for array.join with non-string objects Don’t shift/unshift large arrays java.util.concurrent is your friend! Don’t shell if you don’t have to Remember String#to_java_bytes
  • 76. We’re hiring! david@burtcorp.com @effata burtcorp.com
  • 77. Thank you david@burtcorp.com @effata burtcorp.com

Editor's Notes

  1. \n
  2. Quick show of hands\nWho here runs a ruby system in production?\nWhat about jruby?\nWho runs an advanced jruby system, as in using java modules, threading, java specific gems, that sort of thing?\n
  3. I’m David, and i’m the lead platform developer at Burt\nThat means i’m scrum master and i run the day to day development of the platform team\n\nBurt is an ad analytics startup. Simply put we track ads on your website, crunch a whole lot of data about it and present it in nice reports.\nThe platform team that i’m in runs the whole crunching pipeline, and we process about 15k requests per second at peak times, in real time. \nWe use various versions of JRuby 1.6 in Ruby 1.9 mode, along with tools like RabbitMQ, MongoDB, Redis and Cassandra.\n\n
  4. I’m David, and i’m the lead platform developer at Burt\nThat means i’m scrum master and i run the day to day development of the platform team\n\nBurt is an ad analytics startup. Simply put we track ads on your website, crunch a whole lot of data about it and present it in nice reports.\nThe platform team that i’m in runs the whole crunching pipeline, and we process about 15k requests per second at peak times, in real time. \nWe use various versions of JRuby 1.6 in Ruby 1.9 mode, along with tools like RabbitMQ, MongoDB, Redis and Cassandra.\n\n
  5. I’m David, and i’m the lead platform developer at Burt\nThat means i’m scrum master and i run the day to day development of the platform team\n\nBurt is an ad analytics startup. Simply put we track ads on your website, crunch a whole lot of data about it and present it in nice reports.\nThe platform team that i’m in runs the whole crunching pipeline, and we process about 15k requests per second at peak times, in real time. \nWe use various versions of JRuby 1.6 in Ruby 1.9 mode, along with tools like RabbitMQ, MongoDB, Redis and Cassandra.\n\n
  6. I’m David, and i’m the lead platform developer at Burt\nThat means i’m scrum master and i run the day to day development of the platform team\n\nBurt is an ad analytics startup. Simply put we track ads on your website, crunch a whole lot of data about it and present it in nice reports.\nThe platform team that i’m in runs the whole crunching pipeline, and we process about 15k requests per second at peak times, in real time. \nWe use various versions of JRuby 1.6 in Ruby 1.9 mode, along with tools like RabbitMQ, MongoDB, Redis and Cassandra.\n\n
  7. I’m David, and i’m the lead platform developer at Burt\nThat means i’m scrum master and i run the day to day development of the platform team\n\nBurt is an ad analytics startup. Simply put we track ads on your website, crunch a whole lot of data about it and present it in nice reports.\nThe platform team that i’m in runs the whole crunching pipeline, and we process about 15k requests per second at peak times, in real time. \nWe use various versions of JRuby 1.6 in Ruby 1.9 mode, along with tools like RabbitMQ, MongoDB, Redis and Cassandra.\n\n
  8. What i’m going to talk about are some of the things we’ve learned when building and optimizing our system. \nOur use case is very specific, and not everything i’m going to talk about applies to everyone.\nIt’s a very different thing writing a long running application as opposed to a web application where every session is very short lived. \n\n
  9. What i’m going to talk about are some of the things we’ve learned when building and optimizing our system. \nOur use case is very specific, and not everything i’m going to talk about applies to everyone.\nIt’s a very different thing writing a long running application as opposed to a web application where every session is very short lived. \n\n
  10. What i’m going to talk about are some of the things we’ve learned when building and optimizing our system. \nOur use case is very specific, and not everything i’m going to talk about applies to everyone.\nIt’s a very different thing writing a long running application as opposed to a web application where every session is very short lived. \n\n
  11. What i’m going to talk about are some of the things we’ve learned when building and optimizing our system. \nOur use case is very specific, and not everything i’m going to talk about applies to everyone.\nIt’s a very different thing writing a long running application as opposed to a web application where every session is very short lived. \n\n
  12. What i’m going to talk about are some of the things we’ve learned when building and optimizing our system. \nOur use case is very specific, and not everything i’m going to talk about applies to everyone.\nIt’s a very different thing writing a long running application as opposed to a web application where every session is very short lived. \n\n
  13. First thing i want to talk about are strings.\nIt’s something we all use, all the time\nBut there’s one big pitfall\n\n
  14. Writing a string literal in Ruby creates a new string.\nWhich means that this (“”), is the same as this (String.new)\nMost of the time, this isn’t a problem, but if you do something like this that could be trouble\n\nThe problem here is that when looking at this code, you get a feeling that string_key is the same string all the time. But it’s not, there’s a new string created on every iteration of this loop. This is because strings in ruby are mutable, as compared to languages like Java, C# or Python.\n
  15. Writing a string literal in Ruby creates a new string.\nWhich means that this (“”), is the same as this (String.new)\nMost of the time, this isn’t a problem, but if you do something like this that could be trouble\n\nThe problem here is that when looking at this code, you get a feeling that string_key is the same string all the time. But it’s not, there’s a new string created on every iteration of this loop. This is because strings in ruby are mutable, as compared to languages like Java, C# or Python.\n
  16. Writing a string literal in Ruby creates a new string.\nWhich means that this (“”), is the same as this (String.new)\nMost of the time, this isn’t a problem, but if you do something like this that could be trouble\n\nThe problem here is that when looking at this code, you get a feeling that string_key is the same string all the time. But it’s not, there’s a new string created on every iteration of this loop. This is because strings in ruby are mutable, as compared to languages like Java, C# or Python.\n
  17. What you want to do instead is putting that string in a constant, and then use the constant when working with the hash. Or even better, use a symbol or an int.\n\nHere are some benchmarks for doing this a million times with different keys.\nAs you can see, the string version is slowest, almost twice as slow as using ints as keys\n\nObviously, some of this time goes to calculating the hash codes, which is why int is so much faster than the others.\n\n
  18. Now, the really interesting difference becomes apparent if we turn on verbose garbage collection\n\nThis is the printout for a minute run of a similar loop using a string key\nAs you can see, the GC has to work quite a lot.\nIn comparison, there is NO GC activity at all when using a constant or a symbol\n\n
  19. This is what the memory use looks like.\nNow, in a simple loop the effect of this is quite small. The GC doesn’t really have any problems dealing with it. But once you put this in a complex application along with several other threads and other stuff, and then let it run for a couple of days, this can cause a significant slowdown.\n
  20. As a comparison, the upper graph shows what the memory use looks like with a constant. Do note that the upper limit for that instance is 25 mb, compared to the string example that fluctuates between 25 and 275 mb.\n\nBtw, these graphs are from VisualVM, which is an excellent tool for looking into performance and memory issues in java, and it works great for Jruby too\n
  21. \n
  22. The next thing is something we discovered recently.\nWe had a spot where we took a bunch of different variables, stuck them in an array and joined them together into a coordinate like this\n\nWhen we profiled the code we saw a LOT of calls to method_missing which didn’t make any sense, and it was a real hot spot, like 15-20% of the processing time\n\nTurns out, Array.join uses to_str, not to_s. Which when you think about it makes a lot of sense.\nto_str is an implicit cast, or a more strict conversion. You should only implement it if your object can naturally be used every place a string could be used.\nSo, to_str is not implemented on symbols, fixnum or nilclass.\n\nBut, ruby is clever! So when to_str doesn’t exist, it goes down to method missing and eventually finds it way to to_s. But as you can see, thats quite a call stack being generated. So there’s a lot of overhead.\n
  23. The next thing is something we discovered recently.\nWe had a spot where we took a bunch of different variables, stuck them in an array and joined them together into a coordinate like this\n\nWhen we profiled the code we saw a LOT of calls to method_missing which didn’t make any sense, and it was a real hot spot, like 15-20% of the processing time\n\nTurns out, Array.join uses to_str, not to_s. Which when you think about it makes a lot of sense.\nto_str is an implicit cast, or a more strict conversion. You should only implement it if your object can naturally be used every place a string could be used.\nSo, to_str is not implemented on symbols, fixnum or nilclass.\n\nBut, ruby is clever! So when to_str doesn’t exist, it goes down to method missing and eventually finds it way to to_s. But as you can see, thats quite a call stack being generated. So there’s a lot of overhead.\n
  24. This is a benchmark of joining an array of 1000 entries ten thousand times.\nAs you can see there’s quite a performance hit\n\nOne thing you can do to combat this is to map to_str to to_s. As you can see the overhead is lower, but to_s is still slow.\nBUT, this is not a good idea. Why? \n\n
  25. This is a benchmark of joining an array of 1000 entries ten thousand times.\nAs you can see there’s quite a performance hit\n\nOne thing you can do to combat this is to map to_str to to_s. As you can see the overhead is lower, but to_s is still slow.\nBUT, this is not a good idea. Why? \n\n
  26. Struct is the reason. If you’re not familiar with Struct, it’s a way of bundling attributes together without creating a full class.\nStruct has an optional string argument that names the class. And this is detected with duck-typing by checking to_str.\n\nSo if you send in an object responding to to_str as the first argument, Struct will demand that it behaves like a constant and starts with a capital letter. So if you created an anonymous structure with a symbol, and then added to_str to symbol, you could guess what happens.\n\nAnd the thing is, there’s a lot of gems using anonymous structs. Like webbrick. So if you have this to_str hack, and then decide to require webbrick, everything will crash.\n\n\n\n
  27. So what can we do instead? A simple solution is to convert every item in the array to a string explicitly before joining.\nIt’s not quite as fast as implementing alias_method, but it’s non-invasive and improves performance.\n
  28. So what can we do instead? A simple solution is to convert every item in the array to a string explicitly before joining.\nIt’s not quite as fast as implementing alias_method, but it’s non-invasive and improves performance.\n
  29. \n
  30. My next example comes from troubles we had with an internal FIFO queue.\nWhat we discovered was that when the internal buffer grew, we saw diminishing performance up to a point where it was impossible to catch up.\n\nWhat happens is that shift and unshift on an array causes the entire array to be moved in memory, and that’s quite costly if there’s a lot of entries.\n\nThere are a couple of ways to do this better. You could use a fixed size array with a sweeping index.\nOr you could go to Java and used a LinkedList. If you’re using threads, this is the way you want to go in the first place. Go straight for a LinkedBlockingQueue.\n
  31. My next example comes from troubles we had with an internal FIFO queue.\nWhat we discovered was that when the internal buffer grew, we saw diminishing performance up to a point where it was impossible to catch up.\n\nWhat happens is that shift and unshift on an array causes the entire array to be moved in memory, and that’s quite costly if there’s a lot of entries.\n\nThere are a couple of ways to do this better. You could use a fixed size array with a sweeping index.\nOr you could go to Java and used a LinkedList. If you’re using threads, this is the way you want to go in the first place. Go straight for a LinkedBlockingQueue.\n
  32. My next example comes from troubles we had with an internal FIFO queue.\nWhat we discovered was that when the internal buffer grew, we saw diminishing performance up to a point where it was impossible to catch up.\n\nWhat happens is that shift and unshift on an array causes the entire array to be moved in memory, and that’s quite costly if there’s a lot of entries.\n\nThere are a couple of ways to do this better. You could use a fixed size array with a sweeping index.\nOr you could go to Java and used a LinkedList. If you’re using threads, this is the way you want to go in the first place. Go straight for a LinkedBlockingQueue.\n
  33. My next example comes from troubles we had with an internal FIFO queue.\nWhat we discovered was that when the internal buffer grew, we saw diminishing performance up to a point where it was impossible to catch up.\n\nWhat happens is that shift and unshift on an array causes the entire array to be moved in memory, and that’s quite costly if there’s a lot of entries.\n\nThere are a couple of ways to do this better. You could use a fixed size array with a sweeping index.\nOr you could go to Java and used a LinkedList. If you’re using threads, this is the way you want to go in the first place. Go straight for a LinkedBlockingQueue.\n
  34. My next example comes from troubles we had with an internal FIFO queue.\nWhat we discovered was that when the internal buffer grew, we saw diminishing performance up to a point where it was impossible to catch up.\n\nWhat happens is that shift and unshift on an array causes the entire array to be moved in memory, and that’s quite costly if there’s a lot of entries.\n\nThere are a couple of ways to do this better. You could use a fixed size array with a sweeping index.\nOr you could go to Java and used a LinkedList. If you’re using threads, this is the way you want to go in the first place. Go straight for a LinkedBlockingQueue.\n
  35. My next example comes from troubles we had with an internal FIFO queue.\nWhat we discovered was that when the internal buffer grew, we saw diminishing performance up to a point where it was impossible to catch up.\n\nWhat happens is that shift and unshift on an array causes the entire array to be moved in memory, and that’s quite costly if there’s a lot of entries.\n\nThere are a couple of ways to do this better. You could use a fixed size array with a sweeping index.\nOr you could go to Java and used a LinkedList. If you’re using threads, this is the way you want to go in the first place. Go straight for a LinkedBlockingQueue.\n
  36. This is an example of a sweeping index array queue. You have a fixed size array and two indexes. And data between those indexes.\n
  37. Then you pop a few items from the queue, and the start index is increased.\n
  38. And if you push items to the array and you run over the edge, you start from the beginning again.\n
  39. As you can see, for small queues the difference is minimal\nBut here’s what happens when we grow the queue\n\n
  40. As you can see, for small queues the difference is minimal\nBut here’s what happens when we grow the queue\n\n
  41. Now i’m gonna stop talking about you should avoid, and show you some good things to look at instead\n
  42. There’s really no reason not to use a thread pool.\nNative threads have move overhead and are harder to control. Executor\n
  43. There’s really no reason not to use a thread pool.\nNative threads have move overhead and are harder to control.\n\nYou should really go listen to Theo later, cause he will more about this.\n
  44. If you find yourself using mutex, you’re probably doing it wrong\nSure, there are times where you REALLY need to lock, but most of the time you just need a good concurrent data structure\n\nJavas concurrency library is really good and probably has exactly what you need,\nlike atomic numerics, concurrent maps and lists\n\nAnd lastly Semaphore is a nicer and more feature complete locking mechanism if you ACTUALLY need locking. But again, think a couple of times before going for that.\n
  45. If you find yourself using mutex, you’re probably doing it wrong\nSure, there are times where you REALLY need to lock, but most of the time you just need a good concurrent data structure\n\nJavas concurrency library is really good and probably has exactly what you need,\nlike atomic numerics, concurrent maps and lists\n\nAnd lastly Semaphore is a nicer and more feature complete locking mechanism if you ACTUALLY need locking. But again, think a couple of times before going for that.\n
  46. If you find yourself using mutex, you’re probably doing it wrong\nSure, there are times where you REALLY need to lock, but most of the time you just need a good concurrent data structure\n\nJavas concurrency library is really good and probably has exactly what you need,\nlike atomic numerics, concurrent maps and lists\n\nAnd lastly Semaphore is a nicer and more feature complete locking mechanism if you ACTUALLY need locking. But again, think a couple of times before going for that.\n
  47. If you find yourself using mutex, you’re probably doing it wrong\nSure, there are times where you REALLY need to lock, but most of the time you just need a good concurrent data structure\n\nJavas concurrency library is really good and probably has exactly what you need,\nlike atomic numerics, concurrent maps and lists\n\nAnd lastly Semaphore is a nicer and more feature complete locking mechanism if you ACTUALLY need locking. But again, think a couple of times before going for that.\n
  48. If you find yourself using mutex, you’re probably doing it wrong\nSure, there are times where you REALLY need to lock, but most of the time you just need a good concurrent data structure\n\nJavas concurrency library is really good and probably has exactly what you need,\nlike atomic numerics, concurrent maps and lists\n\nAnd lastly Semaphore is a nicer and more feature complete locking mechanism if you ACTUALLY need locking. But again, think a couple of times before going for that.\n
  49. \n
  50. Shelling out is quite a lot slower in JRuby, so use in moderation. Most things don’t need shelling. For example this you can do with FileUtils.mkdir_p\nAlso look out for things like rake and capistrano shelling out\n\nPassing RubyStrings into java can be tricky, since they will be converted to java strings and you can get problems with string encoding. This is particulary important if the string isn’t really a string but a serialised object.\n\nFor example, Hot bunnies, which uses the rabbitMQ java library and wrapping it in a gem. When publishing data to rmq you need to serialize your data, send that string to java, which sends it across the network, then back into java and finally into ruby. \n
  51. Shelling out is quite a lot slower in JRuby, so use in moderation. Most things don’t need shelling. For example this you can do with FileUtils.mkdir_p\nAlso look out for things like rake and capistrano shelling out\n\nPassing RubyStrings into java can be tricky, since they will be converted to java strings and you can get problems with string encoding. This is particulary important if the string isn’t really a string but a serialised object.\n\nFor example, Hot bunnies, which uses the rabbitMQ java library and wrapping it in a gem. When publishing data to rmq you need to serialize your data, send that string to java, which sends it across the network, then back into java and finally into ruby. \n
  52. Shelling out is quite a lot slower in JRuby, so use in moderation. Most things don’t need shelling. For example this you can do with FileUtils.mkdir_p\nAlso look out for things like rake and capistrano shelling out\n\nPassing RubyStrings into java can be tricky, since they will be converted to java strings and you can get problems with string encoding. This is particulary important if the string isn’t really a string but a serialised object.\n\nFor example, Hot bunnies, which uses the rabbitMQ java library and wrapping it in a gem. When publishing data to rmq you need to serialize your data, send that string to java, which sends it across the network, then back into java and finally into ruby. \n
  53. Shelling out is quite a lot slower in JRuby, so use in moderation. Most things don’t need shelling. For example this you can do with FileUtils.mkdir_p\nAlso look out for things like rake and capistrano shelling out\n\nPassing RubyStrings into java can be tricky, since they will be converted to java strings and you can get problems with string encoding. This is particulary important if the string isn’t really a string but a serialised object.\n\nFor example, Hot bunnies, which uses the rabbitMQ java library and wrapping it in a gem. When publishing data to rmq you need to serialize your data, send that string to java, which sends it across the network, then back into java and finally into ruby. \n
  54. Shelling out is quite a lot slower in JRuby, so use in moderation. Most things don’t need shelling. For example this you can do with FileUtils.mkdir_p\nAlso look out for things like rake and capistrano shelling out\n\nPassing RubyStrings into java can be tricky, since they will be converted to java strings and you can get problems with string encoding. This is particulary important if the string isn’t really a string but a serialised object.\n\nFor example, Hot bunnies, which uses the rabbitMQ java library and wrapping it in a gem. When publishing data to rmq you need to serialize your data, send that string to java, which sends it across the network, then back into java and finally into ruby. \n
  55. Shelling out is quite a lot slower in JRuby, so use in moderation. Most things don’t need shelling. For example this you can do with FileUtils.mkdir_p\nAlso look out for things like rake and capistrano shelling out\n\nPassing RubyStrings into java can be tricky, since they will be converted to java strings and you can get problems with string encoding. This is particulary important if the string isn’t really a string but a serialised object.\n\nFor example, Hot bunnies, which uses the rabbitMQ java library and wrapping it in a gem. When publishing data to rmq you need to serialize your data, send that string to java, which sends it across the network, then back into java and finally into ruby. \n
  56. Shelling out is quite a lot slower in JRuby, so use in moderation. Most things don’t need shelling. For example this you can do with FileUtils.mkdir_p\nAlso look out for things like rake and capistrano shelling out\n\nPassing RubyStrings into java can be tricky, since they will be converted to java strings and you can get problems with string encoding. This is particulary important if the string isn’t really a string but a serialised object.\n\nFor example, Hot bunnies, which uses the rabbitMQ java library and wrapping it in a gem. When publishing data to rmq you need to serialize your data, send that string to java, which sends it across the network, then back into java and finally into ruby. \n
  57. Shelling out is quite a lot slower in JRuby, so use in moderation. Most things don’t need shelling. For example this you can do with FileUtils.mkdir_p\nAlso look out for things like rake and capistrano shelling out\n\nPassing RubyStrings into java can be tricky, since they will be converted to java strings and you can get problems with string encoding. This is particulary important if the string isn’t really a string but a serialised object.\n\nFor example, Hot bunnies, which uses the rabbitMQ java library and wrapping it in a gem. When publishing data to rmq you need to serialize your data, send that string to java, which sends it across the network, then back into java and finally into ruby. \n
  58. \n
  59. \n
  60. \n
  61. \n
  62. \n
  63. \n
  64. \n
  65. \n
  66. \n