|

楼主 |
发表于 2007-10-16 11:39:44
|
显示全部楼层
mirrord/fs_mirror 的简单使用
==使用手册==[ru_data_man_usage]
===安装===
包含 mirrord/fs_mirror 的包是``cutils``,是``ulfs``的一个子项目。uLFS
意思是"**Your** own customed and easily managable **LFS**(Linux From
Scratch) distrubution",它包含一些工具以达到这个目的,例如
[User Based Package Management(包管理系统) #ru_package_man],
Configuration Sharing Management(配置共享管理),以及这个文件系统备份和
近实时镜像(也许在将来我可以实现一个完全实时的应用)。
在需要备份的服务器上安装 mirrord,此时需要 Python 2.4 或更高的版本,
以及 pyinotify-0.7.1:
```
sh$ tar xfz Python-2.5.1.tar.gz
sh$ cd Python-2.5.1
sh$ ./configure --prefix=/usr
sh$ make
sh# make install
sh$ tar xfj pyinotify-0.7.1.tar.bz2
sh$ cd pyinotify-0.7.1
sh$ python setup.py build
sh# python setup.py install
```
在备份主机客户端运行 fs_mirror,只需要 Python 即可。
然后要安装 caxes-0.1.2,这也是``ulfs``的另一个子项目,可以在``cutils``
相同的下载页面取得,它包括我定义的若干辅助的数据结构,例如 Python Tree
```
sh$ tar xfz caxes-0.1.2.tar.gz
sh$ cd caxes-0.1.2
sh$ python setup.py build
sh# python setup.py install
```
最后,安装 cutils-0.1.1:
```
sh$ tar xfz cutils-0.1.1.tar.gz
sh$ cd cutils-0.1.1
sh$ python setup.py build
sh# python setup.py install --install-scripts=/usr/local/bin
```
===简单使用===
参考 [The Second Story #ru_data_man_design_second] 中的图,为备份或镜像
一个文件系统,首先需要告诉备份/镜像程序要备份些什么。可以运行``fs_info``
来做这件事:
```
server# fs_info -a t:/var/www/html system
```
这会将"/var/www/html"加入到备份/镜像包含列表中,并分配一个对文件系统
部分进行标识的标识名"system",这个标识在你第一次运行这个命令的时候创建
,你也可以使用其他名字,例如"www", "web", "work" 等...
只有最上层的目录是必需的,所以:
```
server# fs_info -a t:/var/www/html \
-a t:/var/www/html/include system
```
与前面那个命令的效果完全一样("/var/www/html")。
为了将一些目录/文件排除在备份/镜像之外,使用"x:"标志:
```
server# fs_info -a t:/var/www/html \
-a x:/var/www/html/cache system
```
这会将"/var/www/html/cache"加入到排除列表当中。
如果有一个列表,可以直接将其加入:
```
server# fs_info -a tL:/tmp/included_01 \
-a tL:/tmp/included_02 \
-a xL:/tmp/excluded_01 system
```
fs_info 实际的效果就是向 $datadir/$identity/.{t,x}_files 中追加条目,
所以你也可以直接编辑这两个文件,或者使用 shell 脚本重定向功能:
```
server# find /var -maxdepth 1 >$datadir/$identity/.t_file
```
不过 fs_info 可以为你做若干有效性检查的操作,例如判断文件/目录是否存在
等。无论如何,选择权在你手里。
$datadir 默认是"/var/fs_info",你可以通过编辑
"/etc/python/fs_info_config.py"来调整它为"/var/mirrord",以适应 mirrord
的需要,因为 mirrord 的默认值就是"/var/mirrord",这个值也可以通过编辑
"/etc/python/mirrord_config.py"来调整。
这些配置文件都直接使用" ython Tree"定义的数据结构,在前面提到的``caxes``
包里面。
$identity 默认为"system",如前所述。
这些配置也可以自命令行改变,例如:
```
server# fs_info -o datadir=/var/mirrord -a t:/var/www/html
```
**注意**,inotify 的默认内核参数值太小:
```
16384 /proc/sys/fs/inotify/max_queued_events
8192 /proc/sys/fs/inotify/max_user_watches
```
"max_user_watches"的大小取决于要备份的这部分文件系统包含多少目录,可以
用:
```
sh# find $path -type d | wc -l
```
来统计一下,并保证这个值大于统计结果。
"max_queued_events"意味着 inotify 管理的队列的最大长度,文件系统变化越
频繁,这个值就应该越大。如果你在日志中看到""** Event Queue Overflow **"
这样的消息,这就意味着"max_queued_events"太小,并且自此之后对于文件系统
的监控都是不准确的,你应该在调整参数后重启"mirrord"。
这些设置之后,就可以启动 mirrord 来监控和记录源文件系统的变化了:
```
server# mirrord
# OR verbose:
server# mirrord -v
```
你可以自配置文件"/etc/python/mirrord_config.py"或命令行来调整 mirrord
的行为,例如 wmLog 的长度(o.length, 此值越大,就会保留越多的记录,这
可以为长时间停止的 fs_mirror 客户端从断点重启提供更大的方便,但同时也
意味着在读取和变更 wmLog 时需要更多的资源),绑定的接口和端口,以及
socket 的超时,或需要镜像的 identity 标识集。
mirrord 启动之后,等待一段时间(取决于硬件、文件系统类型以及需要
备份/镜像的目录/文件数量),当"boot init finished"的消息被打印的时候,就
可以切换到客户端并启动 fs_mirror 了。
后续的版本将会消除这个等待阶段,使你可以在启动 mirrord 之后立即启动
fs_mirror。
在启动 fs_mirror 之前,必须保证客户端能够与 mirrord 通信并进行普通文件
的传输(只需要普通文件传输),因此必须在防火墙上允许 2123 端口(或选择另
一个端口),以及你选择用来传输普通文件的端口 -- 就象在
[The Second Story #ru_data_man_design_second] 和
[The Fifth Story: Monitor #ru_data_man_design_monitor]
中所描述的那样,mirrord/fs_mirror 的设计支持很多文件传输机制,例如 FTP,
NFS, SMB/CIFS 等等... 不过目前来说,我只实现了两种:REPORT 和 FTP。
"REPORT" 仅仅打印由 fs_mirror 接收到的 wmLog 中的动作,这仍然是一个很
有用的特性,在后面讨论。
"FTP" 同步机制将创建目录,删除或移动(递归)目录/文件,这些都可以在本地
完成,而只有对普通文件的写操作需要通过 FTP 协议进行实际的文件传输操作,
这种方式降低了在服务器上的资源消耗。注意整个文件都会被传输,而不是仅仅
被变更的部分,所以这**不是**一个字节级别的传输,因此不适用于大的并且
变化频繁的文件,或者说,如果大小和变化频度的乘积过大,或"size/seconds"
的值太小(这里 seconds 表示自第一次传输以来所经过的间隔),都不适合传输。
未来也许会在客户端做一个计算以判断是否应该传输。
这些同步机制定义在 cutils.fs_sync 模块中。
在需要镜像的源文件系统的主机上创建一个明文"mirror"或"backup"的用户是
一个好主意,这个用户应该拥有这部分文件系统的读权限,这可以利用 Linux
的 ACL 功能来实现,并使这个用户能够通过 FTP 访问,也许你想进一步使用
FTP SSL。到目前为止,认证机制还没有实现。
编辑 fs_mirror 的配置文件"/etc/fs_mirror_config.py"以获取关于配置的跟多
信息。
此时,启动 fs_mirror:
```
client# fs_mirror
# OR verbose:
client# fs_mirror -v
```
"fs_mirror --help"将提供命令行的更多信息。
作为一个例子,你可能会使用如下的参数:
```
client# fs_mirror -v -o host=roc \
-o fssync.user=root \
-o fssync.port=2121 \
--password-from=/root/.fs_mirror/secrets:roc \
--datadir=/data/fs_mirror/roc
```
现在,镜像的目录/文件将被放在 /data/fs_mirror/$hostname 中,选项"-o"
(--option) 与 /etc/python/fs_mirror_config.py 中 o.* 拥有相同的含义,
如前所述。这里,hostname 和两个文件同步的参数被改变了,当然要保证
hostname 可以被解析。
如果 verbose 模式打开了的话,在屏幕上可能会有这样的消息:
```
Daemon PID 7094
Connecting to the Mirrord: ('roc', 2123) ...
Conected.
Server reply 'OK' for 'START'
Server reply 'OK' for 'SN:b5e0ce480c925184dbdb6f23a62ddc6d,872302'
Received next serial message: 'SERIAL:862303'
WRITE FILE '/var/Counter/data/5597.dat', PREFIX '/data/fs_mirror/roc'
Received next serial message: 'SERIAL:862306'
CREATE DIR '/var/www/html/sample231.com/syssite', PREFIX 'data/fs_mirror/roc'
WRITE FILE '/var/www/html/sample231.com/sysstie/rec.php', PREFIX '/data/fs_mirror/roc'
DELETE DIR/FILE '/var/www/html/sample231.com/sysstie/rec.php.old', PREFIX '/data/fs_mirror/roc'
...
```
有一个普通文件"$datadir/sn"用来记录 session 和 serial number:
```
sh# cat /data/fs_mirror/roc/sn
b5e0ce480c925184dbdb6f23a62ddc6d,872302
```
这个文件在 fs_mirror 需要从断点重启的时候被使用。它使用一个文件锁
(fcntl.LOCK_EX)来避免镜像两个文件系统到一个目录,或同时镜像一个文件系统
两次(运行两个同样的 fs_mirror 实例)。
在[概述 #ru_data_man_overview]一节说过,轮转机制是必需的。目前
fs_mirror 还没有内置的轮转实现,这只能在以后来实现它,但是可以自己写
一个脚本做这个事情。在 SVN 的 repository 里面的"prototypes"子目录里有
两个例子:prototypes/fs_mirror_rotate.py 和 prototypes/mirror_rotate。
这两个脚本如下:
prototypes/mirror_rotate:
```
[PHP]#!/bin/sh
hosts="p01 2121
p02 2121
p03 2121"
cd `dirname $0`
# for host in hosts; do
echo "$hosts" | while read host port; do
pid=`ps aux | grep "fs_mirror.*$host" | grep -v 'grep' | awk '{print $2}'`
if [ $? -eq 0 ]; then
if [ -n "$pid" ]; then kill $pid; fi \
&& ./fs_mirror_rotate.py $host \
&& /usr/local/bin/fs_mirror -v \
-o host=$host \
-o fssync.user=root \
-o fssync.port=$port \
--passwd-from=/root/.mirror/secrets host \
--datadir=/data/fs_mirror/$host/
fi \
&& cat /data/fs_mirror/$host/www/prima/usermap \
| awk -F, '{printf("%s %s %s %s %s\n", $1, $2, $3, $4, $5)}' \
| while read perm uid user gid site; do
chown $uid.$gid /data/fs_mirror/$host/www/users/$site -R
# gid always be ftpd
done
done[/PHP]
```
prototypes/fs_mirror_rotate.py:
```
[PHP]#!/usr/bin/python
# -*- encoding: utf-8 -*
import os,sys,shutil
import time
import datetime
mirror = "/data/fs_mirror"
backdir = "/data/hosts"
try:
host = sys.argv[1]
except IndexError:
print >> sys.stderr, "Lack of a host identity"
sys.exit(1)
day = datetime.date(*time.localtime()[:3])
new = os.path.normpath("%s/%s" % (mirror, host))
NL = len(new)
old = os.path.normpath("%s/%s/%s" % (backdir, host, str(day)))
OL = len(old)
shutil.move(new, old)
for root, dirs, files in os.walk(old):
d_new = os.path.normpath("%s/%s" % (new, root[OL:]))
os.mkdir(d_new)
# status = os.lstat(root)
# perm = status[0]
# os.chmod(d_new, perm)
# uid = status[4]
# gid = status[5]
# os.chown(d_new, uid, gid)
try:
os.chmod(d_new, 0755)
except OSError:
pass
# print "CREATE DIR '%s'" % d_new
for fname in files:
f_new = os.path.normpath("%s/%s" % (d_new, fname))
f_old = os.path.normpath("%s/%s" % (root, fname))
os.link(f_old, f_new)
# Hard link will reserve the permission and ownership of a file
try:
os.chmod(f_new, 0644)
except OSError:
pass
# print "HARD LINK '%s' -> '%s'" % (f_old, f_new)
interval = datetime.timedelta(days=14)
overdue_day = day - interval
overdue_dir = os.path.normpath("%s/%s/%s" % (backdir, host, str(overdue_day)))
try:
shutil.rmtree(overdue_dir)
except OSError, (errno, strerr):
if errno == 2:
print strerr
else:
raise[/PHP]
```
示例归档:
```
[root@stor p01]# ls -l
total 144
drwxr-xr-x+ 6 root root 4096 Oct 2 03:10 2007-10-03
drwxr-xr-x+ 6 root root 4096 Oct 3 03:10 2007-10-04
drwxr-xr-x+ 6 root root 4096 Oct 4 03:10 2007-10-05
drwxr-xr-x+ 6 root root 4096 Oct 5 03:10 2007-10-06
drwxr-xr-x+ 6 root root 4096 Oct 6 03:10 2007-10-07
drwxr-xr-x+ 6 root root 4096 Oct 7 03:10 2007-10-08
drwxr-xr-x+ 6 root root 4096 Oct 8 03:10 2007-10-09
drwxr-xr-x+ 6 root root 4096 Oct 9 03:10 2007-10-10
drwxr-xr-x+ 6 root root 4096 Oct 10 03:10 2007-10-11
drwxr-xr-x+ 6 root root 4096 Oct 11 03:10 2007-10-12
drwxr-xr-x+ 6 root root 4096 Oct 12 03:10 2007-10-13
drwxr-xr-x+ 6 root root 4096 Oct 13 03:10 2007-10-14
drwxr-xr-x+ 6 root root 4096 Oct 14 03:10 2007-10-15
drwxr-xr-x+ 6 root root 4096 Oct 15 03:10 2007-10-16
[root@stor p01]# ls 2007-10-16/etc/httpd/conf.d -l
total 112
-rw-r--r-- 9 root root 58 Oct 8 13:41 bw_mod.conf
-rw-r--r-- 9 root root 187 Oct 8 13:41 mod_caucho.conf
-rw-r--r-- 9 root root 2965 Oct 8 13:41 site.conf
-rw-r--r-- 9 root root 10919 Oct 8 13:41 ssl.conf
-rw-r--r-- 9 root root 85876 Oct 8 13:41 virtual.conf
```
硬链接数是 8,这意味着上次启动 mirrord 实在 2007-10-08。
注意 fs_sync 会在传输一个普通文件之前先做 unlink,以避免破坏轮转的备份
,既然轮转脚本实际做的就是简单的创建目录和普通文件硬链接。
到目前为止,只有变更动作(CREATE, FWRITE, DELETE, MOVE)及其相应的路径名
被传输,所以如果目录/文件有属主/权限的需求,当前的 mirrord/fs_mirror
自身不能解决,要知道改变属主和权限涉及到遍历操作,因此比较消耗资源。
所以我在上面改变轮转脚本令每天其改变一次属主和权限,这当然不是一个很好
的办法,特别是在没有统一认证中心的情况下。这种更强的功能将在一个未来的
版本中实现。
使用一个认证中心是比较合理的,例如 NIS, LDAP 或 Kerberos,因为保持权限
和属主的一致是很有必要的。
**我必须指出客户端的 fs_mirror 到目前还没有彻底测试**
**这也是我时间有限,经验不足的缘故**
**因此你可能需要多花一些时间做调整** |
|