But 256MB of ram? what can you do with just 256?
Normally a default 256mb linux machine would not handle very well a set of Apache + Mysql + 1 mongrel/thin/ebb instance. due to the high memory usage of a default configuration, it will swap very often.
After much research and instinct i made it run one thin servers with mysql and nginx, without any swapping, and really fast as it can be.
If your linux start swapping often your performance will go down to the floor... Swapping is bad, specially on a XEN VPS.
The trick is to setup Mysql to use MYISAM and use Nginx instead of apache.
Here is the process list with the Resident Memory usage, after 30 days uptime and about 1,800 page views on the website.
| Mysqld 5.0.54 : | 7.5 MB |
| Thin server each : | 66.5 MB |
| Nginx 0.6.29 : | 3.5 MB (1 worker) |
| Postfix | 4.2 MB |
As you can see, total of memory usage of the applications on the server is about 83 MB, thus leaving the server with 170MB of ram for the linux itself and file cache.
this is what #free command tells:
total used free shared buffers cached
Mem: 256 235 20 0 54 62
-/+ buffers/cache: 128 128
Swap: 511 0 511
Nice uh?
you can also make use of the nice tool called "vmstat"
it's very import that 'si' (swap in) and 'so' (swap out) stays zero all the time.
i.e. running vmstat 10 times with a 4 seconds interval. (ignore the 1st line)
# vmstat 4 10 procs -----------memory---------- ---swap-- -----io---- -system-- ----cpu---- r b swpd free buff cache si so bi bo in cs us sy id wa 0 0 116 14900 56668 62692 1 1 3 3 9 5 0 0 100 0 0 0 116 14908 56668 62692 0 0 0 0 34 53 0 0 100 0 0 0 116 14968 56668 62692 0 0 0 0 37 54 0 0 100 0 0 0 116 14968 56668 62692 0 0 0 0 31 52 0 0 100 0 ....
Here is the recipe:
1. Use MyIsam instead of InnoDB
You can read about it more in here: http://blog.evanweaver.com/articles/2007/04/30/top-secret-tuned-mysql-configurations-for-rails/I forgot to add that you need to dump your database first:
mysqldump -u root --all-databases > dump.sql
then change my.cnf accordingly,
restart mysql and reload the database
mysql -u root < dump.sql
Change only the values for my.cnf as shown below, and delete all innodb related stuff
# can be safely set to 1M if you are really tight on Ram key_buffer = 4M max_allowed_packet = 1M table_cache = 32 sort_buffer_size = 512k net_buffer_length = 8K read_buffer_size = 512k read_rnd_buffer_size = 512K # can be safely set to 1M myisam_sort_buffer_size = 2M language = /usr/share/mysql/english # security: # using "localhost" in connects uses sockets by default # skip-networking bind-address = 127.0.0.1 # No logging, # make sure you backup your database more often. #log-bin server-id = 1 # point the following paths to different dedicated disks tmpdir = /tmp/ # Very important to have this here. # otherwise it will still load InnoDB. skip-innodb [mysqldump] quick max_allowed_packet = 16M [mysql] # uncomment the next directive if you are not familiar with SQL #safe-updates [isamchk] key_buffer = 8M sort_buffer_size = 8M read_buffer = 2M write_buffer = 2M [myisamchk] key_buffer = 8M sort_buffer_size = 8M read_buffer = 2M write_buffer = 2M [mysqlhotcopy] interactive-timeoutIf you get problems reloading the database, stop mysql delete the contents in /var/lib/mysql/* , then run mysql-installdb and start it and reload again the sql dump file.
Actually that's the way i most prefer..
2. Use nginx
this is an example nginx config file, located at /etc/nginx/nginx.conf
user nginx nginx;
# set to 2 or 3 if you have more processors or cores.
# it will use about 3MB per worker
worker_processes 1;
error_log /var/log/nginx/error_log info;
events {
# default is 8192
worker_connections 1024;
use epoll;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main
'$remote_addr - $remote_user [$time_local] '
'"$request" $status $bytes_sent '
'"$http_referer" "$http_user_agent" '
'"$gzip_ratio"';
client_header_timeout 10m;
client_body_timeout 10m;
send_timeout 10m;
client_body_buffer_size 128k;
proxy_buffer_size 4k;
proxy_buffers 4 32k;
proxy_busy_buffers_size 64k;
proxy_temp_file_write_size 64k;
connection_pool_size 256;
client_header_buffer_size 1k;
large_client_header_buffers 4 2k;
request_pool_size 4k;
gzip on;
gzip_http_version 1.1;
gzip_comp_level 6;
gzip_proxied any;
gzip_types text/plain text/html text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript;
gzip_buffers 16 8k;
# Disable gzip for certain browsers.
gzip_disable "MSIE [1-6]\.(?!.*SV1)";
gzip_min_length 1100;
output_buffers 1 32k;
postpone_output 1460;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 75 20;
ignore_invalid_headers on;
index index.html;
# The following includes are specified for virtual hosts
include /var/www/apps/bla.com/shared/config/nginx.conf;
}
this is an example vhost file
upstream mongrel_bla_com {
server 127.0.0.1:8001;
}
server {
listen 80;
client_max_body_size 40M;
server_name bla.com www.bla.com;
root /var/www/apps/bla.com/current/public;
access_log /var/www/apps/bla.com/shared/log/nginx.access.log;
location / {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect false;
if (-f $request_filename/index.html) {
rewrite (.*) $1/index.html break;
}
if (-f $request_filename.html) {
rewrite (.*) $1.html break;
}
if (!-f $request_filename) {
proxy_pass http://mongrel_bla_com;
break;
}
}
location ~* ^.+\.(jpg|js|jpeg|png|ico|gif|txt|js|css|swf|zip|rar|avi|exe|mpg|mp3|wav|mpeg|asf|wmv)$ {
root /var/www/apps/bla.com/current/public;
}
}
3. Remove unnecessary Services you dont need.
Some linux distros have enabled by default services we dont need.
such as cupsd, apmd, acpid, mdns, samba, nfs, ftpd... etc...
This is my make.conf in case it helps
Note that I set MAKEOPTS="-J1" , it will only use 1 gcc process at the time, and not disturb the system, (machine has 4 cores)
Also portage_niceness to 18, to make sure it will run smooth and not disturb thin and mysql.
from nice man page: "Nicenesses range from -20 (most favorable scheduling) to 19 (least favorable)."
CFLAGS="-march=athlon64 -O2"
CHOST="x86_64-pc-linux-gnu"
CXXFLAGS="${CFLAGS}"
MAKEOPTS="-j1"
USE="3dnow 3dnowext apache2 \
bash-completion bzip2 \
-cups \
gzip httpd hpn \
innodb imagemagick \
javascript jpeg \
mmx mmxext mysql \
nptl nptlonly \
perl phyton png \
ruby \
screen sse sse2 sqlite sqlite3 ssl \
threads udev unicode utf8 \
vim-syntax \
-X -kde -gnome -gtk -bindist \
xml xml2 zlib "
GENTOO_MIRRORS="http://mirror.datapipe.net/gentoo http://gentoo.cites.uiuc.edu/pub/gentoo/ ftp://gentoo.mirrors.tds.net/gentoo http://ge
APACHE2_MPMS='worker'
PORTAGE_NICENESS=18
if you want to use mod_rails Passenger, set APACHE2_MPMS='prefork'
note: I am positive you can throw in another thin server instance, and it will still not swap, or swap very little at all.
have fun
**************************
Updates :
Wanna know what Slicehost Manager Diagnostics says about my VPS ?
Diagnostics
* Your slice is currently running.
* The host server is up.
* Your swap IO usage over the last 4 hours is low: 0.0016 reads/s, 0.0 writes/s. (Read more about swap here)
* Your root IO usage over the last 4 hours is low: 0.038 reads/s, 0.1643 writes/s.
* The host server's load is nominal: 0.00, 0.03, 0.00.
;)