-
Notifications
You must be signed in to change notification settings - Fork 0
/
atom.xml
2138 lines (1597 loc) · 177 KB
/
atom.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title><![CDATA[Bear Metal]]></title>
<link href="http://bearmetal.eu/theden/atom.xml" rel="self"/>
<link href="http://bearmetal.eu/"/>
<updated>2015-01-18T09:07:53+02:00</updated>
<id>http://bearmetal.eu/</id>
<author>
<name><![CDATA[Bear Metal OÜ]]></name>
</author>
<generator uri="http://octopress.org/">Octopress</generator>
<entry>
<title type="html"><![CDATA[Help! My Rails App Is Melting under the Launch Day Load]]></title>
<link href="http://bearmetal.eu//theden/help-my-rails-app-is-melting-under-the-launch-day-load/"/>
<updated>2015-01-12T13:39:00+02:00</updated>
<id>http://bearmetal.eu//theden/help-my-rails-app-is-melting-under-the-launch-day-load</id>
<content type="html"><![CDATA[<figure markdown="1">
<a href="https://www.flickr.com/photos/pasukaru76/4484360302">
<img src="https://farm5.staticflickr.com/4065/4484360302_70ac4b6a8d_o_d.jpg">
</a>
<figcaption>
<p>
Photo by <a href="https://www.flickr.com/photos/pasukaru76/4484360302">Pascal</a>
</p>
</figcaption>
</figure>
<p>It was to be our day. The Finnish championship relay in orienteering was about to be held close to us, in a terrain type we knew inside and out. We had a great team, with both young guns and old champions. My friend Samuli had been fourth in the individual middle distance championships the day before. My only job was to handle the first leg securely and pass the baton to the more experienced and tougher guys who would then take care of our success. And I failed miserably.</p>
<p>My legs were like dough from the beginning. I was supposed to be in good shape, but I couldn’t keep up with anyone. I was supposed to take it easy and orienteer cleanly, but I ran like a headless chicken, making a mistake after another. Although I wouldn’t learn the term until years later, this was my crash course to <a href="http://en.wikipedia.org/wiki/Ego_depletion">ego depletion</a>.</p>
<hr />
<p>The day before the relay we organized the middle distance Finnish champs in my old hometown Parainen. For obvious reasons, I was the de facto webmaster of our club pages, which also hosted the result service. The site was running on OpenACS, a system running on TCL I had a year or so of work experience with. I was supposed to know it.</p>
<p>After the race was over, I headed back to my friend’s place, opened up my laptop… only to find out that the local orienteering forums were ablaze with complaints about our results page being down. Crap.</p>
<p>After hours or hunting down the issue, getting help on the OpenACS IRC channel, serving the results from a static page meanwhile, I finally managed to fix the issue. The app wasn’t running enough server processes to keep up with the load. And the most embarrassing thing was that <em>the load wasn’t even that high</em> – from high dozens to hundreds of simultaneous users. I headed to bed with my head spinning, hoping to scramble up my self confidence for the next day’s race (with well-known results).</p>
<p>What does this have to do with Ruby or Rails? Nothing, really. And yet everything. The point is that most of us have a similar story to share. It’s much more common to have a meltdown story with a reasonably low number of users than actually have a slashdotting/hackernewsing/daring fireball hit your app. If you aren’t old enough to have gone through something like this, you probably will. But you don’t have to.</p>
<hr />
<p>During the dozen or so years since the aforementioned episode, I’ve gone through some serious loads. Some of them we have handled badly, but most – including the <a href="http://wildfireapp.blogspot.fi/2009/04/wildfire-runs-facebook-site-governance.html">Facebook terms of service vote campaign</a> – with at least reasonable grace. This series of articles about Rails performance builds upon those war stories.</p>
<p>We have already posted a couple of articles to start off the series.</p>
<ol>
<li><a href="http://bearmetal.eu/theden/rails-garbage-collection-naive-defaults/">Rails Garbage Collection: Naive Defaults</a></li>
<li><a href="http://bearmetal.eu/theden/does-rails-scale/">Does Rails Scale?</a></li>
<li><a href="http://bearmetal.eu/theden/rails-garbage-collection-age-matters/">Rails Garbage Collection: Age Matters</a></li>
</ol>
<p>This article will serve as kind of a belated intro to the series, introducing our high level principles regarding the subject but without going more to the details.</p>
<h2>The Bear Metal ironclad rules of Rails performance</h2>
<h3>Scalability is not the same as performance</h3>
<p>As I already noted in <a href="http://bearmetal.eu/theden/does-rails-scale/">Does Rails Scale?</a>, it’s worth pointing out that performance is not the same thing as scalability. They are related for sure. But you can perform similarly poorly from your first to your millionth user and be “scalable”. There is also the difference that performance is right here and now. If your app scales well, you can just throw more hardware (virtual or real) at the problem and solve it by that.</p>
<p>The good news is that Rails scales quite well out of the box for the vast majority of real-world needs. You probably won’t be the next Twitter or even Basecamp. In your dreams and VC prospectus maybe, but let’s be honest, the odds are stacked against you. So don’t sweat about that too much.</p>
<p>Meanwhile, you do want your app to perform well enough for your initial wave of users.</p>
<h3>Perceived performance is what matters</h3>
<p>There are basically three different layers of performance for any web app: the server level (I’m bundling everything from the data store to the frontend server here), browser rendering and the performance perceived by the user. The two latter ones are very close to each other but not exactly the same. You can tweak the perceived performance with tricks on the UI level, something that often isn’t even considered performance.</p>
<p>The most important lesson here is that the perceived performance is what matters. It makes no difference what your synthetic performance tests on your server say if the UI of the app feels sluggish. There is no panacea to solve this, but make no mistake, it is what matters when the chicken come home to roost.</p>
<h3>Start with quick, large, and obvious wins</h3>
<p>The fact is that even a modest amount of users can make your app painfully slow. The good thing is that you can probably fix that just with hitting the low-hanging fruit. You won’t believe how many Rails apps reveal that they’re running in the development mode even in production by – when an error occurs – leaking the whole error trace out to the end user.</p>
<p>Other examples of issues that are fairly easy to spot and fix are N+1 query issues with ActiveRecord associations, missing database indeces, and running a single, non-concurrent app server instance, where any longer-running action will block the whole app from other users.</p>
<h3>YAGNI</h3>
<p>Once you have squashed all the low-hanging fruit with your metal-reinforced bat, relax. Tuning app performance shouldn’t be your top priority at the moment – unless it is, but in that case you will know for sure. What you should be focusing on is how to get paying customers and how you can make them kick ass. If you have clear performance issues, by all means fix them. However…</p>
<h3>Don’t assume, measure</h3>
<p>You probably don’t have any idea how many users your app needs to support from the get go. That’s fine. The reality will teach you. As long as you don’t royally fuck up the share nothing (and 12 factor if you’re on a cloud platform such as Heroku) architecture, you should be able to react to issues quickly.</p>
<p>That said, you probably do want to do some baseline load testing with your app if you’re opening for a much larger private group or the public. The good news is that it is very cheap to spin up a virtual server instance just for a couple of hours and hit your app hard with it. Heck, you can handle the baseline from your laptop if needed. With that you should be able to get over the initial, frightening launch.</p>
<p>Once your app is up and running under load from real users, your tuning work starts for real. Only now will you be able to measure where the real hot paths and bottlenecks in your app are, based on real usage data, not just assumptions. At this point you’ll have a plethora of tools at your disposal, from the good old <a href="https://github.com/wvanbergen/request-log-analyzer">request log analyzer</a> to commercial offerings such as <a href="https://www.skylight.io">Skylight</a>, and <a href="http://newrelic.com">New Relic</a>.</p>
<p>On the frontend most browsers have nowadays developer tools to optimize end-user performance, from Chrome and Safari’s built-in developer tools to <a href="http://getfirebug.com">Firebug</a> for Firefox.</p>
<h2>Wrap-up</h2>
<p>In this introductory article to building performant Rails (or any, for that matter) web apps, we took a look at five basic rules of performance optimization:</p>
<ol>
<li>Scalability is not the same as performance.</li>
<li>Perceived performance is what matters.</li>
<li>Start with the low-hanging fruit.</li>
<li>YAGNI</li>
<li>Don’t assume, measure.</li>
</ol>
<p>We will get (much) more in the details of Rails performance optimization in later articles. At that point we’ll enter a territory where one size does not fit all anymore. However, whatever your particular performance problem is, you should keep the five rules above at the top your mind.</p>
]]></content>
</entry>
<entry>
<title type="html"><![CDATA[How to install Ruby 2.2.0 on OS X Yosemite with Homebrew and rbenv]]></title>
<link href="http://bearmetal.eu//theden/install-ruby-2-dot-2-0-yosemite-openssl-error/"/>
<updated>2015-01-06T16:15:00+02:00</updated>
<id>http://bearmetal.eu//theden/install-ruby-2-dot-2-0-yosemite-openssl-error</id>
<content type="html"><![CDATA[<p>When trying to install Ruby 2.2.0 on Yosemite with <a href="https://github.com/sstephenson/rbenv">rbenv</a> and <a href="http://brew.sh">Homebrew</a>, I got a weird error:</p>
<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>➜ ~ ✗ rbenv install 2.2.0
</span><span class='line'>Downloading ruby-2.2.0.tar.gz...
</span><span class='line'>-> http://dqw8nmjcqpjn7.cloudfront.net/7671e394abfb5d262fbcd3b27a71bf78737c7e9347fa21c39e58b0bb9c4840fc
</span><span class='line'>Installing ruby-2.2.0...
</span><span class='line'>
</span><span class='line'>BUILD FAILED (OS X 10.10.1 using ruby-build 20141225)
</span><span class='line'>
</span><span class='line'>Inspect or clean up the working tree at /var/folders/s_/_zh3skrd0qz2933nns5y425r0000gn/T/ruby-build.20150106151200.81466
</span><span class='line'>Results logged to /var/folders/s_/_zh3skrd0qz2933nns5y425r0000gn/T/ruby-build.20150106151200.81466.log
</span><span class='line'>
</span><span class='line'>Last 10 log lines:
</span><span class='line'>make[2]: *** Waiting for unfinished jobs....
</span><span class='line'>compiling raddrinfo.c
</span><span class='line'>compiling ifaddr.c
</span><span class='line'>make[1]: *** [ext/openssl/all] Error 2
</span><span class='line'>make[1]: *** Waiting for unfinished jobs....
</span><span class='line'>linking shared-object zlib.bundle
</span><span class='line'>linking shared-object socket.bundle
</span><span class='line'>linking shared-object date_core.bundle
</span><span class='line'>linking shared-object ripper.bundle
</span><span class='line'>make: *** [build-ext] Error 2</span></code></pre></td></tr></table></div></figure>
<p>When I opened up the log file mentioned in the output above, I could see the actual cause of the error:</p>
<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
<span class='line-number'>29</span>
<span class='line-number'>30</span>
<span class='line-number'>31</span>
<span class='line-number'>32</span>
<span class='line-number'>33</span>
<span class='line-number'>34</span>
<span class='line-number'>35</span>
<span class='line-number'>36</span>
<span class='line-number'>37</span>
<span class='line-number'>38</span>
<span class='line-number'>39</span>
<span class='line-number'>40</span>
<span class='line-number'>41</span>
<span class='line-number'>42</span>
<span class='line-number'>43</span>
<span class='line-number'>44</span>
<span class='line-number'>45</span>
<span class='line-number'>46</span>
<span class='line-number'>47</span>
<span class='line-number'>48</span>
<span class='line-number'>49</span>
<span class='line-number'>50</span>
<span class='line-number'>51</span>
<span class='line-number'>52</span>
<span class='line-number'>53</span>
<span class='line-number'>54</span>
<span class='line-number'>55</span>
<span class='line-number'>56</span>
<span class='line-number'>57</span>
<span class='line-number'>58</span>
<span class='line-number'>59</span>
<span class='line-number'>60</span>
<span class='line-number'>61</span>
<span class='line-number'>62</span>
<span class='line-number'>63</span>
<span class='line-number'>64</span>
<span class='line-number'>65</span>
<span class='line-number'>66</span>
<span class='line-number'>67</span>
<span class='line-number'>68</span>
<span class='line-number'>69</span>
<span class='line-number'>70</span>
<span class='line-number'>71</span>
<span class='line-number'>72</span>
<span class='line-number'>73</span>
<span class='line-number'>74</span>
<span class='line-number'>75</span>
<span class='line-number'>76</span>
<span class='line-number'>77</span>
<span class='line-number'>78</span>
<span class='line-number'>79</span>
<span class='line-number'>80</span>
<span class='line-number'>81</span>
<span class='line-number'>82</span>
<span class='line-number'>83</span>
<span class='line-number'>84</span>
<span class='line-number'>85</span>
<span class='line-number'>86</span>
<span class='line-number'>87</span>
<span class='line-number'>88</span>
<span class='line-number'>89</span>
<span class='line-number'>90</span>
<span class='line-number'>91</span>
<span class='line-number'>92</span>
<span class='line-number'>93</span>
<span class='line-number'>94</span>
<span class='line-number'>95</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>ossl_ssl.c:125:5: error: use of undeclared identifier 'TLSv1_2_method'
</span><span class='line'> OSSL_SSL_METHOD_ENTRY(TLSv1_2),
</span><span class='line'> ^
</span><span class='line'>ossl_ssl.c:119:69: note: expanded from macro 'OSSL_SSL_METHOD_ENTRY'
</span><span class='line'>#define OSSL_SSL_METHOD_ENTRY(name) { #name, (SSL_METHOD *(*)(void))name##_method }
</span><span class='line'> ^
</span><span class='line'><scratch space>:148:1: note: expanded from here
</span><span class='line'>TLSv1_2_method
</span><span class='line'>^
</span><span class='line'>ossl_ssl.c:126:5: error: use of undeclared identifier 'TLSv1_2_server_method'
</span><span class='line'> OSSL_SSL_METHOD_ENTRY(TLSv1_2_server),
</span><span class='line'> ^
</span><span class='line'>ossl_ssl.c:119:69: note: expanded from macro 'OSSL_SSL_METHOD_ENTRY'
</span><span class='line'>#define OSSL_SSL_METHOD_ENTRY(name) { #name, (SSL_METHOD *(*)(void))name##_method }
</span><span class='line'> ^
</span><span class='line'><scratch space>:148:1: note: expanded from here
</span><span class='line'>TLSv1_2_server_method
</span><span class='line'>^
</span><span class='line'>ossl_ssl.c:127:5: error: use of undeclared identifier 'TLSv1_2_client_method'
</span><span class='line'> OSSL_SSL_METHOD_ENTRY(TLSv1_2_client),
</span><span class='line'> ^
</span><span class='line'>ossl_ssl.c:119:69: note: expanded from macro 'OSSL_SSL_METHOD_ENTRY'
</span><span class='line'>#define OSSL_SSL_METHOD_ENTRY(name) { #name, (SSL_METHOD *(*)(void))name##_method }
</span><span class='line'> ^
</span><span class='line'><scratch space>:148:1: note: expanded from here
</span><span class='line'>TLSv1_2_client_method
</span><span class='line'>^
</span><span class='line'>ossl_ssl.c:131:5: error: use of undeclared identifier 'TLSv1_1_method'
</span><span class='line'> OSSL_SSL_METHOD_ENTRY(TLSv1_1),
</span><span class='line'> ^
</span><span class='line'>ossl_ssl.c:119:69: note: expanded from macro 'OSSL_SSL_METHOD_ENTRY'
</span><span class='line'>#define OSSL_SSL_METHOD_ENTRY(name) { #name, (SSL_METHOD *(*)(void))name##_method }
</span><span class='line'> ^
</span><span class='line'><scratch space>:148:1: note: expanded from here
</span><span class='line'>TLSv1_1_method
</span><span class='line'>^
</span><span class='line'>ossl_ssl.c:132:5: error: use of undeclared identifier 'TLSv1_1_server_method'
</span><span class='line'> OSSL_SSL_METHOD_ENTRY(TLSv1_1_server),
</span><span class='line'> ^
</span><span class='line'>ossl_ssl.c:119:69: note: expanded from macro 'OSSL_SSL_METHOD_ENTRY'
</span><span class='line'>#define OSSL_SSL_METHOD_ENTRY(name) { #name, (SSL_METHOD *(*)(void))name##_method }
</span><span class='line'> ^
</span><span class='line'><scratch space>:148:1: note: expanded from here
</span><span class='line'>TLSv1_1_server_method
</span><span class='line'>^
</span><span class='line'>ossl_ssl.c:133:5: error: use of undeclared identifier 'TLSv1_1_client_method'
</span><span class='line'> OSSL_SSL_METHOD_ENTRY(TLSv1_1_client),
</span><span class='line'> ^
</span><span class='line'>ossl_ssl.c:119:69: note: expanded from macro 'OSSL_SSL_METHOD_ENTRY'
</span><span class='line'>#define OSSL_SSL_METHOD_ENTRY(name) { #name, (SSL_METHOD *(*)(void))name##_method }
</span><span class='line'> ^
</span><span class='line'><scratch space>:148:1: note: expanded from here
</span><span class='line'>TLSv1_1_client_method
</span><span class='line'>^
</span><span class='line'>ossl_ssl.c:210:21: error: invalid application of 'sizeof' to an incomplete type 'const struct <anonymous struct at ossl_ssl.c:115:14> []'
</span><span class='line'> for (i = 0; i < numberof(ossl_ssl_method_tab); i++) {
</span><span class='line'> ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
</span><span class='line'>ossl_ssl.c:19:35: note: expanded from macro 'numberof'
</span><span class='line'>#define numberof(ary) (int)(sizeof(ary)/sizeof((ary)[0]))
</span><span class='line'> ^~~~~
</span><span class='line'>ossl_ssl.c:1127:13: warning: using the result of an assignment as a condition without parentheses [-Wparentheses]
</span><span class='line'> if (rc = SSL_shutdown(ssl))
</span><span class='line'> ~~~^~~~~~~~~~~~~~~~~~~
</span><span class='line'>ossl_ssl.c:1127:13: note: place parentheses around the assignment to silence this warning
</span><span class='line'> if (rc = SSL_shutdown(ssl))
</span><span class='line'> ^
</span><span class='line'> ( )
</span><span class='line'>ossl_ssl.c:1127:13: note: use '==' to turn this assignment into an equality comparison
</span><span class='line'> if (rc = SSL_shutdown(ssl))
</span><span class='line'> ^
</span><span class='line'> ==
</span><span class='line'>ossl_ssl.c:2194:23: error: invalid application of 'sizeof' to an incomplete type 'const struct <anonymous struct at ossl_ssl.c:115:14> []'
</span><span class='line'> ary = rb_ary_new2(numberof(ossl_ssl_method_tab));
</span><span class='line'> ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
</span><span class='line'>ossl_ssl.c:19:35: note: expanded from macro 'numberof'
</span><span class='line'>#define numberof(ary) (int)(sizeof(ary)/sizeof((ary)[0]))
</span><span class='line'> ^~~~~
</span><span class='line'>ossl_ssl.c:2195:21: error: invalid application of 'sizeof' to an incomplete type 'const struct <anonymous struct at ossl_ssl.c:115:14> []'
</span><span class='line'> for (i = 0; i < numberof(ossl_ssl_method_tab); i++) {
</span><span class='line'> ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
</span><span class='line'>ossl_ssl.c:19:35: note: expanded from macro 'numberof'
</span><span class='line'>#define numberof(ary) (int)(sizeof(ary)/sizeof((ary)[0]))
</span><span class='line'> ^~~~~
</span><span class='line'>1 warning and 9 errors generated.
</span><span class='line'>make[2]: *** [ossl_ssl.o] Error 1
</span><span class='line'>make[2]: *** Waiting for unfinished jobs....
</span><span class='line'>compiling raddrinfo.c
</span><span class='line'>compiling ifaddr.c
</span><span class='line'>make[1]: *** [ext/openssl/all] Error 2
</span><span class='line'>make[1]: *** Waiting for unfinished jobs....
</span><span class='line'>linking shared-object zlib.bundle
</span><span class='line'>linking shared-object socket.bundle
</span><span class='line'>linking shared-object date_core.bundle
</span><span class='line'>linking shared-object ripper.bundle
</span><span class='line'>make: *** [build-ext] Error 2</span></code></pre></td></tr></table></div></figure>
<p>The weird thing here is that I did not get the usual ‘Missing the OpenSSL lib?’ warning. The lib <em>was</em> found but somehow the headers were fucked up. It also did not happen with older rbenv Rubies.</p>
<p>Thanks to <a href="https://bearmetal.eu/team/tarmo/">Tarmo</a> I found the solution <a href="https://issues.apache.org/jira/browse/THRIFT-2515?focusedCommentId=14012758&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-14012758">here</a>.</p>
<p>What I had to do was this:</p>
<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>➜ ~ brew update
</span><span class='line'>➜ ~ brew install openssl
</span><span class='line'>➜ ~ /usr/local/opt/openssl/bin/c_rehash</span></code></pre></td></tr></table></div></figure>
<p>Now make sure that your new binary is in your PATH before the system one.</p>
<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>➜ ~ ln -s /usr/local/opt/openssl/bin/openssl /usr/local/bin/openssl
</span><span class='line'>➜ ~ which openssl
</span><span class='line'>/usr/bin/openssl
</span><span class='line'>➜ ~ echo $PATH
</span><span class='line'>/usr/local/heroku/bin:/Users/jarkko/.rbenv/shims:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin</span></code></pre></td></tr></table></div></figure>
<p>That’s no good. Let’s fix our PATH. I’m using zsh, so for me it’s set in <code>~/.zshrc</code>. Your particular file depends on the shell you’re using (for bash it would be <code>~/.bashrc</code> or <code>~/.bash_profile</code>, but see the caveat <a href="http://www.joshstaiger.org/archives/2005/07/bash_profile_vs.html">here</a>).</p>
<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>➜ ~ vim ~/.zshrc
</span><span class='line'># Change the line that sets PATH so that /usr/local/bin
</span><span class='line'># comes BEFORE /usr/bin. For me, it looks like this:
</span><span class='line'># export PATH=/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin</span></code></pre></td></tr></table></div></figure>
<p>Open up a new terminal window and check that the PATH is correct:</p>
<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>➜ ~ echo $PATH
</span><span class='line'>/usr/local/heroku/bin:/Users/jarkko/.rbenv/shims:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin
</span><span class='line'>➜ ~ which openssl
</span><span class='line'>/usr/local/bin/openssl</span></code></pre></td></tr></table></div></figure>
<p>Better. Now, let’s make sure that homebrew libs symlink to the newer openssl.</p>
<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>➜ ~ brew unlink openssl
</span><span class='line'>➜ ~ brew link --overwrite --force openssl
</span><span class='line'>➜ ~ openssl version -a
</span><span class='line'>
</span><span class='line'>OpenSSL 1.0.1j 15 Oct 2014
</span><span class='line'>built on: Sun Dec 7 02:14:31 GMT 2014
</span><span class='line'>platform: darwin64-x86_64-cc
</span><span class='line'>options: bn(64,64) rc4(ptr,char) des(idx,cisc,16,int) idea(int) blowfish(idx)
</span><span class='line'>compiler: clang -fPIC -fno-common -DOPENSSL_PIC -DZLIB_SHARED -DZLIB -DOPENSSL_THREADS -D_REENTRANT -DDSO_DLFCN -DHAVE_DLFCN_H -arch x86_64 -O3 -DL_ENDIAN -Wall -DOPENSSL_IA32_SSE2 -DOPENSSL_BN_ASM_MONT -DOPENSSL_BN_ASM_MONT5 -DOPENSSL_BN_ASM_GF2m -DSHA1_ASM -DSHA256_ASM -DSHA512_ASM -DMD5_ASM -DAES_ASM -DVPAES_ASM -DBSAES_ASM -DWHIRLPOOL_ASM -DGHASH_ASM
</span><span class='line'>OPENSSLDIR: "/usr/local/etc/openssl"</span></code></pre></td></tr></table></div></figure>
<p>Splendid.</p>
<p>After that, Ruby 2.2.0 installed cleanly without any specific parameters needed:</p>
<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>➜ ~ rbenv install 2.2.0
</span><span class='line'>Downloading ruby-2.2.0.tar.gz...
</span><span class='line'>-> http://dqw8nmjcqpjn7.cloudfront.net/7671e394abfb5d262fbcd3b27a71bf78737c7e9347fa21c39e58b0bb9c4840fc
</span><span class='line'>Installing ruby-2.2.0...
</span><span class='line'>Installed ruby-2.2.0 to /Users/jarkko/.rbenv/versions/2.2.0</span></code></pre></td></tr></table></div></figure>
<p><strong>[UPDATE 1, Jan 7]</strong> The original version of this post told you to <code>rm /usr/bin/openssl</code>, based on the link above. As James Tucker pointed out, this is a horrible idea. I fixed the article so that we now fix the <code>$PATH</code> instead.</p>
]]></content>
</entry>
<entry>
<title type="html"><![CDATA[Rails Garbage Collection: age matters]]></title>
<link href="http://bearmetal.eu//theden/rails-garbage-collection-age-matters/"/>
<updated>2014-12-22T20:26:00+02:00</updated>
<id>http://bearmetal.eu//theden/rails-garbage-collection-age-matters</id>
<content type="html"><![CDATA[<p>In a <a href="https://bearmetal.eu/theden/rails-garbage-collection-naive-defaults/">previous post</a> in the <a href="http://bearmetal.eu/theden/categories/rails-performance">Rails Performance</a> series we stated that the default garbage collection settings for <a href="http://www.rubyonrails.org">Ruby on Rails</a> applications are not optimal. In this post we’ll explore the basics of object age in RGenGC, Ruby 2.1’s new <em>restricted generational garbage collector</em>.</p>
<p>As a prerequisite of this and subsequent posts, basic understanding of a <em>mark and sweep</em><sup id="fnref:1"><a href="#fn:1" rel="footnote">1</a></sup> collector is assumed.</p>
<p><img src="http://bearmetal.eu/images/gc_mark_sweep.png" alt="" /></p>
<p>A somewhat simplified mark and sweep cycle goes like this:</p>
<ol>
<li>A mark and sweep collector traverses the object graph.</li>
<li>It checks which objects are in use (referenced) and which ones are not.</li>
<li>This is called object marking, aka. the <strong>MARK PHASE</strong>.</li>
<li>All unused objects are freed, making their memory available.</li>
<li>This is called sweeping, aka. the <strong>SWEEP PHASE</strong>.</li>
<li>Nothing changes for used objects.</li>
</ol>
<p>A GC cycle prior to Ruby 2.1 works like that. A typical Rails app boots with 300 000 live objects of which all need to be scanned during the <strong>MARK</strong> phase. That usually yields a smaller set to <strong>SWEEP</strong>.</p>
<p>A large percentage of the graph is going to be traversed over and over again but will never be reclaimed. This is not only CPU intensive during GC cycles, but also incurs memory overhead for accounting and anticipation for future growth.</p>
<h2>Old and young objects</h2>
<p><strong>What generally makes an object old?</strong></p>
<ul>
<li><em>All new objects are considered to be young</em>.</li>
<li><em>Old objects survived at least one GC cycle (major or minor)</em> The collector thus reasons that the object will stick around and not become garbage quickly.</li>
</ul>
<p>The idea behind the new generational garbage collector is this:</p>
<blockquote><p><strong>MOST OBJECTS DIE YOUNG.</strong></p></blockquote>
<p>To take advantage of this fact, the new GC classifies objects on the Ruby heap as either <strong>OLD</strong> or <strong>YOUNG</strong>. This segregation now allows the garbage collector to work with two distinct generations, with the <strong>OLD</strong> generation much less likely to yield much improvement towards recovering memory.</p>
<p>For a typical Rails request, some examples of old and new objects would be:</p>
<ul>
<li><strong>Old:</strong> compiled routes, templates, ActiveRecord connections, cached DB column info, classes, modules etc.</li>
<li><strong>New:</strong> short lived strings within a partial, a string column value from an ActiveRecord result, a coerced DateTime instance etc.</li>
</ul>
<p>Young objects are more likely to reference old objects than old objects referencing young objects. Old objects also frequently reference other old objects.</p>
<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'> <span class="n">u</span> <span class="o">=</span> <span class="no">User</span><span class="o">.</span><span class="n">first</span>
</span><span class='line'> <span class="c1">#<User id: 1, email: "lourens@something.com", encrypted_password: "blahblah...", reset_password_token: nil, reset_password_sent_at: nil, remember_created_at: nil, sign_in_count: 2, current_sign_in_at: "2014-10-31 11:52:30", last_sign_in_at: "2014-10-29 10:04:01", current_sign_in_ip: "127.0.0.1", last_sign_in_ip: "127.0.0.1", created_at: "2014-10-29 10:04:01", updated_at: "2014-11-30 14:07:15", provider: nil, uid: nil, first_name: "dfdsfds", last_name: "dfdsfds", confirmation_token: nil, confirmed_at: "2014-10-30 10:11:42", confirmation_sent_at: nil, unconfirmed_email: nil, onboarded_at: nil></span>
</span></code></pre></td></tr></table></div></figure>
<p>Notice how the transient attribute keys and names reference the long lived columns here:</p>
<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="p">{</span><span class="s2">"id"</span><span class="o">=></span>
</span><span class='line'> <span class="c1">#<ActiveRecord::ConnectionAdapters::PostgreSQLAdapter::OID::Integer:0x007fbe756d1d30>,</span>
</span><span class='line'> <span class="s2">"email"</span><span class="o">=></span>
</span><span class='line'> <span class="c1">#<ActiveRecord::ConnectionAdapters::PostgreSQLAdapter::OID::Identity:0x007fbe756d1718>,</span>
</span><span class='line'> <span class="s2">"encrypted_password"</span><span class="o">=></span>
</span><span class='line'> <span class="c1">#<ActiveRecord::ConnectionAdapters::PostgreSQLAdapter::OID::Identity:0x007fbe756d1718>,</span>
</span><span class='line'> <span class="s2">"reset_password_token"</span><span class="o">=></span>
</span><span class='line'> <span class="c1">#<ActiveRecord::ConnectionAdapters::PostgreSQLAdapter::OID::Identity:0x007fbe756d1718>,</span>
</span><span class='line'> <span class="s2">"reset_password_sent_at"</span><span class="o">=></span>
</span><span class='line'> <span class="c1">#<ActiveRecord::AttributeMethods::TimeZoneConversion::Type:0x007fbe741f63c0</span>
</span><span class='line'> <span class="vi">@column</span><span class="o">=</span>
</span><span class='line'> <span class="c1">#<ActiveRecord::ConnectionAdapters::PostgreSQLAdapter::OID::Timestamp:0x007fbe756d0e58>>,</span>
</span></code></pre></td></tr></table></div></figure>
<p>Age segregation is also just a classification – old and young objects aren’t stored in distinct memory spaces – they’re just conceptional buckets. The generation of an object refers to the amount of GC cycles it survived:</p>
<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="n">irb</span><span class="p">(</span><span class="n">main</span><span class="p">):</span><span class="mo">00</span><span class="mi">9</span><span class="p">:</span><span class="mi">0</span><span class="o">></span> <span class="no">ObjectSpace</span><span class="o">.</span><span class="n">dump</span><span class="p">(</span><span class="o">[]</span><span class="p">)</span>
</span><span class='line'><span class="o">=></span> <span class="s2">"{</span><span class="se">\"</span><span class="s2">address</span><span class="se">\"</span><span class="s2">:</span><span class="se">\"</span><span class="s2">0x007fd24c007668</span><span class="se">\"</span><span class="s2">, </span><span class="se">\"</span><span class="s2">type</span><span class="se">\"</span><span class="s2">:</span><span class="se">\"</span><span class="s2">ARRAY</span><span class="se">\"</span><span class="s2">, </span><span class="se">\"</span><span class="s2">class</span><span class="se">\"</span><span class="s2">:</span><span class="se">\"</span><span class="s2">0x007fd24b872038</span><span class="se">\"</span><span class="s2">, </span><span class="se">\"</span><span class="s2">length</span><span class="se">\"</span><span class="s2">:0, </span><span class="se">\"</span><span class="s2">file</span><span class="se">\"</span><span class="s2">:</span><span class="se">\"</span><span class="s2">(irb)</span><span class="se">\"</span><span class="s2">, </span><span class="se">\"</span><span class="s2">line</span><span class="se">\"</span><span class="s2">:9, </span><span class="se">\"</span><span class="s2">method</span><span class="se">\"</span><span class="s2">:</span><span class="se">\"</span><span class="s2">irb_binding</span><span class="se">\"</span><span class="s2">, </span><span class="se">\"</span><span class="s2">generation</span><span class="se">\"</span><span class="s2">:8, </span><span class="se">\"</span><span class="s2">flags</span><span class="se">\"</span><span class="s2">:{</span><span class="se">\"</span><span class="s2">wb_protected</span><span class="se">\"</span><span class="s2">:true}}</span><span class="se">\n</span><span class="s2">"</span>
</span><span class='line'><span class="n">irb</span><span class="p">(</span><span class="n">main</span><span class="p">):</span><span class="mo">010</span><span class="p">:</span><span class="mi">0</span><span class="o">></span> <span class="no">GC</span><span class="o">.</span><span class="n">count</span>
</span><span class='line'><span class="o">=></span> <span class="mi">8</span>
</span></code></pre></td></tr></table></div></figure>
<h2>What the heck is major and minor GC?</h2>
<p>You may have heard, read about or noticed in GC.stat output the terms “minor” and “major” GC.</p>
<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="n">irb</span><span class="p">(</span><span class="n">main</span><span class="p">):</span><span class="mo">003</span><span class="p">:</span><span class="mi">0</span><span class="o">></span> <span class="n">pp</span> <span class="no">GC</span><span class="o">.</span><span class="n">stat</span>
</span><span class='line'><span class="p">{</span><span class="ss">:count</span><span class="o">=></span><span class="mi">32</span><span class="p">,</span>
</span><span class='line'> <span class="ss">:heap_used</span><span class="o">=></span><span class="mi">1181</span><span class="p">,</span>
</span><span class='line'> <span class="ss">:heap_length</span><span class="o">=></span><span class="mi">1233</span><span class="p">,</span>
</span><span class='line'> <span class="ss">:heap_increment</span><span class="o">=></span><span class="mi">50</span><span class="p">,</span>
</span><span class='line'> <span class="ss">:heap_live_slot</span><span class="o">=></span><span class="mi">325148</span><span class="p">,</span>
</span><span class='line'> <span class="ss">:heap_free_slot</span><span class="o">=></span><span class="mi">156231</span><span class="p">,</span>
</span><span class='line'> <span class="ss">:heap_final_slot</span><span class="o">=></span><span class="mi">0</span><span class="p">,</span>
</span><span class='line'> <span class="ss">:heap_swept_slot</span><span class="o">=></span><span class="mi">163121</span><span class="p">,</span>
</span><span class='line'> <span class="ss">:heap_eden_page_length</span><span class="o">=></span><span class="mi">1171</span><span class="p">,</span>
</span><span class='line'> <span class="ss">:heap_tomb_page_length</span><span class="o">=></span><span class="mi">10</span><span class="p">,</span>
</span><span class='line'> <span class="ss">:total_allocated_object</span><span class="o">=></span><span class="mi">2050551</span><span class="p">,</span>
</span><span class='line'> <span class="ss">:total_freed_object</span><span class="o">=></span><span class="mi">1725403</span><span class="p">,</span>
</span><span class='line'> <span class="ss">:malloc_increase</span><span class="o">=></span><span class="mi">1462784</span><span class="p">,</span>
</span><span class='line'> <span class="ss">:malloc_limit</span><span class="o">=></span><span class="mi">24750208</span><span class="p">,</span>
</span><span class='line'> <span class="ss">:minor_gc_count</span><span class="o">=></span><span class="mi">26</span><span class="p">,</span>
</span><span class='line'> <span class="ss">:major_gc_count</span><span class="o">=></span><span class="mi">6</span><span class="p">,</span>
</span><span class='line'> <span class="ss">:remembered_shady_object</span><span class="o">=></span><span class="mi">3877</span><span class="p">,</span>
</span><span class='line'> <span class="ss">:remembered_shady_object_limit</span><span class="o">=></span><span class="mi">4042</span><span class="p">,</span>
</span><span class='line'> <span class="ss">:old_object</span><span class="o">=></span><span class="mi">304270</span><span class="p">,</span>
</span><span class='line'> <span class="ss">:old_object_limit</span><span class="o">=></span><span class="mi">259974</span><span class="p">,</span>
</span><span class='line'> <span class="ss">:oldmalloc_increase</span><span class="o">=></span><span class="mi">23639792</span><span class="p">,</span>
</span><span class='line'> <span class="ss">:oldmalloc_limit</span><span class="o">=></span><span class="mi">24159190</span><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure>
<p><strong>Minor GC (or “partial marking”):</strong> This cycle only traverses the young generation and is very fast. Based on the hypothesis that most objects die young, this GC cycle is thus the most effective at reclaiming back a large ratio of memory in proportion to objects traversed.</p>
<p>It runs quite often - 26 times for the GC dump of a booted Rails app above.</p>
<p><strong>Major GC:</strong> Triggered by out-of-memory conditions - Ruby heap space needs to be expanded (not OOM killer! :-)) Both old and young objects are traversed and it’s thus significantly slower than a minor GC round. Generally when there’s a significant increase in old objects, a major GC would be triggered. Every major GC cycle that an object survived bumps its current generation.</p>
<p>It runs much less frequently - six times for the stats dump above.</p>
<p>The following diagram represents a minor GC cycle (<strong>MARK</strong> phase completed, <strong>SWEEP</strong> still pending) that identifies and promotes some objects to old.</p>
<p><img src="http://bearmetal.eu/images/gc_first_minor.png" alt="" /></p>
<p>A subsequent minor GC cycle (<strong>MARK</strong> phase completed, <strong>SWEEP</strong> still pending) ignores old objects during the mark phase.</p>
<p><img src="http://bearmetal.eu/images/gc_second_minor.png" alt="" /></p>
<p>Most of the reclaiming efforts are thus focussed on the young generation (new objects). Generally 95% of objects are dead by the first GC. The current generation of an object is the number of major GC cycles it has survived.</p>
<h2>RGenGC</h2>
<p>At a very high level C Ruby 2.1’s collector has the following properties:</p>
<ul>
<li>High throughput - it can sustain a high rate of allocations / collections due to faster minor GC cycles and very rare major GC cycles.</li>
<li>GC pauses are still long (“stop the world”) for major GC cycles.</li>
<li>Generational collectors have much shorter mark cycles as they traverse only the young generation, most of the time.</li>
</ul>
<p>This is a marked improvement to the C Ruby GC and serves as a base for implementing other advanced features moving forward. Ruby 2.2 supports incremental GC and object ages beyond just old and new definitions. A major GC cycle in 2.1 still runs in a “stop the world” manner, whereas a more involved incremental implementation (Ruby 2.2) interleaves short steps of mark and sweep cycles between other VM operations.</p>
<h2>Object references</h2>
<p>In this simple example below we create a String array with three elements.</p>
<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="n">irb</span><span class="p">(</span><span class="n">main</span><span class="p">):</span><span class="mo">001</span><span class="p">:</span><span class="mi">0</span><span class="o">></span> <span class="nb">require</span> <span class="s1">'objspace'</span>
</span><span class='line'><span class="o">=></span> <span class="kp">true</span>
</span><span class='line'><span class="n">irb</span><span class="p">(</span><span class="n">main</span><span class="p">):</span><span class="mo">002</span><span class="p">:</span><span class="mi">0</span><span class="o">></span> <span class="no">ObjectSpace</span><span class="o">.</span><span class="n">trace_object_allocations_start</span>
</span><span class='line'><span class="o">=></span> <span class="kp">nil</span>
</span><span class='line'><span class="n">irb</span><span class="p">(</span><span class="n">main</span><span class="p">):</span><span class="mo">003</span><span class="p">:</span><span class="mi">0</span><span class="o">></span> <span class="n">ary</span> <span class="o">=</span> <span class="sx">%w(a b c)</span>
</span><span class='line'><span class="o">=></span> <span class="o">[</span><span class="s2">"a"</span><span class="p">,</span> <span class="s2">"b"</span><span class="p">,</span> <span class="s2">"c"</span><span class="o">]</span>
</span></code></pre></td></tr></table></div></figure>
<p>Very much like a river flowing downstream, the array has knowledge of (a reference to) each of its String elements. On the contrary, the strings don’t have an awareness of (or references back to) the array container.</p>
<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="n">irb</span><span class="p">(</span><span class="n">main</span><span class="p">):</span><span class="mo">004</span><span class="p">:</span><span class="mi">0</span><span class="o">></span> <span class="no">ObjectSpace</span><span class="o">.</span><span class="n">dump</span><span class="p">(</span><span class="n">ary</span><span class="p">)</span>
</span><span class='line'><span class="o">=></span> <span class="s2">"{</span><span class="se">\"</span><span class="s2">address</span><span class="se">\"</span><span class="s2">:</span><span class="se">\"</span><span class="s2">0x007fd24b890fd8</span><span class="se">\"</span><span class="s2">, </span><span class="se">\"</span><span class="s2">type</span><span class="se">\"</span><span class="s2">:</span><span class="se">\"</span><span class="s2">ARRAY</span><span class="se">\"</span><span class="s2">, </span><span class="se">\"</span><span class="s2">class</span><span class="se">\"</span><span class="s2">:</span><span class="se">\"</span><span class="s2">0x007fd24b872038</span><span class="se">\"</span><span class="s2">, </span><span class="se">\"</span><span class="s2">length</span><span class="se">\"</span><span class="s2">:3, </span><span class="se">\"</span><span class="s2">embedded</span><span class="se">\"</span><span class="s2">:true, </span><span class="se">\"</span><span class="s2">references</span><span class="se">\"</span><span class="s2">:[</span><span class="se">\"</span><span class="s2">0x007fd24b891050</span><span class="se">\"</span><span class="s2">, </span><span class="se">\"</span><span class="s2">0x007fd24b891028</span><span class="se">\"</span><span class="s2">, </span><span class="se">\"</span><span class="s2">0x007fd24b891000</span><span class="se">\"</span><span class="s2">], </span><span class="se">\"</span><span class="s2">file</span><span class="se">\"</span><span class="s2">:</span><span class="se">\"</span><span class="s2">(irb)</span><span class="se">\"</span><span class="s2">, </span><span class="se">\"</span><span class="s2">line</span><span class="se">\"</span><span class="s2">:3, </span><span class="se">\"</span><span class="s2">method</span><span class="se">\"</span><span class="s2">:</span><span class="se">\"</span><span class="s2">irb_binding</span><span class="se">\"</span><span class="s2">, </span><span class="se">\"</span><span class="s2">generation</span><span class="se">\"</span><span class="s2">:7, </span><span class="se">\"</span><span class="s2">flags</span><span class="se">\"</span><span class="s2">:{</span><span class="se">\"</span><span class="s2">wb_protected</span><span class="se">\"</span><span class="s2">:true}}</span><span class="se">\n</span><span class="s2">"</span>
</span><span class='line'><span class="n">irb</span><span class="p">(</span><span class="n">main</span><span class="p">):</span><span class="mo">004</span><span class="p">:</span><span class="mi">0</span><span class="o">></span> <span class="no">ObjectSpace</span><span class="o">.</span><span class="n">reachable_objects_from</span><span class="p">(</span><span class="n">ary</span><span class="p">)</span>
</span><span class='line'><span class="o">=></span> <span class="o">[</span><span class="nb">Array</span><span class="p">,</span> <span class="s2">"a"</span><span class="p">,</span> <span class="s2">"b"</span><span class="p">,</span> <span class="s2">"c"</span><span class="o">]</span>
</span><span class='line'><span class="n">irb</span><span class="p">(</span><span class="n">main</span><span class="p">):</span><span class="mo">006</span><span class="p">:</span><span class="mi">0</span><span class="o">></span> <span class="no">ObjectSpace</span><span class="o">.</span><span class="n">reachable_objects_from</span><span class="p">(</span><span class="n">ary</span><span class="o">[</span><span class="mi">1</span><span class="o">]</span><span class="p">)</span>
</span><span class='line'><span class="o">=></span> <span class="o">[</span><span class="nb">String</span><span class="o">]</span>
</span><span class='line'><span class="n">irb</span><span class="p">(</span><span class="n">main</span><span class="p">):</span><span class="mo">007</span><span class="p">:</span><span class="mi">0</span><span class="o">></span> <span class="no">ObjectSpace</span><span class="o">.</span><span class="n">dump</span><span class="p">(</span><span class="n">ary</span><span class="o">[</span><span class="mi">1</span><span class="o">]</span><span class="p">)</span>
</span><span class='line'><span class="o">=></span> <span class="s2">"{</span><span class="se">\"</span><span class="s2">address</span><span class="se">\"</span><span class="s2">:</span><span class="se">\"</span><span class="s2">0x007fd24b891028</span><span class="se">\"</span><span class="s2">, </span><span class="se">\"</span><span class="s2">type</span><span class="se">\"</span><span class="s2">:</span><span class="se">\"</span><span class="s2">STRING</span><span class="se">\"</span><span class="s2">, </span><span class="se">\"</span><span class="s2">class</span><span class="se">\"</span><span class="s2">:</span><span class="se">\"</span><span class="s2">0x007fd24b829658</span><span class="se">\"</span><span class="s2">, </span><span class="se">\"</span><span class="s2">embedded</span><span class="se">\"</span><span class="s2">:true, </span><span class="se">\"</span><span class="s2">bytesize</span><span class="se">\"</span><span class="s2">:1, </span><span class="se">\"</span><span class="s2">value</span><span class="se">\"</span><span class="s2">:</span><span class="se">\"</span><span class="s2">b</span><span class="se">\"</span><span class="s2">, </span><span class="se">\"</span><span class="s2">encoding</span><span class="se">\"</span><span class="s2">:</span><span class="se">\"</span><span class="s2">UTF-8</span><span class="se">\"</span><span class="s2">, </span><span class="se">\"</span><span class="s2">file</span><span class="se">\"</span><span class="s2">:</span><span class="se">\"</span><span class="s2">(irb)</span><span class="se">\"</span><span class="s2">, </span><span class="se">\"</span><span class="s2">line</span><span class="se">\"</span><span class="s2">:3, </span><span class="se">\"</span><span class="s2">method</span><span class="se">\"</span><span class="s2">:</span><span class="se">\"</span><span class="s2">irb_binding</span><span class="se">\"</span><span class="s2">, </span><span class="se">\"</span><span class="s2">generation</span><span class="se">\"</span><span class="s2">:7, </span><span class="se">\"</span><span class="s2">flags</span><span class="se">\"</span><span class="s2">:{</span><span class="se">\"</span><span class="s2">wb_protected</span><span class="se">\"</span><span class="s2">:true, </span><span class="se">\"</span><span class="s2">old</span><span class="se">\"</span><span class="s2">:true, </span><span class="se">\"</span><span class="s2">marked</span><span class="se">\"</span><span class="s2">:true}}</span><span class="se">\n</span><span class="s2">"</span>
</span></code></pre></td></tr></table></div></figure>
<p>We stated earlier that:</p>
<p><strong>Young objects are more likely to reference old objects, than old objects referencing young objects. Old objects also frequently reference other old objects.</strong></p>
<p><em>However</em> it’s possible for old objects to reference new objects. What happens when old objects reference new ones?</p>
<p>Old objects with references to new objects are stored in a “remembered set”. The remembered set is a container of references from old objects to new objects and is a shortcut for preventing heap scans for finding such references.</p>
<h2>Implications for Rails</h2>
<p>As our friend Ezra used to say, “no code is faster than no code.” The same applies to automatic memory management. Every object allocation also has a variable recycle cost. Allocation generally is low overhead as it happens once, except for the use case where there are no free object slots on the Ruby heap and a major GC is triggered as a result.</p>
<p>A major drawback of this limited segregation of OLD vs YOUNG is that <strong>many transient objects are in fact promoted to old during large contexts such as a Rails request</strong>. These long lived objects eventually become unexpected “memory leaks”. These transient objects can be conceptually classified as of “medium lifetime” as they need to stick around for the duration of a request. There’s however a large probability that a minor GC would run during request lifetime, promoting young objects to old, effectively increasing their lifetime to well beyond the end of a request. This situation can only be revisited during a major GC which runs infrequently and sweeps both old and young objects.</p>
<p><strong>Each generation can be specifically tweaked, with the older generation being particularly important for balancing total process memory use with maintaining a minimal transient object set (young ones) per request. And subsequent too fast promotion from young to old generation.</strong></p>
<p><em>In our next post we will explore how you’d approach tuning the Ruby GC for Rails applications, balancing tradeoffs of speed and memory. Leave your email address below and we’ll let you know as soon as it’s posted.</em></p>
<div class="footnotes">
<hr/>
<ol>
<li id="fn:1">
<p>See the Ruby Hacking Guide’s <a href="https://ruby-hacking-guide.github.io/gc.html">GC chapter</a> for further context and nitty gritty details. I’d recommended scanning the content below the first few headings, until turned off by C.<a href="#fnref:1" rev="footnote">↩</a></p></li>
</ol>
</div>
]]></content>
</entry>
<entry>
<title type="html"><![CDATA[Does Rails Scale?]]></title>
<link href="http://bearmetal.eu//theden/does-rails-scale/"/>
<updated>2014-12-19T15:22:00+02:00</updated>
<id>http://bearmetal.eu//theden/does-rails-scale</id>
<content type="html"><![CDATA[<figure markdown="1">
<a href="https://www.flickr.com/photos/soctech/43279549/">
<img src="https://farm1.staticflickr.com/24/43279549_465d50976e_b_d.jpg">
</a>
<figcaption>
<p>
Photo by <a href="https://www.flickr.com/photos/soctech/43279549/">Soctech</a>
</p>
</figcaption>
</figure>
<p>Back when Rails was still not mainstream, a common dismissal by developers using other – more established – technologies was that Rails is cool and stuff, but it will never scale<sup id="fnref:1"><a href="#fn:1" rel="footnote">1</a></sup>. While the question isn’t (compared to Rails’ success) as common these days, it still appears in one form or another every once in a while.</p>
<p>Last week on the Ruby on Rails Facebook group, someone asked <a href="https://www.facebook.com/groups/rubyandrails/permalink/10153620823655752/">this question</a>:</p>
<blockquote><p>Can Rails stand up to making a social platform like FB with millions of users using it at the same time?</p>
<p>If so what are the pro’s and the cons?</p></blockquote>
<p>So in other words, can Rails scale <em>a lot</em>?</p>
<p>Just as is customary for a Facebook group, the question got a lot of clueless answers. There were a couple of gems like this:</p>
<blockquote><p>Tony if you want to build some thing like FB, you need to learn deeper mountable engine and SOLID anti pattern.</p></blockquote>
<p>The worst however are answers from people who <em>don’t know</em> they don’t know shit but insist on giving advice that is only bound to either confuse the original poster or lead them astray – and probably both:</p>
<blockquote><p>Twitter is not a good example. They stopped using Rails because it couldn’t handle millions of request per second. They began using Scala.</p></blockquote>
<p>This is of course mostly BS with a hint of truth in it, but we’ll get back to that in a bit.</p>
<p>The issue with the question itself, is that <em>it’s the wrong question to ask</em>, and this has nothing to do with Ruby or Rails per se.</p>
<p>Why is it the wrong question? Let’s have a look.</p>
<p>Sure, Ruby is slow in raw performance. It has gotten a lot faster during the past decade, but it is still a highly dynamic interpreted scripting language. Its main shtick has always been programmer happiness, and its primary way to attain that goal has definitely not been to return from that test run as fast as possible. The same goes for Rails.</p>
<p>That said, there are two reasons bare Ruby performance doesn’t matter <em>that</em> much. First, it’s only a tiny part of the <strong>perceived app performance</strong> for the user. Rails has gone out of its way to automatically make the frontend of your web app performant. This includes frontend caching, asset pipeline, and more opinionated things like Turbolinks. You can of course screw all that up, but you would be amazed how much actual end-user performance you’d miss if you’d write the same app from scratch – not to mention the time you’d waste building it.</p>
<p>Second, and most important for this discussion: <strong>scaling is not the same thing as performance</strong>. Rails has always been built on the <a href="http://en.wikipedia.org/wiki/Shared_nothing_architecture">shared nothing architecture</a>, where in theory the only thing you need to do to scale out your app is to throw more hardware at it – the app should scale linearly. Of course there are limits to this, but they are by no means specific to Rails or Ruby.</p>
<p>Scaling and performance are two separate things. They are related as terms, but not strictly connected. Your app can be very fast for a couple users but awful for a thousand (didn’t scale). Or it can scale at O(1) to a million users but loading a page for even a single concurrent user can take 10 seconds (scales but doesn’t perform).</p>
<p>Like stated above, a traditional crud-style app on Rails can be made to scale very well by just adding app server instances, cores, and finally physical app servers serving the app. This is what is meant by scaling out<sup id="fnref:2"><a href="#fn:2" rel="footnote">2</a></sup>. Most often the limiting factor here is not Rails but the datastore, which is still often the one shared component in the equation. Scaling the database out is still harder than the appservers, but nevertheless possible. That is way outside the scope of this article, however.</p>
<h2>Is this the right tool for the job?</h2>
<p>It’s clear in hindsight that a Rails app wasn’t the right tool for what Twitter became – a juggernaut where millions of people were basically realtime chatting with the whole world.</p>
<p>That doesn’t mean that Rails wasn’t a valid choice for the original app. Maybe it wasn’t the best option even then from the technical perspective, but it for sure made developing Twitter a whole lot faster in its initial stages. You know, twitter wasn’t the only contender in the microblogging stage in the late naughties. We finns fondly remember Jaiku. Then there was that other San Fransisco startup using Django that I can’t even name anymore.</p>
<p>Anyway, the point is that <em>reaching a scale where you have to think harder about scalability is a very, very nice problem to have</em>. Either you built a real business and are making money hand over fist, or you are playing – and winning – the eyeball lotto and have VCs knocking on your door (or, more realistically, have taken on several millions already). The vast majority of businesses <em>never</em> reach this stage.</p>
<p>More likely you just fail in the hockeystick game (the VC option), or perhaps build a sustainable business (the old-fashioned <em>people pay me for helping them kick ass</em> kind). In any case, you won’t have to worry about scaling to millions of concurrent users.</p>
<p>Even at the very profitable, high scale SaaS market there are hoards of examples of apps running on Rails. Kissmetrics runs its frontend on Rails, as does GitHub, not to mention Groupon, Livingsocial<sup id="fnref:3"><a href="#fn:3" rel="footnote">3</a></sup>, and many others.</p>
<p>However, at certain scale you have to go for a more modular architecture, SOA if I may. You can use a message queue for message passing, a noSQL db for non-relational and ephemeral data, node.js for realtime apps, and so on. <em>A good tool for every particular sub-task of your app</em>.</p>
<p>That said, you need to keep in mind what I said above. It is pretty unlikely you will ever reach a state where you really need to scale. Thus, thinking about the architecture at the initial stage too much is a form of premature optimization. As long as you don’t do anything extra stupid, you can probably get away with a simple Rails app. Because splitting up your app to lots of components early on makes several things harder and more expensive:</p>
<ul>
<li>Complexity of development.</li>
<li>Operating and deploying a bunch of different apps.</li>
<li>Keeping track that all apps are up and running.</li>
<li>Hunting bugs.</li>
<li>Making changes in a lean development environment where things change rapidly</li>
<li>Cognitive cost of understanding and learning how the app works. This is especially true when you’re expanding your team.</li>
</ul>
<p>This doesn’t mean that at some point you shouldn’t do the split. There might be a time where the scale for the points above tips, and a monorail app becomes a burden. But then again, <em>there might not</em>. So do what makes sense now, not what makes sense in your imaginary future.</p>
<p>Of <em>course</em> Rails alone won’t scale to a gazillion users for an app it wasn’t really meant for to begin with. Neither is it supposed to. However, it is amazing how far you can get with it, just the same way that the old boring PostgreSQL still beats the shit out of its more “modern” competitors in most common usecases<sup id="fnref:4"><a href="#fn:4" rel="footnote">4</a></sup>.</p>
<h2>Questions you should be asking</h2>
<p>When making a technology decision, instead of “Does is scale?”, here’s what you should be asking instead:</p>
<ul>
<li>What is the right tool for the jobs of my app?</li>
<li>How far can I likely get away with a single Rails app?</li>
<li>Will we ever really reach the scale we claim in our investor prospectus? No need to lie to yourself here.</li>
<li>What is more important: getting the app up and running and in front of real users fast, or making it scalable in an imaginary future that may never come?</li>
</ul>
<p>Only after answering those are you equipped to make a decision.</p>
<p>P.S. Reached the point where optimizing Rails and Ruby performance <em>does</em> make a difference? We’re writing <a href="https://bearmetal.eu/theden/categories/rails-performance/">a series of articles</a> about just that. Pop your details in the <a href="#mc_embed_signup">form ☟ down there</a> and we’ll keep you posted.</p>
<div class="footnotes">
<hr/>
<ol>
<li id="fn:1">
<p>Another good one I heard in EuroOSCON 2005 was that the only thing good about Rails is its marketing.<a href="#fnref:1" rev="footnote">↩</a></p></li>
<li id="fn:2">
<p>Versus scaling up, which means making the single core or thread faster.<a href="#fnref:2" rev="footnote">↩</a></p></li>
<li id="fn:3">
<p>OK, the last two might not pass the profitable bit.<a href="#fnref:3" rev="footnote">↩</a></p></li>
<li id="fn:4">
<p>There are obviously special cases where a single Rails app doesn’t cut it even from the beginning. E.g. computationally intensive apps such as Kissmetrics or Skylight.io obviously won’t run their stats aggregation processes on Rails.<a href="#fnref:4" rev="footnote">↩</a></p></li>
</ol>
</div>
]]></content>
</entry>
<entry>
<title type="html"><![CDATA[Rails Garbage Collection: naive defaults]]></title>
<link href="http://bearmetal.eu//theden/rails-garbage-collection-naive-defaults/"/>
<updated>2014-12-04T17:27:00+02:00</updated>
<id>http://bearmetal.eu//theden/rails-garbage-collection-naive-defaults</id>
<content type="html"><![CDATA[<p><a href="https://www.flickr.com/photos/x1klima/13349077375/in/photolist-mkBvCt-9F5bop-psoHyh-6pkzNo-9uDMLx-85EMnZ-ibSsrK-iog9vf-JtxCJ-iohdxP-ibS242-7RtfVT-k1H87W-jNAG6M-oxaFaw-cR3ow7-gEqUsd-6z6KY5-e1m1pQ-diRWXG-i5md69-iogg32-ibSVHi-ibStrn-ibSVUy-n8CpB1-67QKGw-p3qtEX-4THpny-ebLNCE-nycgpC-6U69md-4yXv5b-pTDf3R-861fmQ-6zABJu-3FKVM-nwzafz-6pgrY2-9ejbm6-QuSM-hvn32M-aomUMi-9eebae-b15Lpi-8tBhZj-6o1Xmn-6z3YKz-5s868-61WvU1"><img src="https://farm8.staticflickr.com/7036/13349077375_36fc92ecce_k_d.jpg" alt="" /></a></p>
<p><small>Photo by <a href="https://www.flickr.com/photos/x1klima/13349077375/in/photolist-mkBvCt-9F5bop-psoHyh-6pkzNo-9uDMLx-85EMnZ-ibSsrK-iog9vf-JtxCJ-iohdxP-ibS242-7RtfVT-k1H87W-jNAG6M-oxaFaw-cR3ow7-gEqUsd-6z6KY5-e1m1pQ-diRWXG-i5md69-iogg32-ibSVHi-ibStrn-ibSVUy-n8CpB1-67QKGw-p3qtEX-4THpny-ebLNCE-nycgpC-6U69md-4yXv5b-pTDf3R-861fmQ-6zABJu-3FKVM-nwzafz-6pgrY2-9ejbm6-QuSM-hvn32M-aomUMi-9eebae-b15Lpi-8tBhZj-6o1Xmn-6z3YKz-5s868-61WvU1">martin</a>, used under the Creative Commons license.</small></p>
<p>The vast majority of <a href="http://www.rubyonrails.org">Ruby on Rails</a> applications deploy to production with the vanilla Ruby GC configuration. A conservative combination of growth factors and accounting that “works” for a demographic from IRB sessions (still my preferred calculator) to massive monolithic Rails apps (the fate of most successful ones). In practice this doesn’t work very well, however. It produces:</p>
<ul>
<li>Too aggressive growth of Ruby heap slots and pages when thresholds are reached.</li>
<li>A large ratio of short and medium lived objects in relation to long lived ones for Rails applications.</li>
<li>Too many intermittent major GC cycles during the request / response cycle.</li>
<li>Heap fragmentation.</li>
</ul>
<p>Let’s use a metaphor most of us can better relate to: <em>dreaded household chores.</em> Your ability and frequency of hosting dinners at home are limited by four things (takeaways and paper plates aside):</p>
<ul>
<li>How many seats and tables you have</li>
<li>How many sets of clean cutlery, plates and glasses are available</li>
<li>Overhead preparing a particular choice of cuisine</li>
<li>Willingness to clean up and do dishes after</li>
</ul>
<p>This is what you have to work with at home:</p>
<ul>
<li>4 chairs and a table</li>
<li>12 plates and equivalent utensils</li>
<li>83 friends (60 from Facebook, 20 at work, your 2 brothers and then there’s Jim)</li>
<li>3 wine glasses and a beer mug</li>
<li>1 bottle of wine and 24 beers<sup id="fnref:1"><a href="#fn:1" rel="footnote">1</a></sup></li>
<li>3 awesome steaks and a piece of tofu</li>
<li>Fresh local produce</li>
</ul>
<p>Some of your friends are also vegetarian.</p>
<p>Let’s have a look at two different scenarios.</p>
<h4>IRB scenario</h4>
<p>You’ve invited and subsequently prepared dinner and the table—seats, plates and cutlery sets—for four, popped open your bottle of wine and fired up the grill. However, only one friend arrives, quite late. You’re grilling steak number three, yet he’s the vegetarian…and only drinks beer. And even then doesn’t talk very much.</p>
<p>In the end, you down the whole bottle of wine and the three steaks. Life’s good again. There’s plenty to clean up and pack away, still.</p>
<h4>Rails scenario</h4>
<p>17 guests show up at your door. Half of them are heavily intoxicated because Dylan invited the rest of his wine tasting group, too. Only one eats any of your food, yet breaks four plates. Beer disappeared in three minutes. The group members reveal seven new bottles of wine, make your dog drink one and he kernel panics as a result.</p>
<p>You were not f*cking prepared. At all. Marinated steak’s now ruined, there’s less inventory and 30+ bottles to recycle. You’re hungry and now there are no plates left!</p>
<p>In both of these scenarios, from the perspective of your friends it mostly worked out just fine. It wasn’t optimal for you or your environment, though. What’s important is that you learned a few things:</p>
<ul>
<li>Next time it’s easier to execute optimally, but there may still be a party and some broken plates.</li>
<li>A barbeque for 17 in your one bedroom flat with a George Foreman grill doesn’t scale well.</li>
</ul>
<h2>Cooking with Ruby</h2>
<p>In the same manner, different use cases for the Ruby runtime require different preparations. Let’s tie the dinner metaphor back to Ruby land and its memory model.</p>
<h4>Home environment</h4>
<p>The Ruby runtime, with everything else inside. Pages, objects and auxilary object data.</p>
<h4>Guest count</h4>
<p>The number of major features and facets you need to support. Gems and engines are good candidates along with individual models, controllers, views etc. These “seats” are also connected - different guests mingle together.</p>
<h4>Guest distribution</h4>
<p>Rails provides a framework for building applications, thus should be considered as part of the guest list too. Like some family members that make their way to gettogethers. First and second tier cousins you may hear of once a year and never talk with - they’re present (consume memory), yet don’t always add much value to the ambient.</p>
<h4>Food and drink</h4>
<p>The amount and distribution of objects required to make a feature or facet work. A mix bag of small entrees (embedded objects like 2-char strings), main dishes (a Rails request and all its context) to cocktails and tequila shots (threads!).</p>
<h4>Plates and glasses</h4>
<p>An object slot on the Ruby heap. One String, Array, Hash or any other object. Keep in mind that they can overflow and be recycled too - a wine glass is good for multiple servings. For buffets, a single plate can go very far too :-)</p>
<h4>Tables</h4>
<p>Ruby pages - containers for objects. All of the plates and glasses on a given table. They’re mostly prepared in advance, but you can “construct” and improvise as needed to.</p>
<h4>Type of cuisine</h4>
<p>Some dishes incur a lot of work to prepare <em>and</em> to clean up. Cooked basmati rice will leave a very very different footprint in your kitchen than a paella or salmon option would.</p>
<p>The GC defaults for most Rails applications assume a reasonable sized home environment, a well defined guest list and just enough food and drinks for each. Everyone can sit at the same table, wine and dine on fine dishes, all with a minimal cleanup burden.</p>
<p><em>In reality, it’s a frat party. Gone seriously wrong.</em></p>
<p><em>In the next part of this series, we’re going to take a look at how the Ruby runtime can better host Rails applications. And what you can optimize for.</em></p>
<div class="footnotes">
<hr/>
<ol>
<li id="fn:1">
<p>Because if there’s a promotion, you buy.<a href="#fnref:1" rev="footnote">↩</a></p></li>
</ol>
</div>
]]></content>
</entry>
<entry>
<title type="html"><![CDATA[Metaprogramming Ruby for Greater Good]]></title>
<link href="http://bearmetal.eu//theden/metaprogramming-ruby-for-greater-good/"/>
<updated>2014-09-29T11:43:00+03:00</updated>
<id>http://bearmetal.eu//theden/metaprogramming-ruby-for-greater-good</id>
<content type="html"><![CDATA[<p><em>This is the transcript of the talk I gave in Reaktor Dev Day in Helsinki, September 26, 2014.</em></p>
<script async class="speakerdeck-embed" data-id="89eb608027ae01321e4c624b84330d5d" data-ratio="1.77777777777778" src="//speakerdeck.com/assets/embed.js"></script>
<p>Thanks, and hi, everyone! It’s a real honor to be here. I’ve been a big fan of Reaktor for a long time, that is, UNTIL ALL MY GEEK FRIENDS DEFECTED THERE. There’s been lots of talk about Rosatom building a new nuclear plant here in Finland. I say fuck that, we already have enough nuclear knowledge locally. But I digress.</p>
<p>I’d like to be one of the cool kids and <em>Start with Why</em> just like Simon Sinek told us. However, before that it’s worth defining the term metaprogramming in the context of this talk.</p>
<p>What do we mean by metaprogramming? <em>In its simplest form, metaprogramming means code that writes code</em>.</p>
<p>A-ha! So, code generators are metaprogramming, too? Not really. I go with the definition where the code is generated on the fly in the runtime. We could perhaps call it dynamic metaprogramming. This means that most of what I’m going to talk about is not possible in a static language.</p>
<p>So a more appropriate definition might be, to quote Paolo Perrotta,</p>
<blockquote><p>Writing code that manipulates language constructs at runtime.</p></blockquote>
<h2>Why?</h2>
<p>But why, I hear you ask. What’s in it for me? Well, first of all, because metaprogramming is…</p>
<p>…magic. And magic is good, right? Right? RIGHT? Well, it <em>can</em> be. At least it’s cool.</p>
<p>It’s also a fun topic for a conference like this, because it’s frankly, quite often, mind-boggling. Think of it like this. You take your brain out of your head. You put it in your backpocket. Then you sit on it. <em>Does it bend?</em> If it does, you’re talking about metaprogramming.</p>
<p>I also like things that make me scratch my head. I mean, scratching your head is a form of exercise. Just try it yourself. Scratch your head vigorously and your Fitbit will tell you you worked out like crazy today. That’s healthy.</p>
<p>But all joking aside, we don’t use metaprogramming to be clever, we use it to be flexible. And with Ruby – and any other sufficiently dynamic language – in the end of the day, <em>metaprogramming is just a fancy word for normal, advanced programming</em>.</p>
<h2>Why Ruby?</h2>
<p>So why Ruby? First of all, Ruby is the language I know by far the best. Second, Ruby combines Lisp-like dynamism and flexibility to a syntax that humans can actually decipher.</p>
<p>Like said, in Ruby there’s really no distinction between metaprogramming and advanced OO programming in general. Thus, before we go to things that are more literally metaprogramming, let’s have a look at Ruby’s object model and constructs that lay the groundwork for metaprogramming.</p>
<p>Thus, in a way, this talk can be reduced to <em>advanced OO concepts in Ruby</em>.</p>
<h2>How?</h2>
<p>Before we delve more deeply into the Ruby object model, let’s take a step back and have a look at what we mean by object-orientation.</p>
<p>Generally, there are two main approaches to object-oriented programming. By far the most popular is class-based OO, used in languages such as C++ and Java. The other one is prototype-based OO, which is most commonly seen in Javascript. So which of the two does Ruby use?</p>
<p>Class-based? Well, let’s have a look.</p>
<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'> <span class="n">speaker</span> <span class="o">=</span> <span class="no">Object</span><span class="o">.</span><span class="n">new</span>
</span><span class='line'>
</span><span class='line'> <span class="k">def</span> <span class="nc">speaker</span><span class="o">.</span><span class="nf">talk_length</span>