小内存vps上wordpress优化

wordpress网站优化

由于图便宜,买了一个就128M内存的vps。所以非常关注性能的问题。

性能主要是2点,php和mysql的部分。

mysql的部分网上很多都有所有说到了,不启动innodb,限制binlog cache, 限制sort buffer等等。具体可以参见如下

[mysql]
no-auto-rehash

[mysqld]
user = mysql
port = 3306
open_files_limit = 600
back_log = 20
max_connections = 100
max_connect_errors = 200
table_cache = 60
external-locking = FALSE
max_allowed_packet = 16M
sort_buffer_size = 128K
join_buffer_size = 128K
thread_cache_size = 10
thread_concurrency = 8
query_cache_size = 0M
query_cache_limit = 2M
query_cache_min_res_unit = 2k
default_table_type = MyISAM
thread_stack = 192K
transaction_isolation = READ-UNCOMMITTED
tmp_table_size = 512K
max_heap_table_size = 32M
long_query_time = 1
log_long_format
server-id = 1
binlog_cache_size = 2M
max_binlog_cache_size = 4M
max_binlog_size = 512M
expire_logs_days = 7
key_buffer_size = 4M
read_buffer_size = 1M
read_rnd_buffer_size = 2M
bulk_insert_buffer_size = 2M
myisam_sort_buffer_size = 4M
myisam_max_sort_file_size = 10G
myisam_max_extra_sort_file_size = 10G
myisam_repair_threads = 1
myisam_recover
skip-innodb

[mysqld_safe]
log-error=/var/log/mysqld.log
pid-file=/var/run/mysqld/mysqld.pid

php的部分。
使用fastcgi, 前端使用nginx来进行fastcgi代理。 fastcgi使用的php-fpm。

使用php-fpm要特别注意如下设置:

; Choose how the process manager will control the number of child processes.
; Possible Values:
; static – a fixed number (pm.max_children) of child processes;
; dynamic – the number of child processes are set dynamically based on the
; following directives:
; pm.max_children – the maximum number of children that can
; be alive at the same time.
; pm.start_servers – the number of children created on startup.
; pm.min_spare_servers – the minimum number of children in ‘idle’
; state (waiting to process). If the number
; of ‘idle’ processes is less than this
; number then some children will be created.
; pm.max_spare_servers – the maximum number of children in ‘idle’
; state (waiting to process). If the number
; of ‘idle’ processes is greater than this
; number then some children will be killed.
; Note: This value is mandatory.
pm = dynamic

; The number of child processes to be created when pm is set to ‘static’ and the
; maximum number of child processes to be created when pm is set to ‘dynamic’.
; This value sets the limit on the number of simultaneous requests that will be
; served. Equivalent to the ApacheMaxClients directive with mpm_prefork.
; Equivalent to the PHP_FCGI_CHILDREN environment variable in the original PHP
; CGI.
; Note: Used when pm is set to either ‘static’ or ‘dynamic’
; Note: This value is mandatory.
pm.max_children = 50

; The number of child processes created on startup.
; Note: Used only when pm is set to ‘dynamic’
; Default Value: min_spare_servers + (max_spare_servers – min_spare_servers) / 2
pm.start_servers = 2

; The desired minimum number of idle server processes.
; Note: Used only when pm is set to ‘dynamic’
; Note: Mandatory when pm is set to ‘dynamic’
pm.min_spare_servers = 1

; The desired maximum number of idle server processes.
; Note: Used only when pm is set to ‘dynamic’
; Note: Mandatory when pm is set to ‘dynamic’
pm.max_spare_servers = 2

不然我的小内存vps很快就会挂的。

listen的部分使用sock的方式,毕竟都是本机,而且sock的速度要比tcp要来的快的多。

listen = /var/run/phpfpm.sock

以上就是php的部分。

下面是nginx的部分

开启fastcgi cache

fastcgi_connect_timeout 300;
fastcgi_send_timeout 300;
fastcgi_read_timeout 300;
fastcgi_buffer_size 32k;
fastcgi_buffers 4 32k;
fastcgi_busy_buffers_size 64k;
fastcgi_temp_file_write_size 64k;
fastcgi_cache_path /opt/server/nginx/fastcgi_cache_dir levels=1:2 keys_zone=cache_fastcgi:128m inactive=1d max_size=1g;

fastcgi_cache cache_fastcgi;
fastcgi_cache_valid 200 302 301 1h;
fastcgi_cache_valid any 1m;
fastcgi_cache_min_uses 1;
fastcgi_cache_use_stale error timeout invalid_header http_500;
fastcgi_cache_key $request_method://$host$request_uri;

