共计 13275 个字符,预计需要花费 34 分钟才能阅读完成。
上一篇简单的了解了一下 Redis 官方自带的 HA 方案 sentinel(见 http://www.linuxidc.com/Linux/2014-02/96079.htm),试用发现还是不错的,但是由于还没有合并进稳定分支中,所以在生产环境也不敢使用,还有一个就是需求还暂时不能完全满足,所以就尝试一下 redis+keepalived 方案,毕竟 keepalived 现在还是很稳定的,而且资料也充足。
实验环境
Ubuntu 12.04 10.20.112.26 默认的 master
10.20.112.27 默认的 slave
VIP 10.20.112.29
redis-server 2.6.16
keepalived 默认只能做到对网络故障和 keepalived 本身的监控,即当出现网络故障或者 keepalived 本身出现问题时,进行切换。但我们更关注的是机器上运行的业务,如果业务出问题了 VIP 没有变化,整体来说还是失败的。这时候就需要根据业务进程的运行状态决定是否需要进行主备切换。还好 keepalived 提供了这样一个自定义脚本监控功能,不过该参数设置在官方默认的文档中并没有出现。
其实文档中有两个我们常用的参数都没有提到:
1 vrrp_script && track_script
vrrp_script 代码块是用来定义监控脚本,脚本执行时间间隔以及脚本的执行结果导致优先级变更幅度的。
vrrp_script chk_redis {
script “/etc/keepalived/scripts/redis_check.sh” #指定执行脚本的路径
interval 1 #指定脚本的执行时间间隔
weight 10 #脚本结果导致的优先级变更:10 表示优先级 +10;-10 则表示优先级 -10
}
定义好 vrrp_script 代码块之后,就可以在 instance 中使用了
track_script {
chk_redis
}
注意:VRRP 脚本 (vrrp_script) 和 VRRP 实例 (vrrp_instance) 属于同一个级别
2 notify_stop
keepalived 停止运行前运行 notify_stop 指定的脚本。
配合官方文档提到的以下三个参数一起使用,功能更强大:
notify_master keepalived 切换到 master 时执行的脚本
notify_backup keepalived 切换到 backup 时执行的脚本
notify_fault keepalived 出现故障时执行的脚本
3 还有个问题需要注意
当 master down 了,backup 接管了,master 再次起来,不能再成为 master。否则 master 恢复了再接管的话,会造成业务来回切换,这时候就需要 nopreempt 参数了。
nopreempt:设置不抢占,这里只能设置在 state 为 backup 的节点上,而且这个节点的优先级必须别另外的高。
先来看看方案的整体思路:
通过 keepalived 的自定义脚本功能监控本机的 redis 服务状态,当监控脚本检测到 redis 服务出现异常时,则改变本机 keepalived 的优先级,同时这会导致 master/backup 角色的变化,而 keepalived 在角色变化时也会触发一些机制执行相关脚本,这就为我们改变 redis 的 master/slave 状态提供了机会,这样做的目的是为了是 redis 的 master/slave 直接的数据保持一致。
在 keepalived+redis 的使用过程中有四种情况:
1 一种是 keepalived 挂了,同时 redis 也挂了,这样的话直接 VIP 飘走之后,是不需要进行 redis 数据同步的,因为 redis 挂了,你也无法去 master 上同步,不过会损失已经写在 master 上却还没同步到 slave 上面的这部分数据。
2 另一种是 keepalived 挂了,redis 没挂,这时候 VIP 飘走后,redis 的 master/slave 还是老的对应关系,如果不变化的话会把数据写入 redis slave 中,从而不会同步到 master 上去,这就要借助监控脚本反转 redis 的 master/slave 关系。这时候就要预留一点时间进行数据同步,然后反转 master/slave。
3 还有一种是 keepalived 没挂,redis 挂了,这时候根据监控脚本会检测到 redis 挂了,并且降低 keepalived master 的优先级,同样会导致 VIP 飘走,情况和第二种一样,也是需要进行数据同步,然后反转当前 redis 的 master/slave 关系的。
4 随后一种是 keepalived 没挂,redis 也没挂,大吉大利啊,什么都不用操作。
本文的实验环境四种情况都适合,第一种是不需要同步数据的,脚本会默认去同步数据,但是其实是不会成功的。脚本主要是用来处理第二和第三种情况的。
Redis 的详细介绍:请点这里
Redis 的下载地址:请点这里
推荐阅读:
Redis 集群明细文档 http://www.linuxidc.com/Linux/2013-09/90118.htm
Ubuntu 12.10 下安装 Redis(图文详解)+ Jedis 连接 Redis http://www.linuxidc.com/Linux/2013-06/85816.htm
Redis 系列 - 安装部署维护篇 http://www.linuxidc.com/Linux/2012-12/75627.htm
CentOS 6.3 安装 Redis http://www.linuxidc.com/Linux/2012-12/75314.htm
Redis 配置文件 redis.conf 详解 http://www.linuxidc.com/Linux/2013-11/92524.htm
配置 10.20.112.26
1 安装 keepalived
apt-get install keepalived
2 安装 Redis
redis 是采用源码编译安装的,Ubuntu12.04 默认自带版本没有这么高,安装过程参照以前文档。
3 配置 keepalived
global_defs {
lvs_id LVS_redis
}
vrrp_script chk_redis {
script “/etc/keepalived/scripts/redis_check.sh”
weight -20
interval 2
}
vrrp_instance VI_1 {
state backup
interface eth0
virtual_router_id 51
nopreempt
priority 200
advert_int 5
track_script {
chk_redis
}
virtual_ipaddress {
10.20.112.29
}
notify_master /etc/keepalived/scripts/redis_master.sh
notify_backup /etc/keepalived/scripts/redis_backup.sh
notify_fault /etc/keepalived/scripts/redis_fault.sh
notify_stop /etc/keepalived/scripts/redis_stop.sh
}
4 配置 redis,/etc/redis/redis.com
最简单的配置就是把默认配置文件中的 bind 127.0.0.1 修改为 0.0.0.0 即可。
5 建立 redis 状态切换脚本
在 /etc/keepalived 目录下建立 log 和 scripts 目录。
在 script 下有五个脚本,一个是检测 redis 状态的 redis_check.sh 脚本,其余四个是 keepalived 状态变化时执行的脚本。keepalived 有 master/backup/stop/fault 四种状态,因为我们主要是关注系统上的业务,所以在在 keepalived 进入 fault/stop 状态后,也认为是进入了 backup 状态,需要对 redis 的 master/slave 关系进行反转,否则即使 VIP 漂移过去,但是 redis 的主从关系还没有改变,会导致数据不一致,所以最终四个脚本只有两种内容。
5.1 redis 服务状态检测脚本 redis_check.sh(27 上面内容和它一样)
#!/bin/bash
###/etc/keepalived/scripts/redis_check.sh
ALIVE=`/usr/bin/redis-cli PING`
if [“$ALIVE” == “PONG”]; then
echo $ALIVE
exit 0
else
echo $ALIVE
exit 1
fi
5.2 keepalived 进入 master 状态时的检测脚本 redis_master.sh
w sourceprint?01 #!/bin/bash
###/etc/keepalived/scripts/redis_master.sh
REDISCLI=”redis-cli”
LOGFILE=”/etc/keepalived/log/redis-state.log”
pid=$$
echo “`date +’%Y-%m-%d:%H:%M:%S’`|$pid|state:[slaver]” >> $LOGFILE
echo “`date +’%Y-%m-%d:%H:%M:%S’`|$pid|state:[slaver] Run ‘SLAVEOF 10.20.112.27 6379′” >> $LOGFILE
$REDISCLI SLAVEOF 10.20.112.27 6379 >> $LOGFILE 2>&1
echo “`date +’%Y-%m-%d:%H:%M:%S’`|$pid|state:[slaver] wait 10 sec for data sync from old master” >> $LOGFILE
sleep 10
echo “`date +’%Y-%m-%d:%H:%M:%S’`|$pid|state:[slaver] data rsync from old mater ok…” >> $LOGFILE
echo “`date +’%Y-%m-%d:%H:%M:%S’`|$pid|state:[master] Run slaveof no one,close master/slave” >> $LOGFILE
$REDISCLI SLAVEOF NO ONE >> $LOGFILE 2>&1
echo “`date +’%Y-%m-%d:%H:%M:%S’`|$pid|state:[master] wait other slave connect….” >> $LOGFILE
5.3 keepalived 进入 backup/stop/fault 时的检测脚本,由于内容都一致,所以只写出 redis_backup.sh
#!/bin/bash
###/etc/keepalived/scripts/redis_backup.sh
REDISCLI=”redis-cli”
LOGFILE=”/etc/keepalived/log/redis-state.log”
pid=$$
echo “`date +’%Y-%m-%d:%H:%M:%S’`|$pid|state:[master]” >> $LOGFILE
echo “`date +’%Y-%m-%d:%H:%M:%S’`|$pid|state:[master] Being slave state…” >> $LOGFILE 2>&1
echo “`date +’%Y-%m-%d:%H:%M:%S’`|$pid|state:[master] wait 10 sec for data sync from old master” >> $LOGFILE
sleep 10
echo “`date +’%Y-%m-%d:%H:%M:%S’`|$pid|state:[master] data rsync from old mater ok…” >> $LOGFILE
echo “`date +’%Y-%m-%d:%H:%M:%S’`|$pid|state:[slaver] Run ‘SLAVEOF 10.20.112.27 6379′” >> $LOGFILE
$REDISCLI SLAVEOF 10.20.112.27 6379 >> $LOGFILE 2>&1
echo “`date +’%Y-%m-%d:%H:%M:%S’`|$pid|state:[slaver] slave connect to 10.20.112.27 ok…” >> $LOGFILE
配置 10.20.112.27
1 安装 keepalived
2 安装 redis
3 配置 redis,/etc/redis/redis.com
前面三步骤均一样
4 配置 keepalived
global_defs {
lvs_id LVS_redis
}
vrrp_script chk_redis {
script “/etc/keepalived/scripts/redis_check.sh”
weight -20
interval 2
}
vrrp_instance VI_1 {
state backup
interface eth0
virtual_router_id 51
priority 190
advert_int 5
track_script {
chk_redis
}
virtual_ipaddress {
10.20.112.29
}
notify_master /etc/keepalived/scripts/redis_master.sh
notify_backup /etc/keepalived/scripts/redis_backup.sh
notify_fault /etc/keepalived/scripts/redis_fault.sh
notify_stop /etc/keepalived/scripts/redis_stop.sh
}
5 建立 redis 状态切换脚本
在 /etc/keepalived 目录下建立 log 和 scripts 目录
5.1 redis 服务状态检测脚本 redis_check.sh(26 上面内容和它一样)
5.2 keepalived 进入 master 状态时的检测脚本 redis_master.sh
#!/bin/bash
###/etc/keepalived/scripts/redis_master.sh
REDISCLI=”/usr/bin/redis-cli”
LOGFILE=”/etc/keepalived/log/redis-state.log”
pid=$$
echo “`date +’%Y-%m-%d:%H:%M:%S’`|$pid|state:[backup]” >> $LOGFILE
echo “`date +’%Y-%m-%d:%H:%M:%S’`|$pid|state:[backup] Run ‘SLAVEOF 10.20.112.26 6379′” >> $LOGFILE
$REDISCLI SLAVEOF 10.20.112.26 6379 >> $LOGFILE 2>&1
echo “`date +’%Y-%m-%d:%H:%M:%S’`|$pid|state:[backup] wait 10 sec for data sync from old master” >> $LOGFILE
sleep 10
echo “`date +’%Y-%m-%d:%H:%M:%S’`|$pid|state:[master] data rsync from old mater ok…” >> $LOGFILE
echo “`date +’%Y-%m-%d:%H:%M:%S’`|$pid|state:[master] Run slaveof no one,close master/slave” >> $LOGFILE
$REDISCLI SLAVEOF NO ONE >> $LOGFILE 2>&1
echo “`date +’%Y-%m-%d:%H:%M:%S’`|$pid|state:[master] wait other slave connect….” >> $LOGFILE
5.3 keepalived 进入 backup/stop/fault 时的检测脚本,由于内容都一致,所以只写出 redis_backup.sh
#!/bin/bash
###/etc/keepalived/scripts/redis_backup.sh
REDISCLI=”/usr/bin/redis-cli”
LOGFILE=”/etc/keepalived/log/redis-state.log”
pid=$$
echo “`date +’%Y-%m-%d:%H:%M:%S’`|$pid|state:[master] Being slave state…” >> $LOGFILE 2>&1
echo “`date +’%Y-%m-%d:%H:%M:%S’`|$pid|state:[master] wait 15 sec for data sync from old master” >> $LOGFILE
sleep 15
echo “`date +’%Y-%m-%d:%H:%M:%S’`|$pid|state:[master] data rsync from old mater ok…” >> $LOGFILE
echo “`date +’%Y-%m-%d:%H:%M:%S’`|$pid|state:[slaver] Run ‘SLAVEOF 10.20.112.26 6379′” >> $LOGFILE
$REDISCLI SLAVEOF 10.20.112.26 6379 >> $LOGFILE 2>&1
echo “`date +’%Y-%m-%d:%H:%M:%S’`|$pid|state:[slaver] slave connect to 10.20.112.26 ok…” >> $LOGFILE
上一篇简单的了解了一下 Redis 官方自带的 HA 方案 sentinel(见 http://www.linuxidc.com/Linux/2014-02/96079.htm),试用发现还是不错的,但是由于还没有合并进稳定分支中,所以在生产环境也不敢使用,还有一个就是需求还暂时不能完全满足,所以就尝试一下 redis+keepalived 方案,毕竟 keepalived 现在还是很稳定的,而且资料也充足。
实验环境
Ubuntu 12.04 10.20.112.26 默认的 master
10.20.112.27 默认的 slave
VIP 10.20.112.29
redis-server 2.6.16
keepalived 默认只能做到对网络故障和 keepalived 本身的监控,即当出现网络故障或者 keepalived 本身出现问题时,进行切换。但我们更关注的是机器上运行的业务,如果业务出问题了 VIP 没有变化,整体来说还是失败的。这时候就需要根据业务进程的运行状态决定是否需要进行主备切换。还好 keepalived 提供了这样一个自定义脚本监控功能,不过该参数设置在官方默认的文档中并没有出现。
其实文档中有两个我们常用的参数都没有提到:
1 vrrp_script && track_script
vrrp_script 代码块是用来定义监控脚本,脚本执行时间间隔以及脚本的执行结果导致优先级变更幅度的。
vrrp_script chk_redis {
script “/etc/keepalived/scripts/redis_check.sh” #指定执行脚本的路径
interval 1 #指定脚本的执行时间间隔
weight 10 #脚本结果导致的优先级变更:10 表示优先级 +10;-10 则表示优先级 -10
}
定义好 vrrp_script 代码块之后,就可以在 instance 中使用了
track_script {
chk_redis
}
注意:VRRP 脚本 (vrrp_script) 和 VRRP 实例 (vrrp_instance) 属于同一个级别
2 notify_stop
keepalived 停止运行前运行 notify_stop 指定的脚本。
配合官方文档提到的以下三个参数一起使用,功能更强大:
notify_master keepalived 切换到 master 时执行的脚本
notify_backup keepalived 切换到 backup 时执行的脚本
notify_fault keepalived 出现故障时执行的脚本
3 还有个问题需要注意
当 master down 了,backup 接管了,master 再次起来,不能再成为 master。否则 master 恢复了再接管的话,会造成业务来回切换,这时候就需要 nopreempt 参数了。
nopreempt:设置不抢占,这里只能设置在 state 为 backup 的节点上,而且这个节点的优先级必须别另外的高。
先来看看方案的整体思路:
通过 keepalived 的自定义脚本功能监控本机的 redis 服务状态,当监控脚本检测到 redis 服务出现异常时,则改变本机 keepalived 的优先级,同时这会导致 master/backup 角色的变化,而 keepalived 在角色变化时也会触发一些机制执行相关脚本,这就为我们改变 redis 的 master/slave 状态提供了机会,这样做的目的是为了是 redis 的 master/slave 直接的数据保持一致。
在 keepalived+redis 的使用过程中有四种情况:
1 一种是 keepalived 挂了,同时 redis 也挂了,这样的话直接 VIP 飘走之后,是不需要进行 redis 数据同步的,因为 redis 挂了,你也无法去 master 上同步,不过会损失已经写在 master 上却还没同步到 slave 上面的这部分数据。
2 另一种是 keepalived 挂了,redis 没挂,这时候 VIP 飘走后,redis 的 master/slave 还是老的对应关系,如果不变化的话会把数据写入 redis slave 中,从而不会同步到 master 上去,这就要借助监控脚本反转 redis 的 master/slave 关系。这时候就要预留一点时间进行数据同步,然后反转 master/slave。
3 还有一种是 keepalived 没挂,redis 挂了,这时候根据监控脚本会检测到 redis 挂了,并且降低 keepalived master 的优先级,同样会导致 VIP 飘走,情况和第二种一样,也是需要进行数据同步,然后反转当前 redis 的 master/slave 关系的。
4 随后一种是 keepalived 没挂,redis 也没挂,大吉大利啊,什么都不用操作。
本文的实验环境四种情况都适合,第一种是不需要同步数据的,脚本会默认去同步数据,但是其实是不会成功的。脚本主要是用来处理第二和第三种情况的。
Redis 的详细介绍:请点这里
Redis 的下载地址:请点这里
推荐阅读:
Redis 集群明细文档 http://www.linuxidc.com/Linux/2013-09/90118.htm
Ubuntu 12.10 下安装 Redis(图文详解)+ Jedis 连接 Redis http://www.linuxidc.com/Linux/2013-06/85816.htm
Redis 系列 - 安装部署维护篇 http://www.linuxidc.com/Linux/2012-12/75627.htm
CentOS 6.3 安装 Redis http://www.linuxidc.com/Linux/2012-12/75314.htm
Redis 配置文件 redis.conf 详解 http://www.linuxidc.com/Linux/2013-11/92524.htm
下面开始试验
既然我们设置了 nopreempt,那么在启动 keepalived 的时候就有启动的顺序问题了,我们把 Redis 的 master 和 keepalived 的 master(虽然配置文件中都是 backup,但是我们是想让 26 这台做 master 的 ) 默认设置在同一台机器上,由于在 keepalived 的 master 上面设置了 nopreempt 参数,所以在启动 keepalived 服务的时候,一定要先启动 redis master 的那台,因为在设置了 nopreempt 了,keepalived 在启动后都是先进入 backup 状态,而脚本又设置了进入 backup 状态后,会连接新的对方进行数据同步,所以, 在启动 keepalived 之前还有一个条件就是 redis 的 master 和 slave 中的数据必须一致。这样先启动 redis 的 master 那台的 keepalived,虽然 redis master 会连接到 redis slave 同步数据,但是两边数据在刚开始的时候是一致的,并不会产生什么问题。
1 先启动 26 和 27 上的 redis 服务,配置 27 从 26 上面同步数据,同步完毕后,取消 27 的同步机制。
这个就是在 27 的 redis 上面执行 slaveof 10.20.112.26 6379,等待数据同步完毕后再执行 slaveos on one,让 26 和 27 的 redis 都保持 master 状态
2 接着启动 26 的 keepalived,不要启动 27 的 keepalived,在 26 和 27 上面各开启三个终端,观察自定义日志和系统日志状态
26 的 syslog
红框 19 秒 keepalived 启动后,由于设置了不抢占,且起始状态都是 backup,所以启动后 keepalived 先进入 backup 状态,进入 bankup 状态后,成功的执行了 redis_backup.sh 脚本
绿框 34 秒的时候,keepalived 开始向 master 状态转变,注意:这个时间很重要,为什么是 34 秒呢?默认是 3 秒后就开始向 master 状态转变,由于我们设置了 advert_int 5,默认检测三次,所以 15 秒之后才向 master 转变,为什么设置间隔这么长时间呢?是为了让 redis_backup.sh 脚本有充足的时间执行完毕。39 秒的时候成功的转变为 master 状态,这时候会执行 redis_master.sh 脚本。
26 的redis-state.log
过程解释:
红框 确实如系统日志表现的那样,19 秒的时候先进入 backup 状态,执行 redis_backup.sh 脚本。redis_backup 是 keepalived 进入到 backup 状态时执行的脚本。进入到 banckup 状态,说明自身以前是 master 状态或者无状态,这时候会等待两秒种,让之前的 slave 把数据同步完,2 秒钟在数据大的时候有些短,其实是可以设置的,只要小于 3 倍的 advert_int 时间就行,因为 3 倍的时间之后会转为 master 状态的。2 秒钟之后我们的redis 连接到 27 上面(27 这时候充当 master),开始进行正常的 master/slave 机制同步数据,也就是红框中 21 秒的时候。到此为止,redis_backup.sh 执行完毕。
绿框 由于设置了不抢占,所以过了 3 倍的 advert_int 时间之后,开始向 master 状态转变,这个转变过程需要的时间是不固定的,在上面的日志中需要 5 秒,正式的成为 master 状态,这时候会执行 redis_master.sh 脚本,脚本指定需要到 27 的 redis 上同步数据(27 在红框中的时候是充当 master 的),你可以看到已经有连接了,那是因为在红框中已经连接过一次了,我设置的是同步 10 秒钟之后断开和 27 的连接,可以看到 49 秒的时候执行了 slaveof no one 命令,断开了和 27 的连接,把 26 自身的 redis 提升为 master,这时候数据也是最新的了。
3 待 26 的各项进程都 ok 后,我们开始启动 27 上面的 keepalived 服务
27 的 syslog
红框 40 秒的时候启动 27 的 keepalived,由于默认都是 backup,所以直接进入 backup 状态,由于 27 的优先级比 26 低,所以 27 并不会过度到 master 状态,这时候 26 是 master 状态了。在 backup 状态执行了 redis_backup.sh 脚本。
27 的redis-state.log
红框 在进入 backup 状态后,默认之前是 master 状态或者无状态,所以等待 15 秒,让 26 把数据同步完(26 这时候充当 backup),在 15 秒之后,开始向 backup 转变,开始执行 slaveof 10.20.112.26 6379,作为 26 的 slave。
下面要模拟故障 3:
1 kill 掉 26 的 redis 进程,保持 keepalived 进程。(模拟 3)
26 的 syslog
红框 可以看到检测脚本 chk_redis 发现 redis 已经宕掉,降低了 26 的 keepalived 的优先级,导致 26 进入 backup 状态,开始执行 redis_backup.sh 监控脚本
26 的redis-state.log
红框 由于 redis 我是 kill 掉的,所以必然不能进行数据同步了,不过这并不影响使用。
27 的 syslog
绿框 可以看到 27 转变到 master 状态,并且执行了 redis_master.sh 脚本
27 的redis-state.log
绿框 由于 26 的 redis 是 kill 掉的,所以��使 27 转变到 master 状态也不能去 26 同步数据,当然 27 也等不到 26 连接上来,不过并不影响我们使用。
下面要模拟故障 2:
2 kill 掉 26 的 keepalived 进程,保持 redis 进程。(模拟 2)
26 的 syslog
红框 是 keepslived 的启动过程,在模拟 3 中已经详细分析过
绿框 是 kill 掉 keepalived 进程后的日志。
26 的redis-state.log
红框 是 keepalived 启动过程中执行的监控脚本日志,前面模拟 3 中已经详细分析过
绿框 是 keepalived 进程 kill 掉之后,执行的监控脚本日志,在等待 27 同步完数据后,作为 27 的 slave 连接上去。
26 的 redis info
可以看到 master/slave 的转变过程
27 的 syslog
红框 是 keepalived 作为 backup 的启动过程,在模拟 3 中已经分析过。
绿框 是 kill 掉 26 的 keepalived 进程后,27 转变为 master 时的日志,执行了 redis_master.sh 脚本。
27 的redis-state.log
红框 是 keepalived 启动时执行的监控脚本日志,由于开始是 backup 的,所以没有过多的状态切换过程。
绿框 是 26 的 keepalived 进程被 kill 掉之后,27 转变为 master 时执行的脚本日志,由于 keepalived 挂了,但是 26 的 redis 进程还在,所以先和 26 进行数据同步,完成之后再把自己提升为 redis master。
27 的 redis info
可以看到 redis 的 master/slave 变化过程
以上就是我所能想到的 keepalived+redis HA 方案中需要注意的地方。
Keepalived 的详细介绍:请点这里
Keepalived 的下载地址:请点这里
推荐阅读:
CentOS 6.3 下 Haproxy+Keepalived+Apache 配置笔记 http://www.linuxidc.com/Linux/2013-06/85598.htm
Haproxy + KeepAlived 实现 WEB 群集 on CentOS 6 http://www.linuxidc.com/Linux/2012-03/55672.htm
Keepalived+Haproxy 配置高可用负载均衡 http://www.linuxidc.com/Linux/2012-03/56748.htm
Haproxy+Keepalived 构建高可用负载均衡 http://www.linuxidc.com/Linux/2012-03/55880.htm