“Web Server”目录存档

Ubuntu Server 10.04 LTS的Linux上编译安装配置nginx0.8.52

2010年10月22日,星期五

Server 10.04 LTS的Linux上安装配置nginx0.8.52

操作系统是linode上的Linux:Ubuntu Server 10.04 LTS。
nginx的最新版本是:0.8.52

http://nginx.org/download/nginx-0.8.52.tar.gz

来源:http://nginx.org/en/download.html
nginx依赖的PCRE库,最新版本是:8.10:
ftp://ftp.csx.cam.ac.uk/pub/software/programming/pcre/pcre-8.10.tar.gz
来源:ftp://ftp.csx.cam.ac.uk/pub/software/programming/pcre/
OpenSSL的最新版本是:1.0.0a:

http://www.openssl.org/source/openssl-1.0.0a.tar.gz

来源:http://www.openssl.org/source/
zlib的最新版本是:1.2.5:

http://zlib.net/zlib-1.2.5.tar.gz

在/usr/local目录下创建app目录,所有应用都安装配置到这个目录下面:
root@618119.com:/usr/local# sudo mkdir app
root@618119.com:/usr/local# cd ./app
然后下载安装程序:
root@618119.com:/usr/local/app# wget http://nginx.org/download/nginx-0.8.52.tar.gz
root@618119.com:/usr/local/app# wget ftp://ftp.csx.cam.ac.uk/pub/software/programming/pcre/pcre-8.10.tar.gz
root@618119.com:/usr/local/app# wget http://www.openssl.org/source/openssl-1.0.0a.tar.gz
root@618119.com:/usr/local/app# wget http://zlib.net/zlib-1.2.5.tar.gz
再解压压缩包:
root@618119.com:/usr/local/app# tar -zxvf *
root@618119.com:/usr/local/app# tar -zxvf pcre*
root@618119.com:/usr/local/app# tar -zxvf *
root@618119.com:/usr/local/app# tar -zxvf zlib*
由于缺少gcc等编译器,需要先运行:
root@618119.com:/usr/local/app# apt-get install gcc libc6-dev build-essential
进入到nginx解压得到的目录:
root@618119.com:/usr/local/app# cd nginx-*
运行configure命令,将nginx的安装目录设置为/usr/local/app/nginx。
with-http_stub_status_module参数是启用stub_status监控。
root@618119.com:/usr/local/app/nginx-0.8.52#  ./configure –prefix=/usr/local/app/nginx –user=nginx –group=nginx –with-http_ssl_module –with-http_stub_status_module –with-pcre=/usr/local/app/pcre-8.10 –with-openssl=/usr/local/app/openssl-1.0.0a –with-zlib=/usr/local/app/zlib-1.2.5
然后再运行make进行编译:
root@618119.com:/usr/local/app/nginx-0.8.52# make
再运行:make install,
root@618119.com:/usr/local/app/nginx-0.8.52# make install

还需要添加nginx用户组(未添加用户组就启动的话:会提示[emerg]: getpwnam(“nginx”) failed):
root@618119.com:/usr/local/app/nginx# sudo adduser –system –no-create-home –disabled-login –disabled-password –group nginx
进入到nginx的sbin目录用-t参数检查配置文件是否ok:
root@618119.com:/usr/local/app/nginx# cd sbin/
root@618119.com:/usr/local/app/nginx/sbin# sudo ./nginx -t
the configuration file /usr/local/app/nginx/conf/nginx.conf syntax is ok
configuration file /usr/local/app/nginx/conf/nginx.conf test is successful

这样就在linode的VPS上将nginx0.8.52安装好了。
root@618119.com:/usr/local/app/nginx/sbin# ./nginx
[emerg]: bind() to 0.0.0.0:80 failed (13: Permission denied)
root@618119.com:/usr/local/app/nginx/sbin#sudo ./nginx
(不用root启动的话,会提示:[emerg]: bind() to 0.0.0.0:80 failed (13: Permission denied))
启动成功后访问http 80端口可以看到Welcome to nginx!

接下来制作nginx系统服务启动的脚本,参考 http://articles.slicehost.com/2007/10/17/ubuntu-lts-adding-an-nginx-init-script

#! /bin/sh

### BEGIN INIT INFO
# Provides: nginx
# Required-Start: $all
# Required-Stop: $all
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: starts the nginx web server
# Description: starts nginx using start-stop-daemon
### END INIT INFO

PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
DAEMON=/usr/local/app/nginx/sbin/nginx
NAME=nginx
DESC=nginx

test -x $DAEMON || exit 0

# Include nginx defaults if available
if [ -f /etc/default/nginx ] ; then
. /etc/default/nginx
fi

set -e

