Friday, September 29, 2006

MySQL 不能启动一例

现象为,启动、长时间等待,最后失败。
查看错误日志,没有任何有效信息。
060929 12:14:36 mysqld started
060929 12:14:36 mysqld ended

查看系统日志 /var/log/messages,能看到形如
Sep 29 11:51:46 localhost kernel: audit(1159498306.605:23): avc: denied { append } for pid=17579 comm="mysqld" name="mysql.err" dev=hda3 ino=4212878 scontext=root:system_r:mysqld_t tcontext=root:objec
t_r:var_lib_t tclass=file
Sep 29 11:51:46 localhost kernel: audit(1159498306.605:24): avc: denied { append } for pid=17579 comm="mysqld" name="mysql.err" dev=hda3 ino=4212878 scontext=root:system_r:mysqld_t tcontext=root:objec
t_r:var_lib_t tclass=file
Sep 29 11:51:46 localhost kernel: audit(1159498306.674:25): avc: denied { create } for pid=17579 comm="mysqld" name="mysql.sock" scontext=root:system_r:mysqld_t tcontext=root:object_r:var_lib_t tclass=sock
_file

排查后,发现为 selinux 所不容,关闭之,解决。

Tuesday, September 26, 2006

MySQL 的选项和变量

不得不说,MySQL 对于开发者是越来越友好。
关于可用的选项和变量,在参考手册中已经有了专门的章节,很好用。

Sunday, September 17, 2006

MySQL Replication 浅尝

虽然 RAID 1 可以避免硬盘的物理损坏带来的损失,但是如果整机发生故障,单节点的数据库(相信一般的中小型站点都是)依然会造成服务陷入较长时间不可用的状态。所以需要导入其他高可用方案,于是我认识了 MySQL Replication。

MySQL Replication 从 MySQL 3.23.15 开始被引入,包含于标准的 MySQL 发行版,可以实现完全复制另一个数据库,而且配置方法很简单,主要有以下几点。

一、主(被复制方)从(复制方)数据库使用相同版本,或者从数据库可以高于主数据库。反之则有较大风险,因为复制(replication)是基于操作(statement)的,而不是基于数据行(row)的,所以高版本的某些操作可能无法被低版本正确执行。MySQL 5.1 开始会引入基于数据行的复制(replication),是个很值得期待的新特性。

二、主从双方的初始数据状态要严格一致,即从库的初始数据要和主库二进制日志(binary log)指定的复制起始点所在时刻的数据要一致。如果备份方案是计划的一部分,那么这不算是个问题,一切都从零开始。但若是要对一个正在运行的数据库实施复制(replication),就不是件那么令人愉快的事情了,烫手山芋就是如何取得一个某时刻下完整的数据拷贝,MySQL 并没有提供一个像样的热备解决方案。如果是个纯 innodb 数据库的话,还能从 InnoDB 的提供商 Innobase Oy 那里获取一个热备工具,当然,价格不菲。除此以外,停机备份几乎是不可避免的,代价取决于数据量。

三、主库需要开启二进制日志,以及创建一个特权用户。从库则相应地在配置文件中指定使用该用户,另外可按需设置复制(replication)数据库(schema)的黑名单或白名单,一般来说,可以把 mysql 和 test 加入黑名单,即在复制时忽略这两个数据库的一切操作。

准备就绪后,只需要启动从数据库,实施备份就开始了。从库上有两个工作线程,其一负责从主数据库读取日志,写入本地中继日志(relay log),其一负责根据中继日志进行数据操作,两者交错工作。

主从数据库中的表类型(Engine)可以是不同的,这一特性可以带来多少效益完全取决于你的创意。简单点的例如,主库中表 A 使用 InnoDB 来满足较大量的并发读写操作,而从库的表 A 则使用 MyISAM 来创建全文索引实现全文检索,或者从库全部使用 ARCHIVE 来节省硬盘空间等等。

MySQL Replication 是单向的,但是从数据库同时可以扮演主数据库的角色,所以双向备份是可以有条件地实现的。主要障碍是数据同步存在延时(虽然正常情况下是毫秒级别的)所以无法保证数据库群任意时刻都拥有相同的数据,一定程度上可以通过全局性的读写规划和设置复制(replication)黑白名单来减轻这个问题,但总的来说是个比较冒险的做法。

在实际应用中我遇到过这样的问题,对于受 DATABASE CHARSET 影响的 LOAD DATA 操作(statement),从数据库并不能正确地复制(replication)这一操作(statement),效果等同于从数据库的 DATABASE CHARSET = latin1,是否是 bug 有待于 MySQL 开发者的验证。