静态文件过期时间

location ~* \.(js|css|png|jpg|jpeg|gif|ico)$ {
expires max;
}

gzip压缩
由于这个vps不光内存少,1个月的带宽也少,那能减少传输就减少一点。

gzip on;
gzip_http_version 1.1;
gzip_vary on;
gzip_comp_level 6;
gzip_proxied any;
gzip_types text/plain text/xml text/css application/x-javascript;

wordpress本身的优化

使用wp-super-cache插件,这个插件可以把动态的php转换成静态的html代码,这样减少了很多fastcgi的压力,其实这个是最根本的解决方法。而且这些html又被缓存到了nginx中,这样访问的速度就会非常非常的快了。

###########################################

Best regards
Timo Seven
Linux System Admin & MySQL DBA

track服务优化之二HTTP

首先我们要了解track服务的特征。

一般互联网广告公司的代码都是嵌入在客户网站中的部分页面,而这些代码的体积也不会很大,因此针对这个特征我们就需要进行对应的http server的优化。

keepalive: 在很多教程中都是推荐开启keepalive,这样可以复用连接,但是在track的http server中还是建议关闭吧,毕竟很多用户连接你的服务器很长时间内只会一次的,你开启了keepalive就会造成很多的无效连接。

TCP_NODELAY: 由于track代码一般都比较小,经常只有几百个字节,而默认tcp会开启nagle算法,这个算法是鼓励发送全尺寸的的数据段,而我们的track代码可能无法填充满一个分组,于是导致等待的延时。有时候会有100ms到200ms的延时。 如果你的track代码大于1500个字节的话,那也可以开启这个算法。

Connection header: 在http的头部中有个connection的部分, 由于一般track代码只运行一次,运行完成我们就需要尽快关闭连接,所以在connection头部返回的时候我们直接变成 Connection: close以此来尽快关闭连接。

增加缓存时间: 由于很多track code不会经常经常进行更改,所以为了避免每次都下载,可以增加相应的过期时间。

开启sendfile: 这个就现在http server基本都是默认开启的。原因就是省去在内核空间和用户空间进行切换了。

这篇文章写的有点干巴巴,没啥营养,基本上都是一些nginx http server的设置吧。 下一篇关于tcp部分的要好好写了。也算是看完tcp/ip详解卷一的一个总结吧。

track服务优化

track服务优化之一 : DNS和域名

在互联网广告公司里,有一些服务是用作跟踪用户的,而这些代码嵌入的不多,qps也不高,然后文件大小也比较小,对于这样的应用我们如何进行优化呢。

我们http请求第一步开始说起。

大部分的http请求都是通过dns来进行的,这样dns解析的速度也关系到整个访问的速度。 下图中我们可以很明显的看到,这个请求最大的2个部分就是dns和内容下载。

14142519581_cde92247c1_z.jpg

我们知道DNS的缓存时间都由DNS设置TTL时间来决定的(除了部分local dns做强制缓存),而当一个域名在local dns中没有缓存时,local dns就会以迭代的方式去查询这个域名的解析。比如我们通过trace来模拟一个本地没有缓存的迭代过程。

下面是我们解析www.sohu.com的一个例子。 我们可以看到这里,首先是找到根域名的服务器,然后找到所有.com域名的根服务器,然后找到sohu.com域名的根服务器,然后解析了www.sohu.com, 而由于www.sohu.com做了一次cname,所以要进行解析,最终得到对应的IP地址。

而这个过程中,我们发现实际去dns.sohu.com的时间才52ms,而他去到根域名服务器和.com根域的解析时间加起来要452ms,而这个时间都是算在整个请求的时间内的。

14142949292_3223302e28_z.jpg

从上可以看到加快DNS解析速度的重要性,而在local dns中缓存是重重之重。而这个第一步就是统一域名,发现国内某些广告商居然用好多域名来进行跟踪。而google却只用了一个单独域名来进行。

下图是我直接访问这家广告公司的跟踪域名,可以看到光dns解析的时间就903ms,这个还是他们使用了dnspod的服务器的情况下。
14142949232_ddcb4b2a20_c.jpg

而他们的很多广告都使用了不同的域名,不过经过查询是应该用了泛域名解析。但是实际dns请求的时候还是会有延迟啊,local dns可不管是不是泛域名呢。 而这家广告商的这些域名指向最终都是同一个IP,那为什么不用单个域名呢?
14165904063_24dcd230ba_z.jpg