case “$1″ in
start)
echo -n “Starting $DESC: ”
start-stop-daemon –start –quiet –pidfile /usr/local/app/nginx/logs/$NAME.pid \
–exec $DAEMON — $DAEMON_OPTS
echo “$NAME.”
;;
stop)
echo -n “Stopping $DESC: ”
start-stop-daemon –stop –quiet –pidfile /usr/local/app/nginx/logs/$NAME.pid \
–exec $DAEMON
echo “$NAME.”
;;
restart|force-reload)
echo -n “Restarting $DESC: ”
start-stop-daemon –stop –quiet –pidfile \
/usr/local/app/nginx/logs/$NAME.pid –exec $DAEMON
sleep 1
start-stop-daemon –start –quiet –pidfile \
/usr/local/app/nginx/logs/$NAME.pid –exec $DAEMON — $DAEMON_OPTS
echo “$NAME.”
;;
reload)
echo -n “Reloading $DESC configuration: ”
start-stop-daemon –stop –signal HUP –quiet –pidfile /usr/local/app/nginx/logs/$NAME.pid \
–exec $DAEMON
echo “$NAME.”
;;
*)
N=/etc/init.d/$NAME
echo “Usage: $N {start|stop|restart|force-reload}” >&2
exit 1
;;
esac

exit 0

再运行命令: sudo /usr/sbin/update-rc.d -f nginx defaults,将nginx安装为默认服务。

这样在linode里对Ubuntu重启之后,nginx服务也自动启动了。

Tags: , , , ,

在linode.com购买vps部署Ubuntu Server 10.04 LTS 64bit

2010年10月20日,星期三

在购买linode的VPS之前,先做了一些准备工作:
首先参考 http://www.blogkid.net/linode 等关于linode的文章介绍,对linode的各方面特点进行了了解。
知道了可以部署Ubuntu等Linux版本,并且自己控制操作系统的root帐号。
购买linode的VPS付款方式主要支持美元信用卡,因此特意在招商银行申请了招商银行双币信用卡,是VISA卡支持美元支付。
招行的个人信用卡从申请到收到卡大概需要三个星期左右。
在申请信用卡期间:则主要浏览linode知识库里的文章,参考: http://library.linode.com/
并在本地的Ubuntu 10.04 操作系统上编译安装nginx和resin等服务器程序。
在拿到信用卡之后,对信用卡的网上支付知识又进行了了解,重点关注CVV码(在信用卡背面签名栏的最后的三位数字)。

