Wednesday, May 23, 2012

My blog is moved!

I stopped using blogger to do blogging. My new blog is chamnap.github.com.


See you there!

Monday, May 2, 2011

High Performance Website Presentation at Hackerspacepp

I’m a little bit disappointed in myself. What I intended to do presentation is about Web Scaling, but I ended up with go through the front end side. This presentation will focus on how to make your website faster on the front end side. I did focus on some aspects on HTTP concept as well. Those are rules from Steve Souders, but I modify and adjust to make it clear to the audience.

Tuesday, March 29, 2011

REST Presenation on DevCamp, Hackerspacepp

Last sunday, I talked to some people, around 10 software developers, about how to build web services using REST architecture. However, I didn't talk on my previous slide presentation. I took on Doing REST Right by Kerry Buckley. I decided to choose this slide because I feel I learnt something new and it's recommended by my boss, Chris. Actually, I were not well-prepared, but the presentation went well. I missed some slides before I went to do this presentation.

Monday, August 30, 2010

Load Balancer Algorithm Explained

I've been googling around 2 days just want to know the best way that heavy-load rails sites was handled. I'm having trouble with mongrel clusters, one of which usually dies because of some heavy requests and nginx still forwards request to that frozen mongrel (using nginx simple load balancer). I was curious what are the options to solve this. I have looked at various solutions: simple nginx load balancer, fair nginx load balancer, HAProxy, and finally Phusion Passenger. However, I didn't go through JRuby for deploy rails app and Unicorn.

Simple Load Balancer
By default, nginx is only a simple robin-round load balancer. What it does is just send those requests to one of those backends (mongrel in this case) in simple manner (a,b,a,b, ...). The round-robin algorithm is often an acceptable tool: if every request finishes within a few milliseconds, there’s no problem. In this scenario, each backend has its own queue for processing concurrent requests. Therefore, if the heavy request comes in, the queue requests in that backend will be waiting and is able to process until that long-running request finishes. So what if that heavy request process longer than 60 seconds, those queue requests will never be able to process because it has been timeout.
Another problem is that nginx would flood mongrels with too many requests and mongrel's request queue was not solid and it would quickly get stuck with too many queued requests.

Here is the configuration of nginx simple load balancer.
http {
upstream myproject {
server 127.0.0.1:8000;
server 127.0.0.1:8001;
server 127.0.0.1:8002;
server 127.0.0.1:8003;
}

server {
listen 80;
server_name www.domain.com;
location / {
proxy_pass http://myproject;
}
}
}

Fair Load Balancer
Seeing this problem, a guy from Engine Yard wrote a personal patch by adding a module in nginx called fair load balancer. What it basically does it know many requests each backend is processing and it will avoid sending further requests to already busy backends. By default, fair load balancer will assign request to idle backend first, when all are busy it will use weighted least-connection round-robin (WLC-RR) algorithm, meaning that it will assign the requests using a score that depends on both the number of requests assigned to the peer (as most important) and if all equal, to the peer that had the earliest assignment.
Another mode is whenever the first backend is idle, it's going to get the next request. If it's busy, the request will go to the second backend unless it's busy too etc.

As you can see, the backend still has its queue requests, and it will run into this scenario:
Suppose we have 3 backends which have 3 requests in their queue, except for the first backend which has only 1 request in its queue.
Backend process A: [* ] (1 request in queue)
Backend process B: [*** ] (3 requests in queue)
Backend process C: [*** ] (3 requests in queue)
Backend process D: [*** ] (3 requests in queue)

Next, new request comes in, so backend A will have 2 requests where X is the new request.
Backend process A: [*X ] (2 request in queue)
Backend process B: [*** ] (3 requests in queue)
Backend process C: [*** ] (3 requests in queue)
Backend process D: [*** ] (3 requests in queue)

Assuming that B, C and D are still processing its queues, the next request comes in (called Y), it will be forwarded to backend A because it has the least number of request queues.
Backend process A: [*XY ] (3 requests in queue)
Backend process B: [*** ] (3 requests in queue)
Backend process C: [*** ] (3 requests in queue)
Backend process D: [*** ] (3 requests in queue)

The problem arises if Backend A needs 60 seconds to process X. Y will never be processed because it has been timeout. It would be much better if Y was forward to other Backends.

Here is the configuration:
upstream mongrel {
fair;
server 127.0.0.1:5000;
server 127.0.0.1:5001;
server 127.0.0.1:5002;
}


HAProxy
Rails was traditionally and mostly deployed using Apache or nginx with either a built-in or standalone proxy (like HAProxy) against a cluster of Mongrels or Unicorns.
HAProxy is a free, very fast and reliable solution offering high availability, load balancing, and proxying for TCP and HTTP-based applications.