而我们看google ga,所有的ga使用的域名都是同一个。这样从dns层面减少了响应的时间。
14142519561_8ec892a088_c.jpg

从上面我们得到,使用单一域名在dns层面的好处是比较大的。

加快DNS解析速度的另外一个因素就是TTL时间。这个从解析速度来看自然是越大越好,比如很多根域名服务器都是缓存1周的,但是我们看到大量的还是缓存1个小时的。毕竟时间放太长,一旦网络出了问题都没办法切换。所以有些请求量很大的域名的ttl时间都是120秒左右的,就是怕万一有问题来不及切换。

这个就没有绝对的要求,全看各自的dns服务器的分布和性能了。


vmware下内存丢失查找

有台服务器,4G内存的。 可以显示可用的内存数字有1070MB, 可机器上没有什么进程占用大量的内存啊,于是就慢慢开始找原因了。

然后用了之前yufeng提供的一段内存检查的代码来进行检查,看是否有slapinfo和pagetable占用的多。

#/bin/bash
for PROC in `ls /proc/|grep "^[0-9]"`
do
if [ -f /proc/$PROC/statm ]; then
  TEP=`cat /proc/$PROC/statm | awk '{print ($2)}'`

  RSS=`expr $RSS + $TEP`
fi
done
RSS=`expr $RSS * 4`
PageTable=`grep PageTables /proc/meminfo | awk '{print $2}'`
SlabInfo=`cat /proc/slabinfo |awk 'BEGIN{sum=0;}{sum=sum+$3*$4;}END{print sum/1024/1024}'`

echo $RSS"KB", $PageTable"KB", $SlabInfo"MB"
printf "rss+pagetable+slabinfo=%sMBn" `echo $RSS/1024 + $PageTable/1024 + $SlabInfo|bc`
free -m

可执行下来的结果,显示已用的vmrss+pagetable+slapinfo总共才1.4GB左右

于是想是不是一些inode占用了比较多的内存,于是在sysctl.conf中加入了如下参数将内存的caches,denties和inodes等信息sync到磁盘上

vm.drop_caches = 3

可执行了sysctl后也就清理了50MB内存,那剩下的内存呢。

然后就查看/proc/meminfo,看看是否free命令有bug啊

看来这里也没有啊,这个结果跟free出来的结果是一致的。

于是就开始 /proc/PID/status 里面的vm部分进行累加计算,发现vmsize的累加的值跟这个内存使用的大小还是很接近的。

for PROC in `ls /proc/|grep "^[0-9]"`
do
  if [ -f /proc/$PROC/status ]; then
      TEP=`grep  'VmSize' /proc/$PROC/status |awk '{print ($2)}'`
      if [ ! -n $TEP ];
	  then
	  	TEP=0
	  fi
	  VMSIZE=`expr $VMSIZE + $TEP`
  fi
done
echo $VMSIZE

这个时候想到,这个虚拟机是在vmware之上的,会不会是vmware的一个bug呢。放狗搜索了一把,还真果然很多人提到了这个问题。

https://access.redhat.com/site/solutions/43729

http://forums.opensuse.org/showthread.php/466043-memory-usage-problem-11-4-vmware

无论是opensuse还是rhel都有这个问题啊。 里面也说到最终的解决办法了,它是直接就关闭了,不过由于vmware-tools带了一些比较好的驱动等等,所以我这边还是先重启一下,后期再改一下guest memory manager部分。

一次诡异的网络故障

今天碰到一个诡异的网络故障,在复杂的网络条件下,保证条理的清楚是很重要的,为了警醒自己,特记录如下。

早上碰到一个事情,说IDC之间的VPN挂了,但是看了监控,发现2个IDC之间ping是没有问题的。

先描述一下网络环境。 2个IDC,一个在国内一个在国外,暂时是用pptp连接的,2边都有硬件防火墙。硬件防火墙在上周做了一次策略升级。pptp两边都是之前用linux server搭建的,2边出和进的pptp server都是单独的。基本架构就是下面这个草图了。

内嵌图片 1

现在问题是,2个IDC之间的服务器有些可以ping通,有些不行,刚好加监控的都可以。 端口也可以telnet, 但是无法建立连接,一建立连接就被reset, tcpdump的结果就是如下这样的,下面这个是建立rsync的一次连接。

内嵌图片 2
好了,情况都描述完成了,如何处理吧看。