更新:
06-10-23 已被确认为 bug,并被判与 15126 重复,后者提交日为 05-11-22。
07-05-01 MySQL Community Server 5.0.41 发布,bug fixed。

其他的,更多的,可以参阅 MySQL 参考手册第六章

Tuesday, September 12, 2006

noticpan.org update 060912

毛坯房在 perlchina 广告了一下,应者寥寥。也是,过分粗糙了,各方各面都是。同时,如期开始了装修工程。到现在为止,第一期简装已经完毕,还是很丑?多多包涵,多多包涵。期间自己在使用中发现了几个 BUG,都一一予以修正。还有部分功能缺失,如注销、忘记/更改密码等,也会于近日慢慢补上。
出乎意料的是,我自己订阅了 10+ 个模块,竟然两个多星期来没有受到一个更新通知,搞笑了,受打击了。但是不能气馁,要相信这个服务肯定是有用的,嗯嗯。
天色不早了,该休息了,各位晚安。

Wednesday, September 06, 2006

noticpan.org online

从想法到实施,花了三个周末,昨晚 noticpan.org 上线了。
最基础的邮件提醒功能已经可用,其他一切都处于史前文明水平,留待日后慢慢开化。
不容易啊,在虚拟主机上搭建 Catalyst 的应用程序。Catalyst 本身已经做得很好了,还有详细的教程说明如何在虚拟主机搭建站点。
革命尚未成功,同志还需努力!

Wednesday, August 30, 2006

DreamHost promo codes

正在筹划个站点,于是满地图找空间,最后决定买 Dreamhost 的虚拟主机。
最初是在 Catalyst 的 wiki 上看到它的广告的,那么想当然地以为它是支持 Catalyst 的,买了之后发现不是这样的,这是后话。
L1: Crazy Domain Insane (20GB disk, 1TB bw, $9.95/month)

咋一看,价格和内容都还不错;再一瞅,跟咱电信一样,包年免初装费,按月付费的话要额外追加一项
$49.95 set up fee

那一年就一年吧,$119.4,也还好吧。那么,最后掏钱之前 Google 一下,这 Dreamhost 到底怎么样,好不好,恕我孤陋寡闻,一搜就搜出了 promo codes 这个东西,大把大把的。使用促销代码注册,最多可以获得$97的优惠,然后$22.4就出手了。
回到上面的话题,原来 Catalyst 需要自己安装的,好就好在 Dreamhost 提供了 ssh/telnet 权限,可以在自己的目录下自行安装。当前正在摸索中……
既然 promo codes 利人又利己,那么我也来弄个玩玩
Code: NOTICPAN
PlanCostThis Code's Discount
L1 Monthly$59.90$50.00
L1 Yearly$119.40$97.00
L1 Two years$190.80$97.00
L2 Monthly$69.90$60.00
L2 Yearly$239.40$97.00
L2 Two years$382.80$97.00
L3 Monthly$89.90$80.00
L3 Yearly$479.40$97.00
L3 Two years$766.80$97.00
L4 Monthly$129.90$97.00
L4 Yearly$959.40$97.00
L4 Two years$1534.80$97.00
While L3 is at L2's price, L2's discount will be used for L3.

Thursday, August 24, 2006

Pound前端下Catalyst的https重定向问题

如果你使用Pound作为前端,那么不可避免地,必须使用Pound作为你的https wrapper,因为Pound和后端只用http通讯。然后说那个Catalyst的重定向,常规情况下,你可以使用这样的代码来做重定向
$c->res->redirect('/foo');

对于大多数现代浏览器,这个响应返回的头部是可以被正常解析的,所以如果你是从一个https入口进的话,这个重定向会正确地被浏览器解析成
https://example.com/foo

但是,根据RFC某某某号的描述,重定向的目标路径应该是全路径,这样的话就有问题了,首先,你必须借助uri_for这个函数来产生你的全路径
$c->res->redirect( $c->uri_for('/foo') )

然后,问题就来了,由于Catalyst只接受到了http的请求,它并不知道外面的世界是上海还是广州,于是,得到了
http://example.com/foo

诚然,也许你要的只是某个区域永远安全,那么简单的解决方法就是这样
my $uri = 'https://' . $c->req->header('host') . '/foo';
$c->res->redirect( $uri );