If using HAProxy, the setup is similar to this:

Web => Nginx => HAProxy => Mongrel

In this setup nginx just proxies to a single haproxy instance and haproxy has all registered mongrels configured. HAProxy queue is much more stable and it better balances all the requests between backends than nginx does. HAProxy has better support for upstream ok/fail detection and can also limit each app server to 1 connection (maxconn directive) which is key for mongrel. HAProxy limits the number of requests sent to mongrel instead of blindly forward requests. The fact that mongrel has only 1 request to process makes the application more scalable since the previous problem never happens. If there is one heavy request, processing that request won't affect on other requests since HAProxy only forwards request to the idle mongrel.

One downside of using this is that it brings any additional latencies.
Another thing is that it's more complicated to setup and administrate than using Phusion Passenger a.k.a. modrails or modrack.

Just to take the advantage of the maxconn directive, try nginx-ey-balancer. One thing to keep in mind is that the maxconn is per nginx worker.
upstream mongrels {
server 127.0.0.1:8001;
server 127.0.0.1:8002;
max_connections 1;
}

Phusion Passenger
Phusion Passenger is an Nginx module, which makes deploying Ruby and Ruby on Rails applications on Nginx a breeze.

It's a great tool for me to deploy rails and rack-based ruby applications. Passenger has both nginx and apache module. Passenger comes with feature called global queuing, which works similar to what I mentioned above.

The good thing about passenger, it's easier to configure than HAProxy. It has a couple of strategies to load rails application (smart, smart-lv2, conservative). It can even reduce memory to 33% if using Ruby Enterprise Edition. The installation process is to install passenger gem, which is quite up-to-date and support ruby 1.9.

I won't dig into detail about passenger, you might go through the documentation by yourself.

Tuesday, August 17, 2010

Ruby Object Model

I conduct a training on Ruby Object Model this week. I start talking about Ruby from scratch then the object model of Ruby. At the same time, I discussed about JavaScript object model.

Saturday, July 31, 2010

Cross-Domain Solutions

Recently, I found a presentation on how to solve cross domain issues. I think it's quite useful for web developers.

Friday, July 16, 2010

REST and RAILS

I made a presentation to InStedd guys recently on REST. This slide cover most parts related to REST and RAILS. Hope it could help.

Monday, May 31, 2010

ruby alias_method for class methods

Generally, a ruby programmer could alias instance methods of a ruby object, but how could he alias class methods instead? The answer is he needs to understand how "self" works in ruby. If not yet knows, check out my presentation.


class Foo
def a; 'a'; end
alias_method :alias_for_a, :a

def self.b; 'b'; end
class <<self
alias_method :alias_for_b, :b
end
end

puts Foo.new.a
puts Foo.new.alias_for_a

puts Foo.b
puts Foo.alias_for_b

Friday, February 19, 2010

Meta-programming in Ruby and JavaScript

Recently, I have been working with writing a ruby gem, Yoolk API Gem. What is really interesting for me is I do some meta programming and object-oriented programming in Ruby which I have never experienced before. A few month later, there is a requirement that my team needs to write in JavaScript, but I don't want to touch JavaScript really much. Therefore, my team member took over this task. Whenever I write code in Ruby, I just try to think how to do it in JavaScript as well. Several things that came up to my mind with some from my team member:

1. Defer class from a variable.

// JavaScript
var klass = "Person";
p = new window[klass]; //class without namespace
p = new yoolk[klass]; //class with namespace


# Ruby
klass = "Person"
p = Object.const_get(klass).new #class without namespace
p = Yoolk.const_get(klass).new #class with namespace

2. Access class method from instance object

// JavaScript
var p = new Person();
p.constructor.getCount();


#Ruby
p = Person.new
p.class.count

3. Define method of an object

//JavaScript
var p = new Person();
p.hello = function() {
alert('hello');
};


//Ruby
p = Person.new
def p.hello
puts "hello"
end

4. Define class methods

//JavaScript
Person.hello = function() {
alert('hello');
};


//Ruby
def Person.hello
puts "hello"
end

Wednesday, October 14, 2009

Script Console Tricks

Script console in rails helps me very much to debug my applications. However, I usually encounter an annoying problem with ActiveRecord. I want to see the generated SQL that has been executed. I never have enough time to figure out this until last week. Just add the following code to your environment.rb, you could see the generated SQL statement.


if "irb" == $0
ActiveRecord::Base.logger = Logger.new(STDOUT) # ActiveRecord
ActiveResource::Base.logger = Logger.new(STDOUT) # ActiveResource
end


For more information:
http://weblog.jamisbuck.org/2007/1/31/more-on-watching-activerecord
http://railscasts.com/episodes/48-console-tricks

Subscribe in a Reader