2014年2月10日星期一
nginx 之图片缓存服务器
大量的图片需要专业的图片服务器来存放。由于 nginx 可以取代 squid 作为代理缓存使用,今天抽空
试了一把,感觉还是不错的。看过程:
编译:增加一个 cache_purge 模块,用来清缓存。
./configure --prefix=/home/ngx_openresty --with-http_stub_status_module \ --add-module=/root/ngx_cache_purge-master/ --with-pcre=/home/tao.li1/pcre-8.30
nginx 主要配置部分:
proxy_temp_path /dev/shm/img_temp; proxy_cache_path /dev/shm/img_cache levels=1:2 keys_zone=pic_cache:500m inactive=1d max_size=10g; server { listen 82; server_name sample.com; location / { proxy_cache pic_cache; proxy_cache_valid 200 304 24h; proxy_cache_key $host$uri$is_args$args; proxy_set_header Host $host; proxy_set_header X-Forwarded-For $remote_addr; proxy_pass http://127.0.0.1:88; expires 1d; } location ~ /purge(/.*) { allow 127.0.0.1; proxy_cache_purge pic_cache $host$1$is_args$args; } } server { listen 88; server_name 127.0.0.1; root /diska/htdocs/images/; location ~ .*\.(gif|jpg|jpeg|png|bmp|swf|ico)$ { expires 10s; #expires -1; access_log logs/88pic.log; } }
测试一下,连续两次访问:
[root@m88 logs]# curl -I 'http://127.0.0.1:82/color.png' HTTP/1.1 200 OK Server: ngx_openresty/1.4.3.9 Date: Thu, 02 Jan 2014 03:03:11 GMT Content-Type: image/png Content-Length: 892 Connection: keep-alive Last-Modified: Thu, 12 Apr 2012 08:50:01 GMT ETag: "4f869739-37c" Expires: Fri, 03 Jan 2014 03:03:11 GMT Cache-Control: max-age=86400 Accept-Ranges: bytes [root@m88 logs]# ls -lh total 16K -rw-r--r-- 1 root root 530 Jan 2 11:03 88pic.log -rw-r--r-- 1 root root 527 Jan 2 11:03 access.log [root@m88 logs]# curl -I 'http://127.0.0.1:82/color.png' HTTP/1.1 200 OK Server: ngx_openresty/1.4.3.9 Date: Thu, 02 Jan 2014 03:03:22 GMT Content-Type: image/png Content-Length: 892 Connection: keep-alive Last-Modified: Thu, 12 Apr 2012 08:50:01 GMT ETag: "4f869739-37c" Expires: Fri, 03 Jan 2014 03:03:22 GMT Cache-Control: max-age=86400 Accept-Ranges: bytes [root@m88 logs]# ls -lh total 16K -rw-r--r-- 1 root root 530 Jan 2 11:03 88pic.log -rw-r--r-- 1 root root 701 Jan 2 11:03 access.log
通过access log 的大小,我们可以发现, 88pic.log 对 color.png 的访问已经没有新增记录,前端的文件大小有了变化,
说明第二次访问使用的已经是服务器端缓存。要清除这个缓存,只需要:
[root@m88 logs]# curl -I 'http://127.0.0.1:82/purge/color.png'
再来看一下相关细节:
1. curl 获取的 Cache-Control: max-age=86400,和nginx 配置中的前端 expires 对应,这个没有疑问。
2. 那么实际上图片缓存在服务器上的时间是多少? 还是要依赖 proxy_cache_path 中 inactive 的时间。
我自己做了几个测试,将 后端 88 端口的时间修改为 -1或者no cache (也就是不缓存),proxy_cache_path
inactive 时间和前端的 expires 都是无效的。即:
proxy_cache_path /dev/shm/img_cache levels=1:2 keys_zone=pic_cache:500m max_size=10g; http { server { listen 82; ...... ...... } server { listen 88; ...... ...... } }
上面的配置注定你想要的缓存功能无法实现。
那这个优先级到底是怎样一个关系呢? 经过再后面的几次测试,发现,缓存有效的时间是以 proxy_cache_path 中的
inactive 的值和 后端 88 中 expires 较小的一个值决定的,相等当然最好。也就是如果配置是这样:
proxy_cache_path /dev/shm/img_cache levels=1:2 keys_zone=pic_cache:500m max_size=10g; http { server { listen 82; ...... ...... } server { listen 88; ...... ...... } }
缓存的有效时间是 10s (以后端的为准);我们可以看服务器上的缓存文件(我是通过curl 模拟一次请求),可以看到
这个缓存文件 /dev/shm/img_cache/4/39/40aaedc4a0bd8e5d6e507e7eca39b394 的时间变了:
[root@m88 logs]# curl -I '127.0.0.1:82/color.png' && ls -l /dev/shm/img_cache/4/39/40aaedc4a0bd8e5d6e507e7eca39b394 && sleep 90 && curl -I '127.0.0.1:82/color.png' && ls -l /dev/shm/img_cache/4/39/40aaedc4a0bd8e5d6e507e7eca39b394 HTTP/1.1 200 OK Server: ngx_openresty/1.4.3.9 Date: Thu, 02 Jan 2014 06:31:50 GMT Content-Type: image/png Content-Length: 892 Connection: keep-alive Last-Modified: Thu, 12 Apr 2012 08:50:01 GMT ETag: "4f869739-37c" Expires: Thu, 02 Jan 2014 06:31:49 GMT Cache-Control: no-cache Accept-Ranges: bytes -rw------- 1 nobody nobody 1267 Jan 2 /dev/shm/img_cache/4/39/40aaedc4a0bd8e5d6e507e7eca39b394 HTTP/1.1 200 OK Server: ngx_openresty/1.4.3.9 Date: Thu, 02 Jan 2014 06:33:20 GMT Content-Type: image/png Content-Length: 892 Connection: keep-alive Last-Modified: Thu, 12 Apr 2012 08:50:01 GMT ETag: "4f869739-37c" Expires: Thu, 02 Jan 2014 06:33:19 GMT Cache-Control: no-cache Accept-Ranges: bytes -rw------- 1 nobody nobody 1267 Jan 2 /dev/shm/img_cache/4/39/40aaedc4a0bd8e5d6e507e7eca39b394
对比两个 access log 可以发现
[root@m88 logs]# ls -lh total 16K -rw-r--r-- 1 root root 875 Jan 2 14:33 88pic.log -rw-r--r-- 1 root root 870 Jan 2 14:33 access.log
也都是两次请求。所以这个 expires 是 10s, 认为过期后会从服务器上重新去取。那么如果配置是这样:
proxy_cache_path /dev/shm/img_cache levels=1:2 keys_zone=pic_cache:500m max_size=10g; http { server { listen 82; ...... ...... } server { listen 88; ...... ...... } }
我们可以理解为缓存文件 /dev/shm/img_cache 在10s 内无请求,自动清除,需要重新下载一份作为缓存,所以需要访问后端。有效时间仍然是 10s。
3. 主要是关于 proxy_cache_path 中的参数:
1) levels 指定目录的层次,这个比较好理解。最多好像是三层目录。
2) keys_zone 设置缓存名字和共享内存大小;名字不多说,主要说大小,这里是针对单个nginx 进程最大可以使用多大内存来保留;
3) inactive 删除过期文件的时间,默认好像是10 分钟,如果删了,必须重新缓存;
4) max_size 最多使用的大小,这里是指定的使用目录如 /dev/shm/img_cache 大小。
发现shell 中date 的一个bug
[root@APP ~]# date +%Y-%m-%d
2013-11-01
[root@APP ~]# date -d "-1 month" "+%m "
10
[root@APP ~]# date -s 2013-12-01
Sun Dec 1 00:00:00 CST 2013
[root@APP ~]# date -d "-1 month" "+%m "
11
[root@APP ~]# date -s 2013-12-31
Tue Dec 31 00:00:00 CST 2013
[root@APP ~]# date -d "-1 month" "+%m "
12
[root@APP ~]# date -s 2013-12-30
Mon Dec 30 00:00:00 CST 2013
[root@APP ~]# date -d "-1 month" "+%m "
11
当今天是31 号的时候,计算就会出现失误了,我再以典型的2月为例子:
(这种计算是减去上个月的天数(例如2月的28 天)
[root@APP ~]# date -s 2014-03-28
Fri Mar 28 00:00:00 CST 2014
[root@APP ~]# date -d "-1 month" "+%m "
02
[root@APP ~]# date -s 2014-03-29
Sat Mar 29 00:00:00 CST 2014
[root@APP ~]# date -d "-1 month" "+%m "
03
[root@APP ~]#
找到一个靠谱的解决办法:
[root@APP ~]# date +%Y-%m-%d
2014-03-29
[root@APP ~]# date +%Y-%m-%d -d "-$(date +%d)days -0 month"
2014-02-28
[root@APP ~]# date -d last-month +%Y-%m-%d
2014-03-01
[root@APP ~]# date -d "-1 month" "+%Y-%m-%d"
2014-03-01
2013-11-01
[root@APP ~]# date -d "-1 month" "+%m "
10
[root@APP ~]# date -s 2013-12-01
Sun Dec 1 00:00:00 CST 2013
[root@APP ~]# date -d "-1 month" "+%m "
11
[root@APP ~]# date -s 2013-12-31
Tue Dec 31 00:00:00 CST 2013
[root@APP ~]# date -d "-1 month" "+%m "
12
[root@APP ~]# date -s 2013-12-30
Mon Dec 30 00:00:00 CST 2013
[root@APP ~]# date -d "-1 month" "+%m "
11
当今天是31 号的时候,计算就会出现失误了,我再以典型的2月为例子:
(这种计算是减去上个月的天数(例如2月的28 天)
[root@APP ~]# date -s 2014-03-28
Fri Mar 28 00:00:00 CST 2014
[root@APP ~]# date -d "-1 month" "+%m "
02
[root@APP ~]# date -s 2014-03-29
Sat Mar 29 00:00:00 CST 2014
[root@APP ~]# date -d "-1 month" "+%m "
03
[root@APP ~]#
找到一个靠谱的解决办法:
[root@APP ~]# date +%Y-%m-%d
2014-03-29
[root@APP ~]# date +%Y-%m-%d -d "-$(date +%d)days -0 month"
2014-02-28
[root@APP ~]# date -d last-month +%Y-%m-%d
2014-03-01
[root@APP ~]# date -d "-1 month" "+%Y-%m-%d"
2014-03-01
php-fpm 配置不当 导致 nginx 502 错误一例
不要总看nginx 的日志文件。
cat /home/php/logs/php-fpm.log 部分内容如下
"Error: Wrong IP address ' 10.11.80.49' in listen.allowed_clients"
"Error: Connection disallowed: IP address '10.11.80.49' has been dropped."
ERROR: Connection disallowed: IP address "10.11.80.49" has been dropped
回头且看php-fpm 配置文件
cat /home/php/etc/php-fpm.conf
[global]
pid = /home/php/logs/php-fpm.pid
error_log = /home/php/logs/php-fpm.log
log_level = notice
[www]
listen = 10.11.80.49:9000
listen.allowed_clients = 10.11.80.47,10.11.80.48, 10.11.80.49
user = nobody
group = nobody
slowlog = /home/php/logs/slow.log
catch_workers_output = yes
request_terminate_timeout = 30s
request_slowlog_timeout = 5s
pm = dynamic
pm.max_children = 100
pm.start_servers = 50
pm.min_spare_servers = 5
pm.max_spare_servers = 100
就是这里
[www]
listen = 10.11.80.49:9000
listen.allowed_clients = 10.11.80.47,10.11.80.48, 10.11.80.49
user = nobody
group = nobody
netstat 看到的端口是listen 状态,启动php-fpm 无报错。
其它两台机器 47 48 也没有问题,我就奇怪了,telnet 一下测试
#telnet 10.11.80.49 9000
Tring 10.11.80.49 ...
Connected to 10.11.80.49
Esape character is '^]'.
我分别在47 和48 上测试, 发现不一样的就是 49 是被直接close 掉的。
后面再看配置文件,48 后面多了一个空格。去掉重启,测试,我勒个去。
python 之图片无法显示 IOError: decoder zip not available
最近用 mezzanine 搭建了一个 blog, 后台管理 media-library 部分总是报错:
About the PIL Error — IOError: decoder zip not available
重新安装,看到安装后的结果是支持的:
*** ZLIB (PNG/ZIP) support available
重装了好几遍,还是没有用,使用模块 Pillow 的 2.3.0 版本安装后,页面可以成功打开了。
处理完那个问题,又有个新问题,就是中文的地址无法解析:
http://ip/%E4%BA%B2%E6%83%85/
'ascii' codec can't encode characters in position 35-36: ordinal not in range(128)
export LC_ALL='en_US.UTF-8'
export LC_ALL='en_US.UTF-8'
mezzanine 的备份和迁移还需要关注一下。 这个虚拟主机还有半年左右就到期了。
About the PIL Error — IOError: decoder zip not available
*** ZLIB (PNG/ZIP) support available
'ascii' codec can't encode characters in position 35-36: ordinal not in range(128)
export LANG='en_US.UTF-8'
export LC_ALL='en_US.UTF-8'
python 之学习检查 /etc/hosts 文件有效性
单线程版本:
#!/usr/bin/python import os import commands f=open("/etc/hosts","r") for line in f.readlines(): ip=str(line.split()[0:1][0]) if ip == '#' or ip == ' ': continue status, output = commands.getstatusoutput('ping -c 3 -w 5' +" " + ip) if status == 0: continue else: print "Warnning:" + ip + " is timed out!!!" f.close
多线程版本:
#!/usr/bin/python import os,re,sys from threading import Thread class testit(Thread): def __init__ (self,ip): Thread.__init__(self) self.ip = ip self.status = -1 def run(self): pingaling = os.popen("ping -w5 -c2 "+self.ip,"r") while 1: line = pingaling.readline() if not line: break igot = re.findall(testit.lifeline,line) if igot: self.status = int(igot[0]) testit.lifeline = re.compile(r"(\d) received") pinglist = [] f=open("/etc/hosts","r") for line in f.readlines(): ip = str(line.split()[0:1][0]) if ip == '#' or ip == '': continue current = testit(ip) pinglist.append(current) current.start() for pingle in pinglist: pingle.join() if pingle.status == 0: print pingle.ip + "is timed out!!"
lvs 超时问题
客户端 http fsopen 调用偶发遭遇timed out,dmesg 看到入口一台机器报:
nf_conntrack: table full, dropping packet.
nf_conntrack: table full, dropping packet.
nf_conntrack: table full, dropping packet.
nf_conntrack: table full, dropping packet.
nf_conntrack: table full, dropping packet.
nf_conntrack: table full, dropping packet.
nf_conntrack: table full, dropping packet.
nf_conntrack: table full, dropping packet.
nf_conntrack: table full, dropping packet.
nf_conntrack: table full, dropping packet.
由于 lvs 架构原因,有做 iptable 策略,增大max 的值,减少timeout 的时间:
net.nf_conntrack_max = 655360
net.netfilter.nf_conntrack_tcp_timeout_established = 1200
其它版本有可能:
net.ipv4.netfilter.ip_conntrack_max = 655350
net.ipv4.netfilter.ip_conntrack_tcp_timeout_established = 1200
too many open files 问题
系统允许用户打开文件最大数,之前修改基本上都是 limitd.conf 文件值。昨天在遭遇mysql 数据库分表连接时候,碰到一个悲剧问题。
当设置的值超过大约 1024000 时候,系统就无法 ssh 进入。这个准确的来讲,需要修改两个地方:
- /proc/sys/fs/file-max 的值,这个是内核参数,直接 echo 方式修改,写入到 /etc/sysctl.conf 文件:
echo 2048 > /proc/sys/fs/file-max
2. 修改 /etc/securety/limitd.conf 文件:
* - nofile 2040
limitd.conf 文件值不能超过 file-max 的值,测试过,如果是那样的话,在你没退出 ssh 之前最好测试一下,否则
出现 ssh 无法登录悲剧。
nscd dns 缓存引起的修改hosts 不及时生效
以下一个需要修改的 ip 对于hosts,发现不生效
[root@app]# cat /etc/hosts |grep app_db.56.com
10.11.81.13 app_db.56.com
[root@app]# ping app_db.56.com
PING uevent_db.56.com (120.31.133.142) 56(84) bytes of data.
120.31.133.142 是旧的,相应的 hosts 文件对应 ip 已修改,
10.11.81.13 app_db.56.com app_db
但ping 的时候内核仍然使用旧的ip
[root@app]# ping app_db PING app_db.56.com (10.11.81.13) 56(84) bytes of data. 64 bytes from SHNHDX81-13.opi.com (10.11.81.13): icmp_seq=1 ttl=60 time=41.3 ms 64 bytes from SHNHDX81-13.opi.com (10.11.81.13): icmp_seq=2 ttl=60 time=31.2 ms [root@app]# ping app_db.56.com PING app_db.56.com (10.11.81.13) 56(84) bytes of data. 64 bytes from SHNHDX81-13.opi.com (10.11.81.13): icmp_seq=1 ttl=60 time=31.9 ms 64 bytes from SHNHDX81-13.opi.com (10.11.81.13): icmp_seq=2 ttl=60 time=31.2 ms
注意到ping 的 那一行和 ttl 返回的行不一样。
检查host.conf 文件
[root@ZHONGSH26-131-DX-DB etc]# vim /etc/host.conf multi on
使用的是 multi on ,将其修改为
order hosts,bind
还是没神马效果,指向的还是旧的 hostname :
[root@app]# ping app2.56.com PING app2.56.com (10.11.81.123) 56(84) bytes of data. ^C --- app2.56.com ping statistics --- 24 packets transmitted, 0 received, 100% packet loss, time 23447ms [root@app]# ping 2.56.com PING app2.56.com (10.11.81.13) 56(84) bytes of data. 64 bytes from app2.56.com (10.11.81.13): icmp_seq=1 ttl=60 time=31.3 ms 64 bytes from app2.56.com (10.11.81.13): icmp_seq=2 ttl=60 time=31.2 ms ^C --- app2.56.com ping statistics --- 2 packets transmitted, 2 received, 0% packet loss, time 1736ms rtt min/avg/max/mdev = 31.250/31.292/31.335/0.181 ms [root@ZHONGSH26-131-DX-DB etc]# cat /etc/hosts |grep app2 10.11.81.14 app2.56.com 2.56.com
怀疑是系统内核的问题,但是我任意加一个新的 ip 和对应的 hosts,是没有问题。就是将其修改过后就是不生效。
混了这几年,还是有盲区啊,这情况还是头次遇到,得想办法查出来。通过strace 来跟踪一下到底是调用了哪些文件。
[root@app]# strace -f -F -o /root/ping.txt /bin/ping app_db.56.com
预计发了两次数据包之后,我 Ctrl C 中断。看了一下那个 ping.txt 文件,果然有发现:
21292 socket(PF_FILE, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0) = 4 21292 connect(4, {sa_family=AF_FILE, path="/var/run/nscd/socket"}, 110) = 0 21292 sendto(4, "\2\0\0\0\r\0\0\0\6\0\0\0hosts\0", 18, MSG_NOSIGNAL, NULL, 0) = 18
为什么要用这个socket 呢? google 之,发现是一个dns 本地缓存服务。继续跟进,ps 发现是起来的:
[root@app]# ps -ef |grep nscd nscd 3027 1 0 17:29 ? 00:00:00 /usr/sbin/nscd
配置文件就是 /etc/nscd.conf ,我看了一下,主要有这么一堆:
enable-cache passwd yes positive-time-to-live passwd 600 negative-time-to-live passwd 20 suggested-size passwd 211 check-files passwd yes persistent passwd yes shared passwd yes max-db-size passwd 33554432 auto-propagate passwd yes enable-cache group yes positive-time-to-live group 3600 negative-time-to-live group 60 suggested-size group 211 check-files group yes persistent group yes shared group yes max-db-size group 33554432 auto-propagate group yes enable-cache hosts yes positive-time-to-live hosts 3600 negative-time-to-live hosts 20 suggested-size hosts 211 check-files hosts yes persistent hosts yes shared hosts yes max-db-size hosts 33554432 enable-cache services yes positive-time-to-live services 28800 negative-time-to-live services 20 suggested-size services 211 check-files services yes persistent services yes shared services yes max-db-size services 33554432
我看是貌似全部加上了,这个服务对于我们全部基于hosts 的应用来讲,相当的无用,反而会带来一些
麻烦。顺便也打算研究一下这个服务。我先是把注释的部分拿掉,看hosts 修改是否能够及时生效:
# ping app_db.56.com PING app_db.56.com (10.11.81.14) 56(84) bytes of data. 64 bytes from app_db.56.com (10.11.81.14): icmp_seq=1 ttl=60 time=31.3 ms
再改一下,生效:
# ping app_db.56.com PING app_db.56.com (10.11.81.13) 56(84) bytes of data. 64 bytes from app_db.56.com (10.11.81.13): icmp_seq=1 ttl=60 time=31.3 ms 64 bytes from app_db.56.com (10.11.81.13): icmp_seq=2 ttl=60 time=31.4 ms
附一个网上的说明:
dns缓存在服务器上的作用
在需要通过域名与外界进行数据交互的时候,dns缓存就派上用场了,它可以减少域名解析的时间,提高效率.例如以下情况:
使用爬虫采集网络上的页面数据,
使用auth2.0协议从其他平台(如微博或QQ)获取用户数据,
使用第三方支付接口,
使用短信通道下发短信等.
使用爬虫采集网络上的页面数据,
使用auth2.0协议从其他平台(如微博或QQ)获取用户数据,
使用第三方支付接口,
使用短信通道下发短信等.
dns缓存到底能提升多少性能呢?
首先要看网络和dns服务器的能力,dns解析越慢,dns缓存的优势就越大.比如我们在北京用的dns服务器202.106.0.20和google的dns服务器8.8.8.8速度会差不少.
如果dns服务器比较稳定,那它对效率的影响就是一个常数.这个常数有多大呢?
我简单试了一下.在局域网内进行压力测试,压一个nginx下的静态页面,使用202.106.0.20这个dns服务器,不用dns缓存.平均一分钟可以访问27万次.压一个简单的php页面,平均一分钟可以访问22万次.加上nscd服务后,静态页面平均一分钟可以访问120万次,要快4倍多.php页面平均一分钟可以访问50万次,快一倍多.
如果是做搜索引擎或是一些代理服务类的项目,比如短信通道,数据推送服务,这个性能提升还是比较可观的.但在一般的项目中,一台服务器每分钟发22万次请求的情况是很少见的,所以这个性能提升也微呼其微.
但在追求极限的道路上,每一小步都至关重要噢~
如果dns服务器比较稳定,那它对效率的影响就是一个常数.这个常数有多大呢?
我简单试了一下.在局域网内进行压力测试,压一个nginx下的静态页面,使用202.106.0.20这个dns服务器,不用dns缓存.平均一分钟可以访问27万次.压一个简单的php页面,平均一分钟可以访问22万次.加上nscd服务后,静态页面平均一分钟可以访问120万次,要快4倍多.php页面平均一分钟可以访问50万次,快一倍多.
如果是做搜索引擎或是一些代理服务类的项目,比如短信通道,数据推送服务,这个性能提升还是比较可观的.但在一般的项目中,一台服务器每分钟发22万次请求的情况是很少见的,所以这个性能提升也微呼其微.
但在追求极限的道路上,每一小步都至关重要噢~
订阅:
博文 (Atom)
订阅:
博文 (Atom)