显然,我们要得更多,又要马儿好,又要马儿不吃草。所以呢,在很多站点的入口都能看到一个醒目的“安全登录”的标签。让你自己选,要安全就给你安全,不要?呵呵,我乐得省下这些开销。这样的话,情况就要复杂一些了,首先,为了让Catalyst知道你的来路,Pound必须履行告知的义务,比如这样

ListenHTTPS
AddHeader "secure: 1"
End

接着,就可以根据这个头部来分情况选择重定向的协议(schema)了,我比较倾向于自己写个插件
package Catalyst::Plugin::Secure;

use strict;
use warnings;

sub uri_for {
my ( $c, $path, @args ) = @_;

my $uri = $c->NEXT::uri_for($path, @args);
if ( $c->req->header('secure') ) {
my $str = $uri->as_string;
$str =~ s/^http/https/;
$uri = new URI( $str )->canonical;
}

return $uri;
}

1;

好,圆满了,多谢观赏!

Wednesday, August 16, 2006

正则表达式的写法和效率一例

#!/usr/bin/perl
use strict;
use warnings;
use Benchmark qw(:all);

my $b = cmpthese( -1,
{
pa => qq("It's a fine day today." =~ /a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z|A|B|C|D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|T|U|V|W|X|Y|Z/g),
pb => qq("It's a fine day today." =~ /[abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ]/g ),
pc => qq("It's a fine day today." =~ /[a-zA-Z]/g ),
}
);

上面的这个例子我一直跑不出个相对稳定的结果,只能随便拿个结果来说明一下:
        Rate   pa   pb   pc
pa 848885/s -- -61% -65%
pb 2204237/s 160% -- -9%
pc 2427045/s 186% 10% --

可以看到,从“或(|)”模式到“类([])”模式,正则匹配的效率可以得到大幅度的提高,如果在“类”中能利用“范围(-)”符的话,还可以有小幅度提升。粗糙地结论就是,正则愈短,效率愈高。

因而在处理特定字符集的情况下,可以将其浓缩成一个精简的字符类描述的话,在执行效率上应该是很有帮助的。

Monday, August 14, 2006

MySQL可靠吗?

由于工作的原因,一直用着MySQL,一来是免费,二来简单易用。
但是随着应用的扩展,对于功能和稳定性的要求也越来越高。最近遇到了一件事情,让我觉得很是不爽,MySQL究竟可不可靠?

事情是这样的,安装完MySQL之后,在简单配置了my.cnf和启动测试之后,就清掉了binlog打算投入使用了。由于经验不足,没有删除ib_logfileX,又因为在第一次启动后修改了配置文件,已创建的ib_logfileX的文件大小和配置文件中的innodb_log_file_size不一致,导致了接下来的问题。
启动MySQL,OK。导入预先准备好的SQL脚本,OK。然后,发现了原来显式声明了Engine=InnoDB的表全部创建成了MyISAM模式。
SHOW ENGINES;后看到InnoDB的状态为DISABLE,很是莫名……最后在hostname.err里面看到,因为innodb_log_file_size的问题,导致了:
1)InnoDB被自动禁用了
2)创建InnoDB模式的表的时候,自动转成了MyISAM

我觉得不满的是,InnoDB被禁用只是在日志里这么一笔带过,终端上没有任何警告信息。据说*nix程序的普识原则是没有输出就是没有错误,难道MySQL认为这只是个小问题,并不会影响用户使用?!之后的自动转换模式就是个衍生问题了,虽然有WARNING,不过在批处理模式下显然是没有任何帮助的了。

问题虽然很好解决,删除innodb-log,重启MySQL,ALTER TABLE,就可以了。但是如果问题发现的晚,或者系统不能轻易下线,那损失就不好估算了。

Saturday, June 24, 2006

Config::General

前面在Catalyst的ML中就配置文件采用哪个模块处理讨论得不亦乐乎,感觉很多人对YMAL都颇有微辞,比如不能使用Tab之类的,最后达成的比较一致的意见是使用Config::General。第一次听说这模块。
正好给朋友写了个脚本,尝试了一下。格式定义和Apache的配置文件格式很相似,就是同一层次的Hash引用和Array引用在配置文件中看起来是不同层的,稍稍有些不爽。例:
<hash>
 foo = bar
</hash>
array = 1
array = 2

好处就是通俗易懂,适用性比较广,毕竟更多人对Apache的配置文件格式比较熟悉。不过如果只是我个人使用,还是会选择YAML的,简洁明了,我喜欢。
---
hash:
 foo: bar
array:
 - 1
 - 2