软件:FlashGet
版本:1.81 -> 1.73
新版本默认行为太暴力了,线程数多到泛滥,而且不容易设置。我原来的设置为 3 线程,最小分段尺寸 1MB。出于使用习惯,选择了降级,没有转投他处。
不在沉默中爆发(FlashGet),就在沉默中死亡(NetAnts),这年头,搞什么啊?
为什么说“又”?看这里。
Tuesday, February 13, 2007
Sunday, February 04, 2007
在 DreamHost 虚拟主机上部署 Catalyst 应用
在虚拟主机上部署 Catalyst 应用的前提是用户可以自己安装 CPAN 模块,DreamHost 提供了 shell 环境,所以就完全没问题了。
如何在非 root 环境下安装 CPAN 模块,请参考 Catalyst Wiki 中的相关文章。
好,在安装完 Catalyst 之后呢,那么就万事具备,只欠东风了。
虚拟主机,Catalyst 自带的 httpd 肯定是不能用的;没有 apache 的控制权限,mod_perl 也上不了;剩下还有 cgi 和 fastcgi 方式,还用想吗?当然用 fastcgi 咯~
下面就以 fastcgi 方式为例,分享一下我的一些经验。
一、部署环境
二、apache 环境
软链接的意义很好理解,不罗嗦了,然后来看一下 .htaccess 文件。
很容易理解吧,也不罗嗦了。
三、定制 myapp_fastcgi.pl
我原以为,修改过了 .bashrc 之后,应该不需要再用 use lib 了,但是数次实践下来,不在 myapp_fastcgi.pl 里声明用户的 lib 还真不行。要是哪位知道这里的道道,记得告诉我啊。
至于为什么要 IGNORE TERM,故事是这样的,很久很久以前,世界和平,大家都过着男耕女织的生活,不用在意什么,MyApp 也能跑得欢快。
突然有一天,电闪雷鸣,大雨瓢泼,MyApp 就再也跑不起来了,访问站点能看到的只有 Internal Server (500) 错误,翻开史册,书上如是说:
在无数次 ps 之后,总算看到 myapp_fastcgi.pl 的身影一闪而过。是他杀,我惊醒!真相只有一个,下面公布凶手的自白书。
说笑啦,上面这段是 DreamHost 客服给我的回复。IGNORE TERM 之后,世界又太平了。
四、应用启动方式
启动应用的方法就是访问站点。如果需要重启,杀掉所有 myapp_fastcgi.pl 即可,如果 IGNORE TERM 了的话,需要 kill -9。
如何在非 root 环境下安装 CPAN 模块,请参考 Catalyst Wiki 中的相关文章。
好,在安装完 Catalyst 之后呢,那么就万事具备,只欠东风了。
虚拟主机,Catalyst 自带的 httpd 肯定是不能用的;没有 apache 的控制权限,mod_perl 也上不了;剩下还有 cgi 和 fastcgi 方式,还用想吗?当然用 fastcgi 咯~
下面就以 fastcgi 方式为例,分享一下我的一些经验。
一、部署环境
[hostname ~]$ ls -1
MyApp/ # 项目名
example.com/ # 域名
二、apache 环境
[hostname ~]$ ls -a1 example.com
.htaccess
script -> /home/islue/MyApp/script/
static -> /home/islue/MyApp/root/static/
软链接的意义很好理解,不罗嗦了,然后来看一下 .htaccess 文件。
[hostname ~]$ cat example.com/.htaccess
AddHandler fastcgi-script .pl
RewriteEngine On
# 避免屏蔽 DreamHost 提供的 Site Statistics 功能
RewriteCond %{REQUEST_URI} ^/stats/(.*)$ [OR]
RewriteCond %{REQUEST_URI} ^/failed_auth.html$
RewriteRule ^.*$ - [L]
# fastcgi 工作模式
RewriteCond %{REQUEST_URI} !^/script/myapp_fastcgi.pl
RewriteRule ^(.*)$ script/myapp_fastcgi.pl/$1 [PT,L]
很容易理解吧,也不罗嗦了。
三、定制 myapp_fastcgi.pl
[hostname ~]$ cat MyApp/script/myapp_fastcgi.pl
...
BEGIN {
$ENV{CATALYST_ENGINE} ||= 'FastCGI';
unshift @INC, qw(
/home/islue/local/lib/perl/5.8
/home/islue/local/lib/perl/5.8.4
/home/islue/local/lib/perl5
/home/islue/local/lib/perl5/i386-linux-thread-multi
/home/islue/local/share/perl/5.8
/home/islue/local/share/perl/5.8.4
);
$SIG{'TERM'} = 'IGNORE';
}
...
我原以为,修改过了 .bashrc 之后,应该不需要再用 use lib 了,但是数次实践下来,不在 myapp_fastcgi.pl 里声明用户的 lib 还真不行。要是哪位知道这里的道道,记得告诉我啊。
至于为什么要 IGNORE TERM,故事是这样的,很久很久以前,世界和平,大家都过着男耕女织的生活,不用在意什么,MyApp 也能跑得欢快。
突然有一天,电闪雷鸣,大雨瓢泼,MyApp 就再也跑不起来了,访问站点能看到的只有 Internal Server (500) 错误,翻开史册,书上如是说:
[Mon Jan 29 06:13:13 2007] [error] [client 210.151.136.180] FastCGI: comm with (dynamic) server "/home/islue/example.com/script/myapp_fastcgi.pl" aborted: (first read) idle timeout (60 sec)
[Mon Jan 29 06:13:13 2007] [error] [client 210.151.136.180] FastCGI: incomplete headers (0 bytes) received from server "/home/islue/example.com/script/myapp_fastcgi.pl"
在无数次 ps 之后,总算看到 myapp_fastcgi.pl 的身影一闪而过。是他杀,我惊醒!真相只有一个,下面公布凶手的自白书。
Dreamhost regularly kills off sleeping processes with a proc watch script. This will kill your dispatch.fcgi processes, leading to Error 500s from time to time. You'll need to make dispatch.fcgi ignore all TERM requests by changing how it responds to them.
说笑啦,上面这段是 DreamHost 客服给我的回复。IGNORE TERM 之后,世界又太平了。
四、应用启动方式
启动应用的方法就是访问站点。如果需要重启,杀掉所有 myapp_fastcgi.pl 即可,如果 IGNORE TERM 了的话,需要 kill -9。
Saturday, February 03, 2007
Saturday, January 20, 2007
ssh-agent 简介
ssh-agent 是一个保管私钥的程序。然后的故事呢是这样的,ssh-agent 在一个 X-session 或者一个 login session 的一开始启动,所有其他窗口以及程序都会作为 ssh-agent 的客户端启动。
以上译自 ssh-agent 的在线手册(man)。
按我的理解来说,ssh-agent 就是一个管理私钥的代理,受管理的私钥通过 ssh-add 来添加,所有 ssh-agent 的客户端都可以共享使用这些私钥。
用处一,不用重复输入密码。
用 ssh-add 添加私钥时,如果私钥有密码的话,照例会被要求输入一次密码,在这之后 ssh-agent 可直接使用该私钥,无需再次密码认证。
用处二,不用到处部署私钥。
假设我有私钥分别可以登录同一内网的主机 A 和主机 B,出于一些原因,不能直接登录 B。我可以通过在 A 上部署私钥或者设置 PortForwarding 来登录 B,也可以转发认证代理连接在 A 上面使用 ssh-agent 管理的私钥登录 B。
以 cygwin 环境为例,描述一下操作流程
通过 ssh-agent 启动 bash,或者说把 bash 挂到 ssh-agent 下面
添加私钥,如果跳过第一步直接添加私钥,也就是说当前的 shell 并没有挂在 ssh-agent 下面,则会收到这样的错误信息
接下来登录主机 A
-A 的作用就是启用转发认证代理连接
从主机 A 上顺利登录主机 B,完毕。
更多内容请参阅 ssh 和 ssh-agent 的在线手册。
以上译自 ssh-agent 的在线手册(man)。
按我的理解来说,ssh-agent 就是一个管理私钥的代理,受管理的私钥通过 ssh-add 来添加,所有 ssh-agent 的客户端都可以共享使用这些私钥。
用处一,不用重复输入密码。
用 ssh-add 添加私钥时,如果私钥有密码的话,照例会被要求输入一次密码,在这之后 ssh-agent 可直接使用该私钥,无需再次密码认证。
用处二,不用到处部署私钥。
假设我有私钥分别可以登录同一内网的主机 A 和主机 B,出于一些原因,不能直接登录 B。我可以通过在 A 上部署私钥或者设置 PortForwarding 来登录 B,也可以转发认证代理连接在 A 上面使用 ssh-agent 管理的私钥登录 B。
以 cygwin 环境为例,描述一下操作流程
islue@localhost $ ssh-agent bash --login -i
通过 ssh-agent 启动 bash,或者说把 bash 挂到 ssh-agent 下面
islue@localhost $ ssh-add
添加私钥,如果跳过第一步直接添加私钥,也就是说当前的 shell 并没有挂在 ssh-agent 下面,则会收到这样的错误信息
Could not open a connection to your authentication agent.
接下来登录主机 A
islue@localhost $ ssh -A HOST_A
-A 的作用就是启用转发认证代理连接
islue@HOST_A $ ssh HOST_B
islue@HOST_B $
从主机 A 上顺利登录主机 B,完毕。
更多内容请参阅 ssh 和 ssh-agent 的在线手册。
用好 MySQL 字符集
我们都知道,MySQL 支持 30 多种字符集,其中包括了我们常用的 gb2312、gbk 和 uft8 等字符集。
在很多简单应用场合下,字符集设置是可有可无的。把后台存储的视为裸数据(raw data),存入的数据可以被原封不动地取出,对于前端的处理及应用,通常是不会有问题的。
当然,不设置正确的字符集,在实际应用中也有诸多不便之处。假设情况是这样的:
那么大概会得到这样的结果:
如果你是个完全无视 GUI 管理工具的开发者,那么无视字符集设置就是了。
设置合适的字符集,我觉得主要是可以获得 GUI 管理工具强大支持。除此以外,其实用处并不是很多,以我的使用经验为例,只是用来做文本排序。
那么以 Perl 为例,说说我的经验,怎样使用合适的字符集,情况如下
设置字符集可以分为四个环节:
客户端,这里指浏览器。当前输出内容编码为 GB2312,所以应该在 HTML 头部加入如下语句:
通常,即使没有上述语句,多数浏览器也能“猜”出正确编码,这是题外话,不深入了。
前端,这里指数据处理程序。因为后端存储是 utf8,所以在这里需要把数据从 GB2312 转为 UTF8,就绪。
连接,这里指由程序创建的数据库连接。通常我们这样连接数据库:
为了加入字符集信息,需要在连接后执行下面的命令:
声明了输入输出使用的都是 utf8 字符集。要保证建立连接后,首先执行字符集声明。
这在某些自动重连的情况下可能会失效,我推荐用读取配置文件的方式声明连接字符集。
首先,在配置文件 /etc/my.cnf 中加入字符集设置
然后,连接语句相应地改为
或者
这样保证了创建连接前就能读取到字符集设置。
后端,这里指 MySQL 数据库。在建表或数据库时,声明字符集
以上就是各环节字符集的设置,一些描述乃属经验记忆,难免会有错漏,还望海涵。更多请参阅 MySQL 参考手册相关章节。
在很多简单应用场合下,字符集设置是可有可无的。把后台存储的视为裸数据(raw data),存入的数据可以被原封不动地取出,对于前端的处理及应用,通常是不会有问题的。
当然,不设置正确的字符集,在实际应用中也有诸多不便之处。假设情况是这样的:
前端应用:GB2312
后端存储:latin1
那么大概会得到这样的结果:
字符终端(GB2312环境):正确
phpMyAdmin:乱码
MySQL Query Browser:乱码
如果你是个完全无视 GUI 管理工具的开发者,那么无视字符集设置就是了。
设置合适的字符集,我觉得主要是可以获得 GUI 管理工具强大支持。除此以外,其实用处并不是很多,以我的使用经验为例,只是用来做文本排序。
那么以 Perl 为例,说说我的经验,怎样使用合适的字符集,情况如下
前端应用:GB2312
后端存储:utf8
设置字符集可以分为四个环节:
客户端 <-> 前端 <-> 连接 <-> 后端
客户端,这里指浏览器。当前输出内容编码为 GB2312,所以应该在 HTML 头部加入如下语句:
<meta http-equiv="Content-Type" content="text/html; charset=GB2312">
通常,即使没有上述语句,多数浏览器也能“猜”出正确编码,这是题外话,不深入了。
前端,这里指数据处理程序。因为后端存储是 utf8,所以在这里需要把数据从 GB2312 转为 UTF8,就绪。
use Encode;
Encode::from_to( $data, 'euc-cn', 'utf8' );
连接,这里指由程序创建的数据库连接。通常我们这样连接数据库:
use DBI;
my $dbh = DBI->connect('dbi:mysql:database=test;host=localhost', $user, $password);
为了加入字符集信息,需要在连接后执行下面的命令:
$dbh->do('SET NAMES utf8');声明了输入输出使用的都是 utf8 字符集。要保证建立连接后,首先执行字符集声明。
这在某些自动重连的情况下可能会失效,我推荐用读取配置文件的方式声明连接字符集。
首先,在配置文件 /etc/my.cnf 中加入字符集设置
[client]
default-character-set=utf8
然后,连接语句相应地改为
my $dbh = DBI->connect('dbi:mysql:database=test;host=localhost;mysql_read_default_file=/etc/my.cnf', $user, $password);或者
my $dbh = DBI->connect('dbi:mysql:database=test;host=localhost;mysql_read_default_file=/etc/my.cnf;mysql_read_default_group=client', $user, $password);这样保证了创建连接前就能读取到字符集设置。
后端,这里指 MySQL 数据库。在建表或数据库时,声明字符集
CREATE TABLE (
...
) CHARSET utf8;
以上就是各环节字符集的设置,一些描述乃属经验记忆,难免会有错漏,还望海涵。更多请参阅 MySQL 参考手册相关章节。
Monday, December 25, 2006
TortoiseSVN 共享文件夹下一样显示图标
虽然是 TortoiseSVN 既有功能,猜想很多人都不知道的。
正常情况下,如果你在一个网络共享文件夹下面 checkout 一个 subversion 控制的项目。这个项目的文件夹并不会像在本地文件夹中一样,以各式各样的图标来表示文件状态。你需要做的是稍许改一下配置:
选中 Network Drivers,就能看到文件状态图标了。
正常情况下,如果你在一个网络共享文件夹下面 checkout 一个 subversion 控制的项目。这个项目的文件夹并不会像在本地文件夹中一样,以各式各样的图标来表示文件状态。你需要做的是稍许改一下配置:
TortoiseSVN -> Settings -> Look and Feel -> Icon Overlays -> Network Drivers
选中 Network Drivers,就能看到文件状态图标了。
货比三家
时常在网上书店买书,本着货比三家的原则,往返于各书店的价格页面,甚是累人。
也听说过用来比较价格的搜索网站,乘兴而去,败兴而归!
罢罢罢!
自己动手,丰衣足食。
暂时只收录了当当和卓越,做了简单的消重再确认。
感想,卓越的页面要比当当规整一些,比较容易解析。
也听说过用来比较价格的搜索网站,乘兴而去,败兴而归!
http://www.tejiawang.com/
收录站点少(2),价格信息单一
http://www.uobuy.com/
收录站点多(4),但是没有 china-pub,价格信息单一、滞后
http://www.danawa.com.cn/
不知所云
http://www.souchang.com/
收录站点少(1)
罢罢罢!
自己动手,丰衣足食。
http://sym.noticpan.org/
暂时只收录了当当和卓越,做了简单的消重再确认。
感想,卓越的页面要比当当规整一些,比较容易解析。
Sunday, December 24, 2006
也谈 Google 和百度
“百度更懂中文”,大家都这么说,著名用例:马勒隔壁的。
就当挑刺吧,正好刚才碰到了,举个例子
从结果看,Google 给我的就是我要的;百度?不知道在干什么。
在中国,恐怕 Google 最痛的莫过于“不能用”。不谈 GFW,百度能做到,Google 为什么做不到?一样是企业,Google 确实逊人一筹。不过我没有这个烦恼,至少现在没有,所以我只用 Google。
就当挑刺吧,正好刚才碰到了,举个例子
测试站点:
www.google.cn
www.baidu.com
搜索用例:
site:www.joyo.com Perl语言入门
从结果看,Google 给我的就是我要的;百度?不知道在干什么。
在中国,恐怕 Google 最痛的莫过于“不能用”。不谈 GFW,百度能做到,Google 为什么做不到?一样是企业,Google 确实逊人一筹。不过我没有这个烦恼,至少现在没有,所以我只用 Google。
Sunday, December 10, 2006
小心时区陷阱(二)
测试用例
输出结果
另外,关于 $ENV{TZ},提醒一下。
假设机器的时区设置为 UTC+9,不考虑非法的时区设置,那么根据值的不同,分别会是这样的结果
Patch for Date::Simple 3.02
参考链接
rt#23875
#!/usr/bin/perl
use strict;
use warnings;
use Time::Piece qw//;
use Date::Simple qw//;
use POSIX qw//;
sub show_info {
my $msg = shift;
my $hour = (localtime)[2];
printf "tz=$ENV{TZ}, tzname=%s:%s, hour=%2d # $msg\n", POSIX::tzname, $hour;
}
$ENV{TZ} = 'JST-9';
print "Date::Simple version is $Date::Simple::VERSION\n";
show_info('start');
my $date = Date::Simple->new;
show_info('after new');
$date->strftime("%Y-%m-%d\n");
show_info('after strftime');
POSIX::tzset;
show_info('after tzset');
输出结果
tz=JST-9, tzname=JST:JST, hour= 8 # start
tz=JST-9, tzname=JST:JST, hour= 8 # after new
tz=JST-9, tzname=UTC:UTC, hour=23 # after strftime
tz=JST-9, tzname=JST:JST, hour= 8 # after tzset
另外,关于 $ENV{TZ},提醒一下。
假设机器的时区设置为 UTC+9,不考虑非法的时区设置,那么根据值的不同,分别会是这样的结果
1. not exists $ENV{TZ} UTC+9
2.1 if ( $ENV{TZ} ) {...} UTC+0
2.2 else {...} UTC+9Patch for Date::Simple 3.02
$ diff -r Date-Simple-3.02.orig Date-Simple-3.02
diff -r Date-Simple-3.02.orig/lib/Date/Simple.pm Date-Simple-3.02/lib/Date/Simple.pm
158a159
>
160,161c161,174
< local $ENV{TZ} = 'UTC+0';
< return POSIX::strftime ($format, _gmtime ($self));
---
> my $exists_env_tz = exists $ENV{TZ};
> my $tz = $ENV{TZ} if $exists_env_tz;
>
> $ENV{TZ} = 'UTC+0';
> my $result = POSIX::strftime ($format, _gmtime ($self));
>
> if ( $exists_env_tz ) {
> $ENV{TZ} = $tz;
> } else {
> delete $ENV{TZ};
> }
> POSIX::tzset();
>
> return $result;
参考链接
rt#23875
Tuesday, December 05, 2006
小心时区陷阱(一)
不知道大家有没有碰到过这样的问题,原本好好的当前时区时间突然变为 0 时区时间。
这个问题困扰了我很久,原因有二:
1、程序不是个单文件脚本
2、单元测试无法重现错误
后来在同事的帮助下,总算找到了问题所在
来看一下 Date::Simple 的一段源代码
POSIX::strftime() 调用 tzset() 时看到的环境变量 $ENV{TZ} 是 UTC+0。在这之后就有问题了,如果使用 localtime(),因为 localtime_r(3) 并不会调用 tzset(),所以即使环境变量 $ENV{TZ} 已经恢复原值,localtime() 查看内部变量的时候,还是之前的 UTC+0。
至于为什么 localtime_r(3) 不像 localtime(3) 一样调用 tzset(3) 根据环境变量重设时区,我理解下来的主要原因是因为,它是线程不安全的。可能会出现下面这种情况
另外,关于环境变量 $ENV{TZ}存在(exists),但其值为空的时候,也会得到 UTC+0 的结果。
相关链接:
perlbug #26136
这个问题困扰了我很久,原因有二:
1、程序不是个单文件脚本
2、单元测试无法重现错误
后来在同事的帮助下,总算找到了问题所在
localtime(3) calls tzset(3), but localtime_r(3) not.
threaded perl localtime() calls localtime_r(3) instead of localtime(3)
来看一下 Date::Simple 的一段源代码
sub format {
my ($self,$format)=@_;
$format= $fmts{refaddr($self)||''} || $fmts{ref($self)} || $Standard_Format
if @_==1;
return "$self" unless defined ($format);
require POSIX;
local $ENV{TZ} = 'UTC+0';
return POSIX::strftime ($format, _gmtime ($self));
}POSIX::strftime() 调用 tzset() 时看到的环境变量 $ENV{TZ} 是 UTC+0。在这之后就有问题了,如果使用 localtime(),因为 localtime_r(3) 并不会调用 tzset(),所以即使环境变量 $ENV{TZ} 已经恢复原值,localtime() 查看内部变量的时候,还是之前的 UTC+0。
至于为什么 localtime_r(3) 不像 localtime(3) 一样调用 tzset(3) 根据环境变量重设时区,我理解下来的主要原因是因为,它是线程不安全的。可能会出现下面这种情况
thread1
thread2
tzset()
tzset()
localtime()
localtime()
另外,关于环境变量 $ENV{TZ}存在(exists),但其值为空的时候,也会得到 UTC+0 的结果。
相关链接:
perlbug #26136
Subscribe to:
Posts (Atom)
