-
Notifications
You must be signed in to change notification settings - Fork 0
/
atom.xml
222 lines (136 loc) · 15.8 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
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title><![CDATA[Codyblog]]></title>
<link href="http://codyhatch.github.io/atom.xml" rel="self"/>
<link href="http://codyhatch.github.io/"/>
<updated>2014-01-06T21:34:29+13:00</updated>
<id>http://codyhatch.github.io/</id>
<author>
<name><![CDATA[Cody Hatch]]></name>
</author>
<generator uri="http://octopress.org/">Octopress</generator>
<entry>
<title type="html"><![CDATA[High performance Nginx and SSL]]></title>
<link href="http://codyhatch.github.io/blog/2014/01/06/high-performance-nginx-and-ssl/"/>
<updated>2014-01-06T17:51:19+13:00</updated>
<id>http://codyhatch.github.io/blog/2014/01/06/high-performance-nginx-and-ssl</id>
<content type="html"><![CDATA[<p>As we move towards launch, we’re doing a lot of long delayed polish and testing. Checking browser compatability, adding cacheing, integrating with a CDN, and generally making sure everything is working just right. We’re also doing some stress tests with the excellent <a href="http://blitz.io/">blitz.io</a> tool.</p>
<h2>About that…</h2>
<p>So, I queued up a basic blitz.io test (or a “rush”, in their terminology), and…</p>
<div class='pagination-centered'><a href='http://codyhatch.github.io/images/blog/whups.png'><img src="http://codyhatch.github.io/images/blog/whups.png" width="350" height="350" title="whups" alt="whups"></a></div>
<p>For those unfamiliar, the grey line shows increasing load, the blue line shows replies, the red line shows errors. Or in simple terms, about the time I got 40 hits a second, everything fell over.</p>
<p>On the surface, this is kind of surprising, since I’m using Nginx, and serving up a static pre-rendered page. Nginx is well known to be fast and really good at serving static content; most of the blog posts and StackOverflow comments about how to fix “my site falls over when I stress test it” boil down to “use Nginx!”. But I’m already using it, so…um.</p>
<h2>A few tweaks</h2>
<p>First off, I poked around a bit, and realised that I actually wasn’t serving up the page directly from disk; a small config error meant I was actually hitting a node.js process which was serving up the static page directly from disk. Node isn’t quite as fast as Nginx, but it’s quite fast enough; fixing my config didn’t do anything.</p>
<p>So then I started tweaking Nginx config variables. <code>worker_processes</code> didn’t seem to do much. And neither did <code>worker_rlimit_nofile</code>, nor <code>open_file_cache</code>, or turning <code>access_log</code> to <code>off</code>, or well…anything. My server froze up and cried little tears of pain every time I hit the test.</p>
<h2>Progress</h2>
<p>Well, okay. So something is bottlenecked. And it’s not clear what exactly is bottlenecked either, so…hm. Let’s try running <code>top</code> on the server while we hit it with a test.</p>
<p>Oh look, my CPU usage is 100%. That certainly explains the results I’m seeing, but Nginx is meant to be super low CPU when it comes to serving static files! What’s going on?</p>
<p><span class='pullquote-right' data-pullquote='At this point, most of your are probably yelling at your monitors:“It says SSL in your title! SSL termination is computationally expensive! You’re a flaming idiot!”'>At this point, most of your are probably yelling at your monitors:“It says SSL in your title! SSL termination is computationally expensive! You’re a flaming idiot!”</span></p>
<p>Indeed. It does, it is, and I might be. Because once I realised what was going wrong I ran an rush on the non-SSL URL for our app. And you can probably guess the results:</p>
<div class="clearfix"></div>
<div class='pagination-centered'><a href='http://codyhatch.github.io/images/blog/hmm.png'><img src="http://codyhatch.github.io/images/blog/hmm.png" width="350" height="350" title="hmm" alt="hmm"></a></div>
<p>What you’re seeing here is that the response time stayed pretty constant, while hits tracked overall volume closely. In short, it responded (quickly!) to whatever I threw at it up to 250 hits/second which is as high as I decided to go. Which is what Nginx is famed for, so uh…good. (Not shown: Our CPU usage, which was essentially nil. No surprise; serving static files from RAM over plain-old-HTTP is practically free.)</p>
<p>But now what? I kind need SSL termination.</p>
<h2>The fix</h2>
<h3>Hardware</h3>
<p>Step one is to look at the hardware I’m throwing at the problem. Which, as it turns out, is a $10/month Digital Ocean droplet. For the price, they’re not bad — 30GB of SSD disk, 1GB of RAM, and 1 vCPU. It’s that last bit which is clearly killing us now though.</p>
<p>Well, it’s the work of a moment to resize our droplet to the next tier up with 2 vCPU. Let’s reset to vanilla Nginx settings and see what that does:</p>
<div class='pagination-centered'><a href='http://codyhatch.github.io/images/blog/better.png'><img src="http://codyhatch.github.io/images/blog/better.png" width="350" height="350" title="better" alt="better"></a></div>
<p>Well, that is technically better…kind of. Okay, now with all those tuned <code>worker_processes</code> settings we copied off the internet?</p>
<div class='pagination-centered'><a href='http://codyhatch.github.io/images/blog/nope.png'><img src="http://codyhatch.github.io/images/blog/nope.png" width="350" height="350" title="nope" alt="nope]"></a></div>
<p>Well, it’s certainly spiky looking. But not what we’re going for.</p>
<h3>Software</h3>
<p>Nginx is very configurable. Maybe there are some specific SSL settings? But of course there are!</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'>ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
</span><span class='line'>ssl_ciphers ECDHE-RSA-AES256-SHA384:AES256-SHA256:RC4:HIGH:!MD5:!aNULL:!eNULL:!NULL:!DH:!EDH:!AESGCM;
</span><span class='line'>ssl_prefer_server_ciphers on;
</span><span class='line'>ssl_session_cache shared:SSL:10m;
</span><span class='line'>ssl_session_timeout 10m;</span></code></pre></td></tr></table></div></figure>
<div class='pagination-centered'><a href='http://codyhatch.github.io/images/blog/success.png'><img src="http://codyhatch.github.io/images/blog/success.png" width="350" height="350" title="yes!" alt="yes!]"></a></div>
<p>Well how about that?</p>
<h2>The conclusion</h2>
<p>Well, the obvious conclusion is “know how to use your tools”, but that’s a bit too general. Let’s look for something a bit more specific. Such as:</p>
<p>Make sure to configure Nginx properly for SSL!</p>
]]></content>
</entry>
<entry>
<title type="html"><![CDATA[Testability]]></title>
<link href="http://codyhatch.github.io/blog/2013/12/25/testability/"/>
<updated>2013-12-25T02:48:19+13:00</updated>
<id>http://codyhatch.github.io/blog/2013/12/25/testability</id>
<content type="html"><![CDATA[<p>The more time in software development, the more I come to understand the importance of testing. Unit tests, functional tests, integration tests…the important thing is to <em>have some tests</em>.</p>
<p>When I was younger and stupider (all of, oh, 2-3 years ago) the benefit of tests seemed more nebulous. And stuff like <a href="http://en.wikipedia.org/wiki/Dependency_injection">DI</a>? That’s some crazy Java crap. Ain’t nobody got time for that stuff!</p>
<h2>I was kind of dumb</h2>
<p>So now I’ve got this fairly massive app (well, massive for a team of 2) we’ve been working on for a couple of years. And I’m starting to really wish I’d been a lot more into testing when we started. That little todo webapp you threw together to learn Ember or whatever probably doesn’t need a lot of tests. But we’ve got something like 9k lines of Coffeescript these days, plus endless Jade templates, a bunch of Stylus stylesheets, and a ton of random scripts, Ansible playbooks, config files, whatever. And a complicated architecture. We need tests!</p>
<p>…and we don’t really have them.</p>
<h2>Meh, just add them!</h2>
<p>If only it were that easy! …well, it kind of is. We do have a server (a lightweight Express app mostly just exposing a somewhat RESTful API) and it is pretty easy to add tests to it. Take a scooping helping of Mocha, a dash of Supertest, and a liberal coating of Nock, shake well, and you get some very nice, very fast, very useful functional tests.</p>
<figure class='code'><figcaption><span>A simple test</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='coffeescript'><span class='line'><span class="nv">app = </span><span class="nx">express</span><span class="p">()</span>
</span><span class='line'><span class="nv">config = </span><span class="nx">require</span> <span class="s">'./config'</span>
</span><span class='line'><span class="nx">require</span><span class="p">(</span><span class="s">'./routes'</span><span class="p">)(</span><span class="nx">app</span><span class="p">,</span> <span class="nx">config</span><span class="p">)</span>
</span><span class='line'><span class="nx">require</span> <span class="s">'./nocks'</span>
</span><span class='line'>
</span><span class='line'><span class="nx">describe</span> <span class="s">'The server'</span><span class="p">,</span> <span class="nf">-></span>
</span><span class='line'> <span class="nx">before</span> <span class="nf">(done) -></span> <span class="nx">app</span><span class="p">.</span><span class="nx">listen</span> <span class="nx">config</span><span class="p">.</span><span class="nx">PORT</span><span class="p">,</span> <span class="nx">config</span><span class="p">.</span><span class="nx">BIND</span><span class="p">,</span> <span class="nf">(err) -></span> <span class="nx">done</span> <span class="nx">err</span>
</span><span class='line'>
</span><span class='line'> <span class="nx">it</span> <span class="s">'should reject logged out requests'</span><span class="p">,</span> <span class="nf">(done) -></span>
</span><span class='line'> <span class="nx">request</span><span class="p">(</span><span class="nx">app</span><span class="p">)</span>
</span><span class='line'> <span class="p">.</span><span class="nx">get</span><span class="p">(</span><span class="s">'/api/test'</span><span class="p">)</span>
</span><span class='line'> <span class="p">.</span><span class="nx">expect</span><span class="p">(</span><span class="mi">401</span><span class="p">,</span> <span class="nx">done</span><span class="p">)</span>
</span></code></pre></td></tr></table></div></figure>
<p>Basically, I require my server code, spin up a testing instance, then make a serious of requests to the API endpoints, with all the calls to other servers mocked out with nock. And it’s amazing.</p>
<p>But our client is written with KnockoutJS, and it’s not very well organised.</p>
<h2>The options</h2>
<h3>Unit tests</h3>
<p>This makes sense. The server can be unit tested trivially, and Knockout is based on the MVVM pattern. Just require the app, and test some view models!</p>
<p><strong>Problem:</strong> Over the months and now years, a few “quick hacks” have tangled the viewmodel code with the view code. We have (just a few!) cases where viewmodel functions are referencing the window, or document globals directly, or using jQuery selectors. This won’t work in a headless unit test.</p>
<h3>Um, unit tests with JSDOM?</h3>
<p>Doesn’t implement enough. The code relies on being in a web browser, and refactoring it now, especially without tests (funny how that works) will be a nightmare.</p>
<h3>Okay, ZombieJS!</h3>
<p>Zombie is pretty awesome; it gives you a headless browser you can play with. But like JSDOM, it isn’t enough. The code expects a Webkit browser.</p>
<h3>Webkit? PhantomJS!</h3>
<p>An obvious choice. We can actually spin up a PhantomJS instance, and hit a dev server, and fetch an actual copy of the app.</p>
<p>But these aren’t unit tests any more; we’re not into the realm of acceptance or integration tests. Which is fine, but…</p>
<p><strong>Problem 1:</strong> They’re really slow. It’s a big, chunky app; it’s meant to be cached and only loaded once. Plus it does a lot of slow processing on initial load, so… These tests are slow.</p>
<p><strong>Problem 2:</strong> The PhantomJS API is a huge pain to use. Something simple like loading the app, then doing some tests to make sure the login form properly validates usernames and passwords, then logging in, waiting for the initial data to load, and then checking to make sure it loaded properly is, again, slow, but also a huge pain to write.</p>
<h3>Okay, CasperJS?</h3>
<p>Not much better. It’s just a painful API.</p>
<h3>Right, Capybara?</h3>
<p>Well, it’s ruby-centric, and we’re not a ruby shop. But it works, and it has a nice API, and I even got a couple of Lettuce+Capybara tests written.</p>
<p>But it’s still very slow to run, and very slow to write. These aren’t a replacement for the unit tests we so desperately need; at most I could write a couple as smoke tests. (Basically “log into the app, connect to the test DB, and make sure a record displays; if that works it can’t be too broken so let’s ship it into production!”)</p>
<p>But we still need unit tests. And this path doesn’t lead to unit tests.</p>
<h2>Now what?</h2>
<p>That’s a good question. I’ve got over 8k lines of poorly organised Knockout code with no unit tests, and no ability to write unit tests unless I refactor it, which will be a nightmare without…unit tests.</p>
<p>At this point, we wince, accept the technical debt, and push forward, and hope we get the resources for a proper rewrite one day.</p>
<h2>And the lesson is?</h2>
<p><strong><em>Testability matters</em></strong>. Which is why you should be writing tests from day one; not because you need them then, but because one day you’ll need them, and having tests guarantees that you can write tests. I look at the search code now, and I wince, because it’s so tightly coupled to, well, everything else, that it’s largely untestable now. But it didn’t have to be that way.</p>
<p>Also: The Knockout docs say almost nothing about testing, and google for Knockout + testing turns up very little. Culture matters, and I think that one of the big advantages Angular may have over Knockout is nothing technical; it’s just the focus the Angular community puts on testing.</p>
]]></content>
</entry>
<entry>
<title type="html"><![CDATA[Hello World]]></title>
<link href="http://codyhatch.github.io/blog/2013/12/25/hello-world/"/>
<updated>2013-12-25T02:38:58+13:00</updated>
<id>http://codyhatch.github.io/blog/2013/12/25/hello-world</id>
<content type="html"><![CDATA[<p>Let’s try the blog thing again.</p>
]]></content>
</entry>
</feed>