这台rsync服务器检查了本身,发现没有问题,因为从本地机房进行rsync没有问题。 那问题就应该是在pptp 或者firewall上面了。

由于上周firewall做了一次升级,恢复了配置,发现问题依旧。

于是我思维凌乱了,这个是什么情况呢?

两边可以ping,但是建立被reset, 让我感觉怎么像是gfw干的事情呢。

抱着最后一丝希望,就一点点排错吧。

首先确定了2边IDC各自内部都没有问题。 于是从pptp client上进行查,这下发现了奇怪的现象。

从pptp client服务器到另外IDC的rsync居然是可以建立连接的,那问题就应该是pptp client上了, 回想了一下之前的操作,发现了问题所在。

因为这个pptp client还拨到了c机房,之前在iptalbes中nat链里的out interface是写死了ppp0和ppp1的,但是由于不定时断线,所以哪条是ppp0,哪条是ppp1是不固定的。

于是这次本来去B IDC应该是走ppp1的,结果走了ppp0,从而导致了异常的故障发生。 从这个可以看出来, iptables的nat链是有点问题的,正常情况out interface指错了的话应该就是不通的。 但是查了man一下,发现如果没有指对的话它就会乱走,有没有规律那就再看源码了。

cleardot.gif

iptables filter

最近发现dns请求里有一些不正常的域名请求,由于bind9早期的版本在这方面比较弱,而且再越上层做越好,那就在iptables上做最好了,当然在外网防火墙上做也行,2层过滤更好。

在iptables有一个string模块就是用来做这个事情,支持很多种模式,u32, string, hex-string 都有,效率最高的是u32了。 具体看看自己iptables支持那些模式可以查看以下文件

/proc/net/ip_tables_matches

具体的过滤命令很容易,就一句, 意思就是过滤input链的udp的53端口,匹配里面的数据含有packetdevil字符的直接drop掉。

-A INPUT -p udp --dport 53 -m string --algo bm --string "packetdevil" -j DROP

这里面的algo表示实用那种匹配的算法,man一下看到bm和kmp两种算法,但是还是不甚了解。google了一下发现这个阮一峰很久以前就写过了关于2个算法的详细解释,这个wiki上也有详细解释。具体就不说了,大家看一下就能明白了。

–algo {bm|kmp}
Select the pattern matching strategy. (bm = Boyer-Moore, kmp = Knuth-Pratt-Morris)

http://www.ruanyifeng.com/blog/2013/05/boyer-moore_string_search_algorithm.html
http://www.ruanyifeng.com/blog/2013/05/Knuth%E2%80%93Morris%E2%80%93Pratt_algorithm.html

 

但是我也发现了一个问题,其实我之前是想要匹配的是packetdevil.com, 但是网上都是说直接写这个就可以了,可是我加上.com后无法进行匹配,然后怕是 . 这个特殊字符导致的,于是用hex-string来匹配,可是也同样无法匹配到,这个就奇怪了,u32模式由于要重新编译就没有做,有谁看到的就麻烦指点一下,谢谢了!

磁盘信息

在linux下想看什么分区对应的哪个盘没有第三方工具根本搞不定啊。默认的/dev/disk/by-id/ 还是太弱了。网上找到如下工具。主要是分为raid模式和非raid模式。

而且现在各种raid,就得注意哪个raid分的是哪个磁盘哪个分区。

无raid模式下很简单,一个物理硬盘就代表一个设备。主要工具是sdparm或者是hdparm。 这2个工具其实是差不多的。只是现在都是sata2以后的接口了,所以还是sdparm更多点


sdparm -p sn /dev/sda 对应与 hdparm -i /dev/sda

[timo@11 hdparm-9.43]# sdparm -p sn /dev/sda
/dev/sda: ATA ST32000645NS RA0A
Unit serial number VPD page:
Z1K000VR

#ST32000645NS:这个就是磁盘的型号
#Z1K000VR: 这个是磁盘的序列号

而对于装了megacli工具的,那也可以用下面命令查看Inquiry Data这行信息就能知道了。
megacli -PDList -aALL

还有工具是lsscsi工具也可以,但是这个工具看不到序列号。

有raid模式的稍微复杂点了,只能通过megacli这样的工具来看了,下面这个命令的slot number就是对应的插槽号。

megacli -cfgdsply -aALL

如果用lsscsi显示的话,可以看到那行显示的就是磁盘的型号,而是raid卡型号。

[timo@11 ~]# lsscsi -p
[0:2:0:0] disk DELL PERC H710 2.12 /dev/sda