Boosting performance using Redis
The event-driven model of Node.js is supposed to be beneficial for resolving the C10K issue. It's been a long time since this site is up. I haven't encountered any problems yet. The traffic is still very low I presume no one is gonna know how awesome ( probably not ) the way my site was built. So last week I did a stress test with the ab command.

Result:
root@debian:/home/penguin# ab -r -k -c 20 -n 250 https://blog.astropenguin.net/
This is ApacheBench, Version 2.3 <$Revision: 1604373 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking blog.astropenguin.net (be patient)
Completed 100 requests
Completed 200 requests
Finished 250 requests


Server Software:        Apache/2.4.10
Server Hostname:        blog.astropenguin.net
Server Port:            443
SSL/TLS Protocol:       TLSv1.2,ECDHE-RSA-AES256-GCM-SHA384,2048,256

Document Path:          /
Document Length:        17570 bytes

Concurrency Level:      20
Time taken for tests:   53.077 seconds
Complete requests:      250
Failed requests:        0
Keep-Alive requests:    250
Total transferred:      4460520 bytes
HTML transferred:       4392500 bytes
Requests per second:    4.71 [#/sec] (mean)
Time per request:       4246.175 [ms] (mean)
Time per request:       212.309 [ms] (mean, across all concurrent requests)
Transfer rate:          82.07 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0  118 551.2      0    3493
Processing:   969 4099 1099.0   3958    6260
Waiting:      954 4084 1098.8   3942    6245
Total:        969 4218 1250.7   4136    8561

Percentage of the requests served within a certain time (ms)
  50%   4136
  66%   4975
  75%   5060
  80%   5244
  90%   5519
  95%   5899
  98%   7678
  99%   8472
 100%   8561 (longest request)

The result has proven that my site is shit.

BotanJS API Blockage



The problem causing the request to wait was mainly because Rosemary was waiting for the Service API to return the corresponding js/css.

Js/CSS are mostly considered static, as long as the source haven't changed. It should be delivered quickly without any problem.

However, because of the nature of BotanJs. it compiles these resources on the fly and the API call is done via http internally ( http://localhost:5000/ ). Shit, I've just created a problem that shouldn't be a problem!

Welp, I guess I need a way to cache the resources acquisition mappings. They probably wouldn't change if the content stays the same. ( That depends on what components I need for writing each blog entry. As the BotanJs is going to minimize the size of the compiled source to extreme, 90%1 of the style / script will be call / used on that page. ) 

An Organic Approach

After some struggling, I have listed some possible approach I could think of:
1. Compile everything into one single, big, all-purpose js/css file. Serve them on every page ( General approach )
2. Compile the scripts in Rosemary, eliminating the *calling layer*
3. Use a cached map to lookup the corresponding file

Most of the site goes for Solution 1 because it is easier to manage and reliable. And because of that js/css is already in their computer after the first load. The next page they visit will be rendering faster because the only resource the browser need to get is the page itself.

I'd say FUCK THAT. Most people stumble upon my blog are just one-time visitor. So every single page should be optimized and should be equally fast even for first load. I hate jquery because many people are using then like whatever and punch in those empty calls2. Using this approach just violates the policy of BotanJs. The goal of BotanJs is to eliminate ( or minimize, at least ) those useless crap when it is not needed.

The only way Rosemary can tell if the resource is up to date is by asking the Service API. But asking it every time does no good. So to reduce the overhead. I have to ask in a way that it will not make the request to wait.

Solution 2 is not practical because the compiling / resolving process costs time and probably won't do much comparing to the http overhead. But it could be done via Node.js.
 
So I go for Solution 3. By setting a timeout for the Service calling, it will instead look for the file compiled last time and use it after the timeout occurred.



Deployment issue


To ensure the content delivery is always the latest. I have to make sure the old content should not be delivered after the source has been updated. This could be achieved by clearing the cached mappings after deployment.

That's why I call this organic - when the number of client increases, the server become *rash* and try to deliver contents as fast as possible. So it ain't have time to wait for that Service call to return.

This was essentially the same concept I used in implementing the lastlog - with the cooldown approach.

( A day later )

Now, let's see the results:
root@debian:/home/penguin# ab -r -k -c 20 -n 250 https://blog.astropenguin.net/
This is ApacheBench, Version 2.3 <$Revision: 1604373 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking blog.astropenguin.net (be patient)
Completed 100 requests
Completed 200 requests
Finished 250 requests


Server Software:        Apache/2.4.10
Server Hostname:        blog.astropenguin.net
Server Port:            443
SSL/TLS Protocol:       TLSv1.2,ECDHE-RSA-AES256-GCM-SHA384,2048,256

Document Path:          /
Document Length:        17570 bytes

Concurrency Level:      20
Time taken for tests:   49.450 seconds
Complete requests:      250
Failed requests:        0
Keep-Alive requests:    250
Total transferred:      4460520 bytes
HTML transferred:       4392500 bytes
Requests per second:    5.06 [#/sec] (mean)
Time per request:       3956.035 [ms] (mean)
Time per request:       197.802 [ms] (mean, across all concurrent requests)
Transfer rate:          88.09 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0  109 550.3      0    3743
Processing:   452 3758 838.6   3928    6214
Waiting:      437 3742 838.6   3911    6199
Total:        452 3866 984.6   3932    8504

Percentage of the requests served within a certain time (ms)
  50%   3932
  66%   3973
  75%   4254
  80%   4275
  90%   4341
  95%   5416
  98%   7075
  99%   7116
 100%   8504 (longest request)

Aaaaand it is still shit. But from the log I could see that the overhead of API calling is solved.

Next stop, profiling!
  1. This might also vary as how well you split your classes
  2. If a specific rule does not match, than the rest of the code will not execute. But the rule matching itself count as a call. And then you just ended up by matching every possible rule for the entire site! And every page runs a tiny portion of the enormous code. fffffffuuuuuuuuuuuu!
Tag(s): c10k botanss
Profile picture
斟酌 鵬兄
Thu Jun 02 2016 03:17:52 GMT+0000 (Coordinated Universal Time)
Last modified: Sun Apr 10 2022 12:30:38 GMT+0000 (Coordinated Universal Time)
Comments
No comments here.
Do you even comment?
website: 
Not a valid website
Invalid email format
Please enter your email
*Name: 
Please enter a name
Submit
抱歉,Google Recaptcha 服務被牆掉了,所以不能回覆了