万事具备之后,开始购买linode的VPS.
1.开始访问http://linode.com/ ,点任何一个方案下面的 Sign Up Now!(这里其实并没有选择套餐),进入 https://www.linode.com/signup/
2.在 https://www.linode.com/signup/ 需要填写内容的各项含义和作用如下:
.com Username:在linode.com登录的账户名,我填写的lizongbo
Linode.com Password:在linode.com登录的密码,大写字母A到Z,小写字母a到z,数字0到9,特殊符号~!#$%^&*()_+等,至少必须有这四种字符中的两种。因此有必要仔细想好密码再注册,否则注册完之后不记得密码的话只能靠邮箱找回密码了。
E-Mail Address:非常重要,找回用户名和重置登录密码就靠它了。因此邮箱的密码也一定要牢固。
How did you hear about us?:应该是linode.com用来统计用的,因此随便填个网址即可,不介意的也可以填:http://618119.com/
Company Name:是可选项,个人就不用填了。
Billing First Name:账单上的姓,我填Li。
Billing Last Name:账单上的名,我填Zongbo。
Billing Address:账单地址,我填了个英文的,例如:
Billing Address 2 :是可选项,不用填了。
Billing City:所在城市,我填的Shenzhen。
Billing State:所在省份,我填Guangdong。
Billing Zip/Postal Code:所在地区的邮编,我填的518000
Billing Country:所在国家,按字母c,多按几次,找到 CN-China,这个选项。
Credit Card Number:输入信用卡卡号。
Expiration Date:选择信用卡上的有效期,月份在前面,年在后面。
CVV:信用卡的CVV码,很重要,在不能完全信任的网站上千万别填这个。
Select your plan,这里才是真正选linode套餐的地方,我选择的是Linode 512 这个套餐计划,内存512M,月付$19.95,磁盘总存储空间16GB,每月网络流量200GB。
Payment Term:付费方式,我选的是Month to month,即每月支付,12 months (10% discount)是一次付一年12个月的可以享受9折优惠,24 months (15% discount)是一次付两年24个月的,可以享受八五折优惠。;现在人民币对美元升值,提前付款不划算了。
Referral Code:推荐码,可填可不填,可以填我的推荐码:1feb04bc629af5b07b3eb99f8ad304d37843a056。
(注册成功之后,可以在https://manager.linode.com/profile/index查看属于自己的推荐码,linode官方对referral code的描述如下:
Referrals reward you when you refer people to Linode. If someone signs up using your referral code, you’ll receive a credit of $20.00, so long as the person you referred remains an active customer for 90 days.
意思是如果有人在购买linode的vps填写了推荐码,并且使用linode的vps超过90天以上,那么推荐码的主人就可以得到$20的优惠。
我的推荐码是 1feb04bc629af5b07b3eb99f8ad304d37843a056,可直接点击链接: http://www.linode.com/?r=1feb04bc629af5b07b3eb99f8ad304d37843a056 进行注册。
http://www.blogkid.net/linode 的张磊的Referral Code为: 2cea6fcaa1db11c5d52af67b20529505208b49fc )
Promotion Code:优惠码,这项不用填。至少我搜索了很久,根本没见到像name.com那样真正的优惠码,网上各种以linode 优惠码进行seo和宣传的文章,几乎都是骗人的,实际就是上面提到的推荐码,
打着优惠码的旗号骗大家填他的推荐码。所以这项保持为空就可以了。(也许将来某天会有linode的优惠码, 但是一定要仔细识别真假,别被忽悠了,网上说的一个优惠码是storecrowd,号称使用完一个月后返还10美元,但没见有人明确确认是否得到了优惠,因此不能确定真假)

以上信息都填写好了之后,点Continue进入下一步。

linode在校验信息ok和支付成功之后,就可以用刚刚注册的账号和密码进行登录了。

这里的第一次扣费不是按一个月扣的,而是从当前日期到月底计算的天数,按天收费的。
比如我是17号购买的,实际扣费是$9.66,(计算公式估计是: (9.66 / (31 – 16)) * 31 = 19.964001)。

选的新的Beta版linode管理界面,入口是: https://manager.linode.com/
登录之后,开始选择VPS需要部署的IDC机房,http://www.linode.com/speedtest/ 提供了每个机房的测试下载文件,可以使用单线程下载工具下载进行测速。
最好多试几次,在测试的时候发现London, UK;Newark, NJ ;Atlanta, GA ;Dallas, TX ,Fremont, CA这五个机房都可能下载速度到250k,也可能只有不到10k。
在多次测试后,感觉Dallas, TX的速度相对稳定一些。于是选择了达拉斯机房。 Dallas, TX, USA 。
然后操作系统选择的Linux版本为: 10.04 LTS 64bit,(都是Server版)
swap区为512m.剩下的磁盘空间都分在一起了。
点Deploy进行部署。等一会部署完成后,再到Dashboard 面板里将部署的Ubuntu 10.04 LTS启动。
再切换Remote Access的tab,在这里可以看到 ssh命令的写法,可以看到服务器的公网ip.默认没分配内网ip,需要点一下添加,才会给分配一个内网的ip。
可以点Launch Lish Ajax Console先在web上体验一下远程ssh连接上去操作的感觉。

使用uname -a查看 当前操作系统的信息为:
li206-174 2.6.35.4-x86_64-linode16 #1 SMP Mon Sep 20 16:03:34 UTC 2010 x86_64 GNU/.

更新升级Ubuntu Linux的命令为先运行apt-get update,然后运行apt-get dist-upgrade
root@618119.com:/usr/local/app# apt-get update
root@618119.com:/usr/local/app# apt-get dist-upgrade

Tags: , , ,

调整resin的resin.conf优化access-log输出日志

2009年02月18日,星期三

目前服务器上resin.conf的日志配置一般是:
《stdout - path=”/stdout.” timestamp=”[%Y-%m-%d %H:%M:%S] ” rollover-size=”200mb” /》
《stderr -log path=”log/stderr.log” timestamp=”[%Y-%m-%d %H:%M:%S] ” rollover-size=”200mb” /》
《access -log path=”logs/access.log” rollover-period=”1D” rollover-size=”200mb”/》

在这种情况下,日志始终是先输出到logs/access.log这样的固定文件里,待文件大小满200M的时候,resin先锁住所有写日志操作,将文件的内容复制到文件名带时间戳的文件里,再清空当前日志文件的内容。
这种情况下,既多增加了磁盘io操作,也因为锁机制导致线程容易满,以至resin被webapp监控重启。
以前出现该问题的时候,只简单的通过关闭access-log绕了过去,而最近web网站的resin也出现了重启,
由于web是lvs负载均衡,因此不能通过关闭accesslog来解决问题。

经过查看resin的源代码分析,结合现在业务的实际情况,可以通过调整日志的配置为按时间周期切割来解决问题。
通过分析和实验,将resin的配置调整后大致为:

《stdout -log path-format=”log/stdout.log.%Y%m%d” timestamp=”[%Y-%m-%d %H:%M:%S] ” rollover-period=”1D” /》
《stderr -log path-format=”log/stderr.log.%Y%m%d” timestamp=”[%Y-%m-%d %H:%M:%S] ” rollover-period=”1D” /》
《access -log path-format=”logs/access.log.%Y%m%d_%H” rollover-period=”1h”/》
(默认format是combined格式)
上面的是stdout和stderr按天切割(如果代码里异常输出比较多的话,也可以配制成按小时打,例如有:ex.printStackTrace();),access.log按小时切割。

大致分析过程:

访问高峰期时,日志滚动时候,导致线程锁住了。
JMX监控查看线程堆栈可以得知,可以看出大量的线程都 在执行com.caucho.server.log.AccessLog.log的时候BLOCKED了。
[code]
==============================
"-tcp-connection-*:80-5973" Id=41812 in BLOCKED on lock=java.lang.Object@14dca59
owned by resin-tcp-connection-*:80-5545 Id=41588
at com.caucho.server.log.AccessLog.log(AccessLog.java:310)
at com.caucho.server.webapp.WebAppFilterChain.doFilter(WebAppFilterChain.java:206)
at com.caucho.server.dispatch.ServletInvocation.service(ServletInvocation.java:229)
at com.caucho.server.http.HttpRequest.handleRequest(HttpRequest.java:268)
at com.caucho.server.port.TcpConnection.run(TcpConnection.java:389)
at com.caucho.util.ThreadPool.runTasks(ThreadPool.java:507)
at com.caucho.util.ThreadPool.run(ThreadPool.java:433)
at java.lang.Thread.run(Thread.java:619)

[/code]

先下载resin的源代码: http://www.caucho.com/download/resin-3.0.19-src.tar.gz

接下来分析AccessLog的log方法。

可以看到:
if (_isSharedBuffer && ! _isAutoFlush) {
synchronized (_sharedBufferLock) {

而这两个选项的默认值是:_isSharedBuffer=true,_isAutoFlush=false;
(因为resin.conf没有配置对应的属性,例如: shared-buffer=”false” auto-flush=”false”)
而这两个属性在官方文档里并没有直接列出。
http://caucho.com/resin-3.0/config/log.xtp#rollover

(测试了不能设置 auto-flush=”true”,因为没缓冲,还没判断好滚动就直接打到文件了,rollover-size几乎等同失效)

com.caucho.vfs. AbstractRolloverLog.java中:
private static final long DEFAULT_ROLLOVER_CHECK_PERIOD = 600L * 1000L;

private long _rolloverCheckPeriod = DEFAULT_ROLLOVER_CHECK_PERIOD;
滚动日志检测周期默认是10分钟。
而该参数没法在resin.conf中动态配置。

在文件超过指定大小之后,日志滚动的方法为:com.caucho.vfs. AbstractRolloverLog 里的rolloverLog, 这个也是个同步方法:

而执行文件内容的操作是movePathToArchive方法:
而movePathToArchive的做法是:

关键代码是: path.writeToStream(out);和path.truncate()
前一个方法,是表示把当前文件的内容读出来,再写到out里。
后一个方法是,把当前文件内容清空。
而其对应的实现是:
com.caucho.vfs.Path和com.caucho.vfs.FilePath。

从整个代码分析可以得知,resin在按文件大小滚动日志的时候,是检测到当前文件超过200M,就先把缓冲全部写入当前日志文件access.log里,再将access.log的内容读出,再写到 access.log.20090206.1047 这样的文件里,写完之后,再通过truncate利用FileOutputStream的append为false将access.log内容清空。相当于先复制内容到新文件,然后再清空当前文件内容。

而这整个过程中,是同步的,因此在执行复制201M日志的时候,线程全部锁住,而这个时候大量的用户请求正在涌来,导致jmx线程过高且webapp监控告警,于是resin被监控重启。

解决办法:
使用path-format属性替代 path,
例如配置:
《access -log path-format=”logs/access.log.%Y%m%d_%H” rollover-period=”1h”/》
这样就是每小时打一个文件,切换日志输出时候,自动切换,不再产生movePathToArchive操作。
jvm.Log里也没了”Archiving access log to “这样的日志。
Stdout和stderr也是同样处理,有这两个日志的内不会太多,可以配置成按天滚动。
stdout-log元素和stderr-log也有path-format属性。

为什么resin不用File的renameTo通过重命名来切换日志呢,这是因为java的io里,只有所有的流都关闭之后,且操作系统中没有程序对文件持有引用时,文件重命名才能够成功,且renameTo是依赖操作系统的,而这种正在对文件进行读写操作的,执行renameTo无法做到一定成功的。Resin也是因为此,在按文件大小进行滚动的时候,才不得已使用复制文件加清空内容的做法。

Tags